From ff24c7e720a6eb33f0a8ab71634df71aad5cd3d0 Mon Sep 17 00:00:00 2001 From: Duncan Mak Date: Tue, 29 Aug 2023 17:51:32 -0400 Subject: [PATCH 001/593] Fix typo in Shape.newBuilder().layout() The other reference to the method is correct, but the call to `layout` was missing here. --- truffle/docs/DynamicObjectModel.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/truffle/docs/DynamicObjectModel.md b/truffle/docs/DynamicObjectModel.md index ad63e1ae0606..9e06845ad12e 100644 --- a/truffle/docs/DynamicObjectModel.md +++ b/truffle/docs/DynamicObjectModel.md @@ -122,7 +122,7 @@ public final class MyLanguage extends TruffleLanguage { private final Shape initialArrayShape; public MyLanguage() { - this.initialObjectShape = Shape.newBuilder(ExtendedObject.class).build(); + this.initialObjectShape = Shape.newBuilder().layout(ExtendedObject.class).build(); this.initialArrayShape = Shape.newBuilder().build(); } From c9cf48b54a49e66d826b9fdbd49d86a867846dff Mon Sep 17 00:00:00 2001 From: Lukas Stadler Date: Tue, 21 Nov 2023 13:08:35 +0100 Subject: [PATCH 002/593] Truffle DSL: support RECORD in ElementUtils.elementEquals --- .../truffle/api/dsl/test/CachedTest.java | 27 ++++++++++++++++++- .../dsl/processor/java/ElementUtils.java | 5 ++-- 2 files changed, 29 insertions(+), 3 deletions(-) diff --git a/truffle/src/com.oracle.truffle.api.dsl.test/src/com/oracle/truffle/api/dsl/test/CachedTest.java b/truffle/src/com.oracle.truffle.api.dsl.test/src/com/oracle/truffle/api/dsl/test/CachedTest.java index ccca370ea9fd..ac45ca03a4a8 100644 --- a/truffle/src/com.oracle.truffle.api.dsl.test/src/com/oracle/truffle/api/dsl/test/CachedTest.java +++ b/truffle/src/com.oracle.truffle.api.dsl.test/src/com/oracle/truffle/api/dsl/test/CachedTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2023, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * The Universal Permissive License (UPL), Version 1.0 @@ -1075,4 +1075,29 @@ static Node[] do1(Node[] value, } + record TestRecord(boolean foo) { + } + + @NodeChild + abstract static class CachedRecord extends ValueNode { + + protected static TestRecord getRecord() { + return null; + } + + // ensure that ElementUtils.elementEquals accepts records + @Specialization + static int do1(int x, + @Cached("getRecord().foo()") boolean cached) { + return 0; + } + + @Specialization + static int do1(double x, + @Cached("getRecord().foo()") boolean cached) { + return 0; + } + + } + } diff --git a/truffle/src/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/java/ElementUtils.java b/truffle/src/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/java/ElementUtils.java index 2ec18f6e4d60..bcfc6e45b9ce 100644 --- a/truffle/src/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/java/ElementUtils.java +++ b/truffle/src/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/java/ElementUtils.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2023, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * The Universal Permissive License (UPL), Version 1.0 @@ -1566,13 +1566,14 @@ public static boolean elementEquals(Element element1, Element element2) { case ENUM: case INTERFACE: case ANNOTATION_TYPE: + case RECORD: return typeEquals(element1.asType(), element2.asType()); case PACKAGE: return ((PackageElement) element1).getQualifiedName().equals(((PackageElement) element2).getQualifiedName()); case TYPE_PARAMETER: return element1.getSimpleName().toString().equals(element2.getSimpleName().toString()); default: - throw new AssertionError("unsupported element type"); + throw new AssertionError("unsupported element type: " + element1.getKind()); } } From 221eabe07ed0337f7e36da04d48b3d51abfe13f2 Mon Sep 17 00:00:00 2001 From: Andreas Woess Date: Fri, 17 Nov 2023 16:01:39 +0100 Subject: [PATCH 003/593] Add SSHLL2 and SXTL2 assembler instructions. --- .../asm/aarch64/AArch64ASIMDAssembler.java | 33 +++++++++++++++++++ .../aarch64/AArch64ASIMDMacroAssembler.java | 24 +++++++++++++- 2 files changed, 56 insertions(+), 1 deletion(-) diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/asm/aarch64/AArch64ASIMDAssembler.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/asm/aarch64/AArch64ASIMDAssembler.java index 0aeff1e8d2fc..147c40344cda 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/asm/aarch64/AArch64ASIMDAssembler.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/asm/aarch64/AArch64ASIMDAssembler.java @@ -3126,6 +3126,8 @@ public void sshlVVV(ASIMDSize size, ElementSize eSize, Register dst, Register sr * vector elements are twice as long as the source vector elements. All the values in this * instruction are signed integer values." * + * Extracts vector elements from the lower half of the source register. + * * @param srcESize source element size. Cannot be ElementSize.DoubleWord. The destination * element size will be double this width. * @param dst SIMD register. @@ -3146,6 +3148,37 @@ public void sshllVVI(ElementSize srcESize, Register dst, Register src, int shift shiftByImmEncoding(ASIMDInstruction.SSHLL, false, imm7, dst, src); } + /** + * C7.2.316 Signed shift left long (immediate).
+ * + *

+ * From the manual: "This instruction reads each vector element from the source SIMD&FP + * register, left shifts each vector element by the specified shift amount ... The destination + * vector elements are twice as long as the source vector elements. All the values in this + * instruction are signed integer values." + * + * Extracts vector elements from the upper half of the source register. + * + * @param srcESize source element size. Cannot be ElementSize.DoubleWord. The destination + * element size will be double this width. + * @param dst SIMD register. + * @param src SIMD register. + * @param shiftAmt shift left amount. + */ + public void sshll2VVI(ElementSize srcESize, Register dst, Register src, int shiftAmt) { + assert dst.getRegisterCategory().equals(SIMD) : dst; + assert src.getRegisterCategory().equals(SIMD) : src; + assert srcESize != ElementSize.DoubleWord : srcESize; + + /* Accepted shift range */ + assert shiftAmt >= 0 && shiftAmt < srcESize.nbits : shiftAmt + " " + srcESize; + + /* shift = imm7 - srcESize.nbits */ + int imm7 = srcESize.nbits + shiftAmt; + + shiftByImmEncoding(ASIMDInstruction.SSHLL, true, imm7, dst, src); + } + /** * C7.2.317 signed shift right (immediate).
* diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/asm/aarch64/AArch64ASIMDMacroAssembler.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/asm/aarch64/AArch64ASIMDMacroAssembler.java index 8089d130ef7f..840b5444b5ba 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/asm/aarch64/AArch64ASIMDMacroAssembler.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/asm/aarch64/AArch64ASIMDMacroAssembler.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 2023, 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 @@ -310,6 +310,8 @@ public void mvnVV(ASIMDSize size, Register dst, Register src) { *

* Preferred alias for sshll when only sign-extending the vector elements. * + * Extracts vector elements from the lower half of the source register. + * * @param srcESize source element size. Cannot be ElementSize.DoubleWord. The destination * element size will be double this width. * @param dst SIMD register. @@ -319,11 +321,29 @@ public void sxtlVV(ElementSize srcESize, Register dst, Register src) { sshllVVI(srcESize, dst, src, 0); } + /** + * C7.2.338 Signed extend long.
+ *

+ * Preferred alias for sshll2 when only sign-extending the vector elements. + * + * Extracts vector elements from the upper half of the source register. + * + * @param srcESize source element size. Cannot be ElementSize.DoubleWord. The destination + * element size will be double this width. + * @param dst SIMD register. + * @param src SIMD register. + */ + public void sxtl2VV(ElementSize srcESize, Register dst, Register src) { + sshll2VVI(srcESize, dst, src, 0); + } + /** * C7.2.398 Unsigned extend long.
*

* Preferred alias for ushll when only zero-extending the vector elements. * + * Extracts vector elements from the lower half of the source register. + * * @param srcESize source element size. Cannot be ElementSize.DoubleWord. The destination * element size will be double this width. * @param dst SIMD register. @@ -338,6 +358,8 @@ public void uxtlVV(ElementSize srcESize, Register dst, Register src) { *

* Preferred alias for ushll2 when only zero-extending the vector elements. * + * Extracts vector elements from the upper half of the source register. + * * @param srcESize source element size. Cannot be ElementSize.DoubleWord. The destination * element size will be double this width. * @param dst SIMD register. From 763614f8e544853476fa4c107575e3690db23456 Mon Sep 17 00:00:00 2001 From: Florian Huemer Date: Wed, 29 Nov 2023 16:56:43 +0100 Subject: [PATCH 004/593] Extended WASI with unimplemented missing functions. Added monotonic clock. Fixed reading from streams. --- .../src/test/wasi/fd_read-stdin-eof.opts | 2 + .../src/test/wasi/fd_read-stdin-eof.result | 1 + .../src/test/wasi/fd_read-stdin-eof.wat | 83 +++++++++++++++++++ .../src/test/wasi/fd_read-stdin-multi.opts | 2 + .../src/test/wasi/fd_read-stdin-multi.result | 1 + .../src/test/wasi/fd_read-stdin-multi.wat | 81 ++++++++++++++++++ .../src/test/wasi/wasm_test_index | 2 + .../predefined/wasi/WasiClockTimeGetNode.java | 7 ++ .../wasi/WasiFdFilestatSetTimesNode.java | 80 ++++++++++++++++++ .../wasm/predefined/wasi/WasiModule.java | 43 +++++++--- .../wasi/WasiUnsupportedFunctionNode.java | 69 +++++++++++++++ .../graalvm/wasm/predefined/wasi/fd/Fd.java | 19 +++++ .../wasm/predefined/wasi/fd/FdUtils.java | 17 ++-- .../wasm/predefined/wasi/fd/FileFd.java | 31 ++++++- 14 files changed, 414 insertions(+), 24 deletions(-) create mode 100644 wasm/src/org.graalvm.wasm.test/src/test/wasi/fd_read-stdin-eof.opts create mode 100644 wasm/src/org.graalvm.wasm.test/src/test/wasi/fd_read-stdin-eof.result create mode 100644 wasm/src/org.graalvm.wasm.test/src/test/wasi/fd_read-stdin-eof.wat create mode 100644 wasm/src/org.graalvm.wasm.test/src/test/wasi/fd_read-stdin-multi.opts create mode 100644 wasm/src/org.graalvm.wasm.test/src/test/wasi/fd_read-stdin-multi.result create mode 100644 wasm/src/org.graalvm.wasm.test/src/test/wasi/fd_read-stdin-multi.wat create mode 100644 wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/predefined/wasi/WasiFdFilestatSetTimesNode.java create mode 100644 wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/predefined/wasi/WasiUnsupportedFunctionNode.java diff --git a/wasm/src/org.graalvm.wasm.test/src/test/wasi/fd_read-stdin-eof.opts b/wasm/src/org.graalvm.wasm.test/src/test/wasi/fd_read-stdin-eof.opts new file mode 100644 index 000000000000..08c1b9fdd5df --- /dev/null +++ b/wasm/src/org.graalvm.wasm.test/src/test/wasi/fd_read-stdin-eof.opts @@ -0,0 +1,2 @@ +stdin=Hello Graal! 🚀 +zero-memory=true diff --git a/wasm/src/org.graalvm.wasm.test/src/test/wasi/fd_read-stdin-eof.result b/wasm/src/org.graalvm.wasm.test/src/test/wasi/fd_read-stdin-eof.result new file mode 100644 index 000000000000..2f381bfc96f1 --- /dev/null +++ b/wasm/src/org.graalvm.wasm.test/src/test/wasi/fd_read-stdin-eof.result @@ -0,0 +1 @@ +stdout Hello Graal! 🚀 \ No newline at end of file diff --git a/wasm/src/org.graalvm.wasm.test/src/test/wasi/fd_read-stdin-eof.wat b/wasm/src/org.graalvm.wasm.test/src/test/wasi/fd_read-stdin-eof.wat new file mode 100644 index 000000000000..64d2334d24de --- /dev/null +++ b/wasm/src/org.graalvm.wasm.test/src/test/wasi/fd_read-stdin-eof.wat @@ -0,0 +1,83 @@ +;; +;; Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved. +;; DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. +;; +;; The Universal Permissive License (UPL), Version 1.0 +;; +;; Subject to the condition set forth below, permission is hereby granted to any +;; person obtaining a copy of this software, associated documentation and/or +;; data (collectively the "Software"), free of charge and under any and all +;; copyright rights in the Software, and any and all patent rights owned or +;; freely licensable by each licensor hereunder covering either (i) the +;; unmodified Software as contributed to or provided by such licensor, or (ii) +;; the Larger Works (as defined below), to deal in both +;; +;; (a) the Software, and +;; +;; (b) any piece of software and/or hardware listed in the lrgrwrks.txt file if +;; one is included with the Software each a "Larger Work" to which the Software +;; is contributed by such licensors), +;; +;; without restriction, including without limitation the rights to copy, create +;; derivative works of, display, perform, and distribute the Software and make, +;; use, sell, offer for sale, import, export, have made, and have sold the +;; Software and the Larger Work(s), and to sublicense the foregoing rights on +;; either these or other terms. +;; +;; This license is subject to the following condition: +;; +;; The above copyright notice and either this complete permission notice or at a +;; minimum a reference to the UPL must be included in all copies or substantial +;; portions of the Software. +;; +;; THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +;; IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +;; FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +;; AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +;; LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +;; OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +;; SOFTWARE. +;; + +(module + (import "wasi_snapshot_preview1" "fd_read" (func $fd_read (param i32 i32 i32 i32) (result i32))) + (import "wasi_snapshot_preview1" "fd_write" (func $fd_write (param i32 i32 i32 i32) (result i32))) + (memory 1) + (export "memory" (memory 0)) + ;; iovec { buf = 24, buf_len = 24} + (data (i32.const 0) "\18\00\00\00\18\00\00\00") + ;; iovec { buf = 48, buf_len = 8} + (data (i32.const 8) "\28\00\00\00\08\00\00\00") + ;; iovec { buf = 24, buf_len = 17} + (data (i32.const 16) "\18\00\00\00\11\00\00\00") + (func (export "_main") (result i32) (local $ret i32) + ;; Read 17 bytes from stdin + (local.set $ret + (call $fd_read + (i32.const 0) ;; fd 0 (stdin) + (i32.const 0) ;; iovec at address 0 + (i32.const 2) ;; iovec size + (i32.const 64) ;; address at which to write the number of bytes read + ) + ) + ;; Exit in case of error + (if (i32.ne (local.get $ret) (i32.const 0)) (then (return (local.get $ret)))) + ;; Number of bytes read should equal 17 + (if (i32.ne (i32.load (i32.const 64)) (i32.const 17)) (then (return (i32.const -1)))) + + ;; Write path to stdout + (local.set $ret + (call $fd_write + (i32.const 1) ;; fd 1 (stdout) + (i32.const 16) ;; iovec at address 0 + (i32.const 1) ;; iovec size + (i32.const 68) ;; address at which to write the number of bytes written + ) + ) + ;; Exit in case of error + (if (i32.ne (local.get $ret) (i32.const 0)) (then (return (local.get $ret)))) + + ;; Success + (i32.const 0) + ) +) diff --git a/wasm/src/org.graalvm.wasm.test/src/test/wasi/fd_read-stdin-multi.opts b/wasm/src/org.graalvm.wasm.test/src/test/wasi/fd_read-stdin-multi.opts new file mode 100644 index 000000000000..08c1b9fdd5df --- /dev/null +++ b/wasm/src/org.graalvm.wasm.test/src/test/wasi/fd_read-stdin-multi.opts @@ -0,0 +1,2 @@ +stdin=Hello Graal! 🚀 +zero-memory=true diff --git a/wasm/src/org.graalvm.wasm.test/src/test/wasi/fd_read-stdin-multi.result b/wasm/src/org.graalvm.wasm.test/src/test/wasi/fd_read-stdin-multi.result new file mode 100644 index 000000000000..2f381bfc96f1 --- /dev/null +++ b/wasm/src/org.graalvm.wasm.test/src/test/wasi/fd_read-stdin-multi.result @@ -0,0 +1 @@ +stdout Hello Graal! 🚀 \ No newline at end of file diff --git a/wasm/src/org.graalvm.wasm.test/src/test/wasi/fd_read-stdin-multi.wat b/wasm/src/org.graalvm.wasm.test/src/test/wasi/fd_read-stdin-multi.wat new file mode 100644 index 000000000000..077a0a733dcc --- /dev/null +++ b/wasm/src/org.graalvm.wasm.test/src/test/wasi/fd_read-stdin-multi.wat @@ -0,0 +1,81 @@ +;; +;; Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved. +;; DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. +;; +;; The Universal Permissive License (UPL), Version 1.0 +;; +;; Subject to the condition set forth below, permission is hereby granted to any +;; person obtaining a copy of this software, associated documentation and/or +;; data (collectively the "Software"), free of charge and under any and all +;; copyright rights in the Software, and any and all patent rights owned or +;; freely licensable by each licensor hereunder covering either (i) the +;; unmodified Software as contributed to or provided by such licensor, or (ii) +;; the Larger Works (as defined below), to deal in both +;; +;; (a) the Software, and +;; +;; (b) any piece of software and/or hardware listed in the lrgrwrks.txt file if +;; one is included with the Software each a "Larger Work" to which the Software +;; is contributed by such licensors), +;; +;; without restriction, including without limitation the rights to copy, create +;; derivative works of, display, perform, and distribute the Software and make, +;; use, sell, offer for sale, import, export, have made, and have sold the +;; Software and the Larger Work(s), and to sublicense the foregoing rights on +;; either these or other terms. +;; +;; This license is subject to the following condition: +;; +;; The above copyright notice and either this complete permission notice or at a +;; minimum a reference to the UPL must be included in all copies or substantial +;; portions of the Software. +;; +;; THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +;; IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +;; FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +;; AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +;; LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +;; OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +;; SOFTWARE. +;; + +(module + (import "wasi_snapshot_preview1" "fd_read" (func $fd_read (param i32 i32 i32 i32) (result i32))) + (import "wasi_snapshot_preview1" "fd_write" (func $fd_write (param i32 i32 i32 i32) (result i32))) + (memory 1) + (export "memory" (memory 0)) + ;; iovec { buf = 16, buf_len = 8} + (data (i32.const 0) "\10\00\00\00\08\00\00\00") + ;; iovec { buf = 24, buf_len = 9 } + (data (i32.const 8) "\18\00\00\00\09\00\00\00") + (func (export "_main") (result i32) (local $ret i32) + ;; Read 17 bytes from stdin + (local.set $ret + (call $fd_read + (i32.const 0) ;; fd 0 (stdin) + (i32.const 0) ;; iovec at address 0 + (i32.const 2) ;; iovec size + (i32.const 36) ;; address at which to write the number of bytes read + ) + ) + ;; Exit in case of error + (if (i32.ne (local.get $ret) (i32.const 0)) (then (return (local.get $ret)))) + ;; Number of bytes read should equal 17 + (if (i32.ne (i32.load (i32.const 36)) (i32.const 17)) (then (return (i32.const -1)))) + + ;; Write path to stdout + (local.set $ret + (call $fd_write + (i32.const 1) ;; fd 1 (stdout) + (i32.const 0) ;; iovec at address 0 + (i32.const 2) ;; iovec size + (i32.const 40) ;; address at which to write the number of bytes written + ) + ) + ;; Exit in case of error + (if (i32.ne (local.get $ret) (i32.const 0)) (then (return (local.get $ret)))) + + ;; Success + (i32.const 0) + ) +) diff --git a/wasm/src/org.graalvm.wasm.test/src/test/wasi/wasm_test_index b/wasm/src/org.graalvm.wasm.test/src/test/wasi/wasm_test_index index c31b05b741bd..949088c17509 100644 --- a/wasm/src/org.graalvm.wasm.test/src/test/wasi/wasm_test_index +++ b/wasm/src/org.graalvm.wasm.test/src/test/wasi/wasm_test_index @@ -6,6 +6,8 @@ environ-sizes-get fd_prestat_get fd_prestat_dir_name fd_read-stdin +fd_read-stdin-eof +fd_read-stdin-multi fd_seek-file fd_fdstat_get-file fd_filestat_get-file diff --git a/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/predefined/wasi/WasiClockTimeGetNode.java b/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/predefined/wasi/WasiClockTimeGetNode.java index c7bf07bd893a..b79d39a3824d 100644 --- a/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/predefined/wasi/WasiClockTimeGetNode.java +++ b/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/predefined/wasi/WasiClockTimeGetNode.java @@ -81,6 +81,8 @@ private Object clockTimeGet(WasmMemory memory, int clockIdValue, int resultAddre memory.store_i64(this, resultAddress, realtimeNow()); break; case Monotonic: + memory.store_i64(this, resultAddress, monotonicNow()); + break; case ProcessCputimeId: case ThreadCputimeId: throw unimplementedClock(clockId); @@ -93,6 +95,11 @@ public static long realtimeNow() { return ChronoUnit.NANOS.between(Instant.EPOCH, Instant.now()); } + @TruffleBoundary + public static long monotonicNow() { + return System.nanoTime(); + } + @TruffleBoundary private static WasmException unimplementedClock(final Clockid clockId) { throw WasmException.create(Failure.UNSPECIFIED_INTERNAL, "Unimplemented ClockID: " + clockId.name()); diff --git a/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/predefined/wasi/WasiFdFilestatSetTimesNode.java b/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/predefined/wasi/WasiFdFilestatSetTimesNode.java new file mode 100644 index 000000000000..e47bf4219493 --- /dev/null +++ b/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/predefined/wasi/WasiFdFilestatSetTimesNode.java @@ -0,0 +1,80 @@ +/* + * Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * The Universal Permissive License (UPL), Version 1.0 + * + * Subject to the condition set forth below, permission is hereby granted to any + * person obtaining a copy of this software, associated documentation and/or + * data (collectively the "Software"), free of charge and under any and all + * copyright rights in the Software, and any and all patent rights owned or + * freely licensable by each licensor hereunder covering either (i) the + * unmodified Software as contributed to or provided by such licensor, or (ii) + * the Larger Works (as defined below), to deal in both + * + * (a) the Software, and + * + * (b) any piece of software and/or hardware listed in the lrgrwrks.txt file if + * one is included with the Software each a "Larger Work" to which the Software + * is contributed by such licensors), + * + * without restriction, including without limitation the rights to copy, create + * derivative works of, display, perform, and distribute the Software and make, + * use, sell, offer for sale, import, export, have made, and have sold the + * Software and the Larger Work(s), and to sublicense the foregoing rights on + * either these or other terms. + * + * This license is subject to the following condition: + * + * The above copyright notice and either this complete permission notice or at a + * minimum a reference to the UPL must be included in all copies or substantial + * portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package org.graalvm.wasm.predefined.wasi; + +import com.oracle.truffle.api.frame.VirtualFrame; +import org.graalvm.wasm.WasmArguments; +import org.graalvm.wasm.WasmContext; +import org.graalvm.wasm.WasmInstance; +import org.graalvm.wasm.WasmLanguage; +import org.graalvm.wasm.WasmModule; +import org.graalvm.wasm.predefined.WasmBuiltinRootNode; +import org.graalvm.wasm.predefined.wasi.fd.Fd; +import org.graalvm.wasm.predefined.wasi.types.Errno; + +public class WasiFdFilestatSetTimesNode extends WasmBuiltinRootNode { + protected WasiFdFilestatSetTimesNode(WasmLanguage language, WasmModule module) { + super(language, module); + } + + @Override + public Object executeWithContext(VirtualFrame frame, WasmContext context, WasmInstance instance) { + final Object[] args = frame.getArguments(); + return fdstatSetTime(context, + (int) WasmArguments.getArgument(args, 0), + (long) WasmArguments.getArgument(args, 1), + (long) WasmArguments.getArgument(args, 2), + (int) WasmArguments.getArgument(args, 3)); + } + + private int fdstatSetTime(WasmContext context, int fd, long atim, long mtim, int fstFlags) { + final Fd handle = context.fdManager().get(fd); + if (handle == null) { + return Errno.Badf.ordinal(); + } + return handle.fdstatSetTimes(this, atim, mtim, fstFlags).ordinal(); + } + + @Override + public String builtinNodeName() { + return "__wasi_fd_filestat_set_times"; + } +} diff --git a/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/predefined/wasi/WasiModule.java b/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/predefined/wasi/WasiModule.java index f41d35767a3b..ee22298f1b8b 100644 --- a/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/predefined/wasi/WasiModule.java +++ b/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/predefined/wasi/WasiModule.java @@ -60,39 +60,58 @@ protected WasmModule createModule(WasmLanguage language, WasmContext context, St } else { importMemory(context, module, "main", "memory", 0, MAX_MEMORY_DECLARATION_SIZE, false, false); } - defineFunction(context, module, "args_sizes_get", types(I32_TYPE, I32_TYPE), types(I32_TYPE), new WasiArgsSizesGetNode(language, module)); defineFunction(context, module, "args_get", types(I32_TYPE, I32_TYPE), types(I32_TYPE), new WasiArgsGetNode(language, module)); - defineFunction(context, module, "environ_sizes_get", types(I32_TYPE, I32_TYPE), types(I32_TYPE), new WasiEnvironSizesGetNode(language, module)); + defineFunction(context, module, "args_sizes_get", types(I32_TYPE, I32_TYPE), types(I32_TYPE), new WasiArgsSizesGetNode(language, module)); defineFunction(context, module, "environ_get", types(I32_TYPE, I32_TYPE), types(I32_TYPE), new WasiEnvironGetNode(language, module)); + defineFunction(context, module, "environ_sizes_get", types(I32_TYPE, I32_TYPE), types(I32_TYPE), new WasiEnvironSizesGetNode(language, module)); + defineFunction(context, module, "clock_res_get", types(I32_TYPE), types(I32_TYPE), new WasiUnsupportedFunctionNode(language, module, "__wasi_clock_res_get")); defineFunction(context, module, "clock_time_get", types(I32_TYPE, I64_TYPE, I32_TYPE), types(I32_TYPE), new WasiClockTimeGetNode(language, module)); - defineFunction(context, module, "proc_exit", types(I32_TYPE), types(), new WasiProcExitNode(language, module)); - defineFunction(context, module, "fd_write", types(I32_TYPE, I32_TYPE, I32_TYPE, I32_TYPE), types(I32_TYPE), new WasiFdWriteNode(language, module)); - defineFunction(context, module, "fd_read", types(I32_TYPE, I32_TYPE, I32_TYPE, I32_TYPE), types(I32_TYPE), new WasiFdReadNode(language, module)); + defineFunction(context, module, "fd_advise", types(I32_TYPE, I32_TYPE, I32_TYPE, I32_TYPE), types(I32_TYPE), new WasiUnsupportedFunctionNode(language, module, "__wasi_fd_advise")); + defineFunction(context, module, "fd_allocate", types(I32_TYPE, I32_TYPE, I32_TYPE), types(I32_TYPE), new WasiUnsupportedFunctionNode(language, module, "__wasi_fd_allocate")); defineFunction(context, module, "fd_close", types(I32_TYPE), types(I32_TYPE), new WasiFdCloseNode(language, module)); - defineFunction(context, module, "fd_seek", types(I32_TYPE, I64_TYPE, I32_TYPE, I32_TYPE), types(I32_TYPE), new WasiFdSeekNode(language, module)); + defineFunction(context, module, "fd_datasync", types(I32_TYPE), types(I32_TYPE), new WasiUnsupportedFunctionNode(language, module, "__wasi_fd_datasync")); defineFunction(context, module, "fd_fdstat_get", types(I32_TYPE, I32_TYPE), types(I32_TYPE), new WasiFdFdstatGetNode(language, module)); defineFunction(context, module, "fd_fdstat_set_flags", types(I32_TYPE, I32_TYPE), types(I32_TYPE), new WasiFdFdstatSetFlagsNode(language, module)); + defineFunction(context, module, "fd_fdstat_set_rights", types(I32_TYPE, I32_TYPE, I32_TYPE), types(I32_TYPE), new WasiUnsupportedFunctionNode(language, module, "__wasi_fd_fdstat_set_rights")); + defineFunction(context, module, "fd_filestat_get", types(I32_TYPE, I32_TYPE), types(I32_TYPE), new WasiFdFilestatGetNode(language, module)); + defineFunction(context, module, "fd_filestat_set_size", types(I32_TYPE, I32_TYPE), types(I32_TYPE), new WasiUnsupportedFunctionNode(language, module, "__wasi_fd_filestat_set_size")); + defineFunction(context, module, "fd_filestat_set_times", types(I32_TYPE, I64_TYPE, I64_TYPE, I32_TYPE), types(I32_TYPE), new WasiFdFilestatSetTimesNode(language, module)); + defineFunction(context, module, "fd_pread", types(I32_TYPE, I32_TYPE, I32_TYPE, I32_TYPE), types(I32_TYPE), new WasiUnsupportedFunctionNode(language, module, "__wasi_fd_pread")); defineFunction(context, module, "fd_prestat_get", types(I32_TYPE, I32_TYPE), types(I32_TYPE), new WasiFdPrestatGetNode(language, module)); defineFunction(context, module, "fd_prestat_dir_name", types(I32_TYPE, I32_TYPE, I32_TYPE), types(I32_TYPE), new WasiFdPrestatDirNameNode(language, module)); - defineFunction(context, module, "fd_filestat_get", types(I32_TYPE, I32_TYPE), types(I32_TYPE), new WasiFdFilestatGetNode(language, module)); - defineFunction(context, module, "path_open", types(I32_TYPE, I32_TYPE, I32_TYPE, I32_TYPE, I32_TYPE, I64_TYPE, I64_TYPE, I32_TYPE, I32_TYPE), types(I32_TYPE), - new WasiPathOpenNode(language, module)); + defineFunction(context, module, "fd_pwrite", types(I32_TYPE, I32_TYPE, I32_TYPE, I32_TYPE), types(I32_TYPE), new WasiUnsupportedFunctionNode(language, module, "__wasi_fd_pwrite")); + defineFunction(context, module, "fd_read", types(I32_TYPE, I32_TYPE, I32_TYPE, I32_TYPE), types(I32_TYPE), new WasiFdReadNode(language, module)); + defineFunction(context, module, "fd_readdir", types(I32_TYPE, I32_TYPE, I32_TYPE, I64_TYPE), types(I32_TYPE), new WasiUnsupportedFunctionNode(language, module, "__wasi_fd_readdir")); + defineFunction(context, module, "fd_renumber", types(I32_TYPE, I32_TYPE), types(I32_TYPE), new WasiUnsupportedFunctionNode(language, module, "__wasi_fd_renumber")); + defineFunction(context, module, "fd_seek", types(I32_TYPE, I64_TYPE, I32_TYPE, I32_TYPE), types(I32_TYPE), new WasiFdSeekNode(language, module)); + defineFunction(context, module, "fd_sync", types(I32_TYPE), types(I32_TYPE), new WasiUnsupportedFunctionNode(language, module, "__wasi_fd_sync")); + defineFunction(context, module, "fd_tell", types(I32_TYPE), types(I32_TYPE), new WasiUnsupportedFunctionNode(language, module, "__wasi_fd_tell")); + defineFunction(context, module, "fd_write", types(I32_TYPE, I32_TYPE, I32_TYPE, I32_TYPE), types(I32_TYPE), new WasiFdWriteNode(language, module)); defineFunction(context, module, "path_create_directory", types(I32_TYPE, I32_TYPE, I32_TYPE), types(I32_TYPE), new WasiPathCreateDirectoryNode(language, module)); - defineFunction(context, module, "path_remove_directory", types(I32_TYPE, I32_TYPE, I32_TYPE), types(I32_TYPE), new WasiPathRemoveDirectoryNode(language, module)); + defineFunction(context, module, "path_filestat_get", types(I32_TYPE, I32_TYPE, I32_TYPE, I32_TYPE, I32_TYPE), types(I32_TYPE), new WasiPathFileStatGetNode(language, module)); defineFunction(context, module, "path_filestat_set_times", types(I32_TYPE, I32_TYPE, I32_TYPE, I32_TYPE, I64_TYPE, I64_TYPE, I32_TYPE), types(I32_TYPE), new WasiPathFilestatSetTimesNode(language, module)); defineFunction(context, module, "path_link", types(I32_TYPE, I32_TYPE, I32_TYPE, I32_TYPE, I32_TYPE, I32_TYPE, I32_TYPE), types(I32_TYPE), new WasiPathLinkNode(language, module)); + defineFunction(context, module, "path_open", types(I32_TYPE, I32_TYPE, I32_TYPE, I32_TYPE, I32_TYPE, I64_TYPE, I64_TYPE, I32_TYPE, I32_TYPE), types(I32_TYPE), + new WasiPathOpenNode(language, module)); + defineFunction(context, module, "path_readlink", types(I32_TYPE, I32_TYPE, I32_TYPE, I32_TYPE, I32_TYPE), types(I32_TYPE), new WasiPathReadLinkNode(language, module)); + defineFunction(context, module, "path_remove_directory", types(I32_TYPE, I32_TYPE, I32_TYPE), types(I32_TYPE), new WasiPathRemoveDirectoryNode(language, module)); defineFunction(context, module, "path_rename", types(I32_TYPE, I32_TYPE, I32_TYPE, I32_TYPE, I32_TYPE, I32_TYPE), types(I32_TYPE), new WasiPathRenameNode(language, module)); defineFunction(context, module, "path_symlink", types(I32_TYPE, I32_TYPE, I32_TYPE, I32_TYPE, I32_TYPE), types(I32_TYPE), new WasiPathSymlinkNode(language, module)); defineFunction(context, module, "path_unlink_file", types(I32_TYPE, I32_TYPE, I32_TYPE), types(I32_TYPE), new WasiPathUnlinkFileNode(language, module)); - defineFunction(context, module, "path_readlink", types(I32_TYPE, I32_TYPE, I32_TYPE, I32_TYPE, I32_TYPE), types(I32_TYPE), new WasiPathReadLinkNode(language, module)); - defineFunction(context, module, "path_filestat_get", types(I32_TYPE, I32_TYPE, I32_TYPE, I32_TYPE, I32_TYPE), types(I32_TYPE), new WasiPathFileStatGetNode(language, module)); + defineFunction(context, module, "poll_oneoff", types(I32_TYPE, I32_TYPE, I32_TYPE, I32_TYPE), types(I32_TYPE), new WasiUnsupportedFunctionNode(language, module, "__wasi_poll_oneoff")); + defineFunction(context, module, "proc_exit", types(I32_TYPE), types(), new WasiProcExitNode(language, module)); + defineFunction(context, module, "proc_raise", types(I32_TYPE), types(I32_TYPE), new WasiUnsupportedFunctionNode(language, module, "__wasi_proc_raise")); defineFunction(context, module, "sched_yield", types(), types(I32_TYPE), new WasiSchedYieldNode(language, module)); if (context.getContextOptions().constantRandomGet()) { defineFunction(context, module, "random_get", types(I32_TYPE, I32_TYPE), types(I32_TYPE), new WasiConstantRandomGetNode(language, module)); } else { defineFunction(context, module, "random_get", types(I32_TYPE, I32_TYPE), types(I32_TYPE), new WasiRandomGetNode(language, module)); } + defineFunction(context, module, "sock_accept", types(I32_TYPE, I32_TYPE), types(I32_TYPE), new WasiUnsupportedFunctionNode(language, module, "__wasi_sock_accept")); + defineFunction(context, module, "sock_recv", types(I32_TYPE, I32_TYPE, I32_TYPE, I32_TYPE), types(I32_TYPE), new WasiUnsupportedFunctionNode(language, module, "__wasi_sock_recv")); + defineFunction(context, module, "sock_send", types(I32_TYPE, I32_TYPE, I32_TYPE, I32_TYPE), types(I32_TYPE), new WasiUnsupportedFunctionNode(language, module, "__wasi_sock_send")); + defineFunction(context, module, "sock_shutdown", types(I32_TYPE, I32_TYPE), types(I32_TYPE), new WasiUnsupportedFunctionNode(language, module, "__wasi_sock_shutdown")); return module; } diff --git a/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/predefined/wasi/WasiUnsupportedFunctionNode.java b/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/predefined/wasi/WasiUnsupportedFunctionNode.java new file mode 100644 index 000000000000..0ecb29fc6327 --- /dev/null +++ b/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/predefined/wasi/WasiUnsupportedFunctionNode.java @@ -0,0 +1,69 @@ +/* + * Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * The Universal Permissive License (UPL), Version 1.0 + * + * Subject to the condition set forth below, permission is hereby granted to any + * person obtaining a copy of this software, associated documentation and/or + * data (collectively the "Software"), free of charge and under any and all + * copyright rights in the Software, and any and all patent rights owned or + * freely licensable by each licensor hereunder covering either (i) the + * unmodified Software as contributed to or provided by such licensor, or (ii) + * the Larger Works (as defined below), to deal in both + * + * (a) the Software, and + * + * (b) any piece of software and/or hardware listed in the lrgrwrks.txt file if + * one is included with the Software each a "Larger Work" to which the Software + * is contributed by such licensors), + * + * without restriction, including without limitation the rights to copy, create + * derivative works of, display, perform, and distribute the Software and make, + * use, sell, offer for sale, import, export, have made, and have sold the + * Software and the Larger Work(s), and to sublicense the foregoing rights on + * either these or other terms. + * + * This license is subject to the following condition: + * + * The above copyright notice and either this complete permission notice or at a + * minimum a reference to the UPL must be included in all copies or substantial + * portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package org.graalvm.wasm.predefined.wasi; + +import org.graalvm.wasm.WasmContext; +import org.graalvm.wasm.WasmInstance; +import org.graalvm.wasm.WasmLanguage; +import org.graalvm.wasm.WasmModule; +import org.graalvm.wasm.predefined.WasmBuiltinRootNode; +import org.graalvm.wasm.predefined.wasi.types.Errno; + +import com.oracle.truffle.api.frame.VirtualFrame; + +public class WasiUnsupportedFunctionNode extends WasmBuiltinRootNode { + private final String name; + + protected WasiUnsupportedFunctionNode(WasmLanguage language, WasmModule module, String name) { + super(language, module); + this.name = name; + } + + @Override + public Object executeWithContext(VirtualFrame frame, WasmContext context, WasmInstance instance) { + return Errno.Nosys; // error code for function not supported + } + + @Override + public String builtinNodeName() { + return name; + } +} diff --git a/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/predefined/wasi/fd/Fd.java b/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/predefined/wasi/fd/Fd.java index 753eb762d903..2d95a8ae0b7e 100644 --- a/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/predefined/wasi/fd/Fd.java +++ b/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/predefined/wasi/fd/Fd.java @@ -295,6 +295,25 @@ public Errno fdstatSetFlags(Node node, WasmMemory memory, short fdflags) { return Errno.Acces; } + /** + * + * Implementation of WASI fd_fdstat_set_times: + * adjusts the times associated with this file descriptor. + * + * @param node the calling node, used as location for any thrown {@link WasmException} + * @param atim the desired values of the data access timestamp + * @param mtim the desired values of the data modification timestamp + * @param fstFlags bitmap of {@link Fstflags} + * @return {@link Errno#Success} in case of success, or another {@link Errno} in case of error + */ + public Errno fdstatSetTimes(Node node, long atim, long mtim, int fstFlags) { + if (!isSet(fsRightsBase, Rights.FdFilestatSetTimes)) { + return Errno.Notcapable; + } + return Errno.Acces; + } + /** * Implementation of WASI fd_filestat_get: diff --git a/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/predefined/wasi/fd/FdUtils.java b/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/predefined/wasi/fd/FdUtils.java index 39d4bee0855d..8084a3dab9c7 100644 --- a/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/predefined/wasi/fd/FdUtils.java +++ b/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/predefined/wasi/fd/FdUtils.java @@ -79,7 +79,7 @@ static Errno writeToStream(Node node, WasmMemory memory, OutputStream stream, in return Errno.Io; } - memory.store_i32(null, sizeAddress, totalBytesWritten); + memory.store_i32(node, sizeAddress, totalBytesWritten); return Errno.Success; } @@ -94,22 +94,17 @@ static Errno readFromStream(Node node, WasmMemory memory, InputStream stream, in final int iovecAddress = iovecArrayAddress + i * Iovec.BYTES; final int start = Iovec.readBuf(node, memory, iovecAddress); final int len = Iovec.readBufLen(node, memory, iovecAddress); - int offset = 0; - int bytesRead; - while (offset < len) { - bytesRead = memory.copyFromStream(node, stream, start + offset, len - offset); - if (bytesRead == -1) { - break; - } - offset += bytesRead; - totalBytesRead += bytesRead; + final int bytesRead = memory.copyFromStream(node, stream, start, len); + if (bytesRead == -1) { + break; } + totalBytesRead += bytesRead; } } catch (IOException e) { return Errno.Io; } - memory.store_i32(null, sizeAddress, totalBytesRead); + memory.store_i32(node, sizeAddress, totalBytesRead); return Errno.Success; } diff --git a/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/predefined/wasi/fd/FileFd.java b/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/predefined/wasi/fd/FileFd.java index 343f6d6b66dd..89e5de4b92d8 100644 --- a/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/predefined/wasi/fd/FileFd.java +++ b/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/predefined/wasi/fd/FileFd.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 2023, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * The Universal Permissive License (UPL), Version 1.0 @@ -45,9 +45,11 @@ import com.oracle.truffle.api.nodes.Node; import org.graalvm.polyglot.io.FileSystem; import org.graalvm.wasm.memory.WasmMemory; +import org.graalvm.wasm.predefined.wasi.WasiClockTimeGetNode; import org.graalvm.wasm.predefined.wasi.types.Errno; import org.graalvm.wasm.predefined.wasi.types.Fdflags; import org.graalvm.wasm.predefined.wasi.types.Filetype; +import org.graalvm.wasm.predefined.wasi.types.Fstflags; import org.graalvm.wasm.predefined.wasi.types.Oflags; import org.graalvm.wasm.predefined.wasi.types.Rights; @@ -56,8 +58,10 @@ import java.nio.file.OpenOption; import java.nio.file.StandardOpenOption; import java.nio.file.attribute.FileAttribute; +import java.nio.file.attribute.FileTime; import java.util.LinkedHashSet; import java.util.Set; +import java.util.concurrent.TimeUnit; import static org.graalvm.wasm.predefined.wasi.FlagUtils.isSet; @@ -163,4 +167,29 @@ public Errno fdstatSetFlags(Node node, WasmMemory memory, short newFsflags) { } } + @Override + public Errno fdstatSetTimes(Node node, long atim, long mtim, int fstFlags) { + if (!isSet(fsRightsBase, Rights.FdFilestatSetTimes)) { + return Errno.Notcapable; + } + try { + if (isSet(fstFlags, Fstflags.Atim)) { + file.setLastAccessTime(FileTime.from(atim, TimeUnit.NANOSECONDS)); + } + if (isSet(fstFlags, Fstflags.AtimNow)) { + file.setLastAccessTime(FileTime.from(WasiClockTimeGetNode.realtimeNow(), TimeUnit.NANOSECONDS)); + } + if (isSet(fstFlags, Fstflags.Mtim)) { + file.setLastModifiedTime(FileTime.from(mtim, TimeUnit.NANOSECONDS)); + } + if (isSet(fstFlags, Fstflags.MtimNow)) { + file.setLastModifiedTime(FileTime.from(WasiClockTimeGetNode.realtimeNow(), TimeUnit.NANOSECONDS)); + } + } catch (IOException e) { + return Errno.Io; + } catch (SecurityException e) { + return Errno.Acces; + } + return Errno.Success; + } } From 21ea752c4a4b48e7aa888da224ee4491dca7e131 Mon Sep 17 00:00:00 2001 From: Olya Gupalo Date: Wed, 29 Nov 2023 18:18:15 +0100 Subject: [PATCH 005/593] Update Maven command for Native Image building --- docs/reference-manual/native-image/Bundles.md | 20 +++---------------- 1 file changed, 3 insertions(+), 17 deletions(-) diff --git a/docs/reference-manual/native-image/Bundles.md b/docs/reference-manual/native-image/Bundles.md index 4231e248d31e..0e3de86ac14c 100644 --- a/docs/reference-manual/native-image/Bundles.md +++ b/docs/reference-manual/native-image/Bundles.md @@ -61,19 +61,12 @@ For that, the following needs to be added to the plugins section of `pom.xml`: ``` -Then, when you run the Maven package command `./mvnw package -Dpackaging=native-image`, you will get the following build artifacts: +Then, when you run the Maven package command `mvn -Pnative native:compile`, you will get the following build artifacts: ``` Finished generating 'micronautguide' in 2m 0s. Native Image Bundles: Bundle build output written to /home/testuser/micronaut-data-jdbc-repository-maven-java/target/micronautguide.output Native Image Bundles: Bundle written to /home/testuser/micronaut-data-jdbc-repository-maven-java/target/micronautguide.nib - -[INFO] ------------------------------------------------------------------------ -[INFO] BUILD SUCCESS -[INFO] ------------------------------------------------------------------------ -[INFO] Total time: 02:08 min -[INFO] Finished at: 2023-03-27T15:09:36+02:00 -[INFO] ------------------------------------------------------------------------ ``` This output indicates that you have created a native executable, `micronautguide`, and a bundle, _micronautguide.nib_. @@ -139,16 +132,9 @@ target/micronautguide.output As mentioned in the `--bundle-create` option description, it is also possible to let `native-image` build a bundle but not actually perform the image building. This might be useful if a user wants to move the bundle to a more powerful machine and build the image there. Modify the `--bundle-create` argument in the `native-maven-plugin` configuration above to `--bundle-create,dry-run`. -Then running `./mvnw package -Dpackaging=native-image` takes only seconds and the created bundle is much smaller: +Then running `mvn -Pnative native:compile` takes only seconds and the created bundle is much smaller: ``` Native Image Bundles: Bundle written to /home/testuser/micronaut-data-jdbc-repository-maven-java/target/micronautguide.nib - -[INFO] ------------------------------------------------------------------------ -[INFO] BUILD SUCCESS -[INFO] ------------------------------------------------------------------------ -[INFO] Total time: 2.267 s -[INFO] Finished at: 2023-03-27T16:33:21+02:00 -[INFO] ------------------------------------------------------------------------ ``` Now _micronautguide.nib_ is only 20 MB in file size and the executable is not included: @@ -381,7 +367,7 @@ $ native-image --bundle-apply=micronautguide-pgo-optimized.nib ... ``` -## Executing the bundled application +## Executing a Bundled Application As described later in [Bundle File Format](#bundle-file-format), a bundle file is a JAR file with a contained launcher for launching the bundled application. This means you can use a native image bundle with any JDK and execute it as a JAR file with `/bin/java -jar [bundle-file.nib]`. From f10fec38c4d17e1554dd6beb43c89e627a5b3f75 Mon Sep 17 00:00:00 2001 From: ol-automation_ww Date: Thu, 30 Nov 2023 10:05:11 +0000 Subject: [PATCH 006/593] update to 22+26-jvmci-b01 --- common.json | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/common.json b/common.json index ac12c51f98e9..291812be3319 100644 --- a/common.json +++ b/common.json @@ -43,12 +43,12 @@ "labsjdk-ee-21-llvm": {"name": "labsjdk", "version": "ee-21.0.1+11-jvmci-23.1-b22-sulong", "platformspecific": true }, "oraclejdk-latest": {"name": "jpg-jdk", "version": "22", "build_id": "25", "release": true, "platformspecific": true, "extrabundles": ["static-libs"]}, - "labsjdk-ce-latest": {"name": "labsjdk", "version": "ce-22+25-jvmci-b01", "platformspecific": true }, - "labsjdk-ce-latestDebug": {"name": "labsjdk", "version": "ce-22+25-jvmci-b01-debug", "platformspecific": true }, - "labsjdk-ce-latest-llvm": {"name": "labsjdk", "version": "ce-22+25-jvmci-b01-sulong", "platformspecific": true }, - "labsjdk-ee-latest": {"name": "labsjdk", "version": "ee-22+25-jvmci-b01", "platformspecific": true }, - "labsjdk-ee-latestDebug": {"name": "labsjdk", "version": "ee-22+25-jvmci-b01-debug", "platformspecific": true }, - "labsjdk-ee-latest-llvm": {"name": "labsjdk", "version": "ee-22+25-jvmci-b01-sulong", "platformspecific": true } + "labsjdk-ce-latest": {"name": "labsjdk", "version": "ce-22+26-jvmci-b01-20231130090102-fe1c594adf", "platformspecific": true }, + "labsjdk-ce-latestDebug": {"name": "labsjdk", "version": "ce-22+26-jvmci-b01-20231130090102-fe1c594adf-debug", "platformspecific": true }, + "labsjdk-ce-latest-llvm": {"name": "labsjdk", "version": "ce-22+26-jvmci-b01-20231130090102-fe1c594adf-sulong", "platformspecific": true }, + "labsjdk-ee-latest": {"name": "labsjdk", "version": "ee-22+26-jvmci-b01-20231130090102-fe1c594adf+48b72ef516", "platformspecific": true }, + "labsjdk-ee-latestDebug": {"name": "labsjdk", "version": "ee-22+26-jvmci-b01-20231130090102-fe1c594adf+48b72ef516-debug", "platformspecific": true }, + "labsjdk-ee-latest-llvm": {"name": "labsjdk", "version": "ee-22+26-jvmci-b01-20231130090102-fe1c594adf+48b72ef516-sulong", "platformspecific": true } }, "eclipse": { From 4b7846f67b7515fb3c9a8a2399195ebde5b8e35c Mon Sep 17 00:00:00 2001 From: Josef Eisl Date: Thu, 30 Nov 2023 11:38:41 +0000 Subject: [PATCH 007/593] ci: update oraclejdk-latest to 22+26 --- common.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/common.json b/common.json index 291812be3319..d6138f626e36 100644 --- a/common.json +++ b/common.json @@ -42,7 +42,7 @@ "labsjdk-ee-21Debug": {"name": "labsjdk", "version": "ee-21.0.1+11-jvmci-23.1-b22-debug", "platformspecific": true }, "labsjdk-ee-21-llvm": {"name": "labsjdk", "version": "ee-21.0.1+11-jvmci-23.1-b22-sulong", "platformspecific": true }, - "oraclejdk-latest": {"name": "jpg-jdk", "version": "22", "build_id": "25", "release": true, "platformspecific": true, "extrabundles": ["static-libs"]}, + "oraclejdk-latest": {"name": "jpg-jdk", "version": "22", "build_id": "26", "release": true, "platformspecific": true, "extrabundles": ["static-libs"]}, "labsjdk-ce-latest": {"name": "labsjdk", "version": "ce-22+26-jvmci-b01-20231130090102-fe1c594adf", "platformspecific": true }, "labsjdk-ce-latestDebug": {"name": "labsjdk", "version": "ce-22+26-jvmci-b01-20231130090102-fe1c594adf-debug", "platformspecific": true }, "labsjdk-ce-latest-llvm": {"name": "labsjdk", "version": "ce-22+26-jvmci-b01-20231130090102-fe1c594adf-sulong", "platformspecific": true }, From bf9d7d07673148c61e371ded739311decbb2bd61 Mon Sep 17 00:00:00 2001 From: Marouane El Hallaoui Date: Thu, 30 Nov 2023 13:35:19 +0100 Subject: [PATCH 008/593] update JVMCIVersionCheck --- .../src/jdk/graal/compiler/hotspot/JVMCIVersionCheck.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/JVMCIVersionCheck.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/JVMCIVersionCheck.java index 7f9e37b8c63d..2eb8499a216d 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/JVMCIVersionCheck.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/JVMCIVersionCheck.java @@ -54,8 +54,8 @@ public final class JVMCIVersionCheck { private static final Map> JVMCI_MIN_VERSIONS = Map.of( "21", Map.of(DEFAULT_VENDOR_ENTRY, new Version(23, 1, 22)), "22", Map.of( - "Oracle Corporation", new Version("22+25", 1), - DEFAULT_VENDOR_ENTRY, new Version("22+25", 1))); + "Oracle Corporation", new Version("22+26", 1), + DEFAULT_VENDOR_ENTRY, new Version("22+26", 1))); private static final int NA = 0; /** * Minimum Java release supported by Graal. From 39d3a577bb5364502158c1e91f72e51ed9ccba2d Mon Sep 17 00:00:00 2001 From: Gilles Duboscq Date: Mon, 27 Nov 2023 19:35:37 +0100 Subject: [PATCH 009/593] Avoid sharing bytecode between "no substitutions" call targets It's not safe to share the `code` array between multiple BytecodeNodes because of quickening since the various bytecode nodes will not have the same quick nodes. This fixes `getCallTargetNoSubstitution` which could previously return multiple different call targets for the same MethodVersion --- .../oracle/truffle/espresso/impl/Method.java | 21 ++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/impl/Method.java b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/impl/Method.java index e428fdedd317..cd31960c2556 100644 --- a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/impl/Method.java +++ b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/impl/Method.java @@ -1076,6 +1076,7 @@ public final class MethodVersion implements MethodRef, ModifiersProvider { private final ExceptionsAttribute exceptionsAttribute; @CompilationFinal private CallTarget callTarget; + @CompilationFinal private CallTarget callTargetNoSubstitutions; @CompilationFinal private int vtableIndex = -1; @CompilationFinal private int itableIndex = -1; @@ -1232,7 +1233,21 @@ private CallTarget getCallTargetNoSubstitution() { CompilerAsserts.neverPartOfCompilation(); EspressoError.guarantee(getSubstitutions().hasSubstitutionFor(getMethod()), "Using 'getCallTargetNoSubstitution' should be done only to bypass the substitution mechanism."); - return findCallTarget(); + if (callTargetNoSubstitutions == null) { + synchronized (this) { + if (callTargetNoSubstitutions == null) { + EspressoRootNode redirectedMethod = getSubstitutions().get(getMethod()); + if (redirectedMethod == null) { + // no substitution, use standard call target + getContext().getLogger().warning("Using getCallTargetNoSubstitution() for " + this + " but there is no substitution available"); + callTargetNoSubstitutions = getCallTarget(); + } else { + callTargetNoSubstitutions = findCallTarget(); + } + } + } + } + return callTargetNoSubstitutions; } public CallTarget getCallTarget() { @@ -1268,6 +1283,10 @@ private void resolveCallTarget() { callTarget = redirectedMethod.getCallTarget(); return; } + if (callTargetNoSubstitutions != null) { + callTarget = callTargetNoSubstitutions; + return; + } CallTarget target = findCallTarget(); if (target != null) { From 10c99ba3ec1e4ef826df94fe8cb359f1d6e7feb0 Mon Sep 17 00:00:00 2001 From: Gilles Duboscq Date: Thu, 30 Nov 2023 15:50:00 +0100 Subject: [PATCH 010/593] Use enforced guarantee to simplify getCallTargetNoSubstitution --- .../com/oracle/truffle/espresso/impl/Method.java | 14 ++------------ 1 file changed, 2 insertions(+), 12 deletions(-) diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/impl/Method.java b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/impl/Method.java index cd31960c2556..d4bb9f1961d8 100644 --- a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/impl/Method.java +++ b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/impl/Method.java @@ -1236,14 +1236,7 @@ private CallTarget getCallTargetNoSubstitution() { if (callTargetNoSubstitutions == null) { synchronized (this) { if (callTargetNoSubstitutions == null) { - EspressoRootNode redirectedMethod = getSubstitutions().get(getMethod()); - if (redirectedMethod == null) { - // no substitution, use standard call target - getContext().getLogger().warning("Using getCallTargetNoSubstitution() for " + this + " but there is no substitution available"); - callTargetNoSubstitutions = getCallTarget(); - } else { - callTargetNoSubstitutions = findCallTarget(); - } + callTargetNoSubstitutions = findCallTarget(); } } } @@ -1283,10 +1276,7 @@ private void resolveCallTarget() { callTarget = redirectedMethod.getCallTarget(); return; } - if (callTargetNoSubstitutions != null) { - callTarget = callTargetNoSubstitutions; - return; - } + assert callTargetNoSubstitutions == null; CallTarget target = findCallTarget(); if (target != null) { From 939b43e5e774b28e0c889cf6e4fe3088ad19d6ff Mon Sep 17 00:00:00 2001 From: Josef Haider Date: Thu, 30 Nov 2023 11:27:17 +0100 Subject: [PATCH 011/593] Allow default value in minimum cpu flags parameters in GenerateStub annotation --- .../lir/processor/IntrinsicStubProcessor.java | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/compiler/src/jdk.graal.compiler.processor/src/jdk/graal/compiler/lir/processor/IntrinsicStubProcessor.java b/compiler/src/jdk.graal.compiler.processor/src/jdk/graal/compiler/lir/processor/IntrinsicStubProcessor.java index 7a57ac3012a7..0ba8bc48417d 100644 --- a/compiler/src/jdk.graal.compiler.processor/src/jdk/graal/compiler/lir/processor/IntrinsicStubProcessor.java +++ b/compiler/src/jdk.graal.compiler.processor/src/jdk/graal/compiler/lir/processor/IntrinsicStubProcessor.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2023, 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 @@ -298,7 +298,9 @@ private void createStubs(AbstractProcessor processor, TargetVM targetVM, TypeEle "jdk.graal.compiler.debug.GraalError", "org.graalvm.nativeimage.ImageSingletons", "java.util.EnumSet", - "jdk.vm.ci.code.Architecture")); + "jdk.vm.ci.code.Architecture", + "jdk.vm.ci.aarch64.AArch64", + "jdk.vm.ci.amd64.AMD64")); break; } for (GenerateStubClass genClass : classes) { @@ -318,9 +320,9 @@ private void createStubs(AbstractProcessor processor, TargetVM targetVM, TypeEle } } out.printf("\n"); - out.printf("public class %s", genClassName); + out.printf("public class %s ", genClassName); if (targetVM == TargetVM.hotspot) { - out.printf(" extends SnippetStub "); + out.printf("extends SnippetStub "); } out.printf("{\n"); if (targetVM == TargetVM.hotspot) { @@ -328,6 +330,9 @@ private void createStubs(AbstractProcessor processor, TargetVM targetVM, TypeEle out.printf(" public %s(OptionValues options, HotSpotProviders providers, HotSpotForeignCallLinkage linkage) {\n", genClassName); out.printf(" super(linkage.getDescriptor().getName(), options, providers, linkage);\n"); out.printf(" }\n"); + } else { + out.printf(" private static final EnumSet EMPTY_CPU_FEATURES_AMD64 = EnumSet.noneOf(AMD64.CPUFeature.class);\n"); + out.printf(" private static final EnumSet EMPTY_CPU_FEATURES_AARCH64 = EnumSet.noneOf(AArch64.CPUFeature.class);\n"); } out.printf("\n"); for (GenerateStubClass genClass : classes) { @@ -340,14 +345,14 @@ private void createStubs(AbstractProcessor processor, TargetVM targetVM, TypeEle out.printf(" Architecture arch = ImageSingletons.lookup(SubstrateTargetDescription.class).arch;\n"); out.printf(" if (arch instanceof jdk.vm.ci.amd64.AMD64) {\n"); if (featuresGetter.amd64Getter.isEmpty()) { - out.printf(" throw GraalError.shouldNotReachHere(\"not implemented\");\n"); + out.printf(" return EMPTY_CPU_FEATURES_AMD64;\n"); } else { out.printf(" return %s.%s();\n", genClass.clazz.getSimpleName(), featuresGetter.amd64Getter); } out.printf(" }\n"); out.printf(" if (arch instanceof jdk.vm.ci.aarch64.AArch64) {\n"); if (featuresGetter.aarch64Getter.isEmpty()) { - out.printf(" throw GraalError.shouldNotReachHere(\"not implemented\");\n"); + out.printf(" return EMPTY_CPU_FEATURES_AARCH64;\n"); } else { out.printf(" return %s.%s();\n", genClass.clazz.getSimpleName(), featuresGetter.aarch64Getter); } From 3d00088a789c19a8c570c8af4e7558a8dac4b7c7 Mon Sep 17 00:00:00 2001 From: Andreas Woess Date: Fri, 17 Nov 2023 15:06:37 +0100 Subject: [PATCH 012/593] Port vectorizedHashCode intrinsic to AArch64. --- .../core/aarch64/AArch64LIRGenerator.java | 9 + .../AArch64HotSpotForeignCallsProvider.java | 6 +- .../aarch64/AArch64VectorizedHashCodeOp.java | 455 ++++++++++++++++++ .../nodes/VectorizedHashCodeNode.java | 7 +- .../stubs/AArch64StubForeignCallsFeature.java | 13 +- 5 files changed, 482 insertions(+), 8 deletions(-) create mode 100644 compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/aarch64/AArch64VectorizedHashCodeOp.java diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/core/aarch64/AArch64LIRGenerator.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/core/aarch64/AArch64LIRGenerator.java index 0b60b9bd3f9e..136c34b6f8c8 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/core/aarch64/AArch64LIRGenerator.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/core/aarch64/AArch64LIRGenerator.java @@ -95,6 +95,7 @@ import jdk.graal.compiler.lir.aarch64.AArch64SpeculativeBarrier; import jdk.graal.compiler.lir.aarch64.AArch64StringLatin1InflateOp; import jdk.graal.compiler.lir.aarch64.AArch64StringUTF16CompressOp; +import jdk.graal.compiler.lir.aarch64.AArch64VectorizedHashCodeOp; import jdk.graal.compiler.lir.aarch64.AArch64VectorizedMismatchOp; import jdk.graal.compiler.lir.aarch64.AArch64ZapRegistersOp; import jdk.graal.compiler.lir.aarch64.AArch64ZapStackOp; @@ -811,6 +812,14 @@ public Variable emitVectorizedMismatch(EnumSet runtimeCheckedCPUFeatures, Val return result; } + @Override + public Variable emitVectorizedHashCode(EnumSet runtimeCheckedCPUFeatures, Value arrayStart, Value length, Value initialValue, JavaKind arrayKind) { + Variable result = newVariable(LIRKind.value(AArch64Kind.DWORD)); + append(new AArch64VectorizedHashCodeOp(this, + result, asAllocatable(arrayStart), asAllocatable(length), asAllocatable(initialValue), arrayKind)); + return result; + } + @Override protected JavaConstant zapValueForKind(PlatformKind kind) { long dead = 0xDEADDEADDEADDEADL; diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/aarch64/AArch64HotSpotForeignCallsProvider.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/aarch64/AArch64HotSpotForeignCallsProvider.java index 4e8db7e6924e..5f737ffda83a 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/aarch64/AArch64HotSpotForeignCallsProvider.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/aarch64/AArch64HotSpotForeignCallsProvider.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 2023, 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 @@ -35,7 +35,9 @@ import jdk.graal.compiler.hotspot.HotSpotGraalRuntimeProvider; import jdk.graal.compiler.hotspot.meta.HotSpotHostForeignCallsProvider; import jdk.graal.compiler.hotspot.meta.HotSpotProviders; +import jdk.graal.compiler.hotspot.stubs.IntrinsicStubsGen; import jdk.graal.compiler.options.OptionValues; +import jdk.graal.compiler.replacements.nodes.VectorizedHashCodeNode; import jdk.graal.compiler.word.WordTypes; import jdk.vm.ci.code.CallingConvention; @@ -71,6 +73,8 @@ public void initialize(HotSpotProviders providers, OptionValues options) { register(new HotSpotForeignCallLinkageImpl(HotSpotBackend.EXCEPTION_HANDLER_IN_CALLER, HotSpotForeignCallLinkage.JUMP_ADDRESS, HotSpotForeignCallLinkage.RegisterEffect.DESTROYS_ALL_CALLER_SAVE_REGISTERS, exceptionCc, null)); + linkSnippetStubs(providers, options, IntrinsicStubsGen::new, VectorizedHashCodeNode.STUBS); + super.initialize(providers, options); } diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/aarch64/AArch64VectorizedHashCodeOp.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/aarch64/AArch64VectorizedHashCodeOp.java new file mode 100644 index 000000000000..73003d6d3e0d --- /dev/null +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/aarch64/AArch64VectorizedHashCodeOp.java @@ -0,0 +1,455 @@ +/* + * Copyright (c) 2023, 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 jdk.graal.compiler.lir.aarch64; + +import static jdk.vm.ci.code.ValueUtil.asRegister; + +import jdk.graal.compiler.asm.Label; +import jdk.graal.compiler.asm.aarch64.AArch64ASIMDAssembler.ASIMDInstruction; +import jdk.graal.compiler.asm.aarch64.AArch64ASIMDAssembler.ASIMDSize; +import jdk.graal.compiler.asm.aarch64.AArch64ASIMDAssembler.ElementSize; +import jdk.graal.compiler.asm.aarch64.AArch64Address; +import jdk.graal.compiler.asm.aarch64.AArch64Address.AddressingMode; +import jdk.graal.compiler.asm.aarch64.AArch64Assembler.ConditionFlag; +import jdk.graal.compiler.asm.aarch64.AArch64MacroAssembler; +import jdk.graal.compiler.debug.GraalError; +import jdk.graal.compiler.lir.LIRInstructionClass; +import jdk.graal.compiler.lir.Opcode; +import jdk.graal.compiler.lir.asm.ArrayDataPointerConstant; +import jdk.graal.compiler.lir.asm.CompilationResultBuilder; +import jdk.graal.compiler.lir.gen.LIRGeneratorTool; +import jdk.vm.ci.aarch64.AArch64; +import jdk.vm.ci.code.CodeUtil; +import jdk.vm.ci.code.Register; +import jdk.vm.ci.meta.AllocatableValue; +import jdk.vm.ci.meta.JavaKind; +import jdk.vm.ci.meta.Value; + +/** + * @see jdk.graal.compiler.replacements.nodes.VectorizedHashCodeNode + * @see jdk.graal.compiler.lir.amd64.AMD64VectorizedHashCodeOp + */ +@Opcode("VECTORIZED_HASHCODE") +public final class AArch64VectorizedHashCodeOp extends AArch64ComplexVectorOp { + + public static final LIRInstructionClass TYPE = LIRInstructionClass.create(AArch64VectorizedHashCodeOp.class); + + @Def({OperandFlag.REG}) private Value resultValue; + @Alive({OperandFlag.REG}) private Value arrayStart; + @Alive({OperandFlag.REG}) private Value length; + @Alive({OperandFlag.REG}) private Value initialValue; + + private final JavaKind arrayKind; + + @Temp({OperandFlag.REG}) Value[] temp; + @Temp({OperandFlag.REG}) Value[] vectorTemp; + + public AArch64VectorizedHashCodeOp(LIRGeneratorTool tool, + AllocatableValue result, AllocatableValue arrayStart, AllocatableValue length, AllocatableValue initialValue, JavaKind arrayKind) { + super(TYPE); + this.resultValue = result; + this.arrayStart = arrayStart; + this.length = length; + this.initialValue = initialValue; + this.arrayKind = arrayKind; + + this.temp = allocateTempRegisters(tool, 5); + this.vectorTemp = allocateVectorRegisters(tool, 13); + } + + private static void arraysHashcodeElload(AArch64MacroAssembler masm, Register dst, AArch64Address src, JavaKind eltype) { + switch (eltype) { + case Boolean -> masm.ldr(8, dst, src); + case Byte -> masm.ldrs(32, 8, dst, src); + case Short -> masm.ldrs(32, 16, dst, src); + case Char -> masm.ldr(16, dst, src); + case Int -> masm.ldr(32, dst, src); + default -> throw GraalError.shouldNotReachHere("Unsupported JavaKind " + eltype); + } + } + + private static final int[] POWERS_OF_31_BACKWARDS = new int[]{ + 2111290369, + -2010103841, + 350799937, + 11316127, + 693101697, + -254736545, + 961614017, + 31019807, + -2077209343, + -67006753, + 1244764481, + -2038056289, + 211350913, + -408824225, + -844471871, + -997072353, + 1353309697, + -510534177, + 1507551809, + -505558625, + -293403007, + 129082719, + -1796951359, + -196513505, + -1807454463, + 1742810335, + 887503681, + 28629151, + 923521, + 29791, + 961, + 31, + 1, + }; + private static final ArrayDataPointerConstant powersOf31 = new ArrayDataPointerConstant(POWERS_OF_31_BACKWARDS, 16); + + @Override + public void emitCode(CompilationResultBuilder crb, AArch64MacroAssembler masm) { + Label labelShortUnrolledBegin = new Label(); + Label labelShortUnrolledLoopBegin = new Label(); + Label labelShortUnrolledLoopExit = new Label(); + Label labelUnrolledVectorLoopBegin = new Label(); + Label labelEnd = new Label(); + + Register result = asRegister(resultValue); + Register ary1 = asRegister(temp[0]); + Register cnt1 = asRegister(temp[1]); + Register tmp2 = asRegister(temp[2]); + Register tmp3 = asRegister(temp[3]); + Register index = asRegister(temp[4]); + + masm.mov(64, ary1, asRegister(arrayStart)); + masm.mov(32, cnt1, asRegister(length)); + masm.mov(32, result, asRegister(initialValue)); + + // For "renaming" for readability of the code + Register vnext = asRegister(vectorTemp[0]); + Register[] vcoef = {asRegister(vectorTemp[1]), asRegister(vectorTemp[2]), asRegister(vectorTemp[3]), asRegister(vectorTemp[4])}; + Register[] vresult = {asRegister(vectorTemp[5]), asRegister(vectorTemp[6]), asRegister(vectorTemp[7]), asRegister(vectorTemp[8])}; + Register[] vtmp = {asRegister(vectorTemp[9]), asRegister(vectorTemp[10]), asRegister(vectorTemp[11]), asRegister(vectorTemp[12])}; + + final boolean unsigned = arrayKind == JavaKind.Boolean || arrayKind == JavaKind.Char; + final ElementSize elSize = switch (arrayKind) { + case Boolean, Byte -> ElementSize.Byte; + case Char, Short -> ElementSize.HalfWord; + case Int -> ElementSize.Word; + default -> throw GraalError.shouldNotReachHereUnexpectedValue(arrayKind); + }; + + final int nRegs = vresult.length; + assert nRegs >= 2 && CodeUtil.isPowerOf2(nRegs) : "number of vectors must be >= 2 and a power of 2"; + final int elementsPerVector = ASIMDSize.FullReg.bytes() / ElementSize.Word.bytes(); + final int elementsPerIteration = elementsPerVector * nRegs; + + // @formatter:off + // elementsPerIteration = 16; + // if (cnt1 >= elementsPerIteration) { + // UNROLLED VECTOR LOOP + // } + // if (cnt1 >= 2) { + // UNROLLED SCALAR LOOP + // } + // SINGLE SCALAR + // @formatter:on + + // if (cnt1 >= elementsPerIteration) && generate_vectorized_loop + masm.compare(32, cnt1, elementsPerIteration); + masm.branchConditionally(ConditionFlag.LT, labelShortUnrolledBegin); + + // index = 0; + masm.mov(index, 0); + // vresult[i] = IntVector.zero(I128); + for (int idx = 0; idx < nRegs; idx++) { + masm.neon.moviVI(ASIMDSize.FullReg, vresult[idx], 0); + } + + Register bound = tmp2; + Register next = tmp3; + + // vnext = IntVector.broadcast(I128, power_of_31_backwards[0]); + boolean useConstant = true; + if (useConstant) { + int nextValue = POWERS_OF_31_BACKWARDS[POWERS_OF_31_BACKWARDS.length - elementsPerIteration - 1]; + masm.mov(next, nextValue); + } else { + crb.recordDataReferenceInCode(powersOf31); + masm.adrpAdd(next); + int nextOffset = (POWERS_OF_31_BACKWARDS.length - elementsPerIteration - 1) * JavaKind.Int.getByteCount(); + if (nextOffset != 0) { + masm.add(64, next, next, nextOffset); + } + masm.ldr(32, next, AArch64Address.createBaseRegisterOnlyAddress(32, next)); + } + masm.neon.dupVG(ASIMDSize.FullReg, ElementSize.Word, vnext, next); + + // bound = cnt1 & ~(elementsPerIteration - 1); + masm.and(32, bound, cnt1, ~(elementsPerIteration - 1)); + + // for (; index < bound; index += elementsPerIteration) { + masm.bind(labelUnrolledVectorLoopBegin); + // result *= next; + masm.mul(32, result, result, next); + + // loop fission to upfront the cost of fetching from memory, + // OOO execution can then hopefully do a better job of prefetching + // load next 16 elements into 4 data vector registers + // vtmp = ary1[index:index+elementsPerIteration]; + try (var scratch1 = masm.getScratchRegister()) { + var rscratch1 = scratch1.getRegister(); + // load next chunk address into scratch reg + AArch64Address dataChunkStart = AArch64Address.createRegisterOffsetAddress(elSize.bits(), ary1, index, true); + masm.loadAddress(rscratch1, dataChunkStart); + + ASIMDSize loadVecSize = elSize == ElementSize.Byte || elSize == ElementSize.HalfWord ? ASIMDSize.HalfReg : ASIMDSize.FullReg; + int consecutiveRegs = elSize == ElementSize.Byte ? 2 : 4; + boolean useMultiRegisterLoad = elSize == ElementSize.Byte && allConsecutiveSIMDRegisters(vtmp) && nRegs >= 4; + if (useMultiRegisterLoad) { + int regsFilledPerLoad = 4; + for (int ldVi = 0; ldVi < nRegs; ldVi += regsFilledPerLoad) { + // load vector size chunk of memory into vtmp, and optionally increment address + if (consecutiveRegs == 2) { + assert elSize == ElementSize.Byte : elSize; + AArch64Address indexedAddr = nRegs == regsFilledPerLoad + ? AArch64Address.createStructureNoOffsetAddress(rscratch1) + : AArch64Address.createStructureImmediatePostIndexAddress(ASIMDInstruction.LD1_MULTIPLE_2R, + loadVecSize, elSize, rscratch1, loadVecSize.bytes() * consecutiveRegs); + masm.neon.ld1MultipleVV(loadVecSize, elSize, vtmp[ldVi], vtmp[ldVi + 1], indexedAddr); + // extend byte to halfword + xtlVV(masm, unsigned, elSize, vtmp[ldVi + 1], vtmp[ldVi + 1]); + xtlVV(masm, unsigned, elSize, vtmp[ldVi], vtmp[ldVi]); + // extend halfword to word + xtl2VV(masm, unsigned, ElementSize.HalfWord, vtmp[ldVi + 3], vtmp[ldVi + 1]); + xtlVV(masm, unsigned, ElementSize.HalfWord, vtmp[ldVi + 2], vtmp[ldVi + 1]); + xtl2VV(masm, unsigned, ElementSize.HalfWord, vtmp[ldVi + 1], vtmp[ldVi]); + xtlVV(masm, unsigned, ElementSize.HalfWord, vtmp[ldVi], vtmp[ldVi]); + } else { + assert consecutiveRegs == 4 : consecutiveRegs; + assert elSize == ElementSize.HalfWord || elSize == ElementSize.Word : elSize; + AArch64Address indexedAddr = nRegs == regsFilledPerLoad + ? AArch64Address.createStructureNoOffsetAddress(rscratch1) + : AArch64Address.createStructureImmediatePostIndexAddress(ASIMDInstruction.LD1_MULTIPLE_4R, + loadVecSize, elSize, rscratch1, loadVecSize.bytes() * consecutiveRegs); + masm.neon.ld1MultipleVVVV(loadVecSize, elSize, vtmp[ldVi], vtmp[ldVi + 1], vtmp[ldVi + 2], vtmp[ldVi + 3], indexedAddr); + if (elSize == ElementSize.HalfWord) { + for (int i = 0; i < consecutiveRegs; i++) { + // extend halfword to word + xtlVV(masm, unsigned, elSize, vtmp[ldVi + i], vtmp[ldVi + i]); + } + } + } + } + } else { + int regsFilledPerLoad = loadVecSize.bytes() / ElementSize.Word.bytes() / elSize.bytes(); + AArch64Address indexedAddr = nRegs == regsFilledPerLoad + ? AArch64Address.createStructureNoOffsetAddress(rscratch1) + : AArch64Address.createStructureImmediatePostIndexAddress(ASIMDInstruction.LD1_MULTIPLE_1R, + loadVecSize, elSize, rscratch1, loadVecSize.bytes()); + // load vector size chunk of memory into vtmp, and optionally increment address + for (int ldVi = 0; ldVi < nRegs; ldVi += regsFilledPerLoad) { + masm.neon.ld1MultipleV(loadVecSize, elSize, vtmp[ldVi], indexedAddr); + } + // expand (i.e. zero- or sign-extend) vector elements to int size + if (elSize == ElementSize.Byte || elSize == ElementSize.HalfWord) { + for (int ldVi = 0; ldVi < nRegs; ldVi += regsFilledPerLoad) { + if (loadVecSize == ASIMDSize.HalfReg) { + xtlVV(masm, unsigned, elSize, vtmp[ldVi], vtmp[ldVi]); + } else { + xtl2VV(masm, unsigned, elSize, vtmp[ldVi + 1], vtmp[ldVi]); + xtlVV(masm, unsigned, elSize, vtmp[ldVi], vtmp[ldVi]); + } + } + if (elSize == ElementSize.Byte) { + for (int ldVi = 0; ldVi < nRegs; ldVi += regsFilledPerLoad) { + if (loadVecSize == ASIMDSize.HalfReg) { + assert regsFilledPerLoad == 2 : regsFilledPerLoad; + xtl2VV(masm, unsigned, ElementSize.HalfWord, vtmp[ldVi + 1], vtmp[ldVi]); + xtlVV(masm, unsigned, ElementSize.HalfWord, vtmp[ldVi], vtmp[ldVi]); + } else { + assert regsFilledPerLoad == 4 : regsFilledPerLoad; + xtl2VV(masm, unsigned, ElementSize.HalfWord, vtmp[ldVi + 3], vtmp[ldVi + 1]); + xtlVV(masm, unsigned, ElementSize.HalfWord, vtmp[ldVi + 2], vtmp[ldVi + 1]); + xtl2VV(masm, unsigned, ElementSize.HalfWord, vtmp[ldVi + 1], vtmp[ldVi]); + xtlVV(masm, unsigned, ElementSize.HalfWord, vtmp[ldVi], vtmp[ldVi]); + } + } + } + } + } + } + + // vresult[i] = vresult[i] * vnext + vtmp[i]; + for (int idx = 0; idx < nRegs; idx++) { + // masm.neon.mulVVV(FullReg, ElementSize.Word, vresult[idx], vresult[idx], vnext); + // masm.neon.addVVV(FullReg, ElementSize.Word, vresult[idx], vresult[idx], vtmp[idx]); + masm.neon.mlaVVV(ASIMDSize.FullReg, ElementSize.Word, vtmp[idx], vresult[idx], vnext); + masm.neon.moveVV(ASIMDSize.FullReg, vresult[idx], vtmp[idx]); + } + + // increment index by the number of elements read in this iteration + masm.add(32, index, index, elementsPerIteration); + + // index < bound; + masm.cmp(32, index, bound); + masm.branchConditionally(ConditionFlag.LT, labelUnrolledVectorLoopBegin); + // } + + // start = ary[bound]; + // cnt1 -= bound; + masm.loadAddress(ary1, AArch64Address.createRegisterOffsetAddress(elSize.bits(), ary1, bound, true)); + masm.sub(32, cnt1, cnt1, bound); + // release bound + + // vcoef = IntVector.fromArray(I128, power_of_31_backwards, 1); + crb.recordDataReferenceInCode(powersOf31); + Register coefAddrReg = tmp2; + masm.adrpAdd(coefAddrReg); + int coefOffset = (POWERS_OF_31_BACKWARDS.length - elementsPerIteration) * JavaKind.Int.getByteCount(); + assert coefOffset >= 0 : coefOffset; + if (coefOffset != 0) { + masm.add(64, coefAddrReg, coefAddrReg, coefOffset); + } + if (allConsecutiveSIMDRegisters(vcoef) && vcoef.length == 4) { + AArch64Address coefAddr = AArch64Address.createStructureNoOffsetAddress(tmp2); + masm.neon.ld1MultipleVVVV(ASIMDSize.FullReg, ElementSize.Word, vcoef[0], vcoef[1], vcoef[2], vcoef[3], coefAddr); + } else { + AArch64Address coefAddrPostIndex = AArch64Address.createStructureImmediatePostIndexAddress(ASIMDInstruction.LD1_MULTIPLE_1R, + ASIMDSize.FullReg, ElementSize.Word, coefAddrReg, ASIMDSize.FullReg.bytes()); + for (int idx = 0; idx < nRegs; idx++) { + masm.neon.ld1MultipleV(ASIMDSize.FullReg, ElementSize.Word, vcoef[idx], coefAddrPostIndex); + } + } + + // vresult *= vcoef; + for (int idx = 0; idx < nRegs; idx++) { + masm.neon.mulVVV(ASIMDSize.FullReg, ElementSize.Word, vresult[idx], vresult[idx], vcoef[idx]); + } + + reduceVectorLanes(masm, ASIMDSize.FullReg, vresult); + + // accumulate horizontal vector sum in result + masm.neon.umovGX(ElementSize.Word, tmp2, vresult[0], 0); + masm.add(32, result, result, tmp2); + + // } else if (cnt1 < elementsPerIteration) { + + masm.bind(labelShortUnrolledBegin); + // int i = 1; + masm.mov(index, 1); + + AArch64Address postIndexAddr = AArch64Address.createImmediateAddress(elSize.bits(), AddressingMode.IMMEDIATE_POST_INDEXED, ary1, elSize.bytes()); + + masm.cmp(32, index, cnt1); + masm.branchConditionally(ConditionFlag.GE, labelShortUnrolledLoopExit); + + // for (; i < cnt1 ; i += 2) { + masm.bind(labelShortUnrolledLoopBegin); + // result *= 31**2; + masm.mov(tmp3, 961); + masm.mul(32, result, result, tmp3); + + // result += ary1[index-1] * 31 + arraysHashcodeElload(masm, tmp2, postIndexAddr, arrayKind); + masm.mov(32, tmp3, tmp2); + masm.lsl(32, tmp3, tmp3, 5); + masm.sub(32, tmp3, tmp3, tmp2); + masm.add(32, result, result, tmp3); + + // result += ary1[index] + arraysHashcodeElload(masm, tmp3, postIndexAddr, arrayKind); + masm.add(32, result, result, tmp3); + // i += 2 + masm.add(32, index, index, 2); + + masm.cmp(32, index, cnt1); + masm.branchConditionally(ConditionFlag.LT, labelShortUnrolledLoopBegin); + + // } + // if (i >= cnt1) { + masm.bind(labelShortUnrolledLoopExit); + // masm.cmp(32, index, cnt1); // already compared above + masm.branchConditionally(ConditionFlag.GT, labelEnd); + // result *= 31; + masm.mov(32, tmp2, result); + masm.lsl(32, result, result, 5); + masm.sub(32, result, result, tmp2); + + // result += ary1[index - 1] + arraysHashcodeElload(masm, tmp3, postIndexAddr, arrayKind); + masm.add(32, result, result, tmp3); + // } + masm.bind(labelEnd); + } + + /** + * Reduces elements from multiple vectors to a single vector and then reduces that vector's + * lanes to a single scalar value in {@code vresult[0]}. + */ + private static void reduceVectorLanes(AArch64MacroAssembler masm, ASIMDSize vsize, Register[] vresult) { + // reduce vectors pairwise until there's only a single vector left + // e.g. vresult = vresult[0].add(vresult[1]).add(vresult[2]).add(vresult[3]); + for (int nRegs = vresult.length, stride = 1; nRegs >= 2; nRegs /= 2, stride *= 2) { + for (int i = 0; i < vresult.length - stride; i += 2 * stride) { + masm.neon.addVVV(vsize, ElementSize.Word, vresult[i], vresult[i], vresult[i + stride]); + } + if (nRegs % 2 != 0) { + masm.neon.addVVV(vsize, ElementSize.Word, vresult[0], vresult[0], vresult[(nRegs - 1) * stride]); + } + } + // result = vresult.reduceLanes(ADD); + masm.neon.addvSV(vsize, ElementSize.Word, vresult[0], vresult[0]); + } + + private static void xtlVV(AArch64MacroAssembler masm, boolean unsigned, ElementSize elementSize, Register dst, Register src) { + if (unsigned) { + masm.neon.uxtlVV(elementSize, dst, src); + } else { + masm.neon.sxtlVV(elementSize, dst, src); + } + } + + private static void xtl2VV(AArch64MacroAssembler masm, boolean unsigned, ElementSize elementSize, Register dst, Register src) { + if (unsigned) { + masm.neon.uxtl2VV(elementSize, dst, src); + } else { + masm.neon.sxtl2VV(elementSize, dst, src); + } + } + + /** + * Checks whether all registers follow one another (modulo the number of SIMD registers). + */ + private static boolean allConsecutiveSIMDRegisters(Register[] regs) { + int numRegs = AArch64.simdRegisters.size(); + for (int i = 1; i < regs.length; i++) { + assert regs[i].getRegisterCategory().equals(AArch64.SIMD) : regs[i]; + if (!((regs[i - 1].encoding + 1) % numRegs == regs[i].encoding)) { + return false; + } + } + return true; + } +} diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/replacements/nodes/VectorizedHashCodeNode.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/replacements/nodes/VectorizedHashCodeNode.java index 6ffe4d5033f0..2f4361f95028 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/replacements/nodes/VectorizedHashCodeNode.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/replacements/nodes/VectorizedHashCodeNode.java @@ -34,6 +34,8 @@ import java.util.EnumSet; +import org.graalvm.word.Pointer; + import jdk.graal.compiler.core.common.spi.ForeignCallDescriptor; import jdk.graal.compiler.core.common.type.StampFactory; import jdk.graal.compiler.debug.GraalError; @@ -45,8 +47,7 @@ import jdk.graal.compiler.nodes.NamedLocationIdentity; import jdk.graal.compiler.nodes.ValueNode; import jdk.graal.compiler.nodes.spi.NodeLIRBuilderTool; -import org.graalvm.word.Pointer; - +import jdk.vm.ci.aarch64.AArch64; import jdk.vm.ci.amd64.AMD64; import jdk.vm.ci.code.Architecture; import jdk.vm.ci.meta.JavaKind; @@ -116,6 +117,8 @@ public static EnumSet minFeaturesAMD64() { public static boolean isSupported(Architecture arch) { if (arch instanceof AMD64) { return ((AMD64) arch).getFeatures().containsAll(minFeaturesAMD64()); + } else if (arch instanceof AArch64) { + return true; } return false; } diff --git a/substratevm/src/com.oracle.svm.graal/src/com/oracle/svm/graal/stubs/AArch64StubForeignCallsFeature.java b/substratevm/src/com.oracle.svm.graal/src/com/oracle/svm/graal/stubs/AArch64StubForeignCallsFeature.java index 1774ca168012..1a8eacc02d80 100644 --- a/substratevm/src/com.oracle.svm.graal/src/com/oracle/svm/graal/stubs/AArch64StubForeignCallsFeature.java +++ b/substratevm/src/com.oracle.svm.graal/src/com/oracle/svm/graal/stubs/AArch64StubForeignCallsFeature.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2023, 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 @@ -26,6 +26,11 @@ import static com.oracle.svm.core.cpufeature.Stubs.AArch64Features.EMPTY_CPU_FEATURES_AARCH64; +import org.graalvm.nativeimage.Platform.AARCH64; +import org.graalvm.nativeimage.Platforms; + +import com.oracle.svm.core.feature.AutomaticallyRegisteredFeature; + import jdk.graal.compiler.replacements.StringLatin1InflateNode; import jdk.graal.compiler.replacements.StringUTF16CompressNode; import jdk.graal.compiler.replacements.nodes.AESNode; @@ -50,11 +55,8 @@ import jdk.graal.compiler.replacements.nodes.MessageDigestNode.SHA256Node; import jdk.graal.compiler.replacements.nodes.MessageDigestNode.SHA3Node; import jdk.graal.compiler.replacements.nodes.MessageDigestNode.SHA512Node; +import jdk.graal.compiler.replacements.nodes.VectorizedHashCodeNode; import jdk.graal.compiler.replacements.nodes.VectorizedMismatchNode; -import org.graalvm.nativeimage.Platform.AARCH64; -import org.graalvm.nativeimage.Platforms; - -import com.oracle.svm.core.feature.AutomaticallyRegisteredFeature; @AutomaticallyRegisteredFeature @Platforms(AARCH64.class) @@ -74,6 +76,7 @@ public AArch64StubForeignCallsFeature() { new StubDescriptor(EncodeArrayNode.STUBS, EMPTY_CPU_FEATURES_AARCH64, EMPTY_CPU_FEATURES_AARCH64), new StubDescriptor(CountPositivesNode.STUB, EMPTY_CPU_FEATURES_AARCH64, EMPTY_CPU_FEATURES_AARCH64), new StubDescriptor(VectorizedMismatchNode.STUB, EMPTY_CPU_FEATURES_AARCH64, EMPTY_CPU_FEATURES_AARCH64), + new StubDescriptor(VectorizedHashCodeNode.STUBS, EMPTY_CPU_FEATURES_AARCH64, EMPTY_CPU_FEATURES_AARCH64), new StubDescriptor(AESNode.STUBS, AESNode.minFeaturesAARCH64(), AESNode.minFeaturesAARCH64()), new StubDescriptor(CounterModeAESNode.STUB, CounterModeAESNode.minFeaturesAARCH64(), CounterModeAESNode.minFeaturesAARCH64()), new StubDescriptor(CipherBlockChainingAESNode.STUBS, CipherBlockChainingAESNode.minFeaturesAARCH64(), CipherBlockChainingAESNode.minFeaturesAARCH64()), From 997654a7676eed9be71c1fa857ed66eb4b499802 Mon Sep 17 00:00:00 2001 From: Andreas Woess Date: Tue, 21 Nov 2023 15:53:15 +0100 Subject: [PATCH 013/593] Intrinsify ArraysSupport.vectorizedHashCode on AArch64. --- .../test/VectorizedHashCodeTest.java | 21 ++--- .../meta/HotSpotGraphBuilderPlugins.java | 27 ++++-- .../StandardGraphBuilderPlugins.java | 85 ++++++++++++++----- .../amd64/AMD64GraphBuilderPlugins.java | 52 +----------- .../SubstrateAArch64GraphBuilderPlugins.java | 26 ++++-- .../SubstrateAMD64GraphBuilderPlugins.java | 26 ++++-- 6 files changed, 130 insertions(+), 107 deletions(-) diff --git a/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/replacements/test/VectorizedHashCodeTest.java b/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/replacements/test/VectorizedHashCodeTest.java index a04a238d5172..4591061dede9 100644 --- a/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/replacements/test/VectorizedHashCodeTest.java +++ b/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/replacements/test/VectorizedHashCodeTest.java @@ -29,23 +29,24 @@ import java.util.Set; import java.util.function.Function; -import jdk.graal.compiler.core.test.GraalCompilerTest; -import jdk.graal.compiler.replacements.amd64.AMD64GraphBuilderPlugins; -import jdk.graal.compiler.test.AddExports; +import org.junit.Assert; import org.junit.Test; +import jdk.graal.compiler.core.test.GraalCompilerTest; +import jdk.graal.compiler.replacements.StandardGraphBuilderPlugins.VectorizedHashCodeInvocationPlugin; +import jdk.graal.compiler.test.AddExports; import jdk.internal.util.ArraysSupport; @AddExports({"java.base/jdk.internal.util"}) public class VectorizedHashCodeTest extends GraalCompilerTest { @Test - public void testJDKConstantValue() throws ClassNotFoundException, NoSuchFieldException, IllegalAccessException { - assertTrue(ArraysSupport.T_BOOLEAN == AMD64GraphBuilderPlugins.T_BOOLEAN); - assertTrue(ArraysSupport.T_CHAR == AMD64GraphBuilderPlugins.T_CHAR); - assertTrue(ArraysSupport.T_BYTE == AMD64GraphBuilderPlugins.T_BYTE); - assertTrue(ArraysSupport.T_SHORT == AMD64GraphBuilderPlugins.T_SHORT); - assertTrue(ArraysSupport.T_INT == AMD64GraphBuilderPlugins.T_INT); + public void testJDKConstantValue() { + Assert.assertEquals(ArraysSupport.T_BOOLEAN, VectorizedHashCodeInvocationPlugin.T_BOOLEAN); + Assert.assertEquals(ArraysSupport.T_CHAR, VectorizedHashCodeInvocationPlugin.T_CHAR); + Assert.assertEquals(ArraysSupport.T_BYTE, VectorizedHashCodeInvocationPlugin.T_BYTE); + Assert.assertEquals(ArraysSupport.T_SHORT, VectorizedHashCodeInvocationPlugin.T_SHORT); + Assert.assertEquals(ArraysSupport.T_INT, VectorizedHashCodeInvocationPlugin.T_INT); } // @formatter:off @@ -56,7 +57,7 @@ public void testJDKConstantValue() throws ClassNotFoundException, NoSuchFieldExc }; // @formatter:on - private static int[] initialValues = {0, 0xDEADBEEF}; + private static int[] initialValues = {0, 1, 0xDEADBEEF}; private void testHash(String method, Function f, Function getLength) throws UnsupportedEncodingException { for (String test : tests) { diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/meta/HotSpotGraphBuilderPlugins.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/meta/HotSpotGraphBuilderPlugins.java index 9a7bf0e2279e..18b762c4be8f 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/meta/HotSpotGraphBuilderPlugins.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/meta/HotSpotGraphBuilderPlugins.java @@ -24,7 +24,6 @@ */ package jdk.graal.compiler.hotspot.meta; -import static jdk.vm.ci.services.Services.IS_IN_NATIVE_IMAGE; import static jdk.graal.compiler.hotspot.HotSpotBackend.BASE64_DECODE_BLOCK; import static jdk.graal.compiler.hotspot.HotSpotBackend.BASE64_ENCODE_BLOCK; import static jdk.graal.compiler.hotspot.HotSpotBackend.CHACHA20Block; @@ -42,6 +41,7 @@ import static jdk.graal.compiler.java.BytecodeParserOptions.InlineDuringParsing; import static jdk.graal.compiler.nodes.ConstantNode.forBoolean; import static jdk.graal.compiler.nodes.extended.BranchProbabilityNode.NOT_FREQUENT_PROBABILITY; +import static jdk.vm.ci.services.Services.IS_IN_NATIVE_IMAGE; import java.lang.annotation.Annotation; import java.lang.invoke.ConstantCallSite; @@ -54,6 +54,8 @@ import java.math.BigInteger; import java.util.zip.CRC32; +import org.graalvm.word.LocationIdentity; + import jdk.graal.compiler.api.directives.GraalDirectives; import jdk.graal.compiler.api.replacements.SnippetReflectionProvider; import jdk.graal.compiler.core.common.calc.Condition; @@ -62,6 +64,12 @@ import jdk.graal.compiler.core.common.spi.ForeignCallDescriptor; import jdk.graal.compiler.core.common.type.StampFactory; import jdk.graal.compiler.debug.GraalError; +import jdk.graal.compiler.hotspot.GraalHotSpotVMConfig; +import jdk.graal.compiler.hotspot.HotSpotBackend; +import jdk.graal.compiler.hotspot.HotSpotGraalRuntimeProvider; +import jdk.graal.compiler.hotspot.nodes.CurrentJavaThreadNode; +import jdk.graal.compiler.hotspot.nodes.HotSpotLoadReservedReferenceNode; +import jdk.graal.compiler.hotspot.nodes.HotSpotStoreReservedReferenceNode; import jdk.graal.compiler.hotspot.replacements.CallSiteTargetNode; import jdk.graal.compiler.hotspot.replacements.DigestBaseSnippets; import jdk.graal.compiler.hotspot.replacements.FastNotifyNode; @@ -72,12 +80,6 @@ import jdk.graal.compiler.hotspot.replacements.HubGetClassNode; import jdk.graal.compiler.hotspot.replacements.ObjectCloneNode; import jdk.graal.compiler.hotspot.replacements.UnsafeCopyMemoryNode; -import jdk.graal.compiler.hotspot.GraalHotSpotVMConfig; -import jdk.graal.compiler.hotspot.HotSpotBackend; -import jdk.graal.compiler.hotspot.HotSpotGraalRuntimeProvider; -import jdk.graal.compiler.hotspot.nodes.CurrentJavaThreadNode; -import jdk.graal.compiler.hotspot.nodes.HotSpotLoadReservedReferenceNode; -import jdk.graal.compiler.hotspot.nodes.HotSpotStoreReservedReferenceNode; import jdk.graal.compiler.hotspot.word.HotSpotWordTypes; import jdk.graal.compiler.java.BytecodeParser; import jdk.graal.compiler.lir.SyncPort; @@ -156,12 +158,11 @@ import jdk.graal.compiler.replacements.nodes.CipherBlockChainingAESNode; import jdk.graal.compiler.replacements.nodes.CounterModeAESNode; import jdk.graal.compiler.replacements.nodes.MacroNode.MacroParams; +import jdk.graal.compiler.replacements.nodes.VectorizedHashCodeNode; import jdk.graal.compiler.replacements.nodes.VectorizedMismatchNode; import jdk.graal.compiler.serviceprovider.GraalServices; import jdk.graal.compiler.serviceprovider.JavaVersionUtil; import jdk.graal.compiler.word.WordTypes; -import org.graalvm.word.LocationIdentity; - import jdk.vm.ci.aarch64.AArch64; import jdk.vm.ci.code.Architecture; import jdk.vm.ci.code.TargetDescription; @@ -1185,6 +1186,14 @@ public boolean isGraalOnly() { return arch instanceof AArch64; } }); + r.registerConditional(VectorizedHashCodeNode.isSupported(arch), new StandardGraphBuilderPlugins.VectorizedHashCodeInvocationPlugin("vectorizedHashCode") { + @Override + public boolean isGraalOnly() { + // On AArch64 HotSpot, this intrinsic is not implemented and + // UseVectorizedHashCodeIntrinsic defaults to false. + return arch instanceof AArch64; + } + }); } private static void registerReferencePlugins(InvocationPlugins plugins, Replacements replacements) { diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/replacements/StandardGraphBuilderPlugins.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/replacements/StandardGraphBuilderPlugins.java index 658590849bc0..b4ed44ae2249 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/replacements/StandardGraphBuilderPlugins.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/replacements/StandardGraphBuilderPlugins.java @@ -24,9 +24,6 @@ */ package jdk.graal.compiler.replacements; -import static jdk.vm.ci.meta.DeoptimizationAction.InvalidateReprofile; -import static jdk.vm.ci.meta.DeoptimizationAction.None; -import static jdk.vm.ci.meta.DeoptimizationReason.TransferToInterpreter; import static jdk.graal.compiler.core.common.calc.Condition.LT; import static jdk.graal.compiler.core.common.memory.MemoryOrderMode.ACQUIRE; import static jdk.graal.compiler.core.common.memory.MemoryOrderMode.PLAIN; @@ -38,6 +35,9 @@ import static jdk.graal.compiler.replacements.BoxingSnippets.Templates.getCacheClass; import static jdk.graal.compiler.replacements.nodes.AESNode.CryptMode.DECRYPT; import static jdk.graal.compiler.replacements.nodes.AESNode.CryptMode.ENCRYPT; +import static jdk.vm.ci.meta.DeoptimizationAction.InvalidateReprofile; +import static jdk.vm.ci.meta.DeoptimizationAction.None; +import static jdk.vm.ci.meta.DeoptimizationReason.TransferToInterpreter; import java.lang.reflect.Array; import java.lang.reflect.Field; @@ -49,6 +49,8 @@ import java.util.Objects; import java.util.function.BiFunction; +import org.graalvm.word.LocationIdentity; + import jdk.graal.compiler.api.directives.GraalDirectives; import jdk.graal.compiler.api.replacements.SnippetReflectionProvider; import jdk.graal.compiler.core.common.calc.Condition; @@ -173,10 +175,28 @@ import jdk.graal.compiler.nodes.util.ConstantReflectionUtil; import jdk.graal.compiler.nodes.util.GraphUtil; import jdk.graal.compiler.nodes.virtual.EnsureVirtualizedNode; +import jdk.graal.compiler.replacements.nodes.AESNode; +import jdk.graal.compiler.replacements.nodes.AESNode.CryptMode; import jdk.graal.compiler.replacements.nodes.ArrayEqualsNode; +import jdk.graal.compiler.replacements.nodes.BigIntegerMulAddNode; import jdk.graal.compiler.replacements.nodes.BigIntegerSquareToLenNode; +import jdk.graal.compiler.replacements.nodes.CipherBlockChainingAESNode; import jdk.graal.compiler.replacements.nodes.CountPositivesNode; +import jdk.graal.compiler.replacements.nodes.CounterModeAESNode; +import jdk.graal.compiler.replacements.nodes.EncodeArrayNode; +import jdk.graal.compiler.replacements.nodes.GHASHProcessBlocksNode; +import jdk.graal.compiler.replacements.nodes.LogNode; import jdk.graal.compiler.replacements.nodes.MacroNode; +import jdk.graal.compiler.replacements.nodes.MessageDigestNode; +import jdk.graal.compiler.replacements.nodes.MessageDigestNode.MD5Node; +import jdk.graal.compiler.replacements.nodes.MessageDigestNode.SHA1Node; +import jdk.graal.compiler.replacements.nodes.MessageDigestNode.SHA256Node; +import jdk.graal.compiler.replacements.nodes.MessageDigestNode.SHA512Node; +import jdk.graal.compiler.replacements.nodes.ProfileBooleanNode; +import jdk.graal.compiler.replacements.nodes.ReverseBitsNode; +import jdk.graal.compiler.replacements.nodes.ReverseBytesNode; +import jdk.graal.compiler.replacements.nodes.VectorizedHashCodeNode; +import jdk.graal.compiler.replacements.nodes.VirtualizableInvokeMacroNode; import jdk.graal.compiler.replacements.nodes.arithmetic.IntegerAddExactNode; import jdk.graal.compiler.replacements.nodes.arithmetic.IntegerAddExactOverflowNode; import jdk.graal.compiler.replacements.nodes.arithmetic.IntegerAddExactSplitNode; @@ -191,27 +211,8 @@ import jdk.graal.compiler.replacements.nodes.arithmetic.IntegerSubExactOverflowNode; import jdk.graal.compiler.replacements.nodes.arithmetic.IntegerSubExactSplitNode; import jdk.graal.compiler.replacements.nodes.arithmetic.UnsignedMulHighNode; -import jdk.graal.compiler.replacements.nodes.AESNode; -import jdk.graal.compiler.replacements.nodes.AESNode.CryptMode; -import jdk.graal.compiler.replacements.nodes.BigIntegerMulAddNode; -import jdk.graal.compiler.replacements.nodes.CipherBlockChainingAESNode; -import jdk.graal.compiler.replacements.nodes.CounterModeAESNode; -import jdk.graal.compiler.replacements.nodes.EncodeArrayNode; -import jdk.graal.compiler.replacements.nodes.GHASHProcessBlocksNode; -import jdk.graal.compiler.replacements.nodes.LogNode; -import jdk.graal.compiler.replacements.nodes.MessageDigestNode; -import jdk.graal.compiler.replacements.nodes.MessageDigestNode.MD5Node; -import jdk.graal.compiler.replacements.nodes.MessageDigestNode.SHA1Node; -import jdk.graal.compiler.replacements.nodes.MessageDigestNode.SHA256Node; -import jdk.graal.compiler.replacements.nodes.MessageDigestNode.SHA512Node; -import jdk.graal.compiler.replacements.nodes.ProfileBooleanNode; -import jdk.graal.compiler.replacements.nodes.ReverseBitsNode; -import jdk.graal.compiler.replacements.nodes.ReverseBytesNode; -import jdk.graal.compiler.replacements.nodes.VirtualizableInvokeMacroNode; import jdk.graal.compiler.serviceprovider.JavaVersionUtil; import jdk.graal.compiler.serviceprovider.SpeculationReasonGroup; -import org.graalvm.word.LocationIdentity; - import jdk.vm.ci.code.Architecture; import jdk.vm.ci.code.BytecodePosition; import jdk.vm.ci.code.CodeUtil; @@ -2505,4 +2506,44 @@ public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Rec } }); } + + public static class VectorizedHashCodeInvocationPlugin extends InlineOnlyInvocationPlugin { + + // Sync with ArraysSupport.java + public static final int T_BOOLEAN = 4; + public static final int T_CHAR = 5; + public static final int T_BYTE = 8; + public static final int T_SHORT = 9; + public static final int T_INT = 10; + + public VectorizedHashCodeInvocationPlugin(String name) { + super(name, Object.class, int.class, int.class, int.class, int.class); + } + + @Override + public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, + ValueNode array, ValueNode fromIndex, ValueNode length, ValueNode initialValue, ValueNode basicType) { + try (InvocationPluginHelper helper = new InvocationPluginHelper(b, targetMethod)) { + if (basicType.isConstant()) { + ValueNode arrayStart; + int basicTypeAsInt = basicType.asJavaConstant().asInt(); + JavaKind componentType = switch (basicTypeAsInt) { + case T_BOOLEAN -> JavaKind.Boolean; + case T_CHAR -> JavaKind.Char; + case T_BYTE -> JavaKind.Byte; + case T_SHORT -> JavaKind.Short; + case T_INT -> JavaKind.Int; + default -> throw GraalError.shouldNotReachHere("Unsupported kind " + basicTypeAsInt); + }; + + // for T_CHAR, the intrinsic accepts both byte[] and char[] + arrayStart = helper.arrayElementPointer(array, componentType, fromIndex, componentType == JavaKind.Char || componentType == JavaKind.Boolean); + b.addPush(JavaKind.Int, new VectorizedHashCodeNode(arrayStart, length, initialValue, componentType)); + return true; + } + } + return false; + } + } + } diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/replacements/amd64/AMD64GraphBuilderPlugins.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/replacements/amd64/AMD64GraphBuilderPlugins.java index 610e058bb050..41e6aceb6fc2 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/replacements/amd64/AMD64GraphBuilderPlugins.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/replacements/amd64/AMD64GraphBuilderPlugins.java @@ -40,7 +40,6 @@ import jdk.graal.compiler.core.common.calc.Condition; import jdk.graal.compiler.core.common.memory.BarrierType; import jdk.graal.compiler.core.common.memory.MemoryOrderMode; -import jdk.graal.compiler.debug.GraalError; import jdk.graal.compiler.nodes.ConstantNode; import jdk.graal.compiler.nodes.NamedLocationIdentity; import jdk.graal.compiler.nodes.NodeView; @@ -74,20 +73,18 @@ import jdk.graal.compiler.replacements.StringUTF16CompressNode; import jdk.graal.compiler.replacements.StringUTF16Snippets; import jdk.graal.compiler.replacements.TargetGraphBuilderPlugins; -import jdk.graal.compiler.replacements.nodes.BinaryMathIntrinsicNode; -import jdk.graal.compiler.replacements.nodes.CountTrailingZerosNode; -import jdk.graal.compiler.replacements.nodes.FloatToHalfFloatNode; -import jdk.graal.compiler.replacements.nodes.FusedMultiplyAddNode; -import jdk.graal.compiler.replacements.nodes.VectorizedHashCodeNode; import jdk.graal.compiler.replacements.nodes.ArrayCompareToNode; import jdk.graal.compiler.replacements.nodes.ArrayIndexOfNode; +import jdk.graal.compiler.replacements.nodes.BinaryMathIntrinsicNode; import jdk.graal.compiler.replacements.nodes.BitCountNode; import jdk.graal.compiler.replacements.nodes.CountLeadingZerosNode; +import jdk.graal.compiler.replacements.nodes.CountTrailingZerosNode; +import jdk.graal.compiler.replacements.nodes.FloatToHalfFloatNode; +import jdk.graal.compiler.replacements.nodes.FusedMultiplyAddNode; import jdk.graal.compiler.replacements.nodes.HalfFloatToFloatNode; import jdk.graal.compiler.replacements.nodes.UnaryMathIntrinsicNode; import jdk.graal.compiler.replacements.nodes.UnaryMathIntrinsicNode.UnaryOperation; import jdk.graal.compiler.serviceprovider.JavaVersionUtil; - import jdk.vm.ci.amd64.AMD64; import jdk.vm.ci.amd64.AMD64.CPUFeature; import jdk.vm.ci.code.Architecture; @@ -118,7 +115,6 @@ public void run() { registerMathPlugins(invocationPlugins, arch, replacements); registerStrictMathPlugins(invocationPlugins, arch, replacements); registerArraysEqualsPlugins(invocationPlugins, replacements); - registerArraysSupportPlugins(invocationPlugins, arch, replacements); } }); } @@ -559,44 +555,4 @@ private static void registerArraysEqualsPlugins(InvocationPlugins plugins, Repla r.register(new StandardGraphBuilderPlugins.ArrayEqualsInvocationPlugin(JavaKind.Double, double[].class, double[].class)); } - // Sync with ArraysSupport.java - public static final int T_BOOLEAN = 4; - public static final int T_CHAR = 5; - public static final int T_BYTE = 8; - public static final int T_SHORT = 9; - public static final int T_INT = 10; - - private static void registerArraysSupportPlugins(InvocationPlugins plugins, AMD64 arch, Replacements replacements) { - Registration r = new Registration(plugins, "jdk.internal.util.ArraysSupport", replacements); - - if (JavaVersionUtil.JAVA_SPEC >= 21) { - r.registerConditional(VectorizedHashCodeNode.isSupported(arch), new InvocationPlugin("vectorizedHashCode", Object.class, int.class, int.class, int.class, int.class) { - @Override - public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, - ValueNode array, ValueNode fromIndex, ValueNode length, ValueNode initialValue, ValueNode basicType) { - try (InvocationPluginHelper helper = new InvocationPluginHelper(b, targetMethod)) { - if (basicType.isConstant()) { - ValueNode arrayStart; - int basicTypeAsInt = basicType.asJavaConstant().asInt(); - JavaKind componentType = switch (basicTypeAsInt) { - case T_BOOLEAN -> JavaKind.Boolean; - case T_CHAR -> JavaKind.Char; - case T_BYTE -> JavaKind.Byte; - case T_SHORT -> JavaKind.Short; - case T_INT -> JavaKind.Int; - default -> throw GraalError.shouldNotReachHere("Unsupported kind " + basicTypeAsInt); - }; - - // for T_CHAR, the intrinsic accepts both byte[] and char[] - arrayStart = helper.arrayElementPointer(array, componentType, fromIndex, componentType == JavaKind.Char || componentType == JavaKind.Boolean); - b.addPush(JavaKind.Int, new VectorizedHashCodeNode(arrayStart, length, initialValue, componentType)); - return true; - } - } - return false; - } - }); - } - } - } diff --git a/substratevm/src/com.oracle.svm.core.graal.aarch64/src/com/oracle/svm/core/graal/aarch64/SubstrateAArch64GraphBuilderPlugins.java b/substratevm/src/com.oracle.svm.core.graal.aarch64/src/com/oracle/svm/core/graal/aarch64/SubstrateAArch64GraphBuilderPlugins.java index b9eb8b448280..e4b20d3df348 100644 --- a/substratevm/src/com.oracle.svm.core.graal.aarch64/src/com/oracle/svm/core/graal/aarch64/SubstrateAArch64GraphBuilderPlugins.java +++ b/substratevm/src/com.oracle.svm.core.graal.aarch64/src/com/oracle/svm/core/graal/aarch64/SubstrateAArch64GraphBuilderPlugins.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2023, 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,6 +24,15 @@ */ package com.oracle.svm.core.graal.aarch64; +import org.graalvm.nativeimage.Platform; +import org.graalvm.nativeimage.Platforms; + +import com.oracle.svm.core.ParsingReason; +import com.oracle.svm.core.SubstrateOptions; +import com.oracle.svm.core.config.ConfigurationValues; +import com.oracle.svm.core.feature.AutomaticallyRegisteredFeature; +import com.oracle.svm.core.feature.InternalFeature; + import jdk.graal.compiler.api.replacements.SnippetReflectionProvider; import jdk.graal.compiler.nodes.ComputeObjectAddressNode; import jdk.graal.compiler.nodes.ValueNode; @@ -33,15 +42,10 @@ import jdk.graal.compiler.nodes.graphbuilderconf.InvocationPlugins; import jdk.graal.compiler.nodes.spi.Replacements; import jdk.graal.compiler.phases.util.Providers; +import jdk.graal.compiler.replacements.StandardGraphBuilderPlugins; +import jdk.graal.compiler.replacements.nodes.VectorizedHashCodeNode; import jdk.graal.compiler.replacements.nodes.VectorizedMismatchNode; -import org.graalvm.nativeimage.Platform; -import org.graalvm.nativeimage.Platforms; - -import com.oracle.svm.core.ParsingReason; -import com.oracle.svm.core.SubstrateOptions; -import com.oracle.svm.core.feature.AutomaticallyRegisteredFeature; -import com.oracle.svm.core.feature.InternalFeature; - +import jdk.graal.compiler.serviceprovider.JavaVersionUtil; import jdk.vm.ci.meta.JavaKind; import jdk.vm.ci.meta.ResolvedJavaMethod; @@ -68,5 +72,9 @@ public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Rec return true; } }); + if (JavaVersionUtil.JAVA_SPEC >= 21) { + r.registerConditional(VectorizedHashCodeNode.isSupported(ConfigurationValues.getTarget().arch), + new StandardGraphBuilderPlugins.VectorizedHashCodeInvocationPlugin("vectorizedHashCode")); + } } } diff --git a/substratevm/src/com.oracle.svm.core.graal.amd64/src/com/oracle/svm/core/graal/amd64/SubstrateAMD64GraphBuilderPlugins.java b/substratevm/src/com.oracle.svm.core.graal.amd64/src/com/oracle/svm/core/graal/amd64/SubstrateAMD64GraphBuilderPlugins.java index 94917e69d287..9153949b128f 100644 --- a/substratevm/src/com.oracle.svm.core.graal.amd64/src/com/oracle/svm/core/graal/amd64/SubstrateAMD64GraphBuilderPlugins.java +++ b/substratevm/src/com.oracle.svm.core.graal.amd64/src/com/oracle/svm/core/graal/amd64/SubstrateAMD64GraphBuilderPlugins.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2023, 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,6 +24,15 @@ */ package com.oracle.svm.core.graal.amd64; +import org.graalvm.nativeimage.Platform; +import org.graalvm.nativeimage.Platforms; + +import com.oracle.svm.core.ParsingReason; +import com.oracle.svm.core.SubstrateOptions; +import com.oracle.svm.core.config.ConfigurationValues; +import com.oracle.svm.core.feature.AutomaticallyRegisteredFeature; +import com.oracle.svm.core.feature.InternalFeature; + import jdk.graal.compiler.api.replacements.SnippetReflectionProvider; import jdk.graal.compiler.nodes.ComputeObjectAddressNode; import jdk.graal.compiler.nodes.ValueNode; @@ -33,15 +42,10 @@ import jdk.graal.compiler.nodes.graphbuilderconf.InvocationPlugins; import jdk.graal.compiler.nodes.spi.Replacements; import jdk.graal.compiler.phases.util.Providers; +import jdk.graal.compiler.replacements.StandardGraphBuilderPlugins; +import jdk.graal.compiler.replacements.nodes.VectorizedHashCodeNode; import jdk.graal.compiler.replacements.nodes.VectorizedMismatchNode; -import org.graalvm.nativeimage.Platform; -import org.graalvm.nativeimage.Platforms; - -import com.oracle.svm.core.ParsingReason; -import com.oracle.svm.core.SubstrateOptions; -import com.oracle.svm.core.feature.InternalFeature; -import com.oracle.svm.core.feature.AutomaticallyRegisteredFeature; - +import jdk.graal.compiler.serviceprovider.JavaVersionUtil; import jdk.vm.ci.meta.JavaKind; import jdk.vm.ci.meta.ResolvedJavaMethod; @@ -68,5 +72,9 @@ public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Rec return true; } }); + if (JavaVersionUtil.JAVA_SPEC >= 21) { + r.registerConditional(VectorizedHashCodeNode.isSupported(ConfigurationValues.getTarget().arch), + new StandardGraphBuilderPlugins.VectorizedHashCodeInvocationPlugin("vectorizedHashCode")); + } } } From 20b4bd8515b67e167852f46bc1ef1f2ffc30bb9d Mon Sep 17 00:00:00 2001 From: Andreas Woess Date: Mon, 13 Nov 2023 23:38:15 +0100 Subject: [PATCH 014/593] Use MADD instruction to speed up tail loop. --- .../aarch64/AArch64VectorizedHashCodeOp.java | 61 +++++++++---------- 1 file changed, 28 insertions(+), 33 deletions(-) diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/aarch64/AArch64VectorizedHashCodeOp.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/aarch64/AArch64VectorizedHashCodeOp.java index 73003d6d3e0d..84863bf30752 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/aarch64/AArch64VectorizedHashCodeOp.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/aarch64/AArch64VectorizedHashCodeOp.java @@ -367,39 +367,34 @@ public void emitCode(CompilationResultBuilder crb, AArch64MacroAssembler masm) { // for (; i < cnt1 ; i += 2) { masm.bind(labelShortUnrolledLoopBegin); - // result *= 31**2; - masm.mov(tmp3, 961); - masm.mul(32, result, result, tmp3); - - // result += ary1[index-1] * 31 - arraysHashcodeElload(masm, tmp2, postIndexAddr, arrayKind); - masm.mov(32, tmp3, tmp2); - masm.lsl(32, tmp3, tmp3, 5); - masm.sub(32, tmp3, tmp3, tmp2); - masm.add(32, result, result, tmp3); - - // result += ary1[index] - arraysHashcodeElload(masm, tmp3, postIndexAddr, arrayKind); - masm.add(32, result, result, tmp3); - // i += 2 - masm.add(32, index, index, 2); - - masm.cmp(32, index, cnt1); - masm.branchConditionally(ConditionFlag.LT, labelShortUnrolledLoopBegin); - - // } - // if (i >= cnt1) { - masm.bind(labelShortUnrolledLoopExit); - // masm.cmp(32, index, cnt1); // already compared above - masm.branchConditionally(ConditionFlag.GT, labelEnd); - // result *= 31; - masm.mov(32, tmp2, result); - masm.lsl(32, result, result, 5); - masm.sub(32, result, result, tmp2); - - // result += ary1[index - 1] - arraysHashcodeElload(masm, tmp3, postIndexAddr, arrayKind); - masm.add(32, result, result, tmp3); + try (var scratch1 = masm.getScratchRegister(); var scratch2 = masm.getScratchRegister()) { + var tmp961 = scratch1.getRegister(); + var tmp31 = scratch2.getRegister(); + // result *= 31**2; + // result += ary1[index-1] * 31 + ary1[index] + arraysHashcodeElload(masm, tmp2, postIndexAddr, arrayKind); + arraysHashcodeElload(masm, tmp3, postIndexAddr, arrayKind); + masm.mov(tmp31, 31); + masm.madd(32, tmp3, tmp2, tmp31, tmp3); + masm.mov(tmp961, 961); + masm.madd(32, result, result, tmp961, tmp3); + // i += 2 + masm.add(32, index, index, 2); + + masm.cmp(32, index, cnt1); + masm.branchConditionally(ConditionFlag.LT, labelShortUnrolledLoopBegin); + + // } + // if (i >= cnt1) { + masm.bind(labelShortUnrolledLoopExit); + // masm.cmp(32, index, cnt1); // already compared right above and before the jump here + masm.branchConditionally(ConditionFlag.GT, labelEnd); + // result *= 31; + // result += ary1[index - 1] + arraysHashcodeElload(masm, tmp3, postIndexAddr, arrayKind); + masm.mov(tmp31, 31); + masm.madd(32, result, result, tmp31, tmp3); + } // } masm.bind(labelEnd); } From b0caf1a00011864a9c0a34a0b5fcba581ee1023b Mon Sep 17 00:00:00 2001 From: Andreas Woess Date: Tue, 14 Nov 2023 00:12:03 +0100 Subject: [PATCH 015/593] Move constant register moves out of the loop. --- .../aarch64/AArch64VectorizedHashCodeOp.java | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/aarch64/AArch64VectorizedHashCodeOp.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/aarch64/AArch64VectorizedHashCodeOp.java index 84863bf30752..25fa2148ac12 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/aarch64/AArch64VectorizedHashCodeOp.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/aarch64/AArch64VectorizedHashCodeOp.java @@ -365,18 +365,19 @@ public void emitCode(CompilationResultBuilder crb, AArch64MacroAssembler masm) { masm.cmp(32, index, cnt1); masm.branchConditionally(ConditionFlag.GE, labelShortUnrolledLoopExit); - // for (; i < cnt1 ; i += 2) { - masm.bind(labelShortUnrolledLoopBegin); try (var scratch1 = masm.getScratchRegister(); var scratch2 = masm.getScratchRegister()) { - var tmp961 = scratch1.getRegister(); - var tmp31 = scratch2.getRegister(); + var tmp31 = scratch1.getRegister(); + var tmp961 = scratch2.getRegister(); + masm.mov(tmp31, 31); + masm.mov(tmp961, 961); + + // for (; i < cnt1 ; i += 2) { + masm.bind(labelShortUnrolledLoopBegin); // result *= 31**2; // result += ary1[index-1] * 31 + ary1[index] - arraysHashcodeElload(masm, tmp2, postIndexAddr, arrayKind); - arraysHashcodeElload(masm, tmp3, postIndexAddr, arrayKind); - masm.mov(tmp31, 31); + arraysHashcodeElload(masm, tmp2, postIndexAddr, arrayKind); // index-1 + arraysHashcodeElload(masm, tmp3, postIndexAddr, arrayKind); // index masm.madd(32, tmp3, tmp2, tmp31, tmp3); - masm.mov(tmp961, 961); masm.madd(32, result, result, tmp961, tmp3); // i += 2 masm.add(32, index, index, 2); @@ -391,8 +392,8 @@ public void emitCode(CompilationResultBuilder crb, AArch64MacroAssembler masm) { masm.branchConditionally(ConditionFlag.GT, labelEnd); // result *= 31; // result += ary1[index - 1] - arraysHashcodeElload(masm, tmp3, postIndexAddr, arrayKind); masm.mov(tmp31, 31); + arraysHashcodeElload(masm, tmp3, postIndexAddr, arrayKind); // index-1 masm.madd(32, result, result, tmp31, tmp3); } // } From f90db6781fc1ae7d1e31df4e1830c134fd551d2c Mon Sep 17 00:00:00 2001 From: Andreas Woess Date: Mon, 20 Nov 2023 17:12:22 +0100 Subject: [PATCH 016/593] Cleanup: Drop unused powers of 31 from data constant. --- .../aarch64/AArch64VectorizedHashCodeOp.java | 32 ++----------------- 1 file changed, 2 insertions(+), 30 deletions(-) diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/aarch64/AArch64VectorizedHashCodeOp.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/aarch64/AArch64VectorizedHashCodeOp.java index 25fa2148ac12..8285761c01a7 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/aarch64/AArch64VectorizedHashCodeOp.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/aarch64/AArch64VectorizedHashCodeOp.java @@ -91,23 +91,6 @@ private static void arraysHashcodeElload(AArch64MacroAssembler masm, Register ds } private static final int[] POWERS_OF_31_BACKWARDS = new int[]{ - 2111290369, - -2010103841, - 350799937, - 11316127, - 693101697, - -254736545, - 961614017, - 31019807, - -2077209343, - -67006753, - 1244764481, - -2038056289, - 211350913, - -408824225, - -844471871, - -997072353, - 1353309697, -510534177, 1507551809, -505558625, @@ -191,19 +174,8 @@ public void emitCode(CompilationResultBuilder crb, AArch64MacroAssembler masm) { Register next = tmp3; // vnext = IntVector.broadcast(I128, power_of_31_backwards[0]); - boolean useConstant = true; - if (useConstant) { - int nextValue = POWERS_OF_31_BACKWARDS[POWERS_OF_31_BACKWARDS.length - elementsPerIteration - 1]; - masm.mov(next, nextValue); - } else { - crb.recordDataReferenceInCode(powersOf31); - masm.adrpAdd(next); - int nextOffset = (POWERS_OF_31_BACKWARDS.length - elementsPerIteration - 1) * JavaKind.Int.getByteCount(); - if (nextOffset != 0) { - masm.add(64, next, next, nextOffset); - } - masm.ldr(32, next, AArch64Address.createBaseRegisterOnlyAddress(32, next)); - } + int nextPow31 = POWERS_OF_31_BACKWARDS[POWERS_OF_31_BACKWARDS.length - elementsPerIteration] * 31; + masm.mov(next, nextPow31); masm.neon.dupVG(ASIMDSize.FullReg, ElementSize.Word, vnext, next); // bound = cnt1 & ~(elementsPerIteration - 1); From e4b721c568ea47d658cc391bc03a3935f52e9a6c Mon Sep 17 00:00:00 2001 From: Andreas Woess Date: Mon, 20 Nov 2023 17:28:11 +0100 Subject: [PATCH 017/593] VectorizedHashCode intrinsic only needs 9 different vector registers. --- .../compiler/lir/aarch64/AArch64VectorizedHashCodeOp.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/aarch64/AArch64VectorizedHashCodeOp.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/aarch64/AArch64VectorizedHashCodeOp.java index 8285761c01a7..a3b71fed3424 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/aarch64/AArch64VectorizedHashCodeOp.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/aarch64/AArch64VectorizedHashCodeOp.java @@ -76,7 +76,7 @@ public AArch64VectorizedHashCodeOp(LIRGeneratorTool tool, this.arrayKind = arrayKind; this.temp = allocateTempRegisters(tool, 5); - this.vectorTemp = allocateVectorRegisters(tool, 13); + this.vectorTemp = allocateVectorRegisters(tool, 9); // (1 vnext + 4 vresult + 4 vtmp/vcoef) } private static void arraysHashcodeElload(AArch64MacroAssembler masm, Register dst, AArch64Address src, JavaKind eltype) { @@ -133,7 +133,7 @@ public void emitCode(CompilationResultBuilder crb, AArch64MacroAssembler masm) { Register vnext = asRegister(vectorTemp[0]); Register[] vcoef = {asRegister(vectorTemp[1]), asRegister(vectorTemp[2]), asRegister(vectorTemp[3]), asRegister(vectorTemp[4])}; Register[] vresult = {asRegister(vectorTemp[5]), asRegister(vectorTemp[6]), asRegister(vectorTemp[7]), asRegister(vectorTemp[8])}; - Register[] vtmp = {asRegister(vectorTemp[9]), asRegister(vectorTemp[10]), asRegister(vectorTemp[11]), asRegister(vectorTemp[12])}; + Register[] vtmp = vcoef; final boolean unsigned = arrayKind == JavaKind.Boolean || arrayKind == JavaKind.Char; final ElementSize elSize = switch (arrayKind) { From 265c382baf051c45ebc554ee43454b45ee7e5574 Mon Sep 17 00:00:00 2001 From: Andreas Woess Date: Mon, 20 Nov 2023 18:10:27 +0100 Subject: [PATCH 018/593] Cleanup: remove commented code. --- .../compiler/lir/aarch64/AArch64VectorizedHashCodeOp.java | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/aarch64/AArch64VectorizedHashCodeOp.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/aarch64/AArch64VectorizedHashCodeOp.java index a3b71fed3424..cbb29cec6109 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/aarch64/AArch64VectorizedHashCodeOp.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/aarch64/AArch64VectorizedHashCodeOp.java @@ -275,8 +275,6 @@ public void emitCode(CompilationResultBuilder crb, AArch64MacroAssembler masm) { // vresult[i] = vresult[i] * vnext + vtmp[i]; for (int idx = 0; idx < nRegs; idx++) { - // masm.neon.mulVVV(FullReg, ElementSize.Word, vresult[idx], vresult[idx], vnext); - // masm.neon.addVVV(FullReg, ElementSize.Word, vresult[idx], vresult[idx], vtmp[idx]); masm.neon.mlaVVV(ASIMDSize.FullReg, ElementSize.Word, vtmp[idx], vresult[idx], vnext); masm.neon.moveVV(ASIMDSize.FullReg, vresult[idx], vtmp[idx]); } @@ -378,7 +376,6 @@ public void emitCode(CompilationResultBuilder crb, AArch64MacroAssembler masm) { */ private static void reduceVectorLanes(AArch64MacroAssembler masm, ASIMDSize vsize, Register[] vresult) { // reduce vectors pairwise until there's only a single vector left - // e.g. vresult = vresult[0].add(vresult[1]).add(vresult[2]).add(vresult[3]); for (int nRegs = vresult.length, stride = 1; nRegs >= 2; nRegs /= 2, stride *= 2) { for (int i = 0; i < vresult.length - stride; i += 2 * stride) { masm.neon.addVVV(vsize, ElementSize.Word, vresult[i], vresult[i], vresult[i + stride]); @@ -387,7 +384,7 @@ private static void reduceVectorLanes(AArch64MacroAssembler masm, ASIMDSize vsiz masm.neon.addVVV(vsize, ElementSize.Word, vresult[0], vresult[0], vresult[(nRegs - 1) * stride]); } } - // result = vresult.reduceLanes(ADD); + // reduce vector lanes horizontally to a scalar value (vresult.reduceLanes(ADD)) masm.neon.addvSV(vsize, ElementSize.Word, vresult[0], vresult[0]); } From e125cc4451e02c1e01ce2f1dc8dc670e4ae7afe2 Mon Sep 17 00:00:00 2001 From: Andreas Woess Date: Mon, 20 Nov 2023 21:23:27 +0100 Subject: [PATCH 019/593] Extract vector element extend logic. --- .../aarch64/AArch64VectorizedHashCodeOp.java | 85 ++++++++++--------- 1 file changed, 45 insertions(+), 40 deletions(-) diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/aarch64/AArch64VectorizedHashCodeOp.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/aarch64/AArch64VectorizedHashCodeOp.java index cbb29cec6109..e9c7d724b756 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/aarch64/AArch64VectorizedHashCodeOp.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/aarch64/AArch64VectorizedHashCodeOp.java @@ -210,14 +210,6 @@ public void emitCode(CompilationResultBuilder crb, AArch64MacroAssembler masm) { : AArch64Address.createStructureImmediatePostIndexAddress(ASIMDInstruction.LD1_MULTIPLE_2R, loadVecSize, elSize, rscratch1, loadVecSize.bytes() * consecutiveRegs); masm.neon.ld1MultipleVV(loadVecSize, elSize, vtmp[ldVi], vtmp[ldVi + 1], indexedAddr); - // extend byte to halfword - xtlVV(masm, unsigned, elSize, vtmp[ldVi + 1], vtmp[ldVi + 1]); - xtlVV(masm, unsigned, elSize, vtmp[ldVi], vtmp[ldVi]); - // extend halfword to word - xtl2VV(masm, unsigned, ElementSize.HalfWord, vtmp[ldVi + 3], vtmp[ldVi + 1]); - xtlVV(masm, unsigned, ElementSize.HalfWord, vtmp[ldVi + 2], vtmp[ldVi + 1]); - xtl2VV(masm, unsigned, ElementSize.HalfWord, vtmp[ldVi + 1], vtmp[ldVi]); - xtlVV(masm, unsigned, ElementSize.HalfWord, vtmp[ldVi], vtmp[ldVi]); } else { assert consecutiveRegs == 4 : consecutiveRegs; assert elSize == ElementSize.HalfWord || elSize == ElementSize.Word : elSize; @@ -226,13 +218,8 @@ public void emitCode(CompilationResultBuilder crb, AArch64MacroAssembler masm) { : AArch64Address.createStructureImmediatePostIndexAddress(ASIMDInstruction.LD1_MULTIPLE_4R, loadVecSize, elSize, rscratch1, loadVecSize.bytes() * consecutiveRegs); masm.neon.ld1MultipleVVVV(loadVecSize, elSize, vtmp[ldVi], vtmp[ldVi + 1], vtmp[ldVi + 2], vtmp[ldVi + 3], indexedAddr); - if (elSize == ElementSize.HalfWord) { - for (int i = 0; i < consecutiveRegs; i++) { - // extend halfword to word - xtlVV(masm, unsigned, elSize, vtmp[ldVi + i], vtmp[ldVi + i]); - } - } } + extendVectorsToWord(masm, unsigned, loadVecSize, elSize, vtmp, ldVi, consecutiveRegs); } } else { int regsFilledPerLoad = loadVecSize.bytes() / ElementSize.Word.bytes() / elSize.bytes(); @@ -243,32 +230,7 @@ public void emitCode(CompilationResultBuilder crb, AArch64MacroAssembler masm) { // load vector size chunk of memory into vtmp, and optionally increment address for (int ldVi = 0; ldVi < nRegs; ldVi += regsFilledPerLoad) { masm.neon.ld1MultipleV(loadVecSize, elSize, vtmp[ldVi], indexedAddr); - } - // expand (i.e. zero- or sign-extend) vector elements to int size - if (elSize == ElementSize.Byte || elSize == ElementSize.HalfWord) { - for (int ldVi = 0; ldVi < nRegs; ldVi += regsFilledPerLoad) { - if (loadVecSize == ASIMDSize.HalfReg) { - xtlVV(masm, unsigned, elSize, vtmp[ldVi], vtmp[ldVi]); - } else { - xtl2VV(masm, unsigned, elSize, vtmp[ldVi + 1], vtmp[ldVi]); - xtlVV(masm, unsigned, elSize, vtmp[ldVi], vtmp[ldVi]); - } - } - if (elSize == ElementSize.Byte) { - for (int ldVi = 0; ldVi < nRegs; ldVi += regsFilledPerLoad) { - if (loadVecSize == ASIMDSize.HalfReg) { - assert regsFilledPerLoad == 2 : regsFilledPerLoad; - xtl2VV(masm, unsigned, ElementSize.HalfWord, vtmp[ldVi + 1], vtmp[ldVi]); - xtlVV(masm, unsigned, ElementSize.HalfWord, vtmp[ldVi], vtmp[ldVi]); - } else { - assert regsFilledPerLoad == 4 : regsFilledPerLoad; - xtl2VV(masm, unsigned, ElementSize.HalfWord, vtmp[ldVi + 3], vtmp[ldVi + 1]); - xtlVV(masm, unsigned, ElementSize.HalfWord, vtmp[ldVi + 2], vtmp[ldVi + 1]); - xtl2VV(masm, unsigned, ElementSize.HalfWord, vtmp[ldVi + 1], vtmp[ldVi]); - xtlVV(masm, unsigned, ElementSize.HalfWord, vtmp[ldVi], vtmp[ldVi]); - } - } - } + extendVectorsToWord(masm, unsigned, loadVecSize, elSize, vtmp, ldVi, consecutiveRegs); } } } @@ -370,6 +332,49 @@ public void emitCode(CompilationResultBuilder crb, AArch64MacroAssembler masm) { masm.bind(labelEnd); } + /** + * Zero-or-sign-extend byte-or-halfword vector registers to word-size vectors. + */ + private static void extendVectorsToWord(AArch64MacroAssembler masm, boolean unsigned, ASIMDSize startVecSize, ElementSize startElSize, Register[] vtmp, int start, int startSourceRegs) { + ASIMDSize vecSize = startVecSize; + ElementSize srcElSize = startElSize; + ElementSize endElSize = ElementSize.Word; + int srcRegs = startSourceRegs; + while (srcElSize.bytes() < endElSize.bytes()) { + if (vecSize == ASIMDSize.HalfReg) { + vecSize = ASIMDSize.FullReg; + extendSameRegs(masm, unsigned, srcElSize, vtmp, start, srcRegs); + } else { + extendPairwise(masm, unsigned, srcElSize, vtmp, start, srcRegs); + srcRegs *= 2; + } + srcElSize = srcElSize.expand(); + } + } + + /** + * Zero-or-sign-extend byte-to-halfword or halfword-to-word within the same register. + */ + private static void extendSameRegs(AArch64MacroAssembler masm, boolean unsigned, ElementSize srcElSize, Register[] vtmp, int start, int srcRegs) { + for (int i = start; i < start + srcRegs; i++) { + xtlVV(masm, unsigned, srcElSize, vtmp[start + i], vtmp[start + i]); + } + } + + /** + * Zero-or-sign-extend 1 to 2 or 2 to 4 vectors (byte-to-halfword or halfword-to-word). + * + * Note that the registers need to be written in the right order to not overwrite any source + * register before we've extended all its elements. + */ + private static void extendPairwise(AArch64MacroAssembler masm, boolean unsigned, ElementSize srcElSize, Register[] vtmp, int start, int srcRegs) { + int dstRegs = srcRegs * 2; + for (int srci = start + srcRegs - 1, dsti = start + dstRegs - 1; srci >= start; srci -= 1, dsti -= 2) { + xtl2VV(masm, unsigned, srcElSize, vtmp[dsti], vtmp[srci]); + xtlVV(masm, unsigned, srcElSize, vtmp[dsti - 1], vtmp[srci]); + } + } + /** * Reduces elements from multiple vectors to a single vector and then reduces that vector's * lanes to a single scalar value in {@code vresult[0]}. From aa6c97f97ac36642830eee64b713c80e8ddd7aa6 Mon Sep 17 00:00:00 2001 From: Andreas Woess Date: Mon, 20 Nov 2023 20:35:00 +0100 Subject: [PATCH 020/593] Extract vector load logic. --- .../aarch64/AArch64VectorizedHashCodeOp.java | 143 ++++++++++++------ 1 file changed, 96 insertions(+), 47 deletions(-) diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/aarch64/AArch64VectorizedHashCodeOp.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/aarch64/AArch64VectorizedHashCodeOp.java index e9c7d724b756..168ce48730c0 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/aarch64/AArch64VectorizedHashCodeOp.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/aarch64/AArch64VectorizedHashCodeOp.java @@ -147,6 +147,7 @@ public void emitCode(CompilationResultBuilder crb, AArch64MacroAssembler masm) { assert nRegs >= 2 && CodeUtil.isPowerOf2(nRegs) : "number of vectors must be >= 2 and a power of 2"; final int elementsPerVector = ASIMDSize.FullReg.bytes() / ElementSize.Word.bytes(); final int elementsPerIteration = elementsPerVector * nRegs; + final int maxConsecutiveRegs = Math.min(nRegs, 4); // @formatter:off // elementsPerIteration = 16; @@ -197,41 +198,17 @@ public void emitCode(CompilationResultBuilder crb, AArch64MacroAssembler masm) { masm.loadAddress(rscratch1, dataChunkStart); ASIMDSize loadVecSize = elSize == ElementSize.Byte || elSize == ElementSize.HalfWord ? ASIMDSize.HalfReg : ASIMDSize.FullReg; - int consecutiveRegs = elSize == ElementSize.Byte ? 2 : 4; - boolean useMultiRegisterLoad = elSize == ElementSize.Byte && allConsecutiveSIMDRegisters(vtmp) && nRegs >= 4; - if (useMultiRegisterLoad) { - int regsFilledPerLoad = 4; - for (int ldVi = 0; ldVi < nRegs; ldVi += regsFilledPerLoad) { - // load vector size chunk of memory into vtmp, and optionally increment address - if (consecutiveRegs == 2) { - assert elSize == ElementSize.Byte : elSize; - AArch64Address indexedAddr = nRegs == regsFilledPerLoad - ? AArch64Address.createStructureNoOffsetAddress(rscratch1) - : AArch64Address.createStructureImmediatePostIndexAddress(ASIMDInstruction.LD1_MULTIPLE_2R, - loadVecSize, elSize, rscratch1, loadVecSize.bytes() * consecutiveRegs); - masm.neon.ld1MultipleVV(loadVecSize, elSize, vtmp[ldVi], vtmp[ldVi + 1], indexedAddr); - } else { - assert consecutiveRegs == 4 : consecutiveRegs; - assert elSize == ElementSize.HalfWord || elSize == ElementSize.Word : elSize; - AArch64Address indexedAddr = nRegs == regsFilledPerLoad - ? AArch64Address.createStructureNoOffsetAddress(rscratch1) - : AArch64Address.createStructureImmediatePostIndexAddress(ASIMDInstruction.LD1_MULTIPLE_4R, - loadVecSize, elSize, rscratch1, loadVecSize.bytes() * consecutiveRegs); - masm.neon.ld1MultipleVVVV(loadVecSize, elSize, vtmp[ldVi], vtmp[ldVi + 1], vtmp[ldVi + 2], vtmp[ldVi + 3], indexedAddr); - } - extendVectorsToWord(masm, unsigned, loadVecSize, elSize, vtmp, ldVi, consecutiveRegs); - } - } else { - int regsFilledPerLoad = loadVecSize.bytes() / ElementSize.Word.bytes() / elSize.bytes(); - AArch64Address indexedAddr = nRegs == regsFilledPerLoad - ? AArch64Address.createStructureNoOffsetAddress(rscratch1) - : AArch64Address.createStructureImmediatePostIndexAddress(ASIMDInstruction.LD1_MULTIPLE_1R, - loadVecSize, elSize, rscratch1, loadVecSize.bytes()); - // load vector size chunk of memory into vtmp, and optionally increment address - for (int ldVi = 0; ldVi < nRegs; ldVi += regsFilledPerLoad) { - masm.neon.ld1MultipleV(loadVecSize, elSize, vtmp[ldVi], indexedAddr); - extendVectorsToWord(masm, unsigned, loadVecSize, elSize, vtmp, ldVi, consecutiveRegs); - } + // number of registers needed to load to fill 4 full vectors. + // i.e. byte: 1 full or 2 half, halfword: 2 full or 4 half, word: 4 full. + int consecutiveRegs = Math.min(elSize.bytes() * ASIMDSize.FullReg.bytes() / loadVecSize.bytes(), maxConsecutiveRegs); + int extensionFactor = (ElementSize.Word.bytes() / elSize.bytes()) / (ASIMDSize.FullReg.bytes() / loadVecSize.bytes()); + int regsFilledPerLoad = consecutiveRegs * extensionFactor; + boolean postIndex = consecutiveRegs > 2; + for (int ldVi = 0; ldVi < nRegs; ldVi += regsFilledPerLoad) { + loadConsecutiveVectors(masm, loadVecSize, elSize, rscratch1, vtmp, ldVi, consecutiveRegs, postIndex, false); + } + for (int ldVi = 0; ldVi < nRegs; ldVi += regsFilledPerLoad) { + extendVectorsToWord(masm, unsigned, loadVecSize, elSize, vtmp, ldVi, consecutiveRegs); } } @@ -264,15 +241,9 @@ public void emitCode(CompilationResultBuilder crb, AArch64MacroAssembler masm) { if (coefOffset != 0) { masm.add(64, coefAddrReg, coefAddrReg, coefOffset); } - if (allConsecutiveSIMDRegisters(vcoef) && vcoef.length == 4) { - AArch64Address coefAddr = AArch64Address.createStructureNoOffsetAddress(tmp2); - masm.neon.ld1MultipleVVVV(ASIMDSize.FullReg, ElementSize.Word, vcoef[0], vcoef[1], vcoef[2], vcoef[3], coefAddr); - } else { - AArch64Address coefAddrPostIndex = AArch64Address.createStructureImmediatePostIndexAddress(ASIMDInstruction.LD1_MULTIPLE_1R, - ASIMDSize.FullReg, ElementSize.Word, coefAddrReg, ASIMDSize.FullReg.bytes()); - for (int idx = 0; idx < nRegs; idx++) { - masm.neon.ld1MultipleV(ASIMDSize.FullReg, ElementSize.Word, vcoef[idx], coefAddrPostIndex); - } + for (int i = 0; i < nRegs; i += maxConsecutiveRegs) { + boolean postIndex = maxConsecutiveRegs < nRegs; + loadConsecutiveVectors(masm, ASIMDSize.FullReg, ElementSize.Word, coefAddrReg, vcoef, i, maxConsecutiveRegs, postIndex, false); } // vresult *= vcoef; @@ -332,14 +303,92 @@ public void emitCode(CompilationResultBuilder crb, AArch64MacroAssembler masm) { masm.bind(labelEnd); } + /** + * Load consecutive vector registers from a register-based memory address, and optionally + * increment the address register by the loaded bytes. + */ + private static void loadConsecutiveVectors(AArch64MacroAssembler masm, + ASIMDSize vecSize, ElementSize elSize, Register indexedAddrReg, Register[] vreg, + int startReg, int consecutiveRegs, boolean postIndex, boolean preferLd1) { + assert consecutiveRegs <= 4 : consecutiveRegs; + switch (consecutiveRegs) { + case 2 -> { + if (preferLd1 && allConsecutiveSIMDRegisters(vreg)) { + masm.neon.ld1MultipleVV(vecSize, elSize, vreg[startReg], vreg[startReg + 1], + addressForLd1M(2, vecSize, elSize, indexedAddrReg, postIndex)); + } else { + masm.fldp(vecSize.bits(), vreg[startReg], vreg[startReg + 1], + addressForLdp(vecSize, indexedAddrReg, postIndex, 0)); + } + } + case 4 -> { + if (preferLd1 && allConsecutiveSIMDRegisters(vreg)) { + masm.neon.ld1MultipleVVVV(vecSize, elSize, + vreg[startReg], vreg[startReg + 1], vreg[startReg + 2], vreg[startReg + 3], + addressForLd1M(4, vecSize, elSize, indexedAddrReg, postIndex)); + } else { + masm.fldp(vecSize.bits(), vreg[startReg], vreg[startReg + 1], + addressForLdp(vecSize, indexedAddrReg, postIndex, 0)); + masm.fldp(vecSize.bits(), vreg[startReg + 2], vreg[startReg + 3], + addressForLdp(vecSize, indexedAddrReg, postIndex, 2)); + } + } + default -> { + for (int i = 0; i < consecutiveRegs; i++) { + if (preferLd1 && (consecutiveRegs == 1 || postIndex)) { + masm.neon.ld1MultipleV(vecSize, elSize, vreg[startReg + i], + addressForLd1M(1, vecSize, elSize, indexedAddrReg, postIndex)); + } else { + masm.fldr(vecSize.bits(), vreg[startReg + i], + addressForLdr(vecSize, indexedAddrReg, postIndex, i)); + } + } + } + } + } + + private static AArch64Address addressForLdr(ASIMDSize vecSize, Register indexedAddrReg, boolean postIndex, int offsetScaled) { + int scale = vecSize.bytes(); + if (postIndex) { + return AArch64Address.createImmediateAddress(vecSize.bits(), AddressingMode.IMMEDIATE_POST_INDEXED, indexedAddrReg, scale); + } else { + return AArch64Address.createImmediateAddress(vecSize.bits(), AddressingMode.IMMEDIATE_UNSIGNED_SCALED, indexedAddrReg, offsetScaled * scale); + } + } + + private static AArch64Address addressForLdp(ASIMDSize vecSize, Register indexedAddrReg, boolean postIndex, int offsetScaled) { + int scale = vecSize.bytes(); + if (postIndex) { + return AArch64Address.createImmediateAddress(vecSize.bits(), AddressingMode.IMMEDIATE_PAIR_POST_INDEXED, indexedAddrReg, 2 * scale); + } else { + return AArch64Address.createImmediateAddress(vecSize.bits(), AddressingMode.IMMEDIATE_PAIR_SIGNED_SCALED, indexedAddrReg, offsetScaled * scale); + } + } + + private static AArch64Address addressForLd1M(int loadedVectors, ASIMDSize vecSize, ElementSize elSize, Register indexedAddrReg, boolean postIndex) { + if (postIndex) { + var ld1Instruction = switch (loadedVectors) { + case 1 -> ASIMDInstruction.LD1_MULTIPLE_1R; + case 2 -> ASIMDInstruction.LD1_MULTIPLE_2R; + case 3 -> ASIMDInstruction.LD1_MULTIPLE_3R; + case 4 -> ASIMDInstruction.LD1_MULTIPLE_4R; + default -> throw GraalError.shouldNotReachHereUnexpectedValue(loadedVectors); + }; + int incrementUnscaled = vecSize.bytes() * loadedVectors; + return AArch64Address.createStructureImmediatePostIndexAddress(ld1Instruction, vecSize, elSize, indexedAddrReg, incrementUnscaled); + } else { + return AArch64Address.createStructureNoOffsetAddress(indexedAddrReg); + } + } + /** * Zero-or-sign-extend byte-or-halfword vector registers to word-size vectors. */ - private static void extendVectorsToWord(AArch64MacroAssembler masm, boolean unsigned, ASIMDSize startVecSize, ElementSize startElSize, Register[] vtmp, int start, int startSourceRegs) { + private static void extendVectorsToWord(AArch64MacroAssembler masm, boolean unsigned, ASIMDSize startVecSize, ElementSize startElSize, Register[] vtmp, int start, int srcRegsInitial) { ASIMDSize vecSize = startVecSize; ElementSize srcElSize = startElSize; ElementSize endElSize = ElementSize.Word; - int srcRegs = startSourceRegs; + int srcRegs = srcRegsInitial; while (srcElSize.bytes() < endElSize.bytes()) { if (vecSize == ASIMDSize.HalfReg) { vecSize = ASIMDSize.FullReg; @@ -357,7 +406,7 @@ private static void extendVectorsToWord(AArch64MacroAssembler masm, boolean unsi */ private static void extendSameRegs(AArch64MacroAssembler masm, boolean unsigned, ElementSize srcElSize, Register[] vtmp, int start, int srcRegs) { for (int i = start; i < start + srcRegs; i++) { - xtlVV(masm, unsigned, srcElSize, vtmp[start + i], vtmp[start + i]); + xtlVV(masm, unsigned, srcElSize, vtmp[i], vtmp[i]); } } From 2405b879171ed87184c0db2a769ebd2c85f1c935 Mon Sep 17 00:00:00 2001 From: Andreas Woess Date: Tue, 21 Nov 2023 05:09:52 +0100 Subject: [PATCH 021/593] Allow 32-bit vector loads. --- .../aarch64/AArch64VectorizedHashCodeOp.java | 38 ++++++++++--------- 1 file changed, 20 insertions(+), 18 deletions(-) diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/aarch64/AArch64VectorizedHashCodeOp.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/aarch64/AArch64VectorizedHashCodeOp.java index 168ce48730c0..9065bdfab224 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/aarch64/AArch64VectorizedHashCodeOp.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/aarch64/AArch64VectorizedHashCodeOp.java @@ -198,17 +198,18 @@ public void emitCode(CompilationResultBuilder crb, AArch64MacroAssembler masm) { masm.loadAddress(rscratch1, dataChunkStart); ASIMDSize loadVecSize = elSize == ElementSize.Byte || elSize == ElementSize.HalfWord ? ASIMDSize.HalfReg : ASIMDSize.FullReg; + int loadVecBits = elSize.bits() * elementsPerVector; // number of registers needed to load to fill 4 full vectors. // i.e. byte: 1 full or 2 half, halfword: 2 full or 4 half, word: 4 full. - int consecutiveRegs = Math.min(elSize.bytes() * ASIMDSize.FullReg.bytes() / loadVecSize.bytes(), maxConsecutiveRegs); - int extensionFactor = (ElementSize.Word.bytes() / elSize.bytes()) / (ASIMDSize.FullReg.bytes() / loadVecSize.bytes()); + int consecutiveRegs = Math.min(elSize.bytes() * (ASIMDSize.FullReg.bits() / loadVecBits), maxConsecutiveRegs); + int extensionFactor = (ElementSize.Word.bits() / elSize.bits()) / (ASIMDSize.FullReg.bits() / loadVecBits); int regsFilledPerLoad = consecutiveRegs * extensionFactor; boolean postIndex = consecutiveRegs > 2; for (int ldVi = 0; ldVi < nRegs; ldVi += regsFilledPerLoad) { - loadConsecutiveVectors(masm, loadVecSize, elSize, rscratch1, vtmp, ldVi, consecutiveRegs, postIndex, false); + loadConsecutiveVectors(masm, loadVecSize, loadVecBits, elSize, rscratch1, vtmp, ldVi, consecutiveRegs, postIndex, false); } for (int ldVi = 0; ldVi < nRegs; ldVi += regsFilledPerLoad) { - extendVectorsToWord(masm, unsigned, loadVecSize, elSize, vtmp, ldVi, consecutiveRegs); + extendVectorsToWord(masm, unsigned, loadVecBits, elSize, vtmp, ldVi, consecutiveRegs); } } @@ -243,7 +244,7 @@ public void emitCode(CompilationResultBuilder crb, AArch64MacroAssembler masm) { } for (int i = 0; i < nRegs; i += maxConsecutiveRegs) { boolean postIndex = maxConsecutiveRegs < nRegs; - loadConsecutiveVectors(masm, ASIMDSize.FullReg, ElementSize.Word, coefAddrReg, vcoef, i, maxConsecutiveRegs, postIndex, false); + loadConsecutiveVectors(masm, ASIMDSize.FullReg, ASIMDSize.FullReg.bits(), ElementSize.Word, coefAddrReg, vcoef, i, maxConsecutiveRegs, postIndex, false); } // vresult *= vcoef; @@ -308,38 +309,39 @@ public void emitCode(CompilationResultBuilder crb, AArch64MacroAssembler masm) { * increment the address register by the loaded bytes. */ private static void loadConsecutiveVectors(AArch64MacroAssembler masm, - ASIMDSize vecSize, ElementSize elSize, Register indexedAddrReg, Register[] vreg, + ASIMDSize vecSize, int vecBits, ElementSize elSize, Register indexedAddrReg, Register[] vreg, int startReg, int consecutiveRegs, boolean postIndex, boolean preferLd1) { assert consecutiveRegs <= 4 : consecutiveRegs; switch (consecutiveRegs) { case 2 -> { - if (preferLd1 && allConsecutiveSIMDRegisters(vreg)) { + if (preferLd1 && allConsecutiveSIMDRegisters(vreg) && vecBits == vecSize.bits()) { masm.neon.ld1MultipleVV(vecSize, elSize, vreg[startReg], vreg[startReg + 1], addressForLd1M(2, vecSize, elSize, indexedAddrReg, postIndex)); } else { - masm.fldp(vecSize.bits(), vreg[startReg], vreg[startReg + 1], + masm.fldp(vecBits, vreg[startReg], vreg[startReg + 1], addressForLdp(vecSize, indexedAddrReg, postIndex, 0)); } } case 4 -> { - if (preferLd1 && allConsecutiveSIMDRegisters(vreg)) { + if (preferLd1 && allConsecutiveSIMDRegisters(vreg) && vecBits == vecSize.bits()) { masm.neon.ld1MultipleVVVV(vecSize, elSize, vreg[startReg], vreg[startReg + 1], vreg[startReg + 2], vreg[startReg + 3], addressForLd1M(4, vecSize, elSize, indexedAddrReg, postIndex)); } else { - masm.fldp(vecSize.bits(), vreg[startReg], vreg[startReg + 1], + masm.fldp(vecBits, vreg[startReg], vreg[startReg + 1], addressForLdp(vecSize, indexedAddrReg, postIndex, 0)); - masm.fldp(vecSize.bits(), vreg[startReg + 2], vreg[startReg + 3], + masm.fldp(vecBits, vreg[startReg + 2], vreg[startReg + 3], addressForLdp(vecSize, indexedAddrReg, postIndex, 2)); } } default -> { + boolean useLd1 = preferLd1 && (consecutiveRegs == 1 || postIndex) && vecBits == vecSize.bits(); for (int i = 0; i < consecutiveRegs; i++) { - if (preferLd1 && (consecutiveRegs == 1 || postIndex)) { + if (useLd1) { masm.neon.ld1MultipleV(vecSize, elSize, vreg[startReg + i], addressForLd1M(1, vecSize, elSize, indexedAddrReg, postIndex)); } else { - masm.fldr(vecSize.bits(), vreg[startReg + i], + masm.fldr(vecBits, vreg[startReg + i], addressForLdr(vecSize, indexedAddrReg, postIndex, i)); } } @@ -384,15 +386,15 @@ private static AArch64Address addressForLd1M(int loadedVectors, ASIMDSize vecSiz /** * Zero-or-sign-extend byte-or-halfword vector registers to word-size vectors. */ - private static void extendVectorsToWord(AArch64MacroAssembler masm, boolean unsigned, ASIMDSize startVecSize, ElementSize startElSize, Register[] vtmp, int start, int srcRegsInitial) { - ASIMDSize vecSize = startVecSize; + private static void extendVectorsToWord(AArch64MacroAssembler masm, boolean unsigned, int startVecBits, ElementSize startElSize, Register[] vtmp, int start, int srcRegsInitial) { + int vecBits = startVecBits; ElementSize srcElSize = startElSize; ElementSize endElSize = ElementSize.Word; int srcRegs = srcRegsInitial; - while (srcElSize.bytes() < endElSize.bytes()) { - if (vecSize == ASIMDSize.HalfReg) { - vecSize = ASIMDSize.FullReg; + while (srcElSize.bits() < endElSize.bits()) { + if (vecBits < ASIMDSize.FullReg.bits()) { extendSameRegs(masm, unsigned, srcElSize, vtmp, start, srcRegs); + vecBits *= 2; } else { extendPairwise(masm, unsigned, srcElSize, vtmp, start, srcRegs); srcRegs *= 2; From fdeaba088451ff45031c014a96d316ae8162800d Mon Sep 17 00:00:00 2001 From: Andreas Woess Date: Tue, 21 Nov 2023 05:24:00 +0100 Subject: [PATCH 022/593] Use single vector load for byte and halfword elements, too. --- .../compiler/lir/aarch64/AArch64VectorizedHashCodeOp.java | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/aarch64/AArch64VectorizedHashCodeOp.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/aarch64/AArch64VectorizedHashCodeOp.java index 9065bdfab224..7045ee4270b8 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/aarch64/AArch64VectorizedHashCodeOp.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/aarch64/AArch64VectorizedHashCodeOp.java @@ -197,8 +197,8 @@ public void emitCode(CompilationResultBuilder crb, AArch64MacroAssembler masm) { AArch64Address dataChunkStart = AArch64Address.createRegisterOffsetAddress(elSize.bits(), ary1, index, true); masm.loadAddress(rscratch1, dataChunkStart); - ASIMDSize loadVecSize = elSize == ElementSize.Byte || elSize == ElementSize.HalfWord ? ASIMDSize.HalfReg : ASIMDSize.FullReg; - int loadVecBits = elSize.bits() * elementsPerVector; + ASIMDSize loadVecSize = ASIMDSize.FullReg; + int loadVecBits = loadVecSize.bits(); // number of registers needed to load to fill 4 full vectors. // i.e. byte: 1 full or 2 half, halfword: 2 full or 4 half, word: 4 full. int consecutiveRegs = Math.min(elSize.bytes() * (ASIMDSize.FullReg.bits() / loadVecBits), maxConsecutiveRegs); @@ -207,8 +207,6 @@ public void emitCode(CompilationResultBuilder crb, AArch64MacroAssembler masm) { boolean postIndex = consecutiveRegs > 2; for (int ldVi = 0; ldVi < nRegs; ldVi += regsFilledPerLoad) { loadConsecutiveVectors(masm, loadVecSize, loadVecBits, elSize, rscratch1, vtmp, ldVi, consecutiveRegs, postIndex, false); - } - for (int ldVi = 0; ldVi < nRegs; ldVi += regsFilledPerLoad) { extendVectorsToWord(masm, unsigned, loadVecBits, elSize, vtmp, ldVi, consecutiveRegs); } } From 658630423b09a2623b499e1f2e83a3d5c9693274 Mon Sep 17 00:00:00 2001 From: Andreas Woess Date: Tue, 21 Nov 2023 22:41:53 +0100 Subject: [PATCH 023/593] Always use post-index addressing and avoid extra offset address computation for array load. --- .../aarch64/AArch64VectorizedHashCodeOp.java | 32 +++++++------------ 1 file changed, 12 insertions(+), 20 deletions(-) diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/aarch64/AArch64VectorizedHashCodeOp.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/aarch64/AArch64VectorizedHashCodeOp.java index 7045ee4270b8..4b1328bb7248 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/aarch64/AArch64VectorizedHashCodeOp.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/aarch64/AArch64VectorizedHashCodeOp.java @@ -191,24 +191,17 @@ public void emitCode(CompilationResultBuilder crb, AArch64MacroAssembler masm) { // OOO execution can then hopefully do a better job of prefetching // load next 16 elements into 4 data vector registers // vtmp = ary1[index:index+elementsPerIteration]; - try (var scratch1 = masm.getScratchRegister()) { - var rscratch1 = scratch1.getRegister(); - // load next chunk address into scratch reg - AArch64Address dataChunkStart = AArch64Address.createRegisterOffsetAddress(elSize.bits(), ary1, index, true); - masm.loadAddress(rscratch1, dataChunkStart); - - ASIMDSize loadVecSize = ASIMDSize.FullReg; - int loadVecBits = loadVecSize.bits(); - // number of registers needed to load to fill 4 full vectors. - // i.e. byte: 1 full or 2 half, halfword: 2 full or 4 half, word: 4 full. - int consecutiveRegs = Math.min(elSize.bytes() * (ASIMDSize.FullReg.bits() / loadVecBits), maxConsecutiveRegs); - int extensionFactor = (ElementSize.Word.bits() / elSize.bits()) / (ASIMDSize.FullReg.bits() / loadVecBits); - int regsFilledPerLoad = consecutiveRegs * extensionFactor; - boolean postIndex = consecutiveRegs > 2; - for (int ldVi = 0; ldVi < nRegs; ldVi += regsFilledPerLoad) { - loadConsecutiveVectors(masm, loadVecSize, loadVecBits, elSize, rscratch1, vtmp, ldVi, consecutiveRegs, postIndex, false); - extendVectorsToWord(masm, unsigned, loadVecBits, elSize, vtmp, ldVi, consecutiveRegs); - } + ASIMDSize loadVecSize = ASIMDSize.FullReg; + int loadVecBits = loadVecSize.bits(); + // number of registers needed to load to fill 4 full vectors. + // i.e. byte: 1 full or 2 half, halfword: 2 full or 4 half, word: 4 full. + int consecutiveRegs = Math.min(elSize.bytes() * (ASIMDSize.FullReg.bits() / loadVecBits), maxConsecutiveRegs); + int extensionFactor = (ElementSize.Word.bits() / elSize.bits()) / (ASIMDSize.FullReg.bits() / loadVecBits); + int regsFilledPerLoad = consecutiveRegs * extensionFactor; + for (int ldVi = 0; ldVi < nRegs; ldVi += regsFilledPerLoad) { + boolean postIndex = true; + loadConsecutiveVectors(masm, loadVecSize, loadVecBits, elSize, ary1, vtmp, ldVi, consecutiveRegs, postIndex, false); + extendVectorsToWord(masm, unsigned, loadVecBits, elSize, vtmp, ldVi, consecutiveRegs); } // vresult[i] = vresult[i] * vnext + vtmp[i]; @@ -225,9 +218,8 @@ public void emitCode(CompilationResultBuilder crb, AArch64MacroAssembler masm) { masm.branchConditionally(ConditionFlag.LT, labelUnrolledVectorLoopBegin); // } - // start = ary[bound]; + // assert index == bound && ary1 == &ary[bound]; // cnt1 -= bound; - masm.loadAddress(ary1, AArch64Address.createRegisterOffsetAddress(elSize.bits(), ary1, bound, true)); masm.sub(32, cnt1, cnt1, bound); // release bound From ce24837a7a90ac0342cda1aa43c1c2b6b11b3e35 Mon Sep 17 00:00:00 2001 From: Andreas Woess Date: Tue, 21 Nov 2023 21:56:43 +0100 Subject: [PATCH 024/593] Update tested lengths in VectorizedHashCodeBenchmark. --- .../strings/bench/VectorizedHashCodeBenchmark.java | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/truffle/src/com.oracle.truffle.api.strings.test/src/com/oracle/truffle/api/strings/bench/VectorizedHashCodeBenchmark.java b/truffle/src/com.oracle.truffle.api.strings.test/src/com/oracle/truffle/api/strings/bench/VectorizedHashCodeBenchmark.java index f6b13bae8baf..4563df0d031a 100644 --- a/truffle/src/com.oracle.truffle.api.strings.test/src/com/oracle/truffle/api/strings/bench/VectorizedHashCodeBenchmark.java +++ b/truffle/src/com.oracle.truffle.api.strings.test/src/com/oracle/truffle/api/strings/bench/VectorizedHashCodeBenchmark.java @@ -72,7 +72,17 @@ private static Random random() { @State(Scope.Benchmark) public static class BenchState { - @Param({"1", "10", "100", "1000", "10000"}) int length; + @Param({ + "3", + "15", // AArch64: only scalar loop, max iterations + "16", // AArch64: only vector loop, 1 iteration + "31", // AMD64: only scalar loop, max iterations + "32", // AMD64 and AArch64: only vector loop, 1 and 2 iterations. + "64", // AMD64 and AArch64: only vector loop, 2 and 4 iterations. + "100", + "1000", + "10000", + }) int length; byte[] b8; byte[] b16; From 272e12f87e0c4995f3457ed169ad76e6771adb4a Mon Sep 17 00:00:00 2001 From: Andreas Woess Date: Wed, 22 Nov 2023 13:34:53 +0100 Subject: [PATCH 025/593] Fix javadoc of moveVV instruction. --- .../compiler/asm/aarch64/AArch64ASIMDMacroAssembler.java | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/asm/aarch64/AArch64ASIMDMacroAssembler.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/asm/aarch64/AArch64ASIMDMacroAssembler.java index 840b5444b5ba..279cc6c28372 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/asm/aarch64/AArch64ASIMDMacroAssembler.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/asm/aarch64/AArch64ASIMDMacroAssembler.java @@ -143,9 +143,10 @@ public void moveVI(ASIMDSize size, Register dst, double imm) { } /** - * Moves an immediate value into each element of the result.
+ * Moves a vector. This instruction copies the vector in the source SIMD register into the + * destination SIMD register.
* - * for i in 0..n-1 do dst[i] = imm + * for i in 0..n-1 do dst[i] = src[i] */ public void moveVV(ASIMDSize size, Register dst, Register src) { if (!src.equals(dst)) { From 240fab919b9f38b68a4a4e273af99fcb5ff6c7bc Mon Sep 17 00:00:00 2001 From: Andreas Woess Date: Wed, 22 Nov 2023 12:31:26 +0100 Subject: [PATCH 026/593] Use fmov wx,sx instead of umovGX wx,vx.s[0]. --- .../compiler/lir/aarch64/AArch64VectorizedHashCodeOp.java | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/aarch64/AArch64VectorizedHashCodeOp.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/aarch64/AArch64VectorizedHashCodeOp.java index 4b1328bb7248..f864ee103861 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/aarch64/AArch64VectorizedHashCodeOp.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/aarch64/AArch64VectorizedHashCodeOp.java @@ -242,10 +242,9 @@ public void emitCode(CompilationResultBuilder crb, AArch64MacroAssembler masm) { masm.neon.mulVVV(ASIMDSize.FullReg, ElementSize.Word, vresult[idx], vresult[idx], vcoef[idx]); } - reduceVectorLanes(masm, ASIMDSize.FullReg, vresult); - // accumulate horizontal vector sum in result - masm.neon.umovGX(ElementSize.Word, tmp2, vresult[0], 0); + reduceVectorLanes(masm, ASIMDSize.FullReg, vresult); + masm.fmov(32, tmp2, vresult[0]); // umovGX(Word, tmp2, vresult[0], 0); masm.add(32, result, result, tmp2); // } else if (cnt1 < elementsPerIteration) { From 3ff9d8a0b45d86297ce2b9dd286d7b9f543aae78 Mon Sep 17 00:00:00 2001 From: Andreas Woess Date: Wed, 22 Nov 2023 16:49:13 +0100 Subject: [PATCH 027/593] Align loop begin and branch targets. --- .../compiler/lir/aarch64/AArch64VectorizedHashCodeOp.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/aarch64/AArch64VectorizedHashCodeOp.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/aarch64/AArch64VectorizedHashCodeOp.java index f864ee103861..6df2092e8d36 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/aarch64/AArch64VectorizedHashCodeOp.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/aarch64/AArch64VectorizedHashCodeOp.java @@ -183,6 +183,7 @@ public void emitCode(CompilationResultBuilder crb, AArch64MacroAssembler masm) { masm.and(32, bound, cnt1, ~(elementsPerIteration - 1)); // for (; index < bound; index += elementsPerIteration) { + masm.align(AArch64MacroAssembler.PREFERRED_LOOP_ALIGNMENT); masm.bind(labelUnrolledVectorLoopBegin); // result *= next; masm.mul(32, result, result, next); @@ -249,6 +250,7 @@ public void emitCode(CompilationResultBuilder crb, AArch64MacroAssembler masm) { // } else if (cnt1 < elementsPerIteration) { + masm.align(AArch64MacroAssembler.PREFERRED_BRANCH_TARGET_ALIGNMENT); masm.bind(labelShortUnrolledBegin); // int i = 1; masm.mov(index, 1); @@ -265,6 +267,7 @@ public void emitCode(CompilationResultBuilder crb, AArch64MacroAssembler masm) { masm.mov(tmp961, 961); // for (; i < cnt1 ; i += 2) { + masm.align(AArch64MacroAssembler.PREFERRED_LOOP_ALIGNMENT); masm.bind(labelShortUnrolledLoopBegin); // result *= 31**2; // result += ary1[index-1] * 31 + ary1[index] From 1322205632b322ad8657910cea766b9402ebe6d9 Mon Sep 17 00:00:00 2001 From: Andreas Woess Date: Wed, 22 Nov 2023 17:19:21 +0100 Subject: [PATCH 028/593] Move vectorizedHashCode intrinsic stub linking to architecture-agnoistic HotSpotHostForeignCallsProvider. --- .../aarch64/AArch64HotSpotForeignCallsProvider.java | 5 ----- .../amd64/AMD64HotSpotForeignCallsProvider.java | 11 ++++------- .../hotspot/meta/HotSpotHostForeignCallsProvider.java | 2 ++ 3 files changed, 6 insertions(+), 12 deletions(-) diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/aarch64/AArch64HotSpotForeignCallsProvider.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/aarch64/AArch64HotSpotForeignCallsProvider.java index 5f737ffda83a..98c98a1054b2 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/aarch64/AArch64HotSpotForeignCallsProvider.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/aarch64/AArch64HotSpotForeignCallsProvider.java @@ -35,11 +35,8 @@ import jdk.graal.compiler.hotspot.HotSpotGraalRuntimeProvider; import jdk.graal.compiler.hotspot.meta.HotSpotHostForeignCallsProvider; import jdk.graal.compiler.hotspot.meta.HotSpotProviders; -import jdk.graal.compiler.hotspot.stubs.IntrinsicStubsGen; import jdk.graal.compiler.options.OptionValues; -import jdk.graal.compiler.replacements.nodes.VectorizedHashCodeNode; import jdk.graal.compiler.word.WordTypes; - import jdk.vm.ci.code.CallingConvention; import jdk.vm.ci.code.CodeCacheProvider; import jdk.vm.ci.code.RegisterValue; @@ -73,8 +70,6 @@ public void initialize(HotSpotProviders providers, OptionValues options) { register(new HotSpotForeignCallLinkageImpl(HotSpotBackend.EXCEPTION_HANDLER_IN_CALLER, HotSpotForeignCallLinkage.JUMP_ADDRESS, HotSpotForeignCallLinkage.RegisterEffect.DESTROYS_ALL_CALLER_SAVE_REGISTERS, exceptionCc, null)); - linkSnippetStubs(providers, options, IntrinsicStubsGen::new, VectorizedHashCodeNode.STUBS); - super.initialize(providers, options); } diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/amd64/AMD64HotSpotForeignCallsProvider.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/amd64/AMD64HotSpotForeignCallsProvider.java index cdb584c4cb13..76899471e6e7 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/amd64/AMD64HotSpotForeignCallsProvider.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/amd64/AMD64HotSpotForeignCallsProvider.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 2023, 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,9 +24,6 @@ */ package jdk.graal.compiler.hotspot.amd64; -import static jdk.vm.ci.amd64.AMD64.rax; -import static jdk.vm.ci.amd64.AMD64.rdx; -import static jdk.vm.ci.meta.Value.ILLEGAL; import static jdk.graal.compiler.core.common.spi.ForeignCallDescriptor.CallSideEffect.NO_SIDE_EFFECT; import static jdk.graal.compiler.hotspot.HotSpotBackend.EXCEPTION_HANDLER; import static jdk.graal.compiler.hotspot.HotSpotBackend.EXCEPTION_HANDLER_IN_CALLER; @@ -42,6 +39,9 @@ import static jdk.graal.compiler.replacements.nodes.UnaryMathIntrinsicNode.UnaryOperation.LOG10; import static jdk.graal.compiler.replacements.nodes.UnaryMathIntrinsicNode.UnaryOperation.SIN; import static jdk.graal.compiler.replacements.nodes.UnaryMathIntrinsicNode.UnaryOperation.TAN; +import static jdk.vm.ci.amd64.AMD64.rax; +import static jdk.vm.ci.amd64.AMD64.rdx; +import static jdk.vm.ci.meta.Value.ILLEGAL; import jdk.graal.compiler.core.common.LIRKind; import jdk.graal.compiler.hotspot.GraalHotSpotVMConfig; @@ -52,9 +52,7 @@ import jdk.graal.compiler.hotspot.stubs.IntrinsicStubsGen; import jdk.graal.compiler.options.OptionValues; import jdk.graal.compiler.replacements.nodes.ArrayEqualsForeignCalls; -import jdk.graal.compiler.replacements.nodes.VectorizedHashCodeNode; import jdk.graal.compiler.word.WordTypes; - import jdk.vm.ci.code.CallingConvention; import jdk.vm.ci.code.CodeCacheProvider; import jdk.vm.ci.code.RegisterValue; @@ -89,7 +87,6 @@ public void initialize(HotSpotProviders providers, OptionValues options) { register(new HotSpotForeignCallLinkageImpl(EXCEPTION_HANDLER_IN_CALLER, JUMP_ADDRESS, DESTROYS_ALL_CALLER_SAVE_REGISTERS, exceptionCc, null)); linkSnippetStubs(providers, options, IntrinsicStubsGen::new, ArrayEqualsForeignCalls.STUBS_AMD64); - linkSnippetStubs(providers, options, IntrinsicStubsGen::new, VectorizedHashCodeNode.STUBS); super.initialize(providers, options); } diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/meta/HotSpotHostForeignCallsProvider.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/meta/HotSpotHostForeignCallsProvider.java index a174a6080f2e..d1a57c022a58 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/meta/HotSpotHostForeignCallsProvider.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/meta/HotSpotHostForeignCallsProvider.java @@ -149,6 +149,7 @@ import jdk.graal.compiler.replacements.nodes.EncodeArrayNode; import jdk.graal.compiler.replacements.nodes.GHASHProcessBlocksNode; import jdk.graal.compiler.replacements.nodes.MessageDigestNode; +import jdk.graal.compiler.replacements.nodes.VectorizedHashCodeNode; import jdk.graal.compiler.replacements.nodes.VectorizedMismatchNode; import jdk.graal.compiler.word.Word; import jdk.graal.compiler.word.WordTypes; @@ -657,6 +658,7 @@ private void registerSnippetStubs(HotSpotProviders providers, OptionValues optio linkSnippetStubs(providers, options, IntrinsicStubsGen::new, EncodeArrayNode.STUBS); linkSnippetStubs(providers, options, IntrinsicStubsGen::new, CountPositivesNode.STUB); linkSnippetStubs(providers, options, IntrinsicStubsGen::new, VectorizedMismatchNode.STUB); + linkSnippetStubs(providers, options, IntrinsicStubsGen::new, VectorizedHashCodeNode.STUBS); linkSnippetStubs(providers, options, IntrinsicStubsGen::new, BigIntegerMultiplyToLenNode.STUB); linkSnippetStubs(providers, options, IntrinsicStubsGen::new, BigIntegerMulAddNode.STUB); linkSnippetStubs(providers, options, IntrinsicStubsGen::new, BigIntegerSquareToLenNode.STUB); From 62de49db480c7e18fe68c4999eeea11546e04312 Mon Sep 17 00:00:00 2001 From: Andreas Woess Date: Wed, 22 Nov 2023 17:27:16 +0100 Subject: [PATCH 029/593] Move ArraysSupport plugins to architecture-agnostic SubstrateGraphBuilderPlugins. --- .../meta/HotSpotGraphBuilderPlugins.java | 2 +- .../nodes/VectorizedMismatchNode.java | 20 ++++++++--- .../SubstrateAArch64GraphBuilderPlugins.java | 34 ------------------- .../SubstrateAMD64GraphBuilderPlugins.java | 34 ------------------- .../SubstrateGraphBuilderPlugins.java | 22 +++++++++++- 5 files changed, 38 insertions(+), 74 deletions(-) diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/meta/HotSpotGraphBuilderPlugins.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/meta/HotSpotGraphBuilderPlugins.java index 18b762c4be8f..6c5e5d154f28 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/meta/HotSpotGraphBuilderPlugins.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/meta/HotSpotGraphBuilderPlugins.java @@ -1169,7 +1169,7 @@ public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Rec private static void registerArraysSupportPlugins(InvocationPlugins plugins, Replacements replacements, Architecture arch) { Registration r = new Registration(plugins, "jdk.internal.util.ArraysSupport", replacements); - r.register(new InvocationPlugin("vectorizedMismatch", Object.class, long.class, Object.class, long.class, int.class, int.class) { + r.registerConditional(VectorizedMismatchNode.isSupported(arch), new InvocationPlugin("vectorizedMismatch", Object.class, long.class, Object.class, long.class, int.class, int.class) { @Override public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode aObject, ValueNode aOffset, ValueNode bObject, ValueNode bOffset, ValueNode length, ValueNode log2ArrayIndexScale) { diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/replacements/nodes/VectorizedMismatchNode.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/replacements/nodes/VectorizedMismatchNode.java index ecddf5e53722..456219c914e6 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/replacements/nodes/VectorizedMismatchNode.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/replacements/nodes/VectorizedMismatchNode.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2023, 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 @@ -26,6 +26,9 @@ import java.util.EnumSet; +import org.graalvm.word.LocationIdentity; +import org.graalvm.word.Pointer; + import jdk.graal.compiler.core.common.spi.ForeignCallDescriptor; import jdk.graal.compiler.core.common.type.StampFactory; import jdk.graal.compiler.graph.NodeClass; @@ -35,9 +38,9 @@ import jdk.graal.compiler.nodeinfo.NodeSize; import jdk.graal.compiler.nodes.ValueNode; import jdk.graal.compiler.nodes.spi.NodeLIRBuilderTool; -import org.graalvm.word.LocationIdentity; -import org.graalvm.word.Pointer; - +import jdk.vm.ci.aarch64.AArch64; +import jdk.vm.ci.amd64.AMD64; +import jdk.vm.ci.code.Architecture; import jdk.vm.ci.meta.JavaKind; // JaCoCo Exclude @@ -111,4 +114,13 @@ public ValueNode[] getForeignCallArguments() { public void emitIntrinsic(NodeLIRBuilderTool gen) { gen.setResult(this, gen.getLIRGeneratorTool().emitVectorizedMismatch(getRuntimeCheckedCPUFeatures(), gen.operand(arrayA), gen.operand(arrayB), gen.operand(length), gen.operand(stride))); } + + public static boolean isSupported(Architecture arch) { + if (arch instanceof AMD64) { + return true; + } else if (arch instanceof AArch64) { + return true; + } + return false; + } } diff --git a/substratevm/src/com.oracle.svm.core.graal.aarch64/src/com/oracle/svm/core/graal/aarch64/SubstrateAArch64GraphBuilderPlugins.java b/substratevm/src/com.oracle.svm.core.graal.aarch64/src/com/oracle/svm/core/graal/aarch64/SubstrateAArch64GraphBuilderPlugins.java index e4b20d3df348..87df8933459e 100644 --- a/substratevm/src/com.oracle.svm.core.graal.aarch64/src/com/oracle/svm/core/graal/aarch64/SubstrateAArch64GraphBuilderPlugins.java +++ b/substratevm/src/com.oracle.svm.core.graal.aarch64/src/com/oracle/svm/core/graal/aarch64/SubstrateAArch64GraphBuilderPlugins.java @@ -28,26 +28,12 @@ import org.graalvm.nativeimage.Platforms; import com.oracle.svm.core.ParsingReason; -import com.oracle.svm.core.SubstrateOptions; -import com.oracle.svm.core.config.ConfigurationValues; import com.oracle.svm.core.feature.AutomaticallyRegisteredFeature; import com.oracle.svm.core.feature.InternalFeature; import jdk.graal.compiler.api.replacements.SnippetReflectionProvider; -import jdk.graal.compiler.nodes.ComputeObjectAddressNode; -import jdk.graal.compiler.nodes.ValueNode; import jdk.graal.compiler.nodes.graphbuilderconf.GraphBuilderConfiguration; -import jdk.graal.compiler.nodes.graphbuilderconf.GraphBuilderContext; -import jdk.graal.compiler.nodes.graphbuilderconf.InvocationPlugin; -import jdk.graal.compiler.nodes.graphbuilderconf.InvocationPlugins; -import jdk.graal.compiler.nodes.spi.Replacements; import jdk.graal.compiler.phases.util.Providers; -import jdk.graal.compiler.replacements.StandardGraphBuilderPlugins; -import jdk.graal.compiler.replacements.nodes.VectorizedHashCodeNode; -import jdk.graal.compiler.replacements.nodes.VectorizedMismatchNode; -import jdk.graal.compiler.serviceprovider.JavaVersionUtil; -import jdk.vm.ci.meta.JavaKind; -import jdk.vm.ci.meta.ResolvedJavaMethod; @AutomaticallyRegisteredFeature @Platforms(Platform.AARCH64.class) @@ -55,26 +41,6 @@ public class SubstrateAArch64GraphBuilderPlugins implements InternalFeature { @Override public void registerInvocationPlugins(Providers providers, SnippetReflectionProvider snippetReflection, GraphBuilderConfiguration.Plugins plugins, ParsingReason reason) { - if (!SubstrateOptions.useLLVMBackend()) { - registerArraysSupportPlugins(plugins.getInvocationPlugins(), providers.getReplacements()); - } } - private static void registerArraysSupportPlugins(InvocationPlugins plugins, Replacements replacements) { - InvocationPlugins.Registration r = new InvocationPlugins.Registration(plugins, "jdk.internal.util.ArraysSupport", replacements); - r.register(new InvocationPlugin("vectorizedMismatch", Object.class, long.class, Object.class, long.class, int.class, int.class) { - @Override - public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, - ValueNode aObject, ValueNode aOffset, ValueNode bObject, ValueNode bOffset, ValueNode length, ValueNode log2ArrayIndexScale) { - ValueNode aAddr = b.add(new ComputeObjectAddressNode(aObject, aOffset)); - ValueNode bAddr = b.add(new ComputeObjectAddressNode(bObject, bOffset)); - b.addPush(JavaKind.Int, new VectorizedMismatchNode(aAddr, bAddr, length, log2ArrayIndexScale)); - return true; - } - }); - if (JavaVersionUtil.JAVA_SPEC >= 21) { - r.registerConditional(VectorizedHashCodeNode.isSupported(ConfigurationValues.getTarget().arch), - new StandardGraphBuilderPlugins.VectorizedHashCodeInvocationPlugin("vectorizedHashCode")); - } - } } diff --git a/substratevm/src/com.oracle.svm.core.graal.amd64/src/com/oracle/svm/core/graal/amd64/SubstrateAMD64GraphBuilderPlugins.java b/substratevm/src/com.oracle.svm.core.graal.amd64/src/com/oracle/svm/core/graal/amd64/SubstrateAMD64GraphBuilderPlugins.java index 9153949b128f..c282f53dd164 100644 --- a/substratevm/src/com.oracle.svm.core.graal.amd64/src/com/oracle/svm/core/graal/amd64/SubstrateAMD64GraphBuilderPlugins.java +++ b/substratevm/src/com.oracle.svm.core.graal.amd64/src/com/oracle/svm/core/graal/amd64/SubstrateAMD64GraphBuilderPlugins.java @@ -28,26 +28,12 @@ import org.graalvm.nativeimage.Platforms; import com.oracle.svm.core.ParsingReason; -import com.oracle.svm.core.SubstrateOptions; -import com.oracle.svm.core.config.ConfigurationValues; import com.oracle.svm.core.feature.AutomaticallyRegisteredFeature; import com.oracle.svm.core.feature.InternalFeature; import jdk.graal.compiler.api.replacements.SnippetReflectionProvider; -import jdk.graal.compiler.nodes.ComputeObjectAddressNode; -import jdk.graal.compiler.nodes.ValueNode; import jdk.graal.compiler.nodes.graphbuilderconf.GraphBuilderConfiguration; -import jdk.graal.compiler.nodes.graphbuilderconf.GraphBuilderContext; -import jdk.graal.compiler.nodes.graphbuilderconf.InvocationPlugin; -import jdk.graal.compiler.nodes.graphbuilderconf.InvocationPlugins; -import jdk.graal.compiler.nodes.spi.Replacements; import jdk.graal.compiler.phases.util.Providers; -import jdk.graal.compiler.replacements.StandardGraphBuilderPlugins; -import jdk.graal.compiler.replacements.nodes.VectorizedHashCodeNode; -import jdk.graal.compiler.replacements.nodes.VectorizedMismatchNode; -import jdk.graal.compiler.serviceprovider.JavaVersionUtil; -import jdk.vm.ci.meta.JavaKind; -import jdk.vm.ci.meta.ResolvedJavaMethod; @AutomaticallyRegisteredFeature @Platforms(Platform.AMD64.class) @@ -55,26 +41,6 @@ public class SubstrateAMD64GraphBuilderPlugins implements InternalFeature { @Override public void registerInvocationPlugins(Providers providers, SnippetReflectionProvider snippetReflection, GraphBuilderConfiguration.Plugins plugins, ParsingReason reason) { - if (!SubstrateOptions.useLLVMBackend()) { - registerArraysSupportPlugins(plugins.getInvocationPlugins(), providers.getReplacements()); - } } - private static void registerArraysSupportPlugins(InvocationPlugins plugins, Replacements replacements) { - InvocationPlugins.Registration r = new InvocationPlugins.Registration(plugins, "jdk.internal.util.ArraysSupport", replacements); - r.register(new InvocationPlugin("vectorizedMismatch", Object.class, long.class, Object.class, long.class, int.class, int.class) { - @Override - public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, - ValueNode aObject, ValueNode aOffset, ValueNode bObject, ValueNode bOffset, ValueNode length, ValueNode log2ArrayIndexScale) { - ValueNode aAddr = b.add(new ComputeObjectAddressNode(aObject, aOffset)); - ValueNode bAddr = b.add(new ComputeObjectAddressNode(bObject, bOffset)); - b.addPush(JavaKind.Int, new VectorizedMismatchNode(aAddr, bAddr, length, log2ArrayIndexScale)); - return true; - } - }); - if (JavaVersionUtil.JAVA_SPEC >= 21) { - r.registerConditional(VectorizedHashCodeNode.isSupported(ConfigurationValues.getTarget().arch), - new StandardGraphBuilderPlugins.VectorizedHashCodeInvocationPlugin("vectorizedHashCode")); - } - } } diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/snippets/SubstrateGraphBuilderPlugins.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/snippets/SubstrateGraphBuilderPlugins.java index 23c886345d27..f6a18f6db0c2 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/snippets/SubstrateGraphBuilderPlugins.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/snippets/SubstrateGraphBuilderPlugins.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2023, 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 @@ -115,6 +115,7 @@ import jdk.graal.compiler.java.LambdaUtils; import jdk.graal.compiler.nodes.AbstractBeginNode; import jdk.graal.compiler.nodes.BeginNode; +import jdk.graal.compiler.nodes.ComputeObjectAddressNode; import jdk.graal.compiler.nodes.ConstantNode; import jdk.graal.compiler.nodes.DynamicPiNode; import jdk.graal.compiler.nodes.FixedNode; @@ -159,6 +160,8 @@ import jdk.graal.compiler.replacements.nodes.CipherBlockChainingAESNode; import jdk.graal.compiler.replacements.nodes.CounterModeAESNode; import jdk.graal.compiler.replacements.nodes.MacroNode.MacroParams; +import jdk.graal.compiler.replacements.nodes.VectorizedHashCodeNode; +import jdk.graal.compiler.replacements.nodes.VectorizedMismatchNode; import jdk.graal.compiler.word.WordCastNode; import jdk.vm.ci.code.Architecture; import jdk.vm.ci.meta.DeoptimizationAction; @@ -209,6 +212,7 @@ public static void registerInvocationPlugins(AnnotationSubstitutionProcessor ann registerReferenceAccessPlugins(plugins); if (supportsStubBasedPlugins) { registerAESPlugins(plugins, replacements, architecture); + registerArraysSupportPlugins(plugins, replacements, architecture); } } @@ -1274,6 +1278,22 @@ public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Rec }); } + private static void registerArraysSupportPlugins(InvocationPlugins plugins, Replacements replacements, Architecture arch) { + InvocationPlugins.Registration r = new InvocationPlugins.Registration(plugins, "jdk.internal.util.ArraysSupport", replacements); + r.registerConditional(VectorizedMismatchNode.isSupported(arch), new InvocationPlugin("vectorizedMismatch", Object.class, long.class, Object.class, long.class, int.class, int.class) { + @Override + public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, + ValueNode aObject, ValueNode aOffset, ValueNode bObject, ValueNode bOffset, ValueNode length, ValueNode log2ArrayIndexScale) { + ValueNode aAddr = b.add(new ComputeObjectAddressNode(aObject, aOffset)); + ValueNode bAddr = b.add(new ComputeObjectAddressNode(bObject, bOffset)); + b.addPush(JavaKind.Int, new VectorizedMismatchNode(aAddr, bAddr, length, log2ArrayIndexScale)); + return true; + } + }); + r.registerConditional(VectorizedHashCodeNode.isSupported(arch), + new StandardGraphBuilderPlugins.VectorizedHashCodeInvocationPlugin("vectorizedHashCode")); + } + private static class SubstrateCipherBlockChainingCryptPlugin extends StandardGraphBuilderPlugins.CipherBlockChainingCryptPlugin { SubstrateCipherBlockChainingCryptPlugin(AESNode.CryptMode mode) { From 7386ba34a34b1cdd9076d1eb4ffaeab831b9a978 Mon Sep 17 00:00:00 2001 From: Andreas Woess Date: Wed, 22 Nov 2023 17:41:36 +0100 Subject: [PATCH 030/593] Fix AArch64HaltOp name and description. --- .../src/jdk/graal/compiler/lir/aarch64/AArch64HaltOp.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/aarch64/AArch64HaltOp.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/aarch64/AArch64HaltOp.java index a5ee08bd48e4..49ded5fd10b0 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/aarch64/AArch64HaltOp.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/aarch64/AArch64HaltOp.java @@ -30,9 +30,9 @@ import jdk.graal.compiler.lir.Opcode; /** - * Emits a pause. + * Emits a halt. */ -@Opcode("PAUSE") +@Opcode("HALT") public final class AArch64HaltOp extends AArch64LIRInstruction { public static final LIRInstructionClass TYPE = LIRInstructionClass.create(AArch64HaltOp.class); From de01d1af4b4aee94baa9bf5a94482d02d6f1062b Mon Sep 17 00:00:00 2001 From: Andreas Woess Date: Wed, 22 Nov 2023 17:51:32 +0100 Subject: [PATCH 031/593] Remove empty Substrate{AArch64,AMD64}GraphBuilderPlugins feature. --- .../SubstrateAArch64GraphBuilderPlugins.java | 46 ------------------- .../SubstrateAMD64GraphBuilderPlugins.java | 46 ------------------- 2 files changed, 92 deletions(-) delete mode 100644 substratevm/src/com.oracle.svm.core.graal.aarch64/src/com/oracle/svm/core/graal/aarch64/SubstrateAArch64GraphBuilderPlugins.java delete mode 100644 substratevm/src/com.oracle.svm.core.graal.amd64/src/com/oracle/svm/core/graal/amd64/SubstrateAMD64GraphBuilderPlugins.java diff --git a/substratevm/src/com.oracle.svm.core.graal.aarch64/src/com/oracle/svm/core/graal/aarch64/SubstrateAArch64GraphBuilderPlugins.java b/substratevm/src/com.oracle.svm.core.graal.aarch64/src/com/oracle/svm/core/graal/aarch64/SubstrateAArch64GraphBuilderPlugins.java deleted file mode 100644 index 87df8933459e..000000000000 --- a/substratevm/src/com.oracle.svm.core.graal.aarch64/src/com/oracle/svm/core/graal/aarch64/SubstrateAArch64GraphBuilderPlugins.java +++ /dev/null @@ -1,46 +0,0 @@ -/* - * Copyright (c) 2022, 2023, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.oracle.svm.core.graal.aarch64; - -import org.graalvm.nativeimage.Platform; -import org.graalvm.nativeimage.Platforms; - -import com.oracle.svm.core.ParsingReason; -import com.oracle.svm.core.feature.AutomaticallyRegisteredFeature; -import com.oracle.svm.core.feature.InternalFeature; - -import jdk.graal.compiler.api.replacements.SnippetReflectionProvider; -import jdk.graal.compiler.nodes.graphbuilderconf.GraphBuilderConfiguration; -import jdk.graal.compiler.phases.util.Providers; - -@AutomaticallyRegisteredFeature -@Platforms(Platform.AARCH64.class) -public class SubstrateAArch64GraphBuilderPlugins implements InternalFeature { - - @Override - public void registerInvocationPlugins(Providers providers, SnippetReflectionProvider snippetReflection, GraphBuilderConfiguration.Plugins plugins, ParsingReason reason) { - } - -} diff --git a/substratevm/src/com.oracle.svm.core.graal.amd64/src/com/oracle/svm/core/graal/amd64/SubstrateAMD64GraphBuilderPlugins.java b/substratevm/src/com.oracle.svm.core.graal.amd64/src/com/oracle/svm/core/graal/amd64/SubstrateAMD64GraphBuilderPlugins.java deleted file mode 100644 index c282f53dd164..000000000000 --- a/substratevm/src/com.oracle.svm.core.graal.amd64/src/com/oracle/svm/core/graal/amd64/SubstrateAMD64GraphBuilderPlugins.java +++ /dev/null @@ -1,46 +0,0 @@ -/* - * Copyright (c) 2022, 2023, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.oracle.svm.core.graal.amd64; - -import org.graalvm.nativeimage.Platform; -import org.graalvm.nativeimage.Platforms; - -import com.oracle.svm.core.ParsingReason; -import com.oracle.svm.core.feature.AutomaticallyRegisteredFeature; -import com.oracle.svm.core.feature.InternalFeature; - -import jdk.graal.compiler.api.replacements.SnippetReflectionProvider; -import jdk.graal.compiler.nodes.graphbuilderconf.GraphBuilderConfiguration; -import jdk.graal.compiler.phases.util.Providers; - -@AutomaticallyRegisteredFeature -@Platforms(Platform.AMD64.class) -public class SubstrateAMD64GraphBuilderPlugins implements InternalFeature { - - @Override - public void registerInvocationPlugins(Providers providers, SnippetReflectionProvider snippetReflection, GraphBuilderConfiguration.Plugins plugins, ParsingReason reason) { - } - -} From f422aabd7af970dd6de65309194e39146908203d Mon Sep 17 00:00:00 2001 From: Andreas Woess Date: Mon, 27 Nov 2023 20:24:15 +0100 Subject: [PATCH 032/593] Cleanup and guarantees in AArch64VectorizedHashCodeOp. --- .../aarch64/AArch64VectorizedHashCodeOp.java | 33 ++++++++++++------- 1 file changed, 22 insertions(+), 11 deletions(-) diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/aarch64/AArch64VectorizedHashCodeOp.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/aarch64/AArch64VectorizedHashCodeOp.java index 6df2092e8d36..426e7e436809 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/aarch64/AArch64VectorizedHashCodeOp.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/aarch64/AArch64VectorizedHashCodeOp.java @@ -144,10 +144,26 @@ public void emitCode(CompilationResultBuilder crb, AArch64MacroAssembler masm) { }; final int nRegs = vresult.length; - assert nRegs >= 2 && CodeUtil.isPowerOf2(nRegs) : "number of vectors must be >= 2 and a power of 2"; + GraalError.guarantee(nRegs >= 2 && CodeUtil.isPowerOf2(nRegs), "number of vectors must be a power of 2 >= 2"); final int elementsPerVector = ASIMDSize.FullReg.bytes() / ElementSize.Word.bytes(); final int elementsPerIteration = elementsPerVector * nRegs; + // We can load up to 4 registers at once. final int maxConsecutiveRegs = Math.min(nRegs, 4); + final int minBits = elSize.bits() * elementsPerVector; + final int maxBits = Math.min(elSize.bits() * elementsPerIteration, ASIMDSize.FullReg.bits()); + // Sub-word element loads can be spread out to more vector registers. + // i.e. byte: 4x32, 2x64, or 1x128, halfword: 4x64 or 2x128, word: 4x128. + final ASIMDSize loadVecSize = nRegs * minBits <= ASIMDSize.HalfReg.bits() ? ASIMDSize.HalfReg : ASIMDSize.FullReg; + final int loadVecBits = loadVecSize.bits(); + GraalError.guarantee(CodeUtil.isPowerOf2(loadVecBits) && loadVecBits % minBits == 0 && loadVecBits <= maxBits, + "loaded bit width must be (2^n)*%d <= %d for %s", minBits, maxBits, elSize); + + // to how many eventual registers do we expand each loaded register? + int extensionFactor = Math.max((ElementSize.Word.bits() / elSize.bits()) / (maxBits / loadVecBits), 1); + // number of registers needed to load to fill 4 full vectors. + // i.e. byte: 1 full or 2 half, halfword: 2 full or 4 half, word: 4 full. + int consecutiveRegs = Math.max(maxConsecutiveRegs / extensionFactor, 1); + int regsFilledPerLoad = consecutiveRegs * extensionFactor; // @formatter:off // elementsPerIteration = 16; @@ -175,6 +191,8 @@ public void emitCode(CompilationResultBuilder crb, AArch64MacroAssembler masm) { Register next = tmp3; // vnext = IntVector.broadcast(I128, power_of_31_backwards[0]); + // Note: (length - elementsPerIteration) is usually zero. + // This code throws if there are not enough elements in the array but allows more. int nextPow31 = POWERS_OF_31_BACKWARDS[POWERS_OF_31_BACKWARDS.length - elementsPerIteration] * 31; masm.mov(next, nextPow31); masm.neon.dupVG(ASIMDSize.FullReg, ElementSize.Word, vnext, next); @@ -192,13 +210,6 @@ public void emitCode(CompilationResultBuilder crb, AArch64MacroAssembler masm) { // OOO execution can then hopefully do a better job of prefetching // load next 16 elements into 4 data vector registers // vtmp = ary1[index:index+elementsPerIteration]; - ASIMDSize loadVecSize = ASIMDSize.FullReg; - int loadVecBits = loadVecSize.bits(); - // number of registers needed to load to fill 4 full vectors. - // i.e. byte: 1 full or 2 half, halfword: 2 full or 4 half, word: 4 full. - int consecutiveRegs = Math.min(elSize.bytes() * (ASIMDSize.FullReg.bits() / loadVecBits), maxConsecutiveRegs); - int extensionFactor = (ElementSize.Word.bits() / elSize.bits()) / (ASIMDSize.FullReg.bits() / loadVecBits); - int regsFilledPerLoad = consecutiveRegs * extensionFactor; for (int ldVi = 0; ldVi < nRegs; ldVi += regsFilledPerLoad) { boolean postIndex = true; loadConsecutiveVectors(masm, loadVecSize, loadVecBits, elSize, ary1, vtmp, ldVi, consecutiveRegs, postIndex, false); @@ -244,7 +255,7 @@ public void emitCode(CompilationResultBuilder crb, AArch64MacroAssembler masm) { } // accumulate horizontal vector sum in result - reduceVectorLanes(masm, ASIMDSize.FullReg, vresult); + reduceVectorLanes(masm, ASIMDSize.FullReg, vresult, nRegs); masm.fmov(32, tmp2, vresult[0]); // umovGX(Word, tmp2, vresult[0], 0); masm.add(32, result, result, tmp2); @@ -422,9 +433,9 @@ private static void extendPairwise(AArch64MacroAssembler masm, boolean unsigned, * Reduces elements from multiple vectors to a single vector and then reduces that vector's * lanes to a single scalar value in {@code vresult[0]}. */ - private static void reduceVectorLanes(AArch64MacroAssembler masm, ASIMDSize vsize, Register[] vresult) { + private static void reduceVectorLanes(AArch64MacroAssembler masm, ASIMDSize vsize, Register[] vresult, int vresultLen) { // reduce vectors pairwise until there's only a single vector left - for (int nRegs = vresult.length, stride = 1; nRegs >= 2; nRegs /= 2, stride *= 2) { + for (int nRegs = vresultLen, stride = 1; nRegs >= 2; nRegs /= 2, stride *= 2) { for (int i = 0; i < vresult.length - stride; i += 2 * stride) { masm.neon.addVVV(vsize, ElementSize.Word, vresult[i], vresult[i], vresult[i + stride]); } From 079f61c62675bd9f9db4034c4178ba13a5b7c45b Mon Sep 17 00:00:00 2001 From: Andreas Woess Date: Tue, 28 Nov 2023 18:17:52 +0100 Subject: [PATCH 033/593] Support different vector counts in AArch64VectorizedHashCodeOp. --- .../aarch64/AArch64VectorizedHashCodeOp.java | 55 +++++++++++++------ 1 file changed, 38 insertions(+), 17 deletions(-) diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/aarch64/AArch64VectorizedHashCodeOp.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/aarch64/AArch64VectorizedHashCodeOp.java index 426e7e436809..88daf7e9ea95 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/aarch64/AArch64VectorizedHashCodeOp.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/aarch64/AArch64VectorizedHashCodeOp.java @@ -26,6 +26,9 @@ import static jdk.vm.ci.code.ValueUtil.asRegister; +import java.util.Arrays; +import java.util.stream.IntStream; + import jdk.graal.compiler.asm.Label; import jdk.graal.compiler.asm.aarch64.AArch64ASIMDAssembler.ASIMDInstruction; import jdk.graal.compiler.asm.aarch64.AArch64ASIMDAssembler.ASIMDSize; @@ -62,10 +65,16 @@ public final class AArch64VectorizedHashCodeOp extends AArch64ComplexVectorOp { @Alive({OperandFlag.REG}) private Value initialValue; private final JavaKind arrayKind; + private final int nRegs; @Temp({OperandFlag.REG}) Value[] temp; @Temp({OperandFlag.REG}) Value[] vectorTemp; + /** Number of vector registers to use per loop iteration. */ + public static int VECTOR_COUNT = 4; + /** If true, tries to use NEON LD1 (multiple structures) instruction, else, uses LDR or LDP. */ + public static boolean USE_LD1 = false; + public AArch64VectorizedHashCodeOp(LIRGeneratorTool tool, AllocatableValue result, AllocatableValue arrayStart, AllocatableValue length, AllocatableValue initialValue, JavaKind arrayKind) { super(TYPE); @@ -75,8 +84,10 @@ public AArch64VectorizedHashCodeOp(LIRGeneratorTool tool, this.initialValue = initialValue; this.arrayKind = arrayKind; + this.nRegs = VECTOR_COUNT; this.temp = allocateTempRegisters(tool, 5); - this.vectorTemp = allocateVectorRegisters(tool, 9); // (1 vnext + 4 vresult + 4 vtmp/vcoef) + // (1 * vnext + n * vresult + n * vtmp/vcoef) + this.vectorTemp = allocateVectorRegisters(tool, 1 + 2 * nRegs); } private static void arraysHashcodeElload(AArch64MacroAssembler masm, Register dst, AArch64Address src, JavaKind eltype) { @@ -91,6 +102,23 @@ private static void arraysHashcodeElload(AArch64MacroAssembler masm, Register ds } private static final int[] POWERS_OF_31_BACKWARDS = new int[]{ + 2111290369, + -2010103841, + 350799937, + 11316127, + 693101697, + -254736545, + 961614017, + 31019807, + -2077209343, + -67006753, + 1244764481, + -2038056289, + 211350913, + -408824225, + -844471871, + -997072353, + 1353309697, -510534177, 1507551809, -505558625, @@ -108,7 +136,6 @@ private static void arraysHashcodeElload(AArch64MacroAssembler masm, Register ds 31, 1, }; - private static final ArrayDataPointerConstant powersOf31 = new ArrayDataPointerConstant(POWERS_OF_31_BACKWARDS, 16); @Override public void emitCode(CompilationResultBuilder crb, AArch64MacroAssembler masm) { @@ -129,10 +156,9 @@ public void emitCode(CompilationResultBuilder crb, AArch64MacroAssembler masm) { masm.mov(32, cnt1, asRegister(length)); masm.mov(32, result, asRegister(initialValue)); - // For "renaming" for readability of the code Register vnext = asRegister(vectorTemp[0]); - Register[] vcoef = {asRegister(vectorTemp[1]), asRegister(vectorTemp[2]), asRegister(vectorTemp[3]), asRegister(vectorTemp[4])}; - Register[] vresult = {asRegister(vectorTemp[5]), asRegister(vectorTemp[6]), asRegister(vectorTemp[7]), asRegister(vectorTemp[8])}; + Register[] vcoef = IntStream.range(1, 1 + nRegs).mapToObj(i -> asRegister(vectorTemp[i])).toArray(Register[]::new); + Register[] vresult = IntStream.range(1 + nRegs, 1 + 2 * nRegs).mapToObj(i -> asRegister(vectorTemp[i])).toArray(Register[]::new); Register[] vtmp = vcoef; final boolean unsigned = arrayKind == JavaKind.Boolean || arrayKind == JavaKind.Char; @@ -143,8 +169,7 @@ public void emitCode(CompilationResultBuilder crb, AArch64MacroAssembler masm) { default -> throw GraalError.shouldNotReachHereUnexpectedValue(arrayKind); }; - final int nRegs = vresult.length; - GraalError.guarantee(nRegs >= 2 && CodeUtil.isPowerOf2(nRegs), "number of vectors must be a power of 2 >= 2"); + GraalError.guarantee(nRegs == 2 || nRegs == 4 || nRegs == 8, "number of vectors must be either 2, 4, or 8"); final int elementsPerVector = ASIMDSize.FullReg.bytes() / ElementSize.Word.bytes(); final int elementsPerIteration = elementsPerVector * nRegs; // We can load up to 4 registers at once. @@ -191,9 +216,9 @@ public void emitCode(CompilationResultBuilder crb, AArch64MacroAssembler masm) { Register next = tmp3; // vnext = IntVector.broadcast(I128, power_of_31_backwards[0]); - // Note: (length - elementsPerIteration) is usually zero. - // This code throws if there are not enough elements in the array but allows more. - int nextPow31 = POWERS_OF_31_BACKWARDS[POWERS_OF_31_BACKWARDS.length - elementsPerIteration] * 31; + // Throws AIOOBE if there are not enough elements in the array but allows more. + int powersOf31Start = POWERS_OF_31_BACKWARDS.length - elementsPerIteration; + int nextPow31 = POWERS_OF_31_BACKWARDS[powersOf31Start - 1]; masm.mov(next, nextPow31); masm.neon.dupVG(ASIMDSize.FullReg, ElementSize.Word, vnext, next); @@ -212,7 +237,7 @@ public void emitCode(CompilationResultBuilder crb, AArch64MacroAssembler masm) { // vtmp = ary1[index:index+elementsPerIteration]; for (int ldVi = 0; ldVi < nRegs; ldVi += regsFilledPerLoad) { boolean postIndex = true; - loadConsecutiveVectors(masm, loadVecSize, loadVecBits, elSize, ary1, vtmp, ldVi, consecutiveRegs, postIndex, false); + loadConsecutiveVectors(masm, loadVecSize, loadVecBits, elSize, ary1, vtmp, ldVi, consecutiveRegs, postIndex, USE_LD1); extendVectorsToWord(masm, unsigned, loadVecBits, elSize, vtmp, ldVi, consecutiveRegs); } @@ -236,17 +261,13 @@ public void emitCode(CompilationResultBuilder crb, AArch64MacroAssembler masm) { // release bound // vcoef = IntVector.fromArray(I128, power_of_31_backwards, 1); + var powersOf31 = new ArrayDataPointerConstant(Arrays.copyOfRange(POWERS_OF_31_BACKWARDS, powersOf31Start, POWERS_OF_31_BACKWARDS.length), 16); crb.recordDataReferenceInCode(powersOf31); Register coefAddrReg = tmp2; masm.adrpAdd(coefAddrReg); - int coefOffset = (POWERS_OF_31_BACKWARDS.length - elementsPerIteration) * JavaKind.Int.getByteCount(); - assert coefOffset >= 0 : coefOffset; - if (coefOffset != 0) { - masm.add(64, coefAddrReg, coefAddrReg, coefOffset); - } for (int i = 0; i < nRegs; i += maxConsecutiveRegs) { boolean postIndex = maxConsecutiveRegs < nRegs; - loadConsecutiveVectors(masm, ASIMDSize.FullReg, ASIMDSize.FullReg.bits(), ElementSize.Word, coefAddrReg, vcoef, i, maxConsecutiveRegs, postIndex, false); + loadConsecutiveVectors(masm, ASIMDSize.FullReg, ASIMDSize.FullReg.bits(), ElementSize.Word, coefAddrReg, vcoef, i, maxConsecutiveRegs, postIndex, USE_LD1); } // vresult *= vcoef; From 787df75a7c9c69162fb593ac650810570c9bda7c Mon Sep 17 00:00:00 2001 From: Andreas Woess Date: Tue, 28 Nov 2023 18:26:26 +0100 Subject: [PATCH 034/593] Test different variants of AArch64VectorizedHashCodeOp. --- .../test/VectorizedHashCodeTest.java | 56 +++++++++++++++---- 1 file changed, 46 insertions(+), 10 deletions(-) diff --git a/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/replacements/test/VectorizedHashCodeTest.java b/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/replacements/test/VectorizedHashCodeTest.java index 4591061dede9..ea4e170474a2 100644 --- a/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/replacements/test/VectorizedHashCodeTest.java +++ b/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/replacements/test/VectorizedHashCodeTest.java @@ -24,7 +24,7 @@ */ package jdk.graal.compiler.replacements.test; -import java.io.UnsupportedEncodingException; +import java.nio.charset.StandardCharsets; import java.util.HashSet; import java.util.Set; import java.util.function.Function; @@ -32,10 +32,15 @@ import org.junit.Assert; import org.junit.Test; +import jdk.graal.compiler.core.common.GraalOptions; import jdk.graal.compiler.core.test.GraalCompilerTest; +import jdk.graal.compiler.lir.aarch64.AArch64VectorizedHashCodeOp; +import jdk.graal.compiler.options.OptionValues; import jdk.graal.compiler.replacements.StandardGraphBuilderPlugins.VectorizedHashCodeInvocationPlugin; import jdk.graal.compiler.test.AddExports; import jdk.internal.util.ArraysSupport; +import jdk.vm.ci.aarch64.AArch64; +import jdk.vm.ci.code.InstalledCode; @AddExports({"java.base/jdk.internal.util"}) public class VectorizedHashCodeTest extends GraalCompilerTest { @@ -59,9 +64,14 @@ public void testJDKConstantValue() { private static int[] initialValues = {0, 1, 0xDEADBEEF}; - private void testHash(String method, Function f, Function getLength) throws UnsupportedEncodingException { + private void testHash(String method, Function f, Function getLength) { + testHashOp(getInitialOptions(), method, f, getLength); + testHashOpVariants(method, f, getLength); + } + + private void testHashOp(OptionValues options, String method, Function f, Function getLength) { for (String test : tests) { - byte[] baseArray = test.getBytes("UTF-8"); + byte[] baseArray = test.getBytes(StandardCharsets.UTF_8); Object array = f.apply(baseArray); int len = getLength.apply(baseArray); @@ -81,7 +91,7 @@ private void testHash(String method, Function f, Function a, a -> a.length); } @@ -102,7 +112,7 @@ public static int hashByteArrayCharElement(byte[] array, int fromIndex, int leng } @Test - public void testHashByteArrayCharElement() throws UnsupportedEncodingException { + public void testHashByteArrayCharElement() { testHash("hashByteArrayCharElement", a -> a, a -> a.length / 2); } @@ -111,7 +121,7 @@ public static int hashBooleanArray(Object array, int fromIndex, int length, int } @Test - public void testHashBooleanArray() throws UnsupportedEncodingException { + public void testHashBooleanArray() { testHash("hashBooleanArray", a -> { byte[] array = new byte[a.length]; for (int i = 0; i < a.length; i++) { @@ -128,7 +138,7 @@ public static int hashCharArray(char[] array, int fromIndex, int length, int ini } @Test - public void testHashCharArray() throws UnsupportedEncodingException { + public void testHashCharArray() { testHash("hashCharArray", a -> { char[] array = new char[a.length]; for (int i = 0; i < a.length; i++) { @@ -143,7 +153,7 @@ public static int hashShortArray(short[] array, int fromIndex, int length, int i } @Test - public void testHashShortArray() throws UnsupportedEncodingException { + public void testHashShortArray() { testHash("hashShortArray", a -> { short[] array = new short[a.length]; for (int i = 0; i < a.length; i++) { @@ -158,7 +168,7 @@ public static int hashIntArray(int[] array, int fromIndex, int length, int initi } @Test - public void testHashIntArray() throws UnsupportedEncodingException { + public void testHashIntArray() { testHash("hashIntArray", a -> { int[] array = new int[a.length]; for (int i = 0; i < a.length; i++) { @@ -167,4 +177,30 @@ public void testHashIntArray() throws UnsupportedEncodingException { return array; }, a -> a.length); } + + private void testHashOpVariants(String method, Function f, Function getLength) { + if (getArchitecture() instanceof AArch64) { + OptionValues options = new OptionValues(getInitialOptions(), GraalOptions.InlineGraalStubs, true); + for (int vectorCount : new int[]{2, 4, 8}) { + for (boolean useLD1 : new boolean[]{false, true}) { + // Do not reuse already compiled code. + InstalledCode compiledMethod = getCode(getResolvedJavaMethod(method), options); + if (compiledMethod != null) { + compiledMethod.invalidate(true); + } + + int prevVectorCount = AArch64VectorizedHashCodeOp.VECTOR_COUNT; + boolean prevNeonLoad = AArch64VectorizedHashCodeOp.USE_LD1; + AArch64VectorizedHashCodeOp.VECTOR_COUNT = vectorCount; + AArch64VectorizedHashCodeOp.USE_LD1 = useLD1; + try { + testHashOp(options, method, f, getLength); + } finally { + AArch64VectorizedHashCodeOp.USE_LD1 = prevNeonLoad; + AArch64VectorizedHashCodeOp.VECTOR_COUNT = prevVectorCount; + } + } + } + } + } } From 1393c7040e668a59580f5c446c507ae372f1faba Mon Sep 17 00:00:00 2001 From: Andreas Woess Date: Thu, 30 Nov 2023 15:38:50 +0100 Subject: [PATCH 035/593] Deinterleave mla and mov instructions. --- .../compiler/lir/aarch64/AArch64VectorizedHashCodeOp.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/aarch64/AArch64VectorizedHashCodeOp.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/aarch64/AArch64VectorizedHashCodeOp.java index 88daf7e9ea95..10fb0a122c45 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/aarch64/AArch64VectorizedHashCodeOp.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/aarch64/AArch64VectorizedHashCodeOp.java @@ -242,8 +242,11 @@ public void emitCode(CompilationResultBuilder crb, AArch64MacroAssembler masm) { } // vresult[i] = vresult[i] * vnext + vtmp[i]; + // (desugared to: vtmp[i] += vresult[i] * vnext, vresult[i] = vtmp[i]) for (int idx = 0; idx < nRegs; idx++) { masm.neon.mlaVVV(ASIMDSize.FullReg, ElementSize.Word, vtmp[idx], vresult[idx], vnext); + } + for (int idx = 0; idx < nRegs; idx++) { masm.neon.moveVV(ASIMDSize.FullReg, vresult[idx], vtmp[idx]); } From 20b329c6d76960173b9ca33cabc65f19db02e331 Mon Sep 17 00:00:00 2001 From: Andreas Woess Date: Thu, 30 Nov 2023 15:48:31 +0100 Subject: [PATCH 036/593] Only support a single variant of AArch64VectorizedHashCodeOp. --- .../test/VectorizedHashCodeTest.java | 38 +------------------ .../aarch64/AArch64VectorizedHashCodeOp.java | 10 ++--- 2 files changed, 5 insertions(+), 43 deletions(-) diff --git a/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/replacements/test/VectorizedHashCodeTest.java b/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/replacements/test/VectorizedHashCodeTest.java index ea4e170474a2..8d84ceb3bbbd 100644 --- a/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/replacements/test/VectorizedHashCodeTest.java +++ b/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/replacements/test/VectorizedHashCodeTest.java @@ -32,15 +32,10 @@ import org.junit.Assert; import org.junit.Test; -import jdk.graal.compiler.core.common.GraalOptions; import jdk.graal.compiler.core.test.GraalCompilerTest; -import jdk.graal.compiler.lir.aarch64.AArch64VectorizedHashCodeOp; -import jdk.graal.compiler.options.OptionValues; import jdk.graal.compiler.replacements.StandardGraphBuilderPlugins.VectorizedHashCodeInvocationPlugin; import jdk.graal.compiler.test.AddExports; import jdk.internal.util.ArraysSupport; -import jdk.vm.ci.aarch64.AArch64; -import jdk.vm.ci.code.InstalledCode; @AddExports({"java.base/jdk.internal.util"}) public class VectorizedHashCodeTest extends GraalCompilerTest { @@ -65,11 +60,6 @@ public void testJDKConstantValue() { private static int[] initialValues = {0, 1, 0xDEADBEEF}; private void testHash(String method, Function f, Function getLength) { - testHashOp(getInitialOptions(), method, f, getLength); - testHashOpVariants(method, f, getLength); - } - - private void testHashOp(OptionValues options, String method, Function f, Function getLength) { for (String test : tests) { byte[] baseArray = test.getBytes(StandardCharsets.UTF_8); Object array = f.apply(baseArray); @@ -91,7 +81,7 @@ private void testHashOp(OptionValues options, String method, Function a.length); } - - private void testHashOpVariants(String method, Function f, Function getLength) { - if (getArchitecture() instanceof AArch64) { - OptionValues options = new OptionValues(getInitialOptions(), GraalOptions.InlineGraalStubs, true); - for (int vectorCount : new int[]{2, 4, 8}) { - for (boolean useLD1 : new boolean[]{false, true}) { - // Do not reuse already compiled code. - InstalledCode compiledMethod = getCode(getResolvedJavaMethod(method), options); - if (compiledMethod != null) { - compiledMethod.invalidate(true); - } - - int prevVectorCount = AArch64VectorizedHashCodeOp.VECTOR_COUNT; - boolean prevNeonLoad = AArch64VectorizedHashCodeOp.USE_LD1; - AArch64VectorizedHashCodeOp.VECTOR_COUNT = vectorCount; - AArch64VectorizedHashCodeOp.USE_LD1 = useLD1; - try { - testHashOp(options, method, f, getLength); - } finally { - AArch64VectorizedHashCodeOp.USE_LD1 = prevNeonLoad; - AArch64VectorizedHashCodeOp.VECTOR_COUNT = prevVectorCount; - } - } - } - } - } } diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/aarch64/AArch64VectorizedHashCodeOp.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/aarch64/AArch64VectorizedHashCodeOp.java index 10fb0a122c45..6004aff8dfa0 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/aarch64/AArch64VectorizedHashCodeOp.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/aarch64/AArch64VectorizedHashCodeOp.java @@ -70,10 +70,8 @@ public final class AArch64VectorizedHashCodeOp extends AArch64ComplexVectorOp { @Temp({OperandFlag.REG}) Value[] temp; @Temp({OperandFlag.REG}) Value[] vectorTemp; - /** Number of vector registers to use per loop iteration. */ - public static int VECTOR_COUNT = 4; - /** If true, tries to use NEON LD1 (multiple structures) instruction, else, uses LDR or LDP. */ - public static boolean USE_LD1 = false; + /** Number of vector registers to use per loop iteration (2, 4, or 8). */ + private static final int VECTOR_COUNT = 4; public AArch64VectorizedHashCodeOp(LIRGeneratorTool tool, AllocatableValue result, AllocatableValue arrayStart, AllocatableValue length, AllocatableValue initialValue, JavaKind arrayKind) { @@ -237,7 +235,7 @@ public void emitCode(CompilationResultBuilder crb, AArch64MacroAssembler masm) { // vtmp = ary1[index:index+elementsPerIteration]; for (int ldVi = 0; ldVi < nRegs; ldVi += regsFilledPerLoad) { boolean postIndex = true; - loadConsecutiveVectors(masm, loadVecSize, loadVecBits, elSize, ary1, vtmp, ldVi, consecutiveRegs, postIndex, USE_LD1); + loadConsecutiveVectors(masm, loadVecSize, loadVecBits, elSize, ary1, vtmp, ldVi, consecutiveRegs, postIndex, false); extendVectorsToWord(masm, unsigned, loadVecBits, elSize, vtmp, ldVi, consecutiveRegs); } @@ -270,7 +268,7 @@ public void emitCode(CompilationResultBuilder crb, AArch64MacroAssembler masm) { masm.adrpAdd(coefAddrReg); for (int i = 0; i < nRegs; i += maxConsecutiveRegs) { boolean postIndex = maxConsecutiveRegs < nRegs; - loadConsecutiveVectors(masm, ASIMDSize.FullReg, ASIMDSize.FullReg.bits(), ElementSize.Word, coefAddrReg, vcoef, i, maxConsecutiveRegs, postIndex, USE_LD1); + loadConsecutiveVectors(masm, ASIMDSize.FullReg, ASIMDSize.FullReg.bits(), ElementSize.Word, coefAddrReg, vcoef, i, maxConsecutiveRegs, postIndex, false); } // vresult *= vcoef; From 068b12d85a356d36469acd8bd2b796caf6c34762 Mon Sep 17 00:00:00 2001 From: Andreas Woess Date: Thu, 30 Nov 2023 16:12:46 +0100 Subject: [PATCH 037/593] Use unsigned index/bound comparisons. --- .../lir/aarch64/AArch64VectorizedHashCodeOp.java | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/aarch64/AArch64VectorizedHashCodeOp.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/aarch64/AArch64VectorizedHashCodeOp.java index 6004aff8dfa0..14f551be4e43 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/aarch64/AArch64VectorizedHashCodeOp.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/aarch64/AArch64VectorizedHashCodeOp.java @@ -201,7 +201,7 @@ public void emitCode(CompilationResultBuilder crb, AArch64MacroAssembler masm) { // if (cnt1 >= elementsPerIteration) && generate_vectorized_loop masm.compare(32, cnt1, elementsPerIteration); - masm.branchConditionally(ConditionFlag.LT, labelShortUnrolledBegin); + masm.branchConditionally(ConditionFlag.LO, labelShortUnrolledBegin); // index = 0; masm.mov(index, 0); @@ -253,7 +253,7 @@ public void emitCode(CompilationResultBuilder crb, AArch64MacroAssembler masm) { // index < bound; masm.cmp(32, index, bound); - masm.branchConditionally(ConditionFlag.LT, labelUnrolledVectorLoopBegin); + masm.branchConditionally(ConditionFlag.LO, labelUnrolledVectorLoopBegin); // } // assert index == bound && ary1 == &ary[bound]; @@ -291,7 +291,7 @@ public void emitCode(CompilationResultBuilder crb, AArch64MacroAssembler masm) { AArch64Address postIndexAddr = AArch64Address.createImmediateAddress(elSize.bits(), AddressingMode.IMMEDIATE_POST_INDEXED, ary1, elSize.bytes()); masm.cmp(32, index, cnt1); - masm.branchConditionally(ConditionFlag.GE, labelShortUnrolledLoopExit); + masm.branchConditionally(ConditionFlag.HS, labelShortUnrolledLoopExit); try (var scratch1 = masm.getScratchRegister(); var scratch2 = masm.getScratchRegister()) { var tmp31 = scratch1.getRegister(); @@ -312,13 +312,13 @@ public void emitCode(CompilationResultBuilder crb, AArch64MacroAssembler masm) { masm.add(32, index, index, 2); masm.cmp(32, index, cnt1); - masm.branchConditionally(ConditionFlag.LT, labelShortUnrolledLoopBegin); + masm.branchConditionally(ConditionFlag.LO, labelShortUnrolledLoopBegin); // } // if (i >= cnt1) { masm.bind(labelShortUnrolledLoopExit); // masm.cmp(32, index, cnt1); // already compared right above and before the jump here - masm.branchConditionally(ConditionFlag.GT, labelEnd); + masm.branchConditionally(ConditionFlag.HI, labelEnd); // result *= 31; // result += ary1[index - 1] masm.mov(tmp31, 31); From 558357d32538dce8d2a66a19383e1f12e6009697 Mon Sep 17 00:00:00 2001 From: Andreas Woess Date: Thu, 30 Nov 2023 15:59:34 +0100 Subject: [PATCH 038/593] Gracefully handle unsupported array element types. --- .../replacements/StandardGraphBuilderPlugins.java | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/replacements/StandardGraphBuilderPlugins.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/replacements/StandardGraphBuilderPlugins.java index b4ed44ae2249..f9ff00bf993c 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/replacements/StandardGraphBuilderPlugins.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/replacements/StandardGraphBuilderPlugins.java @@ -2525,7 +2525,6 @@ public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Rec ValueNode array, ValueNode fromIndex, ValueNode length, ValueNode initialValue, ValueNode basicType) { try (InvocationPluginHelper helper = new InvocationPluginHelper(b, targetMethod)) { if (basicType.isConstant()) { - ValueNode arrayStart; int basicTypeAsInt = basicType.asJavaConstant().asInt(); JavaKind componentType = switch (basicTypeAsInt) { case T_BOOLEAN -> JavaKind.Boolean; @@ -2533,11 +2532,15 @@ public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Rec case T_BYTE -> JavaKind.Byte; case T_SHORT -> JavaKind.Short; case T_INT -> JavaKind.Int; - default -> throw GraalError.shouldNotReachHere("Unsupported kind " + basicTypeAsInt); + default -> JavaKind.Illegal; }; + if (componentType == JavaKind.Illegal) { + // Unsupported array element type + return false; + } // for T_CHAR, the intrinsic accepts both byte[] and char[] - arrayStart = helper.arrayElementPointer(array, componentType, fromIndex, componentType == JavaKind.Char || componentType == JavaKind.Boolean); + ValueNode arrayStart = helper.arrayElementPointer(array, componentType, fromIndex, componentType == JavaKind.Char || componentType == JavaKind.Boolean); b.addPush(JavaKind.Int, new VectorizedHashCodeNode(arrayStart, length, initialValue, componentType)); return true; } From de485de241b5dd1a874e028fc48f5c324d1cbb78 Mon Sep 17 00:00:00 2001 From: Fengyun Liu Date: Mon, 6 Nov 2023 15:24:36 +0100 Subject: [PATCH 039/593] Add SpecJVM2008 native image benchmarks Co-authored-by: Francois Farquet --- .../mx.substratevm/mx_substratevm_benchmark.py | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/substratevm/mx.substratevm/mx_substratevm_benchmark.py b/substratevm/mx.substratevm/mx_substratevm_benchmark.py index c00124b38943..9d57732e5ef4 100644 --- a/substratevm/mx.substratevm/mx_substratevm_benchmark.py +++ b/substratevm/mx.substratevm/mx_substratevm_benchmark.py @@ -644,8 +644,22 @@ def createCommandLineArgs(self, benchmarks, bmSuiteArgs): self.benchmark_name = benchmarks[0] return args + @staticmethod + def short_run_args(): + return ["-wt", "1", "-it", "5"] + + def extra_agent_run_arg(self, benchmark, args, image_run_args): + return super(SpecJVM2008NativeImageBenchmarkSuite, self).extra_agent_run_arg(benchmark, args, image_run_args) + self.short_run_args() + ["-ikv"] + + def extra_profile_run_arg(self, benchmark, args, image_run_args, should_strip_run_args): + return super(SpecJVM2008NativeImageBenchmarkSuite, self).extra_profile_run_arg(benchmark, args, image_run_args, should_strip_run_args) + self.short_run_args() + ["-ikv"] + def extra_image_build_argument(self, benchmark, args): - return super(SpecJVM2008NativeImageBenchmarkSuite, self).extra_image_build_argument(benchmark, args) + mx_sdk_vm_impl.svm_experimental_options(['-H:-ParseRuntimeOptions']) + ['-Djava.awt.headless=false'] + return super(SpecJVM2008NativeImageBenchmarkSuite, self).extra_image_build_argument(benchmark, args) + mx_sdk_vm_impl.svm_experimental_options(['-H:-ParseRuntimeOptions']) + def extra_run_arg(self, benchmark, args, image_run_args): + # disables formatted report generation since chart generation with JFreeChart loads fonts from disk (from java.home) to compute string width + disable_rendered_report = ["-ctf", "false", "-chf", "false"] + return super(SpecJVM2008NativeImageBenchmarkSuite, self).extra_run_arg(benchmark, args, image_run_args) + disable_rendered_report + ["-ikv", "-wt", "5", "-it", "15"] mx_benchmark.add_bm_suite(SpecJVM2008NativeImageBenchmarkSuite()) From 8d30e8bb6c83b3a6326356ac6fffee9c9eaae18e Mon Sep 17 00:00:00 2001 From: Fengyun Liu Date: Thu, 9 Nov 2023 10:32:30 +0100 Subject: [PATCH 040/593] Fix success patterns for agent stages --- .../mx.substratevm/mx_substratevm_benchmark.py | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/substratevm/mx.substratevm/mx_substratevm_benchmark.py b/substratevm/mx.substratevm/mx_substratevm_benchmark.py index 9d57732e5ef4..a9fcad4d7fc0 100644 --- a/substratevm/mx.substratevm/mx_substratevm_benchmark.py +++ b/substratevm/mx.substratevm/mx_substratevm_benchmark.py @@ -635,7 +635,7 @@ def benchSuiteName(self, bmSuiteArgs=None): return 'specjvm2008' def createCommandLineArgs(self, benchmarks, bmSuiteArgs): - args = super(SpecJVM2008NativeImageBenchmarkSuite, self).createCommandLineArgs(benchmarks, bmSuiteArgs) + args = super().createCommandLineArgs(benchmarks, bmSuiteArgs) if benchmarks is None: mx.abort("Suite can only run a single benchmark per VM instance.") elif len(benchmarks) != 1: @@ -649,17 +649,20 @@ def short_run_args(): return ["-wt", "1", "-it", "5"] def extra_agent_run_arg(self, benchmark, args, image_run_args): - return super(SpecJVM2008NativeImageBenchmarkSuite, self).extra_agent_run_arg(benchmark, args, image_run_args) + self.short_run_args() + ["-ikv"] + return super().extra_agent_run_arg(benchmark, args, image_run_args) + self.short_run_args() + ["-ikv"] def extra_profile_run_arg(self, benchmark, args, image_run_args, should_strip_run_args): - return super(SpecJVM2008NativeImageBenchmarkSuite, self).extra_profile_run_arg(benchmark, args, image_run_args, should_strip_run_args) + self.short_run_args() + ["-ikv"] + return super().extra_profile_run_arg(benchmark, args, image_run_args, should_strip_run_args) + self.short_run_args() + ["-ikv"] def extra_image_build_argument(self, benchmark, args): - return super(SpecJVM2008NativeImageBenchmarkSuite, self).extra_image_build_argument(benchmark, args) + mx_sdk_vm_impl.svm_experimental_options(['-H:-ParseRuntimeOptions']) + return super().extra_image_build_argument(benchmark, args) + mx_sdk_vm_impl.svm_experimental_options(['-H:-ParseRuntimeOptions']) def extra_run_arg(self, benchmark, args, image_run_args): # disables formatted report generation since chart generation with JFreeChart loads fonts from disk (from java.home) to compute string width disable_rendered_report = ["-ctf", "false", "-chf", "false"] - return super(SpecJVM2008NativeImageBenchmarkSuite, self).extra_run_arg(benchmark, args, image_run_args) + disable_rendered_report + ["-ikv", "-wt", "5", "-it", "15"] + return super().extra_run_arg(benchmark, args, image_run_args) + disable_rendered_report + ["-ikv", "-wt", "5", "-it", "15"] + + def successPatterns(self): + return super().successPatterns() + [_successful_stage_pattern] mx_benchmark.add_bm_suite(SpecJVM2008NativeImageBenchmarkSuite()) From 2c1d5a02ce015efe765f9954814bffe76e0c7727 Mon Sep 17 00:00:00 2001 From: Fengyun Liu Date: Tue, 14 Nov 2023 10:59:29 +0100 Subject: [PATCH 041/593] Avoid nesting of svm_experimental_options: SVM rejects --- substratevm/mx.substratevm/mx_substratevm_benchmark.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/substratevm/mx.substratevm/mx_substratevm_benchmark.py b/substratevm/mx.substratevm/mx_substratevm_benchmark.py index a9fcad4d7fc0..986acf292a30 100644 --- a/substratevm/mx.substratevm/mx_substratevm_benchmark.py +++ b/substratevm/mx.substratevm/mx_substratevm_benchmark.py @@ -655,7 +655,8 @@ def extra_profile_run_arg(self, benchmark, args, image_run_args, should_strip_ru return super().extra_profile_run_arg(benchmark, args, image_run_args, should_strip_run_args) + self.short_run_args() + ["-ikv"] def extra_image_build_argument(self, benchmark, args): - return super().extra_image_build_argument(benchmark, args) + mx_sdk_vm_impl.svm_experimental_options(['-H:-ParseRuntimeOptions']) + # Don't wrap the option `-H:-ParseRuntimeOptions` with `mx_sdk_vm_impl.svm_experimental_options`, as all args are wrapped already. + return super().extra_image_build_argument(benchmark, args) + ['-H:-ParseRuntimeOptions'] def extra_run_arg(self, benchmark, args, image_run_args): # disables formatted report generation since chart generation with JFreeChart loads fonts from disk (from java.home) to compute string width From f70305235805baf6b4ccefc65e3e29cd8505709d Mon Sep 17 00:00:00 2001 From: Fengyun Liu Date: Wed, 15 Nov 2023 12:20:21 +0100 Subject: [PATCH 042/593] Use -R:ProfilesDumpFile at build-time instead of -XX:ProfilesDumpFile at app run-time: SpecJvm2008 rejects --- vm/mx.vm/mx_vm_benchmark.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/vm/mx.vm/mx_vm_benchmark.py b/vm/mx.vm/mx_vm_benchmark.py index 8771a17496c2..d87f4c634124 100644 --- a/vm/mx.vm/mx_vm_benchmark.py +++ b/vm/mx.vm/mx_vm_benchmark.py @@ -928,9 +928,9 @@ def run_stage_agent(self, config, stages): if file.endswith(".json"): zipf.write(os.path.join(root, file), os.path.relpath(os.path.join(root, file), os.path.join(path, '..'))) - def run_stage_instrument_image(self, config, stages, out, i, instrumentation_image_name, image_path, image_path_latest, instrumented_iterations): + def run_stage_instrument_image(self, config, stages, out, i, instrumentation_image_name, image_path, image_path_latest, instrumented_iterations, profile_path): executable_name_args = ['-o', instrumentation_image_name] - pgo_args = ['--pgo=' + config.latest_profile_path] + pgo_args = ['--pgo=' + config.latest_profile_path, '-R:ProfilesDumpFile=' + profile_path] pgo_args += svm_experimental_options(['-H:' + ('+' if self.pgo_context_sensitive else '-') + 'PGOContextSensitivityEnabled']) instrument_args = ['--pgo-instrument'] + ([] if i == 0 else pgo_args) if self.jdk_profiles_collect: @@ -963,7 +963,7 @@ def _ensureSamplesAreInProfile(self, profile_path): assert sample["records"][0] > 0, "Sampling profiles seem to have a 0 in records in file " + profile_path def run_stage_instrument_run(self, config, stages, image_path, profile_path): - image_run_cmd = [image_path, '-XX:ProfilesDumpFile=' + profile_path] + image_run_cmd = [image_path] image_run_cmd += config.extra_jvm_args image_run_cmd += config.extra_profile_run_args with stages.set_command(image_run_cmd) as s: @@ -1080,7 +1080,7 @@ def run_java(self, args, out=None, err=None, cwd=None, nonZeroIsFatal=False): image_path = os.path.join(config.output_dir, instrumentation_image_name) image_path_latest = os.path.join(config.output_dir, instrumentation_image_latest) if stages.change_stage('instrument-image', str(i)): - self.run_stage_instrument_image(config, stages, out, i, instrumentation_image_name, image_path, image_path_latest, instrumented_iterations) + self.run_stage_instrument_image(config, stages, out, i, instrumentation_image_name, image_path, image_path_latest, instrumented_iterations, profile_path) if stages.change_stage('instrument-run', str(i)): self.run_stage_instrument_run(config, stages, image_path, profile_path) From 4e222de43758c941b4096c50fe7354a3900a0fda Mon Sep 17 00:00:00 2001 From: Fengyun Liu Date: Thu, 16 Nov 2023 17:19:16 +0100 Subject: [PATCH 043/593] Disable rendering report --- substratevm/mx.substratevm/mx_substratevm_benchmark.py | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/substratevm/mx.substratevm/mx_substratevm_benchmark.py b/substratevm/mx.substratevm/mx_substratevm_benchmark.py index 986acf292a30..625019618e78 100644 --- a/substratevm/mx.substratevm/mx_substratevm_benchmark.py +++ b/substratevm/mx.substratevm/mx_substratevm_benchmark.py @@ -627,6 +627,8 @@ class SpecJVM2008NativeImageBenchmarkSuite(mx_java_benchmarks.SpecJvm2008Benchma """ SpecJVM2008 for Native Image """ + # disables formatted report generation since chart generation with JFreeChart loads fonts from disk (from java.home) to compute string width + disable_rendered_report = ["-ctf", "false", "-chf", "false"] def name(self): return 'specjvm2008-native-image' @@ -636,6 +638,7 @@ def benchSuiteName(self, bmSuiteArgs=None): def createCommandLineArgs(self, benchmarks, bmSuiteArgs): args = super().createCommandLineArgs(benchmarks, bmSuiteArgs) + if benchmarks is None: mx.abort("Suite can only run a single benchmark per VM instance.") elif len(benchmarks) != 1: @@ -646,7 +649,7 @@ def createCommandLineArgs(self, benchmarks, bmSuiteArgs): @staticmethod def short_run_args(): - return ["-wt", "1", "-it", "5"] + return SpecJVM2008NativeImageBenchmarkSuite.disable_rendered_report + ["-wt", "1", "-it", "5"] def extra_agent_run_arg(self, benchmark, args, image_run_args): return super().extra_agent_run_arg(benchmark, args, image_run_args) + self.short_run_args() + ["-ikv"] @@ -659,9 +662,7 @@ def extra_image_build_argument(self, benchmark, args): return super().extra_image_build_argument(benchmark, args) + ['-H:-ParseRuntimeOptions'] def extra_run_arg(self, benchmark, args, image_run_args): - # disables formatted report generation since chart generation with JFreeChart loads fonts from disk (from java.home) to compute string width - disable_rendered_report = ["-ctf", "false", "-chf", "false"] - return super().extra_run_arg(benchmark, args, image_run_args) + disable_rendered_report + ["-ikv", "-wt", "5", "-it", "15"] + return super().extra_run_arg(benchmark, args, image_run_args) + SpecJVM2008NativeImageBenchmarkSuite.disable_rendered_report + ["-ikv", "-wt", "5", "-it", "15"] def successPatterns(self): return super().successPatterns() + [_successful_stage_pattern] From 397f66b4de1f113a3a4b1692e2e4bf50eff8b8de Mon Sep 17 00:00:00 2001 From: Fengyun Liu Date: Thu, 16 Nov 2023 18:57:42 +0100 Subject: [PATCH 044/593] Make sure instrumentation works on the first iteration --- vm/mx.vm/mx_vm_benchmark.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/vm/mx.vm/mx_vm_benchmark.py b/vm/mx.vm/mx_vm_benchmark.py index d87f4c634124..5bca3504f8db 100644 --- a/vm/mx.vm/mx_vm_benchmark.py +++ b/vm/mx.vm/mx_vm_benchmark.py @@ -930,9 +930,9 @@ def run_stage_agent(self, config, stages): def run_stage_instrument_image(self, config, stages, out, i, instrumentation_image_name, image_path, image_path_latest, instrumented_iterations, profile_path): executable_name_args = ['-o', instrumentation_image_name] - pgo_args = ['--pgo=' + config.latest_profile_path, '-R:ProfilesDumpFile=' + profile_path] + pgo_args = ['--pgo=' + config.latest_profile_path] pgo_args += svm_experimental_options(['-H:' + ('+' if self.pgo_context_sensitive else '-') + 'PGOContextSensitivityEnabled']) - instrument_args = ['--pgo-instrument'] + ([] if i == 0 else pgo_args) + instrument_args = ['--pgo-instrument', '-R:ProfilesDumpFile=' + profile_path] + ([] if i == 0 else pgo_args) if self.jdk_profiles_collect: instrument_args += svm_experimental_options(['-H:+ProfilingEnabled', '-H:+AOTPriorityInline', '-H:-SamplingCollect', f'-H:ProfilingPackagePrefixes={self.generate_profiling_package_prefixes()}']) From a99df066ab2bb3a55191de2b81c7fba5f1996238 Mon Sep 17 00:00:00 2001 From: Fengyun Liu Date: Fri, 17 Nov 2023 10:04:45 +0100 Subject: [PATCH 045/593] Use short iteration by default --- .../mx.substratevm/mx_substratevm_benchmark.py | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/substratevm/mx.substratevm/mx_substratevm_benchmark.py b/substratevm/mx.substratevm/mx_substratevm_benchmark.py index 625019618e78..345249a01066 100644 --- a/substratevm/mx.substratevm/mx_substratevm_benchmark.py +++ b/substratevm/mx.substratevm/mx_substratevm_benchmark.py @@ -629,6 +629,7 @@ class SpecJVM2008NativeImageBenchmarkSuite(mx_java_benchmarks.SpecJvm2008Benchma """ # disables formatted report generation since chart generation with JFreeChart loads fonts from disk (from java.home) to compute string width disable_rendered_report = ["-ctf", "false", "-chf", "false"] + short_run_args = disable_rendered_report + ["-wt", "1", "-it", "1", "-ikv"] def name(self): return 'specjvm2008-native-image' @@ -647,22 +648,18 @@ def createCommandLineArgs(self, benchmarks, bmSuiteArgs): self.benchmark_name = benchmarks[0] return args - @staticmethod - def short_run_args(): - return SpecJVM2008NativeImageBenchmarkSuite.disable_rendered_report + ["-wt", "1", "-it", "5"] - def extra_agent_run_arg(self, benchmark, args, image_run_args): - return super().extra_agent_run_arg(benchmark, args, image_run_args) + self.short_run_args() + ["-ikv"] + return super().extra_agent_run_arg(benchmark, args, image_run_args) + SpecJVM2008NativeImageBenchmarkSuite.short_run_args def extra_profile_run_arg(self, benchmark, args, image_run_args, should_strip_run_args): - return super().extra_profile_run_arg(benchmark, args, image_run_args, should_strip_run_args) + self.short_run_args() + ["-ikv"] + return super().extra_profile_run_arg(benchmark, args, image_run_args, should_strip_run_args) + SpecJVM2008NativeImageBenchmarkSuite.short_run_args def extra_image_build_argument(self, benchmark, args): # Don't wrap the option `-H:-ParseRuntimeOptions` with `mx_sdk_vm_impl.svm_experimental_options`, as all args are wrapped already. return super().extra_image_build_argument(benchmark, args) + ['-H:-ParseRuntimeOptions'] def extra_run_arg(self, benchmark, args, image_run_args): - return super().extra_run_arg(benchmark, args, image_run_args) + SpecJVM2008NativeImageBenchmarkSuite.disable_rendered_report + ["-ikv", "-wt", "5", "-it", "15"] + return super().extra_run_arg(benchmark, args, image_run_args) + SpecJVM2008NativeImageBenchmarkSuite.short_run_args def successPatterns(self): return super().successPatterns() + [_successful_stage_pattern] From da48646039d180d3e1bcee6673b02a93c84a8b28 Mon Sep 17 00:00:00 2001 From: Fengyun Liu Date: Wed, 22 Nov 2023 11:51:11 +0100 Subject: [PATCH 046/593] =?UTF-8?q?Avoid=20non-determinism=20in=20testing?= =?UTF-8?q?=20SpecJvm2008=20(Thanks=20Fran=C3=A7ois)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../ci/ci_common/benchmark-suites.libsonnet | 3 --- .../mx.java-benchmarks/mx_java_benchmarks.py | 19 ++++++++++++------- 2 files changed, 12 insertions(+), 10 deletions(-) diff --git a/compiler/ci/ci_common/benchmark-suites.libsonnet b/compiler/ci/ci_common/benchmark-suites.libsonnet index 033c897b86fc..2ea20d4f134a 100644 --- a/compiler/ci/ci_common/benchmark-suites.libsonnet +++ b/compiler/ci/ci_common/benchmark-suites.libsonnet @@ -172,9 +172,6 @@ run+: [ self.benchmark_cmd + ["specjvm2008:*", "--"] + self.extra_vm_args + ["--", "-ikv", "-it", "240s", "-wt", "120s"] ], - teardown+: [ - ["rm", "-r", "${SPECJVM2008}/results"] - ], timelimit: "3:00:00", forks_batches:: 5, forks_timelimit:: "06:00:00", diff --git a/java-benchmarks/mx.java-benchmarks/mx_java_benchmarks.py b/java-benchmarks/mx.java-benchmarks/mx_java_benchmarks.py index 7b8bd3eb6d69..e2ef50afe467 100644 --- a/java-benchmarks/mx.java-benchmarks/mx_java_benchmarks.py +++ b/java-benchmarks/mx.java-benchmarks/mx_java_benchmarks.py @@ -29,6 +29,7 @@ import os from os.path import join, exists import json +import shutil from shutil import rmtree from tempfile import mkdtemp, mkstemp @@ -1364,8 +1365,7 @@ def workloadSize(self): if 'startup.compiler.compiler' in _allSpecJVM2008BenchesJDK9: _allSpecJVM2008BenchesJDK9.remove('startup.compiler.compiler') - -class SpecJvm2008BenchmarkSuite(mx_benchmark.JavaBenchmarkSuite): +class SpecJvm2008BenchmarkSuite(mx_benchmark.JavaBenchmarkSuite, mx_benchmark.TemporaryWorkdirMixin): """SpecJVM2008 benchmark suite implementation. This benchmark suite can run multiple benchmarks as part of one VM run. @@ -1384,11 +1384,19 @@ def specJvmPath(self): if specjvm2008 is None: mx.abort("Please set the SPECJVM2008 environment variable to a " + "SPECjvm2008 directory.") - jarpath = join(specjvm2008, "SPECjvm2008.jar") + jarname = "SPECjvm2008.jar" + jarpath = join(specjvm2008, jarname) if not exists(jarpath): mx.abort("The SPECJVM2008 environment variable points to a directory " + "without the SPECjvm2008.jar file.") - return jarpath + + # copy to newly-created temporary working directory + working_dir_jarpath = os.path.abspath(join(self.workdir, jarname)) + if not exists(working_dir_jarpath): + mx.log("copying " + specjvm2008 + " to " + self.workdir) + shutil.copytree(specjvm2008, self.workdir, dirs_exist_ok=True) + + return working_dir_jarpath def validateEnvironment(self): if not self.specJvmPath(): @@ -1398,9 +1406,6 @@ def validateEnvironment(self): def validateReturnCode(self, retcode): return retcode == 0 - def workingDirectory(self, benchmarks, bmSuiteArgs): - return mx.get_env("SPECJVM2008") - def createCommandLineArgs(self, benchmarks, bmSuiteArgs): if benchmarks is None: # No benchmark specified in the command line, so run everything. From 9cbb8d478a0a4665bc36c298b6f2af8fc20af151 Mon Sep 17 00:00:00 2001 From: Fengyun Liu Date: Thu, 30 Nov 2023 17:53:47 +0100 Subject: [PATCH 047/593] Increase compilation timeout --- substratevm/mx.substratevm/mx_substratevm_benchmark.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/substratevm/mx.substratevm/mx_substratevm_benchmark.py b/substratevm/mx.substratevm/mx_substratevm_benchmark.py index 345249a01066..c734cb7d38c1 100644 --- a/substratevm/mx.substratevm/mx_substratevm_benchmark.py +++ b/substratevm/mx.substratevm/mx_substratevm_benchmark.py @@ -656,7 +656,7 @@ def extra_profile_run_arg(self, benchmark, args, image_run_args, should_strip_ru def extra_image_build_argument(self, benchmark, args): # Don't wrap the option `-H:-ParseRuntimeOptions` with `mx_sdk_vm_impl.svm_experimental_options`, as all args are wrapped already. - return super().extra_image_build_argument(benchmark, args) + ['-H:-ParseRuntimeOptions'] + return super().extra_image_build_argument(benchmark, args) + ['-H:-ParseRuntimeOptions', '-H:CompilationExpirationPeriod=600'] def extra_run_arg(self, benchmark, args, image_run_args): return super().extra_run_arg(benchmark, args, image_run_args) + SpecJVM2008NativeImageBenchmarkSuite.short_run_args From 3456402c600812042a1e804ad5f0a8694ef65e2b Mon Sep 17 00:00:00 2001 From: ol-automation_ww Date: Thu, 30 Nov 2023 20:39:52 +0000 Subject: [PATCH 048/593] update to jvmci-23.1-b26 --- common.json | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/common.json b/common.json index ac12c51f98e9..0c00d884d863 100644 --- a/common.json +++ b/common.json @@ -35,12 +35,12 @@ "labsjdk-ee-20-llvm": {"name": "labsjdk", "version": "ee-20.0.2+2-jvmci-23.1-b02-sulong", "platformspecific": true }, "oraclejdk21": {"name": "jpg-jdk", "version": "21", "build_id": "33", "release": true, "platformspecific": true, "extrabundles": ["static-libs"]}, - "labsjdk-ce-21": {"name": "labsjdk", "version": "ce-21.0.1+12-jvmci-23.1-b22", "platformspecific": true }, - "labsjdk-ce-21Debug": {"name": "labsjdk", "version": "ce-21.0.1+12-jvmci-23.1-b22-debug", "platformspecific": true }, - "labsjdk-ce-21-llvm": {"name": "labsjdk", "version": "ce-21.0.1+12-jvmci-23.1-b22-sulong", "platformspecific": true }, - "labsjdk-ee-21": {"name": "labsjdk", "version": "ee-21.0.1+11-jvmci-23.1-b22", "platformspecific": true }, - "labsjdk-ee-21Debug": {"name": "labsjdk", "version": "ee-21.0.1+11-jvmci-23.1-b22-debug", "platformspecific": true }, - "labsjdk-ee-21-llvm": {"name": "labsjdk", "version": "ee-21.0.1+11-jvmci-23.1-b22-sulong", "platformspecific": true }, + "labsjdk-ce-21": {"name": "labsjdk", "version": "ce-21.0.1+12-jvmci-23.1-b26-20231026173927-c23572fa4a", "platformspecific": true }, + "labsjdk-ce-21Debug": {"name": "labsjdk", "version": "ce-21.0.1+12-jvmci-23.1-b26-20231026173927-c23572fa4a-debug", "platformspecific": true }, + "labsjdk-ce-21-llvm": {"name": "labsjdk", "version": "ce-21.0.1+12-jvmci-23.1-b26-20231026173927-c23572fa4a-sulong", "platformspecific": true }, + "labsjdk-ee-21": {"name": "labsjdk", "version": "ee-21.0.1+11-jvmci-23.1-b26-20231027085922-c77176937e+38e747d58e", "platformspecific": true }, + "labsjdk-ee-21Debug": {"name": "labsjdk", "version": "ee-21.0.1+11-jvmci-23.1-b26-20231027085922-c77176937e+38e747d58e-debug", "platformspecific": true }, + "labsjdk-ee-21-llvm": {"name": "labsjdk", "version": "ee-21.0.1+11-jvmci-23.1-b26-20231027085922-c77176937e+38e747d58e-sulong", "platformspecific": true }, "oraclejdk-latest": {"name": "jpg-jdk", "version": "22", "build_id": "25", "release": true, "platformspecific": true, "extrabundles": ["static-libs"]}, "labsjdk-ce-latest": {"name": "labsjdk", "version": "ce-22+25-jvmci-b01", "platformspecific": true }, From 791db3656d240c861a2d77a6d59ba2674fff12b8 Mon Sep 17 00:00:00 2001 From: Josef Eisl Date: Fri, 1 Dec 2023 08:45:59 +0100 Subject: [PATCH 049/593] svm: adopt "JDK-8318776: Require supports_cx8 to always be true" --- .../src/com/oracle/svm/core/jdk/RecomputedFields.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/RecomputedFields.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/RecomputedFields.java index c7725ec4aa1b..7f151ca7be15 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/RecomputedFields.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/RecomputedFields.java @@ -194,7 +194,7 @@ final class Target_java_util_concurrent_atomic_AtomicLongFieldUpdater_CASUpdater } -@TargetClass(className = "java.util.concurrent.atomic.AtomicLongFieldUpdater$LockedUpdater") +@TargetClass(className = "java.util.concurrent.atomic.AtomicLongFieldUpdater$LockedUpdater", onlyWith = JDK21OrEarlier.class) final class Target_java_util_concurrent_atomic_AtomicLongFieldUpdater_LockedUpdater { @Alias @RecomputeFieldValue(kind = AtomicFieldUpdaterOffset) // private long offset; From 207e120d1287df5ce6c0b713c9c84f40a86fc177 Mon Sep 17 00:00:00 2001 From: Josef Eisl Date: Fri, 1 Dec 2023 09:21:07 +0100 Subject: [PATCH 050/593] svm: adopt "JDK-8314745: JFR: @StackFilter" [GR-50452] --- .../core/jfr/Target_jdk_jfr_internal_JVM.java | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jfr/Target_jdk_jfr_internal_JVM.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jfr/Target_jdk_jfr_internal_JVM.java index 15db4a59c588..8d70ddce6a4a 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jfr/Target_jdk_jfr_internal_JVM.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jfr/Target_jdk_jfr_internal_JVM.java @@ -27,7 +27,6 @@ import java.util.List; import java.util.function.BooleanSupplier; -import jdk.graal.compiler.api.replacements.Fold; import org.graalvm.nativeimage.Platform; import org.graalvm.nativeimage.Platforms; import org.graalvm.nativeimage.ProcessProperties; @@ -41,8 +40,10 @@ import com.oracle.svm.core.annotate.TargetElement; import com.oracle.svm.core.jdk.JDK22OrLater; import com.oracle.svm.core.jfr.traceid.JfrTraceId; +import com.oracle.svm.core.util.VMError; import com.oracle.svm.util.ReflectionUtil; +import jdk.graal.compiler.api.replacements.Fold; import jdk.jfr.internal.JVM; import jdk.jfr.internal.LogTag; @@ -147,7 +148,7 @@ public static String getPid() { @Substitute @Uninterruptible(reason = "Needed for SubstrateJVM.getStackTraceId().") @TargetElement(onlyWith = JDK22OrLater.class) - public static long getStackTraceId(int skipCount) { + public static long getStackTraceId(int skipCount, long stackFilterId) { /* * The result is only valid until the epoch changes but this is fine because EventWriter * instances are invalidated when the epoch changes. @@ -155,6 +156,18 @@ public static long getStackTraceId(int skipCount) { return SubstrateJVM.get().getStackTraceId(skipCount); } + @Substitute + @TargetElement(onlyWith = JDK22OrLater.class) + public static long registerStackFilter(String[] classes, String[] methods) { + throw VMError.unimplemented("JFR StackFilters are not yet supported."); + } + + @Substitute + @TargetElement(onlyWith = JDK22OrLater.class) + public static void unregisterStackFilter(long stackFilterId) { + throw VMError.unimplemented("JFR StackFilters are not yet supported."); + } + /** See {@link JVM#getThreadId}. */ @Substitute @TargetElement(onlyWith = JDK22OrLater.class) From 9c1165c86d6c4726d4c865d766053e9129baf321 Mon Sep 17 00:00:00 2001 From: Josef Eisl Date: Fri, 1 Dec 2023 09:58:25 +0100 Subject: [PATCH 051/593] svm: adopt "JDK-8310644: Make panama memory segment close use async handshakes" --- ...arget_jdk_internal_misc_ScopedMemoryAccess.java | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/substratevm/src/com.oracle.svm.core.foreign/src/com/oracle/svm/core/foreign/Target_jdk_internal_misc_ScopedMemoryAccess.java b/substratevm/src/com.oracle.svm.core.foreign/src/com/oracle/svm/core/foreign/Target_jdk_internal_misc_ScopedMemoryAccess.java index 420bd21d9dff..ef77d680204b 100644 --- a/substratevm/src/com.oracle.svm.core.foreign/src/com/oracle/svm/core/foreign/Target_jdk_internal_misc_ScopedMemoryAccess.java +++ b/substratevm/src/com.oracle.svm.core.foreign/src/com/oracle/svm/core/foreign/Target_jdk_internal_misc_ScopedMemoryAccess.java @@ -28,6 +28,9 @@ import com.oracle.svm.core.annotate.Substitute; import com.oracle.svm.core.annotate.TargetClass; +import com.oracle.svm.core.annotate.TargetElement; +import com.oracle.svm.core.jdk.JDK21OrEarlier; +import com.oracle.svm.core.jdk.JDK22OrLater; import jdk.internal.foreign.MemorySessionImpl; @@ -65,7 +68,18 @@ static void registerNatives() { * As one might notice, what is not supported is not creating shared arenas, but closing them. */ @Substitute + @TargetElement(onlyWith = JDK22OrLater.class) + void closeScope0(MemorySessionImpl session, Target_jdk_internal_misc_ScopedMemoryAccess_ScopedAccessError error) { + throw unsupportedFeature("Arena.ofShared is not yet supported."); + } + + @Substitute + @TargetElement(onlyWith = JDK21OrEarlier.class) boolean closeScope0(MemorySessionImpl session) { throw unsupportedFeature("Arena.ofShared is not yet supported."); } } + +@TargetClass(className = "jdk.internal.misc.ScopedMemoryAccess$ScopedAccessError", onlyWith = JDK22OrLater.class) +final class Target_jdk_internal_misc_ScopedMemoryAccess_ScopedAccessError { +} From d9ef8db7c45f0602310fe872010a94c85c1fd7b5 Mon Sep 17 00:00:00 2001 From: Fengyun Liu Date: Fri, 1 Dec 2023 13:57:53 +0100 Subject: [PATCH 052/593] Use more iterations for bench --- substratevm/mx.substratevm/mx_substratevm_benchmark.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/substratevm/mx.substratevm/mx_substratevm_benchmark.py b/substratevm/mx.substratevm/mx_substratevm_benchmark.py index c734cb7d38c1..875c35bc0153 100644 --- a/substratevm/mx.substratevm/mx_substratevm_benchmark.py +++ b/substratevm/mx.substratevm/mx_substratevm_benchmark.py @@ -630,6 +630,7 @@ class SpecJVM2008NativeImageBenchmarkSuite(mx_java_benchmarks.SpecJvm2008Benchma # disables formatted report generation since chart generation with JFreeChart loads fonts from disk (from java.home) to compute string width disable_rendered_report = ["-ctf", "false", "-chf", "false"] short_run_args = disable_rendered_report + ["-wt", "1", "-it", "1", "-ikv"] + long_run_args = disable_rendered_report + ["-wt", "10", "-it", "5", "-ikv"] def name(self): return 'specjvm2008-native-image' @@ -656,10 +657,11 @@ def extra_profile_run_arg(self, benchmark, args, image_run_args, should_strip_ru def extra_image_build_argument(self, benchmark, args): # Don't wrap the option `-H:-ParseRuntimeOptions` with `mx_sdk_vm_impl.svm_experimental_options`, as all args are wrapped already. + # The reason to add `-H:CompilationExpirationPeriod` is that we encounter non-deterministic compiler crash due to expiration. return super().extra_image_build_argument(benchmark, args) + ['-H:-ParseRuntimeOptions', '-H:CompilationExpirationPeriod=600'] def extra_run_arg(self, benchmark, args, image_run_args): - return super().extra_run_arg(benchmark, args, image_run_args) + SpecJVM2008NativeImageBenchmarkSuite.short_run_args + return super().extra_run_arg(benchmark, args, image_run_args) + SpecJVM2008NativeImageBenchmarkSuite.long_run_args def successPatterns(self): return super().successPatterns() + [_successful_stage_pattern] From 3f45f10e7bf7e2aabed7933fed15a751d4d72da9 Mon Sep 17 00:00:00 2001 From: Yudi Zheng Date: Fri, 1 Dec 2023 19:45:59 +0100 Subject: [PATCH 053/593] Mark all killed XMM registers as @Temp in AMD64SHA256AVX2Op. --- .../src/jdk/graal/compiler/lir/amd64/AMD64SHA256AVX2Op.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/amd64/AMD64SHA256AVX2Op.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/amd64/AMD64SHA256AVX2Op.java index 07b6c10e0010..52d52b12dbb9 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/amd64/AMD64SHA256AVX2Op.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/amd64/AMD64SHA256AVX2Op.java @@ -136,6 +136,9 @@ public AMD64SHA256AVX2Op(AllocatableValue bufValue, AllocatableValue stateValue, xmm8.asValue(), xmm9.asValue(), xmm10.asValue(), + xmm11.asValue(), + xmm12.asValue(), + xmm13.asValue(), }; } From 1af1f4c8c4a5cf6c1dbb78e1d6f5712798b60fd6 Mon Sep 17 00:00:00 2001 From: Tom Rodriguez Date: Tue, 28 Nov 2023 22:50:39 -0800 Subject: [PATCH 054/593] Always full gc after compilation --- .../graal/compiler/core/phases/BaseTier.java | 2 +- .../compiler/hotspot/CompilationTask.java | 9 +++- .../compiler/lir/phases/LIRPhaseSuite.java | 3 +- .../serviceprovider/GraalServices.java | 23 ++++++++- .../hotspot/libgraal/LibGraalEntryPoints.java | 47 ++++++++++++------- .../hotspot/libgraal/LibGraalFeature.java | 12 +++-- .../libgraal/LibGraalSubstitutions.java | 4 ++ 7 files changed, 73 insertions(+), 27 deletions(-) diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/core/phases/BaseTier.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/core/phases/BaseTier.java index 8a166bae6078..ce1fb43aaff8 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/core/phases/BaseTier.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/core/phases/BaseTier.java @@ -53,7 +53,7 @@ protected void run(StructuredGraph graph, C context) { // Notify the runtime that most objects allocated in previous HIR phase are dead and can // be reclaimed. This will lower the chance of allocation failure in the next HIR phase. try (DebugCloseable timer = HIRHintedGC.start(graph.getDebug())) { - GraalServices.notifyLowMemoryPoint(false); + GraalServices.notifyLowMemoryPoint(); } phase.apply(graph, context); } diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/CompilationTask.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/CompilationTask.java index 80ea5f839c61..f87405fa7793 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/CompilationTask.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/CompilationTask.java @@ -56,7 +56,9 @@ import jdk.graal.compiler.nodes.StructuredGraph; import jdk.graal.compiler.nodes.spi.StableProfileProvider; import jdk.graal.compiler.nodes.spi.StableProfileProvider.TypeFilter; +import jdk.graal.compiler.options.Option; import jdk.graal.compiler.options.OptionKey; +import jdk.graal.compiler.options.OptionType; import jdk.graal.compiler.options.OptionValues; import jdk.graal.compiler.printer.GraalDebugHandlersFactory; import jdk.graal.compiler.serviceprovider.GraalServices; @@ -74,6 +76,11 @@ public class CompilationTask implements CompilationWatchDog.EventHandler { + static class Options { + @Option(help = "Perform a full GC after every compile to reduce idle heap and reclaim references", type = OptionType.Expert)// + public static final OptionKey FullGCAfterCompile = new OptionKey<>(false); + } + @Override public void onStuckCompilation(CompilationWatchDog watchDog, Thread watched, CompilationIdentifier compilation, StackTraceElement[] stackTrace, int stuckTime) { CompilationWatchDog.EventHandler.super.onStuckCompilation(watchDog, watched, compilation, stackTrace, stuckTime); @@ -379,7 +386,7 @@ public HotSpotCompilationRequestResult runCompilation(DebugContext debug) { // Notify the runtime that most objects allocated in the current compilation // are dead and can be reclaimed. try (DebugCloseable timer = HintedFullGC.start(debug)) { - GraalServices.notifyLowMemoryPoint(true); + GraalServices.notifyLowMemoryPoint(Options.FullGCAfterCompile.getValue(debug.getOptions())); } return result; } diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/phases/LIRPhaseSuite.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/phases/LIRPhaseSuite.java index 96c2ecfc3f9d..83c1d2c1d5da 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/phases/LIRPhaseSuite.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/phases/LIRPhaseSuite.java @@ -35,7 +35,6 @@ import jdk.graal.compiler.debug.TimerKey; import jdk.graal.compiler.lir.gen.LIRGenerationResult; import jdk.graal.compiler.serviceprovider.GraalServices; - import jdk.vm.ci.code.TargetDescription; public class LIRPhaseSuite extends LIRPhase implements PhasePlan> { @@ -109,7 +108,7 @@ protected final void run(TargetDescription target, LIRGenerationResult lirGenRes // Notify the runtime that most objects allocated in previous LIR phase are dead and can // be reclaimed. This will lower the chance of allocation failure in the next LIR phase. try (DebugCloseable timer = LIRHintedGC.start(lirGenRes.getLIR().getDebug())) { - GraalServices.notifyLowMemoryPoint(false); + GraalServices.notifyLowMemoryPoint(); } phase.apply(target, lirGenRes, context); } diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/serviceprovider/GraalServices.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/serviceprovider/GraalServices.java index 6455d3bd97d6..b05acc3ba6a1 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/serviceprovider/GraalServices.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/serviceprovider/GraalServices.java @@ -500,14 +500,33 @@ public static boolean hasLookupMethodWithCaller() { return constantPoolLookupMethodWithCaller != null; } + /** + * Notifies that the compiler is at a point where memory usage is expected to be minimal like + * after the completion of compilation. + * + * @param forceFullGC controls whether to explicitly perform a full GC + */ + public static void notifyLowMemoryPoint(boolean forceFullGC) { + notifyLowMemoryPoint(true, forceFullGC); + } + + /** + * Notifies that the compiler is at a point where memory usage is might have dropped + * significantly like after some major phase execution. + */ + public static void notifyLowMemoryPoint() { + notifyLowMemoryPoint(false, false); + } + /** * Notifies that the compiler is at a point where memory usage is expected to be relatively low * (e.g., just before/after a compilation). The garbage collector might be able to make use of * such a hint to optimize its performance. * - * @param fullGC controls whether the hinted GC should be a full GC. + * @param hintFullGC controls whether the hinted GC should be a full GC. + * @param forceFullGC controls whether to explicitly perform a full GC */ - public static void notifyLowMemoryPoint(@SuppressWarnings("unused") boolean fullGC) { + private static void notifyLowMemoryPoint(boolean hintFullGC, boolean forceFullGC) { // Substituted by // com.oracle.svm.hotspot.libgraal.Target_jdk_graal_compiler_serviceprovider_GraalServices } diff --git a/substratevm/src/com.oracle.svm.graal.hotspot.libgraal/src/com/oracle/svm/graal/hotspot/libgraal/LibGraalEntryPoints.java b/substratevm/src/com.oracle.svm.graal.hotspot.libgraal/src/com/oracle/svm/graal/hotspot/libgraal/LibGraalEntryPoints.java index 7fef8b6ecf1c..9d0e007a3d1d 100644 --- a/substratevm/src/com.oracle.svm.graal.hotspot.libgraal/src/com/oracle/svm/graal/hotspot/libgraal/LibGraalEntryPoints.java +++ b/substratevm/src/com.oracle.svm.graal.hotspot.libgraal/src/com/oracle/svm/graal/hotspot/libgraal/LibGraalEntryPoints.java @@ -35,21 +35,6 @@ import org.graalvm.collections.EconomicMap; import org.graalvm.collections.EconomicSet; -import jdk.graal.compiler.core.common.spi.ForeignCallSignature; -import jdk.graal.compiler.core.target.Backend; -import jdk.graal.compiler.debug.GlobalMetrics; -import jdk.graal.compiler.hotspot.CompilationContext; -import jdk.graal.compiler.hotspot.CompilationTask; -import jdk.graal.compiler.hotspot.HotSpotForeignCallLinkageImpl.CodeInfo; -import jdk.graal.compiler.hotspot.HotSpotGraalCompiler; -import jdk.graal.compiler.hotspot.HotSpotGraalRuntime; -import jdk.graal.compiler.hotspot.HotSpotGraalServices; -import jdk.graal.compiler.hotspot.ProfileReplaySupport; -import jdk.graal.compiler.hotspot.stubs.Stub; -import jdk.graal.compiler.options.OptionDescriptors; -import jdk.graal.compiler.options.OptionKey; -import jdk.graal.compiler.options.OptionValues; -import jdk.graal.compiler.options.OptionsParser; import org.graalvm.jniutils.JNI.JNIEnv; import org.graalvm.jniutils.JNIMethodScope; import org.graalvm.nativeimage.UnmanagedMemory; @@ -60,7 +45,6 @@ import org.graalvm.nativeimage.c.struct.SizeOf; import org.graalvm.nativeimage.c.type.CIntPointer; import org.graalvm.nativeimage.c.type.CTypeConversion; -import jdk.graal.compiler.util.OptionsEncoder; import org.graalvm.word.Pointer; import org.graalvm.word.PointerBase; import org.graalvm.word.WordFactory; @@ -69,6 +53,22 @@ import com.oracle.svm.core.heap.Heap; import com.sun.management.ThreadMXBean; +import jdk.graal.compiler.core.common.spi.ForeignCallSignature; +import jdk.graal.compiler.core.target.Backend; +import jdk.graal.compiler.debug.GlobalMetrics; +import jdk.graal.compiler.hotspot.CompilationContext; +import jdk.graal.compiler.hotspot.CompilationTask; +import jdk.graal.compiler.hotspot.HotSpotForeignCallLinkageImpl.CodeInfo; +import jdk.graal.compiler.hotspot.HotSpotGraalCompiler; +import jdk.graal.compiler.hotspot.HotSpotGraalRuntime; +import jdk.graal.compiler.hotspot.HotSpotGraalServices; +import jdk.graal.compiler.hotspot.ProfileReplaySupport; +import jdk.graal.compiler.hotspot.stubs.Stub; +import jdk.graal.compiler.options.OptionDescriptors; +import jdk.graal.compiler.options.OptionKey; +import jdk.graal.compiler.options.OptionValues; +import jdk.graal.compiler.options.OptionsParser; +import jdk.graal.compiler.util.OptionsEncoder; import jdk.internal.misc.Unsafe; import jdk.vm.ci.code.InstalledCode; import jdk.vm.ci.code.Register; @@ -212,6 +212,17 @@ static class CachedOptions { } } + /** + * Since reference handling is synchronous in libgraal, explicitly perform it here and then run + * any code which is expecting to process a reference queue to let it clean up. + */ + static void doReferenceHandling() { + Heap.getHeap().doReferenceHandling(); + synchronized (Target_jdk_vm_ci_hotspot_Cleaner.class) { + Target_jdk_vm_ci_hotspot_Cleaner.clean(); + } + } + private static final ThreadLocal cachedOptions = new ThreadLocal<>(); private static OptionValues decodeOptions(long address, int size, int hash) { @@ -283,7 +294,7 @@ private static long hashConstantOopFields(JNIEnv jniEnv, if (verbose) { System.out.println("calling reference handling"); } - Heap.getHeap().doReferenceHandling(); + LibGraalEntryPoints.doReferenceHandling(); if (verbose) { System.out.println("called reference handling"); } @@ -406,7 +417,7 @@ private static long compileMethod(JNIEnv jniEnv, * libgraal doesn't use a dedicated reference handler thread, so we trigger the * reference handling manually when a compilation finishes. */ - Heap.getHeap().doReferenceHandling(); + LibGraalEntryPoints.doReferenceHandling(); } } } diff --git a/substratevm/src/com.oracle.svm.graal.hotspot.libgraal/src/com/oracle/svm/graal/hotspot/libgraal/LibGraalFeature.java b/substratevm/src/com.oracle.svm.graal.hotspot.libgraal/src/com/oracle/svm/graal/hotspot/libgraal/LibGraalFeature.java index dc6dc5842038..d91695508fa2 100644 --- a/substratevm/src/com.oracle.svm.graal.hotspot.libgraal/src/com/oracle/svm/graal/hotspot/libgraal/LibGraalFeature.java +++ b/substratevm/src/com.oracle.svm.graal.hotspot.libgraal/src/com/oracle/svm/graal/hotspot/libgraal/LibGraalFeature.java @@ -83,6 +83,7 @@ import com.oracle.svm.core.feature.InternalFeature; import com.oracle.svm.core.graal.meta.RuntimeConfiguration; import com.oracle.svm.core.graal.snippets.NodeLoweringProvider; +import com.oracle.svm.core.heap.GCCause; import com.oracle.svm.core.heap.Heap; import com.oracle.svm.core.log.FunctionPointerLogHandler; import com.oracle.svm.core.option.HostedOptionKey; @@ -691,7 +692,7 @@ private static CompilationRequestResult compileMethod(HotSpotGraalCompiler compi * libgraal doesn't use a dedicated reference handler thread, so we trigger the * reference handling manually when a compilation finishes. */ - Heap.getHeap().doReferenceHandling(); + LibGraalEntryPoints.doReferenceHandling(); } } } @@ -736,8 +737,13 @@ private static void shutdownLibGraal(HotSpotGraalRuntime runtime) { final class Target_jdk_graal_compiler_serviceprovider_GraalServices { @Substitute - private static void notifyLowMemoryPoint(boolean fullGC) { - Heap.getHeap().getGC().collectionHint(fullGC); + private static void notifyLowMemoryPoint(boolean hintFullGC, boolean forceFullGC) { + if (forceFullGC) { + Heap.getHeap().getGC().collectCompletely(GCCause.JavaLangSystemGC); + } else { + Heap.getHeap().getGC().collectionHint(hintFullGC); + } + LibGraalEntryPoints.doReferenceHandling(); } } diff --git a/substratevm/src/com.oracle.svm.graal.hotspot.libgraal/src/com/oracle/svm/graal/hotspot/libgraal/LibGraalSubstitutions.java b/substratevm/src/com.oracle.svm.graal.hotspot.libgraal/src/com/oracle/svm/graal/hotspot/libgraal/LibGraalSubstitutions.java index 371c02f56871..38a5989e4dcb 100644 --- a/substratevm/src/com.oracle.svm.graal.hotspot.libgraal/src/com/oracle/svm/graal/hotspot/libgraal/LibGraalSubstitutions.java +++ b/substratevm/src/com.oracle.svm.graal.hotspot.libgraal/src/com/oracle/svm/graal/hotspot/libgraal/LibGraalSubstitutions.java @@ -30,6 +30,7 @@ import com.oracle.svm.core.annotate.Alias; import com.oracle.svm.core.annotate.RecomputeFieldValue; import com.oracle.svm.core.annotate.TargetClass; +import com.oracle.svm.core.heap.Heap; import jdk.vm.ci.services.Services; @@ -61,6 +62,9 @@ final class Target_jdk_vm_ci_hotspot_Cleaner { @Alias // @RecomputeFieldValue(kind = RecomputeFieldValue.Kind.NewInstance, isFinal = true, declClass = ReferenceQueue.class)// private static ReferenceQueue queue; + + @Alias + static native void clean(); } @TargetClass(className = "jdk.vm.ci.hotspot.HotSpotJDKReflection", onlyWith = LibGraalFeature.IsEnabled.class) From d799c644fbdfdec950443660dffb3c412282273a Mon Sep 17 00:00:00 2001 From: Tom Rodriguez Date: Sun, 3 Dec 2023 10:06:06 -0800 Subject: [PATCH 055/593] Avoid use of addConst in AssertionSnippets --- .../compiler/hotspot/replacements/AssertionSnippets.java | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/replacements/AssertionSnippets.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/replacements/AssertionSnippets.java index fe197e0993c4..f893f0cc4709 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/replacements/AssertionSnippets.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/replacements/AssertionSnippets.java @@ -30,7 +30,6 @@ import static jdk.graal.compiler.replacements.SnippetTemplate.DEFAULT_REPLACER; import jdk.graal.compiler.api.replacements.Snippet; -import jdk.graal.compiler.api.replacements.Snippet.ConstantParameter; import jdk.graal.compiler.core.common.spi.ForeignCallDescriptor; import jdk.graal.compiler.core.common.type.StampFactory; import jdk.graal.compiler.graph.Node.ConstantNodeParameter; @@ -54,14 +53,14 @@ public class AssertionSnippets implements Snippets { @Snippet - public static void assertion(boolean condition, @ConstantParameter Word message, long l1, long l2) { + public static void assertion(boolean condition, Word message, long l1, long l2) { if (injectBranchProbability(SLOWPATH_PROBABILITY, !condition)) { vmMessageC(VM_MESSAGE_C, true, message, l1, l2, 0L); } } @Snippet - public static void stubAssertion(boolean condition, @ConstantParameter Word message, long l1, long l2) { + public static void stubAssertion(boolean condition, Word message, long l1, long l2) { if (injectBranchProbability(SLOWPATH_PROBABILITY, !condition)) { vmMessageStub(VM_MESSAGE_C, true, message, l1, l2, 0L); } @@ -90,7 +89,7 @@ public void lower(AssertionNode assertionNode, LoweringTool tool) { StructuredGraph graph = assertionNode.graph(); Arguments args = new Arguments(graph.start() instanceof StubStartNode ? stubAssertion : assertion, graph.getGuardsStage(), tool.getLoweringStage()); args.add("condition", assertionNode.condition()); - args.addConst("message", + args.add("message", graph.unique(new ConstantNode(new CStringConstant("failed runtime assertion in snippet/stub: " + assertionNode.message() + " (" + graph.method() + ")"), StampFactory.pointer()))); args.add("l1", assertionNode.getL1()); From 486751fc41091119da75763ff4ebb196bfcc0b18 Mon Sep 17 00:00:00 2001 From: Christian Wimmer Date: Sun, 3 Dec 2023 13:16:08 -0800 Subject: [PATCH 056/593] Always parse graphs with unresolvedIsError set to false --- .../graal/pointsto/api/PointstoOptions.java | 7 ++++--- .../pointsto/flow/AnalysisParsedGraph.java | 20 +++++++++---------- .../ParseOnceRuntimeCompilationFeature.java | 5 +++-- .../src/com/oracle/svm/hosted/SVMHost.java | 6 +++--- 4 files changed, 19 insertions(+), 19 deletions(-) diff --git a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/api/PointstoOptions.java b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/api/PointstoOptions.java index de975a2ca381..6dd882ba6cd9 100644 --- a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/api/PointstoOptions.java +++ b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/api/PointstoOptions.java @@ -24,10 +24,11 @@ */ package com.oracle.graal.pointsto.api; -import static jdk.vm.ci.common.JVMCIError.shouldNotReachHere; import static jdk.graal.compiler.options.OptionType.Expert; +import static jdk.vm.ci.common.JVMCIError.shouldNotReachHere; import org.graalvm.collections.EconomicMap; + import jdk.graal.compiler.options.Option; import jdk.graal.compiler.options.OptionKey; @@ -131,8 +132,8 @@ protected void onValueUpdate(EconomicMap, Object> values, Boolean o @Option(help = "Allow a type flow state to contain types not compatible with its declared type.")// public static final OptionKey RelaxTypeFlowStateConstraints = new OptionKey<>(true); - @Option(help = "Report unresolved elements as errors.")// - public static final OptionKey UnresolvedIsError = new OptionKey<>(true); + @Option(help = "Deprecated, option no longer has any effect.", deprecated = true)// + static final OptionKey UnresolvedIsError = new OptionKey<>(true); @Option(help = "Report analysis statistics.")// public static final OptionKey PrintPointsToStatistics = new OptionKey<>(false); diff --git a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/flow/AnalysisParsedGraph.java b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/flow/AnalysisParsedGraph.java index 63ad0b9861f2..8361c75c5fbb 100644 --- a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/flow/AnalysisParsedGraph.java +++ b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/flow/AnalysisParsedGraph.java @@ -24,6 +24,14 @@ */ package com.oracle.graal.pointsto.flow; +import com.oracle.graal.pointsto.BigBang; +import com.oracle.graal.pointsto.api.HostVM; +import com.oracle.graal.pointsto.infrastructure.GraphProvider.Purpose; +import com.oracle.graal.pointsto.meta.AnalysisMethod; +import com.oracle.graal.pointsto.phases.SubstrateIntrinsicGraphBuilder; +import com.oracle.graal.pointsto.util.AnalysisError; +import com.oracle.svm.util.ClassUtil; + import jdk.graal.compiler.api.runtime.GraalJVMCICompiler; import jdk.graal.compiler.bytecode.Bytecode; import jdk.graal.compiler.bytecode.ResolvedJavaMethodBytecode; @@ -42,16 +50,6 @@ import jdk.graal.compiler.phases.OptimisticOptimizations; import jdk.graal.compiler.printer.GraalDebugHandlersFactory; import jdk.graal.compiler.runtime.RuntimeProvider; - -import com.oracle.graal.pointsto.BigBang; -import com.oracle.graal.pointsto.api.HostVM; -import com.oracle.graal.pointsto.api.PointstoOptions; -import com.oracle.graal.pointsto.infrastructure.GraphProvider.Purpose; -import com.oracle.graal.pointsto.meta.AnalysisMethod; -import com.oracle.graal.pointsto.phases.SubstrateIntrinsicGraphBuilder; -import com.oracle.graal.pointsto.util.AnalysisError; -import com.oracle.svm.util.ClassUtil; - import jdk.vm.ci.code.Architecture; import jdk.vm.ci.runtime.JVMCI; @@ -136,7 +134,7 @@ public static AnalysisParsedGraph parseBytecode(BigBang bb, AnalysisMethod metho GraphBuilderConfiguration config = GraphBuilderConfiguration.getDefault(bb.getProviders(method).getGraphBuilderPlugins()) .withEagerResolving(true) - .withUnresolvedIsError(PointstoOptions.UnresolvedIsError.getValue(bb.getOptions())) + .withUnresolvedIsError(false) .withNodeSourcePosition(true) .withBytecodeExceptionMode(BytecodeExceptionMode.CheckAll) .withRetainLocalVariables(true); diff --git a/substratevm/src/com.oracle.svm.graal/src/com/oracle/svm/graal/hosted/ParseOnceRuntimeCompilationFeature.java b/substratevm/src/com.oracle.svm.graal/src/com/oracle/svm/graal/hosted/ParseOnceRuntimeCompilationFeature.java index b770604d5646..b320671142bf 100644 --- a/substratevm/src/com.oracle.svm.graal/src/com/oracle/svm/graal/hosted/ParseOnceRuntimeCompilationFeature.java +++ b/substratevm/src/com.oracle.svm.graal/src/com/oracle/svm/graal/hosted/ParseOnceRuntimeCompilationFeature.java @@ -53,7 +53,6 @@ import com.oracle.graal.pointsto.BigBang; import com.oracle.graal.pointsto.PointsToAnalysis; import com.oracle.graal.pointsto.api.HostVM; -import com.oracle.graal.pointsto.api.PointstoOptions; import com.oracle.graal.pointsto.flow.InvokeTypeFlow; import com.oracle.graal.pointsto.flow.MethodFlowsGraph; import com.oracle.graal.pointsto.heap.ImageHeapScanner; @@ -282,7 +281,9 @@ static RuntimeGraphBuilderPhase createRuntimeGraphBuilderPhase(BigBang bb, Provi GraphBuilderConfiguration graphBuilderConfig, OptimisticOptimizations optimisticOpts) { // Adjust graphbuilderconfig to match analysis phase - var newGraphBuilderConfig = graphBuilderConfig.withEagerResolving(true).withUnresolvedIsError(PointstoOptions.UnresolvedIsError.getValue(bb.getOptions())); + var newGraphBuilderConfig = graphBuilderConfig + .withEagerResolving(true) + .withUnresolvedIsError(false); return new RuntimeGraphBuilderPhase(providers, newGraphBuilderConfig, optimisticOpts, null, providers.getWordTypes(), (SVMHost) bb.getHostVM()); } diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/SVMHost.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/SVMHost.java index aeb92da13938..cd16721bc691 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/SVMHost.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/SVMHost.java @@ -328,9 +328,9 @@ public boolean isInitialized(AnalysisType type) { @Override public GraphBuilderConfiguration updateGraphBuilderConfiguration(GraphBuilderConfiguration config, AnalysisMethod method) { - GraphBuilderConfiguration updatedConfig = config.withRetainLocalVariables(retainLocalVariables()).withUnresolvedIsError(linkAtBuildTimeSupport.linkAtBuildTime(method.getDeclaringClass())) - .withFullInfopoints( - SubstrateOptions.getSourceLevelDebug() && SubstrateOptions.getSourceLevelDebugFilter().test(method.getDeclaringClass().toJavaName())); + GraphBuilderConfiguration updatedConfig = config + .withRetainLocalVariables(retainLocalVariables()) + .withFullInfopoints(SubstrateOptions.getSourceLevelDebug() && SubstrateOptions.getSourceLevelDebugFilter().test(method.getDeclaringClass().toJavaName())); if (parsingSupport != null) { return parsingSupport.updateGraphBuilderConfiguration(updatedConfig, method); } From a63e5b16342a11e47ca9863bb835778507e4ef29 Mon Sep 17 00:00:00 2001 From: Florian Huemer Date: Mon, 4 Dec 2023 09:27:30 +0100 Subject: [PATCH 057/593] Added missing @TruffleBoundary annotation. --- .../wasm/predefined/wasi/WasiFdFilestatSetTimesNode.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/predefined/wasi/WasiFdFilestatSetTimesNode.java b/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/predefined/wasi/WasiFdFilestatSetTimesNode.java index e47bf4219493..821bd89ce45d 100644 --- a/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/predefined/wasi/WasiFdFilestatSetTimesNode.java +++ b/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/predefined/wasi/WasiFdFilestatSetTimesNode.java @@ -40,6 +40,7 @@ */ package org.graalvm.wasm.predefined.wasi; +import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary; import com.oracle.truffle.api.frame.VirtualFrame; import org.graalvm.wasm.WasmArguments; import org.graalvm.wasm.WasmContext; @@ -65,6 +66,7 @@ public Object executeWithContext(VirtualFrame frame, WasmContext context, WasmIn (int) WasmArguments.getArgument(args, 3)); } + @TruffleBoundary private int fdstatSetTime(WasmContext context, int fd, long atim, long mtim, int fstFlags) { final Fd handle = context.fdManager().get(fd); if (handle == null) { From 67af24ee755b0dda489f0b17c6ec3d05a2dc114c Mon Sep 17 00:00:00 2001 From: Bernhard Urban-Forster Date: Mon, 4 Dec 2023 10:04:53 +0100 Subject: [PATCH 058/593] Revert "[GR-48722] Ask linker to create separate code program header on linux-aarch64" --- .../oracle/svm/hosted/image/CCLinkerInvocation.java | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/CCLinkerInvocation.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/CCLinkerInvocation.java index ef324721beeb..4972c17a268b 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/CCLinkerInvocation.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/CCLinkerInvocation.java @@ -264,17 +264,6 @@ private static class BinutilsCCLinkerInvocation extends CCLinkerInvocation { additionalPreOptions.add("-z"); additionalPreOptions.add("notext"); - if (Platform.includedIn(Platform.LINUX_AARCH64_BASE.class)) { - // [GR-48722] Default on linux-amd64, but not on other arches (e.g. aarch64). See - // https://sourceware.org/git/?p=binutils-gdb.git;a=commit;h=f6aec96dce1ddbd8961a3aa8a2925db2021719bb - - // TODO: cannot be enabled on other linux platforms due to - // [GR-50093]: old devkit that does not support separate-code - // [GR-50094]: musl-toolchain breaks with this flag set - additionalPreOptions.add("-z"); - additionalPreOptions.add("separate-code"); - } - if (SubstrateOptions.ForceNoROSectionRelocations.getValue()) { additionalPreOptions.add("-fuse-ld=gold"); additionalPreOptions.add("-Wl,--rosegment"); From 6f46f40d3ee9a7fec9237a05faf452977dbb7d3b Mon Sep 17 00:00:00 2001 From: David Leopoldseder Date: Wed, 22 Nov 2023 12:44:21 +0100 Subject: [PATCH 059/593] unary math intrinsic lowering: expose proper stamp for foreign call --- .../amd64/AMD64HotSpotLoweringProvider.java | 12 ++++++++++- .../amd64/AMD64X87MathIntrinsicNode.java | 6 +++--- .../nodes/UnaryMathIntrinsicNode.java | 21 ++++++++++--------- 3 files changed, 25 insertions(+), 14 deletions(-) diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/amd64/AMD64HotSpotLoweringProvider.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/amd64/AMD64HotSpotLoweringProvider.java index ab531453149e..28efdc9144b2 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/amd64/AMD64HotSpotLoweringProvider.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/amd64/AMD64HotSpotLoweringProvider.java @@ -24,9 +24,13 @@ */ package jdk.graal.compiler.hotspot.amd64; +import java.util.List; + import jdk.graal.compiler.core.amd64.AMD64LoweringProviderMixin; +import jdk.graal.compiler.core.common.spi.ForeignCallDescriptor; import jdk.graal.compiler.core.common.spi.ForeignCallsProvider; import jdk.graal.compiler.core.common.spi.MetaAccessExtensionProvider; +import jdk.graal.compiler.core.common.type.Stamp; import jdk.graal.compiler.debug.DebugHandlersFactory; import jdk.graal.compiler.graph.Node; import jdk.graal.compiler.hotspot.GraalHotSpotVMConfig; @@ -37,6 +41,7 @@ import jdk.graal.compiler.hotspot.meta.HotSpotRegistersProvider; import jdk.graal.compiler.hotspot.replacements.HotSpotAllocationSnippets; import jdk.graal.compiler.hotspot.replacements.arraycopy.HotSpotArraycopySnippets; +import jdk.graal.compiler.nodes.NodeView; import jdk.graal.compiler.nodes.StructuredGraph; import jdk.graal.compiler.nodes.calc.FloatConvertNode; import jdk.graal.compiler.nodes.extended.ForeignCallNode; @@ -118,7 +123,12 @@ private void lowerUnaryMath(UnaryMathIntrinsicNode math, LoweringTool tool) { } } - ForeignCallNode call = graph.add(new ForeignCallNode(foreignCalls, math.getOperation().foreignCallSignature, math.getValue())); +// ForeignCallNode call = graph.add( +// new ForeignCallNode(foreignCalls, math.getOperation().foreignCallSignature, math.getValue())); + + ForeignCallDescriptor desc = foreignCalls.getDescriptor(math.getOperation().foreignCallSignature); + Stamp s = UnaryMathIntrinsicNode.UnaryOperation.computeStamp(math.getOperation(), math.getValue().stamp(NodeView.DEFAULT)); + ForeignCallNode call = graph.add(new ForeignCallNode(desc, s, List.of(math.getValue()))); graph.addAfterFixed(tool.lastFixedNode(), call); math.replaceAtUsages(call); } diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/amd64/AMD64X87MathIntrinsicNode.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/amd64/AMD64X87MathIntrinsicNode.java index fa9511180eb3..d3cbcb5084c9 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/amd64/AMD64X87MathIntrinsicNode.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/amd64/AMD64X87MathIntrinsicNode.java @@ -56,14 +56,14 @@ public final class AMD64X87MathIntrinsicNode extends UnaryNode implements LIRLow protected final UnaryOperation operation; protected AMD64X87MathIntrinsicNode(ValueNode value, UnaryOperation op) { - super(TYPE, op.computeStamp(value.stamp(NodeView.DEFAULT)), value); + super(TYPE, UnaryOperation.computeStamp(op, value.stamp(NodeView.DEFAULT)), value); assert value.stamp(NodeView.DEFAULT) instanceof FloatStamp && PrimitiveStamp.getBits(value.stamp(NodeView.DEFAULT)) == 64 : Assertions.errorMessage(value); this.operation = op; } @Override public Stamp foldStamp(Stamp valueStamp) { - return operation.computeStamp(valueStamp); + return UnaryOperation.computeStamp(operation, valueStamp); } @Override @@ -90,7 +90,7 @@ public void generate(NodeLIRBuilderTool generator) { @Override public ValueNode canonical(CanonicalizerTool tool, ValueNode forValue) { if (forValue.isConstant()) { - return ConstantNode.forDouble(operation.compute(forValue.asJavaConstant().asDouble())); + return ConstantNode.forDouble(UnaryOperation.compute(operation, forValue.asJavaConstant().asDouble())); } return this; } diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/replacements/nodes/UnaryMathIntrinsicNode.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/replacements/nodes/UnaryMathIntrinsicNode.java index 6c913d02b955..ae6f4d4e7fb9 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/replacements/nodes/UnaryMathIntrinsicNode.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/replacements/nodes/UnaryMathIntrinsicNode.java @@ -68,8 +68,8 @@ public enum UnaryOperation { this.foreignCallSignature = foreignCallSignature; } - public double compute(double value) { - switch (this) { + public static double compute(UnaryOperation op, double value) { + switch (op) { case LOG: return Math.log(value); case LOG10: @@ -83,14 +83,14 @@ public double compute(double value) { case TAN: return Math.tan(value); default: - throw new GraalError("unknown op %s", this); + throw new GraalError("unknown op %s", op); } } - public Stamp computeStamp(Stamp valueStamp) { + public static Stamp computeStamp(UnaryOperation op, Stamp valueStamp) { if (valueStamp instanceof FloatStamp) { FloatStamp floatStamp = (FloatStamp) valueStamp; - switch (this) { + switch (op) { case COS: case SIN: { boolean nonNaN = floatStamp.lowerBound() != Double.NEGATIVE_INFINITY && floatStamp.upperBound() != Double.POSITIVE_INFINITY && floatStamp.isNonNaN(); @@ -102,8 +102,8 @@ public Stamp computeStamp(Stamp valueStamp) { } case LOG: case LOG10: { - double lowerBound = compute(floatStamp.lowerBound()); - double upperBound = compute(floatStamp.upperBound()); + double lowerBound = compute(op, floatStamp.lowerBound()); + double upperBound = compute(op, floatStamp.upperBound()); if (floatStamp.contains(0.0)) { // 0.0 and -0.0 infinity produces -Inf lowerBound = Double.NEGATIVE_INFINITY; @@ -139,13 +139,13 @@ public static ValueNode create(ValueNode value, UnaryOperation op) { protected static ValueNode tryConstantFold(ValueNode value, UnaryOperation op) { if (value.isConstant()) { - return ConstantNode.forDouble(op.compute(value.asJavaConstant().asDouble())); + return ConstantNode.forDouble(UnaryOperation.compute(op, value.asJavaConstant().asDouble())); } return null; } protected UnaryMathIntrinsicNode(ValueNode value, UnaryOperation op) { - super(TYPE, op.computeStamp(value.stamp(NodeView.DEFAULT)), value); + super(TYPE, UnaryOperation.computeStamp(op, value.stamp(NodeView.DEFAULT)), value); assert value.stamp(NodeView.DEFAULT) instanceof FloatStamp : Assertions.errorMessageContext("value", value); assert PrimitiveStamp.getBits(value.stamp(NodeView.DEFAULT)) == 64 : value; this.operation = op; @@ -153,7 +153,8 @@ protected UnaryMathIntrinsicNode(ValueNode value, UnaryOperation op) { @Override public Stamp foldStamp(Stamp valueStamp) { - return getOperation().computeStamp(valueStamp); + getOperation(); + return UnaryOperation.computeStamp(this.operation, valueStamp); } @Override From 1c8dd4ab1c537d6d34fc6a75613e94a9194fe5cf Mon Sep 17 00:00:00 2001 From: David Leopoldseder Date: Fri, 24 Nov 2023 14:56:02 +0100 Subject: [PATCH 060/593] amd64 float convert: expose snippets in a way that non unrestricted potentially nan stamps can still fold properly for the non nan case --- .../amd64/AMD64HotSpotLoweringProvider.java | 3 - .../src/jdk/graal/compiler/nodes/PiNode.java | 29 +++++++- .../amd64/AMD64ConvertSnippets.java | 69 +++++++++++-------- .../amd64/AMD64FloatConvertNode.java | 15 ++++ 4 files changed, 82 insertions(+), 34 deletions(-) diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/amd64/AMD64HotSpotLoweringProvider.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/amd64/AMD64HotSpotLoweringProvider.java index 28efdc9144b2..ac57523f0bdf 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/amd64/AMD64HotSpotLoweringProvider.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/amd64/AMD64HotSpotLoweringProvider.java @@ -123,9 +123,6 @@ private void lowerUnaryMath(UnaryMathIntrinsicNode math, LoweringTool tool) { } } -// ForeignCallNode call = graph.add( -// new ForeignCallNode(foreignCalls, math.getOperation().foreignCallSignature, math.getValue())); - ForeignCallDescriptor desc = foreignCalls.getDescriptor(math.getOperation().foreignCallSignature); Stamp s = UnaryMathIntrinsicNode.UnaryOperation.computeStamp(math.getOperation(), math.getValue().stamp(NodeView.DEFAULT)); ForeignCallNode call = graph.add(new ForeignCallNode(desc, s, List.of(math.getValue()))); diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/nodes/PiNode.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/nodes/PiNode.java index 09fa5734a898..767fa85689d8 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/nodes/PiNode.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/nodes/PiNode.java @@ -28,6 +28,7 @@ import static jdk.graal.compiler.nodeinfo.NodeSize.SIZE_0; import jdk.graal.compiler.core.common.type.AbstractPointerStamp; +import jdk.graal.compiler.core.common.type.FloatStamp; import jdk.graal.compiler.core.common.type.ObjectStamp; import jdk.graal.compiler.core.common.type.Stamp; import jdk.graal.compiler.core.common.type.StampFactory; @@ -132,7 +133,9 @@ public enum IntrinsifyOp { NON_NULL, POSITIVE_INT, INT_NON_ZERO, - LONG_NON_ZERO + LONG_NON_ZERO, + DOUBLE_NON_NAN, + FLOAT_NON_NAN } public static boolean intrinsify(GraphBuilderContext b, ValueNode input, ValueNode guard, IntrinsifyOp intrinsifyOp) { @@ -155,6 +158,16 @@ public static boolean intrinsify(GraphBuilderContext b, ValueNode input, ValueNo piStamp = StampFactory.nonZeroLong(); pushKind = JavaKind.Long; break; + case FLOAT_NON_NAN: + // non NAN float stamp + piStamp = new FloatStamp(32, Float.NEGATIVE_INFINITY, Float.POSITIVE_INFINITY, true); + pushKind = JavaKind.Float; + break; + case DOUBLE_NON_NAN: + // non NAN double stamp + piStamp = new FloatStamp(64, Double.NEGATIVE_INFINITY, Double.POSITIVE_INFINITY, true); + pushKind = JavaKind.Double; + break; default: throw GraalError.shouldNotReachHereUnexpectedValue(intrinsifyOp); // ExcludeFromJacocoGeneratedReport } @@ -406,6 +419,20 @@ public static Class piCastNonNullClass(Class type, GuardingNode guard) { return intrinsified(type, guard, IntrinsifyOp.NON_NULL); } + public static float piCastNonNanFloat(float input, GuardingNode guard) { + return intrinsified(input, guard, IntrinsifyOp.FLOAT_NON_NAN); + } + + @NodeIntrinsic + private static native float intrinsified(float input, GuardingNode guard, @ConstantNodeParameter IntrinsifyOp intrinsifyOp); + + public static double piCastNonNanDouble(double input, GuardingNode guard) { + return intrinsified(input, guard, IntrinsifyOp.DOUBLE_NON_NAN); + } + + @NodeIntrinsic + private static native double intrinsified(double input, GuardingNode guard, @ConstantNodeParameter IntrinsifyOp intrinsifyOp); + @NodeIntrinsic private static native Class intrinsified(Class object, GuardingNode guard, @ConstantNodeParameter IntrinsifyOp intrinsifyOp); diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/replacements/amd64/AMD64ConvertSnippets.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/replacements/amd64/AMD64ConvertSnippets.java index db1515e91a95..3d8d80443740 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/replacements/amd64/AMD64ConvertSnippets.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/replacements/amd64/AMD64ConvertSnippets.java @@ -29,9 +29,13 @@ import static jdk.graal.compiler.nodes.extended.BranchProbabilityNode.unknownProbability; import jdk.graal.compiler.api.replacements.Snippet; +import jdk.graal.compiler.core.common.calc.FloatConvert; import jdk.graal.compiler.nodes.GraphState.StageFlag; +import jdk.graal.compiler.nodes.PiNode; +import jdk.graal.compiler.nodes.SnippetAnchorNode; import jdk.graal.compiler.nodes.StructuredGraph; import jdk.graal.compiler.nodes.calc.FloatConvertNode; +import jdk.graal.compiler.nodes.extended.GuardingNode; import jdk.graal.compiler.nodes.spi.LoweringTool; import jdk.graal.compiler.options.OptionValues; import jdk.graal.compiler.phases.util.Providers; @@ -53,16 +57,18 @@ public class AMD64ConvertSnippets implements Snippets { * extra tests are required on the float value to return the correct int value. * * @param input the float being converted - * @param result the result produced by the CVTTSS2SI instruction */ @Snippet - public static int f2i(float input, int result) { + public static int f2i(float input) { + if (probability(SLOW_PATH_PROBABILITY, Float.isNaN(input))) { + return 0; + } + GuardingNode guard = SnippetAnchorNode.anchor(); + float nonNanInput = PiNode.piCastNonNanFloat(input, guard); + int result = AMD64FloatConvertNode.convertToInt(FloatConvert.F2I, nonNanInput); if (probability(SLOW_PATH_PROBABILITY, result == Integer.MIN_VALUE)) { - if (probability(SLOW_PATH_PROBABILITY, Float.isNaN(input))) { - // input is NaN -> return 0 - return 0; - } else if (unknownProbability(input > 0.0f)) { - // input is > 0 -> return max int + if (unknownProbability(input > 0.0d)) { + // input is positive -> return maxInt return Integer.MAX_VALUE; } } @@ -78,16 +84,18 @@ public static int f2i(float input, int result) { * long value. * * @param input the float being converted - * @param result the result produced by the CVTTSS2SI instruction */ @Snippet - public static long f2l(float input, long result) { + public static long f2l(float input) { + if (probability(SLOW_PATH_PROBABILITY, Float.isNaN(input))) { + return 0; + } + GuardingNode guard = SnippetAnchorNode.anchor(); + float nonNanInput = PiNode.piCastNonNanFloat(input, guard); + long result = AMD64FloatConvertNode.convertToLong(FloatConvert.F2L, nonNanInput); if (probability(SLOW_PATH_PROBABILITY, result == Long.MIN_VALUE)) { - if (probability(SLOW_PATH_PROBABILITY, Float.isNaN(input))) { - // input is NaN -> return 0 - return 0; - } else if (unknownProbability(input > 0.0f)) { - // input is > 0 -> return max int + if (unknownProbability(input > 0.0d)) { + // input is positive -> return maxInt return Long.MAX_VALUE; } } @@ -103,15 +111,17 @@ public static long f2l(float input, long result) { * extra tests are required on the double value to return the correct int value. * * @param input the double being converted - * @param result the result produced by the CVTTSS2SI instruction */ @Snippet - public static int d2i(double input, int result) { + public static int d2i(double input) { + if (probability(SLOW_PATH_PROBABILITY, Double.isNaN(input))) { + return 0; + } + GuardingNode guard = SnippetAnchorNode.anchor(); + double nonNanInput = PiNode.piCastNonNanDouble(input, guard); + int result = AMD64FloatConvertNode.convertToInt(FloatConvert.D2I, nonNanInput); if (probability(SLOW_PATH_PROBABILITY, result == Integer.MIN_VALUE)) { - if (probability(SLOW_PATH_PROBABILITY, Double.isNaN(input))) { - // input is NaN -> return 0 - return 0; - } else if (unknownProbability(input > 0.0d)) { + if (unknownProbability(input > 0.0d)) { // input is positive -> return maxInt return Integer.MAX_VALUE; } @@ -128,15 +138,17 @@ public static int d2i(double input, int result) { * tests are required on the double value to return the correct long value. * * @param input the double being converted - * @param result the result produced by the CVTTSS2SI instruction */ @Snippet - public static long d2l(double input, long result) { + public static long d2l(double input) { + if (probability(SLOW_PATH_PROBABILITY, Double.isNaN(input))) { + return 0; + } + GuardingNode guard = SnippetAnchorNode.anchor(); + double nonNanInput = PiNode.piCastNonNanDouble(input, guard); + long result = AMD64FloatConvertNode.convertToLong(FloatConvert.D2L, nonNanInput); if (probability(SLOW_PATH_PROBABILITY, result == Long.MIN_VALUE)) { - if (probability(SLOW_PATH_PROBABILITY, Double.isNaN(input))) { - // input is NaN -> return 0 - return 0; - } else if (unknownProbability(input > 0.0d)) { + if (unknownProbability(input > 0.0d)) { // input is positive -> return maxInt return Long.MAX_VALUE; } @@ -167,6 +179,7 @@ public void lower(FloatConvertNode convert, LoweringTool tool) { } SnippetTemplate.SnippetInfo key; + StructuredGraph graph = convert.graph(); switch (convert.getFloatConvert()) { case F2I: key = f2i; @@ -184,12 +197,8 @@ public void lower(FloatConvertNode convert, LoweringTool tool) { return; } - StructuredGraph graph = convert.graph(); - SnippetTemplate.Arguments args = new SnippetTemplate.Arguments(key, graph.getGuardsStage(), tool.getLoweringStage()); args.add("input", convert.getValue()); - args.add("result", graph.unique(new AMD64FloatConvertNode(convert.getFloatConvert(), convert.getValue()))); - SnippetTemplate template = template(tool, convert, args); convert.getDebug().log("Lowering %s in %s: node=%s, template=%s, arguments=%s", convert.getFloatConvert(), graph, convert, template, args); template.instantiate(tool.getMetaAccess(), convert, SnippetTemplate.DEFAULT_REPLACER, tool, args); diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/replacements/amd64/AMD64FloatConvertNode.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/replacements/amd64/AMD64FloatConvertNode.java index 9760333e7d0d..a4cecf4f4652 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/replacements/amd64/AMD64FloatConvertNode.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/replacements/amd64/AMD64FloatConvertNode.java @@ -63,6 +63,9 @@ public final class AMD64FloatConvertNode extends UnaryArithmeticNode implements ArithmeticLIRLowerable { public static final NodeClass TYPE = NodeClass.create(AMD64FloatConvertNode.class); + /** + * Convert operation of this node. + */ protected final FloatConvert op; public AMD64FloatConvertNode(FloatConvert op, ValueNode value) { @@ -164,4 +167,16 @@ private Stamp createInexactCaseStamp() { public void generate(NodeLIRBuilderTool nodeValueMap, ArithmeticLIRGeneratorTool gen) { nodeValueMap.setResult(this, gen.emitFloatConvert(op, nodeValueMap.operand(getValue()))); } + + @NodeIntrinsic + public static native int convertToInt(@ConstantNodeParameter FloatConvert op, float input); + + @NodeIntrinsic + public static native long convertToLong(@ConstantNodeParameter FloatConvert op, float input); + + @NodeIntrinsic + public static native int convertToInt(@ConstantNodeParameter FloatConvert op, double input); + + @NodeIntrinsic + public static native long convertToLong(@ConstantNodeParameter FloatConvert op, double input); } From 1311efe6b89b2a6ed17e6b20738541f37da97251 Mon Sep 17 00:00:00 2001 From: David Leopoldseder Date: Tue, 28 Nov 2023 07:07:06 +0100 Subject: [PATCH 061/593] unary math intrinsic lowering in default lowering provider: expose proper stamp for foreign call --- .../compiler/replacements/DefaultJavaLoweringProvider.java | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/replacements/DefaultJavaLoweringProvider.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/replacements/DefaultJavaLoweringProvider.java index c82df8ab3202..7c4b74f27c45 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/replacements/DefaultJavaLoweringProvider.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/replacements/DefaultJavaLoweringProvider.java @@ -43,6 +43,7 @@ import jdk.graal.compiler.core.common.memory.BarrierType; import jdk.graal.compiler.core.common.memory.MemoryOrderMode; +import jdk.graal.compiler.core.common.spi.ForeignCallDescriptor; import jdk.graal.compiler.core.common.spi.ForeignCallsProvider; import jdk.graal.compiler.core.common.spi.MetaAccessExtensionProvider; import jdk.graal.compiler.core.common.type.AbstractPointerStamp; @@ -427,7 +428,9 @@ private void lowerUnaryMath(UnaryMathIntrinsicNode math, LoweringTool tool) { } } StructuredGraph graph = math.graph(); - ForeignCallNode call = math.graph().add(new ForeignCallNode(foreignCalls.getDescriptor(math.getOperation().foreignCallSignature), math.getValue())); + ForeignCallDescriptor desc = foreignCalls.getDescriptor(math.getOperation().foreignCallSignature); + Stamp s = UnaryMathIntrinsicNode.UnaryOperation.computeStamp(math.getOperation(), math.getValue().stamp(NodeView.DEFAULT)); + ForeignCallNode call = graph.add(new ForeignCallNode(desc, s, List.of(math.getValue()))); graph.addAfterFixed(tool.lastFixedNode(), call); math.replaceAtUsages(call); } From bc9ae5aa22e75bbf23dd9153704e4515a6ac76e4 Mon Sep 17 00:00:00 2001 From: David Leopoldseder Date: Mon, 4 Dec 2023 11:29:24 +0100 Subject: [PATCH 062/593] math intrinsic lowering: cleanups --- .../amd64/AMD64HotSpotLoweringProvider.java | 14 +------------- .../replacements/DefaultJavaLoweringProvider.java | 4 ++++ .../replacements/nodes/UnaryMathIntrinsicNode.java | 1 - 3 files changed, 5 insertions(+), 14 deletions(-) diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/amd64/AMD64HotSpotLoweringProvider.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/amd64/AMD64HotSpotLoweringProvider.java index ac57523f0bdf..510dd5b7a0d4 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/amd64/AMD64HotSpotLoweringProvider.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/amd64/AMD64HotSpotLoweringProvider.java @@ -24,13 +24,9 @@ */ package jdk.graal.compiler.hotspot.amd64; -import java.util.List; - import jdk.graal.compiler.core.amd64.AMD64LoweringProviderMixin; -import jdk.graal.compiler.core.common.spi.ForeignCallDescriptor; import jdk.graal.compiler.core.common.spi.ForeignCallsProvider; import jdk.graal.compiler.core.common.spi.MetaAccessExtensionProvider; -import jdk.graal.compiler.core.common.type.Stamp; import jdk.graal.compiler.debug.DebugHandlersFactory; import jdk.graal.compiler.graph.Node; import jdk.graal.compiler.hotspot.GraalHotSpotVMConfig; @@ -41,17 +37,14 @@ import jdk.graal.compiler.hotspot.meta.HotSpotRegistersProvider; import jdk.graal.compiler.hotspot.replacements.HotSpotAllocationSnippets; import jdk.graal.compiler.hotspot.replacements.arraycopy.HotSpotArraycopySnippets; -import jdk.graal.compiler.nodes.NodeView; import jdk.graal.compiler.nodes.StructuredGraph; import jdk.graal.compiler.nodes.calc.FloatConvertNode; -import jdk.graal.compiler.nodes.extended.ForeignCallNode; import jdk.graal.compiler.nodes.spi.LoweringTool; import jdk.graal.compiler.nodes.spi.PlatformConfigurationProvider; import jdk.graal.compiler.options.OptionValues; import jdk.graal.compiler.replacements.amd64.AMD64ConvertSnippets; import jdk.graal.compiler.replacements.nodes.UnaryMathIntrinsicNode; import jdk.graal.compiler.replacements.nodes.UnaryMathIntrinsicNode.UnaryOperation; - import jdk.vm.ci.amd64.AMD64; import jdk.vm.ci.code.TargetDescription; import jdk.vm.ci.hotspot.HotSpotConstantReflectionProvider; @@ -122,12 +115,7 @@ private void lowerUnaryMath(UnaryMathIntrinsicNode math, LoweringTool tool) { return; } } - - ForeignCallDescriptor desc = foreignCalls.getDescriptor(math.getOperation().foreignCallSignature); - Stamp s = UnaryMathIntrinsicNode.UnaryOperation.computeStamp(math.getOperation(), math.getValue().stamp(NodeView.DEFAULT)); - ForeignCallNode call = graph.add(new ForeignCallNode(desc, s, List.of(math.getValue()))); - graph.addAfterFixed(tool.lastFixedNode(), call); - math.replaceAtUsages(call); + lowerUnaryMathToForeignCall(math, tool); } @Override diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/replacements/DefaultJavaLoweringProvider.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/replacements/DefaultJavaLoweringProvider.java index 7c4b74f27c45..62f87e0d1639 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/replacements/DefaultJavaLoweringProvider.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/replacements/DefaultJavaLoweringProvider.java @@ -427,6 +427,10 @@ private void lowerUnaryMath(UnaryMathIntrinsicNode math, LoweringTool tool) { return; } } + lowerUnaryMathToForeignCall(math, tool); + } + + protected void lowerUnaryMathToForeignCall(UnaryMathIntrinsicNode math, LoweringTool tool) { StructuredGraph graph = math.graph(); ForeignCallDescriptor desc = foreignCalls.getDescriptor(math.getOperation().foreignCallSignature); Stamp s = UnaryMathIntrinsicNode.UnaryOperation.computeStamp(math.getOperation(), math.getValue().stamp(NodeView.DEFAULT)); diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/replacements/nodes/UnaryMathIntrinsicNode.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/replacements/nodes/UnaryMathIntrinsicNode.java index ae6f4d4e7fb9..8d094aad20b6 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/replacements/nodes/UnaryMathIntrinsicNode.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/replacements/nodes/UnaryMathIntrinsicNode.java @@ -153,7 +153,6 @@ protected UnaryMathIntrinsicNode(ValueNode value, UnaryOperation op) { @Override public Stamp foldStamp(Stamp valueStamp) { - getOperation(); return UnaryOperation.computeStamp(this.operation, valueStamp); } From af68df34e8f61220e8aba171f8486a65d385f69a Mon Sep 17 00:00:00 2001 From: Christian Haeubl Date: Mon, 4 Dec 2023 11:46:36 +0100 Subject: [PATCH 063/593] Fix missing headers in libchelper. --- .../src/com.oracle.svm.native.libchelper/src/getThreadId.c | 1 + .../src/com.oracle.svm.native.libchelper/src/getThreadUserTime.c | 1 + 2 files changed, 2 insertions(+) diff --git a/substratevm/src/com.oracle.svm.native.libchelper/src/getThreadId.c b/substratevm/src/com.oracle.svm.native.libchelper/src/getThreadId.c index 4e60f087cf81..48421bb1ff2a 100644 --- a/substratevm/src/com.oracle.svm.native.libchelper/src/getThreadId.c +++ b/substratevm/src/com.oracle.svm.native.libchelper/src/getThreadId.c @@ -28,6 +28,7 @@ #include #include +#include /* * Based on os::Linux::gettid() from jdk-20-ga, see diff --git a/substratevm/src/com.oracle.svm.native.libchelper/src/getThreadUserTime.c b/substratevm/src/com.oracle.svm.native.libchelper/src/getThreadUserTime.c index e33580a689ab..17836710b5bc 100644 --- a/substratevm/src/com.oracle.svm.native.libchelper/src/getThreadUserTime.c +++ b/substratevm/src/com.oracle.svm.native.libchelper/src/getThreadUserTime.c @@ -26,6 +26,7 @@ #ifdef __linux__ +#include #include #include #include From 063c6ac855771526db8901c31b2e326b887f9e2e Mon Sep 17 00:00:00 2001 From: Carlo Refice Date: Fri, 1 Dec 2023 12:33:36 +0100 Subject: [PATCH 064/593] Add failing testcase for Deopt floating causing OSRMonitorEnter removal --- .../hotspot/test/GraalOSRLockTest.java | 47 +++++++++++++++++-- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/hotspot/test/GraalOSRLockTest.java b/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/hotspot/test/GraalOSRLockTest.java index b266357873bc..966b4b5c637e 100644 --- a/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/hotspot/test/GraalOSRLockTest.java +++ b/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/hotspot/test/GraalOSRLockTest.java @@ -34,6 +34,11 @@ import java.util.List; import org.graalvm.collections.EconomicMap; +import org.junit.Assert; +import org.junit.Assume; +import org.junit.BeforeClass; +import org.junit.Test; + import jdk.graal.compiler.api.directives.GraalDirectives; import jdk.graal.compiler.core.phases.HighTier; import jdk.graal.compiler.debug.DebugContext; @@ -43,11 +48,8 @@ import jdk.graal.compiler.options.OptionKey; import jdk.graal.compiler.options.OptionValues; import jdk.graal.compiler.serviceprovider.GraalServices; -import org.junit.Assert; -import org.junit.Assume; -import org.junit.BeforeClass; -import org.junit.Test; - +import jdk.vm.ci.meta.DeoptimizationAction; +import jdk.vm.ci.meta.DeoptimizationReason; import jdk.vm.ci.meta.ResolvedJavaMethod; /** @@ -319,6 +321,15 @@ public void testLockOSROuterInnerSameLockCompileRestOfMethod() { }); } + @Test + @SuppressWarnings("try") + public void testOuterLockDeoptDoesNotFloatAboveMonitor() { + run(() -> { + OptionValues options = new OptionValues(getInitialOptions(), osrLockNoDeopt()); + testOSR(options, "testOuterLockOptimizeToDeopt"); + }); + } + @Test @SuppressWarnings("try") public void testLockOSRRecursive() { @@ -692,4 +703,30 @@ public static ReturnValue testOuterInnerSameLockCompileRestOfMethod() { } } + public static ReturnValue testOuterLockOptimizeToDeopt() { + ReturnValue ret = ReturnValue.FAILURE; + synchronized (lock) { + Object o = null; + for (int i = 1; i < limit; i++) { + GraalDirectives.blackhole(i); + /* + * Will fold away in canonicalization. After ConvertDeoptimizeToGuard, the deopt + * should float all the way to the start of the OSR graph. + */ + if (o == null) { + ret = ReturnValue.SUCCESS; + if (GraalDirectives.inCompiledCode()) { + GraalDirectives.deoptimize(DeoptimizationAction.InvalidateReprofile, DeoptimizationReason.UnreachedCode, true); + } else { + o = ""; + } + } + } + GraalDirectives.controlFlowAnchor(); + if (GraalDirectives.inCompiledCode()) { + GraalDirectives.deoptimize(DeoptimizationAction.InvalidateReprofile, DeoptimizationReason.UnreachedCode, true); + } + } + return ret; + } } From ef14e41e2b8ab21284a76e176896f638c60fb81b Mon Sep 17 00:00:00 2001 From: Carlo Refice Date: Mon, 4 Dec 2023 11:59:55 +0100 Subject: [PATCH 065/593] Fix Deopt floating causing OSRMonitorEnter removal --- .../loop/phases/ConvertDeoptimizeToGuardPhase.java | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/loop/phases/ConvertDeoptimizeToGuardPhase.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/loop/phases/ConvertDeoptimizeToGuardPhase.java index 29c831662730..b1e81f4a4fc2 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/loop/phases/ConvertDeoptimizeToGuardPhase.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/loop/phases/ConvertDeoptimizeToGuardPhase.java @@ -64,6 +64,7 @@ import jdk.graal.compiler.nodes.calc.IntegerEqualsNode; import jdk.graal.compiler.nodes.cfg.HIRBlock; import jdk.graal.compiler.nodes.extended.BranchProbabilityNode; +import jdk.graal.compiler.nodes.extended.OSRMonitorEnterNode; import jdk.graal.compiler.nodes.loop.LoopEx; import jdk.graal.compiler.nodes.loop.LoopsData; import jdk.graal.compiler.nodes.spi.CoreProviders; @@ -268,6 +269,17 @@ public static void propagateFixed(FixedNode from, StaticDeoptimizingNode deopt, moveAsDeoptAfter((AbstractBeginNode) current, deopt); return; } + } else if (current instanceof OSRMonitorEnterNode monitorEnterNode) { + /* + * OSR locals (including locks) need to remain in the graph and be lowered to LIR + * even when a deopt floats all the way to OSRStart, so that the actions associated + * with OSRStart and OSRMonitorEnter are performed and the associated FrameState is + * correct. Since OSR lock nodes are only lowered along with the OSRMonitorEnter + * they're used by, we must not float a deopt above a OSRMonitorEnterNode to prevent + * it from being removed from the graph. + */ + moveAsDeoptAfter(monitorEnterNode, deopt); + return; } current = current.predecessor(); } From 5c0bfbabb67117884ce1f4093347deea03a48354 Mon Sep 17 00:00:00 2001 From: Foivos Zakkak Date: Thu, 26 Oct 2023 21:29:54 +0300 Subject: [PATCH 066/593] Fix class-path order when Manifests include "Class-Path" attributes `destination` is the classpath GraalVM creates from parsing the jar files passed to it. The ordering of the entries in the classpath is important. Jar files themselves should be added before the entries of their corresponding "Class-Path" attributes. At the same time we want to process the contents of `META-INF/native-image` of the entries in the "Class-Path" before processing the contents of `META-INF/native-image` of the jar itself. This is required to ensure that the jar `META-INF/native-image` contents can override those of the entries in its "Class-Path". As a result I chose to optimistically add the path to the classpath (aka `destination`) and remove it afterwards if deemed necessary. Fixes https://github.com/oracle/graal/issues/7677 --- .../src/com/oracle/svm/driver/NativeImage.java | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/substratevm/src/com.oracle.svm.driver/src/com/oracle/svm/driver/NativeImage.java b/substratevm/src/com.oracle.svm.driver/src/com/oracle/svm/driver/NativeImage.java index b26900527e60..b8ae9598628f 100644 --- a/substratevm/src/com.oracle.svm.driver/src/com/oracle/svm/driver/NativeImage.java +++ b/substratevm/src/com.oracle.svm.driver/src/com/oracle/svm/driver/NativeImage.java @@ -2110,12 +2110,13 @@ private void addImageClasspathEntry(LinkedHashSet destination, Path classp Path classpathEntryFinal = useBundle() ? bundleSupport.substituteClassPath(classpathEntry) : classpathEntry; if (!imageClasspath.contains(classpathEntryFinal) && !customImageClasspath.contains(classpathEntryFinal)) { + boolean added = destination.add(classpathEntryFinal); if (ClasspathUtils.isJar(classpathEntryFinal)) { processJarManifestMainAttributes(classpathEntryFinal, (jarFilePath, attributes) -> handleClassPathAttribute(destination, jarFilePath, attributes)); } boolean ignore = processClasspathNativeImageMetaInf(classpathEntryFinal); - if (!ignore) { - destination.add(classpathEntryFinal); + if (added && ignore) { + destination.remove(classpathEntryFinal); } } } From 944054914bcf734e07db5b2458230c57b651ece8 Mon Sep 17 00:00:00 2001 From: Christian Haeubl Date: Mon, 4 Dec 2023 11:46:58 +0100 Subject: [PATCH 067/593] Fix potentially pending JNI exceptions. --- .../src/com.oracle.svm.native.jvm.posix/src/JvmFuncs.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/substratevm/src/com.oracle.svm.native.jvm.posix/src/JvmFuncs.c b/substratevm/src/com.oracle.svm.native.jvm.posix/src/JvmFuncs.c index ad62c918051e..9f20147f7f55 100644 --- a/substratevm/src/com.oracle.svm.native.jvm.posix/src/JvmFuncs.c +++ b/substratevm/src/com.oracle.svm.native.jvm.posix/src/JvmFuncs.c @@ -31,7 +31,7 @@ #include #include #include -#include +#include #include #include #include @@ -311,10 +311,15 @@ JNIEXPORT jobject JNICALL JVM_DoPrivileged(JNIEnv *env, jclass cls, jobject acti return (*env)->CallObjectMethod(env, action, run); } } + + /* Some error occurred - clear pending exception and try to report the error. */ + (*env)->ExceptionClear(env); + jclass errorClass = (*env)->FindClass(env, "java/lang/InternalError"); if (errorClass != NULL && !(*env)->ExceptionCheck(env)) { (*env)->ThrowNew(env, errorClass, "Could not invoke PrivilegedAction"); } else { + (*env)->ExceptionClear(env); (*env)->FatalError(env, "PrivilegedAction could not be invoked and the error could not be reported"); } return NULL; From 41e6243f47d5d2bcb62890a52891a316f6a93e26 Mon Sep 17 00:00:00 2001 From: Olya Gupalo Date: Mon, 4 Dec 2023 14:57:05 +0100 Subject: [PATCH 068/593] Add a missing semicolon to Java code snippet --- docs/reference-manual/embedding/embed-languages.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/reference-manual/embedding/embed-languages.md b/docs/reference-manual/embedding/embed-languages.md index 6e0dece53b7d..ffb0581821ed 100644 --- a/docs/reference-manual/embedding/embed-languages.md +++ b/docs/reference-manual/embedding/embed-languages.md @@ -713,7 +713,7 @@ public class PolyglotIsolate { .allowHostAccess(HostAccess.SCOPED) .option("engine.SpawnIsolate", "true").build()) { - Value function = context.eval("js", "x => x+1") + Value function = context.eval("js", "x => x+1"); assert function.canExecute(); int x = function.execute(41).asInt(); assert x == 42; From 544245fb5193e2ac6a8b96ef93cb444072f0bb28 Mon Sep 17 00:00:00 2001 From: Sacha Coppey Date: Fri, 1 Dec 2023 01:08:45 +0100 Subject: [PATCH 069/593] Fix lookupConstant exception handling --- .../serviceprovider/GraalServices.java | 34 +++++++++---------- .../phases/SharedGraphBuilderPhase.java | 10 +++--- 2 files changed, 22 insertions(+), 22 deletions(-) diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/serviceprovider/GraalServices.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/serviceprovider/GraalServices.java index 6455d3bd97d6..0f586ca9a1de 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/serviceprovider/GraalServices.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/serviceprovider/GraalServices.java @@ -40,6 +40,7 @@ import java.util.ServiceConfigurationError; import java.util.ServiceLoader; +import jdk.graal.compiler.debug.GraalError; import jdk.vm.ci.meta.ConstantPool; import jdk.vm.ci.meta.EncodedSpeculationReason; import jdk.vm.ci.meta.JavaMethod; @@ -454,15 +455,11 @@ public static int getJavaUpdateVersion() { public static JavaMethod lookupMethodWithCaller(ConstantPool constantPool, int cpi, int opcode, ResolvedJavaMethod caller) { if (constantPoolLookupMethodWithCaller != null) { try { - try { - return (JavaMethod) constantPoolLookupMethodWithCaller.invoke(constantPool, cpi, opcode, caller); - } catch (InvocationTargetException e) { - throw e.getCause(); - } - } catch (Error e) { - throw e; - } catch (Throwable throwable) { - throw new InternalError(throwable); + return (JavaMethod) constantPoolLookupMethodWithCaller.invoke(constantPool, cpi, opcode, caller); + } catch (InvocationTargetException e) { + throw rethrow(e.getCause()); + } catch (IllegalAccessException e) { + throw GraalError.shouldNotReachHere(e, "The method lookupMethod should be accessible."); } } throw new InternalError("This JDK doesn't support ConstantPool.lookupMethod(int, int, ResolvedJavaMethod)"); @@ -471,20 +468,21 @@ public static JavaMethod lookupMethodWithCaller(ConstantPool constantPool, int c public static Object lookupConstant(ConstantPool constantPool, int cpi, boolean resolve) { if (constantPoolLookupConstantWithResolve != null) { try { - try { - return constantPoolLookupConstantWithResolve.invoke(constantPool, cpi, resolve); - } catch (InvocationTargetException e) { - throw e.getCause(); - } - } catch (Error e) { - throw e; - } catch (Throwable throwable) { - throw new InternalError(throwable); + return constantPoolLookupConstantWithResolve.invoke(constantPool, cpi, resolve); + } catch (InvocationTargetException e) { + throw rethrow(e.getCause()); + } catch (IllegalAccessException e) { + throw GraalError.shouldNotReachHere(e, "The method lookupConstant should be accessible."); } } return constantPool.lookupConstant(cpi); } + @SuppressWarnings("unchecked") + static RuntimeException rethrow(Throwable ex) throws E { + throw (E) ex; + } + /** * Returns true if the JDK includes {@code ConstantPool.lookupConstant(int, boolean)}. */ diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/phases/SharedGraphBuilderPhase.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/phases/SharedGraphBuilderPhase.java index d7276b025697..0d1660abd3a5 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/phases/SharedGraphBuilderPhase.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/phases/SharedGraphBuilderPhase.java @@ -24,6 +24,7 @@ */ package com.oracle.svm.hosted.phases; +import java.lang.invoke.LambdaConversionException; import java.lang.reflect.Constructor; import java.lang.reflect.Executable; import java.lang.reflect.Method; @@ -239,11 +240,12 @@ protected void maybeEagerlyResolve(int cpi, int bytecode) { try { super.maybeEagerlyResolve(cpi, bytecode); } catch (UnresolvedElementException e) { - if (e.getCause() instanceof LinkageError || e.getCause() instanceof IllegalAccessError) { + if (e.getCause() instanceof LambdaConversionException || e.getCause() instanceof LinkageError || e.getCause() instanceof IllegalAccessError) { /* - * Ignore LinkageError if thrown from eager resolution attempt. This is usually - * followed by a call to ConstantPool.lookupType() which should return an - * UnresolvedJavaType which we know how to deal with. + * Ignore LinkageError, LambdaConversionException or IllegalAccessError if + * thrown from eager resolution attempt. This is usually followed by a call to + * ConstantPool.lookupType() which should return an UnresolvedJavaType which we + * know how to deal with. */ } else { throw e; From f349deedfb385b5657e56b7241cf22ddd8e816bb Mon Sep 17 00:00:00 2001 From: Sacha Coppey Date: Fri, 1 Dec 2023 16:26:19 +0100 Subject: [PATCH 070/593] update JVMCI version check --- .../src/jdk/graal/compiler/hotspot/JVMCIVersionCheck.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/JVMCIVersionCheck.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/JVMCIVersionCheck.java index 7f9e37b8c63d..a7021b7af40d 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/JVMCIVersionCheck.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/JVMCIVersionCheck.java @@ -52,7 +52,7 @@ public final class JVMCIVersionCheck { * default/fallback entry. */ private static final Map> JVMCI_MIN_VERSIONS = Map.of( - "21", Map.of(DEFAULT_VENDOR_ENTRY, new Version(23, 1, 22)), + "21", Map.of(DEFAULT_VENDOR_ENTRY, new Version(23, 1, 26)), "22", Map.of( "Oracle Corporation", new Version("22+25", 1), DEFAULT_VENDOR_ENTRY, new Version("22+25", 1))); From 1b76b1a3cc649d1451d95c4b78f5293a317da998 Mon Sep 17 00:00:00 2001 From: Tomas Zezula Date: Thu, 30 Nov 2023 18:19:47 +0100 Subject: [PATCH 071/593] [GR-50340] SubprocessTestUtils dumps threads on subprocess timeout. --- truffle/mx.truffle/suite.py | 1 + .../truffle/api/test/SubprocessTestUtils.java | 123 +++++++++++++++++- 2 files changed, 121 insertions(+), 3 deletions(-) diff --git a/truffle/mx.truffle/suite.py b/truffle/mx.truffle/suite.py index 989cd31fece2..3d3fe91d892b 100644 --- a/truffle/mx.truffle/suite.py +++ b/truffle/mx.truffle/suite.py @@ -357,6 +357,7 @@ "java.sql", "jdk.management", "jdk.unsupported", # sun.misc.Unsafe + "jdk.attach", # required by SubprocessTestUtils ], "requiresConcealed" : { "java.base" : [ diff --git a/truffle/src/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/SubprocessTestUtils.java b/truffle/src/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/SubprocessTestUtils.java index 6454ed8f6c5e..3081010194b4 100644 --- a/truffle/src/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/SubprocessTestUtils.java +++ b/truffle/src/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/SubprocessTestUtils.java @@ -44,6 +44,10 @@ import java.io.File; import java.io.IOException; import java.io.InputStreamReader; +import java.io.PrintStream; +import java.lang.management.LockInfo; +import java.lang.management.MonitorInfo; +import java.lang.management.ThreadInfo; import java.lang.reflect.Method; import java.nio.file.Files; import java.nio.file.Path; @@ -53,6 +57,9 @@ import java.util.Formatter; import java.util.List; import java.util.Map; +import java.util.Objects; +import java.util.Optional; +import java.util.Properties; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicReference; import java.util.function.Consumer; @@ -60,10 +67,20 @@ import java.util.regex.Pattern; import java.util.stream.Collectors; +import com.sun.tools.attach.VirtualMachine; +import com.sun.tools.attach.VirtualMachineDescriptor; +import org.graalvm.nativeimage.ImageInfo; import org.junit.Assert; import org.junit.Assume; import org.junit.Test; +import javax.management.MBeanServerConnection; +import javax.management.ObjectName; +import javax.management.openmbean.CompositeData; +import javax.management.remote.JMXConnector; +import javax.management.remote.JMXConnectorFactory; +import javax.management.remote.JMXServiceURL; + /** * Support for executing Truffle tests in a sub-process with filtered compilation failure options. * This support is useful for tests that explicitly set @@ -86,6 +103,14 @@ */ public final class SubprocessTestUtils { + /** + * Recommended value of the subprocess timeout. After exceeding it, the process is forcibly + * terminated. + * + * @see Builder#timeout(Duration) + */ + public static final Duration DEFAULT_TIMEOUT = Duration.ofMinutes(5); + private static final String CONFIGURED_PROPERTY = SubprocessTestUtils.class.getSimpleName() + ".configured"; private static final String TO_REMOVE_PREFIX = "~~"; @@ -154,14 +179,15 @@ private static Method findTestMethod(Class testClass) { throw new IllegalStateException("Failed to find current test method in class " + testClass); } - private static Subprocess execute(Method testMethod, boolean failOnNonZeroExitCode, List prefixVMOptions, List postfixVmOptions) throws IOException, InterruptedException { + private static Subprocess execute(Method testMethod, boolean failOnNonZeroExitCode, List prefixVMOptions, + List postfixVmOptions, Duration timeout) throws IOException, InterruptedException { String enclosingElement = testMethod.getDeclaringClass().getName(); String testName = testMethod.getName(); Subprocess subprocess = javaHelper( configure(getVmArgs(), prefixVMOptions, postfixVmOptions), null, null, List.of("com.oracle.mxtool.junit.MxJUnitWrapper", String.format("%s#%s", enclosingElement, testName)), - null); + timeout); if (failOnNonZeroExitCode && subprocess.exitCode != 0) { Assert.fail(String.join("\n", subprocess.output)); } @@ -319,6 +345,7 @@ public static final class Builder { private final List prefixVmArgs = new ArrayList<>(); private final List postfixVmArgs = new ArrayList<>(); private boolean failOnNonZeroExit = true; + private Duration timeout; private Consumer onExit; private Builder(Class testClass, Runnable run) { @@ -341,6 +368,18 @@ public Builder failOnNonZeroExit(boolean b) { return this; } + /** + * Sets the subprocess timeout. After its expiration, the subprocess is forcibly terminated. + * By default, there is no timeout and the subprocess execution time is not limited. + * + * @see SubprocessTestUtils#DEFAULT_TIMEOUT + * + */ + public Builder timeout(Duration duration) { + this.timeout = Objects.requireNonNull(duration, "duration must be non null"); + return this; + } + public Builder onExit(Consumer exit) { this.onExit = exit; return this; @@ -350,7 +389,7 @@ public void run() throws IOException, InterruptedException { if (isSubprocess()) { runnable.run(); } else { - Subprocess process = execute(findTestMethod(testClass), failOnNonZeroExit, prefixVmArgs, postfixVmArgs); + Subprocess process = execute(findTestMethod(testClass), failOnNonZeroExit, prefixVmArgs, postfixVmArgs, timeout); if (onExit != null) { onExit.accept(process); } @@ -539,6 +578,7 @@ private static Subprocess process(List command, Map env, outputReader.start(); boolean finishedOnTime = process.waitFor(timeout.getSeconds(), TimeUnit.SECONDS); if (!finishedOnTime) { + dumpThreads(process.toHandle()); process.destroyForcibly().waitFor(); } outputReader.join(); @@ -546,6 +586,83 @@ private static Subprocess process(List command, Map env, } } + private static void dumpThreads(ProcessHandle process) { + if (ImageInfo.inImageCode()) { + // The attach API is not supported by substratevm. + return; + } + Optional vmDescriptor = VirtualMachine.list().stream().filter((d) -> { + try { + return Long.parseLong(d.id()) == process.pid(); + } catch (NumberFormatException e) { + return false; + } + }).findAny(); + if (vmDescriptor.isPresent()) { + try { + VirtualMachine vm = VirtualMachine.attach(vmDescriptor.get()); + try { + Properties props = vm.getAgentProperties(); + String connectorAddress = props.getProperty("com.sun.management.jmxremote.localConnectorAddress"); + if (connectorAddress == null) { + connectorAddress = vm.startLocalManagementAgent(); + } + JMXServiceURL url = new JMXServiceURL(connectorAddress); + try (JMXConnector connector = JMXConnectorFactory.connect(url)) { + MBeanServerConnection mbeanConnection = connector.getMBeanServerConnection(); + CompositeData[] result = (CompositeData[]) mbeanConnection.invoke(new ObjectName("java.lang:type=Threading"), "dumpAllThreads", + new Object[]{true, true}, new String[]{boolean.class.getName(), boolean.class.getName()}); + PrintStream out = System.err; + out.printf("%nDumping subprocess threads on timeout%n"); + for (CompositeData element : result) { + dumpThread(ThreadInfo.from(element), out); + } + } + } finally { + vm.detach(); + } + } catch (Exception e) { + // thread dump is an optional operation, just log the error + System.err.println("Failed to generate timed out subprocess thread dump due to"); + e.printStackTrace(System.err); + } + } + } + + private static void dumpThread(ThreadInfo ti, PrintStream out) { + long id = ti.getThreadId(); + Thread.State state = ti.getThreadState(); + out.printf(""" + "%s" %s prio=%d tid=%d %s + java.lang.Thread.State: %s + """, + ti.getThreadName(), + ti.isDaemon() ? "daemon" : "", + ti.getPriority(), + id, + state.name().toLowerCase(), + state.name()); + StackTraceElement[] stackTrace = ti.getStackTrace(); + MonitorInfo[] monitors = ti.getLockedMonitors(); + LockInfo[] synchronizers = ti.getLockedSynchronizers(); + for (int i = 0; i < stackTrace.length; i++) { + StackTraceElement stackTraceElement = stackTrace[i]; + out.printf("\tat %s%n", stackTraceElement); + for (MonitorInfo mi : monitors) { + if (mi.getLockedStackDepth() == i) { + out.printf("\t- locked %s%n", mi); + } + } + } + if (synchronizers.length > 0) { + out.printf("%n Locked ownable synchronizers:%n"); + for (LockInfo li : synchronizers) { + out.printf("\t- %s%n", li); + } + } + out.println(); + } + private static boolean hasArg(String optionName) { if (optionName.equals("-cp") || optionName.equals("-classpath") || optionName.equals("-p")) { return true; From cdac6e48979d77595eaa7b1784a04a5dc8dd7feb Mon Sep 17 00:00:00 2001 From: Tom Rodriguez Date: Mon, 4 Dec 2023 11:05:00 -0800 Subject: [PATCH 072/593] Improve comment --- .../src/jdk/graal/compiler/hotspot/CompilationTask.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/CompilationTask.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/CompilationTask.java index f87405fa7793..d22ff88c8764 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/CompilationTask.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/CompilationTask.java @@ -77,7 +77,8 @@ public class CompilationTask implements CompilationWatchDog.EventHandler { static class Options { - @Option(help = "Perform a full GC after every compile to reduce idle heap and reclaim references", type = OptionType.Expert)// + @Option(help = "Perform a full GC of the libgraal heap after every compile to reduce idle heap and reclaim " + + "references to the HotSpot heap. This flag has no effect in the context of jargraal", type = OptionType.Expert)// public static final OptionKey FullGCAfterCompile = new OptionKey<>(false); } From 2d1efbe94fe5d4d315f17f854c1bc2506554ca00 Mon Sep 17 00:00:00 2001 From: Tom Rodriguez Date: Mon, 4 Dec 2023 11:46:28 -0800 Subject: [PATCH 073/593] Remove unused import --- .../oracle/svm/graal/hotspot/libgraal/LibGraalSubstitutions.java | 1 - 1 file changed, 1 deletion(-) diff --git a/substratevm/src/com.oracle.svm.graal.hotspot.libgraal/src/com/oracle/svm/graal/hotspot/libgraal/LibGraalSubstitutions.java b/substratevm/src/com.oracle.svm.graal.hotspot.libgraal/src/com/oracle/svm/graal/hotspot/libgraal/LibGraalSubstitutions.java index 38a5989e4dcb..1f775466c13a 100644 --- a/substratevm/src/com.oracle.svm.graal.hotspot.libgraal/src/com/oracle/svm/graal/hotspot/libgraal/LibGraalSubstitutions.java +++ b/substratevm/src/com.oracle.svm.graal.hotspot.libgraal/src/com/oracle/svm/graal/hotspot/libgraal/LibGraalSubstitutions.java @@ -30,7 +30,6 @@ import com.oracle.svm.core.annotate.Alias; import com.oracle.svm.core.annotate.RecomputeFieldValue; import com.oracle.svm.core.annotate.TargetClass; -import com.oracle.svm.core.heap.Heap; import jdk.vm.ci.services.Services; From ed9c3ae394ccc3dfa0521046e9e9ee7e93bedce4 Mon Sep 17 00:00:00 2001 From: Christian Wimmer Date: Sat, 2 Dec 2023 17:36:03 -0800 Subject: [PATCH 074/593] Store signature of AnalysisMethod as resolved types --- .../graal/pointsto/PointsToAnalysis.java | 4 +- .../infrastructure/ResolvedSignature.java | 145 ++++++++++++++++++ .../pointsto/infrastructure/Universe.java | 5 +- .../infrastructure/WrappedConstantPool.java | 9 +- .../infrastructure/WrappedSignature.java | 91 ----------- .../graal/pointsto/meta/AnalysisMethod.java | 9 +- .../graal/pointsto/meta/AnalysisUniverse.java | 45 ++++-- .../annotation/CustomSubstitutionMethod.java | 38 ++++- .../code/CFunctionPointerCallStubMethod.java | 15 +- .../svm/hosted/meta/HostedUniverse.java | 10 +- .../svm/hosted/meta/UniverseBuilder.java | 23 +-- 11 files changed, 258 insertions(+), 136 deletions(-) create mode 100644 substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/infrastructure/ResolvedSignature.java delete mode 100644 substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/infrastructure/WrappedSignature.java diff --git a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/PointsToAnalysis.java b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/PointsToAnalysis.java index 86ee885065c0..4889e621ce3c 100644 --- a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/PointsToAnalysis.java +++ b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/PointsToAnalysis.java @@ -56,7 +56,6 @@ import com.oracle.graal.pointsto.flow.OffsetLoadTypeFlow.AbstractUnsafeLoadTypeFlow; import com.oracle.graal.pointsto.flow.OffsetStoreTypeFlow.AbstractUnsafeStoreTypeFlow; import com.oracle.graal.pointsto.flow.TypeFlow; -import com.oracle.graal.pointsto.infrastructure.WrappedSignature; import com.oracle.graal.pointsto.meta.AnalysisField; import com.oracle.graal.pointsto.meta.AnalysisMetaAccess; import com.oracle.graal.pointsto.meta.AnalysisMethod; @@ -88,6 +87,7 @@ import jdk.vm.ci.meta.JavaKind; import jdk.vm.ci.meta.JavaType; import jdk.vm.ci.meta.ResolvedJavaField; +import jdk.vm.ci.meta.Signature; public abstract class PointsToAnalysis extends AbstractAnalysisEngine { /** The type of {@link java.lang.Object}. */ @@ -323,7 +323,7 @@ public AnalysisMethod addRootMethod(AnalysisMethod aMethod, boolean invokeSpecia AnalysisError.guarantee(aMethod.isOriginalMethod()); AnalysisType declaringClass = aMethod.getDeclaringClass(); boolean isStatic = aMethod.isStatic(); - WrappedSignature signature = aMethod.getSignature(); + Signature signature = aMethod.getSignature(); int paramCount = signature.getParameterCount(!isStatic); PointsToAnalysisMethod originalPTAMethod = assertPointsToAnalysisMethod(aMethod); diff --git a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/infrastructure/ResolvedSignature.java b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/infrastructure/ResolvedSignature.java new file mode 100644 index 000000000000..173ef1962207 --- /dev/null +++ b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/infrastructure/ResolvedSignature.java @@ -0,0 +1,145 @@ +/* + * Copyright (c) 2023, 2023, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.graal.pointsto.infrastructure; + +import java.lang.invoke.MethodType; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; +import java.util.Objects; +import java.util.stream.Collectors; + +import jdk.vm.ci.meta.JavaKind; +import jdk.vm.ci.meta.MetaAccessProvider; +import jdk.vm.ci.meta.ResolvedJavaType; +import jdk.vm.ci.meta.Signature; + +/** + * A straightforward implementation of {@link Signature} where all parameter types and the return + * type are {@link ResolvedJavaType}. The generic type allows to further improve type safety of + * usages. + * + * In a regular {@link Signature}, looking up a + * {@link Signature#getParameterType(int, ResolvedJavaType) parameter type} or the + * {@link Signature#getReturnType(ResolvedJavaType) return type} requires to provide the "accessing + * class" for type resolution. Since in this implementation all types are always pre-resolved, these + * parameters are ignored. In addition, methods are offered that allow parameter type and return + * type lookup without providing the accessing class. + */ +public final class ResolvedSignature implements Signature { + + public static ResolvedSignature fromArray(T[] parameterTypes, T returnType) { + return new ResolvedSignature<>(List.of(parameterTypes), returnType); + } + + public static ResolvedSignature fromList(List parameterTypes, T returnType) { + return new ResolvedSignature<>(List.copyOf(parameterTypes), returnType); + } + + public static ResolvedSignature fromKinds(JavaKind[] parameterKinds, JavaKind returnKind, MetaAccessProvider metaAccess) { + return new ResolvedSignature<>( + Arrays.stream(parameterKinds).map(kind -> resolveType(kind, metaAccess)).collect(Collectors.toUnmodifiableList()), + resolveType(returnKind, metaAccess)); + } + + private static ResolvedJavaType resolveType(JavaKind kind, MetaAccessProvider metaAccess) { + return metaAccess.lookupJavaType(kind.isObject() ? Object.class : kind.toJavaClass()); + } + + public static ResolvedSignature fromMethodType(MethodType mt, MetaAccessProvider metaAccess) { + return new ResolvedSignature<>( + Arrays.stream(mt.parameterArray()).map(metaAccess::lookupJavaType).collect(Collectors.toUnmodifiableList()), + metaAccess.lookupJavaType(mt.returnType())); + } + + private final List parameterTypes; + private final T returnType; + + private ResolvedSignature(List parameterTypes, T returnType) { + /* + * All factory methods must pass in an immutable list for the parameter types, so that the + * list can be safely passes out again as the parameter list. Unfortunately, there is no way + * to assert that here. + */ + this.parameterTypes = parameterTypes; + this.returnType = returnType; + } + + @Override + public int getParameterCount(boolean withReceiver) { + return parameterTypes.size() + (withReceiver ? 1 : 0); + } + + @Override + public T getParameterType(int index, ResolvedJavaType accessingClass) { + return getParameterType(index); + } + + public T getParameterType(int index) { + return parameterTypes.get(index); + } + + @Override + public T getReturnType(ResolvedJavaType accessingClass) { + return getReturnType(); + } + + public T getReturnType() { + return returnType; + } + + /** + * A type-safe version of {@link Signature#toParameterTypes}. + * + * @return An unmodifiable list with all parameter types, including the receiverType if it is + * non-null. + */ + public List toParameterList(T receiverType) { + if (receiverType == null) { + /* parameterTypes is always an unmodifiable list, so we can return it directly. */ + return parameterTypes; + } + List withReceiver = new ArrayList<>(parameterTypes.size() + 1); + withReceiver.add(receiverType); + withReceiver.addAll(parameterTypes); + return Collections.unmodifiableList(withReceiver); + } + + @Override + public boolean equals(Object obj) { + return this == obj || (obj instanceof ResolvedSignature other && Objects.equals(parameterTypes, other.parameterTypes) && Objects.equals(returnType, other.returnType)); + } + + @Override + public int hashCode() { + return Objects.hash(parameterTypes, returnType); + } + + @Override + public String toString() { + return toMethodDescriptor(); + } +} diff --git a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/infrastructure/Universe.java b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/infrastructure/Universe.java index a19362f0ff8c..d69f1cd61394 100644 --- a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/infrastructure/Universe.java +++ b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/infrastructure/Universe.java @@ -24,12 +24,11 @@ */ package com.oracle.graal.pointsto.infrastructure; -import jdk.graal.compiler.api.replacements.SnippetReflectionProvider; - import com.oracle.graal.pointsto.api.HostVM; import com.oracle.graal.pointsto.heap.ImageHeap; import com.oracle.graal.pointsto.heap.ImageHeapConstant; +import jdk.graal.compiler.api.replacements.SnippetReflectionProvider; import jdk.vm.ci.meta.ConstantPool; import jdk.vm.ci.meta.JavaConstant; import jdk.vm.ci.meta.JavaField; @@ -58,7 +57,7 @@ public interface Universe { JavaMethod lookupAllowUnresolved(JavaMethod method); - WrappedSignature lookup(Signature signature, ResolvedJavaType defaultAccessingClass); + ResolvedSignature lookup(Signature signature, ResolvedJavaType defaultAccessingClass); WrappedConstantPool lookup(ConstantPool constantPool, ResolvedJavaType defaultAccessingClass); diff --git a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/infrastructure/WrappedConstantPool.java b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/infrastructure/WrappedConstantPool.java index bfecdd052b7b..8c6cf91844f5 100644 --- a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/infrastructure/WrappedConstantPool.java +++ b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/infrastructure/WrappedConstantPool.java @@ -31,13 +31,12 @@ import java.util.List; import java.util.stream.Collectors; -import jdk.graal.compiler.core.common.BootstrapMethodIntrospection; -import jdk.graal.compiler.debug.GraalError; -import jdk.graal.compiler.serviceprovider.GraalServices; - import com.oracle.graal.pointsto.constraints.UnresolvedElementException; import com.oracle.svm.util.ReflectionUtil; +import jdk.graal.compiler.core.common.BootstrapMethodIntrospection; +import jdk.graal.compiler.debug.GraalError; +import jdk.graal.compiler.serviceprovider.GraalServices; import jdk.vm.ci.meta.ConstantPool; import jdk.vm.ci.meta.JavaConstant; import jdk.vm.ci.meta.JavaField; @@ -153,7 +152,7 @@ public JavaType lookupType(int cpi, int opcode) { } @Override - public WrappedSignature lookupSignature(int cpi) { + public ResolvedSignature lookupSignature(int cpi) { return universe.lookup(wrapped.lookupSignature(cpi), defaultAccessingClass); } diff --git a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/infrastructure/WrappedSignature.java b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/infrastructure/WrappedSignature.java deleted file mode 100644 index c685e57bd57e..000000000000 --- a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/infrastructure/WrappedSignature.java +++ /dev/null @@ -1,91 +0,0 @@ -/* - * Copyright (c) 2012, 2017, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.oracle.graal.pointsto.infrastructure; - -import jdk.vm.ci.meta.JavaType; -import jdk.vm.ci.meta.ResolvedJavaType; -import jdk.vm.ci.meta.Signature; - -public class WrappedSignature implements Signature { - - private final Universe universe; - private final Signature wrapped; - private final ResolvedJavaType defaultAccessingClass; - - public WrappedSignature(Universe universe, Signature wrapped, ResolvedJavaType defaultAccessingClass) { - this.universe = universe; - this.wrapped = wrapped; - this.defaultAccessingClass = defaultAccessingClass; - } - - @Override - public int getParameterCount(boolean receiver) { - return wrapped.getParameterCount(receiver); - } - - @Override - public JavaType getParameterType(int index, ResolvedJavaType accessingClass) { - ResolvedJavaType parameterType; - try { - parameterType = resolve(wrapped.getParameterType(index, defaultAccessingClass)); - } catch (LinkageError e) { - /* - * Type resolution fails if the parameter type is missing. Just erase the type by - * returning the Object type. - */ - return universe.objectType(); - } - return universe.lookup(parameterType); - } - - @Override - public JavaType getReturnType(ResolvedJavaType accessingClass) { - ResolvedJavaType returnType; - try { - returnType = resolve(wrapped.getReturnType(defaultAccessingClass)); - } catch (LinkageError e) { - /* - * Type resolution fails if the return type is missing. Just erase the type by returning - * the Object type. - */ - return universe.objectType(); - } - return universe.lookup(returnType); - } - - /** - * We must not invoke {@link JavaType#resolve} on an already resolved type because it can - * actually fail the accessibility check when synthetic methods and synthetic signatures are - * involved. - */ - private ResolvedJavaType resolve(JavaType type) { - if (type instanceof ResolvedJavaType) { - return (ResolvedJavaType) type; - } else { - return type.resolve(defaultAccessingClass); - } - } - -} diff --git a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/meta/AnalysisMethod.java b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/meta/AnalysisMethod.java index d3b99640bbca..108cb2b118e6 100644 --- a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/meta/AnalysisMethod.java +++ b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/meta/AnalysisMethod.java @@ -53,8 +53,8 @@ import com.oracle.graal.pointsto.flow.AnalysisParsedGraph; import com.oracle.graal.pointsto.infrastructure.GraphProvider; import com.oracle.graal.pointsto.infrastructure.OriginalMethodProvider; +import com.oracle.graal.pointsto.infrastructure.ResolvedSignature; import com.oracle.graal.pointsto.infrastructure.WrappedJavaMethod; -import com.oracle.graal.pointsto.infrastructure.WrappedSignature; import com.oracle.graal.pointsto.reports.ReportUtils; import com.oracle.graal.pointsto.util.AnalysisError; import com.oracle.graal.pointsto.util.AtomicUtils; @@ -119,6 +119,7 @@ public record Signature(String name, AnalysisType[] parameterTypes) { private final String qualifiedName; protected final AnalysisType declaringClass; + protected final ResolvedSignature signature; private final int parsingContextMaxDepth; private final MultiMethodKey multiMethodKey; @@ -181,6 +182,7 @@ protected AnalysisMethod(AnalysisUniverse universe, ResolvedJavaMethod wrapped, id = universe.nextMethodId.getAndIncrement(); declaringClass = universe.lookup(wrapped.getDeclaringClass()); + signature = getUniverse().lookup(wrapped.getSignature(), wrapped.getDeclaringClass()); hasNeverInlineDirective = universe.hostVM().hasNeverInlineDirective(wrapped); name = createName(wrapped, multiMethodKey); @@ -228,6 +230,7 @@ protected AnalysisMethod(AnalysisMethod original, MultiMethodKey multiMethodKey) wrapped = original.wrapped; id = original.id; declaringClass = original.declaringClass; + signature = original.signature; hasNeverInlineDirective = original.hasNeverInlineDirective; exceptionHandlers = original.exceptionHandlers; localVariableTable = original.localVariableTable; @@ -627,8 +630,8 @@ public String getName() { } @Override - public WrappedSignature getSignature() { - return getUniverse().lookup(wrapped.getSignature(), wrapped.getDeclaringClass()); + public jdk.vm.ci.meta.Signature getSignature() { + return signature; } @Override diff --git a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/meta/AnalysisUniverse.java b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/meta/AnalysisUniverse.java index f7945793caab..9a21efcd0105 100644 --- a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/meta/AnalysisUniverse.java +++ b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/meta/AnalysisUniverse.java @@ -37,8 +37,6 @@ import java.util.concurrent.atomic.AtomicInteger; import java.util.function.Function; -import jdk.graal.compiler.api.replacements.SnippetReflectionProvider; -import jdk.graal.compiler.core.common.SuppressFBWarnings; import org.graalvm.nativeimage.hosted.Feature.DuringAnalysisAccess; import org.graalvm.nativeimage.impl.AnnotationExtractor; import org.graalvm.word.WordBase; @@ -52,16 +50,18 @@ import com.oracle.graal.pointsto.heap.ImageHeapConstant; import com.oracle.graal.pointsto.heap.ImageHeapScanner; import com.oracle.graal.pointsto.infrastructure.AnalysisConstantPool; +import com.oracle.graal.pointsto.infrastructure.ResolvedSignature; import com.oracle.graal.pointsto.infrastructure.SubstitutionProcessor; import com.oracle.graal.pointsto.infrastructure.Universe; import com.oracle.graal.pointsto.infrastructure.WrappedConstantPool; import com.oracle.graal.pointsto.infrastructure.WrappedJavaType; -import com.oracle.graal.pointsto.infrastructure.WrappedSignature; import com.oracle.graal.pointsto.meta.AnalysisType.UsageKind; import com.oracle.graal.pointsto.util.AnalysisError; import com.oracle.graal.pointsto.util.AnalysisFuture; import com.oracle.graal.pointsto.util.GraalAccess; +import jdk.graal.compiler.api.replacements.SnippetReflectionProvider; +import jdk.graal.compiler.core.common.SuppressFBWarnings; import jdk.vm.ci.code.BytecodePosition; import jdk.vm.ci.common.JVMCIError; import jdk.vm.ci.meta.ConstantPool; @@ -88,7 +88,7 @@ public class AnalysisUniverse implements Universe { private final ConcurrentMap types = new ConcurrentHashMap<>(ESTIMATED_NUMBER_OF_TYPES); private final ConcurrentMap fields = new ConcurrentHashMap<>(ESTIMATED_FIELDS_PER_TYPE * ESTIMATED_NUMBER_OF_TYPES); private final ConcurrentMap methods = new ConcurrentHashMap<>(ESTIMATED_METHODS_PER_TYPE * ESTIMATED_NUMBER_OF_TYPES); - private final ConcurrentMap signatures = new ConcurrentHashMap<>(ESTIMATED_METHODS_PER_TYPE * ESTIMATED_NUMBER_OF_TYPES); + private final ConcurrentMap, ResolvedSignature> uniqueSignatures = new ConcurrentHashMap<>(); private final ConcurrentMap constantPools = new ConcurrentHashMap<>(ESTIMATED_NUMBER_OF_TYPES); private final ConcurrentHashMap embeddedRoots = new ConcurrentHashMap<>(ESTIMATED_EMBEDDED_ROOTS); private final ConcurrentMap unsafeAccessedStaticFields = new ConcurrentHashMap<>(); @@ -470,16 +470,37 @@ public AnalysisMethod[] lookup(JavaMethod[] inputs) { } @Override - public WrappedSignature lookup(Signature signature, ResolvedJavaType defaultAccessingClass) { - assert !(signature instanceof WrappedSignature) : signature; + public ResolvedSignature lookup(Signature signature, ResolvedJavaType defaultAccessingClass) { assert !(defaultAccessingClass instanceof WrappedJavaType) : defaultAccessingClass; - WrappedSignature result = signatures.get(signature); - if (result == null) { - WrappedSignature newValue = new WrappedSignature(this, signature, defaultAccessingClass); - WrappedSignature oldValue = signatures.putIfAbsent(signature, newValue); - result = oldValue != null ? oldValue : newValue; + + AnalysisType[] paramTypes = new AnalysisType[signature.getParameterCount(false)]; + for (int i = 0; i < paramTypes.length; i++) { + paramTypes[i] = lookup(resolveSignatureType(signature.getParameterType(i, defaultAccessingClass), defaultAccessingClass)); + } + AnalysisType returnType = lookup(resolveSignatureType(signature.getReturnType(defaultAccessingClass), defaultAccessingClass)); + ResolvedSignature key = ResolvedSignature.fromArray(paramTypes, returnType); + + return uniqueSignatures.computeIfAbsent(key, k -> k); + } + + private ResolvedJavaType resolveSignatureType(JavaType type, ResolvedJavaType defaultAccessingClass) { + /* + * We must not invoke resolve() on an already resolved type because it can actually fail the + * accessibility check when synthetic methods and synthetic signatures are involved. + */ + if (type instanceof ResolvedJavaType resolvedType) { + return resolvedType; + } + + try { + return type.resolve(defaultAccessingClass); + } catch (LinkageError e) { + /* + * Type resolution fails if the parameter type is missing. Just erase the type by + * returning the Object type. + */ + return objectType().getWrapped(); } - return result; } @Override diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/annotation/CustomSubstitutionMethod.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/annotation/CustomSubstitutionMethod.java index ea9aa91d5843..b6d662a7c444 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/annotation/CustomSubstitutionMethod.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/annotation/CustomSubstitutionMethod.java @@ -37,6 +37,7 @@ import jdk.vm.ci.meta.Constant; import jdk.vm.ci.meta.ConstantPool; import jdk.vm.ci.meta.ExceptionHandler; +import jdk.vm.ci.meta.JavaType; import jdk.vm.ci.meta.LineNumberTable; import jdk.vm.ci.meta.LocalVariableTable; import jdk.vm.ci.meta.ProfilingInfo; @@ -75,7 +76,42 @@ public String getName() { @Override public Signature getSignature() { - return original.getSignature(); + /* + * When the substitution method injects a different declaringClass, then type resolution + * with that new declaringClass could fail due to class visibility differences. We try to + * resolve with the original declaringClass, for which the resolving can then succeed. + */ + return new Signature() { + private final Signature wrapped = original.getSignature(); + + @Override + public int getParameterCount(boolean receiver) { + return wrapped.getParameterCount(receiver); + } + + @Override + public JavaType getParameterType(int index, ResolvedJavaType accessingClass) { + JavaType result = wrapped.getParameterType(index, accessingClass); + if (accessingClass != null && !(result instanceof ResolvedJavaType)) { + result = wrapped.getParameterType(index, original.getDeclaringClass()); + } + return result; + } + + @Override + public JavaType getReturnType(ResolvedJavaType accessingClass) { + JavaType result = wrapped.getReturnType(accessingClass); + if (accessingClass != null && !(result instanceof ResolvedJavaType)) { + result = wrapped.getReturnType(original.getDeclaringClass()); + } + return result; + } + + @Override + public String toString() { + return "CustomSubstitutionMethod.Signature<" + wrapped + ">"; + } + }; } @Override diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/code/CFunctionPointerCallStubMethod.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/code/CFunctionPointerCallStubMethod.java index d68c3a439113..eb11296acf92 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/code/CFunctionPointerCallStubMethod.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/code/CFunctionPointerCallStubMethod.java @@ -63,18 +63,22 @@ private CFunctionPointerCallStubMethod(ResolvedJavaMethod original, int newThrea @Override public Signature getSignature() { + /* + * Inject the declaring class as an additional parameter at the beginning of the parameter + * list, to compensate for making the method `static`. + */ return new Signature() { - private final Signature wrapped = getOriginal().getSignature(); + private final Signature wrapped = CFunctionPointerCallStubMethod.super.getSignature(); @Override public int getParameterCount(boolean receiver) { - return wrapped.getParameterCount(true); + return wrapped.getParameterCount(receiver) + 1; } @Override public JavaType getParameterType(int index, ResolvedJavaType accessingClass) { if (index == 0) { - return getOriginal().getDeclaringClass().resolve(accessingClass); + return getOriginal().getDeclaringClass(); } return wrapped.getParameterType(index - 1, accessingClass); } @@ -83,6 +87,11 @@ public JavaType getParameterType(int index, ResolvedJavaType accessingClass) { public JavaType getReturnType(ResolvedJavaType accessingClass) { return wrapped.getReturnType(accessingClass); } + + @Override + public String toString() { + return "CFunctionPointerCallStubMethod.Signature<" + wrapped + ">"; + } }; } diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/meta/HostedUniverse.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/meta/HostedUniverse.java index be06ee0698b7..cfbecee9c656 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/meta/HostedUniverse.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/meta/HostedUniverse.java @@ -38,8 +38,6 @@ import java.util.Map; import java.util.Optional; -import jdk.graal.compiler.api.replacements.SnippetReflectionProvider; -import jdk.graal.compiler.nodes.StructuredGraph; import org.graalvm.nativeimage.hosted.Feature; import com.oracle.graal.pointsto.BigBang; @@ -49,10 +47,10 @@ import com.oracle.graal.pointsto.infrastructure.OriginalClassProvider; import com.oracle.graal.pointsto.infrastructure.OriginalFieldProvider; import com.oracle.graal.pointsto.infrastructure.OriginalMethodProvider; +import com.oracle.graal.pointsto.infrastructure.ResolvedSignature; import com.oracle.graal.pointsto.infrastructure.SubstitutionProcessor; import com.oracle.graal.pointsto.infrastructure.Universe; import com.oracle.graal.pointsto.infrastructure.WrappedConstantPool; -import com.oracle.graal.pointsto.infrastructure.WrappedSignature; import com.oracle.graal.pointsto.meta.AnalysisField; import com.oracle.graal.pointsto.meta.AnalysisMethod; import com.oracle.graal.pointsto.meta.AnalysisType; @@ -75,6 +73,8 @@ import com.oracle.svm.hosted.substitute.SubstitutionMethod; import com.oracle.svm.hosted.substitute.SubstitutionType; +import jdk.graal.compiler.api.replacements.SnippetReflectionProvider; +import jdk.graal.compiler.nodes.StructuredGraph; import jdk.vm.ci.hotspot.HotSpotResolvedJavaType; import jdk.vm.ci.meta.ConstantPool; import jdk.vm.ci.meta.JavaConstant; @@ -288,7 +288,7 @@ public class HostedUniverse implements Universe { protected final Map types = new HashMap<>(); protected final Map fields = new HashMap<>(); protected final Map methods = new HashMap<>(); - protected final Map signatures = new HashMap<>(); + protected final Map, ResolvedSignature> signatures = new HashMap<>(); protected final Map constantPools = new HashMap<>(); protected EnumMap kindToType = new EnumMap<>(JavaKind.class); @@ -425,7 +425,7 @@ public HostedMethod[] lookup(JavaMethod[] inputs) { } @Override - public WrappedSignature lookup(Signature signature, ResolvedJavaType defaultAccessingClass) { + public ResolvedSignature lookup(Signature signature, ResolvedJavaType defaultAccessingClass) { assert signatures.containsKey(signature) : signature; return signatures.get(signature); } diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/meta/UniverseBuilder.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/meta/UniverseBuilder.java index 91dff3d66c12..f93ea1d32ff0 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/meta/UniverseBuilder.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/meta/UniverseBuilder.java @@ -52,8 +52,8 @@ import com.oracle.graal.pointsto.BigBang; import com.oracle.graal.pointsto.constraints.UnsupportedFeatures; +import com.oracle.graal.pointsto.infrastructure.ResolvedSignature; import com.oracle.graal.pointsto.infrastructure.WrappedConstantPool; -import com.oracle.graal.pointsto.infrastructure.WrappedSignature; import com.oracle.graal.pointsto.meta.AnalysisField; import com.oracle.graal.pointsto.meta.AnalysisMetaAccess; import com.oracle.graal.pointsto.meta.AnalysisMethod; @@ -108,7 +108,6 @@ import jdk.vm.ci.meta.ExceptionHandler; import jdk.vm.ci.meta.JavaKind; import jdk.vm.ci.meta.JavaType; -import jdk.vm.ci.meta.Signature; import jdk.vm.ci.meta.UnresolvedJavaType; public class UniverseBuilder { @@ -294,7 +293,8 @@ private static boolean sameObject(Object x, Object y) { private HostedMethod makeMethod(AnalysisMethod aMethod) { AnalysisType aDeclaringClass = aMethod.getDeclaringClass(); HostedType hDeclaringClass = lookupType(aDeclaringClass); - Signature signature = makeSignature(aMethod.getSignature(), aDeclaringClass); + @SuppressWarnings("unchecked") + var signature = makeSignature((ResolvedSignature) aMethod.getSignature()); ConstantPool constantPool = makeConstantPool(aMethod.getConstantPool(), aDeclaringClass); ExceptionHandler[] aHandlers = aMethod.getExceptionHandlers(); @@ -332,16 +332,17 @@ private HostedMethod makeMethod(AnalysisMethod aMethod) { return hMethod; } - private Signature makeSignature(Signature aSignature, AnalysisType aDefaultAccessingClass) { - WrappedSignature hSignature = hUniverse.signatures.get(aSignature); + private ResolvedSignature makeSignature(ResolvedSignature aSignature) { + ResolvedSignature hSignature = hUniverse.signatures.get(aSignature); if (hSignature == null) { - hSignature = new WrappedSignature(hUniverse, aSignature, aDefaultAccessingClass); - hUniverse.signatures.put(aSignature, hSignature); - - for (int i = 0; i < aSignature.getParameterCount(false); i++) { - lookupType((AnalysisType) aSignature.getParameterType(i, null)); + HostedType[] paramTypes = new HostedType[aSignature.getParameterCount(false)]; + for (int i = 0; i < paramTypes.length; i++) { + paramTypes[i] = lookupType(aSignature.getParameterType(i)); } - lookupType((AnalysisType) aSignature.getReturnType(null)); + HostedType returnType = lookupType(aSignature.getReturnType()); + + hSignature = ResolvedSignature.fromArray(paramTypes, returnType); + hUniverse.signatures.put(aSignature, hSignature); } return hSignature; } From 56ac22d5f0c10fb3e53a4972779fbd62ddd01d6d Mon Sep 17 00:00:00 2001 From: Christian Wimmer Date: Sat, 5 Aug 2023 20:18:33 -0700 Subject: [PATCH 075/593] Disallow the deprecated environment variable USE_NATIVE_IMAGE_JAVA_PLATFORM_MODULE_SYSTEM=false --- substratevm/CHANGELOG.md | 1 + .../src/com/oracle/svm/driver/NativeImage.java | 11 ++++++++++- 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/substratevm/CHANGELOG.md b/substratevm/CHANGELOG.md index a5022d550531..638971acc057 100644 --- a/substratevm/CHANGELOG.md +++ b/substratevm/CHANGELOG.md @@ -15,6 +15,7 @@ This changelog summarizes major changes to GraalVM Native Image. * (GR-45651) Methods, fields and constructors of `Object`, primitive classes and array classes are now registered by default for reflection. * (GR-45651) The Native Image agent now tracks calls to `ClassLoader.findSystemClass`, `ObjectInputStream.resolveClass` and `Bundles.of`, and registers resource bundles as bundle name-locale pairs. * (GR-49807) Before this change the function `System#setSecurityManager` was always halting program execution with a VM error. This was inconvenient as the VM error prints an uncomprehensible error message and prevents further continuation of the program. For cases where the program is expected to throw an exception when `System#setSecurityManager` is called, execution on Native Image was not possible. Now, `System#setSecurityManager` throws an `java.lang.UnsupportedOperationException` by default. If the property `java.security.manager` is set to anything but `disallow` at program startup this function will throw a `java.lang.SecurityException` according to the Java spec. +* (GR-30433) Disallow the deprecated environment variable USE_NATIVE_IMAGE_JAVA_PLATFORM_MODULE_SYSTEM=false. ## GraalVM for JDK 21 (Internal Version 23.1.0) * (GR-35746) Lower the default aligned chunk size from 1 MB to 512 KB for the serial and epsilon GCs, reducing memory usage and image size in many cases. diff --git a/substratevm/src/com.oracle.svm.driver/src/com/oracle/svm/driver/NativeImage.java b/substratevm/src/com.oracle.svm.driver/src/com/oracle/svm/driver/NativeImage.java index b26900527e60..1bffeeccd3ae 100644 --- a/substratevm/src/com.oracle.svm.driver/src/com/oracle/svm/driver/NativeImage.java +++ b/substratevm/src/com.oracle.svm.driver/src/com/oracle/svm/driver/NativeImage.java @@ -1653,7 +1653,16 @@ protected int buildImage(List javaArgs, LinkedHashSet cp, LinkedHa } environment.put(ModuleSupport.ENV_VAR_USE_MODULE_SYSTEM, Boolean.toString(config.modulePathBuild)); if (!config.modulePathBuild) { - LogUtils.warningDeprecatedEnvironmentVariable(ModuleSupport.ENV_VAR_USE_MODULE_SYSTEM); + /** + * The old mode of running the image generator on the class path, which was deprecated + * in GraalVM 22.2, is no longer allowed. Using the environment variable + * `USE_NATIVE_IMAGE_JAVA_PLATFORM_MODULE_SYSTEM=false` that used to enable the + * class-path-mode now leads to an early image build error. We really want to report + * this as an error, because just ignoring the environment variable would most likely + * lead to obscure image build errors later on. + */ + throw showError("Running the image generator on the class path is no longer possible. Setting the environment variable " + + ModuleSupport.ENV_VAR_USE_MODULE_SYSTEM + "=false is no longer supported."); } completeCommandList.addAll(0, environment.entrySet().stream().map(e -> e.getKey() + "=" + e.getValue()).sorted().toList()); From 2a8653f3c0d1a89db6640e12eb1a35ca7b946240 Mon Sep 17 00:00:00 2001 From: Josef Eisl Date: Fri, 1 Dec 2023 12:46:39 +0100 Subject: [PATCH 076/593] svm: adopt "JDK-8306055: Add a built-in Catalog to JDK XML module" [GR-50683] --- .../Target_jdk_xml_internal_JdkCatalog.java | 90 +++++++++++++++++++ 1 file changed, 90 insertions(+) create mode 100644 substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/xml/Target_jdk_xml_internal_JdkCatalog.java diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/xml/Target_jdk_xml_internal_JdkCatalog.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/xml/Target_jdk_xml_internal_JdkCatalog.java new file mode 100644 index 000000000000..3685d914dc66 --- /dev/null +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/xml/Target_jdk_xml_internal_JdkCatalog.java @@ -0,0 +1,90 @@ +/* + * Copyright (c) 2023, 2023, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.svm.core.jdk.xml; + +import java.util.Objects; + +import org.graalvm.nativeimage.hosted.FieldValueTransformer; + +import com.oracle.svm.core.annotate.Alias; +import com.oracle.svm.core.annotate.RecomputeFieldValue; +import com.oracle.svm.core.annotate.Substitute; +import com.oracle.svm.core.annotate.TargetClass; +import com.oracle.svm.core.jdk.JDK22OrLater; +import com.oracle.svm.util.ReflectionUtil; + +/** + * Substitution to initialize {@link #catalog} at build time. + * + * JDK-8306055 introduced a built-in Catalog to JDK XML module in JDK 22. Without special treatment, + * the initialization code would pull intermediate types (e.g. {@code CatalogReader}) into the image + * heap. To avoid this, we initialize the catalog at build time and substitute the {@link #init} + * method to be empty. + * + * Ideally, we would initialize all of {@code jdk.xml} at run time, but that is too intrusive at the + * current point in time (GR-50683). + */ +@TargetClass(className = "jdk.xml.internal.JdkCatalog", onlyWith = JDK22OrLater.class) +public final class Target_jdk_xml_internal_JdkCatalog { + @Alias // + @RecomputeFieldValue(kind = RecomputeFieldValue.Kind.Custom, declClass = JdkCatalogSupplier.class, isFinal = true) // + public static Target_javax_xml_catalog_Catalog catalog; + + @Substitute + @SuppressWarnings("unused") + public static void init(String resolve) { + // initialized at build time + } +} + +@TargetClass(className = "javax.xml.catalog.Catalog", onlyWith = JDK22OrLater.class) +final class Target_javax_xml_catalog_Catalog { +} + +@TargetClass(className = "javax.xml.catalog.CatalogImpl") +final class Target_javax_xml_catalog_CatalogImpl { + @Alias // + @RecomputeFieldValue(kind = RecomputeFieldValue.Kind.Reset) // + Target_javax_xml_parsers_SAXParser parser; +} + +@TargetClass(className = "javax.xml.parsers.SAXParser") +final class Target_javax_xml_parsers_SAXParser { +} + +final class JdkCatalogSupplier implements FieldValueTransformer { + @Override + public Object transform(Object receiver, Object originalValue) { + // Ensure the field is initialized. + Class xmlSecurityManager = ReflectionUtil.lookupClass(false, "jdk.xml.internal.XMLSecurityManager"); + // The constructor call prepareCatalog which will call JdkCatalog#init. + ReflectionUtil.newInstance(xmlSecurityManager); + + Class jdkCatalogClass = ReflectionUtil.lookupClass(false, "jdk.xml.internal.JdkCatalog"); + Object catalog = ReflectionUtil.readStaticField(jdkCatalogClass, "catalog"); + + return Objects.requireNonNull(catalog); + } +} From 10f68600f8c38eb6e8ef36d64b13bf8a0606c65f Mon Sep 17 00:00:00 2001 From: Marouane El Hallaoui Date: Fri, 1 Dec 2023 16:06:40 +0100 Subject: [PATCH 077/593] update to final builds --- common.json | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/common.json b/common.json index d6138f626e36..0fd8827daab7 100644 --- a/common.json +++ b/common.json @@ -43,12 +43,12 @@ "labsjdk-ee-21-llvm": {"name": "labsjdk", "version": "ee-21.0.1+11-jvmci-23.1-b22-sulong", "platformspecific": true }, "oraclejdk-latest": {"name": "jpg-jdk", "version": "22", "build_id": "26", "release": true, "platformspecific": true, "extrabundles": ["static-libs"]}, - "labsjdk-ce-latest": {"name": "labsjdk", "version": "ce-22+26-jvmci-b01-20231130090102-fe1c594adf", "platformspecific": true }, - "labsjdk-ce-latestDebug": {"name": "labsjdk", "version": "ce-22+26-jvmci-b01-20231130090102-fe1c594adf-debug", "platformspecific": true }, - "labsjdk-ce-latest-llvm": {"name": "labsjdk", "version": "ce-22+26-jvmci-b01-20231130090102-fe1c594adf-sulong", "platformspecific": true }, - "labsjdk-ee-latest": {"name": "labsjdk", "version": "ee-22+26-jvmci-b01-20231130090102-fe1c594adf+48b72ef516", "platformspecific": true }, - "labsjdk-ee-latestDebug": {"name": "labsjdk", "version": "ee-22+26-jvmci-b01-20231130090102-fe1c594adf+48b72ef516-debug", "platformspecific": true }, - "labsjdk-ee-latest-llvm": {"name": "labsjdk", "version": "ee-22+26-jvmci-b01-20231130090102-fe1c594adf+48b72ef516-sulong", "platformspecific": true } + "labsjdk-ce-latest": {"name": "labsjdk", "version": "ce-22+26-jvmci-b01", "platformspecific": true }, + "labsjdk-ce-latestDebug": {"name": "labsjdk", "version": "ce-22+26-jvmci-b01-debug", "platformspecific": true }, + "labsjdk-ce-latest-llvm": {"name": "labsjdk", "version": "ce-22+26-jvmci-b01-sulong", "platformspecific": true }, + "labsjdk-ee-latest": {"name": "labsjdk", "version": "ee-22+26-jvmci-b01", "platformspecific": true }, + "labsjdk-ee-latestDebug": {"name": "labsjdk", "version": "ee-22+26-jvmci-b01-debug", "platformspecific": true }, + "labsjdk-ee-latest-llvm": {"name": "labsjdk", "version": "ee-22+26-jvmci-b01-sulong", "platformspecific": true } }, "eclipse": { From e7ee33487219d10f3ec15bd1861467c3c2ca4373 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Paul=20W=C3=B6gerer?= Date: Tue, 5 Dec 2023 09:29:45 +0100 Subject: [PATCH 078/593] Add comments --- .../src/com/oracle/svm/driver/NativeImage.java | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/substratevm/src/com.oracle.svm.driver/src/com/oracle/svm/driver/NativeImage.java b/substratevm/src/com.oracle.svm.driver/src/com/oracle/svm/driver/NativeImage.java index b8ae9598628f..2fb1e4bd5298 100644 --- a/substratevm/src/com.oracle.svm.driver/src/com/oracle/svm/driver/NativeImage.java +++ b/substratevm/src/com.oracle.svm.driver/src/com/oracle/svm/driver/NativeImage.java @@ -2110,12 +2110,17 @@ private void addImageClasspathEntry(LinkedHashSet destination, Path classp Path classpathEntryFinal = useBundle() ? bundleSupport.substituteClassPath(classpathEntry) : classpathEntry; if (!imageClasspath.contains(classpathEntryFinal) && !customImageClasspath.contains(classpathEntryFinal)) { + /* + * Maintain correct order by adding entry before processing its potential "Class-Path" + * attributes from META-INF/MANIFEST.MF (in case the entry is a jar-file). + */ boolean added = destination.add(classpathEntryFinal); if (ClasspathUtils.isJar(classpathEntryFinal)) { processJarManifestMainAttributes(classpathEntryFinal, (jarFilePath, attributes) -> handleClassPathAttribute(destination, jarFilePath, attributes)); } - boolean ignore = processClasspathNativeImageMetaInf(classpathEntryFinal); - if (added && ignore) { + boolean forcedOnModulePath = processClasspathNativeImageMetaInf(classpathEntryFinal); + if (added && forcedOnModulePath) { + /* Entry makes use of ForceOnModulePath. Undo adding to classpath. */ destination.remove(classpathEntryFinal); } } From 1a7d2a4034f4a890759b3e33c13f8191a72ec651 Mon Sep 17 00:00:00 2001 From: Marouane El Hallaoui Date: Tue, 5 Dec 2023 09:59:09 +0100 Subject: [PATCH 079/593] use final builds --- common.json | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/common.json b/common.json index 0c00d884d863..d67234f74416 100644 --- a/common.json +++ b/common.json @@ -35,12 +35,12 @@ "labsjdk-ee-20-llvm": {"name": "labsjdk", "version": "ee-20.0.2+2-jvmci-23.1-b02-sulong", "platformspecific": true }, "oraclejdk21": {"name": "jpg-jdk", "version": "21", "build_id": "33", "release": true, "platformspecific": true, "extrabundles": ["static-libs"]}, - "labsjdk-ce-21": {"name": "labsjdk", "version": "ce-21.0.1+12-jvmci-23.1-b26-20231026173927-c23572fa4a", "platformspecific": true }, - "labsjdk-ce-21Debug": {"name": "labsjdk", "version": "ce-21.0.1+12-jvmci-23.1-b26-20231026173927-c23572fa4a-debug", "platformspecific": true }, - "labsjdk-ce-21-llvm": {"name": "labsjdk", "version": "ce-21.0.1+12-jvmci-23.1-b26-20231026173927-c23572fa4a-sulong", "platformspecific": true }, - "labsjdk-ee-21": {"name": "labsjdk", "version": "ee-21.0.1+11-jvmci-23.1-b26-20231027085922-c77176937e+38e747d58e", "platformspecific": true }, - "labsjdk-ee-21Debug": {"name": "labsjdk", "version": "ee-21.0.1+11-jvmci-23.1-b26-20231027085922-c77176937e+38e747d58e-debug", "platformspecific": true }, - "labsjdk-ee-21-llvm": {"name": "labsjdk", "version": "ee-21.0.1+11-jvmci-23.1-b26-20231027085922-c77176937e+38e747d58e-sulong", "platformspecific": true }, + "labsjdk-ce-21": {"name": "labsjdk", "version": "ce-21.0.1+12-jvmci-23.1-b26", "platformspecific": true }, + "labsjdk-ce-21Debug": {"name": "labsjdk", "version": "ce-21.0.1+12-jvmci-23.1-b26-debug", "platformspecific": true }, + "labsjdk-ce-21-llvm": {"name": "labsjdk", "version": "ce-21.0.1+12-jvmci-23.1-b26-sulong", "platformspecific": true }, + "labsjdk-ee-21": {"name": "labsjdk", "version": "ee-21.0.1+11-jvmci-23.1-b26", "platformspecific": true }, + "labsjdk-ee-21Debug": {"name": "labsjdk", "version": "ee-21.0.1+11-jvmci-23.1-b26-debug", "platformspecific": true }, + "labsjdk-ee-21-llvm": {"name": "labsjdk", "version": "ee-21.0.1+11-jvmci-23.1-b26-sulong", "platformspecific": true }, "oraclejdk-latest": {"name": "jpg-jdk", "version": "22", "build_id": "25", "release": true, "platformspecific": true, "extrabundles": ["static-libs"]}, "labsjdk-ce-latest": {"name": "labsjdk", "version": "ce-22+25-jvmci-b01", "platformspecific": true }, From d4e897adcf0ce8a380d057039b1d2bec99bae81a Mon Sep 17 00:00:00 2001 From: Christian Haeubl Date: Tue, 21 Nov 2023 15:51:59 +0100 Subject: [PATCH 080/593] Add an async-signal-safe way to dump crash logs. --- .../polyglot/nativeapi/PolyglotNativeAPI.java | 58 ++++++++++++++++++- .../types/PolyglotNativeAPITypes.java | 4 +- 2 files changed, 58 insertions(+), 4 deletions(-) diff --git a/substratevm/src/org.graalvm.polyglot.nativeapi/src/org/graalvm/polyglot/nativeapi/PolyglotNativeAPI.java b/substratevm/src/org.graalvm.polyglot.nativeapi/src/org/graalvm/polyglot/nativeapi/PolyglotNativeAPI.java index 4e96c57d976a..80af00069820 100644 --- a/substratevm/src/org.graalvm.polyglot.nativeapi/src/org/graalvm/polyglot/nativeapi/PolyglotNativeAPI.java +++ b/substratevm/src/org.graalvm.polyglot.nativeapi/src/org/graalvm/polyglot/nativeapi/PolyglotNativeAPI.java @@ -50,6 +50,8 @@ import org.graalvm.nativeimage.ImageSingletons; import org.graalvm.nativeimage.LogHandler; import org.graalvm.nativeimage.ObjectHandle; +import org.graalvm.nativeimage.Platform; +import org.graalvm.nativeimage.Platforms; import org.graalvm.nativeimage.Threading; import org.graalvm.nativeimage.Threading.RecurringCallback; import org.graalvm.nativeimage.UnmanagedMemory; @@ -100,6 +102,7 @@ import org.graalvm.polyglot.nativeapi.types.PolyglotNativeAPITypes.PolyglotExceptionHandlePointer; import org.graalvm.polyglot.nativeapi.types.PolyglotNativeAPITypes.PolyglotExtendedErrorInfo; import org.graalvm.polyglot.nativeapi.types.PolyglotNativeAPITypes.PolyglotExtendedErrorInfoPointer; +import org.graalvm.polyglot.nativeapi.types.PolyglotNativeAPITypes.PolyglotIsolate; import org.graalvm.polyglot.nativeapi.types.PolyglotNativeAPITypes.PolyglotIsolateThread; import org.graalvm.polyglot.nativeapi.types.PolyglotNativeAPITypes.PolyglotLanguage; import org.graalvm.polyglot.nativeapi.types.PolyglotNativeAPITypes.PolyglotLanguagePointer; @@ -115,12 +118,19 @@ import org.graalvm.word.UnsignedWord; import org.graalvm.word.WordFactory; +import com.oracle.svm.core.RegisterDumper; +import com.oracle.svm.core.SubstrateSegfaultHandler; import com.oracle.svm.core.Uninterruptible; +import com.oracle.svm.core.c.SetThreadAndHeapBasePrologue; +import com.oracle.svm.core.c.function.CEntryPointOptions; +import com.oracle.svm.core.c.function.CEntryPointOptions.NoEpilogue; +import com.oracle.svm.core.c.function.CEntryPointOptions.NoPrologue; import com.oracle.svm.core.handles.ObjectHandlesImpl; import com.oracle.svm.core.headers.LibC; import com.oracle.svm.core.jdk.RuntimeSupport; import com.oracle.svm.core.jvmstat.PerfDataSupport; import com.oracle.svm.core.thread.ThreadingSupportImpl; +import com.oracle.svm.core.thread.VMThreads.SafepointBehavior; import com.oracle.svm.core.threadlocal.FastThreadLocalFactory; import com.oracle.svm.core.threadlocal.FastThreadLocalObject; import com.oracle.svm.core.util.UnsignedUtils; @@ -2457,8 +2467,7 @@ private static class PolyglotCallbackInfoInternal { "@since 23.1", }) public static PolyglotStatus poly_register_log_handler_callbacks(PolyglotIsolateThread thread, PolyglotNativeAPITypes.PolyglotLogCallback logCallback, - PolyglotNativeAPITypes.PolyglotFlushCallback flushCallback, - PolyglotNativeAPITypes.PolyglotFatalErrorCallback fatalErrorCallback, VoidPointer data) { + PolyglotNativeAPITypes.PolyglotFlushCallback flushCallback, PolyglotNativeAPITypes.PolyglotFatalErrorCallback fatalErrorCallback, VoidPointer data) { resetErrorState(); nullCheck(logCallback, "logCallback"); nullCheck(flushCallback, "flushCallback"); @@ -2498,6 +2507,39 @@ public static PolyglotStatus poly_perf_data_get_address_of_int64_t(PolyglotIsola return poly_ok; } + @Uninterruptible(reason = "Must be uninterruptible until it gets immune to safepoints.") + @CEntryPointOptions(prologue = SetThreadAndHeapBasePrologue.class, epilogue = NoEpilogue.class) + @CEntryPoint(name = "poly_handle_segfault_in_thread", documentation = { + "Prints information about the segfault and calls the fatal error handler. Note that this method may only be called from an already attached thread.", + "", + "@param signal_info the OS-specific signal information, e.g., siginfo_t* on Linux.", + "@param signal_handler_context the OS-specific signal handler context, e.g., ucontext_t* on Linux.", + "@return this method never returns because it invokes the fatal error handling instead.", + "", + "@since 23.1.2", + }) + public static void poly_handle_segfault_in_thread(PolyglotIsolateThread thread, PointerBase signal_info, RegisterDumper.Context signal_handler_context) { + /* Don't reset the error state so that we see it in the crash log. */ + SubstrateSegfaultHandler.dump(signal_info, signal_handler_context); + } + + @Uninterruptible(reason = "Must be uninterruptible until it gets immune to safepoints.") + @CEntryPointOptions(prologue = NoPrologue.class, epilogue = NoEpilogue.class) + @CEntryPoint(name = "poly_handle_segfault_in_isolate", documentation = { + "Prints information about the segfault and calls the fatal error handler. Note that this method may only be called from an already attached thread.", + "", + "@param signal_info the OS-specific signal information, e.g., siginfo_t* on Linux.", + "@param signal_handler_context the OS-specific signal handler context, e.g., ucontext_t* on Linux.", + "@return this method never returns because it invokes the fatal error handling instead.", + "", + "@since 23.1.2", + }) + public static void poly_handle_segfault_in_isolate(PolyglotIsolate isolate, PointerBase signal_info, RegisterDumper.Context signal_handler_context) { + /* Don't reset the error state so that we see it in the crash log. */ + SubstrateSegfaultHandler.enterIsolateAsyncSignalSafe(isolate); + SubstrateSegfaultHandler.dump(signal_info, signal_handler_context); + } + private static void writeUTF8String(String valueString, CCharPointer buffer, UnsignedWord length, SizeTPointer result) { result.write(CTypeConversion.toCString(valueString, UTF8_CHARSET, buffer, length)); } @@ -2661,6 +2703,10 @@ public static class PolyglotNativeLogHandler implements LogHandler { PolyglotNativeAPITypes.PolyglotFlushCallback flush; PolyglotNativeAPITypes.PolyglotFatalErrorCallback fatalError; + @Platforms(Platform.HOSTED_ONLY.class) + PolyglotNativeLogHandler() { + } + @Override public void log(CCharPointer bytes, UnsignedWord length) { if (log.isNonNull()) { @@ -2678,7 +2724,7 @@ public void flush() { @Override public void fatalError() { if (fatalError.isNonNull()) { - fatalError.invoke(data); + markThreadAsCrashedAndInvokeFatalError(); } /* @@ -2686,5 +2732,11 @@ public void fatalError() { */ LibC.abort(); } + + @Uninterruptible(reason = "Don't access objects in the collected Java heap after marking the thread as crashed.") + private void markThreadAsCrashedAndInvokeFatalError() { + SafepointBehavior.markThreadAsCrashed(); + fatalError.invoke(data); + } } } diff --git a/substratevm/src/org.graalvm.polyglot.nativeapi/src/org/graalvm/polyglot/nativeapi/types/PolyglotNativeAPITypes.java b/substratevm/src/org.graalvm.polyglot.nativeapi/src/org/graalvm/polyglot/nativeapi/types/PolyglotNativeAPITypes.java index 6f9000c1a1db..262eb34f64f6 100644 --- a/substratevm/src/org.graalvm.polyglot.nativeapi/src/org/graalvm/polyglot/nativeapi/types/PolyglotNativeAPITypes.java +++ b/substratevm/src/org.graalvm.polyglot.nativeapi/src/org/graalvm/polyglot/nativeapi/types/PolyglotNativeAPITypes.java @@ -24,6 +24,8 @@ */ package org.graalvm.polyglot.nativeapi.types; +import static org.graalvm.nativeimage.c.function.CFunction.Transition.NO_TRANSITION; + import org.graalvm.nativeimage.Isolate; import org.graalvm.nativeimage.IsolateThread; import org.graalvm.nativeimage.ObjectHandle; @@ -249,7 +251,7 @@ public interface PolyglotFlushCallback extends CFunctionPointer { @CTypedef(name = "poly_fatal_error_callback") public interface PolyglotFatalErrorCallback extends CFunctionPointer { - @InvokeCFunctionPointer + @InvokeCFunctionPointer(transition = NO_TRANSITION) void invoke(VoidPointer data); } } From 1333ddc69dfd8f5df07c6bbad78ce003640bba86 Mon Sep 17 00:00:00 2001 From: Codrut Stancu Date: Tue, 5 Dec 2023 11:58:14 +0100 Subject: [PATCH 081/593] Uncompress ImageHeap keys. --- .../common/type/CompressibleConstant.java | 14 ++++++++ .../oracle/graal/pointsto/heap/ImageHeap.java | 10 +++--- .../pointsto/heap/ImageHeapConstant.java | 6 ++-- .../svm/hosted/image/NativeImageHeap.java | 34 +++++-------------- 4 files changed, 32 insertions(+), 32 deletions(-) diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/core/common/type/CompressibleConstant.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/core/common/type/CompressibleConstant.java index 185c5801a345..6070e0571670 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/core/common/type/CompressibleConstant.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/core/common/type/CompressibleConstant.java @@ -33,4 +33,18 @@ public interface CompressibleConstant extends JavaConstant { JavaConstant compress(); JavaConstant uncompress(); + + static JavaConstant uncompress(JavaConstant constant) { + if (constant instanceof CompressibleConstant compressible && compressible.isCompressed()) { + return compressible.uncompress(); + } + return constant; + } + + static boolean isCompressed(JavaConstant constant) { + if (constant instanceof CompressibleConstant compressible) { + return compressible.isCompressed(); + } + return false; + } } diff --git a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/heap/ImageHeap.java b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/heap/ImageHeap.java index 8f8c5c0bed9f..03699324deda 100644 --- a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/heap/ImageHeap.java +++ b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/heap/ImageHeap.java @@ -33,6 +33,7 @@ import com.oracle.graal.pointsto.util.AnalysisError; import com.oracle.graal.pointsto.util.AnalysisFuture; +import jdk.graal.compiler.core.common.type.CompressibleConstant; import jdk.vm.ci.meta.JavaConstant; /** @@ -77,23 +78,24 @@ public ImageHeap() { /** Get the constant snapshot from the cache. */ public Object getSnapshot(JavaConstant constant) { - if (constant instanceof ImageHeapConstant imageHeapConstant) { + JavaConstant uncompressed = CompressibleConstant.uncompress(constant); + if (uncompressed instanceof ImageHeapConstant imageHeapConstant) { assert imageHeapConstant.getHostedObject() == null || objectsCache.get(imageHeapConstant.getHostedObject()).equals(imageHeapConstant); return imageHeapConstant; } - return objectsCache.get(constant); + return objectsCache.get(uncompressed); } /** Record the future computing the snapshot in the heap. */ public Object setTask(JavaConstant constant, AnalysisFuture task) { assert !(constant instanceof ImageHeapConstant) : constant; - return objectsCache.putIfAbsent(constant, task); + return objectsCache.putIfAbsent(CompressibleConstant.uncompress(constant), task); } /** Record the snapshot in the heap. */ public void setValue(JavaConstant constant, ImageHeapConstant value) { assert !(constant instanceof ImageHeapConstant) : constant; - Object previous = objectsCache.put(constant, value); + Object previous = objectsCache.put(CompressibleConstant.uncompress(constant), value); AnalysisError.guarantee(!(previous instanceof ImageHeapConstant), "An ImageHeapConstant: %s is already registered for hosted JavaConstant: %s.", previous, constant); } diff --git a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/heap/ImageHeapConstant.java b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/heap/ImageHeapConstant.java index 3e2bb86d2a7d..549c87d40745 100644 --- a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/heap/ImageHeapConstant.java +++ b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/heap/ImageHeapConstant.java @@ -33,6 +33,7 @@ import com.oracle.graal.pointsto.ObjectScanner; import com.oracle.graal.pointsto.meta.AnalysisType; +import com.oracle.graal.pointsto.util.AnalysisError; import com.oracle.graal.pointsto.util.AnalysisFuture; import com.oracle.svm.util.ReflectionUtil; @@ -84,7 +85,7 @@ public abstract static class ConstantData { ConstantData(AnalysisType type, JavaConstant object, int identityHashCode) { Objects.requireNonNull(type); this.type = type; - this.hostedObject = object; + this.hostedObject = CompressibleConstant.uncompress(object); this.identityHashCode = identityHashCode; } @@ -176,6 +177,7 @@ public int getIdentityHashCode() { } public JavaConstant getHostedObject() { + AnalysisError.guarantee(!CompressibleConstant.isCompressed(constantData.hostedObject), "References to hosted objects should never be compressed."); return constantData.hostedObject; } @@ -269,6 +271,6 @@ public int hashCode() { @Override public String toString() { - return "ImageHeapConstant< " + constantData.type.toJavaName() + ", reachable: " + isReachable() + ", reader installed: " + isReaderInstalled() + ">"; + return "ImageHeapConstant<" + constantData.type.toJavaName() + ", reachable: " + isReachable() + ", reader installed: " + isReaderInstalled() + ", compressed: " + compressed + ">"; } } diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/NativeImageHeap.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/NativeImageHeap.java index e8912d28be12..8ae05374efe3 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/NativeImageHeap.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/NativeImageHeap.java @@ -107,8 +107,11 @@ public final class NativeImageHeap implements ImageHeap { /** * A Map from objects at construction-time to native image objects. - * + *

* More than one host object may be represented by a single native image object. + *

+ * The constants stored in the image heap are always uncompressed. The same object info is + * returned whenever the map is queried regardless of the compressed flag value. */ private final HashMap objects = new HashMap<>(); @@ -164,12 +167,12 @@ public int getObjectCount() { public ObjectInfo getObjectInfo(Object obj) { JavaConstant constant = hUniverse.getSnippetReflection().forObject(obj); VMError.guarantee(constant instanceof ImageHeapConstant, "Expected an ImageHeapConstant, found %s", constant); - return objects.get(uncompress(constant)); + return objects.get(CompressibleConstant.uncompress(constant)); } public ObjectInfo getConstantInfo(JavaConstant constant) { VMError.guarantee(constant instanceof ImageHeapConstant, "Expected an ImageHeapConstant, found %s", constant); - return objects.get(uncompress(constant)); + return objects.get(CompressibleConstant.uncompress(constant)); } protected HybridLayout getHybridLayout(HostedClass clazz) { @@ -341,7 +344,7 @@ public void addConstant(final JavaConstant constant, boolean immutableFromParent } } - JavaConstant uncompressed = uncompress(constant); + JavaConstant uncompressed = CompressibleConstant.uncompress(constant); int identityHashCode = computeIdentityHashCode(uncompressed); VMError.guarantee(identityHashCode != 0, "0 is used as a marker value for 'hash code not yet computed'"); @@ -360,27 +363,6 @@ public void addConstant(final JavaConstant constant, boolean immutableFromParent } } - /** - * The constants stored in the image heap, i.g., the {@link #objects} map, are always - * uncompressed. The same object info is returned whenever the map is queried regardless of the - * compressed flag value. - */ - private static JavaConstant uncompress(JavaConstant constant) { - if (constant instanceof CompressibleConstant compressible) { - if (compressible.isCompressed()) { - return compressible.uncompress(); - } - } - return constant; - } - - private static boolean isCompressed(JavaConstant constant) { - if (constant instanceof CompressibleConstant compressible) { - return compressible.isCompressed(); - } - return false; - } - private static int computeIdentityHashCode(JavaConstant constant) { return ((TypedConstant) constant).getIdentityHashCode(); } @@ -634,7 +616,7 @@ private ObjectInfo addToImageHeap(Object object, HostedClass clazz, long size, i private ObjectInfo addToImageHeap(JavaConstant add, HostedClass clazz, long size, int identityHashCode, Object reason) { VMError.guarantee(add instanceof ImageHeapConstant, "Expected an ImageHeapConstant, found %s", add); - VMError.guarantee(!isCompressed(add), "Constants added to the image heap must be uncompressed."); + VMError.guarantee(!CompressibleConstant.isCompressed(add), "Constants added to the image heap must be uncompressed."); ObjectInfo info = new ObjectInfo(add, size, clazz, identityHashCode, reason); ObjectInfo previous = objects.putIfAbsent(add, info); VMError.guarantee(previous == null, "Found an existing object info associated to constant %s", add); From d51fec80783a64f4459bea1e921ca8eecf584306 Mon Sep 17 00:00:00 2001 From: Codrut Stancu Date: Tue, 21 Nov 2023 23:14:06 +0100 Subject: [PATCH 082/593] Register embedded roots from snippets. --- .../oracle/graal/pointsto/flow/MethodTypeFlowBuilder.java | 6 +++--- .../src/com/oracle/svm/hosted/HostedConfiguration.java | 4 ++-- .../src/com/oracle/svm/hosted/NativeImageGenerator.java | 2 +- .../svm/hosted/analysis/flow/SVMMethodTypeFlowBuilder.java | 4 ++-- 4 files changed, 8 insertions(+), 8 deletions(-) diff --git a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/flow/MethodTypeFlowBuilder.java b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/flow/MethodTypeFlowBuilder.java index 788ba14365b8..931d698dcf9c 100644 --- a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/flow/MethodTypeFlowBuilder.java +++ b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/flow/MethodTypeFlowBuilder.java @@ -228,7 +228,7 @@ private boolean parse(Object reason, boolean forceReparse) { } // Do it again after canonicalization changed type checks and field accesses. - registerUsedElements(bb, graph, true); + registerUsedElements(bb, graph); return true; } catch (Throwable ex) { @@ -236,7 +236,7 @@ private boolean parse(Object reason, boolean forceReparse) { } } - protected static void registerUsedElements(PointsToAnalysis bb, StructuredGraph graph, boolean registerEmbeddedRoots) { + protected static void registerUsedElements(PointsToAnalysis bb, StructuredGraph graph) { PointsToAnalysisMethod method = (PointsToAnalysisMethod) graph.method(); HostedProviders providers = bb.getProviders(method); for (Node n : graph.getNodes()) { @@ -310,7 +310,7 @@ protected static void registerUsedElements(PointsToAnalysis bb, StructuredGraph assert StampTool.isExactType(cn) : cn; AnalysisType type = (AnalysisType) StampTool.typeOrNull(cn, bb.getMetaAccess()); type.registerAsInHeap(new EmbeddedRootScan(AbstractAnalysisEngine.sourcePosition(cn), root)); - if (registerEmbeddedRoots && !ignoreConstant(bb, cn)) { + if (!ignoreConstant(bb, cn)) { registerEmbeddedRoot(bb, cn); } } diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/HostedConfiguration.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/HostedConfiguration.java index bfaeb872e6cd..ca531229c685 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/HostedConfiguration.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/HostedConfiguration.java @@ -177,8 +177,8 @@ public MethodTypeFlowBuilder createMethodTypeFlowBuilder(PointsToAnalysis bb, Po return new SVMMethodTypeFlowBuilder(bb, method, flowsGraph, graphKind); } - public void registerUsedElements(PointsToAnalysis bb, StructuredGraph graph, boolean registerEmbeddedRoots) { - SVMMethodTypeFlowBuilder.registerUsedElements(bb, graph, registerEmbeddedRoots); + public void registerUsedElements(PointsToAnalysis bb, StructuredGraph graph) { + SVMMethodTypeFlowBuilder.registerUsedElements(bb, graph); } public MetaAccessExtensionProvider createAnalysisMetaAccessExtensionProvider() { diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/NativeImageGenerator.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/NativeImageGenerator.java index 7f984272f9d2..6198083fd1f1 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/NativeImageGenerator.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/NativeImageGenerator.java @@ -1143,7 +1143,7 @@ public static void performSnippetGraphAnalysis(BigBang bb, SubstrateReplacements Collection snippetGraphs = replacements.getSnippetGraphs(GraalOptions.TrackNodeSourcePosition.getValue(options), options); if (bb instanceof NativeImagePointsToAnalysis pointsToAnalysis) { for (StructuredGraph graph : snippetGraphs) { - HostedConfiguration.instance().registerUsedElements(pointsToAnalysis, graph, false); + HostedConfiguration.instance().registerUsedElements(pointsToAnalysis, graph); } } else if (bb instanceof NativeImageReachabilityAnalysisEngine reachabilityAnalysis) { for (StructuredGraph graph : snippetGraphs) { diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/analysis/flow/SVMMethodTypeFlowBuilder.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/analysis/flow/SVMMethodTypeFlowBuilder.java index 726c0e165308..7b6da38e8e38 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/analysis/flow/SVMMethodTypeFlowBuilder.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/analysis/flow/SVMMethodTypeFlowBuilder.java @@ -77,8 +77,8 @@ protected SVMHost getHostVM() { return (SVMHost) bb.getHostVM(); } - public static void registerUsedElements(PointsToAnalysis bb, StructuredGraph graph, boolean registerEmbeddedRoots) { - MethodTypeFlowBuilder.registerUsedElements(bb, graph, registerEmbeddedRoots); + public static void registerUsedElements(PointsToAnalysis bb, StructuredGraph graph) { + MethodTypeFlowBuilder.registerUsedElements(bb, graph); for (Node n : graph.getNodes()) { if (n instanceof ConstantNode) { From 2fc13095c467cef87b155ebe08c38a0e16e121ba Mon Sep 17 00:00:00 2001 From: Codrut Stancu Date: Tue, 5 Dec 2023 11:51:28 +0100 Subject: [PATCH 083/593] Bypass shadow heap reading for hybrid fields. --- .../svm/hosted/image/NativeImageHeap.java | 18 ++++++++++++++---- .../hosted/image/NativeImageHeapWriter.java | 8 ++------ .../meta/HostedConstantReflectionProvider.java | 4 ++++ 3 files changed, 20 insertions(+), 10 deletions(-) diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/NativeImageHeap.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/NativeImageHeap.java index 8ae05374efe3..0eee8b7fa585 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/NativeImageHeap.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/NativeImageHeap.java @@ -47,6 +47,7 @@ import org.graalvm.word.WordBase; import com.oracle.graal.pointsto.heap.ImageHeapConstant; +import com.oracle.graal.pointsto.heap.ImageHeapInstance; import com.oracle.graal.pointsto.heap.ImageHeapScanner; import com.oracle.graal.pointsto.meta.AnalysisUniverse; import com.oracle.graal.pointsto.util.AnalysisError; @@ -68,6 +69,7 @@ import com.oracle.svm.core.util.HostedStringDeduplication; import com.oracle.svm.core.util.UserError; import com.oracle.svm.core.util.VMError; +import com.oracle.svm.hosted.ameta.AnalysisConstantReflectionProvider; import com.oracle.svm.hosted.config.HybridLayout; import com.oracle.svm.hosted.meta.HostedArrayClass; import com.oracle.svm.hosted.meta.HostedClass; @@ -241,8 +243,16 @@ public void addTrailingObjects() { assert addObjectWorklist.isEmpty(); } - private Object readObjectField(HostedField field, JavaConstant receiver) { - return hUniverse.getSnippetReflection().asObject(Object.class, hConstantReflection.readFieldValue(field, receiver)); + /** + * Bypass shadow heap reading for hybrid fields. These fields are not actually present in the + * image, their value is inlined, and are not present in the shadow heap either. + */ + Object readHybridField(HostedField field, JavaConstant receiver) { + VMError.guarantee(HybridLayout.isHybridField(field), "Expected a hybrid field, found %s", field); + JavaConstant hostedReceiver = ((ImageHeapInstance) receiver).getHostedObject(); + /* Use the AnalysisConstantReflectionProvider to get direct access to hosted values. */ + AnalysisConstantReflectionProvider analysisConstantReflection = hConstantReflection.getWrappedConstantReflection(); + return hUniverse.getSnippetReflection().asObject(Object.class, analysisConstantReflection.readHostedFieldValue(hMetaAccess, field.getWrapped(), hostedReceiver)); } private JavaConstant readConstantField(HostedField field, JavaConstant receiver) { @@ -465,14 +475,14 @@ private void addObjectToImageHeap(final JavaConstant constant, boolean immutable boolean shouldBlacklist = !HybridLayout.canHybridFieldsBeDuplicated(clazz); hybridTypeIDSlotsField = hybridLayout.getTypeIDSlotsField(); if (hybridTypeIDSlotsField != null && shouldBlacklist) { - Object typeIDSlots = readObjectField(hybridTypeIDSlotsField, constant); + Object typeIDSlots = readHybridField(hybridTypeIDSlotsField, constant); if (typeIDSlots != null) { blacklist.add(typeIDSlots); } } hybridArrayField = hybridLayout.getArrayField(); - hybridArray = readObjectField(hybridArrayField, constant); + hybridArray = readHybridField(hybridArrayField, constant); if (hybridArray != null && shouldBlacklist) { blacklist.add(hybridArray); written = true; diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/NativeImageHeapWriter.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/NativeImageHeapWriter.java index b2d1ea99dca2..87a5078b4791 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/NativeImageHeapWriter.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/NativeImageHeapWriter.java @@ -123,10 +123,6 @@ private void writeStaticFields(RelocatableBuffer buffer) { } } - private Object readObjectField(HostedField field, JavaConstant receiver) { - return snippetReflection().asObject(Object.class, heap.hConstantReflection.readFieldValue(field, receiver)); - } - private int referenceSize() { return heap.objectLayout.getReferenceSize(); } @@ -343,11 +339,11 @@ private void writeObject(ObjectInfo info, RelocatableBuffer buffer) { Object hybridArray = null; if (hybridLayout != null) { hybridArrayField = hybridLayout.getArrayField(); - hybridArray = readObjectField(hybridArrayField, con); + hybridArray = heap.readHybridField(hybridArrayField, con); hybridTypeIDSlotsField = hybridLayout.getTypeIDSlotsField(); if (hybridTypeIDSlotsField != null) { - short[] typeIDSlots = (short[]) readObjectField(hybridTypeIDSlotsField, con); + short[] typeIDSlots = (short[]) heap.readHybridField(hybridTypeIDSlotsField, con); if (typeIDSlots != null) { int length = typeIDSlots.length; for (int i = 0; i < length; i++) { diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/meta/HostedConstantReflectionProvider.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/meta/HostedConstantReflectionProvider.java index d750349b7d57..c95c53e795b7 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/meta/HostedConstantReflectionProvider.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/meta/HostedConstantReflectionProvider.java @@ -110,6 +110,10 @@ public JavaConstant readFieldValue(ResolvedJavaField field, JavaConstant receive return aConstantReflection.readValue(hMetaAccess, hField.getWrapped(), receiver, true); } + public AnalysisConstantReflectionProvider getWrappedConstantReflection() { + return aConstantReflection; + } + @Override public JavaConstant forString(String value) { return aConstantReflection.forString(value); From 3a92acf0d3e2a28e9a0b6831dc19eed39ca2e4cb Mon Sep 17 00:00:00 2001 From: Codrut Stancu Date: Fri, 1 Dec 2023 00:31:11 +0100 Subject: [PATCH 084/593] Cannot interrogate the heap regarding random objects after layout. --- .../ImageHeapConnectedComponentsPrinter.java | 16 ---------------- 1 file changed, 16 deletions(-) diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/ImageHeapConnectedComponentsPrinter.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/ImageHeapConnectedComponentsPrinter.java index ff00eea47e36..69b3ced80e2c 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/ImageHeapConnectedComponentsPrinter.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/ImageHeapConnectedComponentsPrinter.java @@ -41,8 +41,6 @@ import java.util.stream.Collectors; import com.oracle.graal.pointsto.BigBang; -import com.oracle.svm.core.jdk.Resources; -import com.oracle.svm.core.jdk.resources.ResourceStorageEntryBase; import com.oracle.svm.core.util.VMError; import com.oracle.svm.core.util.json.JsonWriter; import com.oracle.svm.hosted.ByteFormattingUtil; @@ -109,7 +107,6 @@ private static EnumMap groupObjectsByReacha ObjectReachabilityGroup.MethodOrStaticField }; - markResources(heap); EnumMap groups = new EnumMap<>(ObjectReachabilityGroup.class); for (ObjectReachabilityGroup group : objectReachabilityGroupOrder) { groups.put(group, new GroupEntry()); @@ -144,19 +141,6 @@ private static EnumMap groupObjectsByReacha return groups; } - private static void markResources(NativeImageHeap heap) { - for (ResourceStorageEntryBase value : Resources.singleton().resources()) { - if (value.hasData()) { - for (byte[] arr : value.getData()) { - ObjectInfo info = heap.getObjectInfo(arr); - if (info != null) { - heap.objectReachabilityInfo.get(info).addReason(HeapInclusionReason.Resource); - } - } - } - } - } - private ObjectInfoGraph constructGraph(Set objects) { ObjectInfoGraph objectInfoGraph = new ObjectInfoGraph(); for (ObjectInfo objectInfo : objects) { From 9aea25c5877d9e55c2c49992127e26d96406bda2 Mon Sep 17 00:00:00 2001 From: Codrut Stancu Date: Tue, 5 Dec 2023 12:09:32 +0100 Subject: [PATCH 085/593] Seal shadow heap before heap layout. After compilation verify using compilation embedded roots. Allow late scan of some constants. --- .../standalone/StandaloneObjectScanner.java | 8 +- .../pointsto/AbstractAnalysisEngine.java | 4 + .../oracle/graal/pointsto/ObjectScanner.java | 79 +++++++++++++++---- .../pointsto/heap/HeapSnapshotVerifier.java | 32 +++++--- .../graal/pointsto/heap/ImageHeapScanner.java | 15 ++++ .../graal/pointsto/meta/AnalysisUniverse.java | 5 +- .../reports/AnalysisHeapHistogramPrinter.java | 4 +- .../pointsto/reports/ObjectTreePrinter.java | 22 +++--- .../graal/pointsto/reports/ReportUtils.java | 6 ++ .../graal/pointsto/util/AnalysisError.java | 16 ++++ .../svm/hosted/NativeImageGenerator.java | 23 ++++++ .../oracle/svm/hosted/image/NativeImage.java | 3 - .../hosted/image/NativeImageCodeCache.java | 34 +++++--- .../svm/hosted/image/NativeImageHeap.java | 5 ++ .../svm/hosted/meta/UniverseBuilder.java | 3 + 15 files changed, 203 insertions(+), 56 deletions(-) diff --git a/substratevm/src/com.oracle.graal.pointsto.standalone/src/com/oracle/graal/pointsto/standalone/StandaloneObjectScanner.java b/substratevm/src/com.oracle.graal.pointsto.standalone/src/com/oracle/graal/pointsto/standalone/StandaloneObjectScanner.java index 25f8abb1bffa..95944778cc59 100644 --- a/substratevm/src/com.oracle.graal.pointsto.standalone/src/com/oracle/graal/pointsto/standalone/StandaloneObjectScanner.java +++ b/substratevm/src/com.oracle.graal.pointsto.standalone/src/com/oracle/graal/pointsto/standalone/StandaloneObjectScanner.java @@ -26,15 +26,15 @@ package com.oracle.graal.pointsto.standalone; +import java.util.function.Predicate; + import com.oracle.graal.pointsto.BigBang; import com.oracle.graal.pointsto.ObjectScanner; import com.oracle.graal.pointsto.ObjectScanningObserver; import com.oracle.graal.pointsto.meta.AnalysisField; import com.oracle.graal.pointsto.util.CompletionExecutor; -import jdk.vm.ci.code.BytecodePosition; -import jdk.vm.ci.meta.JavaConstant; -import java.util.function.Predicate; +import jdk.vm.ci.meta.JavaConstant; public class StandaloneObjectScanner extends ObjectScanner { @@ -49,7 +49,7 @@ public StandaloneObjectScanner(BigBang bb, CompletionExecutor executor, Reusable } @Override - protected void scanEmbeddedRoot(JavaConstant root, BytecodePosition position) { + protected void scanEmbeddedRoot(JavaConstant root, Object position) { if (shouldScanConstant.test(root)) { super.scanEmbeddedRoot(root, position); } diff --git a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/AbstractAnalysisEngine.java b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/AbstractAnalysisEngine.java index 33e680264228..4edd56cac930 100644 --- a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/AbstractAnalysisEngine.java +++ b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/AbstractAnalysisEngine.java @@ -363,6 +363,10 @@ public static BytecodePosition sourcePosition(ValueNode node) { } /** Creates a synthetic position for the node in the given method. */ + public static BytecodePosition syntheticSourcePosition(ResolvedJavaMethod method) { + return syntheticSourcePosition(null, method); + } + public static BytecodePosition syntheticSourcePosition(Node node, ResolvedJavaMethod method) { int bci = BytecodeFrame.UNKNOWN_BCI; if (node instanceof DeoptBciSupplier) { diff --git a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/ObjectScanner.java b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/ObjectScanner.java index 978be16423c5..f758b428e861 100644 --- a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/ObjectScanner.java +++ b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/ObjectScanner.java @@ -48,7 +48,9 @@ import com.oracle.graal.pointsto.util.AnalysisError; import com.oracle.graal.pointsto.util.CompletionExecutor; +import jdk.graal.compiler.graph.NodeSourcePosition; import jdk.vm.ci.code.BytecodePosition; +import jdk.vm.ci.meta.Constant; import jdk.vm.ci.meta.JavaConstant; import jdk.vm.ci.meta.JavaKind; import jdk.vm.ci.meta.ResolvedJavaField; @@ -85,10 +87,18 @@ public ObjectScanner(BigBang bb, CompletionExecutor executor, ReusableSet scanne } public void scanBootImageHeapRoots() { - scanBootImageHeapRoots(null, null); + scanBootImageHeapRoots(bb.getUniverse().getEmbeddedRoots()); } - public void scanBootImageHeapRoots(Comparator fieldComparator, Comparator embeddedRootComparator) { + public void scanBootImageHeapRoots(Map embeddedConstants) { + scanBootImageHeapRoots(null, null, embeddedConstants); + } + + public void scanBootImageHeapRoots(Comparator fieldComparator, Comparator embeddedRootComparator) { + scanBootImageHeapRoots(fieldComparator, embeddedRootComparator, bb.getUniverse().getEmbeddedRoots()); + } + + public void scanBootImageHeapRoots(Comparator fieldComparator, Comparator embeddedRootComparator, Map embeddedRoots) { // scan the original roots // the original roots are all the static fields, of object type, that were accessed Collection fields = bb.getUniverse().getFields(); @@ -104,13 +114,15 @@ public void scanBootImageHeapRoots(Comparator fieldComparator, Co } // scan the constant nodes - Map embeddedRoots = bb.getUniverse().getEmbeddedRoots(); if (embeddedRootComparator != null) { embeddedRoots.entrySet().stream() .sorted(Map.Entry.comparingByValue(embeddedRootComparator)) - .forEach(entry -> execute(() -> scanEmbeddedRoot(entry.getKey(), entry.getValue()))); + .filter(entry -> entry.getKey() instanceof JavaConstant) + .forEach(entry -> execute(() -> scanEmbeddedRoot((JavaConstant) entry.getKey(), entry.getValue()))); } else { - embeddedRoots.forEach((key, value) -> execute(() -> scanEmbeddedRoot(key, value))); + embeddedRoots.entrySet().stream() + .filter(entry -> entry.getKey() instanceof JavaConstant) + .forEach(entry -> execute(() -> scanEmbeddedRoot((JavaConstant) entry.getKey(), entry.getValue()))); } finish(); @@ -124,18 +136,17 @@ private void execute(Runnable runnable) { } } - protected void scanEmbeddedRoot(JavaConstant root, BytecodePosition position) { + protected void scanEmbeddedRoot(JavaConstant root, Object position) { if (root instanceof ImageHeapConstant ihc && ihc.getHostedObject() == null) { /* Skip embedded simulated constants. */ return; } + EmbeddedRootScan reason = new EmbeddedRootScan(position, root); try { - EmbeddedRootScan reason = new EmbeddedRootScan(position, root); scanningObserver.forEmbeddedRoot(root, reason); scanConstant(root, reason); } catch (UnsupportedFeatureException ex) { - AnalysisMethod method = (AnalysisMethod) position.getMethod(); - bb.getUnsupportedFeatures().addMessage(method.format("%H.%n(%p)"), method, ex.getMessage(), null, ex); + bb.getUnsupportedFeatures().addMessage(reason.toString(), reason.getMethod(), ex.getMessage(), null, ex); } } @@ -520,6 +531,7 @@ public String toString(BigBang bb) { } public static class OtherReason extends ScanReason { + public static final ScanReason LATE_SCAN = new OtherReason("late scan, after sealing heap"); public static final ScanReason UNKNOWN = new OtherReason("manually created constant"); public static final ScanReason RESCAN = new OtherReason("manually triggered rescan"); public static final ScanReason HUB = new OtherReason("scanning a class constant"); @@ -673,29 +685,62 @@ public String toString() { } public static class EmbeddedRootScan extends ScanReason { - final BytecodePosition position; + private final BytecodePosition position; + private final AnalysisMethod method; + private final Object reason; - public EmbeddedRootScan(BytecodePosition nodeSourcePosition, JavaConstant root) { - this(nodeSourcePosition, root, new MethodParsing((AnalysisMethod) nodeSourcePosition.getMethod())); + public EmbeddedRootScan(Object reason, JavaConstant root) { + this(root, reason, rootScanReason(reason)); } - public EmbeddedRootScan(BytecodePosition nodeSourcePosition, JavaConstant root, ScanReason previous) { + private EmbeddedRootScan(JavaConstant root, Object reason, ScanReason previous) { super(previous, root); - this.position = nodeSourcePosition; + this.reason = reason; + if (reason instanceof NodeSourcePosition src) { + this.position = src; + this.method = (AnalysisMethod) src.getMethod(); + } else if (reason instanceof AnalysisMethod met) { + this.method = met; + this.position = null; + } else { + this.method = null; + this.position = null; + } + } + + public Object getReason() { + return reason; } public AnalysisMethod getMethod() { - return (AnalysisMethod) position.getMethod(); + return method; } @Override public String toString(BigBang bb) { - return "scanning root " + asString(bb, constant) + " embedded in " + System.lineSeparator() + INDENTATION_AFTER_NEWLINE + position.getMethod().asStackTraceElement(position.getBCI()); + return "scanning root " + asString(bb, constant) + " embedded in " + System.lineSeparator() + INDENTATION_AFTER_NEWLINE + asStackTraceElement(); } @Override public String toString() { - return position.getMethod().asStackTraceElement(position.getBCI()).toString(); + return asStackTraceElement(); + } + + private static ScanReason rootScanReason(Object reason) { + if (reason instanceof NodeSourcePosition position) { + return new MethodParsing((AnalysisMethod) position.getMethod()); + } + return new OtherReason(reason.toString()); + } + + private String asStackTraceElement() { + if (position != null) { + return String.valueOf(method.asStackTraceElement(position.getBCI())); + } else if (method != null) { + return String.valueOf(method.asStackTraceElement(0)); + } else { + return ""; + } } } diff --git a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/heap/HeapSnapshotVerifier.java b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/heap/HeapSnapshotVerifier.java index b2c61529acb1..287e503cc0b3 100644 --- a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/heap/HeapSnapshotVerifier.java +++ b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/heap/HeapSnapshotVerifier.java @@ -27,6 +27,7 @@ import static com.oracle.graal.pointsto.ObjectScanner.ScanReason; import static com.oracle.graal.pointsto.ObjectScanner.constantAsObject; +import java.util.Map; import java.util.Objects; import java.util.function.Consumer; @@ -42,10 +43,12 @@ import com.oracle.graal.pointsto.util.CompletionExecutor; import com.oracle.svm.util.LogUtils; +import jdk.graal.compiler.core.common.type.CompressibleConstant; import jdk.graal.compiler.debug.DebugContext; import jdk.graal.compiler.options.Option; import jdk.graal.compiler.options.OptionKey; import jdk.graal.compiler.options.OptionType; +import jdk.vm.ci.meta.Constant; import jdk.vm.ci.meta.JavaConstant; import jdk.vm.ci.meta.JavaKind; @@ -76,9 +79,13 @@ public HeapSnapshotVerifier(BigBang bb, ImageHeap imageHeap, ImageHeapScanner sc } public boolean checkHeapSnapshot(DebugContext debug, UniverseMetaAccess metaAccess, String stage) { + return checkHeapSnapshot(debug, metaAccess, stage, bb.getUniverse().getEmbeddedRoots()); + } + + public boolean checkHeapSnapshot(DebugContext debug, UniverseMetaAccess metaAccess, String stage, Map embeddedConstants) { CompletionExecutor executor = new CompletionExecutor(debug, bb); executor.init(); - return checkHeapSnapshot(metaAccess, executor, stage, false); + return checkHeapSnapshot(metaAccess, executor, stage, false, embeddedConstants); } /** @@ -88,6 +95,10 @@ public boolean checkHeapSnapshot(DebugContext debug, UniverseMetaAccess metaAcce * analysis then the heap scanner will also notify the analysis of the new objects. */ public boolean checkHeapSnapshot(UniverseMetaAccess metaAccess, CompletionExecutor executor, String phase, boolean forAnalysis) { + return checkHeapSnapshot(metaAccess, executor, phase, forAnalysis, bb.getUniverse().getEmbeddedRoots()); + } + + public boolean checkHeapSnapshot(UniverseMetaAccess metaAccess, CompletionExecutor executor, String phase, boolean forAnalysis, Map embeddedConstants) { info("Verifying the heap snapshot %s%s ...", phase, (forAnalysis ? ", iteration " + iterations : "")); analysisModified = false; heapPatched = false; @@ -97,7 +108,7 @@ public boolean checkHeapSnapshot(UniverseMetaAccess metaAccess, CompletionExecut ObjectScanner objectScanner = installObjectScanner(metaAccess, executor); executor.start(); scanTypes(objectScanner); - objectScanner.scanBootImageHeapRoots(); + objectScanner.scanBootImageHeapRoots(embeddedConstants); try { executor.complete(); } catch (InterruptedException e) { @@ -314,7 +325,8 @@ private ImageHeapConstant getSnapshot(JavaConstant constant, ScanReason reason) } } if (!result.isReaderInstalled()) { - throw error(reason, "Reader not yet installed for constant %s.", constant); + /* This can be a constant discovered after compilation */ + result.ensureReaderInstalled(); } return result; } @@ -326,7 +338,7 @@ public void forEmbeddedRoot(JavaConstant root, ScanReason reason) { if (rootTask == null) { throw error(reason, "No snapshot task found for embedded root %s %n", root); } else if (rootTask instanceof ImageHeapConstant snapshot) { - verifyEmbeddedRoot(maybeUnwrapSnapshot(snapshot, root instanceof ImageHeapConstant), root, reason); + verifyEmbeddedRoot(maybeUnwrapSnapshot(snapshot, root instanceof ImageHeapConstant), CompressibleConstant.uncompress(root), reason); } else { AnalysisFuture future = (AnalysisFuture) rootTask; if (future.isDone()) { @@ -452,22 +464,22 @@ private void info(String format, Object... args) { } private void warning(ScanReason reason, String format, Object... args) { - LogUtils.warning(message(reason, format, "Value was reached by", args)); + LogUtils.warning(formatReason(bb, reason, format, "Value was reached by", args)); } private void analysisWarning(ScanReason reason, String format, Object... args) { - LogUtils.warning(message(reason, format, "This leads to an analysis state change when", args)); + LogUtils.warning(formatReason(bb, reason, format, "This leads to an analysis state change when", args)); } private RuntimeException error(ScanReason reason, String format, Object... args) { - throw AnalysisError.shouldNotReachHere(message(reason, format, args)); + throw AnalysisError.shouldNotReachHere(formatReason(bb, reason, format, args)); } - private String message(ScanReason reason, String format, Object... args) { - return message(reason, format, "", args); + public static String formatReason(BigBang bb, ScanReason reason, String format, Object... args) { + return formatReason(bb, reason, format, "", args); } - private String message(ScanReason reason, String format, String backtraceHeader, Object... args) { + private static String formatReason(BigBang bb, ScanReason reason, String format, String backtraceHeader, Object... args) { String message = format(bb, format, args); StringBuilder objectBacktrace = new StringBuilder(); ObjectScanner.buildObjectBacktrace(bb, reason, objectBacktrace, backtraceHeader); diff --git a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/heap/ImageHeapScanner.java b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/heap/ImageHeapScanner.java index 67b47fa7b430..139d289349af 100644 --- a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/heap/ImageHeapScanner.java +++ b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/heap/ImageHeapScanner.java @@ -90,6 +90,8 @@ public abstract class ImageHeapScanner { protected ObjectScanningObserver scanningObserver; + private boolean sealed; + public ImageHeapScanner(BigBang bb, ImageHeap heap, AnalysisMetaAccess aMetaAccess, SnippetReflectionProvider aSnippetReflection, ConstantReflectionProvider aConstantReflection, ObjectScanningObserver aScanningObserver) { this.bb = bb; @@ -104,6 +106,10 @@ public ImageHeapScanner(BigBang bb, ImageHeap heap, AnalysisMetaAccess aMetaAcce hostedSnippetReflection = GraalAccess.getOriginalProviders().getSnippetReflection(); } + public void seal() { + this.sealed = true; + } + public void scanEmbeddedRoot(JavaConstant root, BytecodePosition position) { if (isNonNullObjectConstant(root)) { EmbeddedRootScan reason = new EmbeddedRootScan(position, root); @@ -202,6 +208,7 @@ protected ImageHeapConstant getOrCreateImageHeapConstant(JavaConstant javaConsta ScanReason nonNullReason = Objects.requireNonNull(reason); Object existingTask = imageHeap.getSnapshot(javaConstant); if (existingTask == null) { + checkSealed(reason, "Trying to create a new ImageHeapConstant for %s after the ImageHeapScanner is sealed.", javaConstant); AnalysisFuture newTask = new AnalysisFuture<>(() -> { ImageHeapConstant imageHeapConstant = createImageHeapObject(javaConstant, nonNullReason); /* When the image heap object is created replace the future in the map. */ @@ -216,6 +223,12 @@ protected ImageHeapConstant getOrCreateImageHeapConstant(JavaConstant javaConsta return existingTask instanceof ImageHeapConstant ? (ImageHeapConstant) existingTask : ((AnalysisFuture) existingTask).ensureDone(); } + private void checkSealed(ScanReason reason, String format, Object... args) { + if (sealed && reason != OtherReason.LATE_SCAN) { + throw AnalysisError.sealedHeapError(HeapSnapshotVerifier.formatReason(bb, reason, format, args)); + } + } + /** * Create the ImageHeapConstant object wrapper, capture the hosted state of fields and arrays, * and install a future that can process them. @@ -255,6 +268,7 @@ private ImageHeapArray createImageHeapObjectArray(JavaConstant constant, Analysi ImageHeapObjectArray array = new ImageHeapObjectArray(type, constant, length); /* Read hosted array element values only when the array is initialized. */ array.constantData.hostedValuesReader = new AnalysisFuture<>(() -> { + checkSealed(reason, "Trying to materialize an ImageHeapObjectArray for %s after the ImageHeapScanner is sealed.", constant); type.registerAsReachable(reason); ScanReason arrayReason = new ArrayScan(type, array, reason); Object[] elementValues = new Object[length]; @@ -276,6 +290,7 @@ private ImageHeapInstance createImageHeapInstance(JavaConstant constant, Analysi ImageHeapInstance instance = new ImageHeapInstance(type, constant); /* Read hosted field values only when the receiver is initialized. */ instance.constantData.hostedValuesReader = new AnalysisFuture<>(() -> { + checkSealed(reason, "Trying to materialize an ImageHeapInstance for %s after the ImageHeapScanner is sealed.", constant); /* If this is a Class constant register the corresponding type as reachable. */ AnalysisType typeFromClassConstant = (AnalysisType) constantReflection.asJavaType(instance); if (typeFromClassConstant != null) { diff --git a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/meta/AnalysisUniverse.java b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/meta/AnalysisUniverse.java index 9a21efcd0105..4623d41da59a 100644 --- a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/meta/AnalysisUniverse.java +++ b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/meta/AnalysisUniverse.java @@ -64,6 +64,7 @@ import jdk.graal.compiler.core.common.SuppressFBWarnings; import jdk.vm.ci.code.BytecodePosition; import jdk.vm.ci.common.JVMCIError; +import jdk.vm.ci.meta.Constant; import jdk.vm.ci.meta.ConstantPool; import jdk.vm.ci.meta.JavaConstant; import jdk.vm.ci.meta.JavaField; @@ -90,7 +91,7 @@ public class AnalysisUniverse implements Universe { private final ConcurrentMap methods = new ConcurrentHashMap<>(ESTIMATED_METHODS_PER_TYPE * ESTIMATED_NUMBER_OF_TYPES); private final ConcurrentMap, ResolvedSignature> uniqueSignatures = new ConcurrentHashMap<>(); private final ConcurrentMap constantPools = new ConcurrentHashMap<>(ESTIMATED_NUMBER_OF_TYPES); - private final ConcurrentHashMap embeddedRoots = new ConcurrentHashMap<>(ESTIMATED_EMBEDDED_ROOTS); + private final ConcurrentHashMap embeddedRoots = new ConcurrentHashMap<>(ESTIMATED_EMBEDDED_ROOTS); private final ConcurrentMap unsafeAccessedStaticFields = new ConcurrentHashMap<>(); private boolean sealed; @@ -587,7 +588,7 @@ public AnalysisMethod getMethod(ResolvedJavaMethod resolvedJavaMethod) { return methods.get(resolvedJavaMethod); } - public Map getEmbeddedRoots() { + public Map getEmbeddedRoots() { return embeddedRoots; } diff --git a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/reports/AnalysisHeapHistogramPrinter.java b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/reports/AnalysisHeapHistogramPrinter.java index 5e319cfa2702..c5655af0aba4 100644 --- a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/reports/AnalysisHeapHistogramPrinter.java +++ b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/reports/AnalysisHeapHistogramPrinter.java @@ -25,7 +25,7 @@ package com.oracle.graal.pointsto.reports; import static com.oracle.graal.pointsto.reports.ReportUtils.fieldComparator; -import static com.oracle.graal.pointsto.reports.ReportUtils.positionComparator; +import static com.oracle.graal.pointsto.reports.ReportUtils.reasonComparator; import java.io.PrintWriter; import java.util.HashMap; @@ -49,7 +49,7 @@ public static void print(BigBang bb, String reportsPath, String reportName) { private static void doPrint(PrintWriter out, BigBang bb) { Map histogram = new HashMap<>(); AnalysisHeapHistogramPrinter printer = new AnalysisHeapHistogramPrinter(bb, histogram); - printer.scanBootImageHeapRoots(fieldComparator, positionComparator); + printer.scanBootImageHeapRoots(fieldComparator, reasonComparator); printHistogram(out, histogram); } diff --git a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/reports/ObjectTreePrinter.java b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/reports/ObjectTreePrinter.java index 75e0645b4350..b23fa89f1cfe 100644 --- a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/reports/ObjectTreePrinter.java +++ b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/reports/ObjectTreePrinter.java @@ -29,7 +29,7 @@ import static com.oracle.graal.pointsto.reports.ReportUtils.EMPTY_INDENT; import static com.oracle.graal.pointsto.reports.ReportUtils.LAST_CHILD; import static com.oracle.graal.pointsto.reports.ReportUtils.fieldComparator; -import static com.oracle.graal.pointsto.reports.ReportUtils.positionComparator; +import static com.oracle.graal.pointsto.reports.ReportUtils.reasonComparator; import java.io.PrintWriter; import java.util.ArrayDeque; @@ -41,14 +41,13 @@ import java.util.Map; import java.util.Set; -import jdk.graal.compiler.options.OptionValues; - import com.oracle.graal.pointsto.BigBang; import com.oracle.graal.pointsto.ObjectScanner; import com.oracle.graal.pointsto.ObjectScanningObserver; import com.oracle.graal.pointsto.meta.AnalysisField; import com.oracle.graal.pointsto.meta.AnalysisType; +import jdk.graal.compiler.options.OptionValues; import jdk.vm.ci.common.JVMCIError; import jdk.vm.ci.meta.JavaConstant; import jdk.vm.ci.meta.JavaKind; @@ -66,7 +65,7 @@ private static void doPrint(PrintWriter out, BigBang bb) { /* Use linked hash map for predictable iteration order. */ Map constantToNode = new LinkedHashMap<>(); ObjectTreePrinter printer = new ObjectTreePrinter(bb, constantToNode); - printer.scanBootImageHeapRoots(fieldComparator, positionComparator); + printer.scanBootImageHeapRoots(fieldComparator, reasonComparator); printer.printTypeHierarchy(out, constantToNode); } @@ -84,9 +83,10 @@ String format() { } else if (source instanceof ResolvedJavaMethod) { ResolvedJavaMethod method = (ResolvedJavaMethod) source; return method.format("%H.%n(%p)"); - } else { - throw JVMCIError.shouldNotReachHere("unknown source: " + source); + } else if (source != null) { + return source.toString(); } + throw JVMCIError.shouldNotReachHere("null source"); } } @@ -378,9 +378,13 @@ public void forScannedConstant(JavaConstant scannedValue, ScanReason reason) { } else { node = ObjectNodeBase.fromConstant(bb, scannedValue); } - } else if (reason instanceof EmbeddedRootScan) { - ResolvedJavaMethod method = ((EmbeddedRootScan) reason).getMethod(); - node = ObjectNodeBase.fromConstant(bb, scannedValue, new RootSource(method)); + } else if (reason instanceof EmbeddedRootScan embeddedRootScan) { + ResolvedJavaMethod method = embeddedRootScan.getMethod(); + if (method != null) { + node = ObjectNodeBase.fromConstant(bb, scannedValue, new RootSource(method)); + } else { + node = ObjectNodeBase.fromConstant(bb, scannedValue, new RootSource(embeddedRootScan.getReason())); + } } else { node = ObjectNodeBase.fromConstant(bb, scannedValue); } diff --git a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/reports/ReportUtils.java b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/reports/ReportUtils.java index 65ac0a1db934..ddacb8868156 100644 --- a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/reports/ReportUtils.java +++ b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/reports/ReportUtils.java @@ -64,6 +64,12 @@ public class ReportUtils { static final Comparator invokeInfoComparator = invokeInfoBCIComparator.thenComparing(i -> comparingMethodNames(i.getTargetMethod())); static final Comparator positionMethodComparator = Comparator.comparing(pos -> pos.getMethod().format("%H.%n(%P):%R")); static final Comparator positionComparator = positionMethodComparator.thenComparing(pos -> pos.getBCI()); + static final Comparator reasonComparator = (o1, o2) -> { + if (o1 instanceof BytecodePosition p1 && o2 instanceof BytecodePosition p2) { + return positionComparator.compare(p1, p2); + } + return o1.toString().compareTo(o2.toString()); + }; /** * diff --git a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/util/AnalysisError.java b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/util/AnalysisError.java index edc813086f2d..e2d35a7acbce 100644 --- a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/util/AnalysisError.java +++ b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/util/AnalysisError.java @@ -75,6 +75,18 @@ public ResolvedJavaType getType() { } } + /** + * Thrown when trying to snapshot new values after the shadow heap was sealed. + */ + public static class SealedHeapError extends AnalysisError { + + private static final long serialVersionUID = 7057678828508165215L; + + SealedHeapError(String message) { + super(message); + } + } + /** * Thrown when the analysis parsing encounters an error. */ @@ -145,6 +157,10 @@ public static TypeNotFoundError typeNotFound(ResolvedJavaType type) { throw new TypeNotFoundError(type); } + public static SealedHeapError sealedHeapError(String message) { + throw new SealedHeapError(message); + } + public static ParsingError parsingError(AnalysisMethod method, Throwable original) { throw new ParsingError(method, original); } diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/NativeImageGenerator.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/NativeImageGenerator.java index 6198083fd1f1..8909402b84e8 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/NativeImageGenerator.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/NativeImageGenerator.java @@ -56,6 +56,7 @@ import java.util.function.BooleanSupplier; import java.util.stream.Stream; +import jdk.vm.ci.meta.Constant; import org.graalvm.collections.EconomicMap; import org.graalvm.collections.EconomicSet; import org.graalvm.collections.MapCursor; @@ -323,6 +324,7 @@ import jdk.vm.ci.code.TargetDescription; import jdk.vm.ci.hotspot.HotSpotJVMCIRuntime; import jdk.vm.ci.meta.ConstantReflectionProvider; +import jdk.vm.ci.meta.JavaConstant; import jdk.vm.ci.meta.JavaKind; import jdk.vm.ci.meta.MetaAccessProvider; import jdk.vm.ci.meta.ResolvedJavaMethod; @@ -684,6 +686,8 @@ protected void doRun(Map entryPoints, JavaMainSupport j nativeLibraries); featureHandler.forEachFeature(feature -> feature.beforeHeapLayout(beforeLayoutConfig)); + verifyAndSealShadowHeap(codeCache, debug, heap); + buildNativeImageHeap(heap, codeCache); AfterHeapLayoutAccessImpl config = new AfterHeapLayoutAccessImpl(featureHandler, loader, heap, hMetaAccess, debug); @@ -740,6 +744,25 @@ protected void doRun(Map entryPoints, JavaMainSupport j } } + /* + * Re-run shadow heap verification before heap layout. This time the verification uses the + * embedded roots discovered after compilation. + */ + private void verifyAndSealShadowHeap(NativeImageCodeCache codeCache, DebugContext debug, NativeImageHeap heap) { + /* + * Get the embedded constants after compilation to include everything, e.g., interned string + * from snippet lowering that would otherwise be missed. + */ + Map embeddedConstants = codeCache.initAndGetEmbeddedConstants(); + bb.getUniverse().getHeapVerifier().checkHeapSnapshot(debug, heap.hMetaAccess, "before heap layout", embeddedConstants); + /* + * Seal shadow heap after final verification. Any modification to the shadow heap after this + * point, i.e., registering a new ImageHeapConstant or materializing the hosted values + * reader of an existing ImageHeapConstant, will result in an error. + */ + bb.getUniverse().getHeapScanner().seal(); + } + protected void buildNativeImageHeap(NativeImageHeap heap, NativeImageCodeCache codeCache) { // Start building the model of the native image heap. heap.addInitialObjects(); diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/NativeImage.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/NativeImage.java index e88fae28f16c..5cabb9e4183b 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/NativeImage.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/NativeImage.java @@ -420,9 +420,6 @@ public void build(String imageName, DebugContext debug) { BuildPhaseProvider.markHeapLayoutFinished(); - /* Re-run shadow heap verification after heap layout. */ - universe.getBigBang().getUniverse().getHeapVerifier().checkHeapSnapshot(debug, heap.hMetaAccess, "after heap layout"); - imageHeapSize = heapLayout.getImageHeapSize(); // Text section (code) diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/NativeImageCodeCache.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/NativeImageCodeCache.java index 25ec320949e5..a0f94651c576 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/NativeImageCodeCache.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/NativeImageCodeCache.java @@ -55,6 +55,7 @@ import org.graalvm.word.UnsignedWord; import org.graalvm.word.WordFactory; +import com.oracle.graal.pointsto.AbstractAnalysisEngine; import com.oracle.graal.pointsto.BigBang; import com.oracle.graal.pointsto.infrastructure.WrappedElement; import com.oracle.graal.pointsto.meta.AnalysisField; @@ -64,6 +65,7 @@ import com.oracle.graal.pointsto.util.CompletionExecutor; import com.oracle.objectfile.ObjectFile; import com.oracle.svm.common.meta.MultiMethod; +import com.oracle.svm.core.BuildPhaseProvider; import com.oracle.svm.core.SubstrateOptions; import com.oracle.svm.core.code.CodeInfo; import com.oracle.svm.core.code.CodeInfoAccess; @@ -107,6 +109,7 @@ import jdk.graal.compiler.debug.DebugContext; import jdk.graal.compiler.options.Option; import jdk.vm.ci.code.BytecodeFrame; +import jdk.vm.ci.code.BytecodePosition; import jdk.vm.ci.code.site.Call; import jdk.vm.ci.code.site.ConstantReference; import jdk.vm.ci.code.site.DataPatch; @@ -121,6 +124,8 @@ public abstract class NativeImageCodeCache { + private final Map embeddedConstants = new HashMap<>(); + public static class Options { @Option(help = "Verify that all possible deoptimization entry points have been properly compiled and registered in the metadata")// public static final HostedOptionKey VerifyDeoptimizationEntryPoints = new HostedOptionKey<>(false); @@ -216,27 +221,38 @@ public void layoutConstants() { dataSection.close(HostedOptionValues.singleton(), 1); } - public void addConstantsToHeap() { + /** Get constants embedded in the data section and compilation results. */ + public Map initAndGetEmbeddedConstants() { + VMError.guarantee(BuildPhaseProvider.isCompilationFinished(), "Code cache embedded constants are available only after compilation."); + VMError.guarantee(embeddedConstants.isEmpty(), "Embedded constants are already computed."); + for (DataSection.Data data : dataSection) { - if (data instanceof SubstrateDataBuilder.ObjectData) { - JavaConstant constant = ((SubstrateDataBuilder.ObjectData) data).getConstant(); - addConstantToHeap(constant, NativeImageHeap.HeapInclusionReason.DataSection); + if (data instanceof SubstrateDataBuilder.ObjectData objectData) { + embeddedConstants.put(objectData.getConstant(), NativeImageHeap.HeapInclusionReason.DataSection); } } for (Pair pair : getOrderedCompilations()) { + BytecodePosition position = AbstractAnalysisEngine.syntheticSourcePosition(pair.getLeft().getWrapped()); CompilationResult compilationResult = pair.getRight(); for (DataPatch patch : compilationResult.getDataPatches()) { - if (patch.reference instanceof ConstantReference) { - addConstantToHeap(((ConstantReference) patch.reference).getConstant(), compilationResult.getName()); + if (patch.reference instanceof ConstantReference ref) { + embeddedConstants.put(ref.getConstant(), position); } } - for (CompilationResult.CodeAnnotation codeAnnotation : compilationResult.getCodeAnnotations()) { - if (codeAnnotation instanceof HostedImageHeapConstantPatch) { - addConstantToHeap(((HostedImageHeapConstantPatch) codeAnnotation).constant, compilationResult.getName()); + if (codeAnnotation instanceof HostedImageHeapConstantPatch patch) { + embeddedConstants.put(patch.constant, position); } } } + return embeddedConstants; + } + + public void addConstantsToHeap() { + VMError.guarantee(!embeddedConstants.isEmpty(), "Embedded constants should already be computed."); + embeddedConstants.forEach((constant, reason) -> { + addConstantToHeap(constant, reason instanceof BytecodePosition position ? position.getMethod().getName() : reason); + }); } private void addConstantToHeap(Constant constant, Object reason) { diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/NativeImageHeap.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/NativeImageHeap.java index 0eee8b7fa585..3e96712d3c08 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/NativeImageHeap.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/NativeImageHeap.java @@ -46,6 +46,7 @@ import org.graalvm.word.UnsignedWord; import org.graalvm.word.WordBase; +import com.oracle.graal.pointsto.ObjectScanner.OtherReason; import com.oracle.graal.pointsto.heap.ImageHeapConstant; import com.oracle.graal.pointsto.heap.ImageHeapInstance; import com.oracle.graal.pointsto.heap.ImageHeapScanner; @@ -231,6 +232,9 @@ public void addTrailingObjects() { String[] imageInternedStrings = internedStrings.keySet().toArray(new String[0]); Arrays.sort(imageInternedStrings); ImageSingletons.lookup(StringInternSupport.class).setImageInternedStrings(imageInternedStrings); + /* Manually snapshot the interned strings array. */ + aUniverse.getHeapScanner().rescanObject(imageInternedStrings, OtherReason.LATE_SCAN); + addObject(imageInternedStrings, true, HeapInclusionReason.InternedStringsTable); // Process any objects that were transitively added to the heap. @@ -642,6 +646,7 @@ private ObjectInfo addToImageHeap(JavaConstant add, HostedClass clazz, long size public ObjectInfo addLateToImageHeap(Object object, Object reason) { assert !(object instanceof DynamicHub) : "needs a different identity hashcode"; assert !(object instanceof String) : "needs String interning"; + aUniverse.getHeapScanner().rescanObject(object, OtherReason.LATE_SCAN); final Optional optionalType = hMetaAccess.optionalLookupJavaType(object.getClass()); HostedType type = requireType(optionalType, object, reason); diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/meta/UniverseBuilder.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/meta/UniverseBuilder.java index f93ea1d32ff0..6ec22dca79c4 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/meta/UniverseBuilder.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/meta/UniverseBuilder.java @@ -702,6 +702,9 @@ private void layoutStaticFields() { Object[] staticObjectFields = new Object[nextObjectField]; byte[] staticPrimitiveFields = new byte[nextPrimitiveField]; StaticFieldsSupport.setData(staticObjectFields, staticPrimitiveFields); + /* After initializing the static field arrays add them to the shadow heap. */ + aUniverse.getHeapScanner().rescanObject(StaticFieldsSupport.getStaticObjectFields()); + aUniverse.getHeapScanner().rescanObject(StaticFieldsSupport.getStaticPrimitiveFields()); } @SuppressWarnings("unchecked") From 1a043fdff8391b1a0a9120233bb85461468dffa4 Mon Sep 17 00:00:00 2001 From: Codrut Stancu Date: Mon, 4 Dec 2023 22:23:29 +0100 Subject: [PATCH 086/593] Rescan and patch primitive array values after layout. --- .../pointsto/heap/HeapSnapshotVerifier.java | 16 ++++++------ .../graal/pointsto/heap/ImageHeapScanner.java | 25 +++++++++++++------ .../svm/core/image/ImageHeapLayouter.java | 4 +++ .../oracle/svm/hosted/image/NativeImage.java | 2 ++ 4 files changed, 32 insertions(+), 15 deletions(-) diff --git a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/heap/HeapSnapshotVerifier.java b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/heap/HeapSnapshotVerifier.java index 287e503cc0b3..7d222ba76a23 100644 --- a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/heap/HeapSnapshotVerifier.java +++ b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/heap/HeapSnapshotVerifier.java @@ -201,7 +201,7 @@ private void verifyStaticFieldValue(TypeData typeData, AnalysisField field, Java Consumer onAnalysisModified = analysisModified(reason, format, field, unwrappedSnapshot, fieldValue); result = scanner.patchStaticField(typeData, field, fieldValue, reason, onAnalysisModified).ensureDone(); heapPatched = true; - } else if (patchPrimitiveArrayValue(fieldSnapshot, fieldValue)) { + } else if (patchPrimitiveArrayValue(bb, fieldSnapshot, fieldValue)) { heapPatched = true; } scanner.ensureReaderInstalled(result); @@ -215,7 +215,7 @@ private void verifyInstanceFieldValue(AnalysisField field, JavaConstant receiver Consumer onAnalysisModified = analysisModified(reason, format, field, asString(receiver), unwrappedSnapshot, fieldValue); result = scanner.patchInstanceField(receiverObject, field, fieldValue, reason, onAnalysisModified).ensureDone(); heapPatched = true; - } else if (patchPrimitiveArrayValue(fieldSnapshot, fieldValue)) { + } else if (patchPrimitiveArrayValue(bb, fieldSnapshot, fieldValue)) { heapPatched = true; } scanner.ensureReaderInstalled(result); @@ -260,7 +260,7 @@ private boolean verifyArrayElementValue(JavaConstant elementValue, int index, Sc Consumer onAnalysisModified = analysisModified(reason, format, index, asString(array), elementSnapshot, elementValue); result = scanner.patchArrayElement(arrayObject, index, elementValue, reason, onAnalysisModified).ensureDone(); heapPatched = true; - } else if (patchPrimitiveArrayValue(elementSnapshot, elementValue)) { + } else if (patchPrimitiveArrayValue(bb, elementSnapshot, elementValue)) { heapPatched = true; } scanner.ensureReaderInstalled(result); @@ -274,13 +274,13 @@ private boolean verifyArrayElementValue(JavaConstant elementValue, int index, Sc * shadowed object did not change since if that happens then the entire constant should have * been patched instead. */ - private boolean patchPrimitiveArrayValue(JavaConstant snapshot, JavaConstant newValue) { + public static boolean patchPrimitiveArrayValue(BigBang bb, JavaConstant snapshot, JavaConstant newValue) { if (snapshot.isNull()) { AnalysisError.guarantee(newValue.isNull()); return false; } - if (isPrimitiveArrayConstant(snapshot)) { - AnalysisError.guarantee(isPrimitiveArrayConstant(newValue)); + if (isPrimitiveArrayConstant(bb, snapshot)) { + AnalysisError.guarantee(isPrimitiveArrayConstant(bb, newValue)); Object snapshotArray = ((ImageHeapPrimitiveArray) snapshot).getArray(); Object newValueArray = constantAsObject(bb, newValue); if (!Objects.deepEquals(snapshotArray, newValueArray)) { @@ -295,7 +295,7 @@ private boolean patchPrimitiveArrayValue(JavaConstant snapshot, JavaConstant new return false; } - private boolean isPrimitiveArrayConstant(JavaConstant snapshot) { + static boolean isPrimitiveArrayConstant(BigBang bb, JavaConstant snapshot) { if (snapshot.getJavaKind() == JavaKind.Object) { AnalysisType type = bb.getMetaAccess().lookupJavaType(snapshot); return type.isArray() && type.getComponentType().getJavaKind() != JavaKind.Object; @@ -355,7 +355,7 @@ public void forEmbeddedRoot(JavaConstant root, ScanReason reason) { * ImageHeapObject that are not backed by a hosted object, we need to make sure that we * compare it with the correct representation of the snapshot, i.e., without unwrapping it. */ - private JavaConstant maybeUnwrapSnapshot(JavaConstant snapshot, boolean asImageHeapObject) { + public static JavaConstant maybeUnwrapSnapshot(JavaConstant snapshot, boolean asImageHeapObject) { if (snapshot instanceof ImageHeapConstant) { return asImageHeapObject ? snapshot : ((ImageHeapConstant) snapshot).getHostedObject(); } diff --git a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/heap/ImageHeapScanner.java b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/heap/ImageHeapScanner.java index 139d289349af..5ed293358b20 100644 --- a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/heap/ImageHeapScanner.java +++ b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/heap/ImageHeapScanner.java @@ -44,6 +44,7 @@ import com.oracle.graal.pointsto.ObjectScanningObserver; import com.oracle.graal.pointsto.api.HostVM; import com.oracle.graal.pointsto.constraints.UnsupportedFeatureException; +import com.oracle.graal.pointsto.heap.HeapSnapshotVerifier.ScanningObserver; import com.oracle.graal.pointsto.heap.value.ValueSupplier; import com.oracle.graal.pointsto.meta.AnalysisField; import com.oracle.graal.pointsto.meta.AnalysisMetaAccess; @@ -581,13 +582,17 @@ public void rescanRoot(Field reflectionField) { } public void rescanField(Object receiver, Field reflectionField) { + rescanField(receiver, reflectionField, OtherReason.RESCAN); + } + + public void rescanField(Object receiver, Field reflectionField, ScanReason reason) { maybeRunInExecutor(unused -> { AnalysisType type = metaAccess.lookupJavaType(reflectionField.getDeclaringClass()); if (type.isReachable()) { AnalysisField field = metaAccess.lookupJavaField(reflectionField); assert !field.isStatic() : field; JavaConstant receiverConstant = asConstant(receiver); - Optional replaced = maybeReplace(receiverConstant, OtherReason.RESCAN); + Optional replaced = maybeReplace(receiverConstant, reason); if (replaced.isPresent()) { if (replaced.get().isNull()) { /* There was some problem during replacement, bailout. */ @@ -597,12 +602,18 @@ public void rescanField(Object receiver, Field reflectionField) { } JavaConstant fieldValue = readHostedFieldValue(field, universe.toHosted(receiverConstant)).get(); if (fieldValue != null) { - ImageHeapInstance receiverObject = (ImageHeapInstance) toImageHeapObject(receiverConstant, OtherReason.RESCAN); - AnalysisFuture fieldTask = patchInstanceField(receiverObject, field, fieldValue, OtherReason.RESCAN, null); - if (field.isRead() || field.isFolded()) { - JavaConstant constant = fieldTask.ensureDone(); - ensureReaderInstalled(constant); - rescanCollectionElements(constant); + ImageHeapInstance receiverObject = (ImageHeapInstance) toImageHeapObject(receiverConstant, reason); + JavaConstant fieldSnapshot = receiverObject.readFieldValue(field); + JavaConstant unwrappedSnapshot = ScanningObserver.maybeUnwrapSnapshot(fieldSnapshot, fieldValue instanceof ImageHeapConstant); + if (!Objects.equals(unwrappedSnapshot, fieldValue)) { + AnalysisFuture fieldTask = patchInstanceField(receiverObject, field, fieldValue, reason, null); + if (field.isRead() || field.isFolded()) { + JavaConstant constant = fieldTask.ensureDone(); + ensureReaderInstalled(constant); + rescanCollectionElements(constant); + } + } else { + ScanningObserver.patchPrimitiveArrayValue(bb, fieldSnapshot, fieldValue); } } } diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/image/ImageHeapLayouter.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/image/ImageHeapLayouter.java index 94e8f977f811..cd6a55a21b12 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/image/ImageHeapLayouter.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/image/ImageHeapLayouter.java @@ -49,6 +49,10 @@ public interface ImageHeapLayouter { */ ImageHeapLayoutInfo layout(ImageHeap imageHeap, int pageSize); + /** Hook to run tasks after heap layout is finished. */ + default void afterLayout(ImageHeap imageHeap) { + } + /** * Based on the layout decided during an earlier call to {@link #layout}, fill the image heap in * the supplied buffer with additional data structures, if any. At this time, the buffer already diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/NativeImage.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/NativeImage.java index 5cabb9e4183b..dd949466ad9e 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/NativeImage.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/NativeImage.java @@ -420,6 +420,8 @@ public void build(String imageName, DebugContext debug) { BuildPhaseProvider.markHeapLayoutFinished(); + heap.getLayouter().afterLayout(heap); + imageHeapSize = heapLayout.getImageHeapSize(); // Text section (code) From 1068e801b6bfe297c286df33c903fb0b70b02e23 Mon Sep 17 00:00:00 2001 From: Codrut Stancu Date: Tue, 5 Dec 2023 12:06:57 +0100 Subject: [PATCH 087/593] Clean-up HeapSnapshotVerifier. --- .../com/oracle/graal/pointsto/AbstractAnalysisEngine.java | 2 +- .../oracle/graal/pointsto/heap/HeapSnapshotVerifier.java | 8 -------- .../src/com/oracle/svm/hosted/NativeImageGenerator.java | 5 ++--- .../com/oracle/svm/hosted/heap/SVMImageHeapVerifier.java | 7 +++++-- 4 files changed, 8 insertions(+), 14 deletions(-) diff --git a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/AbstractAnalysisEngine.java b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/AbstractAnalysisEngine.java index 4edd56cac930..035cb2da64f0 100644 --- a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/AbstractAnalysisEngine.java +++ b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/AbstractAnalysisEngine.java @@ -211,7 +211,7 @@ private boolean analysisModified() { * checkHeapSnapshot returns all heap scanning and verification tasks are completed. */ assert executor.isBeforeStart() : executor.getState(); - analysisModified = universe.getHeapVerifier().checkHeapSnapshot(metaAccess, executor, "during analysis", true); + analysisModified = universe.getHeapVerifier().checkHeapSnapshot(metaAccess, executor, "during analysis", true, universe.getEmbeddedRoots()); } /* Initialize for the next iteration. */ executor.init(getTiming()); diff --git a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/heap/HeapSnapshotVerifier.java b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/heap/HeapSnapshotVerifier.java index 7d222ba76a23..b8cb9b49b631 100644 --- a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/heap/HeapSnapshotVerifier.java +++ b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/heap/HeapSnapshotVerifier.java @@ -78,10 +78,6 @@ public HeapSnapshotVerifier(BigBang bb, ImageHeap imageHeap, ImageHeapScanner sc verbosity = Options.HeapVerifierVerbosity.getValue(bb.getOptions()); } - public boolean checkHeapSnapshot(DebugContext debug, UniverseMetaAccess metaAccess, String stage) { - return checkHeapSnapshot(debug, metaAccess, stage, bb.getUniverse().getEmbeddedRoots()); - } - public boolean checkHeapSnapshot(DebugContext debug, UniverseMetaAccess metaAccess, String stage, Map embeddedConstants) { CompletionExecutor executor = new CompletionExecutor(debug, bb); executor.init(); @@ -94,10 +90,6 @@ public boolean checkHeapSnapshot(DebugContext debug, UniverseMetaAccess metaAcce * values are found then the verifier automatically patches the shadow heap. If this is during * analysis then the heap scanner will also notify the analysis of the new objects. */ - public boolean checkHeapSnapshot(UniverseMetaAccess metaAccess, CompletionExecutor executor, String phase, boolean forAnalysis) { - return checkHeapSnapshot(metaAccess, executor, phase, forAnalysis, bb.getUniverse().getEmbeddedRoots()); - } - public boolean checkHeapSnapshot(UniverseMetaAccess metaAccess, CompletionExecutor executor, String phase, boolean forAnalysis, Map embeddedConstants) { info("Verifying the heap snapshot %s%s ...", phase, (forAnalysis ? ", iteration " + iterations : "")); analysisModified = false; diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/NativeImageGenerator.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/NativeImageGenerator.java index 8909402b84e8..e4c057db1c9b 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/NativeImageGenerator.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/NativeImageGenerator.java @@ -56,7 +56,6 @@ import java.util.function.BooleanSupplier; import java.util.stream.Stream; -import jdk.vm.ci.meta.Constant; import org.graalvm.collections.EconomicMap; import org.graalvm.collections.EconomicSet; import org.graalvm.collections.MapCursor; @@ -323,8 +322,8 @@ import jdk.vm.ci.code.CodeCacheProvider; import jdk.vm.ci.code.TargetDescription; import jdk.vm.ci.hotspot.HotSpotJVMCIRuntime; +import jdk.vm.ci.meta.Constant; import jdk.vm.ci.meta.ConstantReflectionProvider; -import jdk.vm.ci.meta.JavaConstant; import jdk.vm.ci.meta.JavaKind; import jdk.vm.ci.meta.MetaAccessProvider; import jdk.vm.ci.meta.ResolvedJavaMethod; @@ -673,7 +672,7 @@ protected void doRun(Map entryPoints, JavaMainSupport j } /* Re-run shadow heap verification after compilation. */ - aUniverse.getHeapVerifier().checkHeapSnapshot(debug, hMetaAccess, "after compilation"); + aUniverse.getHeapVerifier().checkHeapSnapshot(debug, hMetaAccess, "after compilation", bb.getUniverse().getEmbeddedRoots()); CodeCacheProvider codeCacheProvider = runtimeConfiguration.getBackendForNormalMethod().getProviders().getCodeCache(); reporter.printCreationStart(); diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/heap/SVMImageHeapVerifier.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/heap/SVMImageHeapVerifier.java index 605e5ad56cb3..d52145742a44 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/heap/SVMImageHeapVerifier.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/heap/SVMImageHeapVerifier.java @@ -24,6 +24,8 @@ */ package com.oracle.svm.hosted.heap; +import java.util.Map; + import org.graalvm.nativeimage.ImageSingletons; import com.oracle.graal.pointsto.BigBang; @@ -41,6 +43,7 @@ import com.oracle.svm.hosted.SVMHost; import com.oracle.svm.hosted.ameta.AnalysisConstantReflectionProvider; +import jdk.vm.ci.meta.Constant; import jdk.vm.ci.meta.JavaConstant; public class SVMImageHeapVerifier extends HeapSnapshotVerifier { @@ -49,8 +52,8 @@ public SVMImageHeapVerifier(BigBang bb, ImageHeap imageHeap, ImageHeapScanner sc } @Override - public boolean checkHeapSnapshot(UniverseMetaAccess metaAccess, CompletionExecutor executor, String phase, boolean forAnalysis) { - return super.checkHeapSnapshot(metaAccess, executor, phase, forAnalysis) || imageStateModified(); + public boolean checkHeapSnapshot(UniverseMetaAccess metaAccess, CompletionExecutor executor, String phase, boolean forAnalysis, Map embeddedConstants) { + return super.checkHeapSnapshot(metaAccess, executor, phase, forAnalysis, embeddedConstants) || imageStateModified(); } /** From fb2c8e63e7410d14bad6a93c007b290b28fbdaa8 Mon Sep 17 00:00:00 2001 From: Danilo Ansaloni Date: Tue, 28 Nov 2023 20:56:53 +0100 Subject: [PATCH 088/593] Deploy language artifacts on JDK-latest. --- vm/ci/ci_common/common.jsonnet | 5 +++++ vm/ci/ci_includes/vm.jsonnet | 5 +++++ 2 files changed, 10 insertions(+) diff --git a/vm/ci/ci_common/common.jsonnet b/vm/ci/ci_common/common.jsonnet index 03b959b72d85..baf66c878835 100644 --- a/vm/ci/ci_common/common.jsonnet +++ b/vm/ci/ci_common/common.jsonnet @@ -863,6 +863,7 @@ local devkits = graal_common.devkits; # Linux/AMD64 # - JDK-Latest deploy_vm_base_javaLatest_linux_amd64: vm.vm_java_Latest + self.full_vm_build_linux_amd64 + self.linux_deploy + self.deploy_vm_linux_amd64 + self.deploy_graalvm_base('latest') + {name: 'post-merge-deploy-vm-base-java-latest-linux-amd64', notify_groups:: ["deploy"]}, + deploy_vm_installables_standalones_javaLatest_linux_amd64: vm.vm_java_Latest + self.full_vm_build_linux_amd64 + self.linux_deploy + self.deploy_daily_vm_linux_amd64 + self.deploy_graalvm_components('latest', installables=false, standalones=true, record_file_sizes=true) + {name: 'daily-deploy-vm-installables-standalones-java-latest-linux-amd64', notify_groups:: ["deploy"]}, # - JDK21 deploy_vm_base_java21_linux_amd64: vm.vm_java_21 + self.full_vm_build_linux_amd64 + self.linux_deploy + self.deploy_vm_linux_amd64 + self.deploy_graalvm_base("java21") + {name: 'post-merge-deploy-vm-base-java21-linux-amd64', notify_groups:: ["deploy"]}, deploy_vm_installables_standalones_java21_linux_amd64: vm.vm_java_21_llvm + self.full_vm_build_linux_amd64 + self.linux_deploy + self.deploy_daily_vm_linux_amd64 + self.deploy_graalvm_components("java21", installables=true, standalones=true, record_file_sizes=true) + {name: 'daily-deploy-vm-installables-standalones-java21-linux-amd64', notify_groups:: ["deploy"]}, @@ -870,6 +871,7 @@ local devkits = graal_common.devkits; # Linux/AARCH64 # - JDK-Latest deploy_vm_base_javaLatest_linux_aarch64: vm.vm_java_Latest + self.full_vm_build_linux_aarch64 + self.linux_deploy + self.deploy_daily_vm_linux_aarch64 + self.deploy_graalvm_base('latest') + {name: 'daily-deploy-vm-base-java-latest-linux-aarch64', notify_groups:: ["deploy"], timelimit: '1:30:00', capabilities+: ["!xgene3"]}, + deploy_vm_installables_standalones_javaLatest_linux_aarch64: vm.vm_java_Latest + self.full_vm_build_linux_aarch64 + self.linux_deploy + self.deploy_daily_vm_linux_aarch64 + self.deploy_graalvm_components('latest', installables=false, standalones=true) + {name: 'daily-deploy-vm-installables-standalones-java-latest-linux-aarch64', notify_groups:: ["deploy"], capabilities+: ["!xgene3"]}, # - JDK21 deploy_vm_base_java21_linux_aarch64: vm.vm_java_21 + self.full_vm_build_linux_aarch64 + self.linux_deploy + self.deploy_daily_vm_linux_aarch64 + self.deploy_graalvm_base("java21") + {name: 'daily-deploy-vm-base-java21-linux-aarch64', notify_groups:: ["deploy"], timelimit: '1:30:00', capabilities+: ["!xgene3"]}, deploy_vm_installables_standalones_java21_linux_aarch64: vm.vm_java_21 + self.full_vm_build_linux_aarch64 + self.linux_deploy + self.deploy_daily_vm_linux_aarch64 + self.deploy_graalvm_components("java21", installables=true, standalones=true) + {name: 'daily-deploy-vm-installables-standalones-java21-linux-aarch64', notify_groups:: ["deploy"], capabilities+: ["!xgene3"]}, @@ -877,6 +879,7 @@ local devkits = graal_common.devkits; # Darwin/AMD64 # - JDK-Latest deploy_vm_base_javaLatest_darwin_amd64: vm.vm_java_Latest + self.full_vm_build_darwin_amd64 + self.darwin_deploy + self.deploy_daily_vm_darwin_amd64 + self.deploy_graalvm_base('latest') + {name: 'daily-deploy-vm-base-java-latest-darwin-amd64', notify_groups:: ["deploy"], timelimit: '1:45:00'}, + deploy_vm_standalones_javaLatest_darwin_amd64: vm.vm_java_Latest + self.full_vm_build_darwin_amd64 + self.darwin_deploy + self.deploy_daily_vm_darwin_amd64 + self.deploy_graalvm_components('latest', installables=false, standalones=true) + {name: 'daily-deploy-vm-standalones-java-latest-darwin-amd64', diskspace_required: "31GB", notify_groups:: ["deploy"], timelimit: '3:00:00'}, # - JDK21 deploy_vm_base_java21_darwin_amd64: vm.vm_java_21 + self.full_vm_build_darwin_amd64 + self.darwin_deploy + self.deploy_daily_vm_darwin_amd64 + self.deploy_graalvm_base("java21") + {name: 'daily-deploy-vm-base-java21-darwin-amd64', notify_groups:: ["deploy"], timelimit: '1:45:00'}, deploy_vm_installables_java21_darwin_amd64: vm.vm_java_21_llvm + self.full_vm_build_darwin_amd64 + self.darwin_deploy + self.deploy_weekly_vm_darwin_amd64 + self.deploy_graalvm_components("java21", installables=true, standalones=false) + {name: 'weekly-deploy-vm-installables-java21-darwin-amd64', diskspace_required: "31GB", notify_groups:: ["deploy"], timelimit: '3:00:00'}, @@ -885,6 +888,7 @@ local devkits = graal_common.devkits; # Darwin/AARCH64 # - JDK-Latest deploy_vm_base_javaLatest_darwin_aarch64: vm.vm_java_Latest + self.full_vm_build_darwin_aarch64 + self.darwin_deploy + self.deploy_daily_vm_darwin_aarch64 + self.deploy_graalvm_base('latest') + {name: 'daily-deploy-vm-base-java-latest-darwin-aarch64', notify_groups:: ["deploy"], notify_emails+: ["bernhard.urban-forster@oracle.com"], timelimit: '1:45:00'}, + deploy_vm_standalones_javaLatest_darwin_aarch64: vm.vm_java_Latest + self.full_vm_build_darwin_aarch64 + self.darwin_deploy + self.deploy_daily_vm_darwin_aarch64 + self.deploy_graalvm_components('latest', installables=false, standalones=true) + {name: 'daily-deploy-vm-standalones-java-latest-darwin-aarch64', diskspace_required: "31GB", notify_groups:: ["deploy"], notify_emails+: ["bernhard.urban-forster@oracle.com"], timelimit: '3:00:00'}, # - JDK21 deploy_vm_base_java21_darwin_aarch64: vm.vm_java_21 + self.full_vm_build_darwin_aarch64 + self.darwin_deploy + self.deploy_daily_vm_darwin_aarch64 + self.deploy_graalvm_base("java21") + {name: 'daily-deploy-vm-base-java21-darwin-aarch64', notify_groups:: ["deploy"], notify_emails+: ["bernhard.urban-forster@oracle.com"], timelimit: '1:45:00'}, deploy_vm_installables_java21_darwin_aarch64: vm.vm_java_21 + self.full_vm_build_darwin_aarch64 + self.darwin_deploy + self.deploy_weekly_vm_darwin_aarch64 + self.deploy_graalvm_components("java21", installables=true, standalones=false) + {name: 'weekly-deploy-vm-installables-java21-darwin-aarch64', diskspace_required: "31GB", notify_groups:: ["deploy"], notify_emails+: ["bernhard.urban-forster@oracle.com"], timelimit: '3:00:00'}, @@ -893,6 +897,7 @@ local devkits = graal_common.devkits; # Windows/AMD64 # - JDK-Latest deploy_vm_base_javaLatest_windows_amd64: vm.vm_java_Latest + self.svm_common_windows_amd64('Latest') + self.js_windows_common + self.deploy_daily_vm_windows_jdkLatest + self.deploy_graalvm_base('latest') + self.deploy_build + {name: 'daily-deploy-vm-base-java-latest-windows-amd64', notify_groups:: ["deploy"], timelimit: '1:30:00'}, + deploy_vm_standalones_javaLatest_windows_amd64: vm.vm_java_Latest + self.svm_common_windows_amd64('Latest') + self.js_windows_common + self.sulong_windows + self.deploy_daily_vm_windows_jdkLatest + self.deploy_graalvm_components('latest', installables=false, standalones=true) + self.deploy_build + {name: 'daily-deploy-vm-standalones-java-latest-windows-amd64', diskspace_required: "31GB", timelimit: '2:30:00', notify_groups:: ["deploy"]}, # - JDK21 deploy_vm_base_java21_windows_amd64: vm.vm_java_21 + self.svm_common_windows_amd64("21") + self.js_windows_common + self.deploy_daily_vm_windows_jdk21 + self.deploy_graalvm_base("java21") + self.deploy_build + {name: 'daily-deploy-vm-base-java21-windows-amd64', notify_groups:: ["deploy"], timelimit: '1:30:00'}, deploy_vm_installables_java21_windows_amd64: vm.vm_java_21 + self.svm_common_windows_amd64("21") + self.js_windows_common + self.sulong_windows + self.deploy_weekly_vm_windows_jdk21 + self.deploy_graalvm_components("java21", installables=true, standalones=false) + self.deploy_build + {name: 'weekly-deploy-vm-installables-java21-windows-amd64', diskspace_required: "31GB", timelimit: '2:30:00', notify_groups:: ["deploy"]}, diff --git a/vm/ci/ci_includes/vm.jsonnet b/vm/ci/ci_includes/vm.jsonnet index 9022f1d43dfe..faacb7c67364 100644 --- a/vm/ci/ci_includes/vm.jsonnet +++ b/vm/ci/ci_includes/vm.jsonnet @@ -196,6 +196,7 @@ local graal_common = import '../../../ci/ci_common/common.jsonnet'; # Linux/AMD64 # - JDK-Latest vm_common.deploy_vm_base_javaLatest_linux_amd64, + vm_common.deploy_vm_installables_standalones_javaLatest_linux_amd64, # - JDK21 vm_common.deploy_vm_base_java21_linux_amd64, vm_common.deploy_vm_installables_standalones_java21_linux_amd64, @@ -203,6 +204,7 @@ local graal_common = import '../../../ci/ci_common/common.jsonnet'; # Linux/AARCH64 # - JDK-Latest vm_common.deploy_vm_base_javaLatest_linux_aarch64, + vm_common.deploy_vm_installables_standalones_javaLatest_linux_aarch64, # - JDK21 vm_common.deploy_vm_base_java21_linux_aarch64, vm_common.deploy_vm_installables_standalones_java21_linux_aarch64, @@ -211,6 +213,7 @@ local graal_common = import '../../../ci/ci_common/common.jsonnet'; # - JDK-Latest # GR-49652 # vm_common.deploy_vm_base_javaLatest_darwin_amd64, + # vm_common.deploy_vm_standalones_javaLatest_darwin_amd64, # - JDK21 vm_common.deploy_vm_base_java21_darwin_amd64, vm_common.deploy_vm_installables_java21_darwin_amd64, @@ -219,6 +222,7 @@ local graal_common = import '../../../ci/ci_common/common.jsonnet'; # Darwin/AARCH64 # - JDK-Latest vm_common.deploy_vm_base_javaLatest_darwin_aarch64, + vm_common.deploy_vm_standalones_javaLatest_darwin_aarch64, # - JDK21 vm_common.deploy_vm_base_java21_darwin_aarch64, vm_common.deploy_vm_installables_java21_darwin_aarch64, @@ -227,6 +231,7 @@ local graal_common = import '../../../ci/ci_common/common.jsonnet'; # Windows/AMD64 # - JDK-Latest vm_common.deploy_vm_base_javaLatest_windows_amd64, + vm_common.deploy_vm_standalones_javaLatest_windows_amd64, # - JDK21 vm_common.deploy_vm_base_java21_windows_amd64, vm_common.deploy_vm_installables_java21_windows_amd64, From 47ae2270718fbed65042d048a6f5c2562700e03c Mon Sep 17 00:00:00 2001 From: Danilo Ansaloni Date: Fri, 1 Dec 2023 19:36:08 +0100 Subject: [PATCH 089/593] Remove Espresso from 'complete' env files. The standalone is anyway deployed differently. --- vm/mx.vm/ce-aarch64-complete | 2 +- vm/mx.vm/ce-complete | 2 +- vm/mx.vm/ce-darwin-aarch64-complete | 2 +- vm/mx.vm/ce-darwin-complete | 2 +- vm/mx.vm/ce-win-complete | 2 +- vm/mx.vm/mx_vm.py | 4 ++-- 6 files changed, 7 insertions(+), 7 deletions(-) diff --git a/vm/mx.vm/ce-aarch64-complete b/vm/mx.vm/ce-aarch64-complete index 5c480169ee4e..f6baf4ac45a5 100644 --- a/vm/mx.vm/ce-aarch64-complete +++ b/vm/mx.vm/ce-aarch64-complete @@ -1,4 +1,4 @@ DYNAMIC_IMPORTS=/compiler,/espresso,/graal-js,/graal-nodejs,/regex,/sdk,/substratevm,/sulong,/tools,/truffle,/wasm,graalpython,truffleruby -COMPONENTS=antlr4,cmp,cov,dap,ejvm,gu,gvm,gwa,icu4j,ins,insight,insightheap,java,js,jsl,jss,lg,llp,llrc,llrl,llrn,lsp,nfi-libffi,ni,nic,nil,njs,njsl,poly,polynative,pro,pyn,pynl,rby,rbyl,rgx,sdk,sdkl,svm,svmt,svml,svmnfi,svmsl,tfl,tfla,tflc,tflm,truffle-json,vvm +COMPONENTS=antlr4,cmp,cov,dap,gu,gvm,gwa,icu4j,ins,insight,insightheap,js,jsl,jss,lg,llp,llrc,llrl,llrn,lsp,nfi-libffi,ni,nic,nil,njs,njsl,poly,polynative,pro,pyn,pynl,rby,rbyl,rgx,sdk,sdkl,svm,svmt,svml,svmnfi,svmsl,tfl,tfla,tflc,tflm,truffle-json,vvm NATIVE_IMAGES=lib:pythonvm,graalvm-native-binutil,graalvm-native-clang,graalvm-native-clang-cl,graalvm-native-clang++,graalvm-native-flang,graalvm-native-ld,lib:jsvm,lib:javavm,lib:graal-nodejs,lib:jvmcicompiler,lib:native-image-agent,lib:native-image-diagnostics-agent,lib:llvmvm,native-image,lib:rubyvm,lib:wasmvm DISABLE_INSTALLABLES=False diff --git a/vm/mx.vm/ce-complete b/vm/mx.vm/ce-complete index d7e168ada21c..e7d93e84b8f1 100644 --- a/vm/mx.vm/ce-complete +++ b/vm/mx.vm/ce-complete @@ -1,4 +1,4 @@ DYNAMIC_IMPORTS=/compiler,/espresso,/graal-js,/graal-nodejs,/regex,/sdk,/substratevm,/sulong,/tools,/truffle,/wasm,fastr,graalpython,truffleruby -COMPONENTS=antlr4,cmp,cov,dap,ellvm,ejvm,gu,gvm,gwa,icu4j,xz,ins,insight,insightheap,java,js,jsl,jss,lg,llp,llrc,llrl,llrn,lsp,nfi-libffi,nfi,ni,nic,nil,njs,njsl,poly,polynative,pro,pyn,pynl,R,rby,rbyl,rgx,sdk,sdkl,svm,svmt,svml,svmnfi,svmsl,tfl,tfla,tflc,tflm,truffle-json,vvm +COMPONENTS=antlr4,cmp,cov,dap,gu,gvm,gwa,icu4j,xz,ins,insight,insightheap,js,jsl,jss,lg,llp,llrc,llrl,llrn,lsp,nfi-libffi,nfi,ni,nic,nil,njs,njsl,poly,polynative,pro,pyn,pynl,R,rby,rbyl,rgx,sdk,sdkl,svm,svmt,svml,svmnfi,svmsl,tfl,tfla,tflc,tflm,truffle-json,vvm NATIVE_IMAGES=lib:pythonvm,graalvm-native-binutil,graalvm-native-clang,graalvm-native-clang-cl,graalvm-native-clang++,graalvm-native-flang,graalvm-native-ld,lib:jsvm,lib:javavm,lib:graal-nodejs,lib:jvmcicompiler,lib:native-image-agent,lib:native-image-diagnostics-agent,lib:llvmvm,native-image,lib:rubyvm,lib:wasmvm DISABLE_INSTALLABLES=false diff --git a/vm/mx.vm/ce-darwin-aarch64-complete b/vm/mx.vm/ce-darwin-aarch64-complete index d557b14bb1b1..617300d1dd2f 100644 --- a/vm/mx.vm/ce-darwin-aarch64-complete +++ b/vm/mx.vm/ce-darwin-aarch64-complete @@ -1,4 +1,4 @@ DYNAMIC_IMPORTS=/compiler,/espresso,/graal-js,/graal-nodejs,/regex,/sdk,/substratevm,/sulong,/tools,/truffle,/wasm,graalpython,truffleruby -COMPONENTS=antlr4,cmp,cov,dap,ejvm,gu,gvm,gwa,icu4j,ins,insight,insightheap,java,js,jsl,jss,lg,llp,llrc,llrl,llrn,lsp,nfi-libffi,nfi,ni,nic,nil,njs,njsl,poly,polynative,pro,pyn,pynl,rby,rbyl,rgx,sdk,sdkl,svm,svmt,svmnfi,svmsl,tfl,tfla,tflc,tflm,truffle-json,vvm +COMPONENTS=antlr4,cmp,cov,dap,gu,gvm,gwa,icu4j,ins,insight,insightheap,js,jsl,jss,lg,llp,llrc,llrl,llrn,lsp,nfi-libffi,nfi,ni,nic,nil,njs,njsl,poly,polynative,pro,pyn,pynl,rby,rbyl,rgx,sdk,sdkl,svm,svmt,svmnfi,svmsl,tfl,tfla,tflc,tflm,truffle-json,vvm NATIVE_IMAGES=lib:pythonvm,graalvm-native-binutil,graalvm-native-clang,graalvm-native-clang-cl,graalvm-native-clang++,graalvm-native-flang,graalvm-native-ld,lib:jsvm,lib:javavm,lib:graal-nodejs,lib:jvmcicompiler,lib:native-image-agent,lib:native-image-diagnostics-agent,lib:llvmvm,native-image,lib:rubyvm,lib:wasmvm DISABLE_INSTALLABLES=false diff --git a/vm/mx.vm/ce-darwin-complete b/vm/mx.vm/ce-darwin-complete index d7e168ada21c..e7d93e84b8f1 100644 --- a/vm/mx.vm/ce-darwin-complete +++ b/vm/mx.vm/ce-darwin-complete @@ -1,4 +1,4 @@ DYNAMIC_IMPORTS=/compiler,/espresso,/graal-js,/graal-nodejs,/regex,/sdk,/substratevm,/sulong,/tools,/truffle,/wasm,fastr,graalpython,truffleruby -COMPONENTS=antlr4,cmp,cov,dap,ellvm,ejvm,gu,gvm,gwa,icu4j,xz,ins,insight,insightheap,java,js,jsl,jss,lg,llp,llrc,llrl,llrn,lsp,nfi-libffi,nfi,ni,nic,nil,njs,njsl,poly,polynative,pro,pyn,pynl,R,rby,rbyl,rgx,sdk,sdkl,svm,svmt,svml,svmnfi,svmsl,tfl,tfla,tflc,tflm,truffle-json,vvm +COMPONENTS=antlr4,cmp,cov,dap,gu,gvm,gwa,icu4j,xz,ins,insight,insightheap,js,jsl,jss,lg,llp,llrc,llrl,llrn,lsp,nfi-libffi,nfi,ni,nic,nil,njs,njsl,poly,polynative,pro,pyn,pynl,R,rby,rbyl,rgx,sdk,sdkl,svm,svmt,svml,svmnfi,svmsl,tfl,tfla,tflc,tflm,truffle-json,vvm NATIVE_IMAGES=lib:pythonvm,graalvm-native-binutil,graalvm-native-clang,graalvm-native-clang-cl,graalvm-native-clang++,graalvm-native-flang,graalvm-native-ld,lib:jsvm,lib:javavm,lib:graal-nodejs,lib:jvmcicompiler,lib:native-image-agent,lib:native-image-diagnostics-agent,lib:llvmvm,native-image,lib:rubyvm,lib:wasmvm DISABLE_INSTALLABLES=false diff --git a/vm/mx.vm/ce-win-complete b/vm/mx.vm/ce-win-complete index 187066b6846c..b23d8849c23d 100644 --- a/vm/mx.vm/ce-win-complete +++ b/vm/mx.vm/ce-win-complete @@ -1,4 +1,4 @@ DYNAMIC_IMPORTS=/compiler,/espresso,/graal-js,/graal-nodejs,/regex,/sdk,/substratevm,/sulong,/tools,/truffle,/wasm,graalpython -COMPONENTS=antlr4,cmp,cov,dap,ejvm,gu,gvm,gwa,icu4j,ins,insight,insightheap,java,js,jsl,jss,lg,llp,llrc,llrl,llrn,lsp,nfi-libffi,nfi,ni,nic,nil,njs,njsl,poly,polynative,pro,pyn,pynl,rgx,sdk,sdkl,svm,svmt,svmnfi,svmsl,tfl,tfla,tflc,tflm,truffle-json,vvm +COMPONENTS=antlr4,cmp,cov,dap,gu,gvm,gwa,icu4j,ins,insight,insightheap,js,jsl,jss,lg,llp,llrc,llrl,llrn,lsp,nfi-libffi,nfi,ni,nic,nil,njs,njsl,poly,polynative,pro,pyn,pynl,rgx,sdk,sdkl,svm,svmt,svmnfi,svmsl,tfl,tfla,tflc,tflm,truffle-json,vvm NATIVE_IMAGES=lib:pythonvm,graalvm-native-binutil,graalvm-native-clang,graalvm-native-clang-cl,graalvm-native-clang++,graalvm-native-flang,graalvm-native-ld,lib:jsvm,lib:javavm,lib:graal-nodejs,lib:jvmcicompiler,lib:native-image-agent,lib:native-image-diagnostics-agent,lib:llvmvm,native-image,lib:wasmvm DISABLE_INSTALLABLES=False diff --git a/vm/mx.vm/mx_vm.py b/vm/mx.vm/mx_vm.py index db4b0894d1a1..635852a4dff4 100644 --- a/vm/mx.vm/mx_vm.py +++ b/vm/mx.vm/mx_vm.py @@ -192,9 +192,9 @@ def local_path_to_url(args): ce_unchained_components = ['bnative-image-configure', 'cmp', 'lg', 'ni', 'nic', 'nil', 'nr_lib_jvmcicompiler', 'sdkc', 'sdkni', 'svm', 'svmforeign', 'svmsl', 'svmt', 'tflc', 'tflsm'] ce_components_minimal = ['bpolyglot', 'cmp', 'cov', 'dap', 'gu', 'gvm', 'ins', 'insight', 'insightheap', 'lg', 'libpoly', 'lsp', 'nfi-libffi', 'nfi', 'poly', 'polynative', 'pro', 'sdk', 'sdkni', 'sdkc', 'sdkl', 'spolyglot', 'tfl', 'tfla', 'tflc', 'tflm', 'truffle-json'] ce_components = ce_components_minimal + ['nr_lib_jvmcicompiler', 'bnative-image-configure', 'ni', 'nic', 'nil', 'svm', 'svmt', 'svmnfi', 'svmsl', 'svmforeign'] -ce_win_complete_components = ['antlr4', 'bnative-image-configure', 'bpolyglot', 'cmp', 'cov', 'dap', 'ejvm', 'gu', 'gvm', 'gwa', 'gwal', 'icu4j', 'xz', 'ins', 'insight', 'insightheap', 'java', 'js', 'jsl', 'jss', 'lg', 'libpoly', 'llp', 'llrc', 'llrl', 'llrlf', 'llrn', 'lsp', 'nfi-libffi', 'nfi', 'ni', 'nic', 'nil', 'njs', 'njsl', 'poly', 'polynative', 'pro', 'pyn', 'pynl', 'rgx', 'sdk', 'sdkni', 'sdkc', 'sdkl', 'spolyglot', 'svm', 'svmt', 'svmnfi', 'svmsl', 'svmforeign', 'tfl', 'tfla', 'tflc', 'tflm', 'truffle-json', 'vvm'] +ce_win_complete_components = ['antlr4', 'bnative-image-configure', 'bpolyglot', 'cmp', 'cov', 'dap', 'gu', 'gvm', 'gwa', 'gwal', 'icu4j', 'xz', 'ins', 'insight', 'insightheap', 'js', 'jsl', 'jss', 'lg', 'libpoly', 'llp', 'llrc', 'llrl', 'llrlf', 'llrn', 'lsp', 'nfi-libffi', 'nfi', 'ni', 'nic', 'nil', 'njs', 'njsl', 'poly', 'polynative', 'pro', 'pyn', 'pynl', 'rgx', 'sdk', 'sdkni', 'sdkc', 'sdkl', 'spolyglot', 'svm', 'svmt', 'svmnfi', 'svmsl', 'svmforeign', 'tfl', 'tfla', 'tflc', 'tflm', 'truffle-json', 'vvm'] ce_aarch64_complete_components = ce_win_complete_components + ['rby', 'rbyl', 'svml'] -ce_complete_components = ce_aarch64_complete_components + ['ellvm', 'R', 'bRMain', 'xz'] +ce_complete_components = ce_aarch64_complete_components + ['R', 'bRMain', 'xz'] ce_darwin_aarch64_complete_components = list(ce_aarch64_complete_components) ce_darwin_aarch64_complete_components.remove('svml') # GR-34811 / GR-40147 ce_ruby_components = ['antlr4', 'cmp', 'cov', 'dap', 'gvm', 'icu4j', 'ins', 'insight', 'insightheap', 'lg', 'llp', 'llrc', 'llrlf', 'llrn', 'lsp', 'nfi-libffi', 'nfi', 'pro', 'rby', 'rbyl', 'rgx', 'sdk', 'sdkni', 'sdkc', 'sdkl', 'tfl', 'tfla', 'tflc', 'tflm', 'truffle-json'] From 9586a40805be4b5738a2e89b425c3a49d3cbe7be Mon Sep 17 00:00:00 2001 From: Danilo Ansaloni Date: Mon, 4 Dec 2023 16:04:10 +0100 Subject: [PATCH 090/593] Publish GraalVM Community for JDK22. --- vm/ce-release-artifacts.json | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/vm/ce-release-artifacts.json b/vm/ce-release-artifacts.json index 23254ffea5b8..6c3d7c5688e5 100644 --- a/vm/ce-release-artifacts.json +++ b/vm/ce-release-artifacts.json @@ -26,6 +26,33 @@ } ] }, + { + "name": "graalvm-community-java22", + "core": true, + "jdk": "jdk_22", + "artifacts": [ + { + "os": "linux", + "arch": "amd64" + }, + { + "os": "linux", + "arch": "aarch64" + }, + { + "os": "darwin", + "arch": "amd64" + }, + { + "os": "darwin", + "arch": "aarch64" + }, + { + "os": "windows", + "arch": "amd64" + } + ] + }, { "name": "maven-bundle-ce", "core": true, From 2c662d60f884922057b6ffebd5711d4a72ea2f33 Mon Sep 17 00:00:00 2001 From: Danilo Ansaloni Date: Mon, 4 Dec 2023 16:51:08 +0100 Subject: [PATCH 091/593] Build GraalVM artifacts for darwin on BigSur. Avoid old hardware when building standalones. --- vm/ci/ci_common/common.jsonnet | 8 ++++---- vm/ci/ci_includes/vm.jsonnet | 5 ++--- 2 files changed, 6 insertions(+), 7 deletions(-) diff --git a/vm/ci/ci_common/common.jsonnet b/vm/ci/ci_common/common.jsonnet index baf66c878835..f02806aa9863 100644 --- a/vm/ci/ci_common/common.jsonnet +++ b/vm/ci/ci_common/common.jsonnet @@ -168,13 +168,13 @@ local devkits = graal_common.devkits; vm_linux_aarch64_ol9: self.common_vm_linux + graal_common.linux_aarch64_ol9, vm_darwin_amd64: self.common_vm_darwin + graal_common.darwin_amd64 + { - capabilities+: ['darwin_mojave', 'ram16gb'], + capabilities+: ['darwin_bigsur', 'ram16gb'], packages+: { gcc: '==4.9.2', }, environment+: { - # for compatibility with macOS Sierra - MACOSX_DEPLOYMENT_TARGET: '10.13', + # for compatibility with macOS BigSur + MACOSX_DEPLOYMENT_TARGET: '11.0', }, }, @@ -879,7 +879,7 @@ local devkits = graal_common.devkits; # Darwin/AMD64 # - JDK-Latest deploy_vm_base_javaLatest_darwin_amd64: vm.vm_java_Latest + self.full_vm_build_darwin_amd64 + self.darwin_deploy + self.deploy_daily_vm_darwin_amd64 + self.deploy_graalvm_base('latest') + {name: 'daily-deploy-vm-base-java-latest-darwin-amd64', notify_groups:: ["deploy"], timelimit: '1:45:00'}, - deploy_vm_standalones_javaLatest_darwin_amd64: vm.vm_java_Latest + self.full_vm_build_darwin_amd64 + self.darwin_deploy + self.deploy_daily_vm_darwin_amd64 + self.deploy_graalvm_components('latest', installables=false, standalones=true) + {name: 'daily-deploy-vm-standalones-java-latest-darwin-amd64', diskspace_required: "31GB", notify_groups:: ["deploy"], timelimit: '3:00:00'}, + deploy_vm_standalones_javaLatest_darwin_amd64: vm.vm_java_Latest + self.full_vm_build_darwin_amd64 + self.darwin_deploy + self.deploy_daily_vm_darwin_amd64 + self.deploy_graalvm_components('latest', installables=false, standalones=true) + {name: 'daily-deploy-vm-standalones-java-latest-darwin-amd64', capabilities+: ["!macmini_late_2014"], diskspace_required: "31GB", notify_groups:: ["deploy"], timelimit: '3:00:00'}, # - JDK21 deploy_vm_base_java21_darwin_amd64: vm.vm_java_21 + self.full_vm_build_darwin_amd64 + self.darwin_deploy + self.deploy_daily_vm_darwin_amd64 + self.deploy_graalvm_base("java21") + {name: 'daily-deploy-vm-base-java21-darwin-amd64', notify_groups:: ["deploy"], timelimit: '1:45:00'}, deploy_vm_installables_java21_darwin_amd64: vm.vm_java_21_llvm + self.full_vm_build_darwin_amd64 + self.darwin_deploy + self.deploy_weekly_vm_darwin_amd64 + self.deploy_graalvm_components("java21", installables=true, standalones=false) + {name: 'weekly-deploy-vm-installables-java21-darwin-amd64', diskspace_required: "31GB", notify_groups:: ["deploy"], timelimit: '3:00:00'}, diff --git a/vm/ci/ci_includes/vm.jsonnet b/vm/ci/ci_includes/vm.jsonnet index faacb7c67364..0325ca9c4d96 100644 --- a/vm/ci/ci_includes/vm.jsonnet +++ b/vm/ci/ci_includes/vm.jsonnet @@ -211,9 +211,8 @@ local graal_common = import '../../../ci/ci_common/common.jsonnet'; # Darwin/AMD64 # - JDK-Latest - # GR-49652 - # vm_common.deploy_vm_base_javaLatest_darwin_amd64, - # vm_common.deploy_vm_standalones_javaLatest_darwin_amd64, + vm_common.deploy_vm_base_javaLatest_darwin_amd64, + vm_common.deploy_vm_standalones_javaLatest_darwin_amd64, # - JDK21 vm_common.deploy_vm_base_java21_darwin_amd64, vm_common.deploy_vm_installables_java21_darwin_amd64, From d38c299552b34a195584e156e79e7a45ba14e6a8 Mon Sep 17 00:00:00 2001 From: Danilo Ansaloni Date: Thu, 2 Nov 2023 14:50:49 +0100 Subject: [PATCH 092/593] Suspend the deployment of FastR on darwin/amd64. --- vm/mx.vm/ce-darwin-complete | 4 ++-- vm/mx.vm/mx_vm.py | 5 ++++- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/vm/mx.vm/ce-darwin-complete b/vm/mx.vm/ce-darwin-complete index e7d93e84b8f1..43434dc25f37 100644 --- a/vm/mx.vm/ce-darwin-complete +++ b/vm/mx.vm/ce-darwin-complete @@ -1,4 +1,4 @@ -DYNAMIC_IMPORTS=/compiler,/espresso,/graal-js,/graal-nodejs,/regex,/sdk,/substratevm,/sulong,/tools,/truffle,/wasm,fastr,graalpython,truffleruby -COMPONENTS=antlr4,cmp,cov,dap,gu,gvm,gwa,icu4j,xz,ins,insight,insightheap,js,jsl,jss,lg,llp,llrc,llrl,llrn,lsp,nfi-libffi,nfi,ni,nic,nil,njs,njsl,poly,polynative,pro,pyn,pynl,R,rby,rbyl,rgx,sdk,sdkl,svm,svmt,svml,svmnfi,svmsl,tfl,tfla,tflc,tflm,truffle-json,vvm +DYNAMIC_IMPORTS=/compiler,/espresso,/graal-js,/graal-nodejs,/regex,/sdk,/substratevm,/sulong,/tools,/truffle,/wasm,graalpython,truffleruby +COMPONENTS=antlr4,cmp,cov,dap,gu,gvm,gwa,icu4j,xz,ins,insight,insightheap,js,jsl,jss,lg,llp,llrc,llrl,llrn,lsp,nfi-libffi,nfi,ni,nic,nil,njs,njsl,poly,polynative,pro,pyn,pynl,rby,rbyl,rgx,sdk,sdkl,svm,svmt,svml,svmnfi,svmsl,tfl,tfla,tflc,tflm,truffle-json,vvm NATIVE_IMAGES=lib:pythonvm,graalvm-native-binutil,graalvm-native-clang,graalvm-native-clang-cl,graalvm-native-clang++,graalvm-native-flang,graalvm-native-ld,lib:jsvm,lib:javavm,lib:graal-nodejs,lib:jvmcicompiler,lib:native-image-agent,lib:native-image-diagnostics-agent,lib:llvmvm,native-image,lib:rubyvm,lib:wasmvm DISABLE_INSTALLABLES=false diff --git a/vm/mx.vm/mx_vm.py b/vm/mx.vm/mx_vm.py index 635852a4dff4..41b91dbe2530 100644 --- a/vm/mx.vm/mx_vm.py +++ b/vm/mx.vm/mx_vm.py @@ -195,6 +195,9 @@ def local_path_to_url(args): ce_win_complete_components = ['antlr4', 'bnative-image-configure', 'bpolyglot', 'cmp', 'cov', 'dap', 'gu', 'gvm', 'gwa', 'gwal', 'icu4j', 'xz', 'ins', 'insight', 'insightheap', 'js', 'jsl', 'jss', 'lg', 'libpoly', 'llp', 'llrc', 'llrl', 'llrlf', 'llrn', 'lsp', 'nfi-libffi', 'nfi', 'ni', 'nic', 'nil', 'njs', 'njsl', 'poly', 'polynative', 'pro', 'pyn', 'pynl', 'rgx', 'sdk', 'sdkni', 'sdkc', 'sdkl', 'spolyglot', 'svm', 'svmt', 'svmnfi', 'svmsl', 'svmforeign', 'tfl', 'tfla', 'tflc', 'tflm', 'truffle-json', 'vvm'] ce_aarch64_complete_components = ce_win_complete_components + ['rby', 'rbyl', 'svml'] ce_complete_components = ce_aarch64_complete_components + ['R', 'bRMain', 'xz'] +ce_darwin_complete_components = list(ce_complete_components) +ce_darwin_complete_components.remove('bRMain') # GR-49842 / GR-49835 +ce_darwin_complete_components.remove('R') # GR-49842 / GR-49835 ce_darwin_aarch64_complete_components = list(ce_aarch64_complete_components) ce_darwin_aarch64_complete_components.remove('svml') # GR-34811 / GR-40147 ce_ruby_components = ['antlr4', 'cmp', 'cov', 'dap', 'gvm', 'icu4j', 'ins', 'insight', 'insightheap', 'lg', 'llp', 'llrc', 'llrlf', 'llrn', 'lsp', 'nfi-libffi', 'nfi', 'pro', 'rby', 'rbyl', 'rgx', 'sdk', 'sdkni', 'sdkc', 'sdkl', 'tfl', 'tfla', 'tflc', 'tflm', 'truffle-json'] @@ -219,7 +222,7 @@ def local_path_to_url(args): mx_sdk_vm.register_vm_config('ce', ce_aarch64_complete_components, _suite, dist_name='ce-aarch64-complete') mx_sdk_vm.register_vm_config('ce', ce_darwin_aarch64_complete_components, _suite, dist_name='ce-darwin-aarch64-complete') mx_sdk_vm.register_vm_config('ce', ce_complete_components, _suite, dist_name='ce-complete') -mx_sdk_vm.register_vm_config('ce', ce_complete_components, _suite, dist_name='ce-complete', env_file='ce-darwin-complete') +mx_sdk_vm.register_vm_config('ce', ce_darwin_complete_components, _suite, dist_name='ce-complete', env_file='ce-darwin-complete') mx_sdk_vm.register_vm_config('ce-python', ce_python_components, _suite) mx_sdk_vm.register_vm_config('ce-fastr', ce_fastr_components, _suite) mx_sdk_vm.register_vm_config('ce-no_native', ce_no_native_components, _suite) From b7edf104adef356da8b646dc6c0bf792d8e0d810 Mon Sep 17 00:00:00 2001 From: Danilo Ansaloni Date: Mon, 4 Dec 2023 18:14:56 +0100 Subject: [PATCH 093/593] Remove duplicated 'xz' entry. --- vm/mx.vm/mx_vm.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vm/mx.vm/mx_vm.py b/vm/mx.vm/mx_vm.py index 41b91dbe2530..eabdad421eb4 100644 --- a/vm/mx.vm/mx_vm.py +++ b/vm/mx.vm/mx_vm.py @@ -194,7 +194,7 @@ def local_path_to_url(args): ce_components = ce_components_minimal + ['nr_lib_jvmcicompiler', 'bnative-image-configure', 'ni', 'nic', 'nil', 'svm', 'svmt', 'svmnfi', 'svmsl', 'svmforeign'] ce_win_complete_components = ['antlr4', 'bnative-image-configure', 'bpolyglot', 'cmp', 'cov', 'dap', 'gu', 'gvm', 'gwa', 'gwal', 'icu4j', 'xz', 'ins', 'insight', 'insightheap', 'js', 'jsl', 'jss', 'lg', 'libpoly', 'llp', 'llrc', 'llrl', 'llrlf', 'llrn', 'lsp', 'nfi-libffi', 'nfi', 'ni', 'nic', 'nil', 'njs', 'njsl', 'poly', 'polynative', 'pro', 'pyn', 'pynl', 'rgx', 'sdk', 'sdkni', 'sdkc', 'sdkl', 'spolyglot', 'svm', 'svmt', 'svmnfi', 'svmsl', 'svmforeign', 'tfl', 'tfla', 'tflc', 'tflm', 'truffle-json', 'vvm'] ce_aarch64_complete_components = ce_win_complete_components + ['rby', 'rbyl', 'svml'] -ce_complete_components = ce_aarch64_complete_components + ['R', 'bRMain', 'xz'] +ce_complete_components = ce_aarch64_complete_components + ['R', 'bRMain'] ce_darwin_complete_components = list(ce_complete_components) ce_darwin_complete_components.remove('bRMain') # GR-49842 / GR-49835 ce_darwin_complete_components.remove('R') # GR-49842 / GR-49835 From aace7fb57e73e4dd8622f50a6115e1ef15f90779 Mon Sep 17 00:00:00 2001 From: Danilo Ansaloni Date: Mon, 4 Dec 2023 19:06:17 +0100 Subject: [PATCH 094/593] Remove GraalVM configs for 'complete' images. We only use them for internal testing and to prepare standalones. We do not need them to have a fixed name. --- vm/mx.vm/mx_vm.py | 13 ------------- 1 file changed, 13 deletions(-) diff --git a/vm/mx.vm/mx_vm.py b/vm/mx.vm/mx_vm.py index eabdad421eb4..dbf53d41f778 100644 --- a/vm/mx.vm/mx_vm.py +++ b/vm/mx.vm/mx_vm.py @@ -192,14 +192,6 @@ def local_path_to_url(args): ce_unchained_components = ['bnative-image-configure', 'cmp', 'lg', 'ni', 'nic', 'nil', 'nr_lib_jvmcicompiler', 'sdkc', 'sdkni', 'svm', 'svmforeign', 'svmsl', 'svmt', 'tflc', 'tflsm'] ce_components_minimal = ['bpolyglot', 'cmp', 'cov', 'dap', 'gu', 'gvm', 'ins', 'insight', 'insightheap', 'lg', 'libpoly', 'lsp', 'nfi-libffi', 'nfi', 'poly', 'polynative', 'pro', 'sdk', 'sdkni', 'sdkc', 'sdkl', 'spolyglot', 'tfl', 'tfla', 'tflc', 'tflm', 'truffle-json'] ce_components = ce_components_minimal + ['nr_lib_jvmcicompiler', 'bnative-image-configure', 'ni', 'nic', 'nil', 'svm', 'svmt', 'svmnfi', 'svmsl', 'svmforeign'] -ce_win_complete_components = ['antlr4', 'bnative-image-configure', 'bpolyglot', 'cmp', 'cov', 'dap', 'gu', 'gvm', 'gwa', 'gwal', 'icu4j', 'xz', 'ins', 'insight', 'insightheap', 'js', 'jsl', 'jss', 'lg', 'libpoly', 'llp', 'llrc', 'llrl', 'llrlf', 'llrn', 'lsp', 'nfi-libffi', 'nfi', 'ni', 'nic', 'nil', 'njs', 'njsl', 'poly', 'polynative', 'pro', 'pyn', 'pynl', 'rgx', 'sdk', 'sdkni', 'sdkc', 'sdkl', 'spolyglot', 'svm', 'svmt', 'svmnfi', 'svmsl', 'svmforeign', 'tfl', 'tfla', 'tflc', 'tflm', 'truffle-json', 'vvm'] -ce_aarch64_complete_components = ce_win_complete_components + ['rby', 'rbyl', 'svml'] -ce_complete_components = ce_aarch64_complete_components + ['R', 'bRMain'] -ce_darwin_complete_components = list(ce_complete_components) -ce_darwin_complete_components.remove('bRMain') # GR-49842 / GR-49835 -ce_darwin_complete_components.remove('R') # GR-49842 / GR-49835 -ce_darwin_aarch64_complete_components = list(ce_aarch64_complete_components) -ce_darwin_aarch64_complete_components.remove('svml') # GR-34811 / GR-40147 ce_ruby_components = ['antlr4', 'cmp', 'cov', 'dap', 'gvm', 'icu4j', 'ins', 'insight', 'insightheap', 'lg', 'llp', 'llrc', 'llrlf', 'llrn', 'lsp', 'nfi-libffi', 'nfi', 'pro', 'rby', 'rbyl', 'rgx', 'sdk', 'sdkni', 'sdkc', 'sdkl', 'tfl', 'tfla', 'tflc', 'tflm', 'truffle-json'] ce_python_components = ['antlr4', 'sllvmvm', 'bpolybench', 'bpolyglot', 'cmp', 'cov', 'dap', 'dis', 'gu', 'gvm', 'icu4j', 'xz', 'ins', 'insight', 'insightheap', 'lg', 'libpoly', 'llp', 'llrc', 'llrl', 'llrlf', 'llrn', 'lsp', 'nfi-libffi', 'nfi', 'pbm', 'pmh', 'poly', 'polynative', 'pro', 'pyn', 'pynl', 'rgx', 'sdk', 'sdkni', 'sdkc', 'sdkl', 'spolyglot', 'tfl', 'tfla', 'tflc', 'tflm', 'truffle-json'] ce_fastr_components = ce_components + llvm_components + ['antlr4', 'xz', 'sllvmvm', 'llp', 'bnative-image', 'snative-image-agent', 'R', 'bRMain', 'bnative-image-configure', 'llrc', 'snative-image-diagnostics-agent', 'llrn', 'llrl', 'llrlf'] @@ -218,11 +210,6 @@ def local_path_to_url(args): mx_sdk_vm.register_vm_config('ce', ce_components + ['icu4j', 'js', 'jsl', 'jss', 'rgx', 'bnative-image', 'snative-image-agent', 'snative-image-diagnostics-agent'], _suite, dist_name='ce-js', env_file='ce-js') mx_sdk_vm.register_vm_config('ce', ce_components + ['icu4j', 'js', 'jsl', 'jss', 'njs', 'njsl', 'rgx', 'sjsvm'], _suite, dist_name='ce', env_file='ce-nodejs') mx_sdk_vm.register_vm_config('ce', ce_components_minimal + ['antlr4', 'llrn', 'llp', 'llrc', 'llrl', 'llrlf'], _suite, env_file='ce-llvm') -mx_sdk_vm.register_vm_config('ce', ce_win_complete_components, _suite, dist_name='ce-win-complete') -mx_sdk_vm.register_vm_config('ce', ce_aarch64_complete_components, _suite, dist_name='ce-aarch64-complete') -mx_sdk_vm.register_vm_config('ce', ce_darwin_aarch64_complete_components, _suite, dist_name='ce-darwin-aarch64-complete') -mx_sdk_vm.register_vm_config('ce', ce_complete_components, _suite, dist_name='ce-complete') -mx_sdk_vm.register_vm_config('ce', ce_darwin_complete_components, _suite, dist_name='ce-complete', env_file='ce-darwin-complete') mx_sdk_vm.register_vm_config('ce-python', ce_python_components, _suite) mx_sdk_vm.register_vm_config('ce-fastr', ce_fastr_components, _suite) mx_sdk_vm.register_vm_config('ce-no_native', ce_no_native_components, _suite) From afe3af9ccd43584974d2770db9a007993c883b4a Mon Sep 17 00:00:00 2001 From: Codrut Stancu Date: Tue, 5 Dec 2023 17:53:30 +0100 Subject: [PATCH 095/593] Fix WordFieldTests_test12. --- .../src/com/oracle/graal/pointsto/ObjectScanner.java | 2 +- .../graal/pointsto/infrastructure/UniverseMetaAccess.java | 5 ++--- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/ObjectScanner.java b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/ObjectScanner.java index 978be16423c5..1c6b63befd31 100644 --- a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/ObjectScanner.java +++ b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/ObjectScanner.java @@ -278,7 +278,7 @@ private void scanArrayElement(JavaConstant array, AnalysisType arrayType, ScanRe } public void scanConstant(JavaConstant value, ScanReason reason) { - if (value.isNull() || bb.getMetaAccess().isInstanceOf(value, WordBase.class)) { + if (value.isNull() || value.getJavaKind().isPrimitive() || bb.getMetaAccess().isInstanceOf(value, WordBase.class)) { return; } JavaConstant unwrappedValue = maybeUnwrap(value); diff --git a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/infrastructure/UniverseMetaAccess.java b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/infrastructure/UniverseMetaAccess.java index c5a3626dd761..f8524f70a105 100644 --- a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/infrastructure/UniverseMetaAccess.java +++ b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/infrastructure/UniverseMetaAccess.java @@ -31,10 +31,9 @@ import java.util.concurrent.ConcurrentHashMap; import java.util.function.Function; -import jdk.graal.compiler.core.common.type.TypedConstant; - import com.oracle.graal.pointsto.meta.AnalysisUniverse; +import jdk.graal.compiler.core.common.type.TypedConstant; import jdk.vm.ci.meta.DeoptimizationAction; import jdk.vm.ci.meta.DeoptimizationReason; import jdk.vm.ci.meta.JavaConstant; @@ -90,7 +89,7 @@ public ResolvedJavaType lookupJavaType(Class clazz) { } public boolean isInstanceOf(JavaConstant constant, Class clazz) { - if (constant == null || constant.isNull()) { + if (constant == null || constant.isNull() || constant.getJavaKind().isPrimitive()) { return false; } return lookupJavaType(clazz).isAssignableFrom(lookupJavaType(constant)); From 030aee8e0f198527935ce338b72bbb4920a6e18b Mon Sep 17 00:00:00 2001 From: Danilo Ansaloni Date: Tue, 5 Dec 2023 18:46:55 +0100 Subject: [PATCH 096/593] Do not build language artifacts on old darwin/amd64 machines. --- vm/ci/ci_common/common.jsonnet | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/vm/ci/ci_common/common.jsonnet b/vm/ci/ci_common/common.jsonnet index f02806aa9863..f7a505c0ceb5 100644 --- a/vm/ci/ci_common/common.jsonnet +++ b/vm/ci/ci_common/common.jsonnet @@ -882,8 +882,8 @@ local devkits = graal_common.devkits; deploy_vm_standalones_javaLatest_darwin_amd64: vm.vm_java_Latest + self.full_vm_build_darwin_amd64 + self.darwin_deploy + self.deploy_daily_vm_darwin_amd64 + self.deploy_graalvm_components('latest', installables=false, standalones=true) + {name: 'daily-deploy-vm-standalones-java-latest-darwin-amd64', capabilities+: ["!macmini_late_2014"], diskspace_required: "31GB", notify_groups:: ["deploy"], timelimit: '3:00:00'}, # - JDK21 deploy_vm_base_java21_darwin_amd64: vm.vm_java_21 + self.full_vm_build_darwin_amd64 + self.darwin_deploy + self.deploy_daily_vm_darwin_amd64 + self.deploy_graalvm_base("java21") + {name: 'daily-deploy-vm-base-java21-darwin-amd64', notify_groups:: ["deploy"], timelimit: '1:45:00'}, - deploy_vm_installables_java21_darwin_amd64: vm.vm_java_21_llvm + self.full_vm_build_darwin_amd64 + self.darwin_deploy + self.deploy_weekly_vm_darwin_amd64 + self.deploy_graalvm_components("java21", installables=true, standalones=false) + {name: 'weekly-deploy-vm-installables-java21-darwin-amd64', diskspace_required: "31GB", notify_groups:: ["deploy"], timelimit: '3:00:00'}, - deploy_vm_standalones_java21_darwin_amd64: vm.vm_java_21_llvm + self.full_vm_build_darwin_amd64 + self.darwin_deploy + self.deploy_daily_vm_darwin_amd64 + self.deploy_graalvm_components("java21", installables=false, standalones=true) + {name: 'daily-deploy-vm-standalones-java21-darwin-amd64', diskspace_required: "31GB", notify_groups:: ["deploy"], timelimit: '3:00:00'}, + deploy_vm_installables_java21_darwin_amd64: vm.vm_java_21_llvm + self.full_vm_build_darwin_amd64 + self.darwin_deploy + self.deploy_weekly_vm_darwin_amd64 + self.deploy_graalvm_components("java21", installables=true, standalones=false) + {name: 'weekly-deploy-vm-installables-java21-darwin-amd64', capabilities+: ["!macmini_late_2014"], diskspace_required: "31GB", notify_groups:: ["deploy"], timelimit: '3:00:00'}, + deploy_vm_standalones_java21_darwin_amd64: vm.vm_java_21_llvm + self.full_vm_build_darwin_amd64 + self.darwin_deploy + self.deploy_daily_vm_darwin_amd64 + self.deploy_graalvm_components("java21", installables=false, standalones=true) + {name: 'daily-deploy-vm-standalones-java21-darwin-amd64', capabilities+: ["!macmini_late_2014"], diskspace_required: "31GB", notify_groups:: ["deploy"], timelimit: '3:00:00'}, # Darwin/AARCH64 # - JDK-Latest From 503c312826eb11c85ffcf334f28dc19028089f75 Mon Sep 17 00:00:00 2001 From: Tomas Zezula Date: Tue, 5 Dec 2023 18:51:13 +0100 Subject: [PATCH 097/593] [GR-50682] Quarkus fails even if class loader disabled. --- .../com/oracle/truffle/polyglot/EngineAccessor.java | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/truffle/src/com.oracle.truffle.polyglot/src/com/oracle/truffle/polyglot/EngineAccessor.java b/truffle/src/com.oracle.truffle.polyglot/src/com/oracle/truffle/polyglot/EngineAccessor.java index bef1cf3482ce..45997a160608 100644 --- a/truffle/src/com.oracle.truffle.polyglot/src/com/oracle/truffle/polyglot/EngineAccessor.java +++ b/truffle/src/com.oracle.truffle.polyglot/src/com/oracle/truffle/polyglot/EngineAccessor.java @@ -166,9 +166,13 @@ private static List locatorLoaders() { } private static List defaultLoaders() { - return List.of(new StrongClassLoaderSupplier(EngineAccessor.class.getClassLoader()), - new StrongClassLoaderSupplier(ClassLoader.getSystemClassLoader()), - new WeakClassLoaderSupplier(Thread.currentThread().getContextClassLoader())); + ClassLoader contextClassLoader = Thread.currentThread().getContextClassLoader(); + if (contextClassLoader != null) { + return List.of(new WeakClassLoaderSupplier(contextClassLoader)); + } else { + return List.of(new StrongClassLoaderSupplier(EngineAccessor.class.getClassLoader()), + new StrongClassLoaderSupplier(ClassLoader.getSystemClassLoader())); + } } static List locatorOrDefaultLoaders() { From e8726137ce30f4bb1125900d9b0b5311b5eb2b77 Mon Sep 17 00:00:00 2001 From: Christian Wimmer Date: Tue, 5 Dec 2023 10:37:29 -0800 Subject: [PATCH 098/593] Clean up providers mechanism --- .../core/common/spi/CodeGenProviders.java | 46 -------------- .../compiler/hotspot/HotSpotLIRGenerator.java | 2 - .../AArch64HotSpotDeoptimizeCallerOp.java | 2 +- .../aarch64/AArch64HotSpotDeoptimizeOp.java | 2 +- ...otSpotDeoptimizeWithExceptionCallerOp.java | 3 +- .../aarch64/AArch64HotSpotEpilogueOp.java | 3 +- .../aarch64/AArch64HotSpotSafepointOp.java | 2 +- .../aarch64/AArch64HotSpotUnwindOp.java | 3 +- .../hotspot/amd64/AMD64DeoptimizeOp.java | 2 +- .../amd64/AMD64HotSpotDeoptimizeCallerOp.java | 2 +- ...otSpotDeoptimizeWithExceptionCallerOp.java | 2 +- .../hotspot/amd64/AMD64HotSpotReturnOp.java | 2 +- .../amd64/AMD64HotSpotSafepointOp.java | 2 +- .../hotspot/amd64/AMD64HotSpotUnwindOp.java | 2 +- .../lir/asm/CompilationResultBuilder.java | 16 ++--- .../asm/CompilationResultBuilderFactory.java | 8 +-- .../compiler/lir/asm/EntryPointDecorator.java | 4 +- .../graal/compiler/lir/gen/LIRGenerator.java | 34 ++-------- .../compiler/lir/gen/LIRGeneratorTool.java | 16 +---- .../compiler/nodes/spi/CoreProviders.java | 7 ++- .../nodes/spi/CoreProvidersDelegate.java | 12 +++- .../compiler/nodes/spi/WordVerification.java | 63 ------------------- .../graal/compiler/phases/util/Providers.java | 14 +---- .../hotspot/TruffleEntryPointDecorator.java | 5 +- ...fleCallBoundaryInstrumentationFactory.java | 7 +-- ...fleCallBoundaryInstrumentationFactory.java | 9 ++- .../compiler/word/WordVerificationImpl.java | 52 --------------- .../amd64/AMD64CalleeSavedRegisters.java | 7 +-- .../svm/core/graal/llvm/LLVMGenerator.java | 29 +-------- .../graal/meta/SubstrateReplacements.java | 33 +++++----- .../thread/VMThreadLocalSTHolderNode.java | 12 ++-- .../ParseOnceRuntimeCompilationFeature.java | 7 +-- .../SubstrateRuntimeConfigurationBuilder.java | 3 +- .../svm/hosted/NativeImageGenerator.java | 2 +- .../src/com/oracle/svm/hosted/SVMHost.java | 2 +- .../ClassInitializerGraphBuilderPhase.java | 36 ++++++++--- .../oracle/svm/hosted/code/CompileQueue.java | 8 +-- .../svm/hosted/code/HostedReplacements.java | 18 +++--- .../HostedRuntimeConfigurationBuilder.java | 2 +- .../svm/hosted/code/SubstrateGraphMaker.java | 13 ++-- .../code/SubstrateGraphMakerFactory.java | 16 ++--- .../phases/AnalysisGraphBuilderPhase.java | 5 +- .../phases/SharedGraphBuilderPhase.java | 12 +--- .../phases/SubstrateGraphBuilderPhase.java | 10 ++- 44 files changed, 144 insertions(+), 393 deletions(-) delete mode 100644 compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/core/common/spi/CodeGenProviders.java delete mode 100644 compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/nodes/spi/WordVerification.java delete mode 100644 compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/word/WordVerificationImpl.java diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/core/common/spi/CodeGenProviders.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/core/common/spi/CodeGenProviders.java deleted file mode 100644 index 66f85ae0ac49..000000000000 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/core/common/spi/CodeGenProviders.java +++ /dev/null @@ -1,46 +0,0 @@ -/* - * Copyright (c) 2013, 2021, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package jdk.graal.compiler.core.common.spi; - -import jdk.vm.ci.code.CodeCacheProvider; -import jdk.vm.ci.meta.ConstantReflectionProvider; -import jdk.vm.ci.meta.MetaAccessProvider; - -/** - * A set of providers which are required for LIR and/or code generation. Some may not be present - * (i.e., null). - */ -public interface CodeGenProviders { - - MetaAccessProvider getMetaAccess(); - - CodeCacheProvider getCodeCache(); - - ForeignCallsProvider getForeignCalls(); - - ConstantReflectionProvider getConstantReflection(); - - MetaAccessExtensionProvider getMetaAccessExtensionProvider(); -} diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/HotSpotLIRGenerator.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/HotSpotLIRGenerator.java index 54dfc9d55d31..2085def9ea1c 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/HotSpotLIRGenerator.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/HotSpotLIRGenerator.java @@ -58,7 +58,5 @@ public interface HotSpotLIRGenerator extends LIRGeneratorTool { */ VirtualStackSlot getLockSlot(int lockDepth); - @Override HotSpotProviders getProviders(); - } diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/aarch64/AArch64HotSpotDeoptimizeCallerOp.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/aarch64/AArch64HotSpotDeoptimizeCallerOp.java index 6c428129911e..80149d6225f0 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/aarch64/AArch64HotSpotDeoptimizeCallerOp.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/aarch64/AArch64HotSpotDeoptimizeCallerOp.java @@ -46,6 +46,6 @@ public AArch64HotSpotDeoptimizeCallerOp(GraalHotSpotVMConfig config) { @Override public void emitCode(CompilationResultBuilder crb, AArch64MacroAssembler masm) { leaveFrame(crb, masm, /* emitSafepoint */false, false); - AArch64Call.directJmp(crb, masm, crb.foreignCalls.lookupForeignCall(HotSpotHostBackend.DEOPT_BLOB_UNCOMMON_TRAP)); + AArch64Call.directJmp(crb, masm, crb.getForeignCalls().lookupForeignCall(HotSpotHostBackend.DEOPT_BLOB_UNCOMMON_TRAP)); } } diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/aarch64/AArch64HotSpotDeoptimizeOp.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/aarch64/AArch64HotSpotDeoptimizeOp.java index 5622fad69628..210bde6e8c69 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/aarch64/AArch64HotSpotDeoptimizeOp.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/aarch64/AArch64HotSpotDeoptimizeOp.java @@ -48,7 +48,7 @@ public AArch64HotSpotDeoptimizeOp(LIRFrameState info) { @Override public void emitCode(CompilationResultBuilder crb, AArch64MacroAssembler masm) { try (AArch64MacroAssembler.ScratchRegister scratch = masm.getScratchRegister()) { - AArch64Call.directCall(crb, masm, crb.foreignCalls.lookupForeignCall(HotSpotHostBackend.DEOPT_BLOB_UNCOMMON_TRAP), scratch.getRegister(), info, null); + AArch64Call.directCall(crb, masm, crb.getForeignCalls().lookupForeignCall(HotSpotHostBackend.DEOPT_BLOB_UNCOMMON_TRAP), scratch.getRegister(), info, null); } } diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/aarch64/AArch64HotSpotDeoptimizeWithExceptionCallerOp.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/aarch64/AArch64HotSpotDeoptimizeWithExceptionCallerOp.java index 4542a15e3b49..434078db164d 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/aarch64/AArch64HotSpotDeoptimizeWithExceptionCallerOp.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/aarch64/AArch64HotSpotDeoptimizeWithExceptionCallerOp.java @@ -34,7 +34,6 @@ import jdk.graal.compiler.lir.Opcode; import jdk.graal.compiler.lir.aarch64.AArch64Call; import jdk.graal.compiler.lir.asm.CompilationResultBuilder; - import jdk.vm.ci.code.Register; import jdk.vm.ci.meta.Value; @@ -63,6 +62,6 @@ public void emitCode(CompilationResultBuilder crb, AArch64MacroAssembler masm) { // Store original return address in TLS masm.str(64, lr, masm.makeAddress(64, thread, config.threadExceptionPcOffset)); - AArch64Call.directJmp(crb, masm, crb.foreignCalls.lookupForeignCall(HotSpotHostBackend.DEOPT_BLOB_UNPACK_WITH_EXCEPTION_IN_TLS)); + AArch64Call.directJmp(crb, masm, crb.getForeignCalls().lookupForeignCall(HotSpotHostBackend.DEOPT_BLOB_UNPACK_WITH_EXCEPTION_IN_TLS)); } } diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/aarch64/AArch64HotSpotEpilogueOp.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/aarch64/AArch64HotSpotEpilogueOp.java index be01476c66cb..781f0f40c991 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/aarch64/AArch64HotSpotEpilogueOp.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/aarch64/AArch64HotSpotEpilogueOp.java @@ -42,7 +42,6 @@ import jdk.graal.compiler.lir.aarch64.AArch64BlockEndOp; import jdk.graal.compiler.lir.aarch64.AArch64Call; import jdk.graal.compiler.lir.asm.CompilationResultBuilder; - import jdk.vm.ci.code.CallingConvention; import jdk.vm.ci.code.Register; import jdk.vm.ci.code.RegisterValue; @@ -71,7 +70,7 @@ protected void leaveFrame(CompilationResultBuilder crb, AArch64MacroAssembler ma assert crb.frameContext != null : "We never elide frames in aarch64"; crb.frameContext.leave(crb); if (requiresReservedStackAccessCheck) { - HotSpotForeignCallsProvider foreignCalls = (HotSpotForeignCallsProvider) crb.foreignCalls; + HotSpotForeignCallsProvider foreignCalls = (HotSpotForeignCallsProvider) crb.getForeignCalls(); Label noReserved = new Label(); try (ScratchRegister sc = masm.getScratchRegister()) { Register scratch = sc.getRegister(); diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/aarch64/AArch64HotSpotSafepointOp.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/aarch64/AArch64HotSpotSafepointOp.java index cebe4bf59960..4ed74a10afcc 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/aarch64/AArch64HotSpotSafepointOp.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/aarch64/AArch64HotSpotSafepointOp.java @@ -88,7 +88,7 @@ public static void emitCode(CompilationResultBuilder crb, AArch64MacroAssembler // store mark pc in scratch masm.adr(scratch, poll); masm.str(64, scratch, masm.makeAddress(64, thread, config.savedExceptionPCOffset)); - AArch64Call.directJmp(crb, masm, crb.foreignCalls.lookupForeignCall(HotSpotHostBackend.POLLING_PAGE_RETURN_HANDLER)); + AArch64Call.directJmp(crb, masm, crb.getForeignCalls().lookupForeignCall(HotSpotHostBackend.POLLING_PAGE_RETURN_HANDLER)); }); } else { masm.ldr(64, scratch, masm.makeAddress(64, thread, config.threadPollingPageOffset, scratch)); diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/aarch64/AArch64HotSpotUnwindOp.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/aarch64/AArch64HotSpotUnwindOp.java index dcd6881fba9c..8a76634781c6 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/aarch64/AArch64HotSpotUnwindOp.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/aarch64/AArch64HotSpotUnwindOp.java @@ -36,7 +36,6 @@ import jdk.graal.compiler.lir.Opcode; import jdk.graal.compiler.lir.aarch64.AArch64Call; import jdk.graal.compiler.lir.asm.CompilationResultBuilder; - import jdk.vm.ci.code.CallingConvention; import jdk.vm.ci.code.Register; import jdk.vm.ci.code.RegisterValue; @@ -59,7 +58,7 @@ public AArch64HotSpotUnwindOp(GraalHotSpotVMConfig config, RegisterValue excepti public void emitCode(CompilationResultBuilder crb, AArch64MacroAssembler masm) { leaveFrame(crb, masm, /* emitSafepoint */false, false); - ForeignCallLinkage linkage = crb.foreignCalls.lookupForeignCall(HotSpotBackend.UNWIND_EXCEPTION_TO_CALLER); + ForeignCallLinkage linkage = crb.getForeignCalls().lookupForeignCall(HotSpotBackend.UNWIND_EXCEPTION_TO_CALLER); CallingConvention cc = linkage.getOutgoingCallingConvention(); assert cc.getArgumentCount() == 2 : cc; assert exception.equals(cc.getArgument(0)); diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/amd64/AMD64DeoptimizeOp.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/amd64/AMD64DeoptimizeOp.java index 5617afed38ba..8ae8ea2471bf 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/amd64/AMD64DeoptimizeOp.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/amd64/AMD64DeoptimizeOp.java @@ -48,6 +48,6 @@ final class AMD64DeoptimizeOp extends AMD64BlockEndOp implements BlockEndOp { @Override public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) { - AMD64Call.directCall(crb, masm, crb.foreignCalls.lookupForeignCall(DEOPT_BLOB_UNCOMMON_TRAP), null, false, info); + AMD64Call.directCall(crb, masm, crb.getForeignCalls().lookupForeignCall(DEOPT_BLOB_UNCOMMON_TRAP), null, false, info); } } diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/amd64/AMD64HotSpotDeoptimizeCallerOp.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/amd64/AMD64HotSpotDeoptimizeCallerOp.java index d6d4bd48c52a..6b5bd4ada654 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/amd64/AMD64HotSpotDeoptimizeCallerOp.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/amd64/AMD64HotSpotDeoptimizeCallerOp.java @@ -46,6 +46,6 @@ protected AMD64HotSpotDeoptimizeCallerOp() { @Override public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) { leaveFrameAndRestoreRbp(crb, masm); - AMD64Call.directJmp(crb, masm, crb.foreignCalls.lookupForeignCall(HotSpotHostBackend.DEOPT_BLOB_UNCOMMON_TRAP), null); + AMD64Call.directJmp(crb, masm, crb.getForeignCalls().lookupForeignCall(HotSpotHostBackend.DEOPT_BLOB_UNCOMMON_TRAP), null); } } diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/amd64/AMD64HotSpotDeoptimizeWithExceptionCallerOp.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/amd64/AMD64HotSpotDeoptimizeWithExceptionCallerOp.java index b3040e284817..a6a4397b9b73 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/amd64/AMD64HotSpotDeoptimizeWithExceptionCallerOp.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/amd64/AMD64HotSpotDeoptimizeWithExceptionCallerOp.java @@ -73,6 +73,6 @@ public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) { // Remove return address. masm.addq(stackPointer, crb.target.arch.getReturnAddressSize()); - AMD64Call.directJmp(crb, masm, crb.foreignCalls.lookupForeignCall(DEOPT_BLOB_UNPACK_WITH_EXCEPTION_IN_TLS), null); + AMD64Call.directJmp(crb, masm, crb.getForeignCalls().lookupForeignCall(DEOPT_BLOB_UNPACK_WITH_EXCEPTION_IN_TLS), null); } } diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/amd64/AMD64HotSpotReturnOp.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/amd64/AMD64HotSpotReturnOp.java index 0cc1c6c21205..eae40ec866db 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/amd64/AMD64HotSpotReturnOp.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/amd64/AMD64HotSpotReturnOp.java @@ -79,7 +79,7 @@ public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) { if (!isStub) { if (requiresReservedStackAccessCheck) { assert scratchForSafepointOnReturn != null; - HotSpotForeignCallsProvider foreignCalls = (HotSpotForeignCallsProvider) crb.foreignCalls; + HotSpotForeignCallsProvider foreignCalls = (HotSpotForeignCallsProvider) crb.getForeignCalls(); Label noReserved = new Label(); masm.cmpqAndJcc(rsp, new AMD64Address(r15, config.javaThreadReservedStackActivationOffset), ConditionFlag.Below, noReserved, true); diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/amd64/AMD64HotSpotSafepointOp.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/amd64/AMD64HotSpotSafepointOp.java index 14313d3013cb..c888578bf5bb 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/amd64/AMD64HotSpotSafepointOp.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/amd64/AMD64HotSpotSafepointOp.java @@ -101,7 +101,7 @@ public static void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler as final int afterLea = asm.position(); asm.emitInt(pos[0] - afterLea, afterLea - 4); asm.movq(new AMD64Address(r15, config.savedExceptionPCOffset), scratch); - AMD64Call.directJmp(crb, asm, crb.foreignCalls.lookupForeignCall(POLLING_PAGE_RETURN_HANDLER), null); + AMD64Call.directJmp(crb, asm, crb.getForeignCalls().lookupForeignCall(POLLING_PAGE_RETURN_HANDLER), null); }); } else { asm.movptr(scratch, new AMD64Address(thread, config.threadPollingPageOffset)); diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/amd64/AMD64HotSpotUnwindOp.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/amd64/AMD64HotSpotUnwindOp.java index 122ab74819a0..53ed412d8cb4 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/amd64/AMD64HotSpotUnwindOp.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/amd64/AMD64HotSpotUnwindOp.java @@ -60,7 +60,7 @@ final class AMD64HotSpotUnwindOp extends AMD64HotSpotEpilogueBlockEndOp { public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) { leaveFrameAndRestoreRbp(crb, masm); - ForeignCallLinkage linkage = crb.foreignCalls.lookupForeignCall(HotSpotBackend.UNWIND_EXCEPTION_TO_CALLER); + ForeignCallLinkage linkage = crb.getForeignCalls().lookupForeignCall(HotSpotBackend.UNWIND_EXCEPTION_TO_CALLER); CallingConvention cc = linkage.getOutgoingCallingConvention(); assert cc.getArgumentCount() == 2 : cc; assert exception.equals(cc.getArgument(0)); diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/asm/CompilationResultBuilder.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/asm/CompilationResultBuilder.java index 44e2a278abe3..bd3c9f4da803 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/asm/CompilationResultBuilder.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/asm/CompilationResultBuilder.java @@ -50,8 +50,6 @@ import jdk.graal.compiler.code.DataSection.Data; import jdk.graal.compiler.core.common.cfg.AbstractControlFlowGraph; import jdk.graal.compiler.core.common.cfg.BasicBlock; -import jdk.graal.compiler.core.common.spi.CodeGenProviders; -import jdk.graal.compiler.core.common.spi.ForeignCallsProvider; import jdk.graal.compiler.core.common.type.DataPointerConstant; import jdk.graal.compiler.debug.Assertions; import jdk.graal.compiler.debug.DebugContext; @@ -67,12 +65,13 @@ import jdk.graal.compiler.lir.StandardOp; import jdk.graal.compiler.lir.StandardOp.LabelHoldingOp; import jdk.graal.compiler.lir.framemap.FrameMap; +import jdk.graal.compiler.nodes.spi.CoreProviders; +import jdk.graal.compiler.nodes.spi.CoreProvidersDelegate; import jdk.graal.compiler.options.Option; import jdk.graal.compiler.options.OptionKey; import jdk.graal.compiler.options.OptionType; import jdk.graal.compiler.options.OptionValues; import jdk.vm.ci.code.BailoutException; -import jdk.vm.ci.code.CodeCacheProvider; import jdk.vm.ci.code.DebugInfo; import jdk.vm.ci.code.Register; import jdk.vm.ci.code.StackSlot; @@ -93,7 +92,7 @@ * * @see CompilationResultBuilderFactory */ -public class CompilationResultBuilder { +public class CompilationResultBuilder extends CoreProvidersDelegate { public static class Options { @Option(help = "Include the LIR as comments with the final assembly.", type = OptionType.Debug) // @@ -129,9 +128,6 @@ public static class PendingImplicitException { public final CompilationResult compilationResult; public final Register uncompressedNullRegister; public final TargetDescription target; - public final CodeGenProviders providers; - public final CodeCacheProvider codeCache; - public final ForeignCallsProvider foreignCalls; public final FrameMap frameMap; /** @@ -184,7 +180,7 @@ public final boolean mustReplaceWithUncompressedNullRegister(JavaConstant nullCo private final List lirInstructionVerifiers; - public CompilationResultBuilder(CodeGenProviders providers, + public CompilationResultBuilder(CoreProviders providers, FrameMap frameMap, Assembler asm, DataBuilder dataBuilder, @@ -196,10 +192,8 @@ public CompilationResultBuilder(CodeGenProviders providers, EconomicMap dataCache, List lirInstructionVerifiers, LIR lir) { + super(providers); this.target = providers.getCodeCache().getTarget(); - this.providers = providers; - this.codeCache = providers.getCodeCache(); - this.foreignCalls = providers.getForeignCalls(); this.frameMap = frameMap; this.asm = asm; this.dataBuilder = dataBuilder; diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/asm/CompilationResultBuilderFactory.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/asm/CompilationResultBuilderFactory.java index 46387c81b49c..035801ee4cf3 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/asm/CompilationResultBuilderFactory.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/asm/CompilationResultBuilderFactory.java @@ -34,19 +34,19 @@ import org.graalvm.collections.EconomicMap; import org.graalvm.collections.Equivalence; + import jdk.graal.compiler.asm.Assembler; import jdk.graal.compiler.code.CompilationResult; -import jdk.graal.compiler.core.common.spi.CodeGenProviders; import jdk.graal.compiler.debug.DebugContext; import jdk.graal.compiler.debug.GraalError; import jdk.graal.compiler.lir.LIR; import jdk.graal.compiler.lir.LIRInstructionVerifier; import jdk.graal.compiler.lir.framemap.FrameMap; +import jdk.graal.compiler.nodes.spi.CoreProviders; import jdk.graal.compiler.options.Option; import jdk.graal.compiler.options.OptionKey; import jdk.graal.compiler.options.OptionType; import jdk.graal.compiler.options.OptionValues; - import jdk.vm.ci.code.Register; import jdk.vm.ci.services.Services; @@ -63,7 +63,7 @@ class Options { /** * Creates a new {@link CompilationResultBuilder}. */ - CompilationResultBuilder createBuilder(CodeGenProviders providers, + CompilationResultBuilder createBuilder(CoreProviders providers, FrameMap frameMap, Assembler asm, DataBuilder dataBuilder, @@ -97,7 +97,7 @@ private void initializeLIRVerifiers(String lirInstructionVerifierPath) { } @Override - public CompilationResultBuilder createBuilder(CodeGenProviders providers, + public CompilationResultBuilder createBuilder(CoreProviders providers, FrameMap frameMap, Assembler asm, DataBuilder dataBuilder, diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/asm/EntryPointDecorator.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/asm/EntryPointDecorator.java index a6f4e61c126f..c756f1edec00 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/asm/EntryPointDecorator.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/asm/EntryPointDecorator.java @@ -24,15 +24,15 @@ */ package jdk.graal.compiler.lir.asm; -import jdk.graal.compiler.core.common.spi.CodeGenProviders; import jdk.graal.compiler.lir.gen.LIRGenerationResult; +import jdk.graal.compiler.nodes.spi.CoreProviders; /** * Helper class to allow emitting custom assembly at the normal entry point before any frame setup * has occurred. */ public interface EntryPointDecorator { - void initialize(CodeGenProviders providers, LIRGenerationResult lirGenRes); + void initialize(CoreProviders providers, LIRGenerationResult lirGenRes); void emitEntryPoint(CompilationResultBuilder crb); } diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/gen/LIRGenerator.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/gen/LIRGenerator.java index f1ce59b983f1..5ba3e0576cae 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/gen/LIRGenerator.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/gen/LIRGenerator.java @@ -42,9 +42,7 @@ import jdk.graal.compiler.core.common.LIRKind; import jdk.graal.compiler.core.common.calc.Condition; import jdk.graal.compiler.core.common.cfg.BasicBlock; -import jdk.graal.compiler.core.common.spi.CodeGenProviders; import jdk.graal.compiler.core.common.spi.ForeignCallLinkage; -import jdk.graal.compiler.core.common.spi.ForeignCallsProvider; import jdk.graal.compiler.core.common.spi.LIRKindTool; import jdk.graal.compiler.core.common.type.Stamp; import jdk.graal.compiler.debug.DebugCloseable; @@ -61,12 +59,13 @@ import jdk.graal.compiler.lir.SwitchStrategy; import jdk.graal.compiler.lir.Variable; import jdk.graal.compiler.lir.hashing.IntHasher; +import jdk.graal.compiler.nodes.spi.CoreProviders; +import jdk.graal.compiler.nodes.spi.CoreProvidersDelegate; import jdk.graal.compiler.options.Option; import jdk.graal.compiler.options.OptionKey; import jdk.graal.compiler.options.OptionType; import jdk.graal.compiler.options.OptionValues; import jdk.vm.ci.code.CallingConvention; -import jdk.vm.ci.code.CodeCacheProvider; import jdk.vm.ci.code.Register; import jdk.vm.ci.code.RegisterAttributes; import jdk.vm.ci.code.RegisterConfig; @@ -76,7 +75,6 @@ import jdk.vm.ci.meta.Constant; import jdk.vm.ci.meta.JavaConstant; import jdk.vm.ci.meta.JavaKind; -import jdk.vm.ci.meta.MetaAccessProvider; import jdk.vm.ci.meta.PlatformKind; import jdk.vm.ci.meta.Value; import jdk.vm.ci.meta.ValueKind; @@ -84,7 +82,7 @@ /** * This class traverses the HIR instructions and generates LIR instructions from them. */ -public abstract class LIRGenerator implements LIRGeneratorTool { +public abstract class LIRGenerator extends CoreProvidersDelegate implements LIRGeneratorTool { private final int loopHeaderAlignment; @@ -99,8 +97,6 @@ public static class Options { private final LIRKindTool lirKindTool; - private final CodeGenProviders providers; - private BasicBlock currentBlock; private LIRGenerationResult res; @@ -113,13 +109,13 @@ public static class Options { private final boolean printIrWithLir; private final int traceLIRGeneratorLevel; - public LIRGenerator(LIRKindTool lirKindTool, ArithmeticLIRGenerator arithmeticLIRGen, BarrierSetLIRGenerator barrierSetLIRGen, MoveFactory moveFactory, CodeGenProviders providers, + public LIRGenerator(LIRKindTool lirKindTool, ArithmeticLIRGenerator arithmeticLIRGen, BarrierSetLIRGenerator barrierSetLIRGen, MoveFactory moveFactory, CoreProviders providers, LIRGenerationResult res) { + super(providers); this.lirKindTool = lirKindTool; this.arithmeticLIRGen = arithmeticLIRGen; this.barrierSetLIRGen = barrierSetLIRGen; this.res = res; - this.providers = providers; OptionValues options = res.getLIR().getOptions(); this.printIrWithLir = !TTY.isSuppressed() && Options.PrintIRWithLIR.getValue(options); this.traceLIRGeneratorLevel = TTY.isSuppressed() ? 0 : Options.TraceLIRGeneratorLevel.getValue(options); @@ -176,26 +172,6 @@ public TargetDescription target() { return getCodeCache().getTarget(); } - @Override - public CodeGenProviders getProviders() { - return providers; - } - - @Override - public MetaAccessProvider getMetaAccess() { - return providers.getMetaAccess(); - } - - @Override - public CodeCacheProvider getCodeCache() { - return providers.getCodeCache(); - } - - @Override - public ForeignCallsProvider getForeignCalls() { - return providers.getForeignCalls(); - } - public LIRKindTool getLIRKindTool() { return lirKindTool; } diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/gen/LIRGeneratorTool.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/gen/LIRGeneratorTool.java index a7d429b91b5b..43f0a4494c90 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/gen/LIRGeneratorTool.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/gen/LIRGeneratorTool.java @@ -34,9 +34,7 @@ import jdk.graal.compiler.core.common.cfg.BasicBlock; import jdk.graal.compiler.core.common.memory.BarrierType; import jdk.graal.compiler.core.common.memory.MemoryOrderMode; -import jdk.graal.compiler.core.common.spi.CodeGenProviders; import jdk.graal.compiler.core.common.spi.ForeignCallLinkage; -import jdk.graal.compiler.core.common.spi.ForeignCallsProvider; import jdk.graal.compiler.core.common.type.Stamp; import jdk.graal.compiler.debug.GraalError; import jdk.graal.compiler.lir.LIRFrameState; @@ -45,8 +43,7 @@ import jdk.graal.compiler.lir.LabelRef; import jdk.graal.compiler.lir.Variable; import jdk.graal.compiler.lir.VirtualStackSlot; - -import jdk.vm.ci.code.CodeCacheProvider; +import jdk.graal.compiler.nodes.spi.CoreProviders; import jdk.vm.ci.code.Register; import jdk.vm.ci.code.RegisterConfig; import jdk.vm.ci.code.StackSlot; @@ -56,12 +53,11 @@ import jdk.vm.ci.meta.Constant; import jdk.vm.ci.meta.JavaConstant; import jdk.vm.ci.meta.JavaKind; -import jdk.vm.ci.meta.MetaAccessProvider; import jdk.vm.ci.meta.PlatformKind; import jdk.vm.ci.meta.Value; import jdk.vm.ci.meta.ValueKind; -public interface LIRGeneratorTool extends DiagnosticLIRGeneratorTool, ValueKindFactory { +public interface LIRGeneratorTool extends CoreProviders, DiagnosticLIRGeneratorTool, ValueKindFactory { abstract class BlockScope implements AutoCloseable { @@ -76,16 +72,8 @@ abstract class BlockScope implements AutoCloseable { BarrierSetLIRGeneratorTool getBarrierSet(); - CodeGenProviders getProviders(); - TargetDescription target(); - MetaAccessProvider getMetaAccess(); - - CodeCacheProvider getCodeCache(); - - ForeignCallsProvider getForeignCalls(); - BasicBlock getCurrentBlock(); LIRGenerationResult getResult(); diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/nodes/spi/CoreProviders.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/nodes/spi/CoreProviders.java index cd1e64562945..b89c51d875f1 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/nodes/spi/CoreProviders.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/nodes/spi/CoreProviders.java @@ -28,7 +28,8 @@ import jdk.graal.compiler.core.common.spi.ConstantFieldProvider; import jdk.graal.compiler.core.common.spi.ForeignCallsProvider; import jdk.graal.compiler.core.common.spi.MetaAccessExtensionProvider; - +import jdk.graal.compiler.word.WordTypes; +import jdk.vm.ci.code.CodeCacheProvider; import jdk.vm.ci.meta.ConstantReflectionProvider; import jdk.vm.ci.meta.MetaAccessProvider; @@ -54,7 +55,9 @@ public interface CoreProviders { LoopsDataProvider getLoopsDataProvider(); - WordVerification getWordVerification(); + WordTypes getWordTypes(); + + CodeCacheProvider getCodeCache(); SnippetReflectionProvider getSnippetReflection(); } diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/nodes/spi/CoreProvidersDelegate.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/nodes/spi/CoreProvidersDelegate.java index ab444c29beac..63ae24f909a8 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/nodes/spi/CoreProvidersDelegate.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/nodes/spi/CoreProvidersDelegate.java @@ -28,7 +28,8 @@ import jdk.graal.compiler.core.common.spi.ConstantFieldProvider; import jdk.graal.compiler.core.common.spi.ForeignCallsProvider; import jdk.graal.compiler.core.common.spi.MetaAccessExtensionProvider; - +import jdk.graal.compiler.word.WordTypes; +import jdk.vm.ci.code.CodeCacheProvider; import jdk.vm.ci.meta.ConstantReflectionProvider; import jdk.vm.ci.meta.MetaAccessProvider; @@ -74,6 +75,11 @@ public StampProvider getStampProvider() { return providers.getStampProvider(); } + @Override + public CodeCacheProvider getCodeCache() { + return providers.getCodeCache(); + } + @Override public ForeignCallsProvider getForeignCalls() { return providers.getForeignCalls(); @@ -95,8 +101,8 @@ public LoopsDataProvider getLoopsDataProvider() { } @Override - public WordVerification getWordVerification() { - return providers.getWordVerification(); + public WordTypes getWordTypes() { + return providers.getWordTypes(); } @Override diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/nodes/spi/WordVerification.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/nodes/spi/WordVerification.java deleted file mode 100644 index 28323d08dad0..000000000000 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/nodes/spi/WordVerification.java +++ /dev/null @@ -1,63 +0,0 @@ -/* - * 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 jdk.graal.compiler.nodes.spi; - -import jdk.vm.ci.meta.JavaType; - -/** - * Provides a capability to verify that {@linkplain JavaType types} represent or do not represent - * raw words (as opposed to Objects). - *

- * All methods will either return {@code true} in case the assertion holds or throw an exception if - * it does not. Users are not supposed to catch the exception and make decisions based on it. This - * is a debugging tool. Only use it for assertions and verification. - *

- * - *

Motivation

- * - * This interface exists to avoid exposing {@code WordTypes} in {@link CoreProviders}. Word values - * must be transformed to other types at the very beginning of the pipeline (i.e., during graph - * building). {@link WordVerification} is used to detect when this invariant is violated and to - * issue proper error messages. - */ -public interface WordVerification { - - /** - * Verifies that a given type is a word type. - * - * @return {@code true} - * @throws Error if the assertion does not hold - */ - boolean guaranteeWord(JavaType type); - - /** - * Verifies that a given type is not a word type. - * - * @return {@code true} - * @throws Error if the assertion does not hold - */ - boolean guaranteeNotWord(JavaType type); - -} diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/phases/util/Providers.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/phases/util/Providers.java index 8c1009f3aa85..9f04d4c35718 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/phases/util/Providers.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/phases/util/Providers.java @@ -25,7 +25,6 @@ package jdk.graal.compiler.phases.util; import jdk.graal.compiler.api.replacements.SnippetReflectionProvider; -import jdk.graal.compiler.core.common.spi.CodeGenProviders; import jdk.graal.compiler.core.common.spi.ConstantFieldProvider; import jdk.graal.compiler.core.common.spi.ForeignCallsProvider; import jdk.graal.compiler.core.common.spi.MetaAccessExtensionProvider; @@ -35,10 +34,7 @@ import jdk.graal.compiler.nodes.spi.PlatformConfigurationProvider; import jdk.graal.compiler.nodes.spi.Replacements; import jdk.graal.compiler.nodes.spi.StampProvider; -import jdk.graal.compiler.nodes.spi.WordVerification; import jdk.graal.compiler.word.WordTypes; -import jdk.graal.compiler.word.WordVerificationImpl; - import jdk.vm.ci.code.CodeCacheProvider; import jdk.vm.ci.meta.ConstantReflectionProvider; import jdk.vm.ci.meta.MetaAccessProvider; @@ -46,7 +42,7 @@ /** * A set of providers, some of which may not be present (i.e., null). */ -public class Providers implements CoreProviders, CodeGenProviders { +public class Providers implements CoreProviders { protected final MetaAccessProvider metaAccess; protected final ConstantReflectionProvider constantReflection; @@ -58,7 +54,6 @@ public class Providers implements CoreProviders, CodeGenProviders { protected final PlatformConfigurationProvider platformConfigurationProvider; protected final MetaAccessExtensionProvider metaAccessExtensionProvider; protected final LoopsDataProvider loopsDataProvider; - protected final WordVerification wordVerification; protected final CodeCacheProvider codeCache; protected final SnippetReflectionProvider snippetReflection; protected final WordTypes wordTypes; @@ -76,7 +71,6 @@ public Providers(MetaAccessProvider metaAccess, CodeCacheProvider codeCache, Con this.platformConfigurationProvider = platformConfigurationProvider; this.metaAccessExtensionProvider = metaAccessExtensionProvider; this.loopsDataProvider = loopsDataProvider; - this.wordVerification = new WordVerificationImpl(wordTypes); this.codeCache = codeCache; this.snippetReflection = snippetReflection; this.wordTypes = wordTypes; @@ -138,11 +132,6 @@ public LoopsDataProvider getLoopsDataProvider() { return loopsDataProvider; } - @Override - public WordVerification getWordVerification() { - return wordVerification; - } - @Override public CodeCacheProvider getCodeCache() { return codeCache; @@ -153,6 +142,7 @@ public SnippetReflectionProvider getSnippetReflection() { return snippetReflection; } + @Override public WordTypes getWordTypes() { return wordTypes; } diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/truffle/hotspot/TruffleEntryPointDecorator.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/truffle/hotspot/TruffleEntryPointDecorator.java index bb66cfc69314..2d6972ee7605 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/truffle/hotspot/TruffleEntryPointDecorator.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/truffle/hotspot/TruffleEntryPointDecorator.java @@ -26,15 +26,14 @@ import static jdk.graal.compiler.hotspot.meta.HotSpotHostForeignCallsProvider.Z_FIELD_BARRIER; -import jdk.graal.compiler.core.common.spi.CodeGenProviders; import jdk.graal.compiler.core.common.spi.ForeignCallLinkage; import jdk.graal.compiler.hotspot.GraalHotSpotVMConfig; import jdk.graal.compiler.hotspot.HotSpotGraalRuntime; import jdk.graal.compiler.hotspot.meta.HotSpotRegistersProvider; import jdk.graal.compiler.lir.asm.EntryPointDecorator; import jdk.graal.compiler.lir.gen.LIRGenerationResult; +import jdk.graal.compiler.nodes.spi.CoreProviders; import jdk.graal.compiler.truffle.TruffleCompilerConfiguration; - import jdk.vm.ci.meta.MetaAccessProvider; /** @@ -61,7 +60,7 @@ public TruffleEntryPointDecorator(TruffleCompilerConfiguration compilerConfig, G } @Override - public void initialize(CodeGenProviders providers, LIRGenerationResult lirGenRes) { + public void initialize(CoreProviders providers, LIRGenerationResult lirGenRes) { if (config.gc == HotSpotGraalRuntime.HotSpotGC.Z) { ForeignCallLinkage callTarget = providers.getForeignCalls().lookupForeignCall(Z_FIELD_BARRIER); lirGenRes.getFrameMapBuilder().callsMethod(callTarget.getOutgoingCallingConvention()); diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/truffle/hotspot/aarch64/AArch64TruffleCallBoundaryInstrumentationFactory.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/truffle/hotspot/aarch64/AArch64TruffleCallBoundaryInstrumentationFactory.java index a478bc5a61b2..04f296720765 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/truffle/hotspot/aarch64/AArch64TruffleCallBoundaryInstrumentationFactory.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/truffle/hotspot/aarch64/AArch64TruffleCallBoundaryInstrumentationFactory.java @@ -24,9 +24,9 @@ */ package jdk.graal.compiler.truffle.hotspot.aarch64; +import static jdk.graal.compiler.hotspot.meta.HotSpotHostForeignCallsProvider.Z_FIELD_BARRIER; import static jdk.vm.ci.hotspot.HotSpotCallingConventionType.JavaCall; import static jdk.vm.ci.meta.JavaKind.Object; -import static jdk.graal.compiler.hotspot.meta.HotSpotHostForeignCallsProvider.Z_FIELD_BARRIER; import jdk.graal.compiler.asm.Label; import jdk.graal.compiler.asm.aarch64.AArch64Address; @@ -47,7 +47,6 @@ import jdk.graal.compiler.truffle.TruffleCompilerConfiguration; import jdk.graal.compiler.truffle.hotspot.TruffleCallBoundaryInstrumentationFactory; import jdk.graal.compiler.truffle.hotspot.TruffleEntryPointDecorator; - import jdk.vm.ci.code.Register; @ServiceProvider(TruffleCallBoundaryInstrumentationFactory.class) @@ -62,7 +61,7 @@ public void emitEntryPoint(CompilationResultBuilder crb) { AArch64HotSpotBackend.emitInvalidatePlaceholder(crb, masm); try (ScratchRegister scratch = masm.getScratchRegister()) { - Register thisRegister = crb.codeCache.getRegisterConfig().getCallingConventionRegisters(JavaCall, Object).get(0); + Register thisRegister = crb.getCodeCache().getRegisterConfig().getCallingConventionRegisters(JavaCall, Object).get(0); Register spillRegister = scratch.getRegister(); Label doProlog = new Label(); if (config.useCompressedOops) { @@ -74,7 +73,7 @@ public void emitEntryPoint(CompilationResultBuilder crb) { AArch64Address address = AArch64Address.createImmediateAddress(64, AArch64Address.AddressingMode.IMMEDIATE_UNSIGNED_SCALED, thisRegister, installedCodeOffset); masm.ldr(64, spillRegister, address); if (config.gc == HotSpotGraalRuntime.HotSpotGC.Z) { - ForeignCallLinkage callTarget = crb.providers.getForeignCalls().lookupForeignCall(Z_FIELD_BARRIER); + ForeignCallLinkage callTarget = crb.getForeignCalls().lookupForeignCall(Z_FIELD_BARRIER); AArch64FrameMap frameMap = (AArch64FrameMap) crb.frameMap; AArch64HotSpotZBarrierSetLIRGenerator.emitBarrier(crb, masm, null, spillRegister, config, callTarget, address, null, frameMap); } diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/truffle/hotspot/amd64/AMD64TruffleCallBoundaryInstrumentationFactory.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/truffle/hotspot/amd64/AMD64TruffleCallBoundaryInstrumentationFactory.java index 7631b84ef673..18f93c6973e0 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/truffle/hotspot/amd64/AMD64TruffleCallBoundaryInstrumentationFactory.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/truffle/hotspot/amd64/AMD64TruffleCallBoundaryInstrumentationFactory.java @@ -24,8 +24,8 @@ */ package jdk.graal.compiler.truffle.hotspot.amd64; -import static jdk.vm.ci.hotspot.HotSpotCallingConventionType.JavaCall; import static jdk.graal.compiler.hotspot.meta.HotSpotHostForeignCallsProvider.Z_FIELD_BARRIER; +import static jdk.vm.ci.hotspot.HotSpotCallingConventionType.JavaCall; import jdk.graal.compiler.asm.Label; import jdk.graal.compiler.asm.amd64.AMD64Address; @@ -42,10 +42,9 @@ import jdk.graal.compiler.lir.asm.CompilationResultBuilder; import jdk.graal.compiler.lir.asm.EntryPointDecorator; import jdk.graal.compiler.serviceprovider.ServiceProvider; +import jdk.graal.compiler.truffle.TruffleCompilerConfiguration; import jdk.graal.compiler.truffle.hotspot.TruffleCallBoundaryInstrumentationFactory; import jdk.graal.compiler.truffle.hotspot.TruffleEntryPointDecorator; -import jdk.graal.compiler.truffle.TruffleCompilerConfiguration; - import jdk.vm.ci.amd64.AMD64; import jdk.vm.ci.code.Register; import jdk.vm.ci.meta.JavaKind; @@ -59,7 +58,7 @@ public EntryPointDecorator create(TruffleCompilerConfiguration compilerConfig, G @Override public void emitEntryPoint(CompilationResultBuilder crb) { AMD64MacroAssembler masm = (AMD64MacroAssembler) crb.asm; - Register thisRegister = crb.codeCache.getRegisterConfig().getCallingConventionRegisters(JavaCall, JavaKind.Object).get(0); + Register thisRegister = crb.getCodeCache().getRegisterConfig().getCallingConventionRegisters(JavaCall, JavaKind.Object).get(0); Register spillRegister = AMD64.r10; Label doProlog = new Label(); int pos = masm.position(); @@ -79,7 +78,7 @@ public void emitEntryPoint(CompilationResultBuilder crb) { masm.movq(spillRegister, address, true); assert masm.position() - pos >= AMD64HotSpotBackend.PATCHED_VERIFIED_ENTRY_POINT_INSTRUCTION_SIZE : masm.position() + "-" + pos; if (config.gc == HotSpotGraalRuntime.HotSpotGC.Z) { - ForeignCallLinkage callTarget = crb.providers.getForeignCalls().lookupForeignCall(Z_FIELD_BARRIER); + ForeignCallLinkage callTarget = crb.getForeignCalls().lookupForeignCall(Z_FIELD_BARRIER); AMD64HotSpotZBarrierSetLIRGenerator.emitBarrier(crb, masm, null, spillRegister, config, callTarget, address, null, (AMD64HotSpotBackend.HotSpotFrameContext) crb.frameContext); } diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/word/WordVerificationImpl.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/word/WordVerificationImpl.java deleted file mode 100644 index 94d1109ac56d..000000000000 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/word/WordVerificationImpl.java +++ /dev/null @@ -1,52 +0,0 @@ -/* - * Copyright (c) 2012, 2022, 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 jdk.graal.compiler.word; - -import jdk.graal.compiler.debug.GraalError; -import jdk.graal.compiler.nodes.spi.WordVerification; - -import jdk.vm.ci.meta.JavaType; - -public final class WordVerificationImpl implements WordVerification { - - private final WordTypes wordTypes; - - public WordVerificationImpl(WordTypes wordTypes) { - this.wordTypes = wordTypes; - } - - @Override - public boolean guaranteeWord(JavaType type) { - GraalError.guarantee(wordTypes.isWord(type), "Expected a Word but got %s", type); - return true; - } - - @Override - public boolean guaranteeNotWord(JavaType type) { - GraalError.guarantee(!wordTypes.isWord(type), "Unexpected a Word type %s", type); - return true; - } - -} diff --git a/substratevm/src/com.oracle.svm.core.graal.amd64/src/com/oracle/svm/core/graal/amd64/AMD64CalleeSavedRegisters.java b/substratevm/src/com.oracle.svm.core.graal.amd64/src/com/oracle/svm/core/graal/amd64/AMD64CalleeSavedRegisters.java index 57436e270293..59651a761efe 100644 --- a/substratevm/src/com.oracle.svm.core.graal.amd64/src/com/oracle/svm/core/graal/amd64/AMD64CalleeSavedRegisters.java +++ b/substratevm/src/com.oracle.svm.core.graal.amd64/src/com/oracle/svm/core/graal/amd64/AMD64CalleeSavedRegisters.java @@ -69,7 +69,6 @@ import jdk.graal.compiler.core.common.Stride; import jdk.graal.compiler.debug.GraalError; import jdk.graal.compiler.lir.asm.CompilationResultBuilder; -import jdk.graal.compiler.phases.util.Providers; import jdk.vm.ci.amd64.AMD64; import jdk.vm.ci.amd64.AMD64.CPUFeature; import jdk.vm.ci.amd64.AMD64Kind; @@ -455,13 +454,13 @@ private AMD64BaseAssembler.OperandSize getSize() { @Platforms(Platform.HOSTED_ONLY.class) private AMD64Address getFeatureMapAddress() { - SnippetReflectionProvider snippetReflection = ((Providers) crb.providers).getSnippetReflection(); + SnippetReflectionProvider snippetReflection = crb.getSnippetReflection(); JavaConstant object = snippetReflection.forObject(RuntimeCPUFeatureCheckImpl.instance()); - int fieldOffset = fieldOffset(RuntimeCPUFeatureCheckImpl.getMaskField(crb.providers.getMetaAccess())); + int fieldOffset = fieldOffset(RuntimeCPUFeatureCheckImpl.getMaskField(crb.getMetaAccess())); GraalError.guarantee(ConfigurationValues.getTarget().inlineObjects, "Dynamic feature check for callee saved registers requires inlined objects"); Register heapBase = ReservedRegisters.singleton().getHeapBaseRegister(); GraalError.guarantee(heapBase != null, "Heap base register must not be null"); - return new AMD64Address(heapBase, Register.None, Stride.S1, displacement(object, (SharedConstantReflectionProvider) crb.providers.getConstantReflection()) + fieldOffset, + return new AMD64Address(heapBase, Register.None, Stride.S1, displacement(object, (SharedConstantReflectionProvider) crb.getConstantReflection()) + fieldOffset, displacementAnnotation(object)); } diff --git a/substratevm/src/com.oracle.svm.core.graal.llvm/src/com/oracle/svm/core/graal/llvm/LLVMGenerator.java b/substratevm/src/com.oracle.svm.core.graal.llvm/src/com/oracle/svm/core/graal/llvm/LLVMGenerator.java index a8db9d612be2..609d41eb0803 100644 --- a/substratevm/src/com.oracle.svm.core.graal.llvm/src/com/oracle/svm/core/graal/llvm/LLVMGenerator.java +++ b/substratevm/src/com.oracle.svm.core.graal.llvm/src/com/oracle/svm/core/graal/llvm/LLVMGenerator.java @@ -104,7 +104,6 @@ import jdk.graal.compiler.core.common.memory.MemoryExtendKind; import jdk.graal.compiler.core.common.memory.MemoryOrderMode; import jdk.graal.compiler.core.common.spi.ForeignCallLinkage; -import jdk.graal.compiler.core.common.spi.ForeignCallsProvider; import jdk.graal.compiler.core.common.spi.LIRKindTool; import jdk.graal.compiler.core.common.type.CompressibleConstant; import jdk.graal.compiler.core.common.type.IllegalStamp; @@ -127,11 +126,11 @@ import jdk.graal.compiler.nodes.StructuredGraph; import jdk.graal.compiler.nodes.ValueNode; import jdk.graal.compiler.nodes.cfg.HIRBlock; +import jdk.graal.compiler.nodes.spi.CoreProvidersDelegate; import jdk.graal.compiler.nodes.type.NarrowOopStamp; import jdk.graal.compiler.phases.util.Providers; import jdk.internal.misc.Unsafe; import jdk.vm.ci.code.CallingConvention; -import jdk.vm.ci.code.CodeCacheProvider; import jdk.vm.ci.code.DebugInfo; import jdk.vm.ci.code.MemoryBarriers; import jdk.vm.ci.code.Register; @@ -145,7 +144,6 @@ import jdk.vm.ci.meta.JavaConstant; import jdk.vm.ci.meta.JavaKind; import jdk.vm.ci.meta.JavaType; -import jdk.vm.ci.meta.MetaAccessProvider; import jdk.vm.ci.meta.PlatformKind; import jdk.vm.ci.meta.ResolvedJavaMethod; import jdk.vm.ci.meta.ResolvedJavaType; @@ -156,9 +154,8 @@ * Contains the tools needed to emit instructions from Graal nodes into LLVM bitcode, * via the LLVMIRBuilder class. */ -public class LLVMGenerator implements LIRGeneratorTool, SubstrateLIRGenerator { +public class LLVMGenerator extends CoreProvidersDelegate implements LIRGeneratorTool, SubstrateLIRGenerator { private static final SubstrateDataBuilder dataBuilder = new SubstrateDataBuilder(); - private final Providers providers; private final CompilationResult compilationResult; private final LLVMIRBuilder builder; @@ -179,7 +176,7 @@ public class LLVMGenerator implements LIRGeneratorTool, SubstrateLIRGenerator { private final Map constants = new HashMap<>(); LLVMGenerator(Providers providers, CompilationResult result, StructuredGraph graph, ResolvedJavaMethod method, int debugLevel) { - this.providers = providers; + super(providers); this.compilationResult = result; this.builder = new LLVMIRBuilder(method.format("%H.%n")); this.arithmetic = new ArithmeticLLVMGenerator(); @@ -202,21 +199,6 @@ public BarrierSetLIRGeneratorTool getBarrierSet() { return null; } - @Override - public Providers getProviders() { - return providers; - } - - @Override - public MetaAccessProvider getMetaAccess() { - return providers.getMetaAccess(); - } - - @Override - public CodeCacheProvider getCodeCache() { - return providers.getCodeCache(); - } - @Override public TargetDescription target() { return getCodeCache().getTarget(); @@ -227,11 +209,6 @@ public SubstrateRegisterConfig getRegisterConfig() { return (SubstrateRegisterConfig) getCodeCache().getRegisterConfig(); } - @Override - public ForeignCallsProvider getForeignCalls() { - return providers.getForeignCalls(); - } - CompilationResult getCompilationResult() { return compilationResult; } diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/graal/meta/SubstrateReplacements.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/graal/meta/SubstrateReplacements.java index 04112619a036..1bd919d8fddb 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/graal/meta/SubstrateReplacements.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/graal/meta/SubstrateReplacements.java @@ -42,6 +42,17 @@ import java.util.concurrent.ConcurrentHashMap; import java.util.function.Function; +import org.graalvm.nativeimage.AnnotationAccess; +import org.graalvm.nativeimage.Platform; +import org.graalvm.nativeimage.Platforms; +import org.graalvm.nativeimage.hosted.Feature.BeforeHeapLayoutAccess; + +import com.oracle.svm.core.SubstrateTargetDescription; +import com.oracle.svm.core.config.ConfigurationValues; +import com.oracle.svm.core.meta.SharedMethod; +import com.oracle.svm.core.option.HostedOptionValues; +import com.oracle.svm.core.util.VMError; + import jdk.graal.compiler.api.replacements.Snippet; import jdk.graal.compiler.api.replacements.SnippetReflectionProvider; import jdk.graal.compiler.bytecode.BytecodeProvider; @@ -78,17 +89,6 @@ import jdk.graal.compiler.replacements.PEGraphDecoder; import jdk.graal.compiler.replacements.ReplacementsImpl; import jdk.graal.compiler.word.WordTypes; -import org.graalvm.nativeimage.AnnotationAccess; -import org.graalvm.nativeimage.Platform; -import org.graalvm.nativeimage.Platforms; -import org.graalvm.nativeimage.hosted.Feature.BeforeHeapLayoutAccess; - -import com.oracle.svm.core.SubstrateTargetDescription; -import com.oracle.svm.core.config.ConfigurationValues; -import com.oracle.svm.core.meta.SharedMethod; -import com.oracle.svm.core.option.HostedOptionValues; -import com.oracle.svm.core.util.VMError; - import jdk.vm.ci.code.TargetDescription; import jdk.vm.ci.meta.JavaKind; import jdk.vm.ci.meta.MetaAccessProvider; @@ -150,14 +150,11 @@ public InlineInfo shouldInlineInvoke(GraphBuilderContext b, ResolvedJavaMethod m private Object[] snippetObjects; private NodeClass[] snippetNodeClasses; private Map snippetStartOffsets; - private final WordTypes wordTypes; @Platforms(Platform.HOSTED_ONLY.class) - public SubstrateReplacements(Providers providers, SnippetReflectionProvider snippetReflection, BytecodeProvider bytecodeProvider, TargetDescription target, - WordTypes wordTypes, GraphMakerFactory graphMakerFactory) { + public SubstrateReplacements(Providers providers, SnippetReflectionProvider snippetReflection, BytecodeProvider bytecodeProvider, TargetDescription target, GraphMakerFactory graphMakerFactory) { // Snippets cannot have optimistic assumptions. super(new GraalDebugHandlersFactory(snippetReflection), providers, snippetReflection, bytecodeProvider, target); - this.wordTypes = wordTypes; this.builder = new Builder(graphMakerFactory); } @@ -382,7 +379,7 @@ private static Object[] prepareConstantArguments(Object receiver) { @Override public T getInjectedArgument(Class capability) { if (capability.isAssignableFrom(WordTypes.class)) { - return (T) wordTypes; + return (T) providers.getWordTypes(); } return super.getInjectedArgument(capability); } @@ -392,8 +389,8 @@ public Stamp getInjectedStamp(Class type, boolean nonNull) { JavaKind kind = JavaKind.fromJavaClass(type); if (kind == JavaKind.Object) { ResolvedJavaType returnType = providers.getMetaAccess().lookupJavaType(type); - if (wordTypes.isWord(returnType)) { - return wordTypes.getWordStamp(returnType); + if (providers.getWordTypes().isWord(returnType)) { + return providers.getWordTypes().getWordStamp(returnType); } else { return StampFactory.object(TypeReference.createWithoutAssumptions(returnType), nonNull); } diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/graal/thread/VMThreadLocalSTHolderNode.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/graal/thread/VMThreadLocalSTHolderNode.java index f1a3a04f06e5..4f410d71afcb 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/graal/thread/VMThreadLocalSTHolderNode.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/graal/thread/VMThreadLocalSTHolderNode.java @@ -24,6 +24,11 @@ */ package com.oracle.svm.core.graal.thread; +import org.graalvm.nativeimage.ImageSingletons; + +import com.oracle.svm.core.threadlocal.VMThreadLocalInfo; +import com.oracle.svm.core.threadlocal.VMThreadLocalSTSupport; + import jdk.graal.compiler.api.replacements.SnippetReflectionProvider; import jdk.graal.compiler.core.common.LIRKind; import jdk.graal.compiler.core.common.type.StampFactory; @@ -35,11 +40,6 @@ import jdk.graal.compiler.nodes.NodeView; import jdk.graal.compiler.nodes.spi.LIRLowerable; import jdk.graal.compiler.nodes.spi.NodeLIRBuilderTool; -import jdk.graal.compiler.phases.util.Providers; -import org.graalvm.nativeimage.ImageSingletons; - -import com.oracle.svm.core.threadlocal.VMThreadLocalInfo; -import com.oracle.svm.core.threadlocal.VMThreadLocalSTSupport; @NodeInfo(cycles = NodeCycles.CYCLES_0, size = NodeSize.SIZE_1) public class VMThreadLocalSTHolderNode extends FixedWithNextNode implements LIRLowerable { @@ -64,7 +64,7 @@ public void generate(NodeLIRBuilderTool gen) { } else { holder = ImageSingletons.lookup(VMThreadLocalSTSupport.class).primitiveThreadLocals; } - SnippetReflectionProvider snippetReflection = ((Providers) gen.getLIRGeneratorTool().getProviders()).getSnippetReflection(); + SnippetReflectionProvider snippetReflection = gen.getLIRGeneratorTool().getSnippetReflection(); LIRKind kind = gen.getLIRGeneratorTool().getLIRKind(stamp(NodeView.DEFAULT)); gen.setResult(this, gen.getLIRGeneratorTool().emitLoadConstant(kind, snippetReflection.forObject(holder))); } diff --git a/substratevm/src/com.oracle.svm.graal/src/com/oracle/svm/graal/hosted/ParseOnceRuntimeCompilationFeature.java b/substratevm/src/com.oracle.svm.graal/src/com/oracle/svm/graal/hosted/ParseOnceRuntimeCompilationFeature.java index b320671142bf..849a5928a849 100644 --- a/substratevm/src/com.oracle.svm.graal/src/com/oracle/svm/graal/hosted/ParseOnceRuntimeCompilationFeature.java +++ b/substratevm/src/com.oracle.svm.graal/src/com/oracle/svm/graal/hosted/ParseOnceRuntimeCompilationFeature.java @@ -134,7 +134,6 @@ import jdk.graal.compiler.phases.util.Providers; import jdk.graal.compiler.printer.GraalDebugHandlersFactory; import jdk.graal.compiler.truffle.phases.DeoptimizeOnExceptionPhase; -import jdk.graal.compiler.word.WordTypes; import jdk.vm.ci.code.BytecodeFrame; import jdk.vm.ci.code.BytecodePosition; import jdk.vm.ci.meta.JavaConstant; @@ -273,8 +272,8 @@ public int hashCode() { private static final class RuntimeGraphBuilderPhase extends AnalysisGraphBuilderPhase { private RuntimeGraphBuilderPhase(Providers providers, - GraphBuilderConfiguration graphBuilderConfig, OptimisticOptimizations optimisticOpts, IntrinsicContext initialIntrinsicContext, WordTypes wordTypes, SVMHost hostVM) { - super(providers, graphBuilderConfig, optimisticOpts, initialIntrinsicContext, wordTypes, hostVM); + GraphBuilderConfiguration graphBuilderConfig, OptimisticOptimizations optimisticOpts, IntrinsicContext initialIntrinsicContext, SVMHost hostVM) { + super(providers, graphBuilderConfig, optimisticOpts, initialIntrinsicContext, hostVM); } static RuntimeGraphBuilderPhase createRuntimeGraphBuilderPhase(BigBang bb, Providers providers, @@ -284,7 +283,7 @@ static RuntimeGraphBuilderPhase createRuntimeGraphBuilderPhase(BigBang bb, Provi var newGraphBuilderConfig = graphBuilderConfig .withEagerResolving(true) .withUnresolvedIsError(false); - return new RuntimeGraphBuilderPhase(providers, newGraphBuilderConfig, optimisticOpts, null, providers.getWordTypes(), (SVMHost) bb.getHostVM()); + return new RuntimeGraphBuilderPhase(providers, newGraphBuilderConfig, optimisticOpts, null, (SVMHost) bb.getHostVM()); } @Override diff --git a/substratevm/src/com.oracle.svm.graal/src/com/oracle/svm/graal/meta/SubstrateRuntimeConfigurationBuilder.java b/substratevm/src/com.oracle.svm.graal/src/com/oracle/svm/graal/meta/SubstrateRuntimeConfigurationBuilder.java index d89b62530dbe..a4fb2e99bc5d 100644 --- a/substratevm/src/com.oracle.svm.graal/src/com/oracle/svm/graal/meta/SubstrateRuntimeConfigurationBuilder.java +++ b/substratevm/src/com.oracle.svm.graal/src/com/oracle/svm/graal/meta/SubstrateRuntimeConfigurationBuilder.java @@ -98,8 +98,7 @@ protected LoweringProvider createLoweringProvider(ForeignCallsProvider foreignCa @Override protected Replacements createReplacements(Providers p, SnippetReflectionProvider snippetReflection) { BytecodeProvider bytecodeProvider = new ResolvedJavaMethodBytecodeProvider(); - WordTypes wordTypes = p.getWordTypes(); - return new SubstrateReplacements(p, snippetReflection, bytecodeProvider, ConfigurationValues.getTarget(), wordTypes, new SubstrateGraphMakerFactory(wordTypes)); + return new SubstrateReplacements(p, snippetReflection, bytecodeProvider, ConfigurationValues.getTarget(), new SubstrateGraphMakerFactory()); } @Override diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/NativeImageGenerator.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/NativeImageGenerator.java index 7f984272f9d2..e082a6a4d4d2 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/NativeImageGenerator.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/NativeImageGenerator.java @@ -1177,7 +1177,7 @@ private static HostedProviders createHostedProviders(TargetDescription target, A aWordTypes, platformConfig, aMetaAccessExtensionProvider, originalProviders.getLoopsDataProvider()); BytecodeProvider bytecodeProvider = new ResolvedJavaMethodBytecodeProvider(); - SubstrateReplacements aReplacements = new SubstrateReplacements(aProviders, aSnippetReflection, bytecodeProvider, target, aWordTypes, new SubstrateGraphMakerFactory(aWordTypes)); + SubstrateReplacements aReplacements = new SubstrateReplacements(aProviders, aSnippetReflection, bytecodeProvider, target, new SubstrateGraphMakerFactory()); aProviders = (HostedProviders) aReplacements.getProviders(); assert aReplacements == aProviders.getReplacements(); diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/SVMHost.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/SVMHost.java index cd16721bc691..e1d1f4750401 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/SVMHost.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/SVMHost.java @@ -261,7 +261,7 @@ public void checkForbidden(AnalysisType type, AnalysisType.UsageKind kind) { @Override public Instance createGraphBuilderPhase(HostedProviders builderProviders, GraphBuilderConfiguration graphBuilderConfig, OptimisticOptimizations optimisticOpts, IntrinsicContext initialIntrinsicContext) { - return new AnalysisGraphBuilderPhase(builderProviders, graphBuilderConfig, optimisticOpts, initialIntrinsicContext, builderProviders.getWordTypes(), this); + return new AnalysisGraphBuilderPhase(builderProviders, graphBuilderConfig, optimisticOpts, initialIntrinsicContext, this); } @Override diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/classinitialization/ClassInitializerGraphBuilderPhase.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/classinitialization/ClassInitializerGraphBuilderPhase.java index 95b87a71573c..e70ac9ea2eac 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/classinitialization/ClassInitializerGraphBuilderPhase.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/classinitialization/ClassInitializerGraphBuilderPhase.java @@ -24,6 +24,8 @@ */ package com.oracle.svm.hosted.classinitialization; +import com.oracle.svm.hosted.phases.SharedGraphBuilderPhase; + import jdk.graal.compiler.java.BytecodeParser; import jdk.graal.compiler.java.GraphBuilderPhase; import jdk.graal.compiler.nodes.StructuredGraph; @@ -31,19 +33,35 @@ import jdk.graal.compiler.nodes.graphbuilderconf.IntrinsicContext; import jdk.graal.compiler.nodes.spi.CoreProviders; import jdk.graal.compiler.phases.OptimisticOptimizations; - -import com.oracle.svm.hosted.phases.SharedGraphBuilderPhase; - +import jdk.graal.compiler.phases.util.Providers; +import jdk.graal.compiler.word.WordTypes; import jdk.vm.ci.meta.ResolvedJavaMethod; public class ClassInitializerGraphBuilderPhase extends SharedGraphBuilderPhase { public ClassInitializerGraphBuilderPhase(CoreProviders providers, GraphBuilderConfiguration graphBuilderConfig, OptimisticOptimizations optimisticOpts) { - /* - * We do not want any word-type checking when parsing the class initializers, because we do - * not have the graph builder plugins for word types installed either. Passing null as the - * WordTypes disables the word type checks in the bytecode parser. - */ - super(providers, graphBuilderConfig, optimisticOpts, null, null); + super(clearWordTypes(providers), graphBuilderConfig, optimisticOpts, null); + } + + /** + * We do not want any word-type checking when parsing the class initializers, because we do not + * have the graph builder plugins for word types installed either. Passing null as the WordTypes + * disables the word type checks in the bytecode parser. + */ + private static Providers clearWordTypes(CoreProviders providers) { + WordTypes wordTypes = null; + return new Providers(providers.getMetaAccess(), + providers.getCodeCache(), + providers.getConstantReflection(), + providers.getConstantFieldProvider(), + providers.getForeignCalls(), + providers.getLowerer(), + providers.getReplacements(), + providers.getStampProvider(), + providers.getPlatformConfigurationProvider(), + providers.getMetaAccessExtensionProvider(), + providers.getSnippetReflection(), + wordTypes, + providers.getLoopsDataProvider()); } @Override diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/code/CompileQueue.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/code/CompileQueue.java index 748ce07d4133..dc1f6fa2b35a 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/code/CompileQueue.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/code/CompileQueue.java @@ -38,8 +38,6 @@ import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; -import com.oracle.svm.core.config.ConfigurationValues; -import jdk.graal.compiler.nodes.GraphEncoder; import org.graalvm.collections.EconomicMap; import org.graalvm.nativeimage.ImageSingletons; @@ -52,6 +50,7 @@ import com.oracle.svm.core.SubstrateOptions; import com.oracle.svm.core.SubstrateOptions.OptimizationLevel; import com.oracle.svm.core.Uninterruptible; +import com.oracle.svm.core.config.ConfigurationValues; import com.oracle.svm.core.deopt.DeoptTest; import com.oracle.svm.core.deopt.Specialize; import com.oracle.svm.core.graal.code.SubstrateBackend; @@ -87,7 +86,6 @@ import jdk.graal.compiler.core.GraalCompiler; import jdk.graal.compiler.core.common.CompilationIdentifier; import jdk.graal.compiler.core.common.CompilationIdentifier.Verbosity; -import jdk.graal.compiler.core.common.spi.CodeGenProviders; import jdk.graal.compiler.debug.DebugContext; import jdk.graal.compiler.debug.DebugContext.Description; import jdk.graal.compiler.debug.DebugHandlersFactory; @@ -109,6 +107,7 @@ import jdk.graal.compiler.nodes.ConstantNode; import jdk.graal.compiler.nodes.EncodedGraph; import jdk.graal.compiler.nodes.FrameState; +import jdk.graal.compiler.nodes.GraphEncoder; import jdk.graal.compiler.nodes.GraphState.GuardsStage; import jdk.graal.compiler.nodes.GraphState.StageFlag; import jdk.graal.compiler.nodes.IndirectCallTargetNode; @@ -122,6 +121,7 @@ import jdk.graal.compiler.nodes.graphbuilderconf.GraphBuilderContext; import jdk.graal.compiler.nodes.graphbuilderconf.InlineInvokePlugin; import jdk.graal.compiler.nodes.java.MethodCallTargetNode; +import jdk.graal.compiler.nodes.spi.CoreProviders; import jdk.graal.compiler.options.OptionValues; import jdk.graal.compiler.phases.OptimisticOptimizations; import jdk.graal.compiler.phases.Phase; @@ -1149,7 +1149,7 @@ protected void ensureCompiled(HostedMethod method, CompileReason reason) { class HostedCompilationResultBuilderFactory implements CompilationResultBuilderFactory { @Override - public CompilationResultBuilder createBuilder(CodeGenProviders providers, + public CompilationResultBuilder createBuilder(CoreProviders providers, FrameMap frameMap, Assembler asm, DataBuilder dataBuilder, diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/code/HostedReplacements.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/code/HostedReplacements.java index 5ec4af114311..7ffd8a9454b3 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/code/HostedReplacements.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/code/HostedReplacements.java @@ -26,20 +26,18 @@ import java.util.IdentityHashMap; -import jdk.graal.compiler.api.replacements.SnippetReflectionProvider; -import jdk.graal.compiler.bytecode.BytecodeProvider; -import jdk.graal.compiler.java.BytecodeParser; -import jdk.graal.compiler.nodes.GraphEncoder; -import jdk.graal.compiler.options.OptionValues; -import jdk.graal.compiler.phases.util.Providers; -import jdk.graal.compiler.word.WordTypes; - import com.oracle.graal.pointsto.meta.AnalysisUniverse; import com.oracle.graal.pointsto.meta.HostedProviders; import com.oracle.svm.core.graal.meta.SubstrateReplacements; import com.oracle.svm.hosted.meta.HostedMethod; import com.oracle.svm.hosted.meta.HostedUniverse; +import jdk.graal.compiler.api.replacements.SnippetReflectionProvider; +import jdk.graal.compiler.bytecode.BytecodeProvider; +import jdk.graal.compiler.java.BytecodeParser; +import jdk.graal.compiler.nodes.GraphEncoder; +import jdk.graal.compiler.options.OptionValues; +import jdk.graal.compiler.phases.util.Providers; import jdk.vm.ci.code.TargetDescription; import jdk.vm.ci.meta.ResolvedJavaMethod; @@ -67,8 +65,8 @@ public class HostedReplacements extends SubstrateReplacements { private final SubstrateReplacements aReplacements; public HostedReplacements(HostedUniverse hUniverse, Providers providers, SnippetReflectionProvider snippetReflection, TargetDescription target, HostedProviders anaylysisProviders, - BytecodeProvider bytecodeProvider, WordTypes wordTypes) { - super(providers, snippetReflection, bytecodeProvider, target, wordTypes, null); + BytecodeProvider bytecodeProvider) { + super(providers, snippetReflection, bytecodeProvider, target, null); this.hUniverse = hUniverse; this.aReplacements = (SubstrateReplacements) anaylysisProviders.getReplacements(); } diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/code/HostedRuntimeConfigurationBuilder.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/code/HostedRuntimeConfigurationBuilder.java index 63a320149dc2..24eaaefe2e6c 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/code/HostedRuntimeConfigurationBuilder.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/code/HostedRuntimeConfigurationBuilder.java @@ -94,7 +94,7 @@ protected LoweringProvider createLoweringProvider(ForeignCallsProvider foreignCa @Override protected Replacements createReplacements(Providers p, SnippetReflectionProvider reflectionProvider) { BytecodeProvider bytecodeProvider = new ResolvedJavaMethodBytecodeProvider(); - return new HostedReplacements(universe, p, reflectionProvider, ConfigurationValues.getTarget(), analysisProviders, bytecodeProvider, p.getWordTypes()); + return new HostedReplacements(universe, p, reflectionProvider, ConfigurationValues.getTarget(), analysisProviders, bytecodeProvider); } @Override diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/code/SubstrateGraphMaker.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/code/SubstrateGraphMaker.java index dd7ce7eed105..00a57fccd204 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/code/SubstrateGraphMaker.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/code/SubstrateGraphMaker.java @@ -26,6 +26,8 @@ import java.util.BitSet; +import com.oracle.svm.hosted.phases.SubstrateGraphBuilderPhase; + import jdk.graal.compiler.bytecode.BytecodeProvider; import jdk.graal.compiler.debug.DebugContext; import jdk.graal.compiler.graph.NodeSourcePosition; @@ -37,24 +39,17 @@ import jdk.graal.compiler.phases.util.Providers; import jdk.graal.compiler.replacements.ReplacementsImpl; import jdk.graal.compiler.replacements.ReplacementsImpl.GraphMaker; -import jdk.graal.compiler.word.WordTypes; - -import com.oracle.svm.hosted.phases.SubstrateGraphBuilderPhase; - import jdk.vm.ci.meta.ResolvedJavaMethod; public class SubstrateGraphMaker extends GraphMaker { - private final WordTypes wordTypes; - - public SubstrateGraphMaker(ReplacementsImpl replacements, ResolvedJavaMethod substitute, ResolvedJavaMethod substitutedMethod, WordTypes wordTypes) { + public SubstrateGraphMaker(ReplacementsImpl replacements, ResolvedJavaMethod substitute, ResolvedJavaMethod substitutedMethod) { super(replacements, substitute, substitutedMethod); - this.wordTypes = wordTypes; } @Override protected Instance createGraphBuilder(Providers providers, GraphBuilderConfiguration graphBuilderConfig, OptimisticOptimizations optimisticOpts, IntrinsicContext initialIntrinsicContext) { - return new SubstrateGraphBuilderPhase(providers, graphBuilderConfig, optimisticOpts, initialIntrinsicContext, wordTypes); + return new SubstrateGraphBuilderPhase(providers, graphBuilderConfig, optimisticOpts, initialIntrinsicContext); } @Override diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/code/SubstrateGraphMakerFactory.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/code/SubstrateGraphMakerFactory.java index 1143be0a296f..ef38c27f0136 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/code/SubstrateGraphMakerFactory.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/code/SubstrateGraphMakerFactory.java @@ -24,25 +24,17 @@ */ package com.oracle.svm.hosted.code; -import jdk.vm.ci.meta.MetaAccessProvider; -import jdk.graal.compiler.replacements.ReplacementsImpl; -import jdk.graal.compiler.replacements.ReplacementsImpl.GraphMaker; -import jdk.graal.compiler.word.WordTypes; - import com.oracle.svm.core.graal.meta.SubstrateReplacements; +import jdk.graal.compiler.replacements.ReplacementsImpl; +import jdk.graal.compiler.replacements.ReplacementsImpl.GraphMaker; +import jdk.vm.ci.meta.MetaAccessProvider; import jdk.vm.ci.meta.ResolvedJavaMethod; public class SubstrateGraphMakerFactory implements SubstrateReplacements.GraphMakerFactory { - protected final WordTypes wordTypes; - - public SubstrateGraphMakerFactory(WordTypes wordTypes) { - this.wordTypes = wordTypes; - } - @Override public GraphMaker create(MetaAccessProvider metaAccess, ReplacementsImpl replacements, ResolvedJavaMethod substitute, ResolvedJavaMethod substitutedMethod) { - return new SubstrateGraphMaker(replacements, substitute, substitutedMethod, wordTypes); + return new SubstrateGraphMaker(replacements, substitute, substitutedMethod); } } diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/phases/AnalysisGraphBuilderPhase.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/phases/AnalysisGraphBuilderPhase.java index bbd3c04c1a4c..df68872714bf 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/phases/AnalysisGraphBuilderPhase.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/phases/AnalysisGraphBuilderPhase.java @@ -44,7 +44,6 @@ import jdk.graal.compiler.nodes.graphbuilderconf.NodePlugin; import jdk.graal.compiler.nodes.spi.CoreProviders; import jdk.graal.compiler.phases.OptimisticOptimizations; -import jdk.graal.compiler.word.WordTypes; import jdk.vm.ci.meta.JavaKind; import jdk.vm.ci.meta.ResolvedJavaField; import jdk.vm.ci.meta.ResolvedJavaMethod; @@ -54,8 +53,8 @@ public class AnalysisGraphBuilderPhase extends SharedGraphBuilderPhase { protected final SVMHost hostVM; public AnalysisGraphBuilderPhase(CoreProviders providers, - GraphBuilderConfiguration graphBuilderConfig, OptimisticOptimizations optimisticOpts, IntrinsicContext initialIntrinsicContext, WordTypes wordTypes, SVMHost hostVM) { - super(providers, graphBuilderConfig, optimisticOpts, initialIntrinsicContext, wordTypes); + GraphBuilderConfiguration graphBuilderConfig, OptimisticOptimizations optimisticOpts, IntrinsicContext initialIntrinsicContext, SVMHost hostVM) { + super(providers, graphBuilderConfig, optimisticOpts, initialIntrinsicContext); this.hostVM = hostVM; } diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/phases/SharedGraphBuilderPhase.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/phases/SharedGraphBuilderPhase.java index d7276b025697..d08d9e0b9764 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/phases/SharedGraphBuilderPhase.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/phases/SharedGraphBuilderPhase.java @@ -86,7 +86,6 @@ import jdk.graal.compiler.nodes.spi.CoreProviders; import jdk.graal.compiler.phases.OptimisticOptimizations; import jdk.graal.compiler.replacements.SnippetTemplate; -import jdk.graal.compiler.word.WordTypes; import jdk.vm.ci.meta.JavaConstant; import jdk.vm.ci.meta.JavaField; import jdk.vm.ci.meta.JavaKind; @@ -97,18 +96,15 @@ import jdk.vm.ci.meta.ResolvedJavaType; public abstract class SharedGraphBuilderPhase extends GraphBuilderPhase.Instance { - final WordTypes wordTypes; - public SharedGraphBuilderPhase(CoreProviders providers, GraphBuilderConfiguration graphBuilderConfig, OptimisticOptimizations optimisticOpts, IntrinsicContext initialIntrinsicContext, - WordTypes wordTypes) { + public SharedGraphBuilderPhase(CoreProviders providers, GraphBuilderConfiguration graphBuilderConfig, OptimisticOptimizations optimisticOpts, IntrinsicContext initialIntrinsicContext) { super(providers, graphBuilderConfig, optimisticOpts, initialIntrinsicContext); - this.wordTypes = wordTypes; } @Override protected void run(StructuredGraph graph) { super.run(graph); - assert wordTypes == null || wordTypes.ensureGraphContainsNoWordTypeReferences(graph); + assert providers.getWordTypes() == null || providers.getWordTypes().ensureGraphContainsNoWordTypeReferences(graph); } public abstract static class SharedBytecodeParser extends BytecodeParser { @@ -176,10 +172,6 @@ protected RuntimeException throwParserError(Throwable e) { throw super.throwParserError(e); } - private WordTypes getWordTypes() { - return ((SharedGraphBuilderPhase) getGraphBuilderInstance()).wordTypes; - } - private boolean checkWordTypes() { return getWordTypes() != null; } diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/phases/SubstrateGraphBuilderPhase.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/phases/SubstrateGraphBuilderPhase.java index 4d80120d8d41..a615e58aabe7 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/phases/SubstrateGraphBuilderPhase.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/phases/SubstrateGraphBuilderPhase.java @@ -24,6 +24,8 @@ */ package com.oracle.svm.hosted.phases; +import com.oracle.graal.pointsto.meta.AnalysisMethod; + import jdk.graal.compiler.java.BytecodeParser; import jdk.graal.compiler.java.GraphBuilderPhase; import jdk.graal.compiler.nodes.StructuredGraph; @@ -33,17 +35,13 @@ import jdk.graal.compiler.nodes.graphbuilderconf.IntrinsicContext; import jdk.graal.compiler.nodes.spi.CoreProviders; import jdk.graal.compiler.phases.OptimisticOptimizations; -import jdk.graal.compiler.word.WordTypes; - -import com.oracle.graal.pointsto.meta.AnalysisMethod; - import jdk.vm.ci.meta.ResolvedJavaMethod; public class SubstrateGraphBuilderPhase extends SharedGraphBuilderPhase { public SubstrateGraphBuilderPhase(CoreProviders providers, - GraphBuilderConfiguration graphBuilderConfig, OptimisticOptimizations optimisticOpts, IntrinsicContext initialIntrinsicContext, WordTypes wordTypes) { - super(providers, graphBuilderConfig, optimisticOpts, initialIntrinsicContext, wordTypes); + GraphBuilderConfiguration graphBuilderConfig, OptimisticOptimizations optimisticOpts, IntrinsicContext initialIntrinsicContext) { + super(providers, graphBuilderConfig, optimisticOpts, initialIntrinsicContext); } @Override From b3f27fef86747a2bf6508305a1ca137da23d1e99 Mon Sep 17 00:00:00 2001 From: Christian Wimmer Date: Tue, 5 Dec 2023 13:21:43 -0800 Subject: [PATCH 099/593] Do not pass WordTypes to places that already have a Provider --- .../stubs/AbstractForeignCallStub.java | 6 +- .../hotspot/stubs/HotSpotGraphKit.java | 5 +- .../graal/compiler/replacements/GraphKit.java | 16 ++-- .../core/graal/meta/RuntimeConfiguration.java | 15 +--- .../graal/replacements/SubstrateGraphKit.java | 20 ++--- .../hosted/RuntimeCompilationFeature.java | 4 +- .../svm/hosted/NativeImageGenerator.java | 2 +- .../SharedRuntimeConfigurationBuilder.java | 2 +- .../oracle/svm/hosted/jni/JNIGraphKit.java | 2 +- .../phases/CInterfaceInvocationPlugin.java | 78 +++++++++---------- .../svm/hosted/phases/HostedGraphKit.java | 2 +- 11 files changed, 62 insertions(+), 90 deletions(-) diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/stubs/AbstractForeignCallStub.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/stubs/AbstractForeignCallStub.java index 1422183bc0b5..bea574ddd69c 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/stubs/AbstractForeignCallStub.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/stubs/AbstractForeignCallStub.java @@ -50,7 +50,6 @@ import jdk.graal.compiler.options.OptionValues; import jdk.graal.compiler.replacements.GraphKit; import jdk.graal.compiler.replacements.nodes.ReadRegisterNode; -import jdk.graal.compiler.word.WordTypes; import jdk.vm.ci.hotspot.HotSpotJVMCIRuntime; import jdk.vm.ci.hotspot.HotSpotSignature; import jdk.vm.ci.meta.JavaMethod; @@ -225,7 +224,6 @@ protected final Object debugScopeContext() { @Override @SuppressWarnings("try") protected final StructuredGraph getGraph(DebugContext debug, CompilationIdentifier compilationId) { - WordTypes wordTypes = providers.getWordTypes(); boolean isObjectResult = returnsObject(); // Do we want to clear the pending exception? boolean shouldClearException = shouldClearException(); @@ -235,10 +233,10 @@ protected final StructuredGraph getGraph(DebugContext debug, CompilationIdentifi ResolvedJavaMethod handlePendingException = foreignCallSnippets.handlePendingException.getMethod(); ResolvedJavaMethod getAndClearObjectResult = foreignCallSnippets.getAndClearObjectResult.getMethod(); ResolvedJavaMethod thisMethod = getGraphMethod(); - HotSpotGraphKit kit = new HotSpotGraphKit(debug, thisMethod, providers, wordTypes, providers.getGraphBuilderPlugins(), compilationId, toString(), false, true); + HotSpotGraphKit kit = new HotSpotGraphKit(debug, thisMethod, providers, providers.getGraphBuilderPlugins(), compilationId, toString(), false, true); StructuredGraph graph = kit.getGraph(); graph.getGraphState().forceDisableFrameStateVerification(); - ReadRegisterNode thread = kit.append(new ReadRegisterNode(providers.getRegisters().getThreadRegister(), wordTypes.getWordKind(), true, false)); + ReadRegisterNode thread = kit.append(new ReadRegisterNode(providers.getRegisters().getThreadRegister(), providers.getWordTypes().getWordKind(), true, false)); ValueNode result = createTargetCall(kit, thread); if (linkage.getDescriptor().getTransition() == HotSpotForeignCallDescriptor.Transition.SAFEPOINT) { kit.createIntrinsicInvoke(handlePendingException, thread, forBoolean(shouldClearException, graph), forBoolean(isObjectResult, graph)); diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/stubs/HotSpotGraphKit.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/stubs/HotSpotGraphKit.java index c3dd04b51b2a..5923443b219e 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/stubs/HotSpotGraphKit.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/stubs/HotSpotGraphKit.java @@ -44,7 +44,6 @@ import jdk.graal.compiler.phases.common.inlining.InliningUtil; import jdk.graal.compiler.phases.util.Providers; import jdk.graal.compiler.replacements.GraphKit; -import jdk.graal.compiler.word.WordTypes; import jdk.vm.ci.meta.ResolvedJavaMethod; /** @@ -56,9 +55,9 @@ */ public class HotSpotGraphKit extends GraphKit { - public HotSpotGraphKit(DebugContext debug, ResolvedJavaMethod stubMethod, Providers providers, WordTypes wordTypes, Plugins graphBuilderPlugins, CompilationIdentifier compilationId, String name, + public HotSpotGraphKit(DebugContext debug, ResolvedJavaMethod stubMethod, Providers providers, Plugins graphBuilderPlugins, CompilationIdentifier compilationId, String name, boolean trackNodeSourcePosition, boolean recordInlinedMethods) { - super(debug, stubMethod, providers, wordTypes, graphBuilderPlugins, compilationId, name, trackNodeSourcePosition, recordInlinedMethods); + super(debug, stubMethod, providers, graphBuilderPlugins, compilationId, name, trackNodeSourcePosition, recordInlinedMethods); } /** diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/replacements/GraphKit.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/replacements/GraphKit.java index caafa28a746c..2827a682e325 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/replacements/GraphKit.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/replacements/GraphKit.java @@ -76,7 +76,6 @@ import jdk.graal.compiler.nodes.spi.CoreProvidersDelegate; import jdk.graal.compiler.nodes.type.StampTool; import jdk.graal.compiler.phases.util.Providers; -import jdk.graal.compiler.word.WordTypes; import jdk.vm.ci.code.BytecodeFrame; import jdk.vm.ci.meta.JavaKind; import jdk.vm.ci.meta.JavaType; @@ -92,7 +91,6 @@ public abstract class GraphKit extends CoreProvidersDelegate implements GraphBuilderTool { protected final StructuredGraph graph; - protected final WordTypes wordTypes; protected final GraphBuilderConfiguration.Plugins graphBuilderPlugins; protected FixedWithNextNode lastFixedNode; @@ -101,7 +99,7 @@ public abstract class GraphKit extends CoreProvidersDelegate implements GraphBui protected abstract static class Structure { } - public GraphKit(DebugContext debug, ResolvedJavaMethod stubMethod, Providers providers, WordTypes wordTypes, Plugins graphBuilderPlugins, CompilationIdentifier compilationId, String name, + public GraphKit(DebugContext debug, ResolvedJavaMethod stubMethod, Providers providers, Plugins graphBuilderPlugins, CompilationIdentifier compilationId, String name, boolean trackNodeSourcePosition, boolean recordInlinedMethods) { super(providers); StructuredGraph.Builder builder = new StructuredGraph.Builder(debug.getOptions(), debug).recordInlinedMethods(recordInlinedMethods).compilationId(compilationId).profileProvider(null); @@ -120,7 +118,6 @@ public GraphKit(DebugContext debug, ResolvedJavaMethod stubMethod, Providers pro graph.withNodeSourcePosition(NodeSourcePosition.substitution(stubMethod)); } graph.recordMethod(stubMethod); - this.wordTypes = wordTypes; this.graphBuilderPlugins = graphBuilderPlugins; this.lastFixedNode = graph.start(); @@ -156,20 +153,19 @@ public T add(T node) { } public T changeToWord(T node) { - if (node instanceof ValueNode valueNode && wordTypes != null && wordTypes.isWord(valueNode)) { - valueNode.setStamp(wordTypes.getWordStamp(StampTool.typeOrNull(valueNode))); + if (node instanceof ValueNode valueNode && getWordTypes() != null && getWordTypes().isWord(valueNode)) { + valueNode.setStamp(getWordTypes().getWordStamp(StampTool.typeOrNull(valueNode))); } return node; } public Stamp wordStamp(ResolvedJavaType type) { - assert wordTypes != null; - assert wordTypes.isWord(type) : type; - return wordTypes.getWordStamp(type); + assert getWordTypes().isWord(type) : type; + return getWordTypes().getWordStamp(type); } public final JavaKind asKind(JavaType type) { - return wordTypes != null ? wordTypes.asKind(type) : type.getJavaKind(); + return getWordTypes() != null ? getWordTypes().asKind(type) : type.getJavaKind(); } @Override diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/graal/meta/RuntimeConfiguration.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/graal/meta/RuntimeConfiguration.java index 826c68707dfc..6e39ecec67b8 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/graal/meta/RuntimeConfiguration.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/graal/meta/RuntimeConfiguration.java @@ -27,10 +27,6 @@ import java.util.Collection; import java.util.EnumMap; -import jdk.graal.compiler.api.replacements.SnippetReflectionProvider; -import jdk.graal.compiler.debug.DebugHandlersFactory; -import jdk.graal.compiler.phases.util.Providers; -import jdk.graal.compiler.word.WordTypes; import org.graalvm.nativeimage.Platform; import org.graalvm.nativeimage.Platforms; @@ -38,6 +34,9 @@ import com.oracle.svm.core.graal.meta.SubstrateRegisterConfig.ConfigKind; import com.oracle.svm.core.meta.SharedMethod; +import jdk.graal.compiler.api.replacements.SnippetReflectionProvider; +import jdk.graal.compiler.debug.DebugHandlersFactory; +import jdk.graal.compiler.phases.util.Providers; import jdk.vm.ci.meta.ResolvedJavaMethod; /** @@ -49,16 +48,14 @@ public final class RuntimeConfiguration { private final SnippetReflectionProvider snippetReflection; private final EnumMap backends; private final Iterable debugHandlersFactories; - private final WordTypes wordTypes; @Platforms(Platform.HOSTED_ONLY.class) - public RuntimeConfiguration(Providers providers, SnippetReflectionProvider snippetReflection, EnumMap backends, WordTypes wordTypes, + public RuntimeConfiguration(Providers providers, SnippetReflectionProvider snippetReflection, EnumMap backends, Iterable debugHandlersFactories) { this.providers = providers; this.snippetReflection = snippetReflection; this.backends = backends; this.debugHandlersFactories = debugHandlersFactories; - this.wordTypes = wordTypes; for (SubstrateBackend backend : backends.values()) { backend.setRuntimeConfiguration(this); @@ -92,8 +89,4 @@ public SubstrateBackend getBackendForNormalMethod() { public SnippetReflectionProvider getSnippetReflection() { return snippetReflection; } - - public WordTypes getWordTypes() { - return wordTypes; - } } diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/graal/replacements/SubstrateGraphKit.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/graal/replacements/SubstrateGraphKit.java index 78f021e08a6b..16388d5513c1 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/graal/replacements/SubstrateGraphKit.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/graal/replacements/SubstrateGraphKit.java @@ -27,8 +27,6 @@ import java.util.ArrayList; import java.util.List; -import org.graalvm.word.WordBase; - import com.oracle.svm.core.graal.code.SubstrateCallingConventionKind; import com.oracle.svm.core.graal.meta.SubstrateLoweringProvider; import com.oracle.svm.core.graal.nodes.DeoptEntryNode; @@ -83,7 +81,6 @@ import jdk.graal.compiler.phases.common.inlining.InliningUtil; import jdk.graal.compiler.phases.util.Providers; import jdk.graal.compiler.replacements.GraphKit; -import jdk.graal.compiler.word.WordTypes; import jdk.vm.ci.code.BytecodeFrame; import jdk.vm.ci.code.CallingConvention; import jdk.vm.ci.meta.Constant; @@ -100,10 +97,10 @@ public class SubstrateGraphKit extends GraphKit { private int nextBCI; @SuppressWarnings("this-escape") - public SubstrateGraphKit(DebugContext debug, ResolvedJavaMethod stubMethod, Providers providers, WordTypes wordTypes, + public SubstrateGraphKit(DebugContext debug, ResolvedJavaMethod stubMethod, Providers providers, GraphBuilderConfiguration.Plugins graphBuilderPlugins, CompilationIdentifier compilationId, boolean recordInlinedMethods) { - super(debug, stubMethod, providers, wordTypes, graphBuilderPlugins, compilationId, null, true, recordInlinedMethods); - assert wordTypes != null : "Support for Word types is mandatory"; + super(debug, stubMethod, providers, graphBuilderPlugins, compilationId, null, true, recordInlinedMethods); + assert getWordTypes() != null : "Support for Word types is mandatory"; frameState = new FrameStateBuilder(this, stubMethod, graph); frameState.disableKindVerification(); frameState.disableStateVerification(); @@ -111,9 +108,8 @@ public SubstrateGraphKit(DebugContext debug, ResolvedJavaMethod stubMethod, Prov graph.start().setStateAfter(frameState.create(bci(), graph.start())); } - public SubstrateGraphKit(DebugContext debug, ResolvedJavaMethod stubMethod, Providers providers, WordTypes wordTypes, - GraphBuilderConfiguration.Plugins graphBuilderPlugins, CompilationIdentifier compilationId) { - this(debug, stubMethod, providers, wordTypes, graphBuilderPlugins, compilationId, false); + public SubstrateGraphKit(DebugContext debug, ResolvedJavaMethod stubMethod, Providers providers, GraphBuilderConfiguration.Plugins graphBuilderPlugins, CompilationIdentifier compilationId) { + this(debug, stubMethod, providers, graphBuilderPlugins, compilationId, false); } @Override @@ -329,10 +325,6 @@ public int bci() { return nextBCI++; } - public static boolean isWord(Class klass) { - return WordBase.class.isAssignableFrom(klass); - } - public StructuredGraph finalizeGraph() { if (lastFixedNode != null) { throw VMError.shouldNotReachHere("Manually constructed graph does not terminate control flow properly. lastFixedNode: " + lastFixedNode); @@ -340,7 +332,7 @@ public StructuredGraph finalizeGraph() { mergeUnwinds(); assert graph.verify(); - assert wordTypes.ensureGraphContainsNoWordTypeReferences(graph); + assert getWordTypes().ensureGraphContainsNoWordTypeReferences(graph); return graph; } diff --git a/substratevm/src/com.oracle.svm.graal/src/com/oracle/svm/graal/hosted/RuntimeCompilationFeature.java b/substratevm/src/com.oracle.svm.graal/src/com/oracle/svm/graal/hosted/RuntimeCompilationFeature.java index 77b14a7b94e0..25829a88652a 100644 --- a/substratevm/src/com.oracle.svm.graal/src/com/oracle/svm/graal/hosted/RuntimeCompilationFeature.java +++ b/substratevm/src/com.oracle.svm.graal/src/com/oracle/svm/graal/hosted/RuntimeCompilationFeature.java @@ -118,7 +118,6 @@ import jdk.graal.compiler.phases.tiers.Suites; import jdk.graal.compiler.phases.util.Providers; import jdk.graal.compiler.truffle.nodes.ObjectLocationIdentity; -import jdk.graal.compiler.word.WordTypes; import jdk.vm.ci.code.Architecture; import jdk.vm.ci.meta.JavaConstant; import jdk.vm.ci.meta.JavaKind; @@ -384,10 +383,9 @@ private void installRuntimeConfig(BeforeAnalysisAccessImpl config) { .build(); Providers runtimeProviders = runtimeConfig.getProviders(); - WordTypes wordTypes = runtimeConfig.getWordTypes(); hostedProviders = new HostedProviders(runtimeProviders.getMetaAccess(), runtimeProviders.getCodeCache(), runtimeProviders.getConstantReflection(), runtimeProviders.getConstantFieldProvider(), runtimeProviders.getForeignCalls(), runtimeProviders.getLowerer(), runtimeProviders.getReplacements(), runtimeProviders.getStampProvider(), - runtimeConfig.getSnippetReflection(), wordTypes, runtimeProviders.getPlatformConfigurationProvider(), new GraphPrepareMetaAccessExtensionProvider(), + runtimeConfig.getSnippetReflection(), runtimeProviders.getWordTypes(), runtimeProviders.getPlatformConfigurationProvider(), new GraphPrepareMetaAccessExtensionProvider(), runtimeProviders.getLoopsDataProvider()); FeatureHandler featureHandler = config.getFeatureHandler(); diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/NativeImageGenerator.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/NativeImageGenerator.java index e082a6a4d4d2..b1c12c46ad2a 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/NativeImageGenerator.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/NativeImageGenerator.java @@ -1362,7 +1362,7 @@ public static void registerGraphBuilderPlugins(FeatureHandler featureHandler, Ru plugins.appendNodePlugin(new InjectedAccessorsPlugin()); plugins.appendNodePlugin(new EarlyConstantFoldLoadFieldPlugin(providers.getMetaAccess())); plugins.appendNodePlugin(new ConstantFoldLoadFieldPlugin(reason)); - plugins.appendNodePlugin(new CInterfaceInvocationPlugin(providers.getMetaAccess(), hostedSnippetReflection, providers.getWordTypes(), nativeLibs)); + plugins.appendNodePlugin(new CInterfaceInvocationPlugin(providers.getMetaAccess(), hostedSnippetReflection, nativeLibs)); plugins.appendNodePlugin(new LocalizationFeature.CharsetNodePlugin()); plugins.appendInlineInvokePlugin(wordOperationPlugin); diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/code/SharedRuntimeConfigurationBuilder.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/code/SharedRuntimeConfigurationBuilder.java index 6272b07e2703..27bdbefe72b6 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/code/SharedRuntimeConfigurationBuilder.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/code/SharedRuntimeConfigurationBuilder.java @@ -147,7 +147,7 @@ public final RuntimeConfiguration build() { } } - return new RuntimeConfiguration(p, snippetReflection, backends, wordTypes, handlers); + return new RuntimeConfiguration(p, snippetReflection, backends, handlers); } protected abstract Providers createProviders(CodeCacheProvider codeCache, ConstantReflectionProvider constantReflection, ConstantFieldProvider constantFieldProvider, diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/jni/JNIGraphKit.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/jni/JNIGraphKit.java index 3e354d89dd12..75a98c8d4a19 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/jni/JNIGraphKit.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/jni/JNIGraphKit.java @@ -227,6 +227,6 @@ public FixedWithNextNode setPrimitiveArrayRegionRetainException(JavaKind element } public ConstantNode createWord(long value) { - return ConstantNode.forIntegerKind(wordTypes.getWordKind(), value, graph); + return ConstantNode.forIntegerKind(getWordTypes().getWordKind(), value, graph); } } diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/phases/CInterfaceInvocationPlugin.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/phases/CInterfaceInvocationPlugin.java index 3f1b534d43e8..596cf4254251 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/phases/CInterfaceInvocationPlugin.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/phases/CInterfaceInvocationPlugin.java @@ -29,6 +29,36 @@ import java.util.Arrays; +import org.graalvm.nativeimage.c.function.CEntryPoint; +import org.graalvm.nativeimage.c.function.CFunctionPointer; +import org.graalvm.nativeimage.c.function.InvokeCFunctionPointer; +import org.graalvm.word.LocationIdentity; + +import com.oracle.graal.pointsto.meta.AnalysisMethod; +import com.oracle.svm.core.FrameAccess; +import com.oracle.svm.core.c.InvokeJavaFunctionPointer; +import com.oracle.svm.core.c.struct.CInterfaceLocationIdentity; +import com.oracle.svm.core.graal.code.SubstrateCallingConventionKind; +import com.oracle.svm.core.graal.nodes.CInterfaceReadNode; +import com.oracle.svm.core.graal.nodes.CInterfaceWriteNode; +import com.oracle.svm.core.util.UserError; +import com.oracle.svm.hosted.c.CInterfaceError; +import com.oracle.svm.hosted.c.NativeLibraries; +import com.oracle.svm.hosted.c.info.AccessorInfo; +import com.oracle.svm.hosted.c.info.AccessorInfo.AccessorKind; +import com.oracle.svm.hosted.c.info.ConstantInfo; +import com.oracle.svm.hosted.c.info.ElementInfo; +import com.oracle.svm.hosted.c.info.PointerToInfo; +import com.oracle.svm.hosted.c.info.SizableInfo; +import com.oracle.svm.hosted.c.info.StructBitfieldInfo; +import com.oracle.svm.hosted.c.info.StructFieldInfo; +import com.oracle.svm.hosted.c.info.StructInfo; +import com.oracle.svm.hosted.code.CEntryPointCallStubSupport; +import com.oracle.svm.hosted.code.CEntryPointJavaCallStubMethod; +import com.oracle.svm.hosted.code.CFunctionPointerCallStubSupport; +import com.oracle.svm.hosted.meta.HostedMetaAccess; +import com.oracle.svm.hosted.meta.HostedMethod; + import jdk.graal.compiler.api.replacements.SnippetReflectionProvider; import jdk.graal.compiler.core.common.calc.FloatConvert; import jdk.graal.compiler.core.common.memory.BarrierType; @@ -62,37 +92,6 @@ import jdk.graal.compiler.nodes.graphbuilderconf.NodePlugin; import jdk.graal.compiler.nodes.memory.address.AddressNode; import jdk.graal.compiler.nodes.memory.address.OffsetAddressNode; -import jdk.graal.compiler.word.WordTypes; -import org.graalvm.nativeimage.c.function.CEntryPoint; -import org.graalvm.nativeimage.c.function.CFunctionPointer; -import org.graalvm.nativeimage.c.function.InvokeCFunctionPointer; -import org.graalvm.word.LocationIdentity; - -import com.oracle.graal.pointsto.meta.AnalysisMethod; -import com.oracle.svm.core.FrameAccess; -import com.oracle.svm.core.c.InvokeJavaFunctionPointer; -import com.oracle.svm.core.c.struct.CInterfaceLocationIdentity; -import com.oracle.svm.core.graal.code.SubstrateCallingConventionKind; -import com.oracle.svm.core.graal.nodes.CInterfaceReadNode; -import com.oracle.svm.core.graal.nodes.CInterfaceWriteNode; -import com.oracle.svm.core.util.UserError; -import com.oracle.svm.hosted.c.CInterfaceError; -import com.oracle.svm.hosted.c.NativeLibraries; -import com.oracle.svm.hosted.c.info.AccessorInfo; -import com.oracle.svm.hosted.c.info.AccessorInfo.AccessorKind; -import com.oracle.svm.hosted.c.info.ConstantInfo; -import com.oracle.svm.hosted.c.info.ElementInfo; -import com.oracle.svm.hosted.c.info.PointerToInfo; -import com.oracle.svm.hosted.c.info.SizableInfo; -import com.oracle.svm.hosted.c.info.StructBitfieldInfo; -import com.oracle.svm.hosted.c.info.StructFieldInfo; -import com.oracle.svm.hosted.c.info.StructInfo; -import com.oracle.svm.hosted.code.CEntryPointCallStubSupport; -import com.oracle.svm.hosted.code.CEntryPointJavaCallStubMethod; -import com.oracle.svm.hosted.code.CFunctionPointerCallStubSupport; -import com.oracle.svm.hosted.meta.HostedMetaAccess; -import com.oracle.svm.hosted.meta.HostedMethod; - import jdk.vm.ci.meta.JavaKind; import jdk.vm.ci.meta.JavaType; import jdk.vm.ci.meta.MetaAccessProvider; @@ -100,15 +99,12 @@ import jdk.vm.ci.meta.ResolvedJavaType; public class CInterfaceInvocationPlugin implements NodePlugin { - private final WordTypes wordTypes; - private final NativeLibraries nativeLibs; private final ResolvedJavaType functionPointerType; private final SnippetReflectionProvider snippetReflection; - public CInterfaceInvocationPlugin(MetaAccessProvider metaAccess, SnippetReflectionProvider snippetReflection, WordTypes wordTypes, NativeLibraries nativeLibs) { - this.wordTypes = wordTypes; + public CInterfaceInvocationPlugin(MetaAccessProvider metaAccess, SnippetReflectionProvider snippetReflection, NativeLibraries nativeLibs) { this.nativeLibs = nativeLibs; this.functionPointerType = metaAccess.lookupJavaType(CFunctionPointer.class); this.snippetReflection = snippetReflection; @@ -162,7 +158,7 @@ private boolean replaceOffsetOf(GraphBuilderContext b, ResolvedJavaMethod method */ assert args.length == accessorInfo.parameterCount(!method.isStatic()); - JavaKind kind = wordTypes.asKind(b.getInvokeReturnType()); + JavaKind kind = b.getWordTypes().asKind(b.getInvokeReturnType()); b.addPush(pushKind(method), ConstantNode.forIntegerKind(kind, displacement, b.getGraph())); return true; } @@ -186,7 +182,7 @@ private boolean replaceAccessor(GraphBuilderContext b, ResolvedJavaMethod method return true; } case GETTER: { - JavaKind resultKind = wordTypes.asKind(b.getInvokeReturnType()); + JavaKind resultKind = b.getWordTypes().asKind(b.getInvokeReturnType()); JavaKind readKind = kindFromSize(elementSize, resultKind); if (readKind == JavaKind.Object) { assert resultKind == JavaKind.Object; @@ -316,7 +312,7 @@ private boolean replaceBitfieldAccessor(GraphBuilderContext b, ResolvedJavaMetho cur = graph.unique(new RightShiftNode(cur, ConstantNode.forInt(computeBits - numBits, graph))); } - JavaKind resultKind = wordTypes.asKind(b.getInvokeReturnType()); + JavaKind resultKind = b.getWordTypes().asKind(b.getInvokeReturnType()); b.push(pushKind(method), adaptPrimitiveType(graph, cur, computeKind, resultKind == JavaKind.Boolean ? resultKind : resultKind.getStackKind(), isUnsigned)); return true; } @@ -473,7 +469,7 @@ private static JavaKind kindFromSize(int sizeInBytes, JavaKind matchingKind) { private boolean replaceConstant(GraphBuilderContext b, ResolvedJavaMethod method, ConstantInfo constantInfo) { Object value = constantInfo.getValueInfo().getProperty(); - JavaKind kind = wordTypes.asKind(b.getInvokeReturnType()); + JavaKind kind = b.getWordTypes().asKind(b.getInvokeReturnType()); ConstantNode valueNode; switch (constantInfo.getKind()) { @@ -533,8 +529,8 @@ private boolean replaceJavaFunctionPointerInvoke(GraphBuilderContext b, Resolved assert argsWithoutReceiver.length == parameterTypes.length; Stamp returnStamp; - if (wordTypes.isWord(b.getInvokeReturnType())) { - returnStamp = wordTypes.getWordStamp((ResolvedJavaType) b.getInvokeReturnType()); + if (b.getWordTypes().isWord(b.getInvokeReturnType())) { + returnStamp = b.getWordTypes().getWordStamp((ResolvedJavaType) b.getInvokeReturnType()); } else { returnStamp = b.getInvokeReturnStamp(null).getTrustedStamp(); } diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/phases/HostedGraphKit.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/phases/HostedGraphKit.java index 64563ac088de..84ffed0d53e9 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/phases/HostedGraphKit.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/phases/HostedGraphKit.java @@ -63,7 +63,7 @@ public class HostedGraphKit extends SubstrateGraphKit { public HostedGraphKit(DebugContext debug, HostedProviders providers, ResolvedJavaMethod method) { - super(debug, method, providers, providers.getWordTypes(), providers.getGraphBuilderPlugins(), new SubstrateCompilationIdentifier(), + super(debug, method, providers, providers.getGraphBuilderPlugins(), new SubstrateCompilationIdentifier(), SubstrateCompilationDirectives.isRuntimeCompiledMethod(method)); } From a13df61658c03d89f57c5183bfa53ea921312356 Mon Sep 17 00:00:00 2001 From: Allan Gregersen Date: Wed, 6 Dec 2023 08:52:01 +0100 Subject: [PATCH 100/593] use synchronized blocks for allBindings set due to subtle concurrent modification exception while iterating during stress testing --- .../oracle/truffle/api/debug/Breakpoint.java | 8 ++++++-- .../truffle/api/debug/DebuggerSession.java | 18 ++++++++++++------ 2 files changed, 18 insertions(+), 8 deletions(-) diff --git a/truffle/src/com.oracle.truffle.api.debug/src/com/oracle/truffle/api/debug/Breakpoint.java b/truffle/src/com.oracle.truffle.api.debug/src/com/oracle/truffle/api/debug/Breakpoint.java index c7cdc6314f5a..eb0cf907f20a 100644 --- a/truffle/src/com.oracle.truffle.api.debug/src/com/oracle/truffle/api/debug/Breakpoint.java +++ b/truffle/src/com.oracle.truffle.api.debug/src/com/oracle/truffle/api/debug/Breakpoint.java @@ -680,7 +680,9 @@ private void execBindingAdded(EventBinding if (newBinding != null) { execBindings.add(newBinding); for (DebuggerSession s : sessions) { - s.allBindings.add(newBinding); + synchronized (s.allBindings) { + s.allBindings.add(newBinding); + } } } // If newBinding is null, attach has failed. @@ -758,7 +760,9 @@ private void uninstallBindings(boolean execOnly) { for (EventBinding binding : execBindings) { bindings.add(binding); for (DebuggerSession s : sessions) { - s.allBindings.remove(binding); + synchronized (s.allBindings) { + s.allBindings.remove(binding); + } } } execBindings.clear(); diff --git a/truffle/src/com.oracle.truffle.api.debug/src/com/oracle/truffle/api/debug/DebuggerSession.java b/truffle/src/com.oracle.truffle.api.debug/src/com/oracle/truffle/api/debug/DebuggerSession.java index c677bf908cb9..841a491d3cc2 100644 --- a/truffle/src/com.oracle.truffle.api.debug/src/com/oracle/truffle/api/debug/DebuggerSession.java +++ b/truffle/src/com.oracle.truffle.api.debug/src/com/oracle/truffle/api/debug/DebuggerSession.java @@ -678,7 +678,9 @@ public ExecutionEventNode create(EventContext context) { } } }, hasExpressionElement, syntaxTags); - allBindings.add(syntaxElementsBinding); + synchronized (allBindings) { + allBindings.add(syntaxElementsBinding); + } } } } @@ -706,7 +708,9 @@ public boolean test(Source source) { private void removeBindings() { assert Thread.holdsLock(this); if (syntaxElementsBinding != null) { - allBindings.remove(syntaxElementsBinding); + synchronized (allBindings) { + allBindings.remove(syntaxElementsBinding); + } syntaxElementsBinding.dispose(); syntaxElementsBinding = null; if (Debugger.TRACE) { @@ -1393,10 +1397,12 @@ private List collectDebuggerNodes(DebuggerNode source, SuspendAnch private List collectDebuggerNodes(Node iNode, SuspendAnchor suspendAnchor) { List nodes = new ArrayList<>(); - for (EventBinding binding : allBindings) { - DebuggerNode node = (DebuggerNode) debugger.getInstrumenter().lookupExecutionEventNode(iNode, binding); - if (node != null && node.isActiveAt(suspendAnchor)) { - nodes.add(node); + synchronized (allBindings) { + for (EventBinding binding : allBindings) { + DebuggerNode node = (DebuggerNode) debugger.getInstrumenter().lookupExecutionEventNode(iNode, binding); + if (node != null && node.isActiveAt(suspendAnchor)) { + nodes.add(node); + } } } return nodes; From 21ddf191b16f609f493dc1b84dd1907add5f0e29 Mon Sep 17 00:00:00 2001 From: Josef Haider Date: Tue, 5 Dec 2023 12:13:02 +0100 Subject: [PATCH 101/593] Remove usages of fcmpZero in AArch64 intrinsics. --- .../asm/aarch64/AArch64ASIMDAssembler.java | 59 ++++++- .../lir/aarch64/AArch64ArrayCompareToOp.java | 12 +- .../lir/aarch64/AArch64ArrayEqualsOp.java | 30 ++-- .../lir/aarch64/AArch64ArrayIndexOfOp.java | 15 +- .../AArch64ArrayRegionCompareToOp.java | 22 +-- .../AArch64CalcStringAttributesOp.java | 165 ++++++++---------- .../lir/aarch64/AArch64ComplexVectorOp.java | 44 +++-- .../lir/aarch64/AArch64CountPositivesOp.java | 3 +- .../lir/aarch64/AArch64EncodeArrayOp.java | 19 +- .../aarch64/AArch64StringUTF16CompressOp.java | 11 +- .../aarch64/AArch64VectorizedMismatchOp.java | 19 +- 11 files changed, 228 insertions(+), 171 deletions(-) diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/asm/aarch64/AArch64ASIMDAssembler.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/asm/aarch64/AArch64ASIMDAssembler.java index 0aeff1e8d2fc..a806c7c4fc80 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/asm/aarch64/AArch64ASIMDAssembler.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/asm/aarch64/AArch64ASIMDAssembler.java @@ -24,15 +24,15 @@ */ package jdk.graal.compiler.asm.aarch64; -import static jdk.vm.ci.aarch64.AArch64.CPU; -import static jdk.vm.ci.aarch64.AArch64.SIMD; -import static jdk.vm.ci.aarch64.AArch64.zr; import static jdk.graal.compiler.asm.aarch64.AArch64Assembler.LoadFlag; import static jdk.graal.compiler.asm.aarch64.AArch64Assembler.rd; import static jdk.graal.compiler.asm.aarch64.AArch64Assembler.rn; import static jdk.graal.compiler.asm.aarch64.AArch64Assembler.rs1; import static jdk.graal.compiler.asm.aarch64.AArch64Assembler.rs2; import static jdk.graal.compiler.asm.aarch64.AArch64Assembler.rs3; +import static jdk.vm.ci.aarch64.AArch64.CPU; +import static jdk.vm.ci.aarch64.AArch64.SIMD; +import static jdk.vm.ci.aarch64.AArch64.zr; import java.util.Arrays; import java.util.HashMap; @@ -41,7 +41,6 @@ import jdk.graal.compiler.core.common.NumUtil; import jdk.graal.compiler.core.common.Stride; import jdk.graal.compiler.debug.GraalError; - import jdk.vm.ci.aarch64.AArch64; import jdk.vm.ci.aarch64.AArch64Kind; import jdk.vm.ci.code.Register; @@ -704,7 +703,9 @@ public enum ASIMDInstruction { CMHS(UBit | 0b00111 << 11), USHL(UBit | 0b01000 << 11), UMAX(UBit | 0b01100 << 11), + UMAXP(UBit | 0b10100 << 11), UMIN(UBit | 0b01101 << 11), + UMINP(UBit | 0b10101 << 11), SUB(UBit | 0b10000 << 11), CMEQ(UBit | 0b10001 << 11), MLS(UBit | 0b10010 << 11), @@ -3576,6 +3577,31 @@ public void umaxvSV(ASIMDSize size, ElementSize elementSize, Register dst, Regis acrossLanesEncoding(ASIMDInstruction.UMAXV, size, elemSizeXX(elementSize), dst, src); } + /** + * C7.2.344 Unsigned maximum pairwise.
+ * + * + * concat = src2:src1 + * for i in 0..n-1 do dst[i] = uint_max(concat[2 * i], concat[2 * i + 1]) + * + * + * @param size register size. + * @param eSize element size. + * @param dst SIMD register. + * @param src1 SIMD register. + * @param src2 SIMD register. + */ + public void umaxpVVV(ASIMDSize size, ElementSize eSize, Register dst, Register src1, Register src2) { + assert usesMultipleLanes(size, eSize) : "Must use multiple lanes " + size + " " + eSize; + + assert dst.getRegisterCategory().equals(SIMD) : dst; + assert src1.getRegisterCategory().equals(SIMD) : src1; + assert src2.getRegisterCategory().equals(SIMD) : src2; + assert eSize != ElementSize.DoubleWord : "Invalid lane width for umaxp"; + + threeSameEncoding(ASIMDInstruction.UMAXP, size, elemSizeXX(eSize), dst, src1, src2); + } + /** * C7.2.363 Unsigned minimum.
* @@ -3598,6 +3624,31 @@ public void uminVVV(ASIMDSize size, ElementSize eSize, Register dst, Register sr threeSameEncoding(ASIMDInstruction.UMIN, size, elemSizeXX(eSize), dst, src1, src2); } + /** + * C7.2.347 Unsigned minimum pairwise.
+ * + * + * concat = src2:src1 + * for i in 0..n-1 do dst[i] = uint_min(concat[2 * i], concat[2 * i + 1]) + * + * + * @param size register size. + * @param eSize element size. + * @param dst SIMD register. + * @param src1 SIMD register. + * @param src2 SIMD register. + */ + public void uminpVVV(ASIMDSize size, ElementSize eSize, Register dst, Register src1, Register src2) { + assert usesMultipleLanes(size, eSize) : "Must use multiple lanes " + size + " " + eSize; + + assert dst.getRegisterCategory().equals(SIMD) : dst; + assert src1.getRegisterCategory().equals(SIMD) : src1; + assert src2.getRegisterCategory().equals(SIMD) : src2; + assert eSize != ElementSize.DoubleWord : "Invalid lane width for uminp"; + + threeSameEncoding(ASIMDInstruction.UMINP, size, elemSizeXX(eSize), dst, src1, src2); + } + /** * C7.2.365 Unsigned minimum across vector.
* diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/aarch64/AArch64ArrayCompareToOp.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/aarch64/AArch64ArrayCompareToOp.java index 5f309a9a3917..6bfc24dce510 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/aarch64/AArch64ArrayCompareToOp.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/aarch64/AArch64ArrayCompareToOp.java @@ -24,8 +24,8 @@ */ package jdk.graal.compiler.lir.aarch64; -import static jdk.vm.ci.code.ValueUtil.asRegister; import static jdk.graal.compiler.lir.LIRInstruction.OperandFlag.REG; +import static jdk.vm.ci.code.ValueUtil.asRegister; import jdk.graal.compiler.asm.Label; import jdk.graal.compiler.asm.aarch64.AArch64ASIMDAssembler; @@ -35,11 +35,10 @@ import jdk.graal.compiler.asm.aarch64.AArch64MacroAssembler; import jdk.graal.compiler.core.common.Stride; import jdk.graal.compiler.debug.GraalError; -import jdk.graal.compiler.lir.asm.CompilationResultBuilder; import jdk.graal.compiler.lir.LIRInstructionClass; import jdk.graal.compiler.lir.Opcode; +import jdk.graal.compiler.lir.asm.CompilationResultBuilder; import jdk.graal.compiler.lir.gen.LIRGeneratorTool; - import jdk.vm.ci.aarch64.AArch64Kind; import jdk.vm.ci.code.Register; import jdk.vm.ci.meta.AllocatableValue; @@ -333,8 +332,11 @@ private void emitSIMDCode(AArch64MacroAssembler masm, Label stringsEqualUptoLeng masm.neon.cmeqVVV(AArch64ASIMDAssembler.ASIMDSize.FullReg, eSize, array1HighV, array1HighV, array2HighV); masm.neon.andVVV(AArch64ASIMDAssembler.ASIMDSize.FullReg, tmpRegV1, array1LowV, array1HighV); masm.neon.uminvSV(AArch64ASIMDAssembler.ASIMDSize.FullReg, eSize, tmpRegV1, tmpRegV1); - masm.fcmpZero(64, tmpRegV1); - masm.branchConditionally(ConditionFlag.EQ, mismatchInChunk); + try (AArch64MacroAssembler.ScratchRegister scratchReg = masm.getScratchRegister()) { + Register tmp = scratchReg.getRegister(); + masm.neon.umovGX(AArch64ASIMDAssembler.ElementSize.DoubleWord, tmp, tmpRegV1, 0); + masm.cbz(64, tmp, mismatchInChunk); + } masm.cmp(64, array1, lastChunkAddress1); masm.branchConditionally(ConditionFlag.LO, simdLoop); diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/aarch64/AArch64ArrayEqualsOp.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/aarch64/AArch64ArrayEqualsOp.java index 5ef75444988f..d1216d9bb921 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/aarch64/AArch64ArrayEqualsOp.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/aarch64/AArch64ArrayEqualsOp.java @@ -24,8 +24,6 @@ */ package jdk.graal.compiler.lir.aarch64; -import static jdk.vm.ci.code.ValueUtil.asRegister; -import static jdk.vm.ci.code.ValueUtil.isIllegal; import static jdk.graal.compiler.asm.aarch64.AArch64ASIMDAssembler.ASIMDInstruction.LD2_MULTIPLE_2R; import static jdk.graal.compiler.asm.aarch64.AArch64ASIMDAssembler.ASIMDInstruction.LD4_MULTIPLE_4R; import static jdk.graal.compiler.asm.aarch64.AArch64ASIMDAssembler.ASIMDSize.FullReg; @@ -39,6 +37,8 @@ import static jdk.graal.compiler.asm.aarch64.AArch64MacroAssembler.PREFERRED_LOOP_ALIGNMENT; import static jdk.graal.compiler.lir.LIRInstruction.OperandFlag.ILLEGAL; import static jdk.graal.compiler.lir.LIRInstruction.OperandFlag.REG; +import static jdk.vm.ci.code.ValueUtil.asRegister; +import static jdk.vm.ci.code.ValueUtil.isIllegal; import java.util.Arrays; @@ -53,11 +53,10 @@ import jdk.graal.compiler.core.common.StrideUtil; import jdk.graal.compiler.debug.Assertions; import jdk.graal.compiler.debug.GraalError; -import jdk.graal.compiler.lir.asm.CompilationResultBuilder; import jdk.graal.compiler.lir.LIRInstructionClass; import jdk.graal.compiler.lir.Opcode; +import jdk.graal.compiler.lir.asm.CompilationResultBuilder; import jdk.graal.compiler.lir.gen.LIRGeneratorTool; - import jdk.vm.ci.aarch64.AArch64Kind; import jdk.vm.ci.code.Register; import jdk.vm.ci.meta.Value; @@ -232,7 +231,7 @@ private void emitArrayEquals(AArch64MacroAssembler asm, Register refAddress = len; asm.add(64, refAddress, arrayMax, len, ShiftType.LSL, strideMax.log2); - simdCompare64(asm, strideMax, strideMin, strideA, strideM, arrayMax, arrayMin, arrayM); + simdCompare64(asm, strideMax, strideMin, strideA, strideM, arrayMax, arrayMin, arrayM, tmp); asm.branchConditionally(ConditionFlag.NE, end); asm.cmp(64, refAddress, arrayMax); @@ -249,7 +248,7 @@ private void emitArrayEquals(AArch64MacroAssembler asm, // 64 byte loop asm.align(PREFERRED_LOOP_ALIGNMENT); asm.bind(vectorLoop); - simdCompare64(asm, strideMax, strideMin, strideA, strideM, arrayMax, arrayMin, arrayM); + simdCompare64(asm, strideMax, strideMin, strideA, strideM, arrayMax, arrayMin, arrayM, tmp); asm.branchConditionally(ConditionFlag.NE, end); asm.cmp(64, arrayMax, refAddress); asm.branchConditionally(ConditionFlag.LO, vectorLoop); @@ -263,13 +262,13 @@ private void emitArrayEquals(AArch64MacroAssembler asm, asm.sub(64, arrayM, arrayM, tmp, ShiftType.LSR, strideMax.log2 - strideM.log2); } - simdCompare64(asm, strideMax, strideMin, strideA, strideM, arrayMax, arrayMin, arrayM); + simdCompare64(asm, strideMax, strideMin, strideA, strideM, arrayMax, arrayMin, arrayM, tmp); asm.jmp(end); // tail for 32 - 63 bytes - tail32(asm, strideMax, strideMin, strideA, strideM, arrayMax, arrayMin, arrayM, len, tailLessThan64, tailLessThan32, end); + tail32(asm, strideMax, strideMin, strideA, strideM, arrayMax, arrayMin, arrayM, len, tmp, tailLessThan64, tailLessThan32, end); // tail for 16 - 31 bytes - tail16(asm, strideA, strideB, strideM, strideMax, strideMin, arrayA, arrayB, arrayM, len, tailLessThan32, tailLessThan16, end); + tail16(asm, strideA, strideB, strideM, strideMax, strideMin, arrayA, arrayB, arrayM, len, tmp, tailLessThan32, tailLessThan16, end); // tail for 8 - 15 bytes tailLessThan16(asm, strideA, strideB, strideM, strideMax, arrayA, arrayB, arrayM, len, tmp, ret, tailLessThan16, tailLessThan8, end, 8); // tail for 4 - 7 bytes @@ -291,7 +290,8 @@ private void simdCompare64(AArch64MacroAssembler asm, Stride strideMask, Register arrayMax, Register arrayMin, - Register arrayMask) { + Register arrayMask, + Register tmp) { ElementSize minESize = fromStride(strideMin); switch (strideMax.log2 - strideMin.log2) { case 0: @@ -420,7 +420,7 @@ private void simdCompare64(AArch64MacroAssembler asm, default: throw GraalError.unimplemented("comparison of " + strideMin + " to " + strideMax + " not implemented"); // ExcludeFromJacocoGeneratedReport } - vectorCheckZero(asm, v(0), v(0)); + cmpZeroVector(asm, v(0), v(0), tmp); } private void tail32(AArch64MacroAssembler asm, @@ -432,6 +432,7 @@ private void tail32(AArch64MacroAssembler asm, Register arrayMin, Register arrayMask, Register len, + Register tmp, Label entry, Label nextTail, Label end) { @@ -595,7 +596,7 @@ private void tail32(AArch64MacroAssembler asm, default: throw GraalError.unimplemented("comparison of " + strideMin + " to " + strideMax + " not implemented"); // ExcludeFromJacocoGeneratedReport } - vectorCheckZero(asm, v(0), v(0)); + cmpZeroVector(asm, v(0), v(0), tmp); asm.jmp(end); } @@ -609,6 +610,7 @@ private void tail16(AArch64MacroAssembler asm, Register arrayB, Register arrayM, Register len, + Register tmp, Label entry, Label nextTail, Label end) { @@ -663,7 +665,7 @@ private void tail16(AArch64MacroAssembler asm, asm.neon.eorVVV(FullReg, vecArrayA2, vecArrayA2, vecArrayB2); asm.neon.orrVVV(FullReg, vecArrayA1, vecArrayA1, vecArrayA2); - vectorCheckZero(asm, vecArrayA1, vecArrayA1); + cmpZeroVector(asm, vecArrayA1, vecArrayA1, tmp); asm.jmp(end); } @@ -753,7 +755,7 @@ private void tailLessThan16(AArch64MacroAssembler asm, asm.neon.orrVVV(FullReg, vecArrayA1, vecArrayA1, vecArrayM1); } asm.neon.eorVVV(FullReg, vecArrayA1, vecArrayA1, vecArrayB1); - vectorCheckZero(asm, vecArrayA1, vecArrayA1); + cmpZeroVector(asm, vecArrayA1, vecArrayA1, tmp); } else if (strideMax.value == nBytes) { asm.bind(entry); // tail for length == 1 diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/aarch64/AArch64ArrayIndexOfOp.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/aarch64/AArch64ArrayIndexOfOp.java index 43d7ce4cfa8a..50ec7147f7ed 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/aarch64/AArch64ArrayIndexOfOp.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/aarch64/AArch64ArrayIndexOfOp.java @@ -25,14 +25,14 @@ */ package jdk.graal.compiler.lir.aarch64; -import static jdk.vm.ci.aarch64.AArch64.zr; -import static jdk.vm.ci.code.ValueUtil.asRegister; import static jdk.graal.compiler.asm.aarch64.AArch64ASIMDAssembler.ASIMDInstruction.LD2_MULTIPLE_2R; import static jdk.graal.compiler.asm.aarch64.AArch64ASIMDAssembler.ASIMDInstruction.LD4_MULTIPLE_4R; import static jdk.graal.compiler.asm.aarch64.AArch64ASIMDAssembler.ASIMDSize.FullReg; import static jdk.graal.compiler.asm.aarch64.AArch64Address.createStructureImmediatePostIndexAddress; import static jdk.graal.compiler.asm.aarch64.AArch64Assembler.ConditionFlag; import static jdk.graal.compiler.lir.LIRInstruction.OperandFlag.REG; +import static jdk.vm.ci.aarch64.AArch64.zr; +import static jdk.vm.ci.code.ValueUtil.asRegister; import java.util.Arrays; @@ -46,12 +46,11 @@ import jdk.graal.compiler.asm.aarch64.AArch64MacroAssembler.ScratchRegister; import jdk.graal.compiler.core.common.Stride; import jdk.graal.compiler.debug.GraalError; -import jdk.graal.compiler.lir.asm.CompilationResultBuilder; import jdk.graal.compiler.lir.LIRInstructionClass; import jdk.graal.compiler.lir.Opcode; +import jdk.graal.compiler.lir.asm.CompilationResultBuilder; import jdk.graal.compiler.lir.gen.LIRGeneratorTool; import jdk.graal.compiler.lir.gen.LIRGeneratorTool.ArrayIndexOfVariant; - import jdk.vm.ci.aarch64.AArch64Kind; import jdk.vm.ci.code.Register; import jdk.vm.ci.meta.AllocatableValue; @@ -631,9 +630,11 @@ private void emitSIMDMatch(AArch64MacroAssembler masm, break; } masm.neon.orrVVV(FullReg, vecTmp[0], vecArray1, vecArray2); - /* If value != 0, then there was a match somewhere. */ - vectorCheckZero(masm, ElementSize.fromStride(getMatchResultStride()), vecTmp[0], vecTmp[0], variant != ArrayIndexOfVariant.Table); - masm.branchConditionally(ConditionFlag.NE, matchInChunk); + try (ScratchRegister sc = masm.getScratchRegister()) { + Register tmp = sc.getRegister(); + /* If value != 0, then there was a match somewhere. */ + cbnzVector(masm, ElementSize.fromStride(getMatchResultStride()), vecTmp[0], vecTmp[0], tmp, variant != ArrayIndexOfVariant.Table, matchInChunk); + } } private Stride getMatchResultStride() { diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/aarch64/AArch64ArrayRegionCompareToOp.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/aarch64/AArch64ArrayRegionCompareToOp.java index ea29e1d0720b..7f2e083cc67c 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/aarch64/AArch64ArrayRegionCompareToOp.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/aarch64/AArch64ArrayRegionCompareToOp.java @@ -24,17 +24,17 @@ */ package jdk.graal.compiler.lir.aarch64; -import static jdk.vm.ci.aarch64.AArch64.CPU; -import static jdk.vm.ci.aarch64.AArch64.SIMD; -import static jdk.vm.ci.aarch64.AArch64.zr; -import static jdk.vm.ci.code.ValueUtil.asRegister; -import static jdk.vm.ci.code.ValueUtil.isIllegal; import static jdk.graal.compiler.asm.aarch64.AArch64ASIMDAssembler.ASIMDSize.FullReg; import static jdk.graal.compiler.asm.aarch64.AArch64ASIMDAssembler.ElementSize.fromStride; import static jdk.graal.compiler.asm.aarch64.AArch64MacroAssembler.PREFERRED_BRANCH_TARGET_ALIGNMENT; import static jdk.graal.compiler.asm.aarch64.AArch64MacroAssembler.PREFERRED_LOOP_ALIGNMENT; import static jdk.graal.compiler.lir.LIRInstruction.OperandFlag.ILLEGAL; import static jdk.graal.compiler.lir.LIRInstruction.OperandFlag.REG; +import static jdk.vm.ci.aarch64.AArch64.CPU; +import static jdk.vm.ci.aarch64.AArch64.SIMD; +import static jdk.vm.ci.aarch64.AArch64.zr; +import static jdk.vm.ci.code.ValueUtil.asRegister; +import static jdk.vm.ci.code.ValueUtil.isIllegal; import java.util.Arrays; @@ -49,11 +49,10 @@ import jdk.graal.compiler.core.common.Stride; import jdk.graal.compiler.core.common.StrideUtil; import jdk.graal.compiler.debug.GraalError; -import jdk.graal.compiler.lir.asm.CompilationResultBuilder; import jdk.graal.compiler.lir.LIRInstructionClass; import jdk.graal.compiler.lir.Opcode; +import jdk.graal.compiler.lir.asm.CompilationResultBuilder; import jdk.graal.compiler.lir.gen.LIRGeneratorTool; - import jdk.vm.ci.aarch64.AArch64Kind; import jdk.vm.ci.code.Register; import jdk.vm.ci.meta.AllocatableValue; @@ -202,8 +201,7 @@ private void emitArrayCompare(CompilationResultBuilder crb, AArch64MacroAssemble asm.neon.eorVVV(FullReg, vecTmp1, vecArrayA1, vecArrayB1); asm.neon.eorVVV(FullReg, vecTmp2, vecArrayA2, vecArrayB2); asm.neon.orrVVV(FullReg, vecTmp2, vecTmp2, vecTmp1); - vectorCheckZero(asm, vecTmp2, vecTmp2); - asm.branchConditionally(ConditionFlag.NE, diffFound); + cbnzVector(asm, ElementSize.Byte, vecTmp2, vecTmp2, tmp, false, diffFound); // if so, continue asm.cmp(64, maxStrideArray, refAddress); asm.branchConditionally(ConditionFlag.LO, vectorLoop); @@ -218,8 +216,7 @@ private void emitArrayCompare(CompilationResultBuilder crb, AArch64MacroAssemble asm.neon.eorVVV(FullReg, vecTmp1, vecArrayA1, vecArrayB1); asm.neon.eorVVV(FullReg, vecTmp2, vecArrayA2, vecArrayB2); asm.neon.orrVVV(FullReg, vecTmp2, vecTmp2, vecTmp1); - vectorCheckZero(asm, vecTmp2, vecTmp2); - asm.branchConditionally(ConditionFlag.NE, diffFound); + cbnzVector(asm, ElementSize.Byte, vecTmp2, vecTmp2, tmp, false, diffFound); asm.mov(64, ret, zr); asm.jmp(end); @@ -239,8 +236,7 @@ private void emitArrayCompare(CompilationResultBuilder crb, AArch64MacroAssemble asm.align(PREFERRED_BRANCH_TARGET_ALIGNMENT); asm.bind(diffFound); // check if vecArrayA1 and vecArrayB1 are equal - vectorCheckZero(asm, vecTmp1, vecTmp1); - asm.branchConditionally(ConditionFlag.NE, returnV1); + cbnzVector(asm, ElementSize.Byte, vecTmp1, vecTmp1, tmp, false, returnV1); calcReturnValue(asm, ret, vecArrayA2, vecArrayB2, vecArrayA1, vecArrayB1, vecMask, strideMax); asm.jmp(end); diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/aarch64/AArch64CalcStringAttributesOp.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/aarch64/AArch64CalcStringAttributesOp.java index 704e89ef7dee..428c59cc4aa2 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/aarch64/AArch64CalcStringAttributesOp.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/aarch64/AArch64CalcStringAttributesOp.java @@ -24,8 +24,6 @@ */ package jdk.graal.compiler.lir.aarch64; -import static jdk.vm.ci.aarch64.AArch64.zr; -import static jdk.vm.ci.code.ValueUtil.asRegister; import static jdk.graal.compiler.asm.aarch64.AArch64ASIMDAssembler.ASIMDInstruction.LD1_MULTIPLE_4R; import static jdk.graal.compiler.asm.aarch64.AArch64ASIMDAssembler.ASIMDSize.FullReg; import static jdk.graal.compiler.asm.aarch64.AArch64ASIMDAssembler.ElementSize.DoubleWord; @@ -48,6 +46,8 @@ import static jdk.graal.compiler.lir.gen.LIRGeneratorTool.CalcStringAttributesEncoding.UTF_16; import static jdk.graal.compiler.lir.gen.LIRGeneratorTool.CalcStringAttributesEncoding.UTF_32; import static jdk.graal.compiler.lir.gen.LIRGeneratorTool.CalcStringAttributesEncoding.UTF_8; +import static jdk.vm.ci.aarch64.AArch64.zr; +import static jdk.vm.ci.code.ValueUtil.asRegister; import java.util.Arrays; @@ -63,12 +63,11 @@ import jdk.graal.compiler.core.common.Stride; import jdk.graal.compiler.debug.Assertions; import jdk.graal.compiler.debug.GraalError; -import jdk.graal.compiler.lir.asm.CompilationResultBuilder; import jdk.graal.compiler.lir.LIRInstructionClass; import jdk.graal.compiler.lir.Opcode; +import jdk.graal.compiler.lir.asm.CompilationResultBuilder; import jdk.graal.compiler.lir.gen.LIRGeneratorTool; import jdk.graal.compiler.lir.gen.LIRGeneratorTool.CalcStringAttributesEncoding; - import jdk.vm.ci.aarch64.AArch64Kind; import jdk.vm.ci.code.Register; import jdk.vm.ci.meta.Value; @@ -134,13 +133,14 @@ private static int getNumberOfTempRegisters(CalcStringAttributesEncoding encodin switch (encoding) { case LATIN1: case BMP: + case UTF_32: return 1; case UTF_16: return 2; case UTF_8: return assumeValid ? 2 : 5; default: - return 0; + throw GraalError.shouldNotReachHereUnexpectedValue(encoding); // ExcludeFromJacocoGeneratedReport } } @@ -166,6 +166,7 @@ public void emitCode(CompilationResultBuilder crb, AArch64MacroAssembler asm) { try (AArch64MacroAssembler.ScratchRegister sc1 = asm.getScratchRegister(); AArch64MacroAssembler.ScratchRegister sc2 = asm.getScratchRegister()) { Register arr = sc1.getRegister(); Register len = sc2.getRegister(); + Register tmp = asRegister(temp[0]); Register ret = asRegister(result); Label end = new Label(); @@ -175,19 +176,19 @@ public void emitCode(CompilationResultBuilder crb, AArch64MacroAssembler asm) { switch (encoding) { case LATIN1: - emitLatin1(asm, arr, len, asRegister(temp[0]), ret, end, asRegister(vectorTemp[0]), asRegister(vectorTemp[1]), asRegister(vectorTemp[2])); + emitLatin1(asm, arr, len, tmp, ret, end, asRegister(vectorTemp[0]), asRegister(vectorTemp[1]), asRegister(vectorTemp[2])); break; case BMP: - emitBMP(asm, arr, len, asRegister(temp[0]), ret, end); + emitBMP(asm, arr, len, tmp, ret, end); break; case UTF_8: - emitUTF8(crb, asm, arr, len, asRegister(temp[0]), ret, end); + emitUTF8(crb, asm, arr, len, tmp, ret, end); break; case UTF_16: - emitUTF16(crb, asm, arr, len, asRegister(temp[0]), ret, end); + emitUTF16(crb, asm, arr, len, tmp, ret, end); break; case UTF_32: - emitUTF32(asm, arr, len, ret, end); + emitUTF32(asm, arr, len, tmp, ret, end); break; default: throw GraalError.shouldNotReachHereUnexpectedValue(encoding); // ExcludeFromJacocoGeneratedReport @@ -225,15 +226,18 @@ static void emitLatin1(AArch64MacroAssembler asm, Register arr, Register len, Re asm.bind(vectorLoop); // load 2 vectors from the string asm.fldp(128, vecArray1, vecArray2, createImmediateAddress(128, AddressingMode.IMMEDIATE_PAIR_POST_INDEXED, arr, 32)); - vectorTest(asm, vecArray1, vecArray2, vecMask); - asm.branchConditionally(ConditionFlag.NE, end); + asm.neon.orrVVV(FullReg, vecArray1, vecArray1, vecArray2); + asm.neon.andVVV(FullReg, vecArray1, vecArray1, vecMask); + cbnzVector(asm, ElementSize.Byte, vecArray1, vecArray1, tmp, false, end); asm.cmp(64, arr, refAddress); asm.branchConditionally(ConditionFlag.LO, vectorLoop); // 32 byte loop tail asm.mov(64, arr, refAddress); asm.fldp(128, vecArray1, vecArray2, createPairBaseRegisterOnlyAddress(128, arr)); - vectorTest(asm, vecArray1, vecArray2, vecMask); + asm.neon.orrVVV(FullReg, vecArray1, vecArray1, vecArray2); + asm.neon.andVVV(FullReg, vecArray1, vecArray1, vecMask); + cmpZeroVector(asm, vecArray1, vecArray1, tmp); // use the fact that CR_7BIT is 0 and CR_8BIT is 1 for setting the return value via cset asm.cset(64, ret, ConditionFlag.NE); asm.jmp(end); @@ -248,7 +252,9 @@ static void emitLatin1(AArch64MacroAssembler asm, Register arr, Register len, Re asm.fldr(128, vecArray1, AArch64Address.createBaseRegisterOnlyAddress(128, arr)); // load arr[arrayLength-16:arrayLength] asm.fldr(128, vecArray2, AArch64Address.createRegisterOffsetAddress(128, arr, len, false)); - vectorTest(asm, vecArray1, vecArray2, vecMask); + asm.neon.orrVVV(FullReg, vecArray1, vecArray1, vecArray2); + asm.neon.andVVV(FullReg, vecArray1, vecArray1, vecMask); + cmpZeroVector(asm, vecArray1, vecArray1, tmp); assert returnValueAssertions(); // use the fact that CR_7BIT is 0 and CR_8BIT is 1 for setting the return value via cset asm.cset(64, ret, ConditionFlag.NE); @@ -334,19 +340,22 @@ private void emitBMP(AArch64MacroAssembler asm, Register arr, Register len, Regi asm.align(PREFERRED_LOOP_ALIGNMENT); asm.bind(asciiLoop); asm.fldp(128, vecArray1, vecArray2, createImmediateAddress(128, AddressingMode.IMMEDIATE_PAIR_POST_INDEXED, arr, 32)); - vectorTest(asm, HalfWord, vecTmp1, vecTmp1, vecArray1, vecArray2, vecMask); - asm.branchConditionally(ConditionFlag.NE, latinFound); + asm.neon.orrVVV(FullReg, vecTmp1, vecArray1, vecArray2); + asm.neon.cmtstVVV(FullReg, HalfWord, vecTmp1, vecTmp1, vecMask); + cbnzVector(asm, HalfWord, vecTmp1, vecTmp1, tmp, true, latinFound); asm.cmp(64, arr, refAddress); asm.branchConditionally(ConditionFlag.LO, asciiLoop); // 32 byte ascii loop tail asm.mov(64, arr, refAddress); asm.fldp(128, vecArray1, vecArray2, createImmediateAddress(128, AddressingMode.IMMEDIATE_PAIR_POST_INDEXED, arr, 32)); - vectorTest(asm, HalfWord, vecTmp1, vecTmp1, vecArray1, vecArray2, vecMask); + asm.neon.orrVVV(FullReg, vecTmp1, vecArray1, vecArray2); + asm.neon.cmtstVVV(FullReg, HalfWord, vecTmp1, vecTmp1, vecMask); + cmpZeroVector(asm, HalfWord, vecTmp1, vecTmp1, tmp, true); assert returnValueAssertions(); asm.cset(64, ret, ConditionFlag.NE); asm.neon.uzp2VVV(FullReg, ElementSize.Byte, vecTmp1, vecArray1, vecArray2); - vectorCheckZero(asm, vecTmp1, vecTmp1); + cmpZeroVector(asm, vecTmp1, vecTmp1, tmp); asm.csinc(64, ret, ret, ret, ConditionFlag.EQ); asm.jmp(end); @@ -363,8 +372,7 @@ private void emitBMP(AArch64MacroAssembler asm, Register arr, Register len, Regi asm.neon.uzp2VVV(FullReg, ElementSize.Byte, vecTmp1, vecArray1, vecArray2); // Check if characters are latin1 by extracting the upper bytes and checking if the // resulting vector is zero. - vectorCheckZero(asm, vecTmp1, vecTmp1); - asm.branchConditionally(ConditionFlag.NE, end); + cbnzVector(asm, ElementSize.Byte, vecTmp1, vecTmp1, tmp, false, end); asm.cmp(64, arr, refAddress); asm.branchConditionally(ConditionFlag.LO, latinLoop); @@ -373,7 +381,7 @@ private void emitBMP(AArch64MacroAssembler asm, Register arr, Register len, Regi asm.fldp(128, vecArray1, vecArray2, createImmediateAddress(128, AddressingMode.IMMEDIATE_PAIR_POST_INDEXED, arr, 32)); asm.mov(ret, CR_8BIT); asm.neon.uzp2VVV(FullReg, ElementSize.Byte, vecTmp1, vecArray1, vecArray2); - vectorCheckZero(asm, vecTmp1, vecTmp1); + cmpZeroVector(asm, vecTmp1, vecTmp1, tmp); asm.csinc(64, ret, ret, ret, ConditionFlag.EQ); asm.jmp(end); @@ -385,10 +393,12 @@ private void emitBMP(AArch64MacroAssembler asm, Register arr, Register len, Regi asm.branchConditionally(ConditionFlag.MI, tailLessThan16); asm.fldr(128, vecArray1, AArch64Address.createBaseRegisterOnlyAddress(128, arr)); asm.fldr(128, vecArray2, AArch64Address.createRegisterOffsetAddress(128, arr, len, false)); - vectorTest(asm, HalfWord, vecTmp1, vecTmp1, vecArray1, vecArray2, vecMask); + asm.neon.orrVVV(FullReg, vecTmp1, vecArray1, vecArray2); + asm.neon.cmtstVVV(FullReg, HalfWord, vecTmp1, vecTmp1, vecMask); + cmpZeroVector(asm, HalfWord, vecTmp1, vecTmp1, tmp, true); asm.cset(64, ret, ConditionFlag.NE); asm.neon.uzp2VVV(FullReg, ElementSize.Byte, vecTmp1, vecArray1, vecArray2); - vectorCheckZero(asm, vecTmp1, vecTmp1); + cmpZeroVector(asm, vecTmp1, vecTmp1, tmp); asm.csinc(64, ret, ret, ret, ConditionFlag.EQ); asm.jmp(end); @@ -417,22 +427,6 @@ private void emitBMP(AArch64MacroAssembler asm, Register arr, Register len, Regi asm.csinc(64, ret, ret, ret, ConditionFlag.EQ); } - private static void vectorTest(AArch64MacroAssembler asm, Register vecArray1, Register vecArray2, Register vecMask) { - vectorTest(asm, vecArray1, vecArray1, vecArray1, vecArray2, vecMask); - } - - private static void vectorTest(AArch64MacroAssembler asm, Register vecDstOrr, Register vecDstAnd, Register vecArray1, Register vecArray2, Register vecMask) { - asm.neon.orrVVV(FullReg, vecDstOrr, vecArray1, vecArray2); - asm.neon.andVVV(FullReg, vecDstAnd, vecDstOrr, vecMask); - vectorCheckZero(asm, vecDstAnd, vecDstAnd); - } - - private static void vectorTest(AArch64MacroAssembler asm, ElementSize eSize, Register vecDstOrr, Register vecDstCmtst, Register vecArray1, Register vecArray2, Register vecMask) { - asm.neon.orrVVV(FullReg, vecDstOrr, vecArray1, vecArray2); - asm.neon.cmtstVVV(FullReg, eSize, vecDstCmtst, vecDstOrr, vecMask); - vectorCheckZero(asm, eSize, vecDstCmtst, vecDstCmtst, true); - } - private static final byte TOO_SHORT = 1 << 0; private static final byte TOO_LONG = 1 << 1; private static final byte OVERLONG_3 = 1 << 2; @@ -589,8 +583,9 @@ private void emitUTF8(CompilationResultBuilder crb, AArch64MacroAssembler asm, R asm.align(PREFERRED_LOOP_ALIGNMENT); asm.bind(asciiLoop); asm.fldp(128, vecArray1, vecArray2, createImmediateAddress(128, AddressingMode.IMMEDIATE_PAIR_POST_INDEXED, arr, 32)); - vectorTest(asm, vecTmp1, vecTmp2, vecArray1, vecArray2, vecMask0x80); - asm.branchConditionally(ConditionFlag.NE, multibyteFound); + asm.neon.orrVVV(FullReg, vecTmp1, vecArray1, vecArray2); + asm.neon.andVVV(FullReg, vecTmp2, vecTmp1, vecMask0x80); + cbnzVector(asm, ElementSize.Byte, vecTmp2, vecTmp2, tmp, false, multibyteFound); asm.cmp(64, arr, refAddress); asm.branchConditionally(ConditionFlag.LO, asciiLoop); @@ -598,8 +593,9 @@ private void emitUTF8(CompilationResultBuilder crb, AArch64MacroAssembler asm, R asm.mov(64, arr, refAddress); asm.fldp(128, vecArray1, vecArray2, createImmediateAddress(128, AddressingMode.IMMEDIATE_PAIR_POST_INDEXED, arr, 32)); asm.bind(tailLessThan32Continue); - vectorTest(asm, vecTmp1, vecTmp2, vecArray1, vecArray2, vecMask0x80); - asm.branchConditionally(ConditionFlag.NE, assumeValid ? multibyteFoundTail : multibyteFound); + asm.neon.orrVVV(FullReg, vecTmp1, vecArray1, vecArray2); + asm.neon.andVVV(FullReg, vecTmp2, vecTmp1, vecMask0x80); + cbnzVector(asm, ElementSize.Byte, vecTmp2, vecTmp2, tmp, false, assumeValid ? multibyteFoundTail : multibyteFound); assert returnValueAssertions(); asm.lsl(64, ret, ret, 32); asm.jmp(end); @@ -744,8 +740,7 @@ private void emitUTF8(CompilationResultBuilder crb, AArch64MacroAssembler asm, R // fast path: check if current vector is ascii asm.bind(multibyteContinue); asm.neon.andVVV(FullReg, vecTmp1, vecArray1, vecMask0x80); - vectorCheckZero(asm, vecTmp1, vecTmp1); - asm.branchConditionally(ConditionFlag.NE, multibyteNoFastPath); + cbnzVector(asm, ElementSize.Byte, vecTmp1, vecTmp1, tmp, false, multibyteNoFastPath); // current vector is ascii, if the previous vector ended with an incomplete sequence, we // found an error asm.neon.orrVVV(FullReg, vecResult, vecResult, vecPrevIsIncomplete); @@ -828,7 +823,7 @@ private void emitUTF8(CompilationResultBuilder crb, AArch64MacroAssembler asm, R asm.bind(done); asm.neon.orrVVV(FullReg, vecResult, vecResult, vecPrevIsIncomplete); asm.mov(tmp, CR_VALID_MULTIBYTE); - vectorCheckZero(asm, vecResult, vecResult); + cmpZeroVector(asm, vecResult, vecResult, tmp2); assert returnValueAssertions(); asm.csinc(64, tmp, tmp, tmp, ConditionFlag.EQ); asm.orr(64, ret, tmp, ret, ShiftType.LSL, 32); @@ -856,8 +851,9 @@ private void emitUTF8(CompilationResultBuilder crb, AArch64MacroAssembler asm, R } else { asm.add(64, refAddress, arr, len); asm.add(64, arr, arr, 16); - vectorTest(asm, vecTmp1, vecTmp2, vecArray1, vecArray2, vecMask0x80); - asm.branchConditionally(ConditionFlag.NE, multibyteFoundTail); + asm.neon.orrVVV(FullReg, vecTmp1, vecArray1, vecArray2); + asm.neon.andVVV(FullReg, vecTmp2, vecTmp1, vecMask0x80); + cbnzVector(asm, ElementSize.Byte, vecTmp2, vecTmp2, tmp, false, multibyteFoundTail); assert returnValueAssertions(); asm.lsl(64, ret, ret, 32); asm.jmp(end); @@ -884,8 +880,7 @@ private void emitUTF8(CompilationResultBuilder crb, AArch64MacroAssembler asm, R asm.bind(tailLessThan16Continue); asm.neon.andVVV(FullReg, vecTmp1, vecArray1, vecMask0x80); asm.sub(64, refAddress, arr, 16); - vectorCheckZero(asm, vecTmp1, vecTmp1); - asm.branchConditionally(ConditionFlag.NE, multibyteFoundTail); + cbnzVector(asm, ElementSize.Byte, vecTmp1, vecTmp1, tmp, false, multibyteFoundTail); assert returnValueAssertions(); asm.lsl(64, ret, ret, 32); asm.jmp(end); @@ -1119,8 +1114,9 @@ private void emitUTF16(CompilationResultBuilder crb, AArch64MacroAssembler asm, asm.align(PREFERRED_LOOP_ALIGNMENT); asm.bind(asciiLoop); asm.fldp(128, vecArray1, vecArray2, createImmediateAddress(128, AddressingMode.IMMEDIATE_PAIR_POST_INDEXED, arr, 32)); - vectorTest(asm, HalfWord, vecTmp1, vecTmp2, vecArray1, vecArray2, vecMask); - asm.branchConditionally(ConditionFlag.NE, latinContinue); + asm.neon.orrVVV(FullReg, vecTmp1, vecArray1, vecArray2); + asm.neon.cmtstVVV(FullReg, HalfWord, vecTmp2, vecTmp1, vecMask); + cbnzVector(asm, HalfWord, vecTmp2, vecTmp2, tmp, true, latinContinue); asm.cmp(64, arr, refAddress); asm.branchConditionally(ConditionFlag.LO, asciiLoop); @@ -1128,8 +1124,9 @@ private void emitUTF16(CompilationResultBuilder crb, AArch64MacroAssembler asm, asm.mov(64, arr, refAddress); asm.fldp(128, vecArray1, vecArray2, createImmediateAddress(128, AddressingMode.IMMEDIATE_PAIR_POST_INDEXED, arr, 32)); asm.bind(tailLessThan32Continue); - vectorTest(asm, HalfWord, vecTmp1, vecTmp2, vecArray1, vecArray2, vecMask); - asm.branchConditionally(ConditionFlag.NE, latinFoundTail); + asm.neon.orrVVV(FullReg, vecTmp1, vecArray1, vecArray2); + asm.neon.cmtstVVV(FullReg, HalfWord, vecTmp2, vecTmp1, vecMask); + cbnzVector(asm, HalfWord, vecTmp2, vecTmp2, tmp, true, latinFoundTail); assert returnValueAssertions(); asm.lsl(64, ret, ret, 32); asm.jmp(end); @@ -1140,8 +1137,7 @@ private void emitUTF16(CompilationResultBuilder crb, AArch64MacroAssembler asm, asm.fldp(128, vecArray1, vecArray2, createImmediateAddress(128, AddressingMode.IMMEDIATE_PAIR_POST_INDEXED, arr, 32)); asm.bind(latinContinue); asm.neon.uzp2VVV(FullReg, ElementSize.Byte, vecArray2, vecArray1, vecArray2); - vectorCheckZero(asm, vecTmp1, vecArray2); - asm.branchConditionally(ConditionFlag.NE, bmpContinue); + cbnzVector(asm, ElementSize.Byte, vecTmp1, vecArray2, tmp, false, bmpContinue); asm.cmp(64, arr, refAddress); asm.branchConditionally(ConditionFlag.LO, latinLoop); @@ -1150,8 +1146,7 @@ private void emitUTF16(CompilationResultBuilder crb, AArch64MacroAssembler asm, asm.fldp(128, vecArray1, vecArray2, createImmediateAddress(128, AddressingMode.IMMEDIATE_PAIR_POST_INDEXED, arr, 32)); asm.bind(latinFoundTail); asm.neon.uzp2VVV(FullReg, ElementSize.Byte, vecArray2, vecArray1, vecArray2); - vectorCheckZero(asm, vecTmp1, vecArray2); - asm.branchConditionally(ConditionFlag.NE, bmpFoundTail); + cbnzVector(asm, ElementSize.Byte, vecTmp1, vecArray2, tmp, false, bmpFoundTail); asm.mov(tmp, CR_8BIT); asm.orr(64, ret, tmp, ret, ShiftType.LSL, 32); asm.jmp(end); @@ -1162,8 +1157,8 @@ private void emitUTF16(CompilationResultBuilder crb, AArch64MacroAssembler asm, asm.fldp(128, vecArray1, vecArray2, createImmediateAddress(128, AddressingMode.IMMEDIATE_PAIR_POST_INDEXED, arr, 32)); asm.neon.uzp2VVV(FullReg, ElementSize.Byte, vecArray2, vecArray1, vecArray2); asm.bind(bmpContinue); - utf16MatchSurrogatesAndTest(asm, vecArray2, vecTmp1, vecTmp2, vecMaskSurrogates); - asm.branchConditionally(ConditionFlag.NE, surrogateFound); + utf16MatchSurrogates(asm, vecArray2, vecTmp1, vecMaskSurrogates); + cbnzVector(asm, ElementSize.Byte, vecTmp2, vecTmp1, tmp, true, surrogateFound); asm.cmp(64, arr, refAddress); asm.branchConditionally(ConditionFlag.LO, bmpLoop); @@ -1172,8 +1167,8 @@ private void emitUTF16(CompilationResultBuilder crb, AArch64MacroAssembler asm, asm.fldp(128, vecArray1, vecArray2, createImmediateAddress(128, AddressingMode.IMMEDIATE_PAIR_POST_INDEXED, arr, 32)); asm.neon.uzp2VVV(FullReg, ElementSize.Byte, vecArray2, vecArray1, vecArray2); asm.bind(bmpFoundTail); - utf16MatchSurrogatesAndTest(asm, vecArray2, vecTmp1, vecTmp2, vecMaskSurrogates); - asm.branchConditionally(ConditionFlag.NE, surrogateFoundTail); + utf16MatchSurrogates(asm, vecArray2, vecTmp1, vecMaskSurrogates); + cbnzVector(asm, ElementSize.Byte, vecTmp2, vecTmp1, tmp, true, surrogateFoundTail); asm.mov(tmp, CR_16BIT); asm.orr(64, ret, tmp, ret, ShiftType.LSL, 32); asm.jmp(end); @@ -1325,7 +1320,7 @@ private void emitUTF16(CompilationResultBuilder crb, AArch64MacroAssembler asm, asm.neon.cmeqVVV(FullReg, ElementSize.Byte, vecPrev, vecPrev, vecMaskSurrogates); asm.neon.orrVVV(FullReg, vecResult, vecResult, vecPrev); asm.mov(tmp, CR_VALID_MULTIBYTE); - vectorCheckZero(asm, vecResult, vecResult); + cmpZeroVector(asm, vecResult, vecResult, len); assert returnValueAssertions(); asm.csinc(64, tmp, tmp, tmp, ConditionFlag.EQ); asm.orr(64, ret, tmp, ret, ShiftType.LSL, 32); @@ -1421,16 +1416,10 @@ private void utf16MatchSurrogates(AArch64MacroAssembler asm, Register vecArray2, asm.neon.cmeqVVV(FullReg, ElementSize.Byte, vecTmp1, vecTmp1, vecMaskSurrogates); } - private void utf16MatchSurrogatesAndTest(AArch64MacroAssembler asm, Register vecArray2, Register vecTmp1, Register vecTmp2, Register vecMaskSurrogates) { - utf16MatchSurrogates(asm, vecArray2, vecTmp1, vecMaskSurrogates); - // check if any surrogate character was present - vectorCheckZero(asm, vecTmp2, vecTmp1); - } - /** * Implements the operation described in {@link CalcStringAttributesEncoding#UTF_32}. */ - private void emitUTF32(AArch64MacroAssembler asm, Register arr, Register len, Register ret, Label end) { + private void emitUTF32(AArch64MacroAssembler asm, Register arr, Register len, Register tmp, Register ret, Label end) { assert stride.log2 == 2 : stride; Label tailLessThan64 = new Label(); Label tailLessThan32 = new Label(); @@ -1489,8 +1478,9 @@ private void emitUTF32(AArch64MacroAssembler asm, Register arr, Register len, Re createStructureImmediatePostIndexAddress(LD1_MULTIPLE_4R, FullReg, ElementSize.Byte, arr, 64)); asm.neon.orrVVV(FullReg, vecTmp1, vecArray1, vecArray2); asm.neon.orrVVV(FullReg, vecTmp2, vecArray3, vecArray4); - vectorTest(asm, Word, vecTmp1, vecTmp2, vecTmp1, vecTmp2, vecMask); - asm.branchConditionally(ConditionFlag.NE, latinFound); + asm.neon.orrVVV(FullReg, vecTmp1, vecTmp1, vecTmp2); + asm.neon.cmtstVVV(FullReg, Word, vecTmp2, vecTmp1, vecMask); + cbnzVector(asm, Word, vecTmp2, vecTmp2, tmp, true, latinFound); asm.cmp(64, arr, refAddress); asm.branchConditionally(ConditionFlag.LO, asciiLoop); @@ -1504,8 +1494,7 @@ private void emitUTF32(AArch64MacroAssembler asm, Register arr, Register len, Re asm.bind(tailLessThan64Continue); asm.neon.cmtstVVV(FullReg, Word, vecTmp2, vecTmp1, vecMask); asm.neon.shlVVI(FullReg, Word, vecMask, vecMask, 1); - vectorCheckZero(asm, Word, vecTmp2, vecTmp2, true); - asm.branchConditionally(ConditionFlag.NE, latinFoundTail); + cbnzVector(asm, Word, vecTmp2, vecTmp2, tmp, true, latinFoundTail); asm.mov(ret, CR_7BIT); asm.jmp(end); @@ -1525,8 +1514,7 @@ private void emitUTF32(AArch64MacroAssembler asm, Register arr, Register len, Re asm.neon.orrVVV(FullReg, vecTmp1, vecTmp1, vecTmp2); asm.bind(latinContinue); asm.neon.cmtstVVV(FullReg, Word, vecTmp2, vecTmp1, vecMask); - vectorCheckZero(asm, Word, vecTmp2, vecTmp2, true); - asm.branchConditionally(ConditionFlag.NE, bmpFound); + cbnzVector(asm, Word, vecTmp2, vecTmp2, tmp, true, bmpFound); asm.cmp(64, arr, refAddress); asm.branchConditionally(ConditionFlag.LO, latinLoop); @@ -1540,8 +1528,7 @@ private void emitUTF32(AArch64MacroAssembler asm, Register arr, Register len, Re asm.bind(latinFoundTail); asm.neon.cmtstVVV(FullReg, Word, vecTmp2, vecTmp1, vecMask); asm.neon.shlVVI(FullReg, Word, vecMask, vecMask, 8); - vectorCheckZero(asm, Word, vecTmp2, vecTmp2, true); - asm.branchConditionally(ConditionFlag.NE, bmpFoundTail); + cbnzVector(asm, Word, vecTmp2, vecTmp2, tmp, true, bmpFoundTail); asm.mov(ret, CR_8BIT); asm.jmp(end); @@ -1562,9 +1549,8 @@ private void emitUTF32(AArch64MacroAssembler asm, Register arr, Register len, Re asm.neon.orrVVV(FullReg, vecTmp1, vecTmp1, vecTmp2); asm.bind(bmpContinue); asm.neon.cmtstVVV(FullReg, Word, vecTmp2, vecTmp1, vecMask); - vectorCheckZero(asm, Word, vecTmp2, vecTmp2, true); - asm.branchConditionally(ConditionFlag.NE, astralContinue); - utf32CheckInvalidBMP(asm, vecArray1, vecArray2, vecArray3, vecArray4, vecTmp1, vecTmp2, vecTmp3, vecTmp4, vecMaskBroken, returnBroken); + cbnzVector(asm, Word, vecTmp2, vecTmp2, tmp, true, astralContinue); + utf32CheckInvalidBMP(asm, vecArray1, vecArray2, vecArray3, vecArray4, vecTmp1, vecTmp2, vecTmp3, vecTmp4, vecMaskBroken, tmp, returnBroken); asm.cmp(64, arr, refAddress); asm.branchConditionally(ConditionFlag.LO, bmpLoop); @@ -1577,9 +1563,8 @@ private void emitUTF32(AArch64MacroAssembler asm, Register arr, Register len, Re asm.neon.orrVVV(FullReg, vecTmp1, vecTmp1, vecTmp2); asm.bind(bmpFoundTail); asm.neon.cmtstVVV(FullReg, Word, vecTmp2, vecTmp1, vecMask); - vectorCheckZero(asm, Word, vecTmp2, vecTmp2, true); - asm.branchConditionally(ConditionFlag.NE, astralFoundTail); - utf32CheckInvalidBMP(asm, vecArray1, vecArray2, vecArray3, vecArray4, vecTmp1, vecTmp2, vecTmp3, vecTmp4, vecMaskBroken, returnBroken); + cbnzVector(asm, Word, vecTmp2, vecTmp2, tmp, true, astralFoundTail); + utf32CheckInvalidBMP(asm, vecArray1, vecArray2, vecArray3, vecArray4, vecTmp1, vecTmp2, vecTmp3, vecTmp4, vecMaskBroken, tmp, returnBroken); asm.mov(ret, CR_16BIT); asm.jmp(end); @@ -1589,7 +1574,7 @@ private void emitUTF32(AArch64MacroAssembler asm, Register arr, Register len, Re asm.neon.ld1MultipleVVVV(FullReg, ElementSize.Byte, vecArray1, vecArray2, vecArray3, vecArray4, createStructureImmediatePostIndexAddress(LD1_MULTIPLE_4R, FullReg, ElementSize.Byte, arr, 64)); asm.bind(astralContinue); - utf32CheckInvalid(asm, vecArray1, vecArray2, vecArray3, vecArray4, vecTmp1, vecTmp2, vecTmp3, vecTmp4, vecMaskBroken, vecMaskOutOfRange, returnBroken); + utf32CheckInvalid(asm, vecArray1, vecArray2, vecArray3, vecArray4, vecTmp1, vecTmp2, vecTmp3, vecTmp4, vecMaskBroken, vecMaskOutOfRange, tmp, returnBroken); asm.cmp(64, arr, refAddress); asm.branchConditionally(ConditionFlag.LO, astralLoop); @@ -1598,7 +1583,7 @@ private void emitUTF32(AArch64MacroAssembler asm, Register arr, Register len, Re asm.neon.ld1MultipleVVVV(FullReg, ElementSize.Byte, vecArray1, vecArray2, vecArray3, vecArray4, createStructureImmediatePostIndexAddress(LD1_MULTIPLE_4R, FullReg, ElementSize.Byte, arr, 64)); asm.bind(astralFoundTail); - utf32CheckInvalid(asm, vecArray1, vecArray2, vecArray3, vecArray4, vecTmp1, vecTmp2, vecTmp3, vecTmp4, vecMaskBroken, vecMaskOutOfRange, returnBroken); + utf32CheckInvalid(asm, vecArray1, vecArray2, vecArray3, vecArray4, vecTmp1, vecTmp2, vecTmp3, vecTmp4, vecMaskBroken, vecMaskOutOfRange, tmp, returnBroken); asm.mov(ret, CR_VALID); asm.jmp(end); @@ -1668,6 +1653,7 @@ private static void utf32CheckInvalid(AArch64MacroAssembler asm, Register vecTmp4, Register vecMaskBroken, Register vecMaskOutOfRange, + Register tmp, Label returnBroken) { // right-shift string contents (copy) by 11 asm.neon.ushrVVI(FullReg, Word, vecTmp1, vecArray1, 11); @@ -1691,9 +1677,8 @@ private static void utf32CheckInvalid(AArch64MacroAssembler asm, asm.neon.orrVVV(FullReg, vecTmp1, vecTmp1, vecTmp3); asm.neon.orrVVV(FullReg, vecArray1, vecArray1, vecTmp1); // check if any invalid character was present - vectorCheckZero(asm, Word, vecArray1, vecArray1, true); // return CR_BROKEN if any invalid character was present - asm.branchConditionally(ConditionFlag.NE, returnBroken); + cbnzVector(asm, Word, vecArray1, vecArray1, tmp, true, returnBroken); } private static void utf32CheckInvalidBMP(AArch64MacroAssembler asm, @@ -1706,6 +1691,7 @@ private static void utf32CheckInvalidBMP(AArch64MacroAssembler asm, Register vecTmp3, Register vecTmp4, Register vecMaskBroken, + Register tmp, Label returnBroken) { // right-shift string contents (copy) by 11 asm.neon.ushrVVI(FullReg, Word, vecTmp1, vecArray1, 11); @@ -1723,9 +1709,8 @@ private static void utf32CheckInvalidBMP(AArch64MacroAssembler asm, asm.neon.orrVVV(FullReg, vecTmp3, vecTmp3, vecTmp4); asm.neon.orrVVV(FullReg, vecTmp1, vecTmp1, vecTmp3); // check if any invalid character was present - vectorCheckZero(asm, Word, vecTmp1, vecTmp1, true); // return CR_BROKEN if any invalid character was present - asm.branchConditionally(ConditionFlag.NE, returnBroken); + cbnzVector(asm, Word, vecTmp1, vecTmp1, tmp, true, returnBroken); } /** diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/aarch64/AArch64ComplexVectorOp.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/aarch64/AArch64ComplexVectorOp.java index 6665c7ccf76a..6b75bcd02992 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/aarch64/AArch64ComplexVectorOp.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/aarch64/AArch64ComplexVectorOp.java @@ -24,21 +24,23 @@ */ package jdk.graal.compiler.lir.aarch64; -import static jdk.vm.ci.aarch64.AArch64.SIMD; import static jdk.graal.compiler.asm.aarch64.AArch64ASIMDAssembler.ASIMDSize.FullReg; import static jdk.graal.compiler.asm.aarch64.AArch64ASIMDAssembler.ElementSize.Word; +import static jdk.vm.ci.aarch64.AArch64.CPU; +import static jdk.vm.ci.aarch64.AArch64.SIMD; +import static jdk.vm.ci.aarch64.AArch64.zr; import java.util.Arrays; +import jdk.graal.compiler.asm.Label; import jdk.graal.compiler.asm.aarch64.AArch64ASIMDAssembler; import jdk.graal.compiler.asm.aarch64.AArch64MacroAssembler; import jdk.graal.compiler.code.DataSection; import jdk.graal.compiler.core.common.LIRKind; +import jdk.graal.compiler.lir.LIRInstructionClass; import jdk.graal.compiler.lir.asm.ArrayDataPointerConstant; import jdk.graal.compiler.lir.asm.CompilationResultBuilder; -import jdk.graal.compiler.lir.LIRInstructionClass; import jdk.graal.compiler.lir.gen.LIRGeneratorTool; - import jdk.vm.ci.aarch64.AArch64; import jdk.vm.ci.code.Register; import jdk.vm.ci.meta.AllocatableValue; @@ -122,28 +124,40 @@ protected static void loadDataSectionAddress(CompilationResultBuilder crb, AArch asm.adrpAdd(dst); } + protected static void cbnzVector(AArch64MacroAssembler asm, AArch64ASIMDAssembler.ElementSize eSize, Register vecDst, Register vecSrc, Register tmp, boolean allOnes, Label label) { + vectorCheckZeroReduce(asm, eSize, vecDst, vecSrc, tmp, allOnes); + asm.cbnz(64, tmp, label); + } + + protected static void cmpZeroVector(AArch64MacroAssembler asm, Register vecDst, Register vecSrc, Register tmp) { + vectorCheckZeroReduce(asm, AArch64ASIMDAssembler.ElementSize.Byte, vecDst, vecSrc, tmp, false); + asm.cmp(64, tmp, zr); + } + /** - * Check if vector register {@code src} is all zeros and set condition flags accordingly. - * Register {@code dst} is clobbered by this operation. + * Check if vector register {@code vecSrc} is all zeros and set condition flags accordingly. + * Registers {@code vecDst} and {@code tmp} are clobbered by this operation. */ - protected static void vectorCheckZero(AArch64MacroAssembler asm, Register dst, Register src) { - vectorCheckZero(asm, AArch64ASIMDAssembler.ElementSize.Byte, dst, src, false); + protected static void cmpZeroVector(AArch64MacroAssembler asm, AArch64ASIMDAssembler.ElementSize eSize, Register vecDst, Register vecSrc, Register tmp, boolean allOnes) { + vectorCheckZeroReduce(asm, eSize, vecDst, vecSrc, tmp, allOnes); + asm.cmp(64, tmp, zr); } /** - * Check if vector register {@code src} is all zeros and set condition flags accordingly. If - * {@code allOnes} is true, assume that non-zero elements are always filled with ones, e.g. + * Reduce a 128-bit vector to 64 bit and load it to a general-purpose register for a zero check. + * If {@code allOnes} is true, assume that non-zero elements are always filled with ones, e.g. * {@code 0xff} for byte elements, allowing a slightly faster check. */ - protected static void vectorCheckZero(AArch64MacroAssembler asm, AArch64ASIMDAssembler.ElementSize eSize, Register dst, Register src, boolean allOnes) { - assert src.getRegisterCategory().equals(SIMD); - assert dst.getRegisterCategory().equals(SIMD); + private static void vectorCheckZeroReduce(AArch64MacroAssembler asm, AArch64ASIMDAssembler.ElementSize eSize, Register vecDst, Register vecSrc, Register tmp, boolean allOnes) { + assert vecSrc.getRegisterCategory().equals(SIMD); + assert vecDst.getRegisterCategory().equals(SIMD); + assert tmp.getRegisterCategory().equals(CPU); if (eSize == AArch64ASIMDAssembler.ElementSize.Byte || !allOnes) { - asm.neon.umaxvSV(FullReg, Word, dst, src); + asm.neon.umaxpVVV(FullReg, Word, vecDst, vecSrc, vecSrc); } else { - asm.neon.xtnVV(eSize.narrow(), dst, src); + asm.neon.xtnVV(eSize.narrow(), vecDst, vecSrc); } - asm.fcmpZero(64, dst); + asm.neon.umovGX(AArch64ASIMDAssembler.ElementSize.DoubleWord, tmp, vecDst, 0); } /** diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/aarch64/AArch64CountPositivesOp.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/aarch64/AArch64CountPositivesOp.java index 40cd0f97997c..29c22c2f4e42 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/aarch64/AArch64CountPositivesOp.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/aarch64/AArch64CountPositivesOp.java @@ -323,9 +323,8 @@ private void emitStub(AArch64MacroAssembler masm, Register result, Register ary1 // right-shift by 7 to get only the sign bits masm.neon.ushrVVI(FullReg, ElementSize.Byte, vtmp0, vtmp0, 7); // check if result is zero - masm.fcmpZero(64, vtmp0); + cbnzVector(masm, ElementSize.Byte, vtmp0, vtmp0, tmp5, false, labelRetAdjustLong); - masm.branchConditionally(ConditionFlag.NE, labelRetAdjustLong); masm.compare(32, len, LARGE_LOOP_SIZE); masm.branchConditionally(ConditionFlag.GE, labelLargeLoop); diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/aarch64/AArch64EncodeArrayOp.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/aarch64/AArch64EncodeArrayOp.java index 2b3f184c409f..02f5f5c385d9 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/aarch64/AArch64EncodeArrayOp.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/aarch64/AArch64EncodeArrayOp.java @@ -135,15 +135,18 @@ protected void emitCode(CompilationResultBuilder crb, AArch64MacroAssembler masm if (ascii) { // Check if all merged chars are <= 0x7f masm.neon.cmtstVVV(FullReg, ElementSize.HalfWord, vtmp0, vtmp0, vmask); - // Narrow result to bytes for fcmpZero + // Narrow result to bytes for zero check masm.neon.xtnVV(ElementSize.HalfWord.narrow(), vtmp0, vtmp0); } else { // Extract merged upper bytes for ISO check (all zero). masm.neon.uzp2VVV(FullReg, ElementSize.Byte, vtmp0, vtmp0, vtmp0); } + try (AArch64MacroAssembler.ScratchRegister sc1 = masm.getScratchRegister()) { + Register tmp = sc1.getRegister(); + masm.neon.umovGX(ElementSize.DoubleWord, tmp, vtmp0, 0); + masm.cbnz(64, tmp, labelFail32); + } - masm.fcmpZero(64, vtmp0); - masm.branchConditionally(ConditionFlag.NE, labelFail32); masm.sub(32, cnt, cnt, 32); masm.fstp(128, vlo0, vlo1, createImmediateAddress(FullReg.bits(), AddressingMode.IMMEDIATE_PAIR_POST_INDEXED, dst, 32)); masm.jmp(labelLoop32); @@ -165,15 +168,17 @@ protected void emitCode(CompilationResultBuilder crb, AArch64MacroAssembler masm if (ascii) { // Check if all merged chars are <= 0x7f masm.neon.cmtstVVV(FullReg, ElementSize.HalfWord, vtmp0, vtmp0, vmask); - // Narrow result to bytes for fcmpZero + // Narrow result to bytes for zero check masm.neon.xtnVV(ElementSize.HalfWord.narrow(), vtmp0, vtmp0); } else { // Extract upper bytes for ISO check (all zero). masm.neon.uzp2VVV(FullReg, ElementSize.Byte, vtmp0, vtmp0, vtmp0); } - - masm.fcmpZero(64, vtmp0); - masm.branchConditionally(ConditionFlag.NE, labelSkip8); + try (AArch64MacroAssembler.ScratchRegister sc1 = masm.getScratchRegister()) { + Register tmp = sc1.getRegister(); + masm.neon.umovGX(ElementSize.DoubleWord, tmp, vtmp0, 0); + masm.cbnz(64, tmp, labelSkip8); + } masm.fstr(64, vlo0, createImmediateAddress(64, AddressingMode.IMMEDIATE_POST_INDEXED, dst, 8)); masm.sub(32, cnt, cnt, 8); masm.add(64, src, src, 16); diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/aarch64/AArch64StringUTF16CompressOp.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/aarch64/AArch64StringUTF16CompressOp.java index 3442d7c10f61..876054ad9251 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/aarch64/AArch64StringUTF16CompressOp.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/aarch64/AArch64StringUTF16CompressOp.java @@ -61,6 +61,7 @@ public final class AArch64StringUTF16CompressOp extends AArch64LIRInstruction { @Alive({REG}) protected AllocatableValue dst; @Temp({REG}) protected AllocatableValue temp1; @Temp({REG}) protected AllocatableValue temp2; + @Temp({REG}) protected AllocatableValue temp3; @Temp({REG}) protected AllocatableValue vectorTemp1; @Temp({REG}) protected AllocatableValue vectorTemp2; @Temp({REG}) protected AllocatableValue vectorTemp3; @@ -79,6 +80,7 @@ public AArch64StringUTF16CompressOp(LIRGeneratorTool tool, AllocatableValue src, LIRKind archWordKind = LIRKind.value(AArch64Kind.QWORD); temp1 = tool.newVariable(archWordKind); temp2 = tool.newVariable(archWordKind); + temp3 = tool.newVariable(archWordKind); LIRKind vectorKind = LIRKind.value(tool.target().arch.getLargestStorableKind(SIMD)); vectorTemp1 = tool.newVariable(vectorKind); vectorTemp2 = tool.newVariable(vectorKind); @@ -152,6 +154,7 @@ private void emitSIMD(AArch64MacroAssembler masm, Label scalarImpl, Label done, Register chunkPart1RegV = asRegister(vectorTemp1); Register chunkPart2RegV = asRegister(vectorTemp2); Register tmpRegV1 = asRegister(vectorTemp3); + Register tmp = asRegister(temp3); Label simdLoop = new Label(); Label failToCompress = new Label(); @@ -174,8 +177,8 @@ private void emitSIMD(AArch64MacroAssembler masm, Label scalarImpl, Label done, */ masm.neon.orrVVV(AArch64ASIMDAssembler.ASIMDSize.FullReg, tmpRegV1, chunkPart1RegV, chunkPart2RegV); masm.neon.uzp2VVV(AArch64ASIMDAssembler.ASIMDSize.FullReg, ElementSize.Byte, tmpRegV1, tmpRegV1, tmpRegV1); - masm.fcmpZero(64, tmpRegV1); - masm.branchConditionally(ConditionFlag.NE, failToCompress); + masm.neon.umovGX(ElementSize.DoubleWord, tmp, tmpRegV1, 0); + masm.cbnz(64, tmp, failToCompress); // compress elements masm.neon.xtnVV(ElementSize.Byte, tmpRegV1, chunkPart1RegV); @@ -209,8 +212,8 @@ private void emitSIMD(AArch64MacroAssembler masm, Label scalarImpl, Label done, */ masm.mov(result, 8); masm.neon.uzp2VVV(AArch64ASIMDAssembler.ASIMDSize.FullReg, ElementSize.Byte, tmpRegV1, chunkPart1RegV, chunkPart1RegV); - masm.fcmpZero(64, tmpRegV1); - masm.branchConditionally(ConditionFlag.NE, redoEntireChunk); + masm.neon.umovGX(ElementSize.DoubleWord, tmp, tmpRegV1, 0); + masm.cbnz(64, tmp, redoEntireChunk); // fall-through: store chunkPart1 and start search at chunkPart2 // note this is really CHUNK_ELEMENT_SIZE * 2 / 2 diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/aarch64/AArch64VectorizedMismatchOp.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/aarch64/AArch64VectorizedMismatchOp.java index 715e9e830d8a..7e8a5f11a044 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/aarch64/AArch64VectorizedMismatchOp.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/aarch64/AArch64VectorizedMismatchOp.java @@ -24,14 +24,14 @@ */ package jdk.graal.compiler.lir.aarch64; -import static jdk.vm.ci.aarch64.AArch64.zr; -import static jdk.vm.ci.code.ValueUtil.asRegister; import static jdk.graal.compiler.asm.aarch64.AArch64ASIMDAssembler.ASIMDSize.FullReg; import static jdk.graal.compiler.asm.aarch64.AArch64Address.createBaseRegisterOnlyAddress; import static jdk.graal.compiler.asm.aarch64.AArch64Address.createImmediateAddress; import static jdk.graal.compiler.asm.aarch64.AArch64MacroAssembler.PREFERRED_BRANCH_TARGET_ALIGNMENT; import static jdk.graal.compiler.asm.aarch64.AArch64MacroAssembler.PREFERRED_LOOP_ALIGNMENT; import static jdk.graal.compiler.lir.LIRInstruction.OperandFlag.REG; +import static jdk.vm.ci.aarch64.AArch64.zr; +import static jdk.vm.ci.code.ValueUtil.asRegister; import jdk.graal.compiler.asm.Label; import jdk.graal.compiler.asm.aarch64.AArch64ASIMDAssembler.ElementSize; @@ -40,11 +40,10 @@ import jdk.graal.compiler.asm.aarch64.AArch64Assembler.ShiftType; import jdk.graal.compiler.asm.aarch64.AArch64MacroAssembler; import jdk.graal.compiler.debug.GraalError; -import jdk.graal.compiler.lir.asm.CompilationResultBuilder; import jdk.graal.compiler.lir.LIRInstructionClass; import jdk.graal.compiler.lir.Opcode; +import jdk.graal.compiler.lir.asm.CompilationResultBuilder; import jdk.graal.compiler.lir.gen.LIRGeneratorTool; - import jdk.vm.ci.aarch64.AArch64Kind; import jdk.vm.ci.code.Register; import jdk.vm.ci.meta.AllocatableValue; @@ -156,9 +155,9 @@ private void emitVectorizedMismatch(AArch64MacroAssembler asm, Register arrayA, asm.neon.eorVVV(FullReg, vecArrayA1, vecArrayA1, vecArrayB1); asm.neon.eorVVV(FullReg, vecArrayA2, vecArrayA2, vecArrayB2); asm.neon.orrVVV(FullReg, vecArrayB1, vecArrayA1, vecArrayA2); - asm.neon.umaxvSV(FullReg, ElementSize.Word, vecArrayB1, vecArrayB1); - asm.fcmpZero(64, vecArrayB1); - asm.branchConditionally(ConditionFlag.NE, diffFound); + asm.neon.umaxpVVV(FullReg, ElementSize.Word, vecArrayB1, vecArrayB1, vecArrayB1); + asm.neon.umovGX(ElementSize.DoubleWord, tmp, vecArrayB1, 0); + asm.cbnz(64, tmp, diffFound); asm.cmp(64, arrayA, refAddress); asm.branchConditionally(ConditionFlag.LO, vectorLoop); @@ -172,9 +171,9 @@ private void emitVectorizedMismatch(AArch64MacroAssembler asm, Register arrayA, asm.neon.eorVVV(FullReg, vecArrayA1, vecArrayA1, vecArrayB1); asm.neon.eorVVV(FullReg, vecArrayA2, vecArrayA2, vecArrayB2); asm.neon.orrVVV(FullReg, vecArrayB1, vecArrayA1, vecArrayA2); - asm.neon.umaxvSV(FullReg, ElementSize.Word, vecArrayB1, vecArrayB1); - asm.fcmpZero(64, vecArrayB1); - asm.branchConditionally(ConditionFlag.EQ, retEqual); + asm.neon.umaxpVVV(FullReg, ElementSize.Word, vecArrayB1, vecArrayB1, vecArrayB1); + asm.neon.umovGX(ElementSize.DoubleWord, tmp, vecArrayB1, 0); + asm.cbz(64, tmp, retEqual); asm.align(PREFERRED_BRANCH_TARGET_ALIGNMENT); asm.bind(diffFound); From 3fe5dc81dfbaeeb79eb56198293d25af2cc3694f Mon Sep 17 00:00:00 2001 From: Fabio Niephaus Date: Wed, 6 Dec 2023 11:13:18 +0100 Subject: [PATCH 102/593] Improve docs on reflection. --- docs/reference-manual/native-image/Reflection.md | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/docs/reference-manual/native-image/Reflection.md b/docs/reference-manual/native-image/Reflection.md index d76b14917077..872e279f7e63 100644 --- a/docs/reference-manual/native-image/Reflection.md +++ b/docs/reference-manual/native-image/Reflection.md @@ -11,9 +11,11 @@ redirect_from: /reference-manual/native-image/Reflection/ Java reflection support (the `java.lang.reflect.*` API) enables Java code to examine its own classes, methods, fields and their properties at run time. (Note: loading classes with `Class.forName(String)` are included here since it is closely related to reflection.) -Native Image supports reflection in ahead-of-time compiled images, but requires additional configuration in many cases. -Examining and accessing program elements through `java.lang.reflect.*` or loading classes with `Class.forName(String)` at run time requires preparing additional metadata for those program elements in the image. -This metadata must be stored in the image already when it is created ahead-of-time. +Native Image fully supports reflection in ahead-of-time compiled images. +It may require additional configuration when reflection is used in ways that are unpredictable for the static analysis (e.g., depending on user input). +Examining and accessing program elements through `java.lang.reflect.*` or loading classes with `Class.forName(String)` at run time can require preparing additional metadata for those program elements in the image. +This metadata must be stored in the image already when it is created ahead of time. +To reduce both the overall file size of images and the overhead of maintaining configuration, it is nonetheless recommended to avoid the use of reflection when possible. Native Image tries to resolve the target elements through a static analysis that detects calls to the Reflection API. Where the analysis fails, the program elements reflectively accessed at run time must be specified using a manual configuration. From accae6668c911addbaf35e9925e8246276cf27f9 Mon Sep 17 00:00:00 2001 From: Fabio Niephaus Date: Wed, 6 Dec 2023 12:10:58 +0100 Subject: [PATCH 103/593] `--bundle-apply` also ignores `NATIVE_IMAGE_OPTIONS`. Do not forward env var options and improve warning. --- .../src/com/oracle/svm/driver/NativeImage.java | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/substratevm/src/com.oracle.svm.driver/src/com/oracle/svm/driver/NativeImage.java b/substratevm/src/com.oracle.svm.driver/src/com/oracle/svm/driver/NativeImage.java index 200f4823de26..a5893321b407 100644 --- a/substratevm/src/com.oracle.svm.driver/src/com/oracle/svm/driver/NativeImage.java +++ b/substratevm/src/com.oracle.svm.driver/src/com/oracle/svm/driver/NativeImage.java @@ -864,15 +864,17 @@ private List getDefaultNativeImageArgs() { final String envVarName = SubstrateOptions.NATIVE_IMAGE_OPTIONS_ENV_VAR; String nativeImageOptionsValue = System.getenv(envVarName); if (nativeImageOptionsValue != null) { - addPlainImageBuilderArg(oHNativeImageOptionsEnvVar + nativeImageOptionsValue); defaultNativeImageArgs.addAll(JDKArgsUtils.parseArgsFromEnvVar(nativeImageOptionsValue, envVarName, msg -> showError(msg))); } if (!defaultNativeImageArgs.isEmpty()) { String buildApplyOptionName = BundleSupport.BundleOptionVariants.apply.optionName(); if (config.getBuildArgs().stream().noneMatch(arg -> arg.startsWith(buildApplyOptionName + "="))) { + if (nativeImageOptionsValue != null) { + addPlainImageBuilderArg(oHNativeImageOptionsEnvVar + nativeImageOptionsValue); + } return List.copyOf(defaultNativeImageArgs); } else { - LogUtils.warning("Option " + buildApplyOptionName + " in use. Ignoring args from file specified with environment variable " + NativeImage.CONFIG_FILE_ENV_VAR_KEY + "."); + LogUtils.warning("Option '" + buildApplyOptionName + "' in use. Ignoring environment variables " + envVarName + " and " + NativeImage.CONFIG_FILE_ENV_VAR_KEY + "."); } } return List.of(); From 7b1fd18265863e092d1ab87efc6be114354415a3 Mon Sep 17 00:00:00 2001 From: Fengyun Liu Date: Wed, 6 Dec 2023 13:24:53 +0100 Subject: [PATCH 104/593] Add ticket number to comment --- substratevm/mx.substratevm/mx_substratevm_benchmark.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/substratevm/mx.substratevm/mx_substratevm_benchmark.py b/substratevm/mx.substratevm/mx_substratevm_benchmark.py index 875c35bc0153..b42982dca4f8 100644 --- a/substratevm/mx.substratevm/mx_substratevm_benchmark.py +++ b/substratevm/mx.substratevm/mx_substratevm_benchmark.py @@ -657,7 +657,7 @@ def extra_profile_run_arg(self, benchmark, args, image_run_args, should_strip_ru def extra_image_build_argument(self, benchmark, args): # Don't wrap the option `-H:-ParseRuntimeOptions` with `mx_sdk_vm_impl.svm_experimental_options`, as all args are wrapped already. - # The reason to add `-H:CompilationExpirationPeriod` is that we encounter non-deterministic compiler crash due to expiration. + # The reason to add `-H:CompilationExpirationPeriod` is that we encounter non-deterministic compiler crash due to expiration (GR-50701). return super().extra_image_build_argument(benchmark, args) + ['-H:-ParseRuntimeOptions', '-H:CompilationExpirationPeriod=600'] def extra_run_arg(self, benchmark, args, image_run_args): From 3793ff93b985905e97b7901d77056546c7c129ad Mon Sep 17 00:00:00 2001 From: Carlo Refice Date: Wed, 6 Dec 2023 13:38:35 +0100 Subject: [PATCH 105/593] Clean up various redundant conditions in compiler code --- .../src/jdk/graal/compiler/graph/Graph.java | 8 ++--- .../lsra/LinearScanLifetimeAnalysisPhase.java | 30 +++++++++---------- .../common/ConditionalEliminationUtil.java | 4 +-- .../nodes/BasicArrayCopyNode.java | 5 +--- .../compiler/truffle/ExpansionStatistics.java | 2 +- .../phases/ea/PEReadEliminationClosure.java | 6 ++-- .../phases/ea/ReadEliminationClosure.java | 2 +- 7 files changed, 24 insertions(+), 33 deletions(-) diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/graph/Graph.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/graph/Graph.java index 9d1f787c71de..43aa8bc31fdf 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/graph/Graph.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/graph/Graph.java @@ -1231,12 +1231,8 @@ private Node findFirstLiveIterable(int iterableId, Node node) { * @return return the first live Node with a matching iterableId starting from {@code node} */ Node getIterableNodeNext(Node node) { - if (node == null) { - return null; - } - Node n = node; - if (n == null || !n.isDeleted()) { - return n; + if (node == null || !node.isDeleted()) { + return node; } return findNextLiveiterable(node); diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/alloc/lsra/LinearScanLifetimeAnalysisPhase.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/alloc/lsra/LinearScanLifetimeAnalysisPhase.java index 8524e3b02a34..a5b6143d2630 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/alloc/lsra/LinearScanLifetimeAnalysisPhase.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/alloc/lsra/LinearScanLifetimeAnalysisPhase.java @@ -34,18 +34,9 @@ import java.util.BitSet; import java.util.EnumSet; -import jdk.graal.compiler.lir.InstructionStateProcedure; -import jdk.graal.compiler.lir.InstructionValueConsumer; -import jdk.graal.compiler.lir.LIRInstruction; -import jdk.graal.compiler.lir.LIRValueUtil; -import jdk.graal.compiler.lir.StandardOp; -import jdk.graal.compiler.lir.ValueConsumer; -import jdk.graal.compiler.lir.debug.LIRGenerationDebugContext; -import jdk.graal.compiler.lir.gen.LIRGenerationResult; -import jdk.graal.compiler.lir.phases.AllocationPhase; -import jdk.graal.compiler.lir.util.IndexedValueMap; import org.graalvm.collections.EconomicSet; import org.graalvm.collections.Equivalence; + import jdk.graal.compiler.core.common.LIRKind; import jdk.graal.compiler.core.common.PermanentBailoutException; import jdk.graal.compiler.core.common.cfg.BasicBlock; @@ -54,10 +45,19 @@ import jdk.graal.compiler.debug.DebugContext; import jdk.graal.compiler.debug.GraalError; import jdk.graal.compiler.debug.Indent; +import jdk.graal.compiler.lir.InstructionStateProcedure; +import jdk.graal.compiler.lir.InstructionValueConsumer; +import jdk.graal.compiler.lir.LIRInstruction; +import jdk.graal.compiler.lir.LIRValueUtil; +import jdk.graal.compiler.lir.StandardOp; +import jdk.graal.compiler.lir.ValueConsumer; import jdk.graal.compiler.lir.alloc.lsra.Interval.RegisterPriority; import jdk.graal.compiler.lir.alloc.lsra.Interval.SpillState; import jdk.graal.compiler.lir.alloc.lsra.LinearScan.BlockData; - +import jdk.graal.compiler.lir.debug.LIRGenerationDebugContext; +import jdk.graal.compiler.lir.gen.LIRGenerationResult; +import jdk.graal.compiler.lir.phases.AllocationPhase; +import jdk.graal.compiler.lir.util.IndexedValueMap; import jdk.vm.ci.code.Register; import jdk.vm.ci.code.RegisterArray; import jdk.vm.ci.code.StackSlot; @@ -333,11 +333,9 @@ protected void computeGlobalLiveSets() { if (n > 0) { scratch.clear(); // block has successors - if (n > 0) { - for (int j = 0; j < block.getSuccessorCount(); j++) { - BasicBlock successor = block.getSuccessorAt(j); - scratch.or(allocator.getBlockData(successor).liveIn); - } + for (int j = 0; j < block.getSuccessorCount(); j++) { + BasicBlock successor = block.getSuccessorAt(j); + scratch.or(allocator.getBlockData(successor).liveIn); } if (!blockSets.liveOut.equals(scratch)) { diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/phases/common/ConditionalEliminationUtil.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/phases/common/ConditionalEliminationUtil.java index 6c449e478744..a91b93561b44 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/phases/common/ConditionalEliminationUtil.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/phases/common/ConditionalEliminationUtil.java @@ -27,6 +27,7 @@ import java.util.ArrayDeque; import org.graalvm.collections.Pair; + import jdk.graal.compiler.core.common.type.ArithmeticOpTable; import jdk.graal.compiler.core.common.type.ArithmeticOpTable.BinaryOp; import jdk.graal.compiler.core.common.type.ArithmeticOpTable.BinaryOp.Or; @@ -49,7 +50,6 @@ import jdk.graal.compiler.nodes.calc.IntegerEqualsNode; import jdk.graal.compiler.nodes.calc.UnaryNode; import jdk.graal.compiler.nodes.extended.GuardingNode; - import jdk.vm.ci.meta.JavaConstant; import jdk.vm.ci.meta.TriState; @@ -403,7 +403,7 @@ public static boolean tryProveGuardCondition(InfoElementProvider infoElementProv return true; } } - if (!y.isConstant() && guardFolding != null) { + if (!y.isConstant()) { Stamp newStampY = binaryOpLogicNode.getSucceedingStampForY(thisGuard.isNegated(), getOtherSafeStamp(x), getSafeStamp(y)); if (newStampY != null && guardFolding.foldGuard(thisGuard, y, newStampY, rewireGuardFunction)) { return true; diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/replacements/nodes/BasicArrayCopyNode.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/replacements/nodes/BasicArrayCopyNode.java index 83c90a192163..27bb76c81842 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/replacements/nodes/BasicArrayCopyNode.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/replacements/nodes/BasicArrayCopyNode.java @@ -246,11 +246,8 @@ public boolean isExact() { 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 destType.isAssignableFrom(srcType); } return false; } diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/truffle/ExpansionStatistics.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/truffle/ExpansionStatistics.java index a3dc4ca5925a..f081e4b3e0ac 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/truffle/ExpansionStatistics.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/truffle/ExpansionStatistics.java @@ -926,7 +926,7 @@ private double getFrequency() { */ return 1.0; } - if (frequency == UNSET_FREQUENCY && parent != null) { + if (frequency == UNSET_FREQUENCY) { return parent.getFrequency(); } else { return frequency; diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/virtual/phases/ea/PEReadEliminationClosure.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/virtual/phases/ea/PEReadEliminationClosure.java index f0b685d32869..7cf1b77c8003 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/virtual/phases/ea/PEReadEliminationClosure.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/virtual/phases/ea/PEReadEliminationClosure.java @@ -36,6 +36,8 @@ import org.graalvm.collections.Equivalence; import org.graalvm.collections.MapCursor; import org.graalvm.collections.Pair; +import org.graalvm.word.LocationIdentity; + import jdk.graal.compiler.core.common.cfg.Loop; import jdk.graal.compiler.graph.Node; import jdk.graal.compiler.nodes.AbstractBeginNode; @@ -70,8 +72,6 @@ import jdk.graal.compiler.nodes.virtual.VirtualArrayNode; import jdk.graal.compiler.options.OptionValues; import jdk.graal.compiler.virtual.phases.ea.PEReadEliminationBlockState.ReadCacheEntry; -import org.graalvm.word.LocationIdentity; - import jdk.vm.ci.meta.JavaConstant; import jdk.vm.ci.meta.JavaKind; import jdk.vm.ci.meta.ResolvedJavaType; @@ -492,7 +492,7 @@ protected void processKilledLoopLocations(Loop loop, PEReadElimination for (LocationIdentity location : forwardEndLiveLocations) { loopKilledLocations.rememberLoopKilledLocation(location); } - if (debug.isLogEnabled() && loopKilledLocations != null) { + if (debug.isLogEnabled()) { debug.log("[Early Read Elimination] Setting loop killed locations of loop at node %s with %s", beginNode, forwardEndLiveLocations); } diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/virtual/phases/ea/ReadEliminationClosure.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/virtual/phases/ea/ReadEliminationClosure.java index 1edd10c33f85..0f1f89da427f 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/virtual/phases/ea/ReadEliminationClosure.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/virtual/phases/ea/ReadEliminationClosure.java @@ -373,7 +373,7 @@ protected void processKilledLoopLocations(Loop loop, ReadEliminationBl for (LocationIdentity location : forwardEndLiveLocations) { loopKilledLocations.rememberLoopKilledLocation(location); } - if (debug.isLogEnabled() && loopKilledLocations != null) { + if (debug.isLogEnabled()) { debug.log("[Early Read Elimination] Setting loop killed locations of loop at node %s with %s", loop.getHeader().getBeginNode(), forwardEndLiveLocations); } From 91cd7d9a03cecc9f49a37d5d7a5c9d83ce361fd9 Mon Sep 17 00:00:00 2001 From: Allan Gregersen Date: Wed, 6 Dec 2023 14:15:10 +0100 Subject: [PATCH 106/593] add comment that explains why we need synchronization on 'allBindings' which is a SynchronizedSet --- .../src/com/oracle/truffle/api/debug/DebuggerSession.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/truffle/src/com.oracle.truffle.api.debug/src/com/oracle/truffle/api/debug/DebuggerSession.java b/truffle/src/com.oracle.truffle.api.debug/src/com/oracle/truffle/api/debug/DebuggerSession.java index 841a491d3cc2..c33573fa78b3 100644 --- a/truffle/src/com.oracle.truffle.api.debug/src/com/oracle/truffle/api/debug/DebuggerSession.java +++ b/truffle/src/com.oracle.truffle.api.debug/src/com/oracle/truffle/api/debug/DebuggerSession.java @@ -1398,6 +1398,8 @@ private List collectDebuggerNodes(DebuggerNode source, SuspendAnch private List collectDebuggerNodes(Node iNode, SuspendAnchor suspendAnchor) { List nodes = new ArrayList<>(); synchronized (allBindings) { + // allBindings is a synchronized set, but we still need to synchronize + // iteration against manipulations, to avoid ConcurrentModificationExceptions for (EventBinding binding : allBindings) { DebuggerNode node = (DebuggerNode) debugger.getInstrumenter().lookupExecutionEventNode(iNode, binding); if (node != null && node.isActiveAt(suspendAnchor)) { From 3b3907b7edfd3e7b2db4ca8c55c9b95ae4f44d03 Mon Sep 17 00:00:00 2001 From: Christian Haeubl Date: Wed, 6 Dec 2023 12:42:28 +0100 Subject: [PATCH 107/593] Minor fixes and cleanups. --- .../posix/pthread/PthreadConditionUtils.java | 5 ++-- .../core/code/CompilationResultFrameTree.java | 7 ++--- .../truffle/HSTruffleCompilerRuntime.java | 3 -- .../svm/hosted/NativeImageClassLoader.java | 30 +++++-------------- 4 files changed, 13 insertions(+), 32 deletions(-) diff --git a/substratevm/src/com.oracle.svm.core.posix/src/com/oracle/svm/core/posix/pthread/PthreadConditionUtils.java b/substratevm/src/com.oracle.svm.core.posix/src/com/oracle/svm/core/posix/pthread/PthreadConditionUtils.java index ee6507dd17ba..154f2b691505 100644 --- a/substratevm/src/com.oracle.svm.core.posix/src/com/oracle/svm/core/posix/pthread/PthreadConditionUtils.java +++ b/substratevm/src/com.oracle.svm.core.posix/src/com/oracle/svm/core/posix/pthread/PthreadConditionUtils.java @@ -24,7 +24,6 @@ */ package com.oracle.svm.core.posix.pthread; -import jdk.graal.compiler.api.replacements.Fold; import org.graalvm.nativeimage.Platform; import org.graalvm.nativeimage.StackValue; import org.graalvm.word.WordFactory; @@ -40,6 +39,8 @@ import com.oracle.svm.core.posix.headers.linux.LinuxTime; import com.oracle.svm.core.util.TimeUtils; +import jdk.graal.compiler.api.replacements.Fold; + /** * This class contains helper methods for the clock and time handling for {@link pthread_cond_t * conditions}. Depending on how a {@link pthread_cond_t condition} is initialized, it uses a @@ -87,7 +88,7 @@ public static int initConditionWithRelativeTime(pthread_cond_t cond) { if (status == 0) { try { if (useMonotonicClockForRelativeWait()) { - LinuxPthread.pthread_condattr_setclock(attr, LinuxTime.CLOCK_MONOTONIC()); + status = LinuxPthread.pthread_condattr_setclock(attr, LinuxTime.CLOCK_MONOTONIC()); if (status != 0) { return status; } diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/code/CompilationResultFrameTree.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/code/CompilationResultFrameTree.java index c6483298f972..5312c2063a96 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/code/CompilationResultFrameTree.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/code/CompilationResultFrameTree.java @@ -31,12 +31,11 @@ import java.util.List; import java.util.function.Consumer; +import com.oracle.svm.core.util.VMError; + import jdk.graal.compiler.code.CompilationResult; import jdk.graal.compiler.code.SourceMapping; import jdk.graal.compiler.debug.DebugContext; - -import com.oracle.svm.core.util.VMError; - import jdk.vm.ci.code.BytecodeFrame; import jdk.vm.ci.code.BytecodePosition; import jdk.vm.ci.code.site.Call; @@ -329,7 +328,7 @@ public String getLocalsStr() { sb.append(", "); } sb.append("li("); - Local local = locals != null ? locals[i] : null; + Local local = locals[i]; if (local != null) { sb.append(local.getName()); sb.append("="); diff --git a/substratevm/src/com.oracle.svm.graal.hotspot.libgraal/src/com/oracle/svm/graal/hotspot/libgraal/truffle/HSTruffleCompilerRuntime.java b/substratevm/src/com.oracle.svm.graal.hotspot.libgraal/src/com/oracle/svm/graal/hotspot/libgraal/truffle/HSTruffleCompilerRuntime.java index 004f82d13de8..32cd6f7730c2 100644 --- a/substratevm/src/com.oracle.svm.graal.hotspot.libgraal/src/com/oracle/svm/graal/hotspot/libgraal/truffle/HSTruffleCompilerRuntime.java +++ b/substratevm/src/com.oracle.svm.graal.hotspot.libgraal/src/com/oracle/svm/graal/hotspot/libgraal/truffle/HSTruffleCompilerRuntime.java @@ -194,9 +194,6 @@ public ConstantFieldInfo getConstantFieldInfo(ResolvedJavaField field) { } long typeHandle = LibGraal.translate(enclosingType); int rawValue = callGetConstantFieldInfo(calls, env(), getHandle(), typeHandle, isStatic, fieldIndex); - if (rawValue == Integer.MIN_VALUE) { - return null; - } switch (rawValue) { case Integer.MIN_VALUE: return null; diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/NativeImageClassLoader.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/NativeImageClassLoader.java index 13ffa9b972be..2fcb41dd3309 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/NativeImageClassLoader.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/NativeImageClassLoader.java @@ -59,7 +59,6 @@ import com.oracle.svm.core.util.UserError; import jdk.internal.access.SharedSecrets; -import jdk.internal.loader.BootLoader; import jdk.internal.loader.ClassLoaders; import jdk.internal.loader.Resource; import jdk.internal.loader.URLClassPath; @@ -145,6 +144,7 @@ CodeSource codeSource() { NativeImageClassLoader(List classpath, Configuration configuration, ClassLoader parent) { super(parent); + Objects.requireNonNull(parent); this.parent = parent; Map nameToModule = new HashMap<>(); @@ -269,7 +269,7 @@ protected URL findResource(String mn, String name) throws IOException { } /* otherwise search in specific module */ - ModuleReference mref = (mn != null) ? localNameToModule.get(mn) : null; + ModuleReference mref = localNameToModule.get(mn); if (mref == null) { return null; } @@ -344,11 +344,7 @@ public URL getResource(String name) { URL url = findResource(name); if (url == null) { - if (parent != null) { - url = parent.getResource(name); - } else { - url = BootLoader.findResource(name); - } + url = parent.getResource(name); } return url; } @@ -361,13 +357,7 @@ public Enumeration getResources(String name) throws IOException { Objects.requireNonNull(name); List urls = findResourcesAsList(name); - - Enumeration e; - if (parent != null) { - e = parent.getResources(name); - } else { - e = BootLoader.findResources(name); - } + Enumeration e = parent.getResources(name); return new Enumeration<>() { final Iterator iterator = urls.iterator(); @@ -625,7 +615,7 @@ protected Class loadClass(String cn, boolean resolve) throws ClassNotFoundExc try { c = parent.loadClass(cn); } catch (ClassNotFoundException ignore) { - c = null; + /* Ignore. */ } } @@ -636,9 +626,7 @@ protected Class loadClass(String cn, boolean resolve) throws ClassNotFoundExc c = findClassInModuleOrNull(loadedModule, cn); } else { /* Not found in modules of this loader, try class-path instead */ - if (c == null) { - c = findClassViaClassPath(cn); - } + c = findClassViaClassPath(cn); if (c == null) { String pn = packageName(cn); @@ -646,11 +634,7 @@ protected Class loadClass(String cn, boolean resolve) throws ClassNotFoundExc if (loader == null) { loader = parent; } - if (loader == null) { - c = BootLoader.loadClassOrNull(cn); - } else { - c = loader.loadClass(cn); - } + c = loader.loadClass(cn); } } } From e7f970aaa6f53d17c2c98f6882e953e502b6dab1 Mon Sep 17 00:00:00 2001 From: David Leopoldseder Date: Tue, 5 Dec 2023 13:15:03 +0100 Subject: [PATCH 108/593] array length node: replace with pi anchored in the block of the original array length to avoid using the array length found by the provider at a place where it might not even be correct --- .../compiler/nodes/java/ArrayLengthNode.java | 61 ++++++++++++++++--- 1 file changed, 51 insertions(+), 10 deletions(-) diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/nodes/java/ArrayLengthNode.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/nodes/java/ArrayLengthNode.java index 58271225b723..29a75326c1c6 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/nodes/java/ArrayLengthNode.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/nodes/java/ArrayLengthNode.java @@ -27,13 +27,12 @@ import static jdk.graal.compiler.nodeinfo.NodeCycles.CYCLES_2; import static jdk.graal.compiler.nodeinfo.NodeSize.SIZE_1; +import org.graalvm.word.LocationIdentity; + import jdk.graal.compiler.core.common.type.AbstractObjectStamp; import jdk.graal.compiler.core.common.type.StampFactory; import jdk.graal.compiler.graph.Node.NodeIntrinsicFactory; import jdk.graal.compiler.graph.NodeClass; -import jdk.graal.compiler.nodes.virtual.VirtualArrayNode; -import jdk.graal.compiler.nodes.spi.Canonicalizable; -import jdk.graal.compiler.nodes.spi.CanonicalizerTool; import jdk.graal.compiler.nodeinfo.NodeInfo; import jdk.graal.compiler.nodes.BeginNode; import jdk.graal.compiler.nodes.ConstantNode; @@ -42,16 +41,20 @@ import jdk.graal.compiler.nodes.NamedLocationIdentity; import jdk.graal.compiler.nodes.NodeView; import jdk.graal.compiler.nodes.PiNode; +import jdk.graal.compiler.nodes.StructuredGraph; import jdk.graal.compiler.nodes.ValueNode; import jdk.graal.compiler.nodes.graphbuilderconf.GraphBuilderContext; import jdk.graal.compiler.nodes.memory.MemoryAccess; import jdk.graal.compiler.nodes.spi.ArrayLengthProvider; +import jdk.graal.compiler.nodes.spi.Canonicalizable; +import jdk.graal.compiler.nodes.spi.CanonicalizerTool; import jdk.graal.compiler.nodes.spi.Lowerable; +import jdk.graal.compiler.nodes.spi.Simplifiable; +import jdk.graal.compiler.nodes.spi.SimplifierTool; import jdk.graal.compiler.nodes.spi.Virtualizable; import jdk.graal.compiler.nodes.spi.VirtualizerTool; import jdk.graal.compiler.nodes.util.GraphUtil; -import org.graalvm.word.LocationIdentity; - +import jdk.graal.compiler.nodes.virtual.VirtualArrayNode; import jdk.vm.ci.meta.ConstantReflectionProvider; import jdk.vm.ci.meta.DeoptimizationAction; import jdk.vm.ci.meta.DeoptimizationReason; @@ -62,7 +65,7 @@ */ @NodeInfo(cycles = CYCLES_2, size = SIZE_1) @NodeIntrinsicFactory -public final class ArrayLengthNode extends FixedWithNextNode implements Canonicalizable.Unary, Lowerable, Virtualizable, MemoryAccess { +public final class ArrayLengthNode extends FixedWithNextNode implements Canonicalizable.Unary, Lowerable, Virtualizable, MemoryAccess, Simplifiable { public static final NodeClass TYPE = NodeClass.create(ArrayLengthNode.class); @Input ValueNode array; @@ -104,13 +107,51 @@ public ValueNode canonical(CanonicalizerTool tool, ValueNode forValue) { if (forValue.isNullConstant()) { return new DeoptimizeNode(DeoptimizationAction.InvalidateReprofile, DeoptimizationReason.NullCheckException); } - ValueNode length = readArrayLength(forValue, tool.getConstantReflection()); - if (length != null) { - return length; - } return this; } + @Override + public void simplify(SimplifierTool tool) { + ValueNode length = readArrayLength(getValue(), tool.getConstantReflection()); + if (tool.allUsagesAvailable() && length != null) { + /** + * If we are using the array length directly (for example from an allocation) instead of + * this array length node we must ensure we are preserving the previously used + * positiveInt stamp and that the positive int stamp users are not floating above the + * position of this array length (which is dominated by the null check & min array size + * check ensuring len>=0). + * + * So for code like + * + *
+             * int[] arr = new int[length];
+             * aLotOfCode();
+             * use(arr.length);
+             * aLotMoreCode();
+             * userOptimizingBasedOnPositiveIntStamp(arr.length);
+             * 
+ * + * we must preserve the fact that only at the point of the original allocation the + * property that length >= 0 is guaranteed. Thus we replace this with + * + * + *
+             * int[] arr = new int[length];
+             * lengthPiGuardedHere = new Pi(Length >= 0);
+             * aLotOfCode();
+             * use(lengthPiGuardedHere);
+             * aLotMoreCode();
+             * userOptimizingBasedOnPositiveIntStamp(lengthPiGuardedHere);
+             * 
+ */ + StructuredGraph graph = graph(); + BeginNode guard = graph.add(new BeginNode()); + graph.addAfterFixed(this, guard); + ValueNode anchoredLengthNonNegative = graph.addWithoutUnique(new PiNode(length, StampFactory.positiveInt(), guard)); + graph.replaceFixedWithFloating(this, anchoredLengthNonNegative); + } + } + /** * Gets the length of an array if possible. * From 3710ba6f130de28fc6cd14971d4eb8b51a51f4fb Mon Sep 17 00:00:00 2001 From: David Leopoldseder Date: Wed, 6 Dec 2023 11:29:01 +0100 Subject: [PATCH 109/593] array length: preserve length stamp with pi anchored at position of the allocation --- .../graal/compiler/nodes/java/ArrayLengthNode.java | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/nodes/java/ArrayLengthNode.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/nodes/java/ArrayLengthNode.java index 29a75326c1c6..c87bda282c80 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/nodes/java/ArrayLengthNode.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/nodes/java/ArrayLengthNode.java @@ -145,10 +145,16 @@ public void simplify(SimplifierTool tool) { * */ StructuredGraph graph = graph(); - BeginNode guard = graph.add(new BeginNode()); - graph.addAfterFixed(this, guard); - ValueNode anchoredLengthNonNegative = graph.addWithoutUnique(new PiNode(length, StampFactory.positiveInt(), guard)); - graph.replaceFixedWithFloating(this, anchoredLengthNonNegative); + ValueNode replacee = length; + if (!length.isConstant()) { + BeginNode guard = graph.add(new BeginNode()); + graph.addAfterFixed(this, guard); + replacee = graph.addWithoutUnique(new PiNode(length, StampFactory.positiveInt(), guard)); + } + if (!replacee.isAlive()) { + replacee = graph.addOrUnique(replacee); + } + graph.replaceFixedWithFloating(this, replacee); } } From f599efb46b61f10dcf5ea803375b7d4818426f65 Mon Sep 17 00:00:00 2001 From: David Leopoldseder Date: Wed, 6 Dec 2023 12:33:57 +0100 Subject: [PATCH 110/593] float convert: preserve stamp for float convert by pi - avoid expanding all snippet paths --- .../jdk/graal/compiler/core/common/type/Stamp.java | 7 +++++++ .../compiler/replacements/SnippetTemplate.java | 5 ++++- .../replacements/amd64/AMD64ConvertSnippets.java | 14 ++++++++++++-- 3 files changed, 23 insertions(+), 3 deletions(-) diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/core/common/type/Stamp.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/core/common/type/Stamp.java index 0330e870e799..5a2e230fbd62 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/core/common/type/Stamp.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/core/common/type/Stamp.java @@ -218,6 +218,13 @@ public Constant readConstant(MemoryAccessProvider provider, Constant base, long */ public abstract Stamp improveWith(Stamp other); + /** + * @return if this stamp can be improved by the other stamp, i.e., it can be made more precise. + */ + public boolean canBeImprovedWith(Stamp other) { + return !improveWith(other).equals(this); + } + /** * Tries to improve this stamp with the stamp given as parameter. If successful, returns the new * improved stamp. Otherwise, returns null. diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/replacements/SnippetTemplate.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/replacements/SnippetTemplate.java index dfd9a7f88850..610c3f29772d 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/replacements/SnippetTemplate.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/replacements/SnippetTemplate.java @@ -2306,9 +2306,10 @@ public StructuredGraph copySpecializedGraph(DebugContext debugForCopy) { * @param replacer object that replaces the usages of {@code replacee} * @param tool lowering tool used to insert the snippet into the control-flow * @param args the arguments to be bound to the flattened positional parameters of the snippet + * @return the return node of the inlined snippet */ @SuppressWarnings("try") - public void instantiate(MetaAccessProvider metaAccess, FloatingNode replacee, UsageReplacer replacer, LoweringTool tool, Arguments args) { + public ValueNode instantiate(MetaAccessProvider metaAccess, FloatingNode replacee, UsageReplacer replacer, LoweringTool tool, Arguments args) { DebugContext debug = replacee.getDebug(); assert assertSnippetKills(replacee); try (DebugCloseable a = args.info.instantiationTimer.start(debug); @@ -2353,6 +2354,8 @@ public void instantiate(MetaAccessProvider metaAccess, FloatingNode replacee, Us } debug.dump(DebugContext.DETAILED_LEVEL, replaceeGraph, "After lowering %s with %s", replacee, this); + + return returnValue; } } diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/replacements/amd64/AMD64ConvertSnippets.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/replacements/amd64/AMD64ConvertSnippets.java index 3d8d80443740..2184524945e2 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/replacements/amd64/AMD64ConvertSnippets.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/replacements/amd64/AMD64ConvertSnippets.java @@ -30,10 +30,15 @@ import jdk.graal.compiler.api.replacements.Snippet; import jdk.graal.compiler.core.common.calc.FloatConvert; +import jdk.graal.compiler.core.common.type.IntegerStamp; +import jdk.graal.compiler.nodes.AbstractBeginNode; +import jdk.graal.compiler.nodes.FixedNode; import jdk.graal.compiler.nodes.GraphState.StageFlag; +import jdk.graal.compiler.nodes.NodeView; import jdk.graal.compiler.nodes.PiNode; import jdk.graal.compiler.nodes.SnippetAnchorNode; import jdk.graal.compiler.nodes.StructuredGraph; +import jdk.graal.compiler.nodes.ValueNode; import jdk.graal.compiler.nodes.calc.FloatConvertNode; import jdk.graal.compiler.nodes.extended.GuardingNode; import jdk.graal.compiler.nodes.spi.LoweringTool; @@ -196,13 +201,18 @@ public void lower(FloatConvertNode convert, LoweringTool tool) { default: return; } - + IntegerStamp oldRetStamp = (IntegerStamp) convert.stamp(NodeView.DEFAULT); SnippetTemplate.Arguments args = new SnippetTemplate.Arguments(key, graph.getGuardsStage(), tool.getLoweringStage()); args.add("input", convert.getValue()); + FixedNode oldNext = tool.lastFixedNode().next(); SnippetTemplate template = template(tool, convert, args); convert.getDebug().log("Lowering %s in %s: node=%s, template=%s, arguments=%s", convert.getFloatConvert(), graph, convert, template, args); - template.instantiate(tool.getMetaAccess(), convert, SnippetTemplate.DEFAULT_REPLACER, tool, args); + ValueNode replacer = template.instantiate(tool.getMetaAccess(), convert, SnippetTemplate.DEFAULT_REPLACER, tool, args); convert.safeDelete(); + if (replacer.stamp(NodeView.DEFAULT).canBeImprovedWith(oldRetStamp)) { + PiNode pi = graph.addOrUnique(new PiNode(replacer, oldRetStamp, AbstractBeginNode.prevBegin(oldNext))); + replacer.replaceAtMatchingUsages(pi, x -> x != pi); + } } } } From e19a8d7710bc58da04edb0a6cd7e73034e054975 Mon Sep 17 00:00:00 2001 From: David Leopoldseder Date: Wed, 6 Dec 2023 14:49:08 +0100 Subject: [PATCH 111/593] array length: only fold after lowering: if its replaced make sure ni pi gvn stuff gets doubled --- .../compiler/nodes/java/ArrayLengthNode.java | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/nodes/java/ArrayLengthNode.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/nodes/java/ArrayLengthNode.java index c87bda282c80..be6068a6534b 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/nodes/java/ArrayLengthNode.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/nodes/java/ArrayLengthNode.java @@ -43,6 +43,7 @@ import jdk.graal.compiler.nodes.PiNode; import jdk.graal.compiler.nodes.StructuredGraph; import jdk.graal.compiler.nodes.ValueNode; +import jdk.graal.compiler.nodes.GraphState.StageFlag; import jdk.graal.compiler.nodes.graphbuilderconf.GraphBuilderContext; import jdk.graal.compiler.nodes.memory.MemoryAccess; import jdk.graal.compiler.nodes.spi.ArrayLengthProvider; @@ -112,6 +113,19 @@ public ValueNode canonical(CanonicalizerTool tool, ValueNode forValue) { @Override public void simplify(SimplifierTool tool) { + boolean foldBeforeLowering = graph().isAfterStage(StageFlag.HIGH_TIER_LOWERING); + if (!foldBeforeLowering) { + /* + * If we are before lowering we only fold to constants: replacing the load with a length + * guarded pi can be done in multiple places and we only want to do it once for all + * users, so we let it be done after lowering to catch all users at once. + */ + ValueNode len = GraphUtil.arrayLength(getValue(), ArrayLengthProvider.FindLengthMode.SEARCH_ONLY, tool.getConstantReflection()); + foldBeforeLowering = len != null && len.isConstant(); + } + if (!foldBeforeLowering) { + return; + } ValueNode length = readArrayLength(getValue(), tool.getConstantReflection()); if (tool.allUsagesAvailable() && length != null) { /** @@ -146,7 +160,7 @@ public void simplify(SimplifierTool tool) { */ StructuredGraph graph = graph(); ValueNode replacee = length; - if (!length.isConstant()) { + if (!length.isConstant() && length.stamp(NodeView.DEFAULT).canBeImprovedWith(StampFactory.positiveInt())) { BeginNode guard = graph.add(new BeginNode()); graph.addAfterFixed(this, guard); replacee = graph.addWithoutUnique(new PiNode(length, StampFactory.positiveInt(), guard)); From e86d4c16e03dccaadea29675a32a9f6bf54327d1 Mon Sep 17 00:00:00 2001 From: David Leopoldseder Date: Wed, 6 Dec 2023 15:29:12 +0100 Subject: [PATCH 112/593] array length: still fold constant lengths in canon: thats needed for unrolling and loop explosion as it uses canonical and not simplify during unroll to avoid recomputing the cfg --- .../compiler/nodes/java/ArrayLengthNode.java | 21 +++++++++++++++---- 1 file changed, 17 insertions(+), 4 deletions(-) diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/nodes/java/ArrayLengthNode.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/nodes/java/ArrayLengthNode.java index be6068a6534b..fec1772f1d86 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/nodes/java/ArrayLengthNode.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/nodes/java/ArrayLengthNode.java @@ -108,22 +108,35 @@ public ValueNode canonical(CanonicalizerTool tool, ValueNode forValue) { if (forValue.isNullConstant()) { return new DeoptimizeNode(DeoptimizationAction.InvalidateReprofile, DeoptimizationReason.NullCheckException); } + + /** + * Normally we run replacement to any length provider node in simplify but for snippets and + * explode loop we run a limited form to constants before. + */ + boolean foldBasedOnLowering = graph().isAfterStage(StageFlag.HIGH_TIER_LOWERING); + if (!foldBasedOnLowering) { + ValueNode len = GraphUtil.arrayLength(getValue(), ArrayLengthProvider.FindLengthMode.SEARCH_ONLY, tool.getConstantReflection()); + if (len != null && len.isConstant()) { + return len; + } + } + return this; } @Override public void simplify(SimplifierTool tool) { - boolean foldBeforeLowering = graph().isAfterStage(StageFlag.HIGH_TIER_LOWERING); - if (!foldBeforeLowering) { + boolean foldBasedOnLowering = graph().isAfterStage(StageFlag.HIGH_TIER_LOWERING); + if (!foldBasedOnLowering) { /* * If we are before lowering we only fold to constants: replacing the load with a length * guarded pi can be done in multiple places and we only want to do it once for all * users, so we let it be done after lowering to catch all users at once. */ ValueNode len = GraphUtil.arrayLength(getValue(), ArrayLengthProvider.FindLengthMode.SEARCH_ONLY, tool.getConstantReflection()); - foldBeforeLowering = len != null && len.isConstant(); + foldBasedOnLowering = len != null && len.isConstant(); } - if (!foldBeforeLowering) { + if (!foldBasedOnLowering) { return; } ValueNode length = readArrayLength(getValue(), tool.getConstantReflection()); From e4cc411b6698f5627de5d7d3b698172bc69de9ac Mon Sep 17 00:00:00 2001 From: Danilo Ansaloni Date: Wed, 6 Dec 2023 16:39:29 +0100 Subject: [PATCH 113/593] Targets and other base snippets are composed by a function. Removes many small snippets. No changes in the expanded JSON. --- vm/ci/ci_common/common-bench.jsonnet | 54 ++--- vm/ci/ci_common/common.jsonnet | 314 ++++----------------------- vm/ci/ci_common/libgraal.jsonnet | 6 +- vm/ci/ci_includes/vm-native.jsonnet | 22 +- vm/ci/ci_includes/vm.jsonnet | 30 +-- 5 files changed, 98 insertions(+), 328 deletions(-) diff --git a/vm/ci/ci_common/common-bench.jsonnet b/vm/ci/ci_common/common-bench.jsonnet index 77af4aec7921..959ffbe2b30c 100644 --- a/vm/ci/ci_common/common-bench.jsonnet +++ b/vm/ci/ci_common/common-bench.jsonnet @@ -278,39 +278,39 @@ local repo_config = import '../../../ci/repo-configuration.libsonnet'; local builds = [ # We used to expand `${common_vm_linux}` here to work around some limitations in the version of pyhocon that we use in the CI - vm_common.bench_ondemand_vm_linux_amd64 + self.vm_bench_js_linux_amd64('octane') + {name: 'ondemand-bench-vm-' + vm.vm_setup.short_name + '-js-octane-java' + self.jdk_version + '-linux-amd64'}, - vm_common.bench_ondemand_vm_linux_amd64 + self.vm_bench_js_linux_amd64('jetstream') + {name: 'ondemand-bench-vm-' + vm.vm_setup.short_name + '-js-jetstream-java' + self.jdk_version + '-linux-amd64'}, - vm_common.bench_ondemand_vm_linux_amd64 + self.vm_bench_js_linux_amd64('jetstream2') + {name: 'ondemand-bench-vm-' + vm.vm_setup.short_name + '-js-jetstream2-java' + self.jdk_version + '-linux-amd64'}, - vm_common.bench_ondemand_vm_linux_amd64 + self.vm_bench_js_linux_amd64('micro') + {name: 'ondemand-bench-vm-' + vm.vm_setup.short_name + '-js-micro-java' + self.jdk_version + '-linux-amd64'}, - vm_common.bench_ondemand_vm_linux_amd64 + self.vm_bench_js_linux_amd64('v8js') + {name: 'ondemand-bench-vm-' + vm.vm_setup.short_name + '-js-v8js-java' + self.jdk_version + '-linux-amd64'}, - vm_common.bench_ondemand_vm_linux_amd64 + self.vm_bench_js_linux_amd64('misc') + {name: 'ondemand-bench-vm-' + vm.vm_setup.short_name + '-js-misc-java' + self.jdk_version + '-linux-amd64'}, - vm_common.bench_ondemand_vm_linux_amd64 + self.vm_bench_js_linux_amd64('npm-regex') + {name: 'ondemand-bench-vm-' + vm.vm_setup.short_name + '-js-npm-regex-java' + self.jdk_version + '-linux-amd64'}, + vm_common.vm_base('linux', 'amd64', 'ondemand', bench=true) + self.vm_bench_js_linux_amd64('octane') + {name: 'ondemand-bench-vm-' + vm.vm_setup.short_name + '-js-octane-java' + self.jdk_version + '-linux-amd64'}, + vm_common.vm_base('linux', 'amd64', 'ondemand', bench=true) + self.vm_bench_js_linux_amd64('jetstream') + {name: 'ondemand-bench-vm-' + vm.vm_setup.short_name + '-js-jetstream-java' + self.jdk_version + '-linux-amd64'}, + vm_common.vm_base('linux', 'amd64', 'ondemand', bench=true) + self.vm_bench_js_linux_amd64('jetstream2') + {name: 'ondemand-bench-vm-' + vm.vm_setup.short_name + '-js-jetstream2-java' + self.jdk_version + '-linux-amd64'}, + vm_common.vm_base('linux', 'amd64', 'ondemand', bench=true) + self.vm_bench_js_linux_amd64('micro') + {name: 'ondemand-bench-vm-' + vm.vm_setup.short_name + '-js-micro-java' + self.jdk_version + '-linux-amd64'}, + vm_common.vm_base('linux', 'amd64', 'ondemand', bench=true) + self.vm_bench_js_linux_amd64('v8js') + {name: 'ondemand-bench-vm-' + vm.vm_setup.short_name + '-js-v8js-java' + self.jdk_version + '-linux-amd64'}, + vm_common.vm_base('linux', 'amd64', 'ondemand', bench=true) + self.vm_bench_js_linux_amd64('misc') + {name: 'ondemand-bench-vm-' + vm.vm_setup.short_name + '-js-misc-java' + self.jdk_version + '-linux-amd64'}, + vm_common.vm_base('linux', 'amd64', 'ondemand', bench=true) + self.vm_bench_js_linux_amd64('npm-regex') + {name: 'ondemand-bench-vm-' + vm.vm_setup.short_name + '-js-npm-regex-java' + self.jdk_version + '-linux-amd64'}, - vm_common.bench_daily_vm_linux_amd64 + self.vm_bench_polybench_linux_interpreter + {name: 'daily-bench-vm-' + vm.vm_setup.short_name + '-polybench-linux-amd64', notify_groups:: ['polybench']}, - vm_common.bench_daily_vm_linux_amd64 + self.vm_bench_polybench_linux_compiler + {name: 'daily-bench-vm-' + vm.vm_setup.short_name + '-polybench-compiler-linux-amd64', notify_groups:: ['polybench']}, - vm_common.bench_daily_vm_linux_amd64 + self.vm_bench_polybench_linux_context_init + {name: 'daily-bench-vm-' + vm.vm_setup.short_name + '-polybench-context-init-linux-amd64', notify_groups:: ['polybench']}, - vm_common.bench_daily_vm_linux_amd64 + self.vm_bench_polybench_linux_warmup + {name: 'daily-bench-vm-' + vm.vm_setup.short_name + '-polybench-warmup-linux-amd64', notify_groups:: ['polybench']}, - vm_common.bench_daily_vm_linux_amd64 + self.vm_bench_polybench_linux_memory + {name: 'daily-bench-vm-' + vm.vm_setup.short_name + '-polybench-memory-linux-amd64', notify_groups:: ['polybench'] }, + vm_common.vm_base('linux', 'amd64', 'daily', bench=true) + self.vm_bench_polybench_linux_interpreter + {name: 'daily-bench-vm-' + vm.vm_setup.short_name + '-polybench-linux-amd64', notify_groups:: ['polybench']}, + vm_common.vm_base('linux', 'amd64', 'daily', bench=true) + self.vm_bench_polybench_linux_compiler + {name: 'daily-bench-vm-' + vm.vm_setup.short_name + '-polybench-compiler-linux-amd64', notify_groups:: ['polybench']}, + vm_common.vm_base('linux', 'amd64', 'daily', bench=true) + self.vm_bench_polybench_linux_context_init + {name: 'daily-bench-vm-' + vm.vm_setup.short_name + '-polybench-context-init-linux-amd64', notify_groups:: ['polybench']}, + vm_common.vm_base('linux', 'amd64', 'daily', bench=true) + self.vm_bench_polybench_linux_warmup + {name: 'daily-bench-vm-' + vm.vm_setup.short_name + '-polybench-warmup-linux-amd64', notify_groups:: ['polybench']}, + vm_common.vm_base('linux', 'amd64', 'daily', bench=true) + self.vm_bench_polybench_linux_memory + {name: 'daily-bench-vm-' + vm.vm_setup.short_name + '-polybench-memory-linux-amd64', notify_groups:: ['polybench'] }, # Produces the graalvm-with-polybench artifact - vm_common.ondemand_vm_linux_amd64 + self.vm_bench_polybenchmarks_linux_build + {name: 'ondemand-vm-build-' + vm.vm_setup.short_name + '-with-polybench-linux-amd64', notify_groups:: ['polybench']}, + vm_common.vm_base('linux', 'amd64', 'ondemand') + self.vm_bench_polybenchmarks_linux_build + {name: 'ondemand-vm-build-' + vm.vm_setup.short_name + '-with-polybench-linux-amd64', notify_groups:: ['polybench']}, # Consume the graalvm-with-polybench artifact - vm_common.bench_daily_vm_linux_amd64 + self.vm_bench_polybenchmarks_linux_common(vm_config='native') + {name: 'daily-bench-vm-' + vm.vm_setup.short_name + '-polybenchmarks-default-native-linux-amd64', notify_groups:: ['polybench']}, - vm_common.bench_daily_vm_linux_amd64 + self.vm_bench_polybenchmarks_linux_common(vm_config='jvm') + {name: 'daily-bench-vm-' + vm.vm_setup.short_name + '-polybenchmarks-default-jvm-linux-amd64', notify_groups:: ['polybench']}, - vm_common.bench_daily_vm_linux_amd64 + self.vm_bench_polybenchmarks_linux_common(vm_config='native', suite='awfy:r[.*py]') + {name: 'daily-bench-vm-' + vm.vm_setup.short_name + '-polybenchmarks-awfy-py-native-linux-amd64', notify_groups:: ['polybench']}, - vm_common.bench_daily_vm_linux_amd64 + self.vm_bench_polybenchmarks_linux_common(vm_config='jvm', suite='awfy:r[.*py]') + {name: 'daily-bench-vm-' + vm.vm_setup.short_name + '-polybenchmarks-awfy-py-jvm-linux-amd64', notify_groups:: ['polybench']}, - vm_common.bench_daily_vm_linux_amd64 + self.vm_bench_polybenchmarks_linux_common(vm_config='native', suite='awfy:r[.*rb]') + {name: 'daily-bench-vm-' + vm.vm_setup.short_name + '-polybenchmarks-awfy-rb-native-linux-amd64', notify_groups:: ['polybench']}, - vm_common.bench_daily_vm_linux_amd64 + self.vm_bench_polybenchmarks_linux_common(vm_config='jvm', suite='awfy:r[.*rb]') + {name: 'daily-bench-vm-' + vm.vm_setup.short_name + '-polybenchmarks-awfy-rb-jvm-linux-amd64', notify_groups:: ['polybench']}, - vm_common.bench_daily_vm_linux_amd64 + self.vm_bench_polybenchmarks_linux_common(vm_config='native', suite='awfy:r[.*jar]') + {name: 'daily-bench-vm-' + vm.vm_setup.short_name + '-polybenchmarks-awfy-jar-native-linux-amd64', notify_groups:: ['polybench']}, - vm_common.bench_daily_vm_linux_amd64 + self.vm_bench_polybenchmarks_linux_common(vm_config='jvm', suite='awfy:r[.*jar]') + {name: 'daily-bench-vm-' + vm.vm_setup.short_name + '-polybenchmarks-awfy-jar-jvm-linux-amd64', notify_groups:: ['polybench']}, + vm_common.vm_base('linux', 'amd64', 'daily', bench=true) + self.vm_bench_polybenchmarks_linux_common(vm_config='native') + {name: 'daily-bench-vm-' + vm.vm_setup.short_name + '-polybenchmarks-default-native-linux-amd64', notify_groups:: ['polybench']}, + vm_common.vm_base('linux', 'amd64', 'daily', bench=true) + self.vm_bench_polybenchmarks_linux_common(vm_config='jvm') + {name: 'daily-bench-vm-' + vm.vm_setup.short_name + '-polybenchmarks-default-jvm-linux-amd64', notify_groups:: ['polybench']}, + vm_common.vm_base('linux', 'amd64', 'daily', bench=true) + self.vm_bench_polybenchmarks_linux_common(vm_config='native', suite='awfy:r[.*py]') + {name: 'daily-bench-vm-' + vm.vm_setup.short_name + '-polybenchmarks-awfy-py-native-linux-amd64', notify_groups:: ['polybench']}, + vm_common.vm_base('linux', 'amd64', 'daily', bench=true) + self.vm_bench_polybenchmarks_linux_common(vm_config='jvm', suite='awfy:r[.*py]') + {name: 'daily-bench-vm-' + vm.vm_setup.short_name + '-polybenchmarks-awfy-py-jvm-linux-amd64', notify_groups:: ['polybench']}, + vm_common.vm_base('linux', 'amd64', 'daily', bench=true) + self.vm_bench_polybenchmarks_linux_common(vm_config='native', suite='awfy:r[.*rb]') + {name: 'daily-bench-vm-' + vm.vm_setup.short_name + '-polybenchmarks-awfy-rb-native-linux-amd64', notify_groups:: ['polybench']}, + vm_common.vm_base('linux', 'amd64', 'daily', bench=true) + self.vm_bench_polybenchmarks_linux_common(vm_config='jvm', suite='awfy:r[.*rb]') + {name: 'daily-bench-vm-' + vm.vm_setup.short_name + '-polybenchmarks-awfy-rb-jvm-linux-amd64', notify_groups:: ['polybench']}, + vm_common.vm_base('linux', 'amd64', 'daily', bench=true) + self.vm_bench_polybenchmarks_linux_common(vm_config='native', suite='awfy:r[.*jar]') + {name: 'daily-bench-vm-' + vm.vm_setup.short_name + '-polybenchmarks-awfy-jar-native-linux-amd64', notify_groups:: ['polybench']}, + vm_common.vm_base('linux', 'amd64', 'daily', bench=true) + self.vm_bench_polybenchmarks_linux_common(vm_config='jvm', suite='awfy:r[.*jar]') + {name: 'daily-bench-vm-' + vm.vm_setup.short_name + '-polybenchmarks-awfy-jar-jvm-linux-amd64', notify_groups:: ['polybench']}, - vm_common.bench_daily_vm_linux_amd64 + self.vm_bench_polybench_nfi_linux_amd64 + vm.vm_java_21 + {name: 'daily-bench-vm-' + vm.vm_setup.short_name + '-polybench-nfi-java21-linux-amd64', notify_groups:: ['polybench']}, + vm_common.vm_base('linux', 'amd64', 'daily', bench=true) + self.vm_bench_polybench_nfi_linux_amd64 + vm.vm_java_21 + {name: 'daily-bench-vm-' + vm.vm_setup.short_name + '-polybench-nfi-java21-linux-amd64', notify_groups:: ['polybench']}, - vm_common.bench_daily_vm_linux_amd64 + self.x52_js_bench_compilation_throughput(true) + vm.vm_java_21 + { name: 'daily-bench-vm-' + vm.vm_setup.short_name + '-libgraal-pgo-throughput-js-typescript-java' + self.jdk_version + '-linux-amd64' }, - vm_common.bench_daily_vm_linux_amd64 + self.x52_js_bench_compilation_throughput(false) + vm.vm_java_21 + { name: 'daily-bench-vm-' + vm.vm_setup.short_name + '-libgraal-no-pgo-throughput-js-typescript-java' + self.jdk_version + '-linux-amd64' }, + vm_common.vm_base('linux', 'amd64', 'daily', bench=true) + self.x52_js_bench_compilation_throughput(true) + vm.vm_java_21 + { name: 'daily-bench-vm-' + vm.vm_setup.short_name + '-libgraal-pgo-throughput-js-typescript-java' + self.jdk_version + '-linux-amd64' }, + vm_common.vm_base('linux', 'amd64', 'daily', bench=true) + self.x52_js_bench_compilation_throughput(false) + vm.vm_java_21 + { name: 'daily-bench-vm-' + vm.vm_setup.short_name + '-libgraal-no-pgo-throughput-js-typescript-java' + self.jdk_version + '-linux-amd64' }, - vm_common.bench_daily_vm_linux_amd64 + self.vm_bench_js_linux_amd64() + { + vm_common.vm_base('linux', 'amd64', 'daily', bench=true) + self.vm_bench_js_linux_amd64() + { # Override `self.vm_bench_js_linux_amd64.run` run: [ vm_common.mx_vm_common + ['benchmark', '--results-file', self.result_file, 'agentscript-graal-js:*', '--', '--jvm=graalvm-${VM_ENV}', '--jvm-config=jvm', '--js=graal-js', '--js-config=default'], @@ -323,8 +323,8 @@ local repo_config = import '../../../ci/repo-configuration.libsonnet'; notify_groups:: ['javascript'], }, - vm_common.gate_vm_linux_amd64 + self.vm_bench_polybenchmarks_linux_common(is_gate=true) + {name: 'gate-vm-' + vm.vm_setup.short_name + '-polybenchmarks-linux-amd64'}, - vm_common.gate_vm_linux_amd64 + self.vm_gate_polybench_linux + {name: 'gate-vm-' + vm.vm_setup.short_name + '-polybench-linux-amd64'}, + vm_common.vm_base('linux', 'amd64', 'gate') + self.vm_bench_polybenchmarks_linux_common(is_gate=true) + {name: 'gate-vm-' + vm.vm_setup.short_name + '-polybenchmarks-linux-amd64'}, + vm_common.vm_base('linux', 'amd64', 'gate') + self.vm_gate_polybench_linux + {name: 'gate-vm-' + vm.vm_setup.short_name + '-polybench-linux-amd64'}, ], builds: utils.add_defined_in(builds, std.thisFile), diff --git a/vm/ci/ci_common/common.jsonnet b/vm/ci/ci_common/common.jsonnet index f7a505c0ceb5..dcc182146560 100644 --- a/vm/ci/ci_common/common.jsonnet +++ b/vm/ci/ci_common/common.jsonnet @@ -160,12 +160,15 @@ local devkits = graal_common.devkits; vm_linux_amd64: graal_common.linux_amd64 + self.common_vm_linux + self.vm_linux_amd64_common, vm_linux_amd64_ol9: graal_common.linux_amd64_ol9 + self.common_vm_linux + self.vm_linux_amd64_common, + vm_ol9_amd64: self.vm_linux_amd64_ol9, vm_linux_amd64_ubuntu: graal_common.linux_amd64_ubuntu + self.common_vm + self.vm_linux_amd64_common, + vm_ununtu_amd64: self.vm_linux_amd64_ubuntu, vm_linux_aarch64: self.common_vm_linux + graal_common.linux_aarch64, vm_linux_aarch64_ol9: self.common_vm_linux + graal_common.linux_aarch64_ol9, + vm_ol9_aarch64: self.vm_linux_aarch64_ol9, vm_darwin_amd64: self.common_vm_darwin + graal_common.darwin_amd64 + { capabilities+: ['darwin_bigsur', 'ram16gb'], @@ -190,249 +193,16 @@ local devkits = graal_common.devkits; vm_windows_jdk17: self.common_vm_windows_jdk17 + graal_common.windows_server_2016_amd64, vm_windows_jdk21: self.common_vm_windows_jdk21 + graal_common.windows_server_2016_amd64, vm_windows_jdkLatest: self.common_vm_windows_jdkLatest + graal_common.windows_server_2016_amd64, + vm_windows_amd64: self.vm_windows, + vm_windows_amd64_jdk17: self.vm_windows_jdk17, + vm_windows_amd64_jdk21: self.vm_windows_jdk21, + vm_windows_amd64_jdkLatest: self.vm_windows_jdkLatest, - gate_vm_linux_amd64: vm.default_diskspace_required('linux', 'amd64', large=false) + self.vm_linux_amd64 + { - targets+: ['gate'] - }, - - gate_vm_linux_amd64_ubuntu: vm.default_diskspace_required('linux', 'amd64', large=false) + self.vm_linux_amd64_ubuntu + { - targets+: ['gate'] - }, - - gate_vm_linux_aarch64: vm.default_diskspace_required('linux', 'aarch64', large=false) + self.vm_linux_aarch64 + { - targets+: ['gate'], - }, - - gate_vm_darwin_amd64: vm.default_diskspace_required('darwin', 'amd64', large=false) + self.vm_darwin_amd64 + { - targets+: ['gate'], - }, - - gate_vm_darwin_aarch64: vm.default_diskspace_required('darwin', 'aarch64', large=false) + self.vm_darwin_aarch64 + { - targets+: ['gate'], - }, - - gate_vm_windows_amd64: vm.default_diskspace_required('windows', 'amd64', large=false) + self.vm_windows + { - targets+: ['gate'], - }, - - daily_vm_linux_amd64_ol9: vm.default_diskspace_required('linux', 'amd64', large=false) + self.vm_linux_amd64_ol9 + { - targets+: ['daily'] - }, - - daily_vm_linux_aarch64_ol9: vm.default_diskspace_required('linux', 'aarch64', large=false) + self.vm_linux_aarch64_ol9 + { - targets+: ['daily'] - }, - - daily_vm_linux_amd64_ubuntu: vm.default_diskspace_required('linux', 'amd64', large=false) + self.vm_linux_amd64_ubuntu + { - targets+: ['daily'] - }, - - bench_daily_vm_linux_amd64: vm.default_diskspace_required('linux', 'amd64', large=false) + self.vm_linux_amd64 + { - capabilities+: ['no_frequency_scaling'], - targets+: ['daily', 'bench'], - }, - - bench_daily_vm_darwin_amd64: vm.default_diskspace_required('darwin', 'amd64', large=false) + self.vm_darwin_amd64 + { - capabilities+: ['no_frequency_scaling'], - targets+: ['daily', 'bench'], - }, - - bench_ondemand_vm_linux_amd64: vm.default_diskspace_required('linux', 'amd64', large=false) + self.vm_linux_amd64 + { - capabilities+: ['no_frequency_scaling'], - targets+: ['ondemand', 'bench'], - }, - - deploy_vm_linux_amd64: vm.default_diskspace_required('linux', 'amd64', large=true) + self.vm_linux_amd64 + { - targets+: ['post-merge', 'deploy'], - }, - - deploy_vm_linux_aarch64: vm.default_diskspace_required('linux', 'aarch64', large=true) + self.vm_linux_aarch64 + { - targets+: ['post-merge', 'deploy'], - }, - - deploy_vm_darwin_amd64: vm.default_diskspace_required('darwin', 'amd64', large=true) + self.vm_darwin_amd64 + { - targets+: ['post-merge', 'deploy'], - }, - - deploy_vm_darwin_aarch64: vm.default_diskspace_required('darwin', 'aarch64', large=true) + self.vm_darwin_aarch64 + { - targets+: ['post-merge', 'deploy'], - }, - - deploy_vm_windows: vm.default_diskspace_required('windows', 'amd64', large=true) + self.vm_windows + { - targets+: ['post-merge', 'deploy'], - }, - - deploy_vm_windows_jdk17: vm.default_diskspace_required('windows', 'amd64', large=true) + self.vm_windows_jdk17 + { - targets+: ['post-merge', 'deploy'], - }, - - deploy_vm_windows_jdk21: vm.default_diskspace_required('windows', 'amd64', large=true) + self.vm_windows_jdk21 + { - targets+: ['post-merge', 'deploy'], - }, - - deploy_daily_vm_linux_amd64: vm.default_diskspace_required('linux', 'amd64', large=true) + self.vm_linux_amd64 + { - targets+: ['daily', 'deploy'], - }, - - deploy_daily_vm_linux_aarch64: vm.default_diskspace_required('linux', 'aarch64', large=true) + self.vm_linux_aarch64 + { - targets+: ['daily', 'deploy'], - }, - - deploy_daily_vm_darwin_amd64: vm.default_diskspace_required('darwin', 'amd64', large=true) + self.vm_darwin_amd64 + { - targets+: ['daily', 'deploy'], - }, - - deploy_daily_vm_darwin_aarch64: vm.default_diskspace_required('darwin', 'aarch64', large=true) + self.vm_darwin_aarch64 + { - targets+: ['daily', 'deploy'], - }, - - deploy_daily_vm_windows: vm.default_diskspace_required('windows', 'amd64', large=true) + self.vm_windows + { - targets+: ['daily', 'deploy'], - }, - - deploy_daily_vm_windows_jdk17: vm.default_diskspace_required('windows', 'amd64', large=true) + self.vm_windows_jdk17 + { - targets+: ['daily', 'deploy'], - }, - - deploy_daily_vm_windows_jdk21: vm.default_diskspace_required('windows', 'amd64', large=true) + self.vm_windows_jdk21 + { - targets+: ['daily', 'deploy'], - }, - - deploy_daily_vm_windows_jdkLatest: vm.default_diskspace_required('windows', 'amd64', large=true) + self.vm_windows_jdkLatest + { - targets+: ['daily', 'deploy'], - }, - - deploy_weekly_vm_linux_amd64: vm.default_diskspace_required('linux', 'amd64', large=true) + self.vm_linux_amd64 + { - targets+: ['weekly', 'deploy'], - }, - - deploy_weekly_vm_linux_aarch64: vm.default_diskspace_required('linux', 'aarch64', large=true) + self.vm_linux_aarch64 + { - targets+: ['weekly', 'deploy'], - }, - - deploy_weekly_vm_darwin_amd64: vm.default_diskspace_required('darwin', 'amd64', large=true) + self.vm_darwin_amd64 + { - targets+: ['weekly', 'deploy'], - }, - - deploy_weekly_vm_darwin_aarch64: vm.default_diskspace_required('darwin', 'aarch64', large=true) + self.vm_darwin_aarch64 + { - targets+: ['weekly', 'deploy'], - }, - - deploy_weekly_vm_windows: vm.default_diskspace_required('windows', 'amd64', large=true) + self.vm_windows + { - targets+: ['weekly', 'deploy'], - }, - - deploy_weekly_vm_windows_jdk17: vm.default_diskspace_required('windows', 'amd64', large=true) + self.vm_windows_jdk17 + { - targets+: ['weekly', 'deploy'], - }, - - deploy_weekly_vm_windows_jdk21: vm.default_diskspace_required('windows', 'amd64', large=true) + self.vm_windows_jdk21 + { - targets+: ['weekly', 'deploy'], - }, - - postmerge_vm_linux_amd64: vm.default_diskspace_required('linux', 'amd64', large=false) + self.vm_linux_amd64 + { - targets+: ['post-merge'], - }, - - daily_vm_linux_amd64: vm.default_diskspace_required('linux', 'amd64', large=false) + self.vm_linux_amd64 + { - targets+: ['daily'], - }, - - daily_vm_linux_aarch64: vm.default_diskspace_required('linux', 'aarch64', large=false) + self.vm_linux_aarch64 + { - targets+: ['daily'], - }, - - daily_vm_darwin_amd64: vm.default_diskspace_required('darwin', 'amd64', large=false) + self.vm_darwin_amd64 + { - targets+: ['daily'], - }, - - daily_vm_darwin_aarch64: vm.default_diskspace_required('darwin', 'aarch64', large=false) + self.vm_darwin_aarch64 + { - targets+: ['daily'], - }, - - daily_vm_windows: vm.default_diskspace_required('windows', 'amd64', large=false) + self.vm_windows + { - targets+: ['daily'], - }, - - daily_vm_windows_amd64: vm.default_diskspace_required('windows', 'amd64', large=false) + self.vm_windows + { - targets+: ['daily'], - }, - - daily_vm_windows_jdk17: vm.default_diskspace_required('windows', 'amd64', large=false) + self.vm_windows_jdk17 + { - targets+: ['daily'], - }, - - daily_vm_windows_jdk21: vm.default_diskspace_required('windows', 'amd64', large=false) + self.vm_windows_jdk21 + { - targets+: ['daily'], - }, - - weekly_vm_linux_amd64: vm.default_diskspace_required('linux', 'amd64', large=false) + self.vm_linux_amd64 + { - targets+: ['weekly'], - }, - - weekly_vm_linux_aarch64: vm.default_diskspace_required('linux', 'aarch64', large=false) + self.vm_linux_aarch64 + { - targets+: ['weekly'], - }, - - weekly_vm_darwin_amd64: vm.default_diskspace_required('darwin', 'amd64', large=false) + self.vm_darwin_amd64 + { - targets+: ['weekly'], - }, - - weekly_vm_darwin_aarch64: vm.default_diskspace_required('darwin', 'aarch64', large=false) + self.vm_darwin_aarch64+ { - targets+: ['weekly'], - }, - - weekly_vm_windows: vm.default_diskspace_required('windows', 'amd64', large=false) + self.vm_windows + { - targets+: ['weekly'], - }, - - weekly_vm_windows_amd64: vm.default_diskspace_required('windows', 'amd64', large=false) + self.vm_windows + { - targets+: ['weekly'], - }, - - weekly_vm_windows_jdk17: vm.default_diskspace_required('windows', 'amd64', large=false) + self.vm_windows_jdk17 + { - targets+: ['weekly'], - }, - - weekly_vm_windows_jdk21: vm.default_diskspace_required('windows', 'amd64', large=false) + self.vm_windows_jdk21 + { - targets+: ['weekly'], - }, - - ondemand_vm_linux_amd64: vm.default_diskspace_required('linux', 'amd64', large=false) + self.vm_linux_amd64 + { - targets+: ['ondemand'], - }, - - ondemand_vm_darwin_amd64: vm.default_diskspace_required('darwin', 'amd64', large=false) + self.vm_darwin_amd64 + { - targets+: ['ondemand'], - }, - - ondemand_vm_darwin_aarch64: vm.default_diskspace_required('darwin', 'aarch64', large=false) + self.vm_darwin_aarch64+ { - targets+: ['ondemand'], - }, - - ondemand_deploy_vm_linux_amd64: vm.default_diskspace_required('linux', 'amd64', large=true) + self.vm_linux_amd64 + { - targets+: ['ondemand', 'deploy'], - }, - - ondemand_deploy_vm_linux_aarch64: vm.default_diskspace_required('linux', 'aarch64', large=true) + self.vm_linux_aarch64 + { - targets+: ['ondemand', 'deploy'], - }, - - ondemand_deploy_vm_darwin_amd64: vm.default_diskspace_required('darwin', 'amd64', large=true) + self.vm_darwin_amd64 + { - targets+: ['ondemand', 'deploy'], - }, - - ondemand_deploy_vm_darwin_aarch64: vm.default_diskspace_required('darwin', 'aarch64', large=true) + self.vm_darwin_aarch64 + { - targets+: ['ondemand', 'deploy'], - }, - - ondemand_deploy_vm_windows_jdk17: vm.default_diskspace_required('windows', 'amd64', large=true) + self.vm_windows_jdk17 + { - targets+: ['ondemand', 'deploy'], - }, - - ondemand_deploy_vm_windows_jdk21: vm.default_diskspace_required('windows', 'amd64', large=true) + self.vm_windows_jdk21 + { - targets+: ['ondemand', 'deploy'], - }, + vm_base(os, arch, main_target, deploy=false, bench=false, os_distro=null, jdk_hint=null): + vm.default_diskspace_required(os, arch, large=deploy) + + self['vm_' + os + '_' + arch + (if (os_distro != null) then '_' + os_distro else '') + (if (jdk_hint != null) then '_jdk' + jdk_hint else '')] # examples: `self.vm_linux_amd64_ubuntu`, `self.vm_windows_amd_jdkLatest` + + { targets+: [main_target] + (if (deploy) then ['deploy'] else []) + (if (bench) then ['bench'] else []) } + + (if (bench) then { capabilities+: ['no_frequency_scaling'] } else {}), mx_vm_cmd_suffix: ['--sources=sdk:GRAAL_SDK,truffle:TRUFFLE_API,compiler:GRAAL,substratevm:SVM', '--debuginfo-dists', '--base-jdk-info=${BASE_JDK_NAME}:${BASE_JDK_VERSION}'], mx_vm_common: vm.mx_cmd_base_no_env + ['--env', '${VM_ENV}'] + self.mx_vm_cmd_suffix, @@ -862,58 +632,58 @@ local devkits = graal_common.devkits; # Linux/AMD64 # - JDK-Latest - deploy_vm_base_javaLatest_linux_amd64: vm.vm_java_Latest + self.full_vm_build_linux_amd64 + self.linux_deploy + self.deploy_vm_linux_amd64 + self.deploy_graalvm_base('latest') + {name: 'post-merge-deploy-vm-base-java-latest-linux-amd64', notify_groups:: ["deploy"]}, - deploy_vm_installables_standalones_javaLatest_linux_amd64: vm.vm_java_Latest + self.full_vm_build_linux_amd64 + self.linux_deploy + self.deploy_daily_vm_linux_amd64 + self.deploy_graalvm_components('latest', installables=false, standalones=true, record_file_sizes=true) + {name: 'daily-deploy-vm-installables-standalones-java-latest-linux-amd64', notify_groups:: ["deploy"]}, + deploy_vm_base_javaLatest_linux_amd64: vm.vm_java_Latest + self.full_vm_build_linux_amd64 + self.linux_deploy + self.vm_base('linux', 'amd64', 'post-merge', deploy=true) + self.deploy_graalvm_base('latest') + {name: 'post-merge-deploy-vm-base-java-latest-linux-amd64', notify_groups:: ["deploy"]}, + deploy_vm_installables_standalones_javaLatest_linux_amd64: vm.vm_java_Latest + self.full_vm_build_linux_amd64 + self.linux_deploy + self.vm_base('linux', 'amd64', 'daily', deploy=true) + self.deploy_graalvm_components('latest', installables=false, standalones=true, record_file_sizes=true) + {name: 'daily-deploy-vm-installables-standalones-java-latest-linux-amd64', notify_groups:: ["deploy"]}, # - JDK21 - deploy_vm_base_java21_linux_amd64: vm.vm_java_21 + self.full_vm_build_linux_amd64 + self.linux_deploy + self.deploy_vm_linux_amd64 + self.deploy_graalvm_base("java21") + {name: 'post-merge-deploy-vm-base-java21-linux-amd64', notify_groups:: ["deploy"]}, - deploy_vm_installables_standalones_java21_linux_amd64: vm.vm_java_21_llvm + self.full_vm_build_linux_amd64 + self.linux_deploy + self.deploy_daily_vm_linux_amd64 + self.deploy_graalvm_components("java21", installables=true, standalones=true, record_file_sizes=true) + {name: 'daily-deploy-vm-installables-standalones-java21-linux-amd64', notify_groups:: ["deploy"]}, + deploy_vm_base_java21_linux_amd64: vm.vm_java_21 + self.full_vm_build_linux_amd64 + self.linux_deploy + self.vm_base('linux', 'amd64', 'post-merge', deploy=true) + self.deploy_graalvm_base("java21") + {name: 'post-merge-deploy-vm-base-java21-linux-amd64', notify_groups:: ["deploy"]}, + deploy_vm_installables_standalones_java21_linux_amd64: vm.vm_java_21_llvm + self.full_vm_build_linux_amd64 + self.linux_deploy + self.vm_base('linux', 'amd64', 'daily', deploy=true) + self.deploy_graalvm_components("java21", installables=true, standalones=true, record_file_sizes=true) + {name: 'daily-deploy-vm-installables-standalones-java21-linux-amd64', notify_groups:: ["deploy"]}, # Linux/AARCH64 # - JDK-Latest - deploy_vm_base_javaLatest_linux_aarch64: vm.vm_java_Latest + self.full_vm_build_linux_aarch64 + self.linux_deploy + self.deploy_daily_vm_linux_aarch64 + self.deploy_graalvm_base('latest') + {name: 'daily-deploy-vm-base-java-latest-linux-aarch64', notify_groups:: ["deploy"], timelimit: '1:30:00', capabilities+: ["!xgene3"]}, - deploy_vm_installables_standalones_javaLatest_linux_aarch64: vm.vm_java_Latest + self.full_vm_build_linux_aarch64 + self.linux_deploy + self.deploy_daily_vm_linux_aarch64 + self.deploy_graalvm_components('latest', installables=false, standalones=true) + {name: 'daily-deploy-vm-installables-standalones-java-latest-linux-aarch64', notify_groups:: ["deploy"], capabilities+: ["!xgene3"]}, + deploy_vm_base_javaLatest_linux_aarch64: vm.vm_java_Latest + self.full_vm_build_linux_aarch64 + self.linux_deploy + self.vm_base('linux', 'aarch64', 'daily', deploy=true) + self.deploy_graalvm_base('latest') + {name: 'daily-deploy-vm-base-java-latest-linux-aarch64', notify_groups:: ["deploy"], timelimit: '1:30:00', capabilities+: ["!xgene3"]}, + deploy_vm_installables_standalones_javaLatest_linux_aarch64: vm.vm_java_Latest + self.full_vm_build_linux_aarch64 + self.linux_deploy + self.vm_base('linux', 'aarch64', 'daily', deploy=true) + self.deploy_graalvm_components('latest', installables=false, standalones=true) + {name: 'daily-deploy-vm-installables-standalones-java-latest-linux-aarch64', notify_groups:: ["deploy"], capabilities+: ["!xgene3"]}, # - JDK21 - deploy_vm_base_java21_linux_aarch64: vm.vm_java_21 + self.full_vm_build_linux_aarch64 + self.linux_deploy + self.deploy_daily_vm_linux_aarch64 + self.deploy_graalvm_base("java21") + {name: 'daily-deploy-vm-base-java21-linux-aarch64', notify_groups:: ["deploy"], timelimit: '1:30:00', capabilities+: ["!xgene3"]}, - deploy_vm_installables_standalones_java21_linux_aarch64: vm.vm_java_21 + self.full_vm_build_linux_aarch64 + self.linux_deploy + self.deploy_daily_vm_linux_aarch64 + self.deploy_graalvm_components("java21", installables=true, standalones=true) + {name: 'daily-deploy-vm-installables-standalones-java21-linux-aarch64', notify_groups:: ["deploy"], capabilities+: ["!xgene3"]}, + deploy_vm_base_java21_linux_aarch64: vm.vm_java_21 + self.full_vm_build_linux_aarch64 + self.linux_deploy + self.vm_base('linux', 'aarch64', 'daily', deploy=true) + self.deploy_graalvm_base("java21") + {name: 'daily-deploy-vm-base-java21-linux-aarch64', notify_groups:: ["deploy"], timelimit: '1:30:00', capabilities+: ["!xgene3"]}, + deploy_vm_installables_standalones_java21_linux_aarch64: vm.vm_java_21 + self.full_vm_build_linux_aarch64 + self.linux_deploy + self.vm_base('linux', 'aarch64', 'daily', deploy=true) + self.deploy_graalvm_components("java21", installables=true, standalones=true) + {name: 'daily-deploy-vm-installables-standalones-java21-linux-aarch64', notify_groups:: ["deploy"], capabilities+: ["!xgene3"]}, # Darwin/AMD64 # - JDK-Latest - deploy_vm_base_javaLatest_darwin_amd64: vm.vm_java_Latest + self.full_vm_build_darwin_amd64 + self.darwin_deploy + self.deploy_daily_vm_darwin_amd64 + self.deploy_graalvm_base('latest') + {name: 'daily-deploy-vm-base-java-latest-darwin-amd64', notify_groups:: ["deploy"], timelimit: '1:45:00'}, - deploy_vm_standalones_javaLatest_darwin_amd64: vm.vm_java_Latest + self.full_vm_build_darwin_amd64 + self.darwin_deploy + self.deploy_daily_vm_darwin_amd64 + self.deploy_graalvm_components('latest', installables=false, standalones=true) + {name: 'daily-deploy-vm-standalones-java-latest-darwin-amd64', capabilities+: ["!macmini_late_2014"], diskspace_required: "31GB", notify_groups:: ["deploy"], timelimit: '3:00:00'}, + deploy_vm_base_javaLatest_darwin_amd64: vm.vm_java_Latest + self.full_vm_build_darwin_amd64 + self.darwin_deploy + self.vm_base('darwin', 'amd64', 'daily', deploy=true) + self.deploy_graalvm_base('latest') + {name: 'daily-deploy-vm-base-java-latest-darwin-amd64', notify_groups:: ["deploy"], timelimit: '1:45:00'}, + deploy_vm_standalones_javaLatest_darwin_amd64: vm.vm_java_Latest + self.full_vm_build_darwin_amd64 + self.darwin_deploy + self.vm_base('darwin', 'amd64', 'daily', deploy=true) + self.deploy_graalvm_components('latest', installables=false, standalones=true) + {name: 'daily-deploy-vm-standalones-java-latest-darwin-amd64', capabilities+: ["!macmini_late_2014"], diskspace_required: "31GB", notify_groups:: ["deploy"], timelimit: '3:00:00'}, # - JDK21 - deploy_vm_base_java21_darwin_amd64: vm.vm_java_21 + self.full_vm_build_darwin_amd64 + self.darwin_deploy + self.deploy_daily_vm_darwin_amd64 + self.deploy_graalvm_base("java21") + {name: 'daily-deploy-vm-base-java21-darwin-amd64', notify_groups:: ["deploy"], timelimit: '1:45:00'}, - deploy_vm_installables_java21_darwin_amd64: vm.vm_java_21_llvm + self.full_vm_build_darwin_amd64 + self.darwin_deploy + self.deploy_weekly_vm_darwin_amd64 + self.deploy_graalvm_components("java21", installables=true, standalones=false) + {name: 'weekly-deploy-vm-installables-java21-darwin-amd64', capabilities+: ["!macmini_late_2014"], diskspace_required: "31GB", notify_groups:: ["deploy"], timelimit: '3:00:00'}, - deploy_vm_standalones_java21_darwin_amd64: vm.vm_java_21_llvm + self.full_vm_build_darwin_amd64 + self.darwin_deploy + self.deploy_daily_vm_darwin_amd64 + self.deploy_graalvm_components("java21", installables=false, standalones=true) + {name: 'daily-deploy-vm-standalones-java21-darwin-amd64', capabilities+: ["!macmini_late_2014"], diskspace_required: "31GB", notify_groups:: ["deploy"], timelimit: '3:00:00'}, + deploy_vm_base_java21_darwin_amd64: vm.vm_java_21 + self.full_vm_build_darwin_amd64 + self.darwin_deploy + self.vm_base('darwin', 'amd64', 'daily', deploy=true) + self.deploy_graalvm_base("java21") + {name: 'daily-deploy-vm-base-java21-darwin-amd64', notify_groups:: ["deploy"], timelimit: '1:45:00'}, + deploy_vm_installables_java21_darwin_amd64: vm.vm_java_21_llvm + self.full_vm_build_darwin_amd64 + self.darwin_deploy + self.vm_base('darwin', 'amd64', 'weekly', deploy=true) + self.deploy_graalvm_components("java21", installables=true, standalones=false) + {name: 'weekly-deploy-vm-installables-java21-darwin-amd64', capabilities+: ["!macmini_late_2014"], diskspace_required: "31GB", notify_groups:: ["deploy"], timelimit: '3:00:00'}, + deploy_vm_standalones_java21_darwin_amd64: vm.vm_java_21_llvm + self.full_vm_build_darwin_amd64 + self.darwin_deploy + self.vm_base('darwin', 'amd64', 'daily', deploy=true) + self.deploy_graalvm_components("java21", installables=false, standalones=true) + {name: 'daily-deploy-vm-standalones-java21-darwin-amd64', capabilities+: ["!macmini_late_2014"], diskspace_required: "31GB", notify_groups:: ["deploy"], timelimit: '3:00:00'}, # Darwin/AARCH64 # - JDK-Latest - deploy_vm_base_javaLatest_darwin_aarch64: vm.vm_java_Latest + self.full_vm_build_darwin_aarch64 + self.darwin_deploy + self.deploy_daily_vm_darwin_aarch64 + self.deploy_graalvm_base('latest') + {name: 'daily-deploy-vm-base-java-latest-darwin-aarch64', notify_groups:: ["deploy"], notify_emails+: ["bernhard.urban-forster@oracle.com"], timelimit: '1:45:00'}, - deploy_vm_standalones_javaLatest_darwin_aarch64: vm.vm_java_Latest + self.full_vm_build_darwin_aarch64 + self.darwin_deploy + self.deploy_daily_vm_darwin_aarch64 + self.deploy_graalvm_components('latest', installables=false, standalones=true) + {name: 'daily-deploy-vm-standalones-java-latest-darwin-aarch64', diskspace_required: "31GB", notify_groups:: ["deploy"], notify_emails+: ["bernhard.urban-forster@oracle.com"], timelimit: '3:00:00'}, + deploy_vm_base_javaLatest_darwin_aarch64: vm.vm_java_Latest + self.full_vm_build_darwin_aarch64 + self.darwin_deploy + self.vm_base('darwin', 'aarch64', 'daily', deploy=true) + self.deploy_graalvm_base('latest') + {name: 'daily-deploy-vm-base-java-latest-darwin-aarch64', notify_groups:: ["deploy"], notify_emails+: ["bernhard.urban-forster@oracle.com"], timelimit: '1:45:00'}, + deploy_vm_standalones_javaLatest_darwin_aarch64: vm.vm_java_Latest + self.full_vm_build_darwin_aarch64 + self.darwin_deploy + self.vm_base('darwin', 'aarch64', 'daily', deploy=true) + self.deploy_graalvm_components('latest', installables=false, standalones=true) + {name: 'daily-deploy-vm-standalones-java-latest-darwin-aarch64', diskspace_required: "31GB", notify_groups:: ["deploy"], notify_emails+: ["bernhard.urban-forster@oracle.com"], timelimit: '3:00:00'}, # - JDK21 - deploy_vm_base_java21_darwin_aarch64: vm.vm_java_21 + self.full_vm_build_darwin_aarch64 + self.darwin_deploy + self.deploy_daily_vm_darwin_aarch64 + self.deploy_graalvm_base("java21") + {name: 'daily-deploy-vm-base-java21-darwin-aarch64', notify_groups:: ["deploy"], notify_emails+: ["bernhard.urban-forster@oracle.com"], timelimit: '1:45:00'}, - deploy_vm_installables_java21_darwin_aarch64: vm.vm_java_21 + self.full_vm_build_darwin_aarch64 + self.darwin_deploy + self.deploy_weekly_vm_darwin_aarch64 + self.deploy_graalvm_components("java21", installables=true, standalones=false) + {name: 'weekly-deploy-vm-installables-java21-darwin-aarch64', diskspace_required: "31GB", notify_groups:: ["deploy"], notify_emails+: ["bernhard.urban-forster@oracle.com"], timelimit: '3:00:00'}, - deploy_vm_standalones_java21_darwin_aarch64: vm.vm_java_21 + self.full_vm_build_darwin_aarch64 + self.darwin_deploy + self.deploy_daily_vm_darwin_aarch64 + self.deploy_graalvm_components("java21", installables=false, standalones=true) + {name: 'daily-deploy-vm-standalones-java21-darwin-aarch64', diskspace_required: "31GB", notify_groups:: ["deploy"], notify_emails+: ["bernhard.urban-forster@oracle.com"], timelimit: '3:00:00'}, + deploy_vm_base_java21_darwin_aarch64: vm.vm_java_21 + self.full_vm_build_darwin_aarch64 + self.darwin_deploy + self.vm_base('darwin', 'aarch64', 'daily', deploy=true) + self.deploy_graalvm_base("java21") + {name: 'daily-deploy-vm-base-java21-darwin-aarch64', notify_groups:: ["deploy"], notify_emails+: ["bernhard.urban-forster@oracle.com"], timelimit: '1:45:00'}, + deploy_vm_installables_java21_darwin_aarch64: vm.vm_java_21 + self.full_vm_build_darwin_aarch64 + self.darwin_deploy + self.vm_base('darwin', 'aarch64', 'weekly', deploy=true) + self.deploy_graalvm_components("java21", installables=true, standalones=false) + {name: 'weekly-deploy-vm-installables-java21-darwin-aarch64', diskspace_required: "31GB", notify_groups:: ["deploy"], notify_emails+: ["bernhard.urban-forster@oracle.com"], timelimit: '3:00:00'}, + deploy_vm_standalones_java21_darwin_aarch64: vm.vm_java_21 + self.full_vm_build_darwin_aarch64 + self.darwin_deploy + self.vm_base('darwin', 'aarch64', 'daily', deploy=true) + self.deploy_graalvm_components("java21", installables=false, standalones=true) + {name: 'daily-deploy-vm-standalones-java21-darwin-aarch64', diskspace_required: "31GB", notify_groups:: ["deploy"], notify_emails+: ["bernhard.urban-forster@oracle.com"], timelimit: '3:00:00'}, # Windows/AMD64 # - JDK-Latest - deploy_vm_base_javaLatest_windows_amd64: vm.vm_java_Latest + self.svm_common_windows_amd64('Latest') + self.js_windows_common + self.deploy_daily_vm_windows_jdkLatest + self.deploy_graalvm_base('latest') + self.deploy_build + {name: 'daily-deploy-vm-base-java-latest-windows-amd64', notify_groups:: ["deploy"], timelimit: '1:30:00'}, - deploy_vm_standalones_javaLatest_windows_amd64: vm.vm_java_Latest + self.svm_common_windows_amd64('Latest') + self.js_windows_common + self.sulong_windows + self.deploy_daily_vm_windows_jdkLatest + self.deploy_graalvm_components('latest', installables=false, standalones=true) + self.deploy_build + {name: 'daily-deploy-vm-standalones-java-latest-windows-amd64', diskspace_required: "31GB", timelimit: '2:30:00', notify_groups:: ["deploy"]}, + deploy_vm_base_javaLatest_windows_amd64: vm.vm_java_Latest + self.svm_common_windows_amd64('Latest') + self.js_windows_common + self.vm_base('windows', 'amd64', 'daily', deploy=true, jdk_hint='Latest') + self.deploy_graalvm_base('latest') + self.deploy_build + {name: 'daily-deploy-vm-base-java-latest-windows-amd64', notify_groups:: ["deploy"], timelimit: '1:30:00'}, + deploy_vm_standalones_javaLatest_windows_amd64: vm.vm_java_Latest + self.svm_common_windows_amd64('Latest') + self.js_windows_common + self.sulong_windows + self.vm_base('windows', 'amd64', 'daily', deploy=true, jdk_hint='Latest') + self.deploy_graalvm_components('latest', installables=false, standalones=true) + self.deploy_build + {name: 'daily-deploy-vm-standalones-java-latest-windows-amd64', diskspace_required: "31GB", timelimit: '2:30:00', notify_groups:: ["deploy"]}, # - JDK21 - deploy_vm_base_java21_windows_amd64: vm.vm_java_21 + self.svm_common_windows_amd64("21") + self.js_windows_common + self.deploy_daily_vm_windows_jdk21 + self.deploy_graalvm_base("java21") + self.deploy_build + {name: 'daily-deploy-vm-base-java21-windows-amd64', notify_groups:: ["deploy"], timelimit: '1:30:00'}, - deploy_vm_installables_java21_windows_amd64: vm.vm_java_21 + self.svm_common_windows_amd64("21") + self.js_windows_common + self.sulong_windows + self.deploy_weekly_vm_windows_jdk21 + self.deploy_graalvm_components("java21", installables=true, standalones=false) + self.deploy_build + {name: 'weekly-deploy-vm-installables-java21-windows-amd64', diskspace_required: "31GB", timelimit: '2:30:00', notify_groups:: ["deploy"]}, - deploy_vm_standalones_java21_windows_amd64: vm.vm_java_21 + self.svm_common_windows_amd64("21") + self.js_windows_common + self.sulong_windows + self.deploy_daily_vm_windows_jdk21 + self.deploy_graalvm_components("java21", installables=false, standalones=true) + self.deploy_build + {name: 'daily-deploy-vm-standalones-java21-windows-amd64', diskspace_required: "31GB", timelimit: '2:30:00', notify_groups:: ["deploy"]}, + deploy_vm_base_java21_windows_amd64: vm.vm_java_21 + self.svm_common_windows_amd64("21") + self.js_windows_common + self.vm_base('windows', 'amd64', 'daily', deploy=true, jdk_hint='21') + self.deploy_graalvm_base("java21") + self.deploy_build + {name: 'daily-deploy-vm-base-java21-windows-amd64', notify_groups:: ["deploy"], timelimit: '1:30:00'}, + deploy_vm_installables_java21_windows_amd64: vm.vm_java_21 + self.svm_common_windows_amd64("21") + self.js_windows_common + self.sulong_windows + self.vm_base('windows', 'amd64', 'weekly', deploy=true, jdk_hint='21') + self.deploy_graalvm_components("java21", installables=true, standalones=false) + self.deploy_build + {name: 'weekly-deploy-vm-installables-java21-windows-amd64', diskspace_required: "31GB", timelimit: '2:30:00', notify_groups:: ["deploy"]}, + deploy_vm_standalones_java21_windows_amd64: vm.vm_java_21 + self.svm_common_windows_amd64("21") + self.js_windows_common + self.sulong_windows + self.vm_base('windows', 'amd64', 'daily', deploy=true, jdk_hint='21') + self.deploy_graalvm_components("java21", installables=false, standalones=true) + self.deploy_build + {name: 'daily-deploy-vm-standalones-java21-windows-amd64', diskspace_required: "31GB", timelimit: '2:30:00', notify_groups:: ["deploy"]}, # # Deploy the GraalVM Espresso artifact (GraalVM Base + espresso - native image) # - deploy_vm_espresso_java21_linux_amd64: vm.vm_java_21_llvm + self.full_vm_build_linux_amd64 + self.linux_deploy + self.deploy_daily_vm_linux_amd64 + self.deploy_graalvm_espresso('linux', 'amd64', 'java21') + {name: 'daily-deploy-vm-espresso-java21-linux-amd64', notify_groups:: ["deploy"]}, - deploy_vm_espresso_java21_linux_aarch64: vm.vm_java_21 + self.full_vm_build_linux_aarch64 + self.linux_deploy + self.deploy_daily_vm_linux_aarch64 + self.deploy_graalvm_espresso('linux', 'aarch64', 'java21') + {name: 'daily-deploy-vm-espresso-java21-linux-aarch64', notify_groups:: ["deploy"]}, - deploy_vm_espresso_java21_darwin_amd64: vm.vm_java_21_llvm + self.full_vm_build_darwin_amd64 + self.darwin_deploy + self.deploy_daily_vm_darwin_amd64 + self.deploy_graalvm_espresso('darwin', 'amd64', 'java21') + {name: 'daily-deploy-vm-espresso-java21-darwin-amd64', notify_groups:: ["deploy"]}, - deploy_vm_espresso_java21_darwin_aarch64: vm.vm_java_21 + self.full_vm_build_darwin_aarch64 + self.darwin_deploy + self.deploy_daily_vm_darwin_aarch64 + self.deploy_graalvm_espresso('darwin', 'aarch64', 'java21') + {name: 'daily-deploy-vm-espresso-java21-darwin-aarch64', notify_groups:: ["deploy"]}, - deploy_vm_espresso_java21_windows_amd64: vm.vm_java_21 + self.svm_common_windows_amd64("21") + self.sulong_windows + self.deploy_build + self.deploy_daily_vm_windows_jdk21 + self.deploy_graalvm_espresso('windows', 'amd64', 'java21') + {name: 'daily-deploy-vm-espresso-java21-windows-amd64', notify_groups:: ["deploy"]}, + deploy_vm_espresso_java21_linux_amd64: vm.vm_java_21_llvm + self.full_vm_build_linux_amd64 + self.linux_deploy + self.vm_base('linux', 'amd64', 'daily', deploy=true) + self.deploy_graalvm_espresso('linux', 'amd64', 'java21') + {name: 'daily-deploy-vm-espresso-java21-linux-amd64', notify_groups:: ["deploy"]}, + deploy_vm_espresso_java21_linux_aarch64: vm.vm_java_21 + self.full_vm_build_linux_aarch64 + self.linux_deploy + self.vm_base('linux', 'aarch64', 'daily', deploy=true) + self.deploy_graalvm_espresso('linux', 'aarch64', 'java21') + {name: 'daily-deploy-vm-espresso-java21-linux-aarch64', notify_groups:: ["deploy"]}, + deploy_vm_espresso_java21_darwin_amd64: vm.vm_java_21_llvm + self.full_vm_build_darwin_amd64 + self.darwin_deploy + self.vm_base('darwin', 'amd64', 'daily', deploy=true) + self.deploy_graalvm_espresso('darwin', 'amd64', 'java21') + {name: 'daily-deploy-vm-espresso-java21-darwin-amd64', notify_groups:: ["deploy"]}, + deploy_vm_espresso_java21_darwin_aarch64: vm.vm_java_21 + self.full_vm_build_darwin_aarch64 + self.darwin_deploy + self.vm_base('darwin', 'aarch64', 'daily', deploy=true) + self.deploy_graalvm_espresso('darwin', 'aarch64', 'java21') + {name: 'daily-deploy-vm-espresso-java21-darwin-aarch64', notify_groups:: ["deploy"]}, + deploy_vm_espresso_java21_windows_amd64: vm.vm_java_21 + self.svm_common_windows_amd64("21") + self.sulong_windows + self.deploy_build + self.vm_base('windows', 'amd64', 'daily', deploy=true, jdk_hint='21') + self.deploy_graalvm_espresso('windows', 'amd64', 'java21') + {name: 'daily-deploy-vm-espresso-java21-windows-amd64', notify_groups:: ["deploy"]}, - local sulong_vm_tests = self.svm_common_linux_amd64 + self.sulong_linux + vm.custom_vm_linux + self.gate_vm_linux_amd64 + { + local sulong_vm_tests = self.svm_common_linux_amd64 + self.sulong_linux + vm.custom_vm_linux + self.vm_base('linux', 'amd64', 'gate') + { run: [ ['export', 'SVM_SUITE=' + vm.svm_suite], ['mx', '--dynamicimports', '$SVM_SUITE,/sulong', '--disable-polyglot', '--disable-libpolyglot', 'gate', '--no-warning-as-error', '--tags', 'build,sulong'], @@ -926,7 +696,7 @@ local devkits = graal_common.devkits; # # Gates # - vm.vm_java_21 + graal_common.deps.eclipse + graal_common.deps.jdt + self.gate_vm_linux_amd64 + galahad.include + { + vm.vm_java_21 + graal_common.deps.eclipse + graal_common.deps.jdt + self.vm_base('linux', 'amd64', 'gate') + galahad.include + { run: [ ['mx', 'gate', '-B=--force-deprecation-as-warning', '--tags', 'style,fullbuild'], ], diff --git a/vm/ci/ci_common/libgraal.jsonnet b/vm/ci/ci_common/libgraal.jsonnet index c5c52ec13c59..e783f1643380 100644 --- a/vm/ci/ci_common/libgraal.jsonnet +++ b/vm/ci/ci_common/libgraal.jsonnet @@ -113,7 +113,7 @@ local utils = import '../../../ci/ci_common/common-utils.libsonnet'; # Builds run on all platforms (platform = JDK + OS + ARCH) local all_platforms_builds = [ - c["gate_vm_" + underscore(os_arch)] + + c.vm_base(os(os_arch), arch(os_arch), 'gate') + svm_common(os_arch, jdk) + vm["custom_vm_" + os(os_arch)] + g.make_build(jdk, os_arch, task, extra_tasks=self, suite="vm", @@ -144,7 +144,7 @@ local utils = import '../../../ci/ci_common/common-utils.libsonnet'; # Builds run on all platforms (platform = JDK + OS + ARCH) but Windows currently requires Windows server 2019 local all_platforms_zgc_builds = [ - adjust_windows_version(c["gate_vm_" + underscore(os_arch)]) + + adjust_windows_version(c.vm_base(os(os_arch), arch(os_arch), 'gate')) + svm_common(os_arch, jdk) + vm["custom_vm_" + os(os_arch)] + g.make_build(jdk, os_arch, task, extra_tasks=self, suite="vm", @@ -166,7 +166,7 @@ local utils = import '../../../ci/ci_common/common-utils.libsonnet'; # Coverage builds only on jdk21 (GR-46676) local coverage_jdk21_builds = [ - c["gate_vm_" + underscore(os_arch)] + + c.vm_base(os(os_arch), arch(os_arch), 'gate') + svm_common(os_arch, jdk) + vm["custom_vm_" + os(os_arch)] + g.make_build(jdk, os_arch, task, extra_tasks=self, suite="vm", diff --git a/vm/ci/ci_includes/vm-native.jsonnet b/vm/ci/ci_includes/vm-native.jsonnet index d2012f7ef46e..c134fcc96214 100644 --- a/vm/ci/ci_includes/vm-native.jsonnet +++ b/vm/ci/ci_includes/vm-native.jsonnet @@ -47,7 +47,7 @@ local vm_common = import '../ci_common/common.jsonnet'; }, local builds = [ - vm.vm_java_21 + vm_common.svm_common_linux_amd64 + vm_common.sulong_linux + vm_common.graalpython_linux_amd64 + vm.custom_vm_linux + vm_common.gate_vm_linux_amd64 + { + vm.vm_java_21 + vm_common.svm_common_linux_amd64 + vm_common.sulong_linux + vm_common.graalpython_linux_amd64 + vm.custom_vm_linux + vm_common.vm_base('linux', 'amd64', 'gate') + { run+: [ ['export', 'SVM_SUITE=' + vm.svm_suite], ['mx', '--dynamicimports', '$SVM_SUITE,graalpython', '--disable-polyglot', '--disable-libpolyglot', '--force-bash-launchers=lli,native-image', 'gate', '--no-warning-as-error', '--tags', 'build,python'], @@ -55,24 +55,24 @@ local vm_common = import '../ci_common/common.jsonnet'; timelimit: '45:00', name: 'gate-vm-native-graalpython-linux-amd64', }, - vm.vm_java_21 + vm_common.daily_vm_linux_amd64 + { + vm.vm_java_21 + vm_common.vm_base('linux', 'amd64', 'daily') + { gate_tag_suffix: '', } + native_substratevm_truffle, - vm.vm_java_21 + vm_common.daily_vm_linux_amd64 + { + vm.vm_java_21 + vm_common.vm_base('linux', 'amd64', 'daily') + { gate_tag_suffix: '-quickbuild', } + native_substratevm_truffle, - vm.vm_java_Latest + vm_common.gate_vm_linux_amd64 + { + vm.vm_java_Latest + vm_common.vm_base('linux', 'amd64', 'gate') + { gate_tag_suffix: '', } + native_substratevm_truffle, - vm.vm_java_Latest + vm_common.gate_vm_linux_amd64 + { + vm.vm_java_Latest + vm_common.vm_base('linux', 'amd64', 'gate') + { gate_tag_suffix: '-quickbuild', } + native_substratevm_truffle, - vm.vm_java_21 + vm_common.daily_vm_linux_amd64 + svm_truffle_tck, - vm.vm_java_Latest + vm_common.gate_vm_linux_amd64 + svm_truffle_tck, - vm.vm_java_21 + vm_common.daily_vm_linux_amd64 + truffle_unchained, - vm.vm_java_Latest + vm_common.gate_vm_linux_amd64 + truffle_unchained, - vm.vm_java_21 + vm_common.daily_vm_linux_amd64 + truffle_maven_downloader, - vm.vm_java_Latest + vm_common.gate_vm_linux_amd64 + truffle_maven_downloader, + vm.vm_java_21 + vm_common.vm_base('linux', 'amd64', 'daily') + svm_truffle_tck, + vm.vm_java_Latest + vm_common.vm_base('linux', 'amd64', 'gate') + svm_truffle_tck, + vm.vm_java_21 + vm_common.vm_base('linux', 'amd64', 'daily') + truffle_unchained, + vm.vm_java_Latest + vm_common.vm_base('linux', 'amd64', 'gate') + truffle_unchained, + vm.vm_java_21 + vm_common.vm_base('linux', 'amd64', 'daily') + truffle_maven_downloader, + vm.vm_java_Latest + vm_common.vm_base('linux', 'amd64', 'gate') + truffle_maven_downloader, ], builds: utils.add_defined_in(builds, std.thisFile), diff --git a/vm/ci/ci_includes/vm.jsonnet b/vm/ci/ci_includes/vm.jsonnet index 0325ca9c4d96..f13bef3a7c41 100644 --- a/vm/ci/ci_includes/vm.jsonnet +++ b/vm/ci/ci_includes/vm.jsonnet @@ -44,7 +44,7 @@ local graal_common = import '../../../ci/ci_common/common.jsonnet'; ], }, - notify_releaser_build: vm_common.deploy_daily_vm_linux_amd64 + { + notify_releaser_build: vm_common.vm_base('linux', 'amd64', 'daily', deploy=true) + { name: 'daily-deploy-vm-notify-releaser-build-linux-amd64', packages+: { curl: '>=7.50.1', @@ -98,21 +98,21 @@ local graal_common = import '../../../ci/ci_common/common.jsonnet'; }, local builds = [ - utils.add_gate_predicate(self.vm_java_21 + vm_common.gate_vm_linux_amd64 + { + utils.add_gate_predicate(self.vm_java_21 + vm_common.vm_base('linux', 'amd64', 'gate') + { run: [ ['mx', 'build'], ['mx', 'unittest', '--suite', 'vm'], ], name: 'gate-vm-unittest-linux-amd64', }, ['sdk', 'truffle', 'vm']), - utils.add_gate_predicate(self.vm_java_21 + graal_common.devkits['windows-jdk21'] + vm_common.gate_vm_windows_amd64 + { + utils.add_gate_predicate(self.vm_java_21 + graal_common.devkits['windows-jdk21'] + vm_common.vm_base('windows', 'amd64', 'gate') + { run: [ ['mx', 'build'], ['mx', 'unittest', '--suite', 'vm'], ], name: 'gate-vm-unittest-windows-amd64', }, ["sdk", "truffle", "vm"]), - self.vm_java_21 + vm_common.gate_vm_linux_amd64 + vm_common.sulong_linux + { + self.vm_java_21 + vm_common.vm_base('linux', 'amd64', 'gate') + vm_common.sulong_linux + { environment+: { DYNAMIC_IMPORTS: '/tools,/substratevm,/sulong', NATIVE_IMAGES: 'polyglot', @@ -125,51 +125,51 @@ local graal_common = import '../../../ci/ci_common/common.jsonnet'; }, # Linux/AMD64 - vm_common.graalvm_complete_build_deps('ce', 'linux', 'amd64') + vm_common.linux_deploy + vm_common.gate_vm_linux_amd64 + vm_common.maven_deploy_base_functions.base_object('linux', 'amd64', dry_run=true, remote_mvn_repo=$.maven_deploy_repository, remote_non_mvn_repo=$.binaries_repository, local_repo='local') + { + vm_common.graalvm_complete_build_deps('ce', 'linux', 'amd64') + vm_common.linux_deploy + vm_common.vm_base('linux', 'amd64', 'gate') + vm_common.maven_deploy_base_functions.base_object('linux', 'amd64', dry_run=true, remote_mvn_repo=$.maven_deploy_repository, remote_non_mvn_repo=$.binaries_repository, local_repo='local') + { name: 'gate-vm-maven-dry-run-linux-amd64', timelimit: '1:00:00', }, - vm_common.graalvm_complete_build_deps('ce', 'linux', 'amd64') + vm_common.linux_deploy + vm_common.deploy_daily_vm_linux_amd64 + vm_common.maven_deploy_base_functions.base_object('linux', 'amd64', dry_run=false, remote_mvn_repo=$.maven_deploy_repository, remote_non_mvn_repo=$.binaries_repository, local_repo='local') + { + vm_common.graalvm_complete_build_deps('ce', 'linux', 'amd64') + vm_common.linux_deploy + vm_common.vm_base('linux', 'amd64', 'daily', deploy=true) + vm_common.maven_deploy_base_functions.base_object('linux', 'amd64', dry_run=false, remote_mvn_repo=$.maven_deploy_repository, remote_non_mvn_repo=$.binaries_repository, local_repo='local') + { name: 'daily-deploy-vm-maven-linux-amd64', timelimit: '1:00:00', notify_groups:: ['deploy'], }, # Linux/AARCH64 - vm_common.graalvm_complete_build_deps('ce', 'linux', 'aarch64') + vm_common.linux_deploy + vm_common.gate_vm_linux_aarch64 + vm_common.maven_deploy_base_functions.base_object('linux', 'aarch64', dry_run=true, remote_mvn_repo=$.maven_deploy_repository, remote_non_mvn_repo=$.binaries_repository, local_repo='local') + { + vm_common.graalvm_complete_build_deps('ce', 'linux', 'aarch64') + vm_common.linux_deploy + vm_common.vm_base('linux', 'aarch64', 'gate') + vm_common.maven_deploy_base_functions.base_object('linux', 'aarch64', dry_run=true, remote_mvn_repo=$.maven_deploy_repository, remote_non_mvn_repo=$.binaries_repository, local_repo='local') + { name: 'gate-vm-maven-dry-run-linux-aarch64', timelimit: '1:00:00', }, - vm_common.graalvm_complete_build_deps('ce', 'linux', 'aarch64') + vm_common.linux_deploy + vm_common.deploy_daily_vm_linux_aarch64 + vm_common.maven_deploy_base_functions.base_object('linux', 'aarch64', dry_run=false, remote_mvn_repo=$.maven_deploy_repository, remote_non_mvn_repo=$.binaries_repository, local_repo='local') + { + vm_common.graalvm_complete_build_deps('ce', 'linux', 'aarch64') + vm_common.linux_deploy + vm_common.vm_base('linux', 'aarch64', 'daily', deploy=true) + vm_common.maven_deploy_base_functions.base_object('linux', 'aarch64', dry_run=false, remote_mvn_repo=$.maven_deploy_repository, remote_non_mvn_repo=$.binaries_repository, local_repo='local') + { name: 'daily-deploy-vm-maven-linux-aarch64', timelimit: '1:00:00', notify_groups:: ['deploy'], }, # Darwin/AMD64 - vm_common.graalvm_complete_build_deps('ce', 'darwin', 'amd64') + vm_common.darwin_deploy + vm_common.gate_vm_darwin_amd64 + vm_common.maven_deploy_base_functions.base_object('darwin', 'amd64', dry_run=true, remote_mvn_repo=$.maven_deploy_repository, remote_non_mvn_repo=$.binaries_repository, local_repo='local') + { + vm_common.graalvm_complete_build_deps('ce', 'darwin', 'amd64') + vm_common.darwin_deploy + vm_common.vm_base('darwin', 'amd64', 'gate') + vm_common.maven_deploy_base_functions.base_object('darwin', 'amd64', dry_run=true, remote_mvn_repo=$.maven_deploy_repository, remote_non_mvn_repo=$.binaries_repository, local_repo='local') + { name: 'gate-vm-maven-dry-run-darwin-amd64', timelimit: '1:00:00', }, - vm_common.graalvm_complete_build_deps('ce', 'darwin', 'amd64') + vm_common.darwin_deploy + vm_common.deploy_daily_vm_darwin_amd64 + vm_common.maven_deploy_base_functions.base_object('darwin', 'amd64', dry_run=false, remote_mvn_repo=$.maven_deploy_repository, remote_non_mvn_repo=$.binaries_repository, local_repo='local') + { + vm_common.graalvm_complete_build_deps('ce', 'darwin', 'amd64') + vm_common.darwin_deploy + vm_common.vm_base('darwin', 'amd64', 'daily', deploy=true) + vm_common.maven_deploy_base_functions.base_object('darwin', 'amd64', dry_run=false, remote_mvn_repo=$.maven_deploy_repository, remote_non_mvn_repo=$.binaries_repository, local_repo='local') + { name: 'daily-deploy-vm-maven-darwin-amd64', timelimit: '1:00:00', notify_groups:: ['deploy'], }, # Darwin/AARCH64 - vm_common.graalvm_complete_build_deps('ce', 'darwin', 'aarch64') + vm_common.darwin_deploy + vm_common.gate_vm_darwin_aarch64 + vm_common.maven_deploy_base_functions.base_object('darwin', 'aarch64', dry_run=true, remote_mvn_repo=$.maven_deploy_repository, remote_non_mvn_repo=$.binaries_repository, local_repo='local') + { + vm_common.graalvm_complete_build_deps('ce', 'darwin', 'aarch64') + vm_common.darwin_deploy + vm_common.vm_base('darwin', 'aarch64', 'gate') + vm_common.maven_deploy_base_functions.base_object('darwin', 'aarch64', dry_run=true, remote_mvn_repo=$.maven_deploy_repository, remote_non_mvn_repo=$.binaries_repository, local_repo='local') + { name: 'gate-vm-maven-dry-run-darwin-aarch64', timelimit: '1:00:00', }, - vm_common.graalvm_complete_build_deps('ce', 'darwin', 'aarch64') + vm_common.darwin_deploy + vm_common.deploy_daily_vm_darwin_aarch64 + vm_common.maven_deploy_base_functions.base_object('darwin', 'aarch64', dry_run=false, remote_mvn_repo=$.maven_deploy_repository, remote_non_mvn_repo=$.binaries_repository, local_repo='local') + { + vm_common.graalvm_complete_build_deps('ce', 'darwin', 'aarch64') + vm_common.darwin_deploy + vm_common.vm_base('darwin', 'aarch64', 'daily', deploy=true) + vm_common.maven_deploy_base_functions.base_object('darwin', 'aarch64', dry_run=false, remote_mvn_repo=$.maven_deploy_repository, remote_non_mvn_repo=$.binaries_repository, local_repo='local') + { name: 'daily-deploy-vm-maven-darwin-aarch64', timelimit: '1:00:00', notify_groups:: ['deploy'], }, # Windows/AMD64 - vm_common.graalvm_complete_build_deps('ce', 'windows', 'amd64') + vm_common.deploy_build + vm_common.gate_vm_windows_amd64 + vm_common.maven_deploy_base_functions.base_object('windows', 'amd64', dry_run=true, remote_mvn_repo=$.maven_deploy_repository, remote_non_mvn_repo=$.binaries_repository, local_repo='local') + { + vm_common.graalvm_complete_build_deps('ce', 'windows', 'amd64') + vm_common.deploy_build + vm_common.vm_base('windows', 'amd64', 'gate') + vm_common.maven_deploy_base_functions.base_object('windows', 'amd64', dry_run=true, remote_mvn_repo=$.maven_deploy_repository, remote_non_mvn_repo=$.binaries_repository, local_repo='local') + { name: 'gate-vm-maven-dry-run-windows-amd64', timelimit: '1:00:00', }, - vm_common.graalvm_complete_build_deps('ce', 'windows', 'amd64') + vm_common.deploy_build + vm_common.deploy_daily_vm_windows_jdk21 + vm_common.maven_deploy_base_functions.base_object('windows', 'amd64', dry_run=false, remote_mvn_repo=$.maven_deploy_repository, remote_non_mvn_repo=$.binaries_repository, local_repo='local') + { + vm_common.graalvm_complete_build_deps('ce', 'windows', 'amd64') + vm_common.deploy_build + vm_common.vm_base('windows', 'amd64', 'daily', deploy=true, jdk_hint='21') + vm_common.maven_deploy_base_functions.base_object('windows', 'amd64', dry_run=false, remote_mvn_repo=$.maven_deploy_repository, remote_non_mvn_repo=$.binaries_repository, local_repo='local') + { name: 'daily-deploy-vm-maven-windows-amd64', timelimit: '1:00:00', notify_groups:: ['deploy'], @@ -178,7 +178,7 @@ local graal_common = import '../../../ci/ci_common/common.jsonnet'; # # Update the `stable` mx branch with the currently imported revision # - vm_common.postmerge_vm_linux_amd64 + { + vm_common.vm_base('linux', 'amd64', 'post-merge') + { run: [ ['set-export', 'BRANCH_NAME', ['git', 'rev-parse', '--abbrev-ref', 'HEAD']], ['bash', '-c', 'if [[ ${BRANCH_NAME} == master ]] || [[ ${BRANCH_NAME} == release/* ]] || [[ ${BRANCH_NAME} == cpu/* ]]; then git -C ${MX_HOME} push origin +HEAD:refs/heads/graal/${BRANCH_NAME}; fi'] From ce47027d8baccfd5974c02565768dee1c9dd5018 Mon Sep 17 00:00:00 2001 From: Andreas Woess Date: Wed, 6 Dec 2023 14:55:59 +0100 Subject: [PATCH 114/593] Remove shouldNotReachHere() from Frame.getTag(), just throw AIOOBE. --- .../oracle/truffle/api/impl/FrameWithoutBoxing.java | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/truffle/src/com.oracle.truffle.api/src/com/oracle/truffle/api/impl/FrameWithoutBoxing.java b/truffle/src/com.oracle.truffle.api/src/com/oracle/truffle/api/impl/FrameWithoutBoxing.java index 0c82e0952866..43563e5e0abf 100644 --- a/truffle/src/com.oracle.truffle.api/src/com/oracle/truffle/api/impl/FrameWithoutBoxing.java +++ b/truffle/src/com.oracle.truffle.api/src/com/oracle/truffle/api/impl/FrameWithoutBoxing.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 2023, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * The Universal Permissive License (UPL), Version 1.0 @@ -232,12 +232,9 @@ private static long getPrimitiveOffset(int slotIndex) { @Override public byte getTag(int slotIndex) { - try { - final byte tag = getIndexedTags()[slotIndex]; - return tag < STATIC_TAG ? tag : STATIC_TAG; - } catch (ArrayIndexOutOfBoundsException e) { - throw CompilerDirectives.shouldNotReachHere("invalid indexed slot", e); - } + // this may raise an AIOOBE + final byte tag = getIndexedTags()[slotIndex]; + return tag < STATIC_TAG ? tag : STATIC_TAG; } @SuppressWarnings({"unchecked", "unused"}) From 91b4fac2dd8b1b5b004d1e5aa81e16c88e6868b5 Mon Sep 17 00:00:00 2001 From: Andreas Woess Date: Wed, 6 Dec 2023 00:55:44 +0100 Subject: [PATCH 115/593] Simplify non-static frame slot type/tag checks. --- .../truffle/api/impl/FrameWithoutBoxing.java | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/truffle/src/com.oracle.truffle.api/src/com/oracle/truffle/api/impl/FrameWithoutBoxing.java b/truffle/src/com.oracle.truffle.api/src/com/oracle/truffle/api/impl/FrameWithoutBoxing.java index 43563e5e0abf..3c37b68e231b 100644 --- a/truffle/src/com.oracle.truffle.api/src/com/oracle/truffle/api/impl/FrameWithoutBoxing.java +++ b/truffle/src/com.oracle.truffle.api/src/com/oracle/truffle/api/impl/FrameWithoutBoxing.java @@ -237,6 +237,11 @@ public byte getTag(int slotIndex) { return tag < STATIC_TAG ? tag : STATIC_TAG; } + private boolean isNonStaticType(int slotIndex, byte tag) { + assert tag < STATIC_TAG : tag; + return getIndexedTags()[slotIndex] == tag; + } + @SuppressWarnings({"unchecked", "unused"}) private static T unsafeCast(Object value, Class type, boolean condition, boolean nonNull, boolean exact) { return (T) value; @@ -434,37 +439,37 @@ private byte getIndexedTagChecked(int slot) { @Override public boolean isObject(int slot) { - return getTag(slot) == OBJECT_TAG; + return isNonStaticType(slot, OBJECT_TAG); } @Override public boolean isByte(int slot) { - return getTag(slot) == BYTE_TAG; + return isNonStaticType(slot, BYTE_TAG); } @Override public boolean isBoolean(int slot) { - return getTag(slot) == BOOLEAN_TAG; + return isNonStaticType(slot, BOOLEAN_TAG); } @Override public boolean isInt(int slot) { - return getTag(slot) == INT_TAG; + return isNonStaticType(slot, INT_TAG); } @Override public boolean isLong(int slot) { - return getTag(slot) == LONG_TAG; + return isNonStaticType(slot, LONG_TAG); } @Override public boolean isFloat(int slot) { - return getTag(slot) == FLOAT_TAG; + return isNonStaticType(slot, FLOAT_TAG); } @Override public boolean isDouble(int slot) { - return getTag(slot) == DOUBLE_TAG; + return isNonStaticType(slot, DOUBLE_TAG); } @Override From 60ae3cb0ee37b9d9ac38bccab0c8657798a9a75a Mon Sep 17 00:00:00 2001 From: Andreas Woess Date: Wed, 6 Dec 2023 11:14:59 +0100 Subject: [PATCH 116/593] Use getIndexed(Primitive)Locals() getter consistently. --- .../truffle/api/impl/FrameWithoutBoxing.java | 112 ++++++++++-------- 1 file changed, 62 insertions(+), 50 deletions(-) diff --git a/truffle/src/com.oracle.truffle.api/src/com/oracle/truffle/api/impl/FrameWithoutBoxing.java b/truffle/src/com.oracle.truffle.api/src/com/oracle/truffle/api/impl/FrameWithoutBoxing.java index 3c37b68e231b..38d65569c4ab 100644 --- a/truffle/src/com.oracle.truffle.api/src/com/oracle/truffle/api/impl/FrameWithoutBoxing.java +++ b/truffle/src/com.oracle.truffle.api/src/com/oracle/truffle/api/impl/FrameWithoutBoxing.java @@ -390,28 +390,32 @@ public void setDouble(int slot, double value) { @Override public void copy(int srcSlot, int destSlot) { byte tag = getIndexedTagChecked(srcSlot); - Object value = unsafeGetObject(getIndexedLocals(), Unsafe.ARRAY_OBJECT_BASE_OFFSET + srcSlot * (long) Unsafe.ARRAY_OBJECT_INDEX_SCALE, true, OBJECT_LOCATION); + final Object[] referenceLocals = getIndexedLocals(); + final long[] primitiveLocals = getIndexedPrimitiveLocals(); + Object value = unsafeGetObject(referenceLocals, Unsafe.ARRAY_OBJECT_BASE_OFFSET + srcSlot * (long) Unsafe.ARRAY_OBJECT_INDEX_SCALE, true, OBJECT_LOCATION); verifyIndexedSet(destSlot, tag); - unsafePutObject(getIndexedLocals(), Unsafe.ARRAY_OBJECT_BASE_OFFSET + destSlot * (long) Unsafe.ARRAY_OBJECT_INDEX_SCALE, value, OBJECT_LOCATION); - long primitiveValue = unsafeGetLong(getIndexedPrimitiveLocals(), getPrimitiveOffset(srcSlot), true, PRIMITIVE_LOCATION); - unsafePutLong(getIndexedPrimitiveLocals(), getPrimitiveOffset(destSlot), primitiveValue, PRIMITIVE_LOCATION); + unsafePutObject(referenceLocals, Unsafe.ARRAY_OBJECT_BASE_OFFSET + destSlot * (long) Unsafe.ARRAY_OBJECT_INDEX_SCALE, value, OBJECT_LOCATION); + long primitiveValue = unsafeGetLong(primitiveLocals, getPrimitiveOffset(srcSlot), true, PRIMITIVE_LOCATION); + unsafePutLong(primitiveLocals, getPrimitiveOffset(destSlot), primitiveValue, PRIMITIVE_LOCATION); } @Override public void swap(int first, int second) { byte firstTag = getIndexedTagChecked(first); - Object firstValue = unsafeGetObject(getIndexedLocals(), Unsafe.ARRAY_OBJECT_BASE_OFFSET + first * (long) Unsafe.ARRAY_OBJECT_INDEX_SCALE, true, OBJECT_LOCATION); - long firstPrimitiveValue = unsafeGetLong(getIndexedPrimitiveLocals(), getPrimitiveOffset(first), true, PRIMITIVE_LOCATION); + final Object[] referenceLocals = getIndexedLocals(); + final long[] primitiveLocals = getIndexedPrimitiveLocals(); + Object firstValue = unsafeGetObject(referenceLocals, Unsafe.ARRAY_OBJECT_BASE_OFFSET + first * (long) Unsafe.ARRAY_OBJECT_INDEX_SCALE, true, OBJECT_LOCATION); + long firstPrimitiveValue = unsafeGetLong(primitiveLocals, getPrimitiveOffset(first), true, PRIMITIVE_LOCATION); byte secondTag = getIndexedTagChecked(second); - Object secondValue = unsafeGetObject(getIndexedLocals(), Unsafe.ARRAY_OBJECT_BASE_OFFSET + second * (long) Unsafe.ARRAY_OBJECT_INDEX_SCALE, true, OBJECT_LOCATION); - long secondPrimitiveValue = unsafeGetLong(getIndexedPrimitiveLocals(), getPrimitiveOffset(second), true, PRIMITIVE_LOCATION); + Object secondValue = unsafeGetObject(referenceLocals, Unsafe.ARRAY_OBJECT_BASE_OFFSET + second * (long) Unsafe.ARRAY_OBJECT_INDEX_SCALE, true, OBJECT_LOCATION); + long secondPrimitiveValue = unsafeGetLong(primitiveLocals, getPrimitiveOffset(second), true, PRIMITIVE_LOCATION); verifyIndexedSet(first, secondTag); verifyIndexedSet(second, firstTag); - unsafePutObject(getIndexedLocals(), Unsafe.ARRAY_OBJECT_BASE_OFFSET + first * (long) Unsafe.ARRAY_OBJECT_INDEX_SCALE, secondValue, OBJECT_LOCATION); - unsafePutLong(getIndexedPrimitiveLocals(), getPrimitiveOffset(first), secondPrimitiveValue, PRIMITIVE_LOCATION); - unsafePutObject(getIndexedLocals(), Unsafe.ARRAY_OBJECT_BASE_OFFSET + second * (long) Unsafe.ARRAY_OBJECT_INDEX_SCALE, firstValue, OBJECT_LOCATION); - unsafePutLong(getIndexedPrimitiveLocals(), getPrimitiveOffset(second), firstPrimitiveValue, PRIMITIVE_LOCATION); + unsafePutObject(referenceLocals, Unsafe.ARRAY_OBJECT_BASE_OFFSET + first * (long) Unsafe.ARRAY_OBJECT_INDEX_SCALE, secondValue, OBJECT_LOCATION); + unsafePutLong(primitiveLocals, getPrimitiveOffset(first), secondPrimitiveValue, PRIMITIVE_LOCATION); + unsafePutObject(referenceLocals, Unsafe.ARRAY_OBJECT_BASE_OFFSET + second * (long) Unsafe.ARRAY_OBJECT_INDEX_SCALE, firstValue, OBJECT_LOCATION); + unsafePutLong(primitiveLocals, getPrimitiveOffset(second), firstPrimitiveValue, PRIMITIVE_LOCATION); } private void verifyIndexedSet(int slot, byte tag) { @@ -504,7 +508,7 @@ public Object getAuxiliarySlot(int slot) { public Object getObjectStatic(int slot) { assert indexedTags[slot] == STATIC_OBJECT_TAG : "Unexpected read of static object value"; - return indexedLocals[slot]; + return getIndexedLocals()[slot]; } @Override @@ -515,14 +519,14 @@ public void setObjectStatic(int slot, Object value) { indexedTags[slot] = STATIC_OBJECT_TAG; } - indexedLocals[slot] = value; + getIndexedLocals()[slot] = value; } @Override public byte getByteStatic(int slot) { assert indexedTags[slot] == STATIC_BYTE_TAG : "Unexpected read of static byte value"; - return (byte) (int) indexedPrimitiveLocals[slot]; + return (byte) (int) getIndexedPrimitiveLocals()[slot]; } @Override @@ -533,14 +537,14 @@ public void setByteStatic(int slot, byte value) { indexedTags[slot] = STATIC_BYTE_TAG; } - indexedPrimitiveLocals[slot] = extend(value); + getIndexedPrimitiveLocals()[slot] = extend(value); } @Override public boolean getBooleanStatic(int slot) { assert indexedTags[slot] == STATIC_BOOLEAN_TAG : "Unexpected read of static boolean value"; - return (int) indexedPrimitiveLocals[slot] != 0; + return (int) getIndexedPrimitiveLocals()[slot] != 0; } @Override @@ -551,14 +555,14 @@ public void setBooleanStatic(int slot, boolean value) { indexedTags[slot] = STATIC_BOOLEAN_TAG; } - indexedPrimitiveLocals[slot] = value ? 1L : 0L; + getIndexedPrimitiveLocals()[slot] = value ? 1L : 0L; } @Override public int getIntStatic(int slot) { assert indexedTags[slot] == STATIC_INT_TAG : "Unexpected read of static int value"; - return (int) indexedPrimitiveLocals[slot]; + return (int) getIndexedPrimitiveLocals()[slot]; } @Override @@ -569,14 +573,14 @@ public void setIntStatic(int slot, int value) { indexedTags[slot] = STATIC_INT_TAG; } - indexedPrimitiveLocals[slot] = extend(value); + getIndexedPrimitiveLocals()[slot] = extend(value); } @Override public long getLongStatic(int slot) { assert indexedTags[slot] == STATIC_LONG_TAG : "Unexpected read of static long value"; - return indexedPrimitiveLocals[slot]; + return getIndexedPrimitiveLocals()[slot]; } @Override @@ -587,14 +591,14 @@ public void setLongStatic(int slot, long value) { indexedTags[slot] = STATIC_LONG_TAG; } - indexedPrimitiveLocals[slot] = value; + getIndexedPrimitiveLocals()[slot] = value; } @Override public float getFloatStatic(int slot) { assert indexedTags[slot] == STATIC_FLOAT_TAG : "Unexpected read of static float value"; - return Float.intBitsToFloat((int) indexedPrimitiveLocals[slot]); + return Float.intBitsToFloat((int) getIndexedPrimitiveLocals()[slot]); } @Override @@ -605,14 +609,14 @@ public void setFloatStatic(int slot, float value) { indexedTags[slot] = STATIC_FLOAT_TAG; } - indexedPrimitiveLocals[slot] = extend(Float.floatToRawIntBits(value)); + getIndexedPrimitiveLocals()[slot] = extend(Float.floatToRawIntBits(value)); } @Override public double getDoubleStatic(int slot) { assert indexedTags[slot] == STATIC_DOUBLE_TAG : "Unexpected read of static double value"; - return Double.longBitsToDouble(indexedPrimitiveLocals[slot]); + return Double.longBitsToDouble(getIndexedPrimitiveLocals()[slot]); } @Override @@ -623,7 +627,7 @@ public void setDoubleStatic(int slot, double value) { indexedTags[slot] = STATIC_DOUBLE_TAG; } - indexedPrimitiveLocals[slot] = Double.doubleToRawLongBits(value); + getIndexedPrimitiveLocals()[slot] = Double.doubleToRawLongBits(value); } @Override @@ -634,7 +638,8 @@ public void copyPrimitiveStatic(int srcSlot, int destSlot) { indexedTags[destSlot] = indexedTags[srcSlot]; } - indexedPrimitiveLocals[destSlot] = indexedPrimitiveLocals[srcSlot]; + long[] primitiveLocals = getIndexedPrimitiveLocals(); + primitiveLocals[destSlot] = primitiveLocals[srcSlot]; } @Override @@ -645,7 +650,8 @@ public void copyObjectStatic(int srcSlot, int destSlot) { indexedTags[destSlot] = indexedTags[srcSlot]; } - indexedLocals[destSlot] = indexedLocals[srcSlot]; + Object[] referenceLocals = getIndexedLocals(); + referenceLocals[destSlot] = referenceLocals[srcSlot]; } @Override @@ -656,8 +662,10 @@ public void copyStatic(int srcSlot, int destSlot) { indexedTags[destSlot] = indexedTags[srcSlot]; } - indexedLocals[destSlot] = indexedLocals[srcSlot]; - indexedPrimitiveLocals[destSlot] = indexedPrimitiveLocals[srcSlot]; + final Object[] referenceLocals = getIndexedLocals(); + final long[] primitiveLocals = getIndexedPrimitiveLocals(); + referenceLocals[destSlot] = referenceLocals[srcSlot]; + primitiveLocals[destSlot] = primitiveLocals[srcSlot]; } @Override @@ -670,11 +678,12 @@ public void swapPrimitiveStatic(int first, int second) { indexedTags[second] = swapTag; } - final long firstValue = indexedPrimitiveLocals[first]; - final long secondValue = indexedPrimitiveLocals[second]; + final long[] primitiveLocals = getIndexedPrimitiveLocals(); + final long firstValue = primitiveLocals[first]; + final long secondValue = primitiveLocals[second]; - indexedPrimitiveLocals[first] = secondValue; - indexedPrimitiveLocals[second] = firstValue; + primitiveLocals[first] = secondValue; + primitiveLocals[second] = firstValue; } @Override @@ -688,11 +697,12 @@ public void swapObjectStatic(int first, int second) { indexedTags[second] = swapTag; } - final Object firstValue = indexedLocals[first]; - final Object secondValue = indexedLocals[second]; + final Object[] referenceLocals = getIndexedLocals(); + final Object firstValue = referenceLocals[first]; + final Object secondValue = referenceLocals[second]; - indexedLocals[first] = secondValue; - indexedLocals[second] = firstValue; + referenceLocals[first] = secondValue; + referenceLocals[second] = firstValue; } @Override @@ -705,15 +715,17 @@ public void swapStatic(int first, int second) { indexedTags[second] = swapTag; } - final Object firstValue = indexedLocals[first]; - final Object secondValue = indexedLocals[second]; - final long firstPrimitiveValue = indexedPrimitiveLocals[first]; - final long secondPrimitiveValue = indexedPrimitiveLocals[second]; + final Object[] referenceLocals = getIndexedLocals(); + final long[] primitiveLocals = getIndexedPrimitiveLocals(); + final Object firstValue = referenceLocals[first]; + final Object secondValue = referenceLocals[second]; + final long firstPrimitiveValue = primitiveLocals[first]; + final long secondPrimitiveValue = primitiveLocals[second]; - indexedLocals[first] = secondValue; - indexedLocals[second] = firstValue; - indexedPrimitiveLocals[first] = secondPrimitiveValue; - indexedPrimitiveLocals[second] = firstPrimitiveValue; + referenceLocals[first] = secondValue; + referenceLocals[second] = firstValue; + primitiveLocals[first] = secondPrimitiveValue; + primitiveLocals[second] = firstPrimitiveValue; } @Override @@ -726,7 +738,7 @@ public void clearPrimitiveStatic(int slot) { if (CompilerDirectives.inCompiledCode()) { // Avoids keeping track of cleared frame slots in FrameStates - indexedPrimitiveLocals[slot] = 0L; + getIndexedPrimitiveLocals()[slot] = 0L; } } @@ -738,7 +750,7 @@ public void clearObjectStatic(int slot) { indexedTags[slot] = STATIC_ILLEGAL_TAG; } - indexedLocals[slot] = null; + getIndexedLocals()[slot] = null; } @Override @@ -751,9 +763,9 @@ public void clearStatic(int slot) { if (CompilerDirectives.inCompiledCode()) { // Avoid keeping track of cleared frame slots in FrameStates - indexedPrimitiveLocals[slot] = 0L; + getIndexedPrimitiveLocals()[slot] = 0L; } - indexedLocals[slot] = null; + getIndexedLocals()[slot] = null; } /** From d2b31cc0fa48891b52bea90c1c4aa6060b82c01b Mon Sep 17 00:00:00 2001 From: Codrut Stancu Date: Tue, 28 Nov 2023 14:06:05 +0100 Subject: [PATCH 117/593] Disable MethodHandle inlining blocking. --- .../src/com/oracle/svm/driver/NativeImage.java | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/substratevm/src/com.oracle.svm.driver/src/com/oracle/svm/driver/NativeImage.java b/substratevm/src/com.oracle.svm.driver/src/com/oracle/svm/driver/NativeImage.java index 200f4823de26..c3af20f955ef 100644 --- a/substratevm/src/com.oracle.svm.driver/src/com/oracle/svm/driver/NativeImage.java +++ b/substratevm/src/com.oracle.svm.driver/src/com/oracle/svm/driver/NativeImage.java @@ -1115,6 +1115,14 @@ private int completeImageBuild() { // The following two are for backwards compatibility reasons. They should be removed. imageBuilderJavaArgs.add("-Djdk.internal.lambda.eagerlyInitialize=false"); imageBuilderJavaArgs.add("-Djava.lang.invoke.InnerClassLambdaMetafactory.initializeLambdas=false"); + /* + * DONT_INLINE_THRESHOLD is used to set a profiling threshold for certain method handles and + * only allow inlining after n invocations. This is used for example in the implementation + * of record equals methods. We disable this behavior in the image builder because it can + * prevent optimizing the method handles for AOT compilation if the threshold is not + * reached. + */ + imageBuilderJavaArgs.add("-Djava.lang.invoke.MethodHandle.DONT_INLINE_THRESHOLD=-1"); /* After JavaArgs consolidation add the user provided JavaArgs */ boolean afterOption = false; From 961de3afebc091ba28dd1776dbc5bd04e2468fea Mon Sep 17 00:00:00 2001 From: Tom Rodriguez Date: Wed, 6 Dec 2023 11:10:23 -0800 Subject: [PATCH 118/593] Adjust to JDK-8315458 --- .../src/com/oracle/svm/core/hub/DynamicHub.java | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/hub/DynamicHub.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/hub/DynamicHub.java index 56329a35a4a8..013f50a7ba69 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/hub/DynamicHub.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/hub/DynamicHub.java @@ -874,10 +874,6 @@ void setClassLoaderAtRuntime(ClassLoader loader) { @KeepOriginal private native boolean isAnonymousClass(); - @KeepOriginal - @TargetElement - private native boolean isUnnamedClass(); - @Substitute @Uninterruptible(reason = "Called from uninterruptible code.", mayBeInlined = true) public boolean isHidden() { @@ -1756,7 +1752,7 @@ private Class[] getPermittedSubclasses0() { private static native void addAll(Collection c, Field[] o); @KeepOriginal - private native Target_java_lang_PublicMethods_MethodList getMethodsRecursive(String methodName, Class[] parameterTypes, boolean includeStatic); + private native Target_java_lang_PublicMethods_MethodList getMethodsRecursive(String methodName, Class[] parameterTypes, boolean includeStatic, boolean publicOnly); @KeepOriginal private native Field getField0(String fieldName); From b0974ddeace76eb69996cf7980c7f81413c65ddc Mon Sep 17 00:00:00 2001 From: Danilo Ansaloni Date: Wed, 6 Dec 2023 16:40:34 +0100 Subject: [PATCH 119/593] Update CI overlay. --- graal-common.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/graal-common.json b/graal-common.json index 948a787096e1..955938b47ed6 100644 --- a/graal-common.json +++ b/graal-common.json @@ -1,6 +1,6 @@ { "README": "This file contains definitions that are useful for the jsonnet CI files of the graal and graal-enterprise repositories.", "ci": { - "overlay": "31451a8c1805ea37b8535088dc84331bb7796ab4" + "overlay": "8a3ad79620a470a48e5b23ecc47a212c8b32da7f" } } From 0fd65f92dbe14e9050343b4a9246f787f24abcd7 Mon Sep 17 00:00:00 2001 From: Danilo Ansaloni Date: Wed, 6 Dec 2023 16:53:08 +0100 Subject: [PATCH 120/593] Only darwin/amd64 jobs for JDK-latest must run on BigSur. --- vm/ci/ci_common/common.jsonnet | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/vm/ci/ci_common/common.jsonnet b/vm/ci/ci_common/common.jsonnet index dcc182146560..313f1f9dffec 100644 --- a/vm/ci/ci_common/common.jsonnet +++ b/vm/ci/ci_common/common.jsonnet @@ -171,6 +171,17 @@ local devkits = graal_common.devkits; vm_ol9_aarch64: self.vm_linux_aarch64_ol9, vm_darwin_amd64: self.common_vm_darwin + graal_common.darwin_amd64 + { + capabilities+: ['darwin_mojave', 'ram16gb'], + packages+: { + gcc: '==4.9.2', + }, + environment+: { + # for compatibility with macOS Sierra + MACOSX_DEPLOYMENT_TARGET: '10.13', + }, + }, + + vm_darwin_amd64_jdkLatest: self.common_vm_darwin + graal_common.darwin_amd64 + { capabilities+: ['darwin_bigsur', 'ram16gb'], packages+: { gcc: '==4.9.2', @@ -648,8 +659,8 @@ local devkits = graal_common.devkits; # Darwin/AMD64 # - JDK-Latest - deploy_vm_base_javaLatest_darwin_amd64: vm.vm_java_Latest + self.full_vm_build_darwin_amd64 + self.darwin_deploy + self.vm_base('darwin', 'amd64', 'daily', deploy=true) + self.deploy_graalvm_base('latest') + {name: 'daily-deploy-vm-base-java-latest-darwin-amd64', notify_groups:: ["deploy"], timelimit: '1:45:00'}, - deploy_vm_standalones_javaLatest_darwin_amd64: vm.vm_java_Latest + self.full_vm_build_darwin_amd64 + self.darwin_deploy + self.vm_base('darwin', 'amd64', 'daily', deploy=true) + self.deploy_graalvm_components('latest', installables=false, standalones=true) + {name: 'daily-deploy-vm-standalones-java-latest-darwin-amd64', capabilities+: ["!macmini_late_2014"], diskspace_required: "31GB", notify_groups:: ["deploy"], timelimit: '3:00:00'}, + deploy_vm_base_javaLatest_darwin_amd64: vm.vm_java_Latest + self.full_vm_build_darwin_amd64 + self.darwin_deploy + self.vm_base('darwin', 'amd64', 'daily', deploy=true, jdk_hint='Latest') + self.deploy_graalvm_base('latest') + {name: 'daily-deploy-vm-base-java-latest-darwin-amd64', notify_groups:: ["deploy"], timelimit: '1:45:00'}, + deploy_vm_standalones_javaLatest_darwin_amd64: vm.vm_java_Latest + self.full_vm_build_darwin_amd64 + self.darwin_deploy + self.vm_base('darwin', 'amd64', 'daily', deploy=true, jdk_hint='Latest') + self.deploy_graalvm_components('latest', installables=false, standalones=true) + {name: 'daily-deploy-vm-standalones-java-latest-darwin-amd64', capabilities+: ["!macmini_late_2014"], diskspace_required: "31GB", notify_groups:: ["deploy"], timelimit: '3:00:00'}, # - JDK21 deploy_vm_base_java21_darwin_amd64: vm.vm_java_21 + self.full_vm_build_darwin_amd64 + self.darwin_deploy + self.vm_base('darwin', 'amd64', 'daily', deploy=true) + self.deploy_graalvm_base("java21") + {name: 'daily-deploy-vm-base-java21-darwin-amd64', notify_groups:: ["deploy"], timelimit: '1:45:00'}, deploy_vm_installables_java21_darwin_amd64: vm.vm_java_21_llvm + self.full_vm_build_darwin_amd64 + self.darwin_deploy + self.vm_base('darwin', 'amd64', 'weekly', deploy=true) + self.deploy_graalvm_components("java21", installables=true, standalones=false) + {name: 'weekly-deploy-vm-installables-java21-darwin-amd64', capabilities+: ["!macmini_late_2014"], diskspace_required: "31GB", notify_groups:: ["deploy"], timelimit: '3:00:00'}, From 9e1adbe24cb9e45f3df8889f09ffa35ff20b7e13 Mon Sep 17 00:00:00 2001 From: Danilo Ansaloni Date: Wed, 6 Dec 2023 17:55:08 +0100 Subject: [PATCH 121/593] Make the JDK version configurable. No changes in the expanded JSON. --- vm/ci/ci_common/common.jsonnet | 8 ++++---- vm/ci/ci_includes/vm.jsonnet | 20 ++++++++++---------- 2 files changed, 14 insertions(+), 14 deletions(-) diff --git a/vm/ci/ci_common/common.jsonnet b/vm/ci/ci_common/common.jsonnet index 313f1f9dffec..6a9dfb56290c 100644 --- a/vm/ci/ci_common/common.jsonnet +++ b/vm/ci/ci_common/common.jsonnet @@ -260,12 +260,12 @@ local devkits = graal_common.devkits; full_vm_build_darwin_amd64: self.ruby_python_vm_build_darwin_amd64 + self.fastr_darwin, full_vm_build_darwin_aarch64: self.ruby_python_vm_build_darwin_aarch64, - graalvm_complete_build_deps(edition, os, arch): + graalvm_complete_build_deps(edition, os, arch, java_version): local java_deps(edition) = { downloads+: { - JAVA_HOME: graal_common.jdks_data['labsjdk-' + edition + '-21'], - } + if (os == 'linux' || os == 'darwin') && (arch == 'amd64') then { - LLVM_JAVA_HOME: graal_common.jdks_data['labsjdk-' + edition + '-21-llvm'], + JAVA_HOME: graal_common.jdks_data['labsjdk-' + edition + '-' + java_version], + } + if (os == 'linux' || os == 'darwin') && (arch == 'amd64') && (java_version != 'latest') then { + LLVM_JAVA_HOME: graal_common.jdks_data['labsjdk-' + edition + '-' + java_version + '-llvm'], } else { } }; diff --git a/vm/ci/ci_includes/vm.jsonnet b/vm/ci/ci_includes/vm.jsonnet index f13bef3a7c41..192a143def02 100644 --- a/vm/ci/ci_includes/vm.jsonnet +++ b/vm/ci/ci_includes/vm.jsonnet @@ -125,51 +125,51 @@ local graal_common = import '../../../ci/ci_common/common.jsonnet'; }, # Linux/AMD64 - vm_common.graalvm_complete_build_deps('ce', 'linux', 'amd64') + vm_common.linux_deploy + vm_common.vm_base('linux', 'amd64', 'gate') + vm_common.maven_deploy_base_functions.base_object('linux', 'amd64', dry_run=true, remote_mvn_repo=$.maven_deploy_repository, remote_non_mvn_repo=$.binaries_repository, local_repo='local') + { + vm_common.graalvm_complete_build_deps('ce', 'linux', 'amd64', java_version='21') + vm_common.linux_deploy + vm_common.vm_base('linux', 'amd64', 'gate') + vm_common.maven_deploy_base_functions.base_object('linux', 'amd64', dry_run=true, remote_mvn_repo=$.maven_deploy_repository, remote_non_mvn_repo=$.binaries_repository, local_repo='local') + { name: 'gate-vm-maven-dry-run-linux-amd64', timelimit: '1:00:00', }, - vm_common.graalvm_complete_build_deps('ce', 'linux', 'amd64') + vm_common.linux_deploy + vm_common.vm_base('linux', 'amd64', 'daily', deploy=true) + vm_common.maven_deploy_base_functions.base_object('linux', 'amd64', dry_run=false, remote_mvn_repo=$.maven_deploy_repository, remote_non_mvn_repo=$.binaries_repository, local_repo='local') + { + vm_common.graalvm_complete_build_deps('ce', 'linux', 'amd64', java_version='21') + vm_common.linux_deploy + vm_common.vm_base('linux', 'amd64', 'daily', deploy=true) + vm_common.maven_deploy_base_functions.base_object('linux', 'amd64', dry_run=false, remote_mvn_repo=$.maven_deploy_repository, remote_non_mvn_repo=$.binaries_repository, local_repo='local') + { name: 'daily-deploy-vm-maven-linux-amd64', timelimit: '1:00:00', notify_groups:: ['deploy'], }, # Linux/AARCH64 - vm_common.graalvm_complete_build_deps('ce', 'linux', 'aarch64') + vm_common.linux_deploy + vm_common.vm_base('linux', 'aarch64', 'gate') + vm_common.maven_deploy_base_functions.base_object('linux', 'aarch64', dry_run=true, remote_mvn_repo=$.maven_deploy_repository, remote_non_mvn_repo=$.binaries_repository, local_repo='local') + { + vm_common.graalvm_complete_build_deps('ce', 'linux', 'aarch64', java_version='21') + vm_common.linux_deploy + vm_common.vm_base('linux', 'aarch64', 'gate') + vm_common.maven_deploy_base_functions.base_object('linux', 'aarch64', dry_run=true, remote_mvn_repo=$.maven_deploy_repository, remote_non_mvn_repo=$.binaries_repository, local_repo='local') + { name: 'gate-vm-maven-dry-run-linux-aarch64', timelimit: '1:00:00', }, - vm_common.graalvm_complete_build_deps('ce', 'linux', 'aarch64') + vm_common.linux_deploy + vm_common.vm_base('linux', 'aarch64', 'daily', deploy=true) + vm_common.maven_deploy_base_functions.base_object('linux', 'aarch64', dry_run=false, remote_mvn_repo=$.maven_deploy_repository, remote_non_mvn_repo=$.binaries_repository, local_repo='local') + { + vm_common.graalvm_complete_build_deps('ce', 'linux', 'aarch64', java_version='21') + vm_common.linux_deploy + vm_common.vm_base('linux', 'aarch64', 'daily', deploy=true) + vm_common.maven_deploy_base_functions.base_object('linux', 'aarch64', dry_run=false, remote_mvn_repo=$.maven_deploy_repository, remote_non_mvn_repo=$.binaries_repository, local_repo='local') + { name: 'daily-deploy-vm-maven-linux-aarch64', timelimit: '1:00:00', notify_groups:: ['deploy'], }, # Darwin/AMD64 - vm_common.graalvm_complete_build_deps('ce', 'darwin', 'amd64') + vm_common.darwin_deploy + vm_common.vm_base('darwin', 'amd64', 'gate') + vm_common.maven_deploy_base_functions.base_object('darwin', 'amd64', dry_run=true, remote_mvn_repo=$.maven_deploy_repository, remote_non_mvn_repo=$.binaries_repository, local_repo='local') + { + vm_common.graalvm_complete_build_deps('ce', 'darwin', 'amd64', java_version='21') + vm_common.darwin_deploy + vm_common.vm_base('darwin', 'amd64', 'gate') + vm_common.maven_deploy_base_functions.base_object('darwin', 'amd64', dry_run=true, remote_mvn_repo=$.maven_deploy_repository, remote_non_mvn_repo=$.binaries_repository, local_repo='local') + { name: 'gate-vm-maven-dry-run-darwin-amd64', timelimit: '1:00:00', }, - vm_common.graalvm_complete_build_deps('ce', 'darwin', 'amd64') + vm_common.darwin_deploy + vm_common.vm_base('darwin', 'amd64', 'daily', deploy=true) + vm_common.maven_deploy_base_functions.base_object('darwin', 'amd64', dry_run=false, remote_mvn_repo=$.maven_deploy_repository, remote_non_mvn_repo=$.binaries_repository, local_repo='local') + { + vm_common.graalvm_complete_build_deps('ce', 'darwin', 'amd64', java_version='21') + vm_common.darwin_deploy + vm_common.vm_base('darwin', 'amd64', 'daily', deploy=true) + vm_common.maven_deploy_base_functions.base_object('darwin', 'amd64', dry_run=false, remote_mvn_repo=$.maven_deploy_repository, remote_non_mvn_repo=$.binaries_repository, local_repo='local') + { name: 'daily-deploy-vm-maven-darwin-amd64', timelimit: '1:00:00', notify_groups:: ['deploy'], }, # Darwin/AARCH64 - vm_common.graalvm_complete_build_deps('ce', 'darwin', 'aarch64') + vm_common.darwin_deploy + vm_common.vm_base('darwin', 'aarch64', 'gate') + vm_common.maven_deploy_base_functions.base_object('darwin', 'aarch64', dry_run=true, remote_mvn_repo=$.maven_deploy_repository, remote_non_mvn_repo=$.binaries_repository, local_repo='local') + { + vm_common.graalvm_complete_build_deps('ce', 'darwin', 'aarch64', java_version='21') + vm_common.darwin_deploy + vm_common.vm_base('darwin', 'aarch64', 'gate') + vm_common.maven_deploy_base_functions.base_object('darwin', 'aarch64', dry_run=true, remote_mvn_repo=$.maven_deploy_repository, remote_non_mvn_repo=$.binaries_repository, local_repo='local') + { name: 'gate-vm-maven-dry-run-darwin-aarch64', timelimit: '1:00:00', }, - vm_common.graalvm_complete_build_deps('ce', 'darwin', 'aarch64') + vm_common.darwin_deploy + vm_common.vm_base('darwin', 'aarch64', 'daily', deploy=true) + vm_common.maven_deploy_base_functions.base_object('darwin', 'aarch64', dry_run=false, remote_mvn_repo=$.maven_deploy_repository, remote_non_mvn_repo=$.binaries_repository, local_repo='local') + { + vm_common.graalvm_complete_build_deps('ce', 'darwin', 'aarch64', java_version='21') + vm_common.darwin_deploy + vm_common.vm_base('darwin', 'aarch64', 'daily', deploy=true) + vm_common.maven_deploy_base_functions.base_object('darwin', 'aarch64', dry_run=false, remote_mvn_repo=$.maven_deploy_repository, remote_non_mvn_repo=$.binaries_repository, local_repo='local') + { name: 'daily-deploy-vm-maven-darwin-aarch64', timelimit: '1:00:00', notify_groups:: ['deploy'], }, # Windows/AMD64 - vm_common.graalvm_complete_build_deps('ce', 'windows', 'amd64') + vm_common.deploy_build + vm_common.vm_base('windows', 'amd64', 'gate') + vm_common.maven_deploy_base_functions.base_object('windows', 'amd64', dry_run=true, remote_mvn_repo=$.maven_deploy_repository, remote_non_mvn_repo=$.binaries_repository, local_repo='local') + { + vm_common.graalvm_complete_build_deps('ce', 'windows', 'amd64', java_version='21') + vm_common.deploy_build + vm_common.vm_base('windows', 'amd64', 'gate') + vm_common.maven_deploy_base_functions.base_object('windows', 'amd64', dry_run=true, remote_mvn_repo=$.maven_deploy_repository, remote_non_mvn_repo=$.binaries_repository, local_repo='local') + { name: 'gate-vm-maven-dry-run-windows-amd64', timelimit: '1:00:00', }, - vm_common.graalvm_complete_build_deps('ce', 'windows', 'amd64') + vm_common.deploy_build + vm_common.vm_base('windows', 'amd64', 'daily', deploy=true, jdk_hint='21') + vm_common.maven_deploy_base_functions.base_object('windows', 'amd64', dry_run=false, remote_mvn_repo=$.maven_deploy_repository, remote_non_mvn_repo=$.binaries_repository, local_repo='local') + { + vm_common.graalvm_complete_build_deps('ce', 'windows', 'amd64', java_version='21') + vm_common.deploy_build + vm_common.vm_base('windows', 'amd64', 'daily', deploy=true, jdk_hint='21') + vm_common.maven_deploy_base_functions.base_object('windows', 'amd64', dry_run=false, remote_mvn_repo=$.maven_deploy_repository, remote_non_mvn_repo=$.binaries_repository, local_repo='local') + { name: 'daily-deploy-vm-maven-windows-amd64', timelimit: '1:00:00', notify_groups:: ['deploy'], From e55f6564670d10bc3d16d600ef2869a41def83ac Mon Sep 17 00:00:00 2001 From: Danilo Ansaloni Date: Wed, 6 Dec 2023 17:57:06 +0100 Subject: [PATCH 122/593] Use JDK-latest to build artifacts to be deployed on Maven. --- vm/ci/ci_includes/vm.jsonnet | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/vm/ci/ci_includes/vm.jsonnet b/vm/ci/ci_includes/vm.jsonnet index 192a143def02..6bbdf7f3cbc6 100644 --- a/vm/ci/ci_includes/vm.jsonnet +++ b/vm/ci/ci_includes/vm.jsonnet @@ -125,51 +125,51 @@ local graal_common = import '../../../ci/ci_common/common.jsonnet'; }, # Linux/AMD64 - vm_common.graalvm_complete_build_deps('ce', 'linux', 'amd64', java_version='21') + vm_common.linux_deploy + vm_common.vm_base('linux', 'amd64', 'gate') + vm_common.maven_deploy_base_functions.base_object('linux', 'amd64', dry_run=true, remote_mvn_repo=$.maven_deploy_repository, remote_non_mvn_repo=$.binaries_repository, local_repo='local') + { + vm_common.graalvm_complete_build_deps('ce', 'linux', 'amd64', java_version='latest') + vm_common.linux_deploy + vm_common.vm_base('linux', 'amd64', 'gate') + vm_common.maven_deploy_base_functions.base_object('linux', 'amd64', dry_run=true, remote_mvn_repo=$.maven_deploy_repository, remote_non_mvn_repo=$.binaries_repository, local_repo='local') + { name: 'gate-vm-maven-dry-run-linux-amd64', timelimit: '1:00:00', }, - vm_common.graalvm_complete_build_deps('ce', 'linux', 'amd64', java_version='21') + vm_common.linux_deploy + vm_common.vm_base('linux', 'amd64', 'daily', deploy=true) + vm_common.maven_deploy_base_functions.base_object('linux', 'amd64', dry_run=false, remote_mvn_repo=$.maven_deploy_repository, remote_non_mvn_repo=$.binaries_repository, local_repo='local') + { + vm_common.graalvm_complete_build_deps('ce', 'linux', 'amd64', java_version='latest') + vm_common.linux_deploy + vm_common.vm_base('linux', 'amd64', 'daily', deploy=true) + vm_common.maven_deploy_base_functions.base_object('linux', 'amd64', dry_run=false, remote_mvn_repo=$.maven_deploy_repository, remote_non_mvn_repo=$.binaries_repository, local_repo='local') + { name: 'daily-deploy-vm-maven-linux-amd64', timelimit: '1:00:00', notify_groups:: ['deploy'], }, # Linux/AARCH64 - vm_common.graalvm_complete_build_deps('ce', 'linux', 'aarch64', java_version='21') + vm_common.linux_deploy + vm_common.vm_base('linux', 'aarch64', 'gate') + vm_common.maven_deploy_base_functions.base_object('linux', 'aarch64', dry_run=true, remote_mvn_repo=$.maven_deploy_repository, remote_non_mvn_repo=$.binaries_repository, local_repo='local') + { + vm_common.graalvm_complete_build_deps('ce', 'linux', 'aarch64', java_version='latest') + vm_common.linux_deploy + vm_common.vm_base('linux', 'aarch64', 'gate') + vm_common.maven_deploy_base_functions.base_object('linux', 'aarch64', dry_run=true, remote_mvn_repo=$.maven_deploy_repository, remote_non_mvn_repo=$.binaries_repository, local_repo='local') + { name: 'gate-vm-maven-dry-run-linux-aarch64', timelimit: '1:00:00', }, - vm_common.graalvm_complete_build_deps('ce', 'linux', 'aarch64', java_version='21') + vm_common.linux_deploy + vm_common.vm_base('linux', 'aarch64', 'daily', deploy=true) + vm_common.maven_deploy_base_functions.base_object('linux', 'aarch64', dry_run=false, remote_mvn_repo=$.maven_deploy_repository, remote_non_mvn_repo=$.binaries_repository, local_repo='local') + { + vm_common.graalvm_complete_build_deps('ce', 'linux', 'aarch64', java_version='latest') + vm_common.linux_deploy + vm_common.vm_base('linux', 'aarch64', 'daily', deploy=true) + vm_common.maven_deploy_base_functions.base_object('linux', 'aarch64', dry_run=false, remote_mvn_repo=$.maven_deploy_repository, remote_non_mvn_repo=$.binaries_repository, local_repo='local') + { name: 'daily-deploy-vm-maven-linux-aarch64', timelimit: '1:00:00', notify_groups:: ['deploy'], }, # Darwin/AMD64 - vm_common.graalvm_complete_build_deps('ce', 'darwin', 'amd64', java_version='21') + vm_common.darwin_deploy + vm_common.vm_base('darwin', 'amd64', 'gate') + vm_common.maven_deploy_base_functions.base_object('darwin', 'amd64', dry_run=true, remote_mvn_repo=$.maven_deploy_repository, remote_non_mvn_repo=$.binaries_repository, local_repo='local') + { + vm_common.graalvm_complete_build_deps('ce', 'darwin', 'amd64', java_version='latest') + vm_common.darwin_deploy + vm_common.vm_base('darwin', 'amd64', 'gate') + vm_common.maven_deploy_base_functions.base_object('darwin', 'amd64', dry_run=true, remote_mvn_repo=$.maven_deploy_repository, remote_non_mvn_repo=$.binaries_repository, local_repo='local') + { name: 'gate-vm-maven-dry-run-darwin-amd64', timelimit: '1:00:00', }, - vm_common.graalvm_complete_build_deps('ce', 'darwin', 'amd64', java_version='21') + vm_common.darwin_deploy + vm_common.vm_base('darwin', 'amd64', 'daily', deploy=true) + vm_common.maven_deploy_base_functions.base_object('darwin', 'amd64', dry_run=false, remote_mvn_repo=$.maven_deploy_repository, remote_non_mvn_repo=$.binaries_repository, local_repo='local') + { + vm_common.graalvm_complete_build_deps('ce', 'darwin', 'amd64', java_version='latest') + vm_common.darwin_deploy + vm_common.vm_base('darwin', 'amd64', 'daily', deploy=true) + vm_common.maven_deploy_base_functions.base_object('darwin', 'amd64', dry_run=false, remote_mvn_repo=$.maven_deploy_repository, remote_non_mvn_repo=$.binaries_repository, local_repo='local') + { name: 'daily-deploy-vm-maven-darwin-amd64', timelimit: '1:00:00', notify_groups:: ['deploy'], }, # Darwin/AARCH64 - vm_common.graalvm_complete_build_deps('ce', 'darwin', 'aarch64', java_version='21') + vm_common.darwin_deploy + vm_common.vm_base('darwin', 'aarch64', 'gate') + vm_common.maven_deploy_base_functions.base_object('darwin', 'aarch64', dry_run=true, remote_mvn_repo=$.maven_deploy_repository, remote_non_mvn_repo=$.binaries_repository, local_repo='local') + { + vm_common.graalvm_complete_build_deps('ce', 'darwin', 'aarch64', java_version='latest') + vm_common.darwin_deploy + vm_common.vm_base('darwin', 'aarch64', 'gate') + vm_common.maven_deploy_base_functions.base_object('darwin', 'aarch64', dry_run=true, remote_mvn_repo=$.maven_deploy_repository, remote_non_mvn_repo=$.binaries_repository, local_repo='local') + { name: 'gate-vm-maven-dry-run-darwin-aarch64', timelimit: '1:00:00', }, - vm_common.graalvm_complete_build_deps('ce', 'darwin', 'aarch64', java_version='21') + vm_common.darwin_deploy + vm_common.vm_base('darwin', 'aarch64', 'daily', deploy=true) + vm_common.maven_deploy_base_functions.base_object('darwin', 'aarch64', dry_run=false, remote_mvn_repo=$.maven_deploy_repository, remote_non_mvn_repo=$.binaries_repository, local_repo='local') + { + vm_common.graalvm_complete_build_deps('ce', 'darwin', 'aarch64', java_version='latest') + vm_common.darwin_deploy + vm_common.vm_base('darwin', 'aarch64', 'daily', deploy=true) + vm_common.maven_deploy_base_functions.base_object('darwin', 'aarch64', dry_run=false, remote_mvn_repo=$.maven_deploy_repository, remote_non_mvn_repo=$.binaries_repository, local_repo='local') + { name: 'daily-deploy-vm-maven-darwin-aarch64', timelimit: '1:00:00', notify_groups:: ['deploy'], }, # Windows/AMD64 - vm_common.graalvm_complete_build_deps('ce', 'windows', 'amd64', java_version='21') + vm_common.deploy_build + vm_common.vm_base('windows', 'amd64', 'gate') + vm_common.maven_deploy_base_functions.base_object('windows', 'amd64', dry_run=true, remote_mvn_repo=$.maven_deploy_repository, remote_non_mvn_repo=$.binaries_repository, local_repo='local') + { + vm_common.graalvm_complete_build_deps('ce', 'windows', 'amd64', java_version='latest') + vm_common.deploy_build + vm_common.vm_base('windows', 'amd64', 'gate') + vm_common.maven_deploy_base_functions.base_object('windows', 'amd64', dry_run=true, remote_mvn_repo=$.maven_deploy_repository, remote_non_mvn_repo=$.binaries_repository, local_repo='local') + { name: 'gate-vm-maven-dry-run-windows-amd64', timelimit: '1:00:00', }, - vm_common.graalvm_complete_build_deps('ce', 'windows', 'amd64', java_version='21') + vm_common.deploy_build + vm_common.vm_base('windows', 'amd64', 'daily', deploy=true, jdk_hint='21') + vm_common.maven_deploy_base_functions.base_object('windows', 'amd64', dry_run=false, remote_mvn_repo=$.maven_deploy_repository, remote_non_mvn_repo=$.binaries_repository, local_repo='local') + { + vm_common.graalvm_complete_build_deps('ce', 'windows', 'amd64', java_version='latest') + vm_common.deploy_build + vm_common.vm_base('windows', 'amd64', 'daily', deploy=true, jdk_hint='21') + vm_common.maven_deploy_base_functions.base_object('windows', 'amd64', dry_run=false, remote_mvn_repo=$.maven_deploy_repository, remote_non_mvn_repo=$.binaries_repository, local_repo='local') + { name: 'daily-deploy-vm-maven-windows-amd64', timelimit: '1:00:00', notify_groups:: ['deploy'], From a2e7e272f27353d0957bd6b686c25c067d9047cf Mon Sep 17 00:00:00 2001 From: Danilo Ansaloni Date: Wed, 6 Dec 2023 18:06:40 +0100 Subject: [PATCH 123/593] Reduce the frequency of the deployment of JDK21-based artifacts. --- vm/ci/ci_common/common.jsonnet | 12 ++++++------ vm/ci/ci_includes/vm.jsonnet | 12 ++++++------ 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/vm/ci/ci_common/common.jsonnet b/vm/ci/ci_common/common.jsonnet index 6a9dfb56290c..1b6851310567 100644 --- a/vm/ci/ci_common/common.jsonnet +++ b/vm/ci/ci_common/common.jsonnet @@ -646,8 +646,8 @@ local devkits = graal_common.devkits; deploy_vm_base_javaLatest_linux_amd64: vm.vm_java_Latest + self.full_vm_build_linux_amd64 + self.linux_deploy + self.vm_base('linux', 'amd64', 'post-merge', deploy=true) + self.deploy_graalvm_base('latest') + {name: 'post-merge-deploy-vm-base-java-latest-linux-amd64', notify_groups:: ["deploy"]}, deploy_vm_installables_standalones_javaLatest_linux_amd64: vm.vm_java_Latest + self.full_vm_build_linux_amd64 + self.linux_deploy + self.vm_base('linux', 'amd64', 'daily', deploy=true) + self.deploy_graalvm_components('latest', installables=false, standalones=true, record_file_sizes=true) + {name: 'daily-deploy-vm-installables-standalones-java-latest-linux-amd64', notify_groups:: ["deploy"]}, # - JDK21 - deploy_vm_base_java21_linux_amd64: vm.vm_java_21 + self.full_vm_build_linux_amd64 + self.linux_deploy + self.vm_base('linux', 'amd64', 'post-merge', deploy=true) + self.deploy_graalvm_base("java21") + {name: 'post-merge-deploy-vm-base-java21-linux-amd64', notify_groups:: ["deploy"]}, - deploy_vm_installables_standalones_java21_linux_amd64: vm.vm_java_21_llvm + self.full_vm_build_linux_amd64 + self.linux_deploy + self.vm_base('linux', 'amd64', 'daily', deploy=true) + self.deploy_graalvm_components("java21", installables=true, standalones=true, record_file_sizes=true) + {name: 'daily-deploy-vm-installables-standalones-java21-linux-amd64', notify_groups:: ["deploy"]}, + deploy_vm_base_java21_linux_amd64: vm.vm_java_21 + self.full_vm_build_linux_amd64 + self.linux_deploy + self.vm_base('linux', 'amd64', 'daily', deploy=true) + self.deploy_graalvm_base("java21") + {name: 'daily-deploy-vm-base-java21-linux-amd64', notify_groups:: ["deploy"]}, + deploy_vm_installables_standalones_java21_linux_amd64: vm.vm_java_21_llvm + self.full_vm_build_linux_amd64 + self.linux_deploy + self.vm_base('linux', 'amd64', 'weekly', deploy=true) + self.deploy_graalvm_components("java21", installables=true, standalones=true, record_file_sizes=true) + {name: 'weekly-deploy-vm-installables-standalones-java21-linux-amd64', notify_groups:: ["deploy"]}, # Linux/AARCH64 # - JDK-Latest @@ -655,7 +655,7 @@ local devkits = graal_common.devkits; deploy_vm_installables_standalones_javaLatest_linux_aarch64: vm.vm_java_Latest + self.full_vm_build_linux_aarch64 + self.linux_deploy + self.vm_base('linux', 'aarch64', 'daily', deploy=true) + self.deploy_graalvm_components('latest', installables=false, standalones=true) + {name: 'daily-deploy-vm-installables-standalones-java-latest-linux-aarch64', notify_groups:: ["deploy"], capabilities+: ["!xgene3"]}, # - JDK21 deploy_vm_base_java21_linux_aarch64: vm.vm_java_21 + self.full_vm_build_linux_aarch64 + self.linux_deploy + self.vm_base('linux', 'aarch64', 'daily', deploy=true) + self.deploy_graalvm_base("java21") + {name: 'daily-deploy-vm-base-java21-linux-aarch64', notify_groups:: ["deploy"], timelimit: '1:30:00', capabilities+: ["!xgene3"]}, - deploy_vm_installables_standalones_java21_linux_aarch64: vm.vm_java_21 + self.full_vm_build_linux_aarch64 + self.linux_deploy + self.vm_base('linux', 'aarch64', 'daily', deploy=true) + self.deploy_graalvm_components("java21", installables=true, standalones=true) + {name: 'daily-deploy-vm-installables-standalones-java21-linux-aarch64', notify_groups:: ["deploy"], capabilities+: ["!xgene3"]}, + deploy_vm_installables_standalones_java21_linux_aarch64: vm.vm_java_21 + self.full_vm_build_linux_aarch64 + self.linux_deploy + self.vm_base('linux', 'aarch64', 'weekly', deploy=true) + self.deploy_graalvm_components("java21", installables=true, standalones=true) + {name: 'weekly-deploy-vm-installables-standalones-java21-linux-aarch64', notify_groups:: ["deploy"], capabilities+: ["!xgene3"]}, # Darwin/AMD64 # - JDK-Latest @@ -664,7 +664,7 @@ local devkits = graal_common.devkits; # - JDK21 deploy_vm_base_java21_darwin_amd64: vm.vm_java_21 + self.full_vm_build_darwin_amd64 + self.darwin_deploy + self.vm_base('darwin', 'amd64', 'daily', deploy=true) + self.deploy_graalvm_base("java21") + {name: 'daily-deploy-vm-base-java21-darwin-amd64', notify_groups:: ["deploy"], timelimit: '1:45:00'}, deploy_vm_installables_java21_darwin_amd64: vm.vm_java_21_llvm + self.full_vm_build_darwin_amd64 + self.darwin_deploy + self.vm_base('darwin', 'amd64', 'weekly', deploy=true) + self.deploy_graalvm_components("java21", installables=true, standalones=false) + {name: 'weekly-deploy-vm-installables-java21-darwin-amd64', capabilities+: ["!macmini_late_2014"], diskspace_required: "31GB", notify_groups:: ["deploy"], timelimit: '3:00:00'}, - deploy_vm_standalones_java21_darwin_amd64: vm.vm_java_21_llvm + self.full_vm_build_darwin_amd64 + self.darwin_deploy + self.vm_base('darwin', 'amd64', 'daily', deploy=true) + self.deploy_graalvm_components("java21", installables=false, standalones=true) + {name: 'daily-deploy-vm-standalones-java21-darwin-amd64', capabilities+: ["!macmini_late_2014"], diskspace_required: "31GB", notify_groups:: ["deploy"], timelimit: '3:00:00'}, + deploy_vm_standalones_java21_darwin_amd64: vm.vm_java_21_llvm + self.full_vm_build_darwin_amd64 + self.darwin_deploy + self.vm_base('darwin', 'amd64', 'weekly', deploy=true) + self.deploy_graalvm_components("java21", installables=false, standalones=true) + {name: 'weekly-deploy-vm-standalones-java21-darwin-amd64', capabilities+: ["!macmini_late_2014"], diskspace_required: "31GB", notify_groups:: ["deploy"], timelimit: '3:00:00'}, # Darwin/AARCH64 # - JDK-Latest @@ -673,7 +673,7 @@ local devkits = graal_common.devkits; # - JDK21 deploy_vm_base_java21_darwin_aarch64: vm.vm_java_21 + self.full_vm_build_darwin_aarch64 + self.darwin_deploy + self.vm_base('darwin', 'aarch64', 'daily', deploy=true) + self.deploy_graalvm_base("java21") + {name: 'daily-deploy-vm-base-java21-darwin-aarch64', notify_groups:: ["deploy"], notify_emails+: ["bernhard.urban-forster@oracle.com"], timelimit: '1:45:00'}, deploy_vm_installables_java21_darwin_aarch64: vm.vm_java_21 + self.full_vm_build_darwin_aarch64 + self.darwin_deploy + self.vm_base('darwin', 'aarch64', 'weekly', deploy=true) + self.deploy_graalvm_components("java21", installables=true, standalones=false) + {name: 'weekly-deploy-vm-installables-java21-darwin-aarch64', diskspace_required: "31GB", notify_groups:: ["deploy"], notify_emails+: ["bernhard.urban-forster@oracle.com"], timelimit: '3:00:00'}, - deploy_vm_standalones_java21_darwin_aarch64: vm.vm_java_21 + self.full_vm_build_darwin_aarch64 + self.darwin_deploy + self.vm_base('darwin', 'aarch64', 'daily', deploy=true) + self.deploy_graalvm_components("java21", installables=false, standalones=true) + {name: 'daily-deploy-vm-standalones-java21-darwin-aarch64', diskspace_required: "31GB", notify_groups:: ["deploy"], notify_emails+: ["bernhard.urban-forster@oracle.com"], timelimit: '3:00:00'}, + deploy_vm_standalones_java21_darwin_aarch64: vm.vm_java_21 + self.full_vm_build_darwin_aarch64 + self.darwin_deploy + self.vm_base('darwin', 'aarch64', 'weekly', deploy=true) + self.deploy_graalvm_components("java21", installables=false, standalones=true) + {name: 'weekly-deploy-vm-standalones-java21-darwin-aarch64', diskspace_required: "31GB", notify_groups:: ["deploy"], notify_emails+: ["bernhard.urban-forster@oracle.com"], timelimit: '3:00:00'}, # Windows/AMD64 # - JDK-Latest @@ -682,7 +682,7 @@ local devkits = graal_common.devkits; # - JDK21 deploy_vm_base_java21_windows_amd64: vm.vm_java_21 + self.svm_common_windows_amd64("21") + self.js_windows_common + self.vm_base('windows', 'amd64', 'daily', deploy=true, jdk_hint='21') + self.deploy_graalvm_base("java21") + self.deploy_build + {name: 'daily-deploy-vm-base-java21-windows-amd64', notify_groups:: ["deploy"], timelimit: '1:30:00'}, deploy_vm_installables_java21_windows_amd64: vm.vm_java_21 + self.svm_common_windows_amd64("21") + self.js_windows_common + self.sulong_windows + self.vm_base('windows', 'amd64', 'weekly', deploy=true, jdk_hint='21') + self.deploy_graalvm_components("java21", installables=true, standalones=false) + self.deploy_build + {name: 'weekly-deploy-vm-installables-java21-windows-amd64', diskspace_required: "31GB", timelimit: '2:30:00', notify_groups:: ["deploy"]}, - deploy_vm_standalones_java21_windows_amd64: vm.vm_java_21 + self.svm_common_windows_amd64("21") + self.js_windows_common + self.sulong_windows + self.vm_base('windows', 'amd64', 'daily', deploy=true, jdk_hint='21') + self.deploy_graalvm_components("java21", installables=false, standalones=true) + self.deploy_build + {name: 'daily-deploy-vm-standalones-java21-windows-amd64', diskspace_required: "31GB", timelimit: '2:30:00', notify_groups:: ["deploy"]}, + deploy_vm_standalones_java21_windows_amd64: vm.vm_java_21 + self.svm_common_windows_amd64("21") + self.js_windows_common + self.sulong_windows + self.vm_base('windows', 'amd64', 'weekly', deploy=true, jdk_hint='21') + self.deploy_graalvm_components("java21", installables=false, standalones=true) + self.deploy_build + {name: 'weekly-deploy-vm-standalones-java21-windows-amd64', diskspace_required: "31GB", timelimit: '2:30:00', notify_groups:: ["deploy"]}, # # Deploy the GraalVM Espresso artifact (GraalVM Base + espresso - native image) diff --git a/vm/ci/ci_includes/vm.jsonnet b/vm/ci/ci_includes/vm.jsonnet index 6bbdf7f3cbc6..c4077895354f 100644 --- a/vm/ci/ci_includes/vm.jsonnet +++ b/vm/ci/ci_includes/vm.jsonnet @@ -54,16 +54,16 @@ local graal_common = import '../../../ci/ci_common/common.jsonnet'; ['test', ['git', 'rev-parse', '--abbrev-ref', 'HEAD'], '!=', 'master', '||'] + self.ci_resources.infra.notify_releaser_service, ], runAfter: [ - 'post-merge-deploy-vm-base-java21-linux-amd64', - 'daily-deploy-vm-installables-standalones-java21-linux-amd64', + 'daily-deploy-vm-base-java21-linux-amd64', + 'weekly-deploy-vm-installables-standalones-java21-linux-amd64', 'daily-deploy-vm-base-java21-linux-aarch64', - 'daily-deploy-vm-installables-standalones-java21-linux-aarch64', + 'weekly-deploy-vm-installables-standalones-java21-linux-aarch64', 'daily-deploy-vm-base-java21-darwin-amd64', - 'daily-deploy-vm-standalones-java21-darwin-amd64', + 'weekly-deploy-vm-standalones-java21-darwin-amd64', 'daily-deploy-vm-base-java21-darwin-aarch64', - 'daily-deploy-vm-standalones-java21-darwin-aarch64', + 'weekly-deploy-vm-standalones-java21-darwin-aarch64', 'daily-deploy-vm-base-java21-windows-amd64', - 'daily-deploy-vm-standalones-java21-windows-amd64', + 'weekly-deploy-vm-standalones-java21-windows-amd64', 'daily-deploy-vm-maven-linux-amd64', 'daily-deploy-vm-espresso-java21-linux-amd64', 'daily-deploy-vm-espresso-java21-linux-aarch64', From eaad09d81dc317472991023416365c724c79cf90 Mon Sep 17 00:00:00 2001 From: Danilo Ansaloni Date: Wed, 6 Dec 2023 18:40:21 +0100 Subject: [PATCH 124/593] Publish dev builds based on JDK22. --- vm/ce-release-artifacts.json | 42 ++++++++++++++++++------------------ vm/ci/ci_includes/vm.jsonnet | 15 ++++++++----- 2 files changed, 31 insertions(+), 26 deletions(-) diff --git a/vm/ce-release-artifacts.json b/vm/ce-release-artifacts.json index 6c3d7c5688e5..8b0fce53735f 100644 --- a/vm/ce-release-artifacts.json +++ b/vm/ce-release-artifacts.json @@ -56,7 +56,7 @@ { "name": "maven-bundle-ce", "core": true, - "jdk": "jdk_21", + "jdk": "jdk_22", "override_name":"maven-resource-bundle", "artifacts": [ { @@ -67,9 +67,9 @@ ] }, { - "name": "js-native-standalone-svm-java21", + "name": "js-native-standalone-svm-java22", "core": true, - "jdk": "jdk_21", + "jdk": "jdk_22", "override_name":"graaljs", "artifacts": [ { @@ -100,9 +100,9 @@ ] }, { - "name": "js-java-standalone-svm-java21", + "name": "js-java-standalone-svm-java22", "core": true, - "jdk": "jdk_21", + "jdk": "jdk_22", "override_name":"graaljs", "artifacts": [ { @@ -133,9 +133,9 @@ ] }, { - "name": "nodejs-native-standalone-svm-java21", + "name": "nodejs-native-standalone-svm-java22", "core": true, - "jdk": "jdk_21", + "jdk": "jdk_22", "override_name":"graalnodejs", "artifacts": [ { @@ -166,9 +166,9 @@ ] }, { - "name": "nodejs-java-standalone-svm-java21", + "name": "nodejs-java-standalone-svm-java22", "core": true, - "jdk": "jdk_21", + "jdk": "jdk_22", "override_name":"graalnodejs", "artifacts": [ { @@ -199,9 +199,9 @@ ] }, { - "name": "ruby-native-standalone-svm-java21", + "name": "ruby-native-standalone-svm-java22", "core": true, - "jdk": "jdk_21", + "jdk": "jdk_22", "override_name":"truffleruby", "artifacts": [ { @@ -227,9 +227,9 @@ ] }, { - "name": "ruby-java-standalone-svm-java21", + "name": "ruby-java-standalone-svm-java22", "core": true, - "jdk": "jdk_21", + "jdk": "jdk_22", "override_name":"truffleruby", "artifacts": [ { @@ -255,9 +255,9 @@ ] }, { - "name": "python-native-standalone-svm-java21", + "name": "python-native-standalone-svm-java22", "core": true, - "jdk": "jdk_21", + "jdk": "jdk_22", "override_name":"graalpy", "artifacts": [ { @@ -288,9 +288,9 @@ ] }, { - "name": "python-java-standalone-svm-java21", + "name": "python-java-standalone-svm-java22", "core": true, - "jdk": "jdk_21", + "jdk": "jdk_22", "override_name":"graalpy", "artifacts": [ { @@ -321,9 +321,9 @@ ] }, { - "name": "wasm-native-standalone-svm-java21", + "name": "wasm-native-standalone-svm-java22", "core": true, - "jdk": "jdk_21", + "jdk": "jdk_22", "override_name": "graalwasm", "artifacts": [ { @@ -354,9 +354,9 @@ ] }, { - "name": "wasm-java-standalone-svm-java21", + "name": "wasm-java-standalone-svm-java22", "core": true, - "jdk": "jdk_21", + "jdk": "jdk_22", "override_name": "graalwasm", "artifacts": [ { diff --git a/vm/ci/ci_includes/vm.jsonnet b/vm/ci/ci_includes/vm.jsonnet index c4077895354f..25217a9a3239 100644 --- a/vm/ci/ci_includes/vm.jsonnet +++ b/vm/ci/ci_includes/vm.jsonnet @@ -55,15 +55,20 @@ local graal_common = import '../../../ci/ci_common/common.jsonnet'; ], runAfter: [ 'daily-deploy-vm-base-java21-linux-amd64', - 'weekly-deploy-vm-installables-standalones-java21-linux-amd64', + 'post-merge-deploy-vm-base-java-latest-linux-amd64', + 'daily-deploy-vm-installables-standalones-java-latest-linux-amd64', 'daily-deploy-vm-base-java21-linux-aarch64', - 'weekly-deploy-vm-installables-standalones-java21-linux-aarch64', + 'daily-deploy-vm-base-java-latest-linux-aarch64', + 'daily-deploy-vm-installables-standalones-java-latest-linux-aarch64', 'daily-deploy-vm-base-java21-darwin-amd64', - 'weekly-deploy-vm-standalones-java21-darwin-amd64', + 'daily-deploy-vm-base-java-latest-darwin-amd64', + 'daily-deploy-vm-standalones-java-latest-darwin-amd64', 'daily-deploy-vm-base-java21-darwin-aarch64', - 'weekly-deploy-vm-standalones-java21-darwin-aarch64', + 'daily-deploy-vm-base-java-latest-darwin-aarch64', + 'daily-deploy-vm-standalones-java-latest-darwin-aarch64', 'daily-deploy-vm-base-java21-windows-amd64', - 'weekly-deploy-vm-standalones-java21-windows-amd64', + 'daily-deploy-vm-base-java-latest-windows-amd64', + 'daily-deploy-vm-standalones-java-latest-windows-amd64', 'daily-deploy-vm-maven-linux-amd64', 'daily-deploy-vm-espresso-java21-linux-amd64', 'daily-deploy-vm-espresso-java21-linux-aarch64', From 34c56dcd81c730da146f0120eca2f91a347b9f28 Mon Sep 17 00:00:00 2001 From: Danilo Ansaloni Date: Wed, 6 Dec 2023 18:42:48 +0100 Subject: [PATCH 125/593] Do not publish base GraalVM dev builds for JDK21. --- vm/ce-release-artifacts.json | 27 --------------------------- vm/ci/ci_includes/vm.jsonnet | 5 ----- 2 files changed, 32 deletions(-) diff --git a/vm/ce-release-artifacts.json b/vm/ce-release-artifacts.json index 8b0fce53735f..14a29a02e1c1 100644 --- a/vm/ce-release-artifacts.json +++ b/vm/ce-release-artifacts.json @@ -1,31 +1,4 @@ [ - { - "name": "graalvm-community-java21", - "core": true, - "jdk": "jdk_21", - "artifacts": [ - { - "os": "linux", - "arch": "amd64" - }, - { - "os": "linux", - "arch": "aarch64" - }, - { - "os": "darwin", - "arch": "amd64" - }, - { - "os": "darwin", - "arch": "aarch64" - }, - { - "os": "windows", - "arch": "amd64" - } - ] - }, { "name": "graalvm-community-java22", "core": true, diff --git a/vm/ci/ci_includes/vm.jsonnet b/vm/ci/ci_includes/vm.jsonnet index 25217a9a3239..363eb79a64b1 100644 --- a/vm/ci/ci_includes/vm.jsonnet +++ b/vm/ci/ci_includes/vm.jsonnet @@ -54,19 +54,14 @@ local graal_common = import '../../../ci/ci_common/common.jsonnet'; ['test', ['git', 'rev-parse', '--abbrev-ref', 'HEAD'], '!=', 'master', '||'] + self.ci_resources.infra.notify_releaser_service, ], runAfter: [ - 'daily-deploy-vm-base-java21-linux-amd64', 'post-merge-deploy-vm-base-java-latest-linux-amd64', 'daily-deploy-vm-installables-standalones-java-latest-linux-amd64', - 'daily-deploy-vm-base-java21-linux-aarch64', 'daily-deploy-vm-base-java-latest-linux-aarch64', 'daily-deploy-vm-installables-standalones-java-latest-linux-aarch64', - 'daily-deploy-vm-base-java21-darwin-amd64', 'daily-deploy-vm-base-java-latest-darwin-amd64', 'daily-deploy-vm-standalones-java-latest-darwin-amd64', - 'daily-deploy-vm-base-java21-darwin-aarch64', 'daily-deploy-vm-base-java-latest-darwin-aarch64', 'daily-deploy-vm-standalones-java-latest-darwin-aarch64', - 'daily-deploy-vm-base-java21-windows-amd64', 'daily-deploy-vm-base-java-latest-windows-amd64', 'daily-deploy-vm-standalones-java-latest-windows-amd64', 'daily-deploy-vm-maven-linux-amd64', From 64834197de6a5ebfe1741f7e89e89d0857a92c5d Mon Sep 17 00:00:00 2001 From: Danilo Ansaloni Date: Wed, 6 Dec 2023 18:44:22 +0100 Subject: [PATCH 126/593] Reduce the frequency of the deployment of JDK21-based artifacts. --- vm/ci/ci_common/common.jsonnet | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/vm/ci/ci_common/common.jsonnet b/vm/ci/ci_common/common.jsonnet index 1b6851310567..c6e70f24d289 100644 --- a/vm/ci/ci_common/common.jsonnet +++ b/vm/ci/ci_common/common.jsonnet @@ -646,7 +646,7 @@ local devkits = graal_common.devkits; deploy_vm_base_javaLatest_linux_amd64: vm.vm_java_Latest + self.full_vm_build_linux_amd64 + self.linux_deploy + self.vm_base('linux', 'amd64', 'post-merge', deploy=true) + self.deploy_graalvm_base('latest') + {name: 'post-merge-deploy-vm-base-java-latest-linux-amd64', notify_groups:: ["deploy"]}, deploy_vm_installables_standalones_javaLatest_linux_amd64: vm.vm_java_Latest + self.full_vm_build_linux_amd64 + self.linux_deploy + self.vm_base('linux', 'amd64', 'daily', deploy=true) + self.deploy_graalvm_components('latest', installables=false, standalones=true, record_file_sizes=true) + {name: 'daily-deploy-vm-installables-standalones-java-latest-linux-amd64', notify_groups:: ["deploy"]}, # - JDK21 - deploy_vm_base_java21_linux_amd64: vm.vm_java_21 + self.full_vm_build_linux_amd64 + self.linux_deploy + self.vm_base('linux', 'amd64', 'daily', deploy=true) + self.deploy_graalvm_base("java21") + {name: 'daily-deploy-vm-base-java21-linux-amd64', notify_groups:: ["deploy"]}, + deploy_vm_base_java21_linux_amd64: vm.vm_java_21 + self.full_vm_build_linux_amd64 + self.linux_deploy + self.vm_base('linux', 'amd64', 'weekly', deploy=true) + self.deploy_graalvm_base("java21") + {name: 'weekly-deploy-vm-base-java21-linux-amd64', notify_groups:: ["deploy"]}, deploy_vm_installables_standalones_java21_linux_amd64: vm.vm_java_21_llvm + self.full_vm_build_linux_amd64 + self.linux_deploy + self.vm_base('linux', 'amd64', 'weekly', deploy=true) + self.deploy_graalvm_components("java21", installables=true, standalones=true, record_file_sizes=true) + {name: 'weekly-deploy-vm-installables-standalones-java21-linux-amd64', notify_groups:: ["deploy"]}, # Linux/AARCH64 @@ -654,7 +654,7 @@ local devkits = graal_common.devkits; deploy_vm_base_javaLatest_linux_aarch64: vm.vm_java_Latest + self.full_vm_build_linux_aarch64 + self.linux_deploy + self.vm_base('linux', 'aarch64', 'daily', deploy=true) + self.deploy_graalvm_base('latest') + {name: 'daily-deploy-vm-base-java-latest-linux-aarch64', notify_groups:: ["deploy"], timelimit: '1:30:00', capabilities+: ["!xgene3"]}, deploy_vm_installables_standalones_javaLatest_linux_aarch64: vm.vm_java_Latest + self.full_vm_build_linux_aarch64 + self.linux_deploy + self.vm_base('linux', 'aarch64', 'daily', deploy=true) + self.deploy_graalvm_components('latest', installables=false, standalones=true) + {name: 'daily-deploy-vm-installables-standalones-java-latest-linux-aarch64', notify_groups:: ["deploy"], capabilities+: ["!xgene3"]}, # - JDK21 - deploy_vm_base_java21_linux_aarch64: vm.vm_java_21 + self.full_vm_build_linux_aarch64 + self.linux_deploy + self.vm_base('linux', 'aarch64', 'daily', deploy=true) + self.deploy_graalvm_base("java21") + {name: 'daily-deploy-vm-base-java21-linux-aarch64', notify_groups:: ["deploy"], timelimit: '1:30:00', capabilities+: ["!xgene3"]}, + deploy_vm_base_java21_linux_aarch64: vm.vm_java_21 + self.full_vm_build_linux_aarch64 + self.linux_deploy + self.vm_base('linux', 'aarch64', 'weekly', deploy=true) + self.deploy_graalvm_base("java21") + {name: 'weekly-deploy-vm-base-java21-linux-aarch64', notify_groups:: ["deploy"], timelimit: '1:30:00', capabilities+: ["!xgene3"]}, deploy_vm_installables_standalones_java21_linux_aarch64: vm.vm_java_21 + self.full_vm_build_linux_aarch64 + self.linux_deploy + self.vm_base('linux', 'aarch64', 'weekly', deploy=true) + self.deploy_graalvm_components("java21", installables=true, standalones=true) + {name: 'weekly-deploy-vm-installables-standalones-java21-linux-aarch64', notify_groups:: ["deploy"], capabilities+: ["!xgene3"]}, # Darwin/AMD64 @@ -662,7 +662,7 @@ local devkits = graal_common.devkits; deploy_vm_base_javaLatest_darwin_amd64: vm.vm_java_Latest + self.full_vm_build_darwin_amd64 + self.darwin_deploy + self.vm_base('darwin', 'amd64', 'daily', deploy=true, jdk_hint='Latest') + self.deploy_graalvm_base('latest') + {name: 'daily-deploy-vm-base-java-latest-darwin-amd64', notify_groups:: ["deploy"], timelimit: '1:45:00'}, deploy_vm_standalones_javaLatest_darwin_amd64: vm.vm_java_Latest + self.full_vm_build_darwin_amd64 + self.darwin_deploy + self.vm_base('darwin', 'amd64', 'daily', deploy=true, jdk_hint='Latest') + self.deploy_graalvm_components('latest', installables=false, standalones=true) + {name: 'daily-deploy-vm-standalones-java-latest-darwin-amd64', capabilities+: ["!macmini_late_2014"], diskspace_required: "31GB", notify_groups:: ["deploy"], timelimit: '3:00:00'}, # - JDK21 - deploy_vm_base_java21_darwin_amd64: vm.vm_java_21 + self.full_vm_build_darwin_amd64 + self.darwin_deploy + self.vm_base('darwin', 'amd64', 'daily', deploy=true) + self.deploy_graalvm_base("java21") + {name: 'daily-deploy-vm-base-java21-darwin-amd64', notify_groups:: ["deploy"], timelimit: '1:45:00'}, + deploy_vm_base_java21_darwin_amd64: vm.vm_java_21 + self.full_vm_build_darwin_amd64 + self.darwin_deploy + self.vm_base('darwin', 'amd64', 'weekly', deploy=true) + self.deploy_graalvm_base("java21") + {name: 'weekly-deploy-vm-base-java21-darwin-amd64', notify_groups:: ["deploy"], timelimit: '1:45:00'}, deploy_vm_installables_java21_darwin_amd64: vm.vm_java_21_llvm + self.full_vm_build_darwin_amd64 + self.darwin_deploy + self.vm_base('darwin', 'amd64', 'weekly', deploy=true) + self.deploy_graalvm_components("java21", installables=true, standalones=false) + {name: 'weekly-deploy-vm-installables-java21-darwin-amd64', capabilities+: ["!macmini_late_2014"], diskspace_required: "31GB", notify_groups:: ["deploy"], timelimit: '3:00:00'}, deploy_vm_standalones_java21_darwin_amd64: vm.vm_java_21_llvm + self.full_vm_build_darwin_amd64 + self.darwin_deploy + self.vm_base('darwin', 'amd64', 'weekly', deploy=true) + self.deploy_graalvm_components("java21", installables=false, standalones=true) + {name: 'weekly-deploy-vm-standalones-java21-darwin-amd64', capabilities+: ["!macmini_late_2014"], diskspace_required: "31GB", notify_groups:: ["deploy"], timelimit: '3:00:00'}, @@ -671,7 +671,7 @@ local devkits = graal_common.devkits; deploy_vm_base_javaLatest_darwin_aarch64: vm.vm_java_Latest + self.full_vm_build_darwin_aarch64 + self.darwin_deploy + self.vm_base('darwin', 'aarch64', 'daily', deploy=true) + self.deploy_graalvm_base('latest') + {name: 'daily-deploy-vm-base-java-latest-darwin-aarch64', notify_groups:: ["deploy"], notify_emails+: ["bernhard.urban-forster@oracle.com"], timelimit: '1:45:00'}, deploy_vm_standalones_javaLatest_darwin_aarch64: vm.vm_java_Latest + self.full_vm_build_darwin_aarch64 + self.darwin_deploy + self.vm_base('darwin', 'aarch64', 'daily', deploy=true) + self.deploy_graalvm_components('latest', installables=false, standalones=true) + {name: 'daily-deploy-vm-standalones-java-latest-darwin-aarch64', diskspace_required: "31GB", notify_groups:: ["deploy"], notify_emails+: ["bernhard.urban-forster@oracle.com"], timelimit: '3:00:00'}, # - JDK21 - deploy_vm_base_java21_darwin_aarch64: vm.vm_java_21 + self.full_vm_build_darwin_aarch64 + self.darwin_deploy + self.vm_base('darwin', 'aarch64', 'daily', deploy=true) + self.deploy_graalvm_base("java21") + {name: 'daily-deploy-vm-base-java21-darwin-aarch64', notify_groups:: ["deploy"], notify_emails+: ["bernhard.urban-forster@oracle.com"], timelimit: '1:45:00'}, + deploy_vm_base_java21_darwin_aarch64: vm.vm_java_21 + self.full_vm_build_darwin_aarch64 + self.darwin_deploy + self.vm_base('darwin', 'aarch64', 'weekly', deploy=true) + self.deploy_graalvm_base("java21") + {name: 'weekly-deploy-vm-base-java21-darwin-aarch64', notify_groups:: ["deploy"], notify_emails+: ["bernhard.urban-forster@oracle.com"], timelimit: '1:45:00'}, deploy_vm_installables_java21_darwin_aarch64: vm.vm_java_21 + self.full_vm_build_darwin_aarch64 + self.darwin_deploy + self.vm_base('darwin', 'aarch64', 'weekly', deploy=true) + self.deploy_graalvm_components("java21", installables=true, standalones=false) + {name: 'weekly-deploy-vm-installables-java21-darwin-aarch64', diskspace_required: "31GB", notify_groups:: ["deploy"], notify_emails+: ["bernhard.urban-forster@oracle.com"], timelimit: '3:00:00'}, deploy_vm_standalones_java21_darwin_aarch64: vm.vm_java_21 + self.full_vm_build_darwin_aarch64 + self.darwin_deploy + self.vm_base('darwin', 'aarch64', 'weekly', deploy=true) + self.deploy_graalvm_components("java21", installables=false, standalones=true) + {name: 'weekly-deploy-vm-standalones-java21-darwin-aarch64', diskspace_required: "31GB", notify_groups:: ["deploy"], notify_emails+: ["bernhard.urban-forster@oracle.com"], timelimit: '3:00:00'}, @@ -680,7 +680,7 @@ local devkits = graal_common.devkits; deploy_vm_base_javaLatest_windows_amd64: vm.vm_java_Latest + self.svm_common_windows_amd64('Latest') + self.js_windows_common + self.vm_base('windows', 'amd64', 'daily', deploy=true, jdk_hint='Latest') + self.deploy_graalvm_base('latest') + self.deploy_build + {name: 'daily-deploy-vm-base-java-latest-windows-amd64', notify_groups:: ["deploy"], timelimit: '1:30:00'}, deploy_vm_standalones_javaLatest_windows_amd64: vm.vm_java_Latest + self.svm_common_windows_amd64('Latest') + self.js_windows_common + self.sulong_windows + self.vm_base('windows', 'amd64', 'daily', deploy=true, jdk_hint='Latest') + self.deploy_graalvm_components('latest', installables=false, standalones=true) + self.deploy_build + {name: 'daily-deploy-vm-standalones-java-latest-windows-amd64', diskspace_required: "31GB", timelimit: '2:30:00', notify_groups:: ["deploy"]}, # - JDK21 - deploy_vm_base_java21_windows_amd64: vm.vm_java_21 + self.svm_common_windows_amd64("21") + self.js_windows_common + self.vm_base('windows', 'amd64', 'daily', deploy=true, jdk_hint='21') + self.deploy_graalvm_base("java21") + self.deploy_build + {name: 'daily-deploy-vm-base-java21-windows-amd64', notify_groups:: ["deploy"], timelimit: '1:30:00'}, + deploy_vm_base_java21_windows_amd64: vm.vm_java_21 + self.svm_common_windows_amd64("21") + self.js_windows_common + self.vm_base('windows', 'amd64', 'weekly', deploy=true, jdk_hint='21') + self.deploy_graalvm_base("java21") + self.deploy_build + {name: 'weekly-deploy-vm-base-java21-windows-amd64', notify_groups:: ["deploy"], timelimit: '1:30:00'}, deploy_vm_installables_java21_windows_amd64: vm.vm_java_21 + self.svm_common_windows_amd64("21") + self.js_windows_common + self.sulong_windows + self.vm_base('windows', 'amd64', 'weekly', deploy=true, jdk_hint='21') + self.deploy_graalvm_components("java21", installables=true, standalones=false) + self.deploy_build + {name: 'weekly-deploy-vm-installables-java21-windows-amd64', diskspace_required: "31GB", timelimit: '2:30:00', notify_groups:: ["deploy"]}, deploy_vm_standalones_java21_windows_amd64: vm.vm_java_21 + self.svm_common_windows_amd64("21") + self.js_windows_common + self.sulong_windows + self.vm_base('windows', 'amd64', 'weekly', deploy=true, jdk_hint='21') + self.deploy_graalvm_components("java21", installables=false, standalones=true) + self.deploy_build + {name: 'weekly-deploy-vm-standalones-java21-windows-amd64', diskspace_required: "31GB", timelimit: '2:30:00', notify_groups:: ["deploy"]}, From 59e9cedb3efb74b66f358498f9bfc9f664cef565 Mon Sep 17 00:00:00 2001 From: Danilo Ansaloni Date: Wed, 6 Dec 2023 19:14:10 +0100 Subject: [PATCH 127/593] JDK-latest jobs on darwin/amd64 must run on BigSur. --- vm/ci/ci_includes/vm.jsonnet | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vm/ci/ci_includes/vm.jsonnet b/vm/ci/ci_includes/vm.jsonnet index 363eb79a64b1..63cbb2ac4b72 100644 --- a/vm/ci/ci_includes/vm.jsonnet +++ b/vm/ci/ci_includes/vm.jsonnet @@ -149,7 +149,7 @@ local graal_common = import '../../../ci/ci_common/common.jsonnet'; name: 'gate-vm-maven-dry-run-darwin-amd64', timelimit: '1:00:00', }, - vm_common.graalvm_complete_build_deps('ce', 'darwin', 'amd64', java_version='latest') + vm_common.darwin_deploy + vm_common.vm_base('darwin', 'amd64', 'daily', deploy=true) + vm_common.maven_deploy_base_functions.base_object('darwin', 'amd64', dry_run=false, remote_mvn_repo=$.maven_deploy_repository, remote_non_mvn_repo=$.binaries_repository, local_repo='local') + { + vm_common.graalvm_complete_build_deps('ce', 'darwin', 'amd64', java_version='latest') + vm_common.darwin_deploy + vm_common.vm_base('darwin', 'amd64', 'daily', deploy=true, jdk_hint='Latest') + vm_common.maven_deploy_base_functions.base_object('darwin', 'amd64', dry_run=false, remote_mvn_repo=$.maven_deploy_repository, remote_non_mvn_repo=$.binaries_repository, local_repo='local') + { name: 'daily-deploy-vm-maven-darwin-amd64', timelimit: '1:00:00', notify_groups:: ['deploy'], From fb02ab0e0da9a0073ee00ae9905c58ea0ddf27f5 Mon Sep 17 00:00:00 2001 From: Danilo Ansaloni Date: Wed, 6 Dec 2023 20:42:09 +0100 Subject: [PATCH 128/593] JDK-latest jobs on darwin/amd64 must run on BigSur. --- vm/ci/ci_includes/vm.jsonnet | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vm/ci/ci_includes/vm.jsonnet b/vm/ci/ci_includes/vm.jsonnet index 63cbb2ac4b72..b13a3dfec21c 100644 --- a/vm/ci/ci_includes/vm.jsonnet +++ b/vm/ci/ci_includes/vm.jsonnet @@ -145,7 +145,7 @@ local graal_common = import '../../../ci/ci_common/common.jsonnet'; notify_groups:: ['deploy'], }, # Darwin/AMD64 - vm_common.graalvm_complete_build_deps('ce', 'darwin', 'amd64', java_version='latest') + vm_common.darwin_deploy + vm_common.vm_base('darwin', 'amd64', 'gate') + vm_common.maven_deploy_base_functions.base_object('darwin', 'amd64', dry_run=true, remote_mvn_repo=$.maven_deploy_repository, remote_non_mvn_repo=$.binaries_repository, local_repo='local') + { + vm_common.graalvm_complete_build_deps('ce', 'darwin', 'amd64', java_version='latest') + vm_common.darwin_deploy + vm_common.vm_base('darwin', 'amd64', 'gate', jdk_hint='Latest') + vm_common.maven_deploy_base_functions.base_object('darwin', 'amd64', dry_run=true, remote_mvn_repo=$.maven_deploy_repository, remote_non_mvn_repo=$.binaries_repository, local_repo='local') + { name: 'gate-vm-maven-dry-run-darwin-amd64', timelimit: '1:00:00', }, From 96efa3a8b80ddff14236c426747f3e0a80e1bc96 Mon Sep 17 00:00:00 2001 From: Danilo Ansaloni Date: Wed, 6 Dec 2023 22:16:24 +0100 Subject: [PATCH 129/593] Set `$TOOLS_HOME` when necessary. --- vm/ci/ci_common/common.jsonnet | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/vm/ci/ci_common/common.jsonnet b/vm/ci/ci_common/common.jsonnet index c6e70f24d289..be3c970b9063 100644 --- a/vm/ci/ci_common/common.jsonnet +++ b/vm/ci/ci_common/common.jsonnet @@ -264,10 +264,17 @@ local devkits = graal_common.devkits; local java_deps(edition) = { downloads+: { JAVA_HOME: graal_common.jdks_data['labsjdk-' + edition + '-' + java_version], - } + if (os == 'linux' || os == 'darwin') && (arch == 'amd64') && (java_version != 'latest') then { + } + ( + if (os == 'linux' || os == 'darwin') && (arch == 'amd64') && (java_version != 'latest') then { LLVM_JAVA_HOME: graal_common.jdks_data['labsjdk-' + edition + '-' + java_version + '-llvm'], - } else { - } + } else { + } + ) + ( + if (java_version == 'latest') then { + TOOLS_JAVA_HOME: graal_common.jdks_data['oraclejdk21'], + } else { + } + ) }; if (os == 'linux') then From 6b59cecd431065427749d52eca1a93421c276a13 Mon Sep 17 00:00:00 2001 From: Sacha Coppey Date: Thu, 9 Nov 2023 18:03:57 +0100 Subject: [PATCH 130/593] Move toUnboxedClass to SubstrateUtil --- .../com/oracle/svm/core/SubstrateUtil.java | 32 +++++++++++++++++-- .../hosted/substitute/ComputedValueField.java | 25 ++------------- 2 files changed, 31 insertions(+), 26 deletions(-) diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/SubstrateUtil.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/SubstrateUtil.java index c565552cab19..b3e38c7ceea0 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/SubstrateUtil.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/SubstrateUtil.java @@ -37,9 +37,6 @@ import java.util.regex.Matcher; import java.util.regex.Pattern; -import jdk.graal.compiler.graph.Node.NodeIntrinsic; -import jdk.graal.compiler.java.LambdaUtils; -import jdk.graal.compiler.nodes.BreakpointNode; import org.graalvm.nativeimage.Platform; import org.graalvm.nativeimage.Platforms; import org.graalvm.nativeimage.c.type.CCharPointer; @@ -57,6 +54,9 @@ import com.oracle.svm.util.ReflectionUtil; import com.oracle.svm.util.StringUtil; +import jdk.graal.compiler.graph.Node.NodeIntrinsic; +import jdk.graal.compiler.java.LambdaUtils; +import jdk.graal.compiler.nodes.BreakpointNode; import jdk.vm.ci.meta.ResolvedJavaMethod; import jdk.vm.ci.meta.ResolvedJavaType; import jdk.vm.ci.meta.Signature; @@ -455,4 +455,30 @@ public static UUID getUUIDFromString(String digest) { long leastSigBits = new BigInteger(digest.substring(16), 16).longValue(); return new UUID(mostSigBits, leastSigBits); } + + public static Class toUnboxedClass(Class clazz) { + return toUnboxedClassWithDefault(clazz, clazz); + } + + public static Class toUnboxedClassWithDefault(Class clazz, Class defaultClass) { + if (clazz == Boolean.class) { + return boolean.class; + } else if (clazz == Byte.class) { + return byte.class; + } else if (clazz == Short.class) { + return short.class; + } else if (clazz == Character.class) { + return char.class; + } else if (clazz == Integer.class) { + return int.class; + } else if (clazz == Long.class) { + return long.class; + } else if (clazz == Float.class) { + return float.class; + } else if (clazz == Double.class) { + return double.class; + } else { + return defaultClass; + } + } } diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/substitute/ComputedValueField.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/substitute/ComputedValueField.java index 75fab2f43059..0a7724cb6da3 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/substitute/ComputedValueField.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/substitute/ComputedValueField.java @@ -24,6 +24,7 @@ */ package com.oracle.svm.hosted.substitute; +import static com.oracle.svm.core.SubstrateUtil.toUnboxedClass; import static com.oracle.svm.core.annotate.RecomputeFieldValue.Kind.AtomicFieldUpdaterOffset; import static com.oracle.svm.core.annotate.RecomputeFieldValue.Kind.FieldOffset; import static com.oracle.svm.core.annotate.RecomputeFieldValue.Kind.StaticFieldBase; @@ -42,7 +43,6 @@ import java.util.concurrent.locks.ReentrantReadWriteLock.WriteLock; import org.graalvm.collections.EconomicMap; -import jdk.graal.compiler.api.replacements.SnippetReflectionProvider; import org.graalvm.nativeimage.hosted.FieldValueTransformer; import com.oracle.graal.pointsto.infrastructure.OriginalFieldProvider; @@ -65,6 +65,7 @@ import com.oracle.svm.util.ReflectionUtil; import com.oracle.svm.util.ReflectionUtil.ReflectionUtilError; +import jdk.graal.compiler.api.replacements.SnippetReflectionProvider; import jdk.internal.misc.Unsafe; import jdk.vm.ci.common.NativeImageReinitialize; import jdk.vm.ci.meta.JavaConstant; @@ -396,28 +397,6 @@ private void checkValue(Object newValue) { } } - private static Class toUnboxedClass(Class clazz) { - if (clazz == Boolean.class) { - return boolean.class; - } else if (clazz == Byte.class) { - return byte.class; - } else if (clazz == Short.class) { - return short.class; - } else if (clazz == Character.class) { - return char.class; - } else if (clazz == Integer.class) { - return int.class; - } else if (clazz == Long.class) { - return long.class; - } else if (clazz == Float.class) { - return float.class; - } else if (clazz == Double.class) { - return double.class; - } else { - return clazz; - } - } - private String fieldFormat() { return "field " + original.format("%H.%n") + (annotated != null ? " specified by alias " + annotated.format("%H.%n") : ""); } From 0102b20fa417f40ac8461bfd03057622c677ae0b Mon Sep 17 00:00:00 2001 From: Fengyun Liu Date: Fri, 24 Nov 2023 14:13:24 +0100 Subject: [PATCH 131/593] Add tags to build jobs --- ci.jsonnet | 24 ++++++++++++------------ ci/ci_common/common.jsonnet | 13 +++++++++++++ 2 files changed, 25 insertions(+), 12 deletions(-) diff --git a/ci.jsonnet b/ci.jsonnet index 015e4137bbaf..b3608f995816 100644 --- a/ci.jsonnet +++ b/ci.jsonnet @@ -50,18 +50,18 @@ local exclude_latest_darwin_amd64(builds) = [b for b in builds if !(import 'ci/c overlay: graal_common.ci.overlay, specVersion: "3", builds: exclude_latest_darwin_amd64([common.add_excludes_guard(b) for b in ( - compiler.builds + - wasm.builds + - espresso.builds + - regex.builds + - sdk.builds + - substratevm.builds + - sulong.builds + - tools.builds + - truffle.builds + - javadoc.builds + - vm.builds + - visualizer.builds + common.with_tags(compiler.builds, ["compiler"]) + + common.with_tags(wasm.builds, ["wasm"]) + + common.with_tags(espresso.builds, ["expresso"]) + + common.with_tags(regex.builds, ["regex"]) + + common.with_tags(sdk.builds, ["sdk"]) + + common.with_tags(substratevm.builds, ["svm"]) + + common.with_tags(sulong.builds, ["sulong"]) + + common.with_tags(tools.builds, ["tools"]) + + common.with_tags(truffle.builds, ["truffle"]) + + common.with_tags(javadoc.builds, ["javadoc"]) + + common.with_tags(vm.builds, ["vm"]) + + common.with_tags(visualizer.builds, ["visualizer"]) )]), assert verify_ci(self.builds), // verify that the run-spec demo works diff --git a/ci/ci_common/common.jsonnet b/ci/ci_common/common.jsonnet index 8c1687e43360..0763282ee2e9 100644 --- a/ci/ci_common/common.jsonnet +++ b/ci/ci_common/common.jsonnet @@ -47,6 +47,19 @@ common + common.frequencies + { } else {} ), + # Add the specified tags to the field `tags` of builds if `build.targets` contains "gate". + with_tags(builds, tags):: + [ + if std.count(build.targets, "gate") > 0 then + if std.objectHas(build, "tags") then + build + { "tags" : std.setUnion(tags, build.tags) } + else + build + { "tags" : tags } + else + build + for build in builds + ], + // Heap settings // ************* local small_heap = "1G", From 877bed6917321b340e8132a13a980dadcb3fac9a Mon Sep 17 00:00:00 2001 From: Fengyun Liu Date: Tue, 28 Nov 2023 08:39:13 +0100 Subject: [PATCH 132/593] =?UTF-8?q?Better=20names=20and=20typo=20(Thanks?= =?UTF-8?q?=20Fran=C3=A7ois)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ci.jsonnet | 24 ++++++++++++------------ ci/ci_common/common.jsonnet | 2 +- 2 files changed, 13 insertions(+), 13 deletions(-) diff --git a/ci.jsonnet b/ci.jsonnet index b3608f995816..ca4d645e6fed 100644 --- a/ci.jsonnet +++ b/ci.jsonnet @@ -50,18 +50,18 @@ local exclude_latest_darwin_amd64(builds) = [b for b in builds if !(import 'ci/c overlay: graal_common.ci.overlay, specVersion: "3", builds: exclude_latest_darwin_amd64([common.add_excludes_guard(b) for b in ( - common.with_tags(compiler.builds, ["compiler"]) + - common.with_tags(wasm.builds, ["wasm"]) + - common.with_tags(espresso.builds, ["expresso"]) + - common.with_tags(regex.builds, ["regex"]) + - common.with_tags(sdk.builds, ["sdk"]) + - common.with_tags(substratevm.builds, ["svm"]) + - common.with_tags(sulong.builds, ["sulong"]) + - common.with_tags(tools.builds, ["tools"]) + - common.with_tags(truffle.builds, ["truffle"]) + - common.with_tags(javadoc.builds, ["javadoc"]) + - common.with_tags(vm.builds, ["vm"]) + - common.with_tags(visualizer.builds, ["visualizer"]) + common.with_tags_for_gates(compiler.builds, ["compiler"]) + + common.with_tags_for_gates(wasm.builds, ["wasm"]) + + common.with_tags_for_gates(espresso.builds, ["espresso"]) + + common.with_tags_for_gates(regex.builds, ["regex"]) + + common.with_tags_for_gates(sdk.builds, ["sdk"]) + + common.with_tags_for_gates(substratevm.builds, ["svm"]) + + common.with_tags_for_gates(sulong.builds, ["sulong"]) + + common.with_tags_for_gates(tools.builds, ["tools"]) + + common.with_tags_for_gates(truffle.builds, ["truffle"]) + + common.with_tags_for_gates(javadoc.builds, ["javadoc"]) + + common.with_tags_for_gates(vm.builds, ["vm"]) + + common.with_tags_for_gates(visualizer.builds, ["visualizer"]) )]), assert verify_ci(self.builds), // verify that the run-spec demo works diff --git a/ci/ci_common/common.jsonnet b/ci/ci_common/common.jsonnet index 0763282ee2e9..f28fe2db1e59 100644 --- a/ci/ci_common/common.jsonnet +++ b/ci/ci_common/common.jsonnet @@ -48,7 +48,7 @@ common + common.frequencies + { ), # Add the specified tags to the field `tags` of builds if `build.targets` contains "gate". - with_tags(builds, tags):: + with_tags_for_gates(builds, tags):: [ if std.count(build.targets, "gate") > 0 then if std.objectHas(build, "tags") then From 5e69a272beaf918332ba7b01b32cae96ef0b2591 Mon Sep 17 00:00:00 2001 From: Josef Eisl Date: Thu, 7 Dec 2023 09:16:47 +0100 Subject: [PATCH 133/593] Adopt "Adjust to JDK-8315458" for JDK 21 --- .../src/com/oracle/svm/core/hub/DynamicHub.java | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/hub/DynamicHub.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/hub/DynamicHub.java index 013f50a7ba69..e2ba26a408ed 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/hub/DynamicHub.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/hub/DynamicHub.java @@ -73,6 +73,7 @@ import java.util.Optional; import java.util.StringJoiner; +import com.oracle.svm.core.jdk.JDK21OrEarlier; import org.graalvm.nativeimage.AnnotationAccess; import org.graalvm.nativeimage.ImageSingletons; import org.graalvm.nativeimage.Platform; @@ -874,6 +875,10 @@ void setClassLoaderAtRuntime(ClassLoader loader) { @KeepOriginal private native boolean isAnonymousClass(); + @KeepOriginal + @TargetElement(onlyWith = JDK21OrEarlier.class) + private native boolean isUnnamedClass(); + @Substitute @Uninterruptible(reason = "Called from uninterruptible code.", mayBeInlined = true) public boolean isHidden() { @@ -1752,6 +1757,11 @@ private Class[] getPermittedSubclasses0() { private static native void addAll(Collection c, Field[] o); @KeepOriginal + @TargetElement(onlyWith = JDK21OrEarlier.class) + private native Target_java_lang_PublicMethods_MethodList getMethodsRecursive(String methodName, Class[] parameterTypes, boolean includeStatic); + + @KeepOriginal + @TargetElement(onlyWith = JDK22OrLater.class) private native Target_java_lang_PublicMethods_MethodList getMethodsRecursive(String methodName, Class[] parameterTypes, boolean includeStatic, boolean publicOnly); @KeepOriginal From 1643fcfa119dd0f458d4d90578e1995b7c165ed9 Mon Sep 17 00:00:00 2001 From: Christian Haeubl Date: Wed, 15 Nov 2023 14:32:19 +0100 Subject: [PATCH 134/593] Only report useful options with JVMCIPrintProperties. --- .../test/HotSpotGraalOptionValuesTest.java | 5 +- .../graal/compiler/debug/DebugOptions.java | 3 +- .../hotspot/HotSpotGraalCompilerFactory.java | 3 +- .../graal/compiler/options/OptionValues.java | 64 +++++---- .../svm/core/option/RuntimeOptionKey.java | 7 +- .../hotspot/libgraal/LibGraalFeature.java | 136 +++++++++++++++--- .../libgraal/LibGraalRuntimeOptionKey.java | 37 +++++ 7 files changed, 200 insertions(+), 55 deletions(-) create mode 100644 substratevm/src/com.oracle.svm.graal.hotspot.libgraal/src/com/oracle/svm/graal/hotspot/libgraal/LibGraalRuntimeOptionKey.java diff --git a/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/hotspot/test/HotSpotGraalOptionValuesTest.java b/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/hotspot/test/HotSpotGraalOptionValuesTest.java index 5b0ae6657b6e..ad9ed9f22f80 100644 --- a/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/hotspot/test/HotSpotGraalOptionValuesTest.java +++ b/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/hotspot/test/HotSpotGraalOptionValuesTest.java @@ -30,11 +30,12 @@ import java.io.IOException; import java.io.PrintStream; -import jdk.graal.compiler.options.OptionValues; -import jdk.graal.compiler.options.OptionsParser; import org.junit.Assert; import org.junit.Test; +import jdk.graal.compiler.options.OptionValues; +import jdk.graal.compiler.options.OptionsParser; + public class HotSpotGraalOptionValuesTest extends HotSpotGraalCompilerTest { @Test diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/debug/DebugOptions.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/debug/DebugOptions.java index 9cc6d49fcef8..85a64c82677e 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/debug/DebugOptions.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/debug/DebugOptions.java @@ -34,6 +34,7 @@ import java.util.Date; import org.graalvm.collections.EconomicMap; + import jdk.graal.compiler.options.EnumMultiOptionKey; import jdk.graal.compiler.options.EnumOptionKey; import jdk.graal.compiler.options.Option; @@ -122,7 +123,7 @@ public enum OptimizationLogTarget { @Option(help = "Pattern for specifying scopes in which logging is enabled. " + "See the Dump option for the pattern syntax.", type = OptionType.Debug) public static final OptionKey Log = new OptionKey<>(null); - @Option(help = "file:doc-files/MethodFilterHelp.txt", stability = OptionStability.STABLE) + @Option(help = "file:doc-files/MethodFilterHelp.txt") public static final OptionKey MethodFilter = new OptionKey<>(null); @Option(help = "Only check MethodFilter against the root method in the context if true, otherwise check all methods", type = OptionType.Debug) public static final OptionKey MethodFilterRootOnly = new OptionKey<>(false); diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/HotSpotGraalCompilerFactory.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/HotSpotGraalCompilerFactory.java index 7e9941e56ff2..299225cfe61e 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/HotSpotGraalCompilerFactory.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/HotSpotGraalCompilerFactory.java @@ -24,11 +24,11 @@ */ package jdk.graal.compiler.hotspot; +import static jdk.graal.compiler.hotspot.HotSpotGraalOptionValues.GRAAL_OPTION_PROPERTY_PREFIX; import static jdk.vm.ci.common.InitTimer.timer; import static jdk.vm.ci.hotspot.HotSpotJVMCICompilerFactory.CompilationLevelAdjustment.None; import static jdk.vm.ci.services.Services.IS_BUILDING_NATIVE_IMAGE; import static jdk.vm.ci.services.Services.IS_IN_NATIVE_IMAGE; -import static jdk.graal.compiler.hotspot.HotSpotGraalOptionValues.GRAAL_OPTION_PROPERTY_PREFIX; import java.io.PrintStream; @@ -40,7 +40,6 @@ import jdk.graal.compiler.options.OptionValues; import jdk.graal.compiler.options.OptionsParser; import jdk.graal.compiler.phases.tiers.CompilerConfiguration; - import jdk.vm.ci.common.InitTimer; import jdk.vm.ci.hotspot.HotSpotJVMCICompilerFactory; import jdk.vm.ci.hotspot.HotSpotJVMCIRuntime; diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/options/OptionValues.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/options/OptionValues.java index ad2b949938e0..f6b9723c3021 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/options/OptionValues.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/options/OptionValues.java @@ -206,34 +206,48 @@ public void printHelp(Iterable loader, PrintStream out, Strin } } for (Map.Entry e : sortedOptions.entrySet()) { + String key = e.getKey(); OptionDescriptor desc = e.getValue(); - Object value = desc.getOptionKey().getValue(this); - if (value instanceof String) { - value = '"' + String.valueOf(value) + '"'; - } - String name = namePrefix + e.getKey(); - String assign = containsKey(desc.getOptionKey()) ? ":=" : "="; - String typeName = desc.getOptionKey() instanceof EnumOptionKey ? "String" : desc.getOptionValueType().getSimpleName(); - String linePrefix = String.format("%s %s %s ", name, assign, value); - int typeStartPos = PROPERTY_LINE_WIDTH - typeName.length(); - int linePad = typeStartPos - linePrefix.length(); - if (linePad > 0) { - out.printf("%s%-" + linePad + "s[%s]%n", linePrefix, "", typeName); - } else { - out.printf("%s[%s]%n", linePrefix, typeName); + if (!excludeOptionFromHelp(key, desc)) { + printHelp(out, namePrefix, key, desc); } + } + } - List helpLines; - String help = desc.getHelp(); - if (help.length() != 0) { - helpLines = wrap(help, PROPERTY_LINE_WIDTH - PROPERTY_HELP_INDENT); - helpLines.addAll(desc.getExtraHelp()); - } else { - helpLines = desc.getExtraHelp(); - } - for (String line : helpLines) { - out.printf("%" + PROPERTY_HELP_INDENT + "s%s%n", "", line); - } + private void printHelp(PrintStream out, String namePrefix, String key, OptionDescriptor desc) { + Object value = desc.getOptionKey().getValue(this); + if (value instanceof String) { + value = '"' + String.valueOf(value) + '"'; + } + String name = namePrefix + key; + String assign = containsKey(desc.getOptionKey()) ? ":=" : "="; + String typeName = desc.getOptionKey() instanceof EnumOptionKey ? "String" : desc.getOptionValueType().getSimpleName(); + String linePrefix = String.format("%s %s %s ", name, assign, value); + int typeStartPos = PROPERTY_LINE_WIDTH - typeName.length(); + int linePad = typeStartPos - linePrefix.length(); + if (linePad > 0) { + out.printf("%s%-" + linePad + "s[%s]%n", linePrefix, "", typeName); + } else { + out.printf("%s[%s]%n", linePrefix, typeName); } + + List helpLines; + String help = desc.getHelp(); + if (help.length() != 0) { + helpLines = wrap(help, PROPERTY_LINE_WIDTH - PROPERTY_HELP_INDENT); + helpLines.addAll(desc.getExtraHelp()); + } else { + helpLines = desc.getExtraHelp(); + } + for (String line : helpLines) { + out.printf("%" + PROPERTY_HELP_INDENT + "s%s%n", "", line); + } + } + + private static boolean excludeOptionFromHelp(String optionKey, OptionDescriptor desc) { + /* Filter out debug, Truffle, and Native Image options. */ + return desc.getOptionType() == OptionType.Debug || + optionKey.startsWith("compiler.") || + optionKey.startsWith("internal."); } } diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/option/RuntimeOptionKey.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/option/RuntimeOptionKey.java index ed02adf22a05..e4de02be01d7 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/option/RuntimeOptionKey.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/option/RuntimeOptionKey.java @@ -28,9 +28,6 @@ import java.util.function.Consumer; import org.graalvm.collections.EconomicMap; -import jdk.graal.compiler.api.replacements.Fold; -import jdk.graal.compiler.options.Option; -import jdk.graal.compiler.options.OptionKey; import org.graalvm.nativeimage.ImageSingletons; import org.graalvm.nativeimage.Platform; import org.graalvm.nativeimage.Platforms; @@ -38,6 +35,10 @@ import com.oracle.svm.core.SubstrateUtil; import com.oracle.svm.core.jdk.RuntimeSupport; +import jdk.graal.compiler.api.replacements.Fold; +import jdk.graal.compiler.options.Option; +import jdk.graal.compiler.options.OptionKey; + /** * Defines a runtime {@link Option}, in contrast to a {@link HostedOptionKey hosted option}. * diff --git a/substratevm/src/com.oracle.svm.graal.hotspot.libgraal/src/com/oracle/svm/graal/hotspot/libgraal/LibGraalFeature.java b/substratevm/src/com.oracle.svm.graal.hotspot.libgraal/src/com/oracle/svm/graal/hotspot/libgraal/LibGraalFeature.java index dc6dc5842038..e8c311ca1fb6 100644 --- a/substratevm/src/com.oracle.svm.graal.hotspot.libgraal/src/com/oracle/svm/graal/hotspot/libgraal/LibGraalFeature.java +++ b/substratevm/src/com.oracle.svm.graal.hotspot.libgraal/src/com/oracle/svm/graal/hotspot/libgraal/LibGraalFeature.java @@ -49,7 +49,9 @@ import java.util.Map; import java.util.SortedSet; import java.util.TreeSet; +import java.util.concurrent.ConcurrentHashMap; import java.util.function.BooleanSupplier; +import java.util.function.Function; import java.util.stream.Collectors; import org.graalvm.collections.EconomicMap; @@ -62,6 +64,7 @@ import org.graalvm.nativeimage.StackValue; import org.graalvm.nativeimage.VMRuntime; import org.graalvm.nativeimage.hosted.Feature; +import org.graalvm.nativeimage.hosted.FieldValueTransformer; import org.graalvm.nativeimage.hosted.RuntimeJNIAccess; import org.graalvm.nativeimage.hosted.RuntimeReflection; import org.graalvm.word.Pointer; @@ -74,7 +77,9 @@ import com.oracle.svm.core.OS; import com.oracle.svm.core.RuntimeAssertionsSupport; import com.oracle.svm.core.SubstrateUtil; +import com.oracle.svm.core.annotate.Alias; import com.oracle.svm.core.annotate.Delete; +import com.oracle.svm.core.annotate.InjectAccessors; import com.oracle.svm.core.annotate.Substitute; import com.oracle.svm.core.annotate.TargetClass; import com.oracle.svm.core.annotate.TargetElement; @@ -84,8 +89,8 @@ import com.oracle.svm.core.graal.meta.RuntimeConfiguration; import com.oracle.svm.core.graal.snippets.NodeLoweringProvider; import com.oracle.svm.core.heap.Heap; +import com.oracle.svm.core.heap.UnknownObjectField; import com.oracle.svm.core.log.FunctionPointerLogHandler; -import com.oracle.svm.core.option.HostedOptionKey; import com.oracle.svm.core.option.RuntimeOptionKey; import com.oracle.svm.core.option.RuntimeOptionValues; import com.oracle.svm.core.option.XOptions; @@ -144,6 +149,7 @@ import jdk.graal.compiler.truffle.hotspot.TruffleCallBoundaryInstrumentationFactory; import jdk.graal.compiler.truffle.substitutions.GraphBuilderInvocationPluginProvider; import jdk.graal.compiler.truffle.substitutions.GraphDecoderInvocationPluginProvider; +import jdk.internal.misc.Unsafe; import jdk.vm.ci.code.CompilationRequest; import jdk.vm.ci.code.CompilationRequestResult; import jdk.vm.ci.hotspot.HotSpotConstantReflectionProvider; @@ -159,20 +165,21 @@ class LibGraalOptions { @Option(help = "Converts an exception triggered by the CrashAt option into a fatal error " + "if a non-null pointer was passed in the _fatal option to JNI_CreateJavaVM. " + "This option exists for the purpose of testing fatal error handling in libgraal.") // - static final RuntimeOptionKey CrashAtIsFatal = new RuntimeOptionKey<>(false); + static final RuntimeOptionKey CrashAtIsFatal = new LibGraalRuntimeOptionKey<>(false); @Option(help = "The fully qualified name of a no-arg, void, static method to be invoked " + "in HotSpot from libgraal when the libgraal isolate is being shutdown." + "This option exists for the purpose of testing callbacks in this context.") // - static final RuntimeOptionKey OnShutdownCallback = new RuntimeOptionKey<>(null); + static final RuntimeOptionKey OnShutdownCallback = new LibGraalRuntimeOptionKey<>(null); @Option(help = "Replaces first exception thrown by the CrashAt option with an OutOfMemoryError. " + "Subsequently CrashAt exceptions are suppressed. " + "This option exists to test HeapDumpOnOutOfMemoryError. " + "See the MethodFilter option for the pattern syntax.") // - static final RuntimeOptionKey CrashAtThrowsOOME = new RuntimeOptionKey<>(false); + static final RuntimeOptionKey CrashAtThrowsOOME = new LibGraalRuntimeOptionKey<>(false); } public class LibGraalFeature implements InternalFeature { + private final OptionCollector optionCollector = new OptionCollector(); private HotSpotReplacementsImpl hotSpotSubstrateReplacements; public LibGraalFeature() { @@ -212,25 +219,36 @@ public boolean getAsBoolean() { @Override public void duringSetup(DuringSetupAccess access) { - ImageClassLoader imageClassLoader = ((DuringSetupAccessImpl) access).getImageClassLoader(); + access.registerObjectReplacer(optionCollector); + ImageClassLoader imageClassLoader = ((DuringSetupAccessImpl) access).getImageClassLoader(); registerJNIConfiguration(imageClassLoader); - EconomicMap descriptors = EconomicMap.create(); - for (Class optionsClass : imageClassLoader.findSubclasses(OptionDescriptors.class, false)) { - if (!Modifier.isAbstract(optionsClass.getModifiers()) && !OptionDescriptorsMap.class.isAssignableFrom(optionsClass)) { - try { - ModuleSupport.accessModuleByClass(ModuleSupport.Access.EXPORT, LibGraalFeature.class, optionsClass); - for (OptionDescriptor d : optionsClass.getDeclaredConstructor().newInstance()) { - if (!(d.getOptionKey() instanceof HostedOptionKey)) { - descriptors.put(d.getName(), d); - } - } - } catch (ReflectiveOperationException ex) { - throw VMError.shouldNotReachHere(ex); + } + + /** + * Collects all reachable {@link OptionKey}s. Note that this includes options where the class is + * only reachable at image build-time (e.g., + * {@link com.oracle.svm.core.option.HostedOptionKey}). + */ + private static class OptionCollector implements Function { + final ConcurrentHashMap, OptionKey> options = new ConcurrentHashMap<>(); + private boolean sealed; + + @Override + public Object apply(Object source) { + if (source instanceof OptionKey option) { + if (sealed) { + assert options.contains(option) : "All options must have been discovered during static analysis"; + } else { + options.put(option, option); } } + return source; + } + + public void setSealed() { + sealed = true; } - OptionsParser.setCachedOptionDescriptors(Collections.singletonList(new OptionDescriptorsMap(descriptors))); } /** @@ -434,6 +452,9 @@ public void beforeAnalysis(BeforeAnalysisAccess access) { BigBang bb = impl.getBigBang(); DebugContext debug = bb.getDebug(); + /* Transform option names so that Native Image options are in a separate namespace. */ + access.registerFieldValueTransformer(ReflectionUtil.lookupField(OptionDescriptor.class, "name"), new OptionDescriptorNameTransformer()); + // Services that will not be loaded if native-image is run // with -XX:-UseJVMCICompiler. GraalServices.load(TruffleCallBoundaryInstrumentationFactory.class); @@ -534,13 +555,23 @@ private static void filterArchitectureServices(String archPackage, Map, @Override public void afterAnalysis(AfterAnalysisAccess access) { + optionCollector.setSealed(); + verifyReachableTruffleClasses(access); + registerReachableOptions(access); } - @Override - public void afterCompilation(AfterCompilationAccess access) { - EncodedSnippets encodedSnippets = HotSpotReplacementsImpl.getEncodedSnippets(); - encodedSnippets.visitImmutable(access::registerAsImmutable); + private void registerReachableOptions(AfterAnalysisAccess access) { + EconomicMap options = EconomicMap.create(); + for (OptionKey option : optionCollector.options.keySet()) { + // This reachability check can be removed once GR-50219 is in place. + if (access.isReachable(option.getClass())) { + String optionKey = getPrefixedOptionName(option); + options.put(optionKey, option.getDescriptor()); + } + } + + OptionsParserAccessors.optionDescriptors = options; } /** @@ -606,6 +637,67 @@ static HotSpotReplacementsImpl getReplacements() { HotSpotProviders originalProvider = compiler.getGraalRuntime().getHostProviders(); return (HotSpotReplacementsImpl) originalProvider.getReplacements(); } + + static String getPrefixedOptionName(OptionKey key) { + if (isNativeImageOption(key)) { + return "internal." + key.getName(); + } + return key.getName(); + } + + private static boolean isNativeImageOption(OptionKey key) { + return key instanceof RuntimeOptionKey && !(key instanceof LibGraalRuntimeOptionKey); + } +} + +/* + * Transforms option names so that Native Image options are in a separate namespace, e.g., + * jdk.graal.internal.MaxHeap. + */ +final class OptionDescriptorNameTransformer implements FieldValueTransformer { + @Override + public Object transform(Object receiver, Object originalValue) { + OptionDescriptor desc = (OptionDescriptor) receiver; + return LibGraalFeature.getPrefixedOptionName(desc.getOptionKey()); + } +} + +@TargetClass(className = "jdk.graal.compiler.options.OptionsParser", onlyWith = LibGraalFeature.IsEnabled.class) +final class Target_jdk_graal_compiler_options_OptionsParser { + @Alias @InjectAccessors(OptionsParserAccessors.class) // + private static volatile List cachedOptionDescriptors; +} + +class OptionsParserAccessors { + @UnknownObjectField(fullyQualifiedTypes = "org.graalvm.collections.EconomicMapImpl") // + static EconomicMap optionDescriptors; + private static List cachedOptions; + + @SuppressWarnings("unused") + static List getCachedOptionDescriptors() { + List result = cachedOptions; + if (result == null) { + result = initialize(); + } + return result; + } + + @SuppressWarnings("unused") + static void setCachedOptionDescriptors(List value) { + throw VMError.shouldNotReachHereAtRuntime(); + } + + private static synchronized List initialize() { + List result = cachedOptions; + if (result == null) { + result = Collections.singletonList(new OptionDescriptorsMap(optionDescriptors)); + + /* Ensure that all stores are visible before we publish the data. */ + Unsafe.getUnsafe().storeFence(); + cachedOptions = result; + } + return result; + } } @TargetClass(className = "jdk.vm.ci.hotspot.SharedLibraryJVMCIReflection", onlyWith = LibGraalFeature.IsEnabled.class) diff --git a/substratevm/src/com.oracle.svm.graal.hotspot.libgraal/src/com/oracle/svm/graal/hotspot/libgraal/LibGraalRuntimeOptionKey.java b/substratevm/src/com.oracle.svm.graal.hotspot.libgraal/src/com/oracle/svm/graal/hotspot/libgraal/LibGraalRuntimeOptionKey.java new file mode 100644 index 000000000000..dd8536e553b3 --- /dev/null +++ b/substratevm/src/com.oracle.svm.graal.hotspot.libgraal/src/com/oracle/svm/graal/hotspot/libgraal/LibGraalRuntimeOptionKey.java @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2023, 2023, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.svm.graal.hotspot.libgraal; + +import com.oracle.svm.core.option.RuntimeOptionKey; + +/** + * Libgraal-specific subclass so that we can distinguish between Native Image and libgraal runtime + * options. + */ +public class LibGraalRuntimeOptionKey extends RuntimeOptionKey { + LibGraalRuntimeOptionKey(T defaultValue, RuntimeOptionKeyFlag... flags) { + super(defaultValue, flags); + } +} From 79bf39fb72ee1a2c7223ff850459c516f62d159c Mon Sep 17 00:00:00 2001 From: Christian Haeubl Date: Fri, 24 Nov 2023 17:08:41 +0100 Subject: [PATCH 135/593] Fixed test case failures. --- .../hotspot/test/OptionsInFileTest.java | 31 +++++++------- .../compiler/options/test/TestOptionKey.java | 41 ++++++++++--------- substratevm/mx.substratevm/mx_substratevm.py | 2 +- vm/mx.vm/mx_vm_gate.py | 8 ++-- 4 files changed, 40 insertions(+), 42 deletions(-) diff --git a/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/hotspot/test/OptionsInFileTest.java b/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/hotspot/test/OptionsInFileTest.java index c14c25c106c9..3e9db62fa39f 100644 --- a/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/hotspot/test/OptionsInFileTest.java +++ b/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/hotspot/test/OptionsInFileTest.java @@ -24,9 +24,8 @@ */ package jdk.graal.compiler.hotspot.test; -import static jdk.graal.compiler.debug.DebugOptions.Dump; -import static jdk.graal.compiler.debug.DebugOptions.MethodFilter; -import static jdk.graal.compiler.debug.DebugOptions.PrintGraph; +import static jdk.graal.compiler.core.common.GraalOptions.InlineMegamorphicCalls; +import static jdk.graal.compiler.core.common.GraalOptions.MaximumDesiredSize; import static jdk.graal.compiler.test.SubprocessUtil.getVMCommandLine; import static jdk.graal.compiler.test.SubprocessUtil.withoutDebuggerArguments; @@ -36,12 +35,12 @@ import java.io.PrintStream; import java.util.List; +import org.junit.Assert; +import org.junit.Test; + import jdk.graal.compiler.core.test.GraalCompilerTest; -import jdk.graal.compiler.debug.DebugOptions.PrintGraphTarget; import jdk.graal.compiler.test.SubprocessUtil; import jdk.graal.compiler.test.SubprocessUtil.Subprocess; -import org.junit.Assert; -import org.junit.Test; /** * Tests reading options from a file specified by the {@code graal.options.file}. @@ -49,18 +48,16 @@ public class OptionsInFileTest extends GraalCompilerTest { @Test public void test() throws IOException, InterruptedException { - String methodFilterValue = "a very unlikely method name"; - String debugFilterValue = "a very unlikely debug scope"; + Boolean inlineMegamorphic = false; + Integer maximumDesiredSize = 10000; File optionsFile = File.createTempFile("options", ".properties").getAbsoluteFile(); try { - Assert.assertFalse(methodFilterValue.equals(MethodFilter.getDefaultValue())); - Assert.assertFalse(debugFilterValue.equals(Dump.getDefaultValue())); - Assert.assertEquals(PrintGraphTarget.File, PrintGraph.getDefaultValue()); + Assert.assertFalse(inlineMegamorphic.equals(InlineMegamorphicCalls.getDefaultValue())); + Assert.assertFalse(maximumDesiredSize.equals(MaximumDesiredSize.getDefaultValue())); try (PrintStream out = new PrintStream(new FileOutputStream(optionsFile))) { - out.println(MethodFilter.getName() + "=" + methodFilterValue); - out.println(Dump.getName() + "=" + debugFilterValue); - out.println(PrintGraph.getName() + " = Network"); + out.println(InlineMegamorphicCalls.getName() + "=" + inlineMegamorphic); + out.println(MaximumDesiredSize.getName() + "=" + maximumDesiredSize); } List vmArgs = withoutDebuggerArguments(getVMCommandLine()); @@ -68,10 +65,10 @@ public void test() throws IOException, InterruptedException { vmArgs.add("-Djdk.graal.options.file=" + optionsFile); vmArgs.add("-XX:+JVMCIPrintProperties"); Subprocess proc = SubprocessUtil.java(vmArgs); + String[] expected = { - "graal.MethodFilter := \"a very unlikely method name\"", - "graal.Dump := \"a very unlikely debug scope\"", - "graal.PrintGraph := Network"}; + "graal.InlineMegamorphicCalls := false", + "graal.MaximumDesiredSize := 10000"}; for (String line : proc.output) { for (int i = 0; i < expected.length; i++) { if (expected[i] != null && line.contains(expected[i])) { diff --git a/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/options/test/TestOptionKey.java b/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/options/test/TestOptionKey.java index 6a297de9992c..a687f06b8a85 100644 --- a/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/options/test/TestOptionKey.java +++ b/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/options/test/TestOptionKey.java @@ -27,15 +27,15 @@ import static jdk.graal.compiler.options.OptionValues.asMap; import static jdk.graal.compiler.options.OptionValues.newOptionMap; import static jdk.graal.compiler.options.OptionsParser.parseOptionValue; +import static jdk.graal.compiler.options.test.TestOptionKey.Options.MyBooleanOption; import static jdk.graal.compiler.options.test.TestOptionKey.Options.MyDeprecatedOption; -import static jdk.graal.compiler.options.test.TestOptionKey.Options.MyOption; -import static jdk.graal.compiler.options.test.TestOptionKey.Options.MyOtherOption; +import static jdk.graal.compiler.options.test.TestOptionKey.Options.MyDoubleOption; +import static jdk.graal.compiler.options.test.TestOptionKey.Options.MyFloatOption; import static jdk.graal.compiler.options.test.TestOptionKey.Options.MyIntegerOption; import static jdk.graal.compiler.options.test.TestOptionKey.Options.MyLongOption; -import static jdk.graal.compiler.options.test.TestOptionKey.Options.MyBooleanOption; -import static jdk.graal.compiler.options.test.TestOptionKey.Options.MyFloatOption; -import static jdk.graal.compiler.options.test.TestOptionKey.Options.MyDoubleOption; import static jdk.graal.compiler.options.test.TestOptionKey.Options.MyMultiEnumOption; +import static jdk.graal.compiler.options.test.TestOptionKey.Options.MyOption; +import static jdk.graal.compiler.options.test.TestOptionKey.Options.MyOtherOption; import static jdk.graal.compiler.options.test.TestOptionKey.Options.MySecondOption; import static jdk.graal.compiler.options.test.TestOptionKey.TestEnum.Value2; import static jdk.graal.compiler.options.test.TestOptionKey.TestEnum.Value3; @@ -52,6 +52,10 @@ import org.graalvm.collections.EconomicMap; import org.graalvm.collections.EconomicSet; +import org.junit.Assert; +import org.junit.Assume; +import org.junit.Test; + import jdk.graal.compiler.options.EnumMultiOptionKey; import jdk.graal.compiler.options.EnumOptionKey; import jdk.graal.compiler.options.ModifiableOptionValues; @@ -63,9 +67,6 @@ import jdk.graal.compiler.options.OptionType; import jdk.graal.compiler.options.OptionValues; import jdk.graal.compiler.options.OptionsParser; -import org.junit.Assert; -import org.junit.Assume; -import org.junit.Test; @SuppressWarnings("try") public class TestOptionKey { @@ -94,18 +95,18 @@ public static class Options { private static final OptionDescriptors OPTION_DESCRIPTORS; static { EconomicMap map = EconomicMap.create(); - map.put("MyOption", OptionDescriptor.create("MyOption", OptionType.Debug, String.class, "", Options.class, "MyOption", MyOption)); - map.put("MyIntegerOption", OptionDescriptor.create("MyIntegerOption", OptionType.Debug, Integer.class, "", Options.class, "MyIntegerOption", MyIntegerOption)); - map.put("MyLongOption", OptionDescriptor.create("MyLongOption", OptionType.Debug, Long.class, "", Options.class, "MyLongOption", MyLongOption)); - map.put("MyBooleanOption", OptionDescriptor.create("MyBooleanOption", OptionType.Debug, Boolean.class, "", Options.class, "MyBooleanOption", MyBooleanOption)); - map.put("MyFloatOption", OptionDescriptor.create("MyFloatOption", OptionType.Debug, Float.class, "", Options.class, "MyFloatOption", MyFloatOption)); - map.put("MyDoubleOption", OptionDescriptor.create("MyDoubleOption", OptionType.Debug, Double.class, "", Options.class, "MyDoubleOption", MyDoubleOption)); - map.put("MySecondOption", OptionDescriptor.create("MySecondOption", OptionType.Debug, String.class, "", Options.class, "MySecondOption", MySecondOption)); - map.put("MyMultiEnumOption", OptionDescriptor.create("MyMultiEnumOption", OptionType.Debug, EconomicSet.class, "", Options.class, "MyMultiEnumOption", MyMultiEnumOption)); + map.put("MyOption", OptionDescriptor.create("MyOption", OptionType.User, String.class, "", Options.class, "MyOption", MyOption)); + map.put("MyIntegerOption", OptionDescriptor.create("MyIntegerOption", OptionType.User, Integer.class, "", Options.class, "MyIntegerOption", MyIntegerOption)); + map.put("MyLongOption", OptionDescriptor.create("MyLongOption", OptionType.User, Long.class, "", Options.class, "MyLongOption", MyLongOption)); + map.put("MyBooleanOption", OptionDescriptor.create("MyBooleanOption", OptionType.User, Boolean.class, "", Options.class, "MyBooleanOption", MyBooleanOption)); + map.put("MyFloatOption", OptionDescriptor.create("MyFloatOption", OptionType.User, Float.class, "", Options.class, "MyFloatOption", MyFloatOption)); + map.put("MyDoubleOption", OptionDescriptor.create("MyDoubleOption", OptionType.User, Double.class, "", Options.class, "MyDoubleOption", MyDoubleOption)); + map.put("MySecondOption", OptionDescriptor.create("MySecondOption", OptionType.User, String.class, "", Options.class, "MySecondOption", MySecondOption)); + map.put("MyMultiEnumOption", OptionDescriptor.create("MyMultiEnumOption", OptionType.User, EconomicSet.class, "", Options.class, "MyMultiEnumOption", MyMultiEnumOption)); map.put("MyDeprecatedOption", OptionDescriptor.create( // @formatter:off /*name*/ "MyDeprecatedOption", - /*optionType*/ OptionType.Debug, + /*optionType*/ OptionType.User, /*optionValueType*/ String.class, /*help*/ "Help for MyDeprecatedOption with", /*extraHelp*/ new String[] { @@ -164,7 +165,7 @@ public void testOptionsParser() { Assert.assertEquals(true, parseOptionValue(descs.get("MyBooleanOption"), "true")); OptionKey exceptionOption = new OptionKey<>(null); - OptionDescriptor desc = OptionDescriptor.create("exceptionOption", OptionType.Debug, Exception.class, "", Options.class, "exceptionOption", exceptionOption); + OptionDescriptor desc = OptionDescriptor.create("exceptionOption", OptionType.User, Exception.class, "", Options.class, "exceptionOption", exceptionOption); try { parseOptionValue(desc, "impossible value"); Assert.fail("expected IllegalArgumentException"); @@ -282,7 +283,7 @@ public void testEnumOptionValidValue() { map = OptionValues.newOptionMap(); option.update(map, TestEnum.Value3); OptionValues values = new OptionValues(map); - OptionDescriptor.create("myEnumOption", OptionType.Debug, String.class, "", Options.class, "myEnumOption", option); + OptionDescriptor.create("myEnumOption", OptionType.User, String.class, "", Options.class, "myEnumOption", option); Assert.assertEquals(option.getValue(values), TestEnum.Value3); } @@ -370,7 +371,7 @@ public void testModifiableOptionValues() { public void testOptionDescriptors() { OptionDescriptor desc = MyDeprecatedOption.getDescriptor(); Assert.assertTrue(desc.isDeprecated()); - Assert.assertEquals(desc.getOptionType(), OptionType.Debug); + Assert.assertEquals(desc.getOptionType(), OptionType.User); Assert.assertEquals(desc.getDeprecationMessage(), "Some deprecation message"); Assert.assertEquals(desc.getHelp(), "Help for MyDeprecatedOption with"); Assert.assertEquals(desc.getExtraHelp(), List.of("some extra text on", "following lines.")); diff --git a/substratevm/mx.substratevm/mx_substratevm.py b/substratevm/mx.substratevm/mx_substratevm.py index 0c874a4f5df3..edbd30eefe8e 100644 --- a/substratevm/mx.substratevm/mx_substratevm.py +++ b/substratevm/mx.substratevm/mx_substratevm.py @@ -1332,7 +1332,7 @@ def _native_image_launcher_extra_jvm_args(): '-H:+PreserveFramePointer', '-H:-DeleteLocalSymbols', - # Configure -Djdk.libgraal.HeapDumpOnOutOfMemoryError=true + # Configure -Djdk.libgraal.internal.HeapDumpOnOutOfMemoryError=true '--enable-monitoring=heapdump', '-H:HeapDumpDefaultFilenamePrefix=libgraal_pid', diff --git a/vm/mx.vm/mx_vm_gate.py b/vm/mx.vm/mx_vm_gate.py index 13c388fce2e6..ded42bef26dd 100644 --- a/vm/mx.vm/mx_vm_gate.py +++ b/vm/mx.vm/mx_vm_gate.py @@ -288,15 +288,15 @@ def _test_libgraal_oome_dumping(): } if mx.is_windows(): # GR-39501 - mx.log('-Djdk.libgraal.HeapDumpOnOutOfMemoryError=true is not supported on Windows') + mx.log('-Djdk.libgraal.internal.HeapDumpOnOutOfMemoryError=true is not supported on Windows') return for n, v in inputs.items(): vmargs = ['-Djdk.libgraal.CrashAt=*', '-Djdk.libgraal.Xmx128M', - '-Djdk.libgraal.PrintGC=true', - '-Djdk.libgraal.HeapDumpOnOutOfMemoryError=true', - f'-Djdk.libgraal.HeapDumpPath={n}', + '-Djdk.libgraal.internal.PrintGC=true', + '-Djdk.libgraal.internal.HeapDumpOnOutOfMemoryError=true', + f'-Djdk.libgraal.internal.HeapDumpPath={n}', '-Djdk.libgraal.CrashAtThrowsOOME=true'] cmd = [join(graalvm_home, 'bin', 'java')] + vmargs + _get_CountUppercase_vmargs() mx.run(cmd, cwd=scratch_dir) From d592a45be0c88b9b598b6f7ac0b613ec205a6b0e Mon Sep 17 00:00:00 2001 From: Allan Gregersen Date: Thu, 7 Dec 2023 10:44:33 +0100 Subject: [PATCH 136/593] don't waste time on removing sub-type when superclass is known to be j.l.Object --- .../src/com/oracle/truffle/espresso/impl/ObjectKlass.java | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/impl/ObjectKlass.java b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/impl/ObjectKlass.java index 3a497df02dab..4107c4982c69 100644 --- a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/impl/ObjectKlass.java +++ b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/impl/ObjectKlass.java @@ -253,7 +253,9 @@ private void addSubType(ObjectKlass objectKlass) { } public void removeAsSubType() { - getSuperKlass().removeSubType(this); + if (getSuperKlass() != getMeta().java_lang_Object) { + getSuperKlass().removeSubType(this); + } for (ObjectKlass superInterface : getSuperInterfaces()) { superInterface.removeSubType(this); } @@ -816,7 +818,7 @@ public Method.MethodVersion[] getDeclaredMethodVersions() { @Override public Field[] getDeclaredFields() { - // Speculate that there are no hidden fields + // Speculate that there are no hidden nor removed fields Field[] declaredFields = new Field[staticFieldTable.length + fieldTable.length - localFieldTableIndex]; int insertionIndex = 0; for (int i = 0; i < staticFieldTable.length; i++) { From 6b3ba5d7592f5d2931a1e324b5998835594f87d0 Mon Sep 17 00:00:00 2001 From: Allan Gregersen Date: Thu, 7 Dec 2023 10:47:58 +0100 Subject: [PATCH 137/593] synchronize extension fields to avoid inconsistent state during class redefinition --- .../impl/ExtensionFieldsMetadata.java | 20 +++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/impl/ExtensionFieldsMetadata.java b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/impl/ExtensionFieldsMetadata.java index fcd4775384bb..f25e5f6136c4 100644 --- a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/impl/ExtensionFieldsMetadata.java +++ b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/impl/ExtensionFieldsMetadata.java @@ -38,7 +38,7 @@ final class ExtensionFieldsMetadata { @CompilationFinal(dimensions = 1) private Field[] addedInstanceFields = Field.EMPTY_ARRAY; @CompilationFinal(dimensions = 1) private Field[] addedStaticFields = Field.EMPTY_ARRAY; - void addNewStaticFields(ObjectKlass.KlassVersion holder, List newFields, RuntimeConstantPool pool, Map compatibleFields, + synchronized void addNewStaticFields(ObjectKlass.KlassVersion holder, List newFields, RuntimeConstantPool pool, Map compatibleFields, ClassRedefinition classRedefinition) { CompilerAsserts.neverPartOfCompilation(); @@ -53,7 +53,7 @@ void addNewStaticFields(ObjectKlass.KlassVersion holder, List newFi } } - void addNewInstanceFields(ObjectKlass.KlassVersion holder, List newFields, RuntimeConstantPool pool, Map compatibleFields, + synchronized void addNewInstanceFields(ObjectKlass.KlassVersion holder, List newFields, RuntimeConstantPool pool, Map compatibleFields, ClassRedefinition classRedefinition) { CompilerAsserts.neverPartOfCompilation(); @@ -68,7 +68,7 @@ void addNewInstanceFields(ObjectKlass.KlassVersion holder, List new } } - void addNewInstanceField(Field toAdd) { + synchronized void addNewInstanceField(Field toAdd) { int nextIndex = addedInstanceFields.length; addedInstanceFields = Arrays.copyOf(addedInstanceFields, addedInstanceFields.length + 1); addedInstanceFields[nextIndex] = toAdd; @@ -107,7 +107,7 @@ private static List initNewFields(ObjectKlass.KlassVersion holder, List

Date: Thu, 7 Dec 2023 10:53:45 +0100 Subject: [PATCH 138/593] array length: handle constant case the same in simplify and canon --- .../compiler/nodes/java/ArrayLengthNode.java | 49 +++++++++---------- 1 file changed, 23 insertions(+), 26 deletions(-) diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/nodes/java/ArrayLengthNode.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/nodes/java/ArrayLengthNode.java index fec1772f1d86..0ef69f766e63 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/nodes/java/ArrayLengthNode.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/nodes/java/ArrayLengthNode.java @@ -108,38 +108,35 @@ public ValueNode canonical(CanonicalizerTool tool, ValueNode forValue) { if (forValue.isNullConstant()) { return new DeoptimizeNode(DeoptimizationAction.InvalidateReprofile, DeoptimizationReason.NullCheckException); } - /** * Normally we run replacement to any length provider node in simplify but for snippets and - * explode loop we run a limited form to constants before. + * explode loop we run a limited form for constants before. This is needed for unrolling for + * example that uses #canonical instead of #simplify to not recompute the cfg all the time. */ - boolean foldBasedOnLowering = graph().isAfterStage(StageFlag.HIGH_TIER_LOWERING); - if (!foldBasedOnLowering) { - ValueNode len = GraphUtil.arrayLength(getValue(), ArrayLengthProvider.FindLengthMode.SEARCH_ONLY, tool.getConstantReflection()); - if (len != null && len.isConstant()) { - return len; - } + ValueNode len = searchForConstantLength(tool.getConstantReflection()); + if (len != null) { + return len; } - return this; } + private ValueNode searchForConstantLength(ConstantReflectionProvider constantReflection) { + ValueNode len = GraphUtil.arrayLength(getValue(), ArrayLengthProvider.FindLengthMode.SEARCH_ONLY, constantReflection); + return len != null && len.isConstant() ? len : null; + } + @Override public void simplify(SimplifierTool tool) { - boolean foldBasedOnLowering = graph().isAfterStage(StageFlag.HIGH_TIER_LOWERING); - if (!foldBasedOnLowering) { - /* - * If we are before lowering we only fold to constants: replacing the load with a length - * guarded pi can be done in multiple places and we only want to do it once for all - * users, so we let it be done after lowering to catch all users at once. - */ - ValueNode len = GraphUtil.arrayLength(getValue(), ArrayLengthProvider.FindLengthMode.SEARCH_ONLY, tool.getConstantReflection()); - foldBasedOnLowering = len != null && len.isConstant(); - } - if (!foldBasedOnLowering) { + /* + * If we are before lowering we only fold to constants: replacing the load with a length + * guarded pi can be done in multiple places and we only want to do it once for all users, + * so we let it be done after lowering to catch all users at once. + */ + ValueNode constantLength = searchForConstantLength(tool.getConstantReflection()); + if (constantLength == null && !graph().isAfterStage(StageFlag.HIGH_TIER_LOWERING)) { return; } - ValueNode length = readArrayLength(getValue(), tool.getConstantReflection()); + ValueNode length = constantLength == null ? readArrayLength(getValue(), tool.getConstantReflection()) : constantLength; if (tool.allUsagesAvailable() && length != null) { /** * If we are using the array length directly (for example from an allocation) instead of @@ -172,16 +169,16 @@ public void simplify(SimplifierTool tool) { * */ StructuredGraph graph = graph(); - ValueNode replacee = length; + ValueNode replacement = length; if (!length.isConstant() && length.stamp(NodeView.DEFAULT).canBeImprovedWith(StampFactory.positiveInt())) { BeginNode guard = graph.add(new BeginNode()); graph.addAfterFixed(this, guard); - replacee = graph.addWithoutUnique(new PiNode(length, StampFactory.positiveInt(), guard)); + replacement = graph.addWithoutUnique(new PiNode(length, StampFactory.positiveInt(), guard)); } - if (!replacee.isAlive()) { - replacee = graph.addOrUnique(replacee); + if (!replacement.isAlive()) { + replacement = graph.addOrUnique(replacement); } - graph.replaceFixedWithFloating(this, replacee); + graph.replaceFixedWithFloating(this, replacement); } } From 8a2dad6002fbe81c1dff1bdede3cc13d8e95107e Mon Sep 17 00:00:00 2001 From: Sacha Coppey Date: Wed, 8 Nov 2023 12:10:20 +0100 Subject: [PATCH 139/593] Execute potentially dangerous bootstrap methods at run time instead of build time --- .../graal/compiler/java/BytecodeParser.java | 48 +- .../BootstrapMethodIntrospectionImpl.java | 145 +++++ .../serviceprovider/GraalServices.java | 25 + .../infrastructure/WrappedConstantPool.java | 84 +-- .../BootstrapMethodConfiguration.java | 156 ++++++ .../core/bootstrap/BootstrapMethodInfo.java | 61 ++ .../phases/AnalysisGraphBuilderPhase.java | 156 +++++- .../phases/SharedGraphBuilderPhase.java | 523 +++++++++++++++++- .../SubstrateGraphBuilderPlugins.java | 4 +- 9 files changed, 1094 insertions(+), 108 deletions(-) create mode 100644 compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/serviceprovider/BootstrapMethodIntrospectionImpl.java create mode 100644 substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/bootstrap/BootstrapMethodConfiguration.java create mode 100644 substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/bootstrap/BootstrapMethodInfo.java diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/java/BytecodeParser.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/java/BytecodeParser.java index bc05f845e39a..770d22fc45fb 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/java/BytecodeParser.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/java/BytecodeParser.java @@ -1792,7 +1792,7 @@ private boolean genDynamicInvokeHelper(ResolvedJavaMethod target, int cpi, int o } - boolean hasReceiver = (opcode == INVOKEDYNAMIC) ? false : !target.isStatic(); + boolean hasReceiver = opcode != INVOKEDYNAMIC && !target.isStatic(); ValueNode[] args = frameState.popArguments(target.getSignature().getParameterCount(hasReceiver)); if (hasReceiver) { appendInvoke(InvokeKind.Virtual, target, args, null); @@ -2089,12 +2089,7 @@ private static boolean checkPartialIntrinsicExit(ValueNode[] originalArgs, Value protected Invoke createNonInlinedInvoke(ExceptionEdgeAction exceptionEdge, int invokeBci, ValueNode[] invokeArgs, ResolvedJavaMethod targetMethod, InvokeKind invokeKind, JavaKind resultType, JavaType returnType, JavaTypeProfile profile) { - StampPair returnStamp = graphBuilderConfig.getPlugins().getOverridingStamp(this, returnType, false); - if (returnStamp == null) { - returnStamp = StampFactory.forDeclaredType(graph.getAssumptions(), returnType, false); - } - - MethodCallTargetNode callTarget = graph.add(createMethodCallTarget(invokeKind, targetMethod, invokeArgs, returnStamp, profile)); + MethodCallTargetNode callTarget = graph.add(createMethodCallTarget(invokeKind, targetMethod, invokeArgs, returnType, profile)); Invoke invoke = createNonInlinedInvoke(exceptionEdge, invokeBci, callTarget, resultType); for (InlineInvokePlugin plugin : graphBuilderConfig.getPlugins().getInlineInvokePlugins()) { @@ -2105,11 +2100,14 @@ protected Invoke createNonInlinedInvoke(ExceptionEdgeAction exceptionEdge, int i } protected Invoke createNonInlinedInvoke(ExceptionEdgeAction exceptionEdge, int invokeBci, CallTargetNode callTarget, JavaKind resultType) { + Invoke invoke; if (exceptionEdge == ExceptionEdgeAction.OMIT) { - return createInvoke(invokeBci, callTarget, resultType); + invoke = append(createInvoke(invokeBci, callTarget, resultType)); } else { - return createInvokeWithException(invokeBci, callTarget, resultType, exceptionEdge); + invoke = append(createInvokeWithException(invokeBci, callTarget, resultType, exceptionEdge)); } + invoke.setStateAfter(createFrameState(stream.nextBCI(), invoke)); + return invoke; } /** @@ -2675,14 +2673,22 @@ private ValueNode processCalleeReturn(ResolvedJavaMethod targetMethod, InliningS return null; } + public MethodCallTargetNode createMethodCallTarget(InvokeKind invokeKind, ResolvedJavaMethod targetMethod, ValueNode[] args, JavaType returnType, JavaTypeProfile profile) { + StampPair returnStamp = graphBuilderConfig.getPlugins().getOverridingStamp(this, returnType, false); + if (returnStamp == null) { + returnStamp = StampFactory.forDeclaredType(graph.getAssumptions(), returnType, false); + } + + return createMethodCallTarget(invokeKind, targetMethod, args, returnStamp, profile); + } + public MethodCallTargetNode createMethodCallTarget(InvokeKind invokeKind, ResolvedJavaMethod targetMethod, ValueNode[] args, StampPair returnStamp, JavaTypeProfile profile) { return new MethodCallTargetNode(invokeKind, targetMethod, args, returnStamp, profile); } protected InvokeNode createInvoke(int invokeBci, CallTargetNode callTarget, JavaKind resultType) { - InvokeNode invoke = append(new InvokeNode(callTarget, invokeBci)); + InvokeNode invoke = new InvokeNode(callTarget, invokeBci); frameState.pushReturn(resultType, invoke); - invoke.setStateAfter(createFrameState(stream.nextBCI(), invoke)); return invoke; } @@ -2696,9 +2702,8 @@ protected InvokeWithExceptionNode createInvokeWithException(int invokeBci, CallT } AbstractBeginNode exceptionEdge = handleException(null, bci(), exceptionEdgeAction == ExceptionEdgeAction.INCLUDE_AND_DEOPTIMIZE); - InvokeWithExceptionNode invoke = append(new InvokeWithExceptionNode(callTarget, exceptionEdge, invokeBci)); + InvokeWithExceptionNode invoke = new InvokeWithExceptionNode(callTarget, exceptionEdge, invokeBci); frameState.pushReturn(resultType, invoke); - invoke.setStateAfter(createFrameState(stream.nextBCI(), invoke)); return invoke; } @@ -3939,7 +3944,7 @@ public BailoutException bailout(String string) { throw GraphUtil.createBailoutException(string, bailout, elements); } - private FrameState createFrameState(int bci, StateSplit forStateSplit) { + protected FrameState createFrameState(int bci, StateSplit forStateSplit) { assert !(forStateSplit instanceof BytecodeExceptionNode) : Assertions.errorMessageContext("forStateSplit", forStateSplit); if (currentBlock != null && bci > currentBlock.getEndBci()) { frameState.clearNonLiveLocals(currentBlock, liveness, false); @@ -4023,19 +4028,24 @@ public void storeLocal(JavaKind kind, int index) { protected void genLoadConstant(int cpi, int opcode) { Object con = lookupConstant(cpi, opcode, false); + genLoadConstantHelper(con, opcode); + } + + protected void genLoadConstantHelper(Object con, int opcode) { if (con == null) { handleUnresolvedLoadConstant(null); - } else if (con instanceof JavaType) { + } else if (con instanceof JavaType type) { // this is a load of class constant which might be unresolved - JavaType type = (JavaType) con; if (typeIsResolved(type)) { + assert opcode != LDC2_W : "Type cannot use two slots"; frameState.push(JavaKind.Object, appendConstant(getConstantReflection().asJavaClass((ResolvedJavaType) type))); } else { handleUnresolvedLoadConstant(type); } - } else if (con instanceof JavaConstant) { - JavaConstant constant = (JavaConstant) con; - frameState.push(constant.getJavaKind(), appendConstant(constant)); + } else if (con instanceof JavaConstant constant) { + JavaKind javaKind = constant.getJavaKind(); + assert (opcode == LDC2_W) == javaKind.needsTwoSlots() : "Constant required incorrect number of slots: needsTwoSlots is " + javaKind.needsTwoSlots(); + frameState.push(javaKind, appendConstant(constant)); } else if (!(con instanceof Throwable)) { /** * We use the exceptional return value of {@link #lookupConstant(int, int)} as sentinel diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/serviceprovider/BootstrapMethodIntrospectionImpl.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/serviceprovider/BootstrapMethodIntrospectionImpl.java new file mode 100644 index 000000000000..86051dc7ff3d --- /dev/null +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/serviceprovider/BootstrapMethodIntrospectionImpl.java @@ -0,0 +1,145 @@ +/* + * Copyright (c) 2023, 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 jdk.graal.compiler.serviceprovider; + +import java.lang.reflect.Method; +import java.util.List; + +import jdk.graal.compiler.core.common.BootstrapMethodIntrospection; +import jdk.graal.compiler.debug.GraalError; +import jdk.vm.ci.meta.JavaConstant; +import jdk.vm.ci.meta.ResolvedJavaMethod; + +public class BootstrapMethodIntrospectionImpl implements BootstrapMethodIntrospection { + private final Object wrapped; + + /** + * The interface jdk.vm.ci.meta.ConstantPool.BootstrapMethodInvocation was introduced in JVMCI + * 22.1. + */ + private static final Class bsmClass; + private static final Method bsmGetMethod; + private static final Method bsmIsInvokeDynamic; + private static final Method bsmGetName; + private static final Method bsmGetType; + private static final Method bsmGetStaticArguments; + + static { + Class bootstrapMethodClass = null; + try { + bootstrapMethodClass = Class.forName("jdk.vm.ci.meta.ConstantPool$BootstrapMethodInvocation"); + } catch (ClassNotFoundException e) { + } + bsmClass = bootstrapMethodClass; + + Method bootstrapMethodGetMethod = null; + Method bootstrapMethodIsInvokeDynamic = null; + Method bootstrapMethodGetName = null; + Method bootstrapMethodGetType = null; + Method bootstrapMethodGetStaticArguments = null; + + try { + bootstrapMethodGetMethod = bsmClass == null ? null : bsmClass.getMethod("getMethod"); + } catch (NoSuchMethodException e) { + } + + try { + bootstrapMethodIsInvokeDynamic = bsmClass == null ? null : bsmClass.getMethod("isInvokeDynamic"); + } catch (NoSuchMethodException e) { + } + + try { + bootstrapMethodGetName = bsmClass == null ? null : bsmClass.getMethod("getName"); + } catch (NoSuchMethodException e) { + } + + try { + bootstrapMethodGetType = bsmClass == null ? null : bsmClass.getMethod("getType"); + } catch (NoSuchMethodException e) { + } + + try { + bootstrapMethodGetStaticArguments = bsmClass == null ? null : bsmClass.getMethod("getStaticArguments"); + } catch (NoSuchMethodException e) { + } + + bsmGetMethod = bootstrapMethodGetMethod; + bsmIsInvokeDynamic = bootstrapMethodIsInvokeDynamic; + bsmGetName = bootstrapMethodGetName; + bsmGetType = bootstrapMethodGetType; + bsmGetStaticArguments = bootstrapMethodGetStaticArguments; + + } + + public BootstrapMethodIntrospectionImpl(Object wrapped) { + this.wrapped = wrapped; + } + + @Override + public ResolvedJavaMethod getMethod() { + try { + return (ResolvedJavaMethod) bsmGetMethod.invoke(wrapped); + } catch (Throwable t) { + throw GraalError.shouldNotReachHere(t); // ExcludeFromJacocoGeneratedReport + } + } + + @Override + public boolean isInvokeDynamic() { + try { + return (boolean) bsmIsInvokeDynamic.invoke(wrapped); + } catch (Throwable t) { + throw GraalError.shouldNotReachHere(t); // ExcludeFromJacocoGeneratedReport + } + } + + @Override + public String getName() { + try { + return (String) bsmGetName.invoke(wrapped); + } catch (Throwable t) { + throw GraalError.shouldNotReachHere(t); // ExcludeFromJacocoGeneratedReport + } + } + + @Override + public JavaConstant getType() { + try { + return (JavaConstant) bsmGetType.invoke(wrapped); + } catch (Throwable t) { + throw GraalError.shouldNotReachHere(t); // ExcludeFromJacocoGeneratedReport + } + } + + @SuppressWarnings("unchecked") + @Override + public List getStaticArguments() { + try { + return (List) bsmGetStaticArguments.invoke(wrapped); + } catch (Throwable t) { + throw GraalError.shouldNotReachHere(t); // ExcludeFromJacocoGeneratedReport + } + } +} diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/serviceprovider/GraalServices.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/serviceprovider/GraalServices.java index 0f586ca9a1de..c50328fe0d53 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/serviceprovider/GraalServices.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/serviceprovider/GraalServices.java @@ -40,6 +40,7 @@ import java.util.ServiceConfigurationError; import java.util.ServiceLoader; +import jdk.graal.compiler.core.common.BootstrapMethodIntrospection; import jdk.graal.compiler.debug.GraalError; import jdk.vm.ci.meta.ConstantPool; import jdk.vm.ci.meta.EncodedSpeculationReason; @@ -61,10 +62,12 @@ public final class GraalServices { private static final Method constantPoolLookupMethodWithCaller; private static final Method constantPoolLookupConstantWithResolve; + private static final Method constantPoolLookupBootstrapMethodInvocation; static { Method lookupMethodWithCaller = null; Method lookupConstantWithResolve = null; + Method lookupBootstrapMethodInvocation = null; try { lookupMethodWithCaller = ConstantPool.class.getDeclaredMethod("lookupMethod", Integer.TYPE, Integer.TYPE, ResolvedJavaMethod.class); @@ -76,8 +79,14 @@ public final class GraalServices { } catch (NoSuchMethodException e) { } + try { + lookupBootstrapMethodInvocation = ConstantPool.class.getDeclaredMethod("lookupBootstrapMethodInvocation", Integer.TYPE, Integer.TYPE); + } catch (NoSuchMethodException e) { + } + constantPoolLookupMethodWithCaller = lookupMethodWithCaller; constantPoolLookupConstantWithResolve = lookupConstantWithResolve; + constantPoolLookupBootstrapMethodInvocation = lookupBootstrapMethodInvocation; } private GraalServices() { @@ -478,6 +487,22 @@ public static Object lookupConstant(ConstantPool constantPool, int cpi, boolean return constantPool.lookupConstant(cpi); } + public static BootstrapMethodIntrospection lookupBootstrapMethodIntrospection(ConstantPool constantPool, int cpi, int opcode) { + if (constantPoolLookupBootstrapMethodInvocation != null) { + try { + Object bootstrapMethodInvocation = constantPoolLookupBootstrapMethodInvocation.invoke(constantPool, cpi, opcode); + if (bootstrapMethodInvocation != null) { + return new BootstrapMethodIntrospectionImpl(bootstrapMethodInvocation); + } + } catch (InvocationTargetException e) { + throw rethrow(e.getCause()); + } catch (IllegalAccessException e) { + throw GraalError.shouldNotReachHere(e, "The method lookupBootstrapMethodInvocation should be accessible"); + } + } + return null; + } + @SuppressWarnings("unchecked") static RuntimeException rethrow(Throwable ex) throws E { throw (E) ex; diff --git a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/infrastructure/WrappedConstantPool.java b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/infrastructure/WrappedConstantPool.java index 8c6cf91844f5..77c40e622c03 100644 --- a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/infrastructure/WrappedConstantPool.java +++ b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/infrastructure/WrappedConstantPool.java @@ -36,6 +36,7 @@ import jdk.graal.compiler.core.common.BootstrapMethodIntrospection; import jdk.graal.compiler.debug.GraalError; +import jdk.graal.compiler.serviceprovider.BootstrapMethodIntrospectionImpl; import jdk.graal.compiler.serviceprovider.GraalServices; import jdk.vm.ci.meta.ConstantPool; import jdk.vm.ci.meta.JavaConstant; @@ -78,17 +79,6 @@ private JavaConstant lookupConstant(JavaConstant constant) { */ private static final Method lookupMethodWithCaller = ReflectionUtil.lookupMethod(true, ConstantPool.class, "lookupMethod", int.class, int.class, ResolvedJavaMethod.class); - /** - * The interface jdk.vm.ci.meta.ConstantPool.BootstrapMethodInvocation was introduced in JVMCI - * 22.1. - */ - private static final Class bsmClass = ReflectionUtil.lookupClass(true, "jdk.vm.ci.meta.ConstantPool$BootstrapMethodInvocation"); - private static final Method bsmGetMethod = bsmClass == null ? null : ReflectionUtil.lookupMethod(bsmClass, "getMethod"); - private static final Method bsmIsInvokeDynamic = bsmClass == null ? null : ReflectionUtil.lookupMethod(bsmClass, "isInvokeDynamic"); - private static final Method bsmGetName = bsmClass == null ? null : ReflectionUtil.lookupMethod(bsmClass, "getName"); - private static final Method bsmGetType = bsmClass == null ? null : ReflectionUtil.lookupMethod(bsmClass, "getType"); - private static final Method bsmGetStaticArguments = bsmClass == null ? null : ReflectionUtil.lookupMethod(bsmClass, "getStaticArguments"); - @Override public void loadReferencedType(int cpi, int opcode, boolean initialize) { GraalError.guarantee(!initialize, "Must not initialize classes"); @@ -199,80 +189,42 @@ public BootstrapMethodIntrospection lookupBootstrapMethodIntrospection(int cpi, if (cpLookupBootstrapMethodInvocation != null) { try { Object bootstrapMethodInvocation = cpLookupBootstrapMethodInvocation.invoke(wrapped, cpi, opcode); - return new WrappedBootstrapMethodInvocation(bootstrapMethodInvocation); - } catch (Throwable ignored) { - // GR-38955 - understand why exception is thrown + if (bootstrapMethodInvocation != null) { + return new WrappedBootstrapMethodInvocation(bootstrapMethodInvocation); + } + } catch (InvocationTargetException ex) { + throw rethrow(ex.getCause()); + } catch (IllegalAccessException e) { + throw GraalError.shouldNotReachHere(e, "The method lookupBootstrapMethodInvocation should be accessible."); } } return null; } - public class WrappedBootstrapMethodInvocation implements BootstrapMethodIntrospection { - private final Object wrapped; + @SuppressWarnings("unchecked") + static RuntimeException rethrow(Throwable ex) throws E { + throw (E) ex; + } + + public class WrappedBootstrapMethodInvocation extends BootstrapMethodIntrospectionImpl { public WrappedBootstrapMethodInvocation(Object wrapped) { - this.wrapped = wrapped; + super(wrapped); } @Override public ResolvedJavaMethod getMethod() { - if (bsmGetMethod != null) { - try { - return universe.lookup((ResolvedJavaMethod) bsmGetMethod.invoke(wrapped)); - } catch (Throwable t) { - throw GraalError.shouldNotReachHere(t); // ExcludeFromJacocoGeneratedReport - } - } - throw GraalError.shouldNotReachHere("unexpected null"); // ExcludeFromJacocoGeneratedReport - } - - @Override - public boolean isInvokeDynamic() { - if (bsmIsInvokeDynamic != null) { - try { - return (boolean) bsmIsInvokeDynamic.invoke(wrapped); - } catch (Throwable t) { - throw GraalError.shouldNotReachHere(t); // ExcludeFromJacocoGeneratedReport - } - } - throw GraalError.shouldNotReachHere("unexpected null"); // ExcludeFromJacocoGeneratedReport - } - - @Override - public String getName() { - if (bsmGetName != null) { - try { - return (String) bsmGetName.invoke(wrapped); - } catch (Throwable t) { - throw GraalError.shouldNotReachHere(t); // ExcludeFromJacocoGeneratedReport - } - } - throw GraalError.shouldNotReachHere("unexpected null"); // ExcludeFromJacocoGeneratedReport + return universe.lookup(super.getMethod()); } @Override public JavaConstant getType() { - if (bsmGetType != null) { - try { - return lookupConstant((JavaConstant) bsmGetType.invoke(wrapped)); - } catch (Throwable t) { - throw GraalError.shouldNotReachHere(t); // ExcludeFromJacocoGeneratedReport - } - } - throw GraalError.shouldNotReachHere("unexpected null"); // ExcludeFromJacocoGeneratedReport + return lookupConstant(super.getType()); } @Override public List getStaticArguments() { - if (bsmGetStaticArguments != null) { - try { - List original = (List) bsmGetStaticArguments.invoke(wrapped); - return original.stream().map(e -> lookupConstant((JavaConstant) e)).collect(Collectors.toList()); - } catch (Throwable t) { - throw GraalError.shouldNotReachHere(t); // ExcludeFromJacocoGeneratedReport - } - } - throw GraalError.shouldNotReachHere("unexpected null"); // ExcludeFromJacocoGeneratedReport + return super.getStaticArguments().stream().map(WrappedConstantPool.this::lookupConstant).collect(Collectors.toList()); } } } diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/bootstrap/BootstrapMethodConfiguration.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/bootstrap/BootstrapMethodConfiguration.java new file mode 100644 index 000000000000..b684efa32ff4 --- /dev/null +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/bootstrap/BootstrapMethodConfiguration.java @@ -0,0 +1,156 @@ +/* + * Copyright (c) 2023, 2023, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.svm.core.bootstrap; + +import java.lang.invoke.ConstantBootstraps; +import java.lang.invoke.LambdaMetafactory; +import java.lang.invoke.MethodHandle; +import java.lang.invoke.MethodHandles; +import java.lang.invoke.MethodType; +import java.lang.invoke.StringConcatFactory; +import java.lang.invoke.TypeDescriptor; +import java.lang.reflect.Executable; +import java.lang.reflect.Method; +import java.lang.runtime.ObjectMethods; +import java.lang.runtime.SwitchBootstraps; +import java.util.Set; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentMap; + +import org.graalvm.nativeimage.ImageSingletons; +import org.graalvm.nativeimage.hosted.RuntimeReflection; + +import com.oracle.svm.core.feature.AutomaticallyRegisteredFeature; +import com.oracle.svm.core.feature.InternalFeature; +import com.oracle.svm.util.ReflectionUtil; + +import jdk.vm.ci.meta.ResolvedJavaMethod; + +/** + * Class storing a list of bootstrap methods that are allowed to be executed at build time. Those + * methods are trusted methods from the JDK. Additionally used to register methods used by some + * bootstrap methods for runtime reflection. + */ +@AutomaticallyRegisteredFeature +public class BootstrapMethodConfiguration implements InternalFeature { + + public record BootstrapMethodRecord(int bci, int cpi, ResolvedJavaMethod method) { + } + + /* + * Map used to cache the BootstrapMethodInfo and reuse it for duplicated bytecode, avoiding to + * execute the bootstrap method for the same bci and method pair. This can happen during + * bytecode parsing as some blocks are duplicated, or for methods that are parsed multiple times + * (see MultiMethod). + */ + private final ConcurrentMap bootstrapMethodInfoCache = new ConcurrentHashMap<>(); + private final Set indyBuildTimeAllowList; + private final Set condyBuildTimeAllowList; + private final Set trustedCondy; + + public static BootstrapMethodConfiguration singleton() { + return ImageSingletons.lookup(BootstrapMethodConfiguration.class); + } + + public BootstrapMethodConfiguration() { + /* + * Bootstrap method used for Lambdas. Executing this method at run time implies defining + * hidden class at run time, which is unsupported. + */ + Method metafactory = ReflectionUtil.lookupMethod(LambdaMetafactory.class, "metafactory", MethodHandles.Lookup.class, String.class, MethodType.class, MethodType.class, MethodHandle.class, + MethodType.class); + /* Alternate version of LambdaMetafactory.metafactory. */ + Method altMetafactory = ReflectionUtil.lookupMethod(LambdaMetafactory.class, "altMetafactory", MethodHandles.Lookup.class, String.class, MethodType.class, Object[].class); + + /* + * Bootstrap method used to optimize String concatenation. Executing it at run time + * currently causes a StackOverFlow error as it infinitely calls itself. + */ + Method makeConcat = ReflectionUtil.lookupMethod(StringConcatFactory.class, "makeConcat", MethodHandles.Lookup.class, String.class, MethodType.class); + /* Alternate version of StringConcatFactory.makeConcat with constant arguments. */ + Method makeConcatWithConstants = ReflectionUtil.lookupMethod(StringConcatFactory.class, "makeConcatWithConstants", MethodHandles.Lookup.class, String.class, MethodType.class, String.class, + Object[].class); + + /* Causes deadlock in Permission feature. */ + Method bootstrap = ReflectionUtil.lookupMethod(ObjectMethods.class, "bootstrap", MethodHandles.Lookup.class, String.class, TypeDescriptor.class, Class.class, String.class, + MethodHandle[].class); + Method typeSwitch = ReflectionUtil.lookupMethod(SwitchBootstraps.class, "typeSwitch", MethodHandles.Lookup.class, String.class, MethodType.class, Object[].class); + + indyBuildTimeAllowList = Set.of(metafactory, altMetafactory, makeConcat, makeConcatWithConstants, bootstrap, typeSwitch); + + /* Bootstrap methods used for various dynamic constants. */ + Method nullConstant = ReflectionUtil.lookupMethod(ConstantBootstraps.class, "nullConstant", MethodHandles.Lookup.class, String.class, Class.class); + Method primitiveClass = ReflectionUtil.lookupMethod(ConstantBootstraps.class, "primitiveClass", MethodHandles.Lookup.class, String.class, Class.class); + Method enumConstant = ReflectionUtil.lookupMethod(ConstantBootstraps.class, "enumConstant", MethodHandles.Lookup.class, String.class, Class.class); + Method getStaticFinal = ReflectionUtil.lookupMethod(ConstantBootstraps.class, "getStaticFinal", MethodHandles.Lookup.class, String.class, Class.class, Class.class); + Method invoke = ReflectionUtil.lookupMethod(ConstantBootstraps.class, "invoke", MethodHandles.Lookup.class, String.class, Class.class, MethodHandle.class, Object[].class); + Method explicitCast = ReflectionUtil.lookupMethod(ConstantBootstraps.class, "explicitCast", MethodHandles.Lookup.class, String.class, Class.class, Object.class); + + /* Bootstrap methods used for dynamic constants representing class data. */ + Method classData = ReflectionUtil.lookupMethod(MethodHandles.class, "classData", MethodHandles.Lookup.class, String.class, Class.class); + Method classDataAt = ReflectionUtil.lookupMethod(MethodHandles.class, "classDataAt", MethodHandles.Lookup.class, String.class, Class.class, int.class); + + /* Set of bootstrap methods for constant dynamic allowed at build time is empty for now */ + condyBuildTimeAllowList = Set.of(); + trustedCondy = Set.of(nullConstant, primitiveClass, enumConstant, getStaticFinal, invoke, explicitCast, classData, classDataAt); + } + + @Override + public void beforeAnalysis(BeforeAnalysisAccess a) { + /* + * Those methods are used by ObjectMethods.bootstrap to combine the Strings of the records + * into one String + */ + Class stringConcatHelper = ReflectionUtil.lookupClass(false, "java.lang.StringConcatHelper"); + Class formatConcatItem = ReflectionUtil.lookupClass(false, "jdk.internal.util.FormatConcatItem"); + RuntimeReflection.register(ReflectionUtil.lookupMethod(stringConcatHelper, "prepend", long.class, byte[].class, formatConcatItem, String.class)); + RuntimeReflection.register(ReflectionUtil.lookupMethod(stringConcatHelper, "mix", long.class, formatConcatItem)); + } + + /** + * Check if the provided method is allowed to be executed at build time. + */ + public boolean isIndyAllowedAtBuildTime(Executable method) { + return indyBuildTimeAllowList.contains(method); + } + + /** + * Check if the provided method is allowed to be executed at build time. + */ + public boolean isCondyAllowedAtBuildTime(Executable method) { + return condyBuildTimeAllowList.contains(method); + } + + /** + * Check if the provided method is defined in the JDK. + */ + public boolean isCondyTrusted(Executable method) { + return trustedCondy.contains(method); + } + + public ConcurrentMap getBootstrapMethodInfoCache() { + return bootstrapMethodInfoCache; + } +} diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/bootstrap/BootstrapMethodInfo.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/bootstrap/BootstrapMethodInfo.java new file mode 100644 index 000000000000..1d6365d78d33 --- /dev/null +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/bootstrap/BootstrapMethodInfo.java @@ -0,0 +1,61 @@ +/* + * Copyright (c) 2023, 2023, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.svm.core.bootstrap; + +/** + * Information about a bootstrap method on an invoke dynamic or constant dynamic call. This object + * stores the CallSite or the constant linked to the call, allowing to execute the bootstrap method + * only once. + *

+ * As in Hotspot, there is no synchronization mechanism, meaning it is possible to have a bootstrap + * method executed twice for the same call if multiple threads execute it at the same time. + *

+ * In Hotspot, the CallSite or the constant is stored in the constant pool of the Class, but in + * Native Image, we only store it using this object, which is attached to the call. + */ +public final class BootstrapMethodInfo { + /** + * All field accesses are manually generated in Graal graphs. + */ + @SuppressWarnings("unused") private Object object; + + /** + * Class used to wrap an exception and store it in {@link BootstrapMethodInfo#object} to + * distinguish from a {@link Throwable} outputted by a constant dynamic. + *

+ * If a {@link ExceptionWrapper} is stored in {@link BootstrapMethodInfo#object}, the + * {@link ExceptionWrapper#throwable} is rethrown instead of calling the bootstrap method again. + *

+ * This class is not implemented as a record as it might cause cycles since it would have + * bootstrapped methods. + */ + public static class ExceptionWrapper { + public final Throwable throwable; + + public ExceptionWrapper(Throwable throwable) { + this.throwable = throwable; + } + } +} diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/phases/AnalysisGraphBuilderPhase.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/phases/AnalysisGraphBuilderPhase.java index df68872714bf..a538662b8981 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/phases/AnalysisGraphBuilderPhase.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/phases/AnalysisGraphBuilderPhase.java @@ -24,29 +24,64 @@ */ package com.oracle.svm.hosted.phases; +import java.lang.invoke.CallSite; +import java.lang.invoke.MethodHandle; +import java.lang.invoke.MethodType; +import java.lang.invoke.WrongMethodTypeException; +import java.util.List; + +import com.oracle.graal.pointsto.heap.ImageHeapInstance; import com.oracle.graal.pointsto.infrastructure.AnalysisConstantPool; +import com.oracle.graal.pointsto.infrastructure.OriginalMethodProvider; import com.oracle.graal.pointsto.meta.AnalysisMethod; +import com.oracle.svm.core.bootstrap.BootstrapMethodConfiguration; +import com.oracle.svm.core.meta.DirectSubstrateObjectConstant; import com.oracle.svm.hosted.SVMHost; +import com.oracle.svm.hosted.ameta.AnalysisConstantReflectionProvider; import com.oracle.svm.hosted.code.SubstrateCompilationDirectives; import com.oracle.svm.util.ModuleSupport; import jdk.graal.compiler.core.common.BootstrapMethodIntrospection; +import jdk.graal.compiler.core.common.type.StampFactory; +import jdk.graal.compiler.core.common.type.TypeReference; import jdk.graal.compiler.java.BciBlockMapping; import jdk.graal.compiler.java.BytecodeParser; import jdk.graal.compiler.java.FrameStateBuilder; import jdk.graal.compiler.java.GraphBuilderPhase; +import jdk.graal.compiler.nodes.AbstractBeginNode; import jdk.graal.compiler.nodes.CallTargetNode.InvokeKind; +import jdk.graal.compiler.nodes.ConstantNode; +import jdk.graal.compiler.nodes.EndNode; +import jdk.graal.compiler.nodes.FixedNode; +import jdk.graal.compiler.nodes.FixedWithNextNode; +import jdk.graal.compiler.nodes.IfNode; +import jdk.graal.compiler.nodes.InvokeWithExceptionNode; +import jdk.graal.compiler.nodes.LogicNode; +import jdk.graal.compiler.nodes.MergeNode; +import jdk.graal.compiler.nodes.NodeView; import jdk.graal.compiler.nodes.StructuredGraph; import jdk.graal.compiler.nodes.ValueNode; +import jdk.graal.compiler.nodes.calc.IsNullNode; +import jdk.graal.compiler.nodes.calc.ObjectEqualsNode; +import jdk.graal.compiler.nodes.extended.BoxNode; +import jdk.graal.compiler.nodes.extended.BranchProbabilityNode; +import jdk.graal.compiler.nodes.extended.BytecodeExceptionNode.BytecodeExceptionKind; +import jdk.graal.compiler.nodes.extended.UnboxNode; import jdk.graal.compiler.nodes.graphbuilderconf.GraphBuilderConfiguration; import jdk.graal.compiler.nodes.graphbuilderconf.IntrinsicContext; import jdk.graal.compiler.nodes.graphbuilderconf.InvocationPlugin; import jdk.graal.compiler.nodes.graphbuilderconf.NodePlugin; +import jdk.graal.compiler.nodes.java.InstanceOfNode; +import jdk.graal.compiler.nodes.java.NewArrayNode; +import jdk.graal.compiler.nodes.java.StoreIndexedNode; import jdk.graal.compiler.nodes.spi.CoreProviders; import jdk.graal.compiler.phases.OptimisticOptimizations; +import jdk.vm.ci.meta.JavaConstant; import jdk.vm.ci.meta.JavaKind; +import jdk.vm.ci.meta.JavaMethod; import jdk.vm.ci.meta.ResolvedJavaField; import jdk.vm.ci.meta.ResolvedJavaMethod; +import jdk.vm.ci.meta.ResolvedJavaType; public class AnalysisGraphBuilderPhase extends SharedGraphBuilderPhase { @@ -67,6 +102,7 @@ public static class AnalysisBytecodeParser extends SharedBytecodeParser { private final SVMHost hostVM; + @SuppressWarnings("this-escape") protected AnalysisBytecodeParser(GraphBuilderPhase.Instance graphBuilderInstance, StructuredGraph graph, BytecodeParser parent, ResolvedJavaMethod method, int entryBCI, IntrinsicContext intrinsicContext, SVMHost hostVM, boolean explicitExceptionEdges) { super(graphBuilderInstance, graph, parent, method, entryBCI, intrinsicContext, explicitExceptionEdges); @@ -114,11 +150,127 @@ private boolean tryNodePluginForDynamicInvocation(BootstrapMethodIntrospection b @Override protected void genInvokeDynamic(int cpi, int opcode) { - BootstrapMethodIntrospection bootstrap = ((AnalysisConstantPool) constantPool).lookupBootstrapMethodIntrospection(cpi, opcode); + BootstrapMethodIntrospection bootstrap; + try { + bootstrap = ((AnalysisConstantPool) constantPool).lookupBootstrapMethodIntrospection(cpi, opcode); + } catch (Throwable ex) { + bootstrapMethodHandler.handleBootstrapException(ex, "invoke dynamic"); + return; + } if (bootstrap != null && tryNodePluginForDynamicInvocation(bootstrap)) { return; } - super.genInvokeDynamic(cpi, opcode); + JavaMethod calleeMethod = lookupMethodInPool(cpi, opcode); + if (bootstrap == null || calleeMethod instanceof ResolvedJavaMethod || + BootstrapMethodConfiguration.singleton().isIndyAllowedAtBuildTime(OriginalMethodProvider.getJavaMethod(bootstrap.getMethod()))) { + super.genInvokeDynamic(cpi, opcode); + return; + } + + int parameterLength = bootstrap.getMethod().getParameters().length; + List staticArgumentsList = bootstrap.getStaticArguments(); + boolean isVarargs = bootstrap.getMethod().isVarArgs(); + int bci = bci(); + JavaConstant type = ((ImageHeapInstance) bootstrap.getType()).getHostedObject(); + MethodType methodType = (MethodType) ((DirectSubstrateObjectConstant) type).getObject(); + + if (!bootstrapMethodHandler.checkBootstrapParameters(bootstrap.getMethod(), staticArgumentsList, false)) { + WrongMethodTypeException cause = new WrongMethodTypeException("Cannot convert " + methodType + " to correct MethodType"); + replaceWithThrowingAtRuntime(this, new BootstrapMethodError("Bootstrap method initialization exception", cause)); + return; + } + + /* + * Steps 1-4: Fetch the linked call site and execute the bootstrap method if needed (see + * resolveLinkedObject for details). + */ + + Object initializedCallSite = bootstrapMethodHandler.resolveLinkedObject(bci, cpi, opcode, bootstrap, parameterLength, staticArgumentsList, isVarargs, false); + if (initializedCallSite instanceof Throwable) { + return; + } + ValueNode initializedCallSiteNode = (ValueNode) initializedCallSite; + + /* + * Check if the CallSite returned is null and throw a BootstrapMethodError if it is. + */ + + LogicNode isInitializedCallSiteNodeNull = graph.unique(IsNullNode.create(initializedCallSiteNode)); + createBytecodeExceptionCheck(bci, isInitializedCallSiteNodeNull, BytecodeExceptionKind.NULL_POINTER, false); + + /* + * Cast the object stored in the BootstrapMethodInfo to ensure it is a CallSite. Doing + * so allows to correctly throw a ClassCastException as hotspot does. + */ + ResolvedJavaType callSiteType = getMetaAccess().lookupJavaType(CallSite.class); + LogicNode isInstanceOfCallSite = graph.unique(InstanceOfNode.create(TypeReference.create(getAssumptions(), callSiteType), initializedCallSiteNode)); + ValueNode callSiteClass = ConstantNode.forConstant(StampFactory.forKind(JavaKind.Object), getConstantReflection().asJavaClass(callSiteType), getMetaAccess(), getGraph()); + createBytecodeExceptionCheck(bci, isInstanceOfCallSite, BytecodeExceptionKind.CLASS_CAST, true, initializedCallSiteNode, callSiteClass); + + bootstrapMethodHandler.invokeMethodAndAppend(bci, CallSite.class, MethodHandle.class, "dynamicInvoker", InvokeKind.Virtual, new ValueNode[]{initializedCallSiteNode}); + ValueNode methodHandleNode = frameState.pop(JavaKind.Object); + + bootstrapMethodHandler.invokeMethodAndAppend(bci, MethodHandle.class, MethodType.class, "type", InvokeKind.Virtual, new ValueNode[]{methodHandleNode}); + ValueNode callSiteMethodTypeNode = frameState.pop(JavaKind.Object); + + LogicNode checkMethodTypeEqual = graph.unique( + ObjectEqualsNode.create(callSiteMethodTypeNode, ConstantNode.forConstant(bootstrap.getType(), getMetaAccess(), getGraph()), getConstantReflection(), NodeView.DEFAULT)); + + EndNode checkMethodTypeEqualTrueEnd = graph.add(new EndNode()); + EndNode checkMethodTypeEqualFalseEnd = graph.add(new EndNode()); + + JavaConstant wrongMethodTypeException = ((AnalysisConstantReflectionProvider) getConstantReflection()) + .forObject(new WrongMethodTypeException("CallSite MethodType should be of type " + methodType)); + ConstantNode wrongMethodTypeExceptionNode = ConstantNode.forConstant(StampFactory.forKind(JavaKind.Object), wrongMethodTypeException, getMetaAccess(), getGraph()); + InvokeWithExceptionNode throwWrongMethodTypeNode = bootstrapMethodHandler.throwBootstrapMethodError(bci, wrongMethodTypeExceptionNode); + throwWrongMethodTypeNode.setNext(checkMethodTypeEqualFalseEnd); + + append(new IfNode(checkMethodTypeEqual, checkMethodTypeEqualTrueEnd, throwWrongMethodTypeNode, BranchProbabilityNode.NOT_LIKELY_PROFILE)); + + MergeNode checkMethodTypeEqualMergeNode = append(new MergeNode()); + checkMethodTypeEqualMergeNode.setStateAfter(createFrameState(stream.nextBCI(), checkMethodTypeEqualMergeNode)); + checkMethodTypeEqualMergeNode.addForwardEnd(checkMethodTypeEqualTrueEnd); + checkMethodTypeEqualMergeNode.addForwardEnd(checkMethodTypeEqualFalseEnd); + + /* Step 5.1: Prepare the arguments for invoking the MethodHandle. */ + + int paramLength = calleeMethod.getSignature().getParameterCount(false); + ValueNode[] invokeExactArguments = popArguments(paramLength); + NewArrayNode newArrayNode = append(new NewArrayNode(getMetaAccess().lookupJavaType(Object.class), ConstantNode.forInt(paramLength, getGraph()), true)); + for (int i = 0; i < paramLength; ++i) { + JavaKind stackKind = invokeExactArguments[i].getStackKind(); + if (stackKind.isPrimitive()) { + /* + * Primitive parameter have to be boxed because invokeExact takes a list of + * Objects as argument. + */ + invokeExactArguments[i] = append(BoxNode.create(invokeExactArguments[i], getMetaAccess().lookupJavaType(stackKind.toBoxedJavaClass()), stackKind)); + } + append(new StoreIndexedNode(newArrayNode, ConstantNode.forInt(i, getGraph()), null, null, JavaKind.Object, invokeExactArguments[i])); + } + ValueNode[] invokeArguments = new ValueNode[]{methodHandleNode, newArrayNode}; + + /* Step 5.2: Invoke the MethodHandle. */ + + Class returnType = methodType.returnType(); + JavaKind returnKind = getMetaAccessExtensionProvider().getStorageKind(getMetaAccess().lookupJavaType(returnType)); + bootstrapMethodHandler.invokeMethodAndAppend(bci, MethodHandle.class, Object.class, "invokeExact", InvokeKind.Virtual, invokeArguments, Object.class.arrayType()); + if (returnKind.equals(JavaKind.Void)) { + frameState.pop(JavaKind.Object); + } else if (returnKind.isPrimitive()) { + /* If the return type is a primitive, unbox the result of invokeExact. */ + frameState.push(returnKind, append(UnboxNode.create(getMetaAccess(), getConstantReflection(), frameState.pop(JavaKind.Object), returnKind))); + } + } + + private void createBytecodeExceptionCheck(int bci, LogicNode logicNode, BytecodeExceptionKind exception, boolean passingOnTrue, ValueNode... arguments) { + AbstractBeginNode passingPath = emitBytecodeExceptionCheck(logicNode, passingOnTrue, exception, arguments); + IfNode bytecodeExceptionIfNode = (IfNode) passingPath.predecessor(); + FixedWithNextNode bytecodeException = (FixedWithNextNode) (passingOnTrue ? bytecodeExceptionIfNode.falseSuccessor() : bytecodeExceptionIfNode.trueSuccessor()).next(); + InvokeWithExceptionNode bootstrapMethodError = bootstrapMethodHandler.throwBootstrapMethodError(bci, bytecodeException); + FixedNode bytecodeExceptionNext = bytecodeException.next(); + bytecodeException.setNext(bootstrapMethodError); + bootstrapMethodError.setNext(bytecodeExceptionNext); } @Override diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/phases/SharedGraphBuilderPhase.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/phases/SharedGraphBuilderPhase.java index fea99b3fcf07..4323ed7a11ac 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/phases/SharedGraphBuilderPhase.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/phases/SharedGraphBuilderPhase.java @@ -24,9 +24,15 @@ */ package com.oracle.svm.hosted.phases; +import static com.oracle.svm.core.SubstrateUtil.toUnboxedClass; +import static jdk.graal.compiler.bytecode.Bytecodes.LDC2_W; + import java.lang.invoke.LambdaConversionException; +import java.lang.invoke.MethodHandles; +import java.lang.invoke.MethodType; import java.lang.reflect.Constructor; import java.lang.reflect.Executable; +import java.lang.reflect.Field; import java.lang.reflect.Method; import java.lang.reflect.Modifier; import java.util.Arrays; @@ -35,64 +41,104 @@ import com.oracle.graal.pointsto.constraints.TypeInstantiationException; import com.oracle.graal.pointsto.constraints.UnresolvedElementException; import com.oracle.graal.pointsto.constraints.UnsupportedFeatureException; +import com.oracle.graal.pointsto.heap.ImageHeapConstant; +import com.oracle.graal.pointsto.heap.ImageHeapInstance; +import com.oracle.graal.pointsto.infrastructure.AnalysisConstantPool; import com.oracle.graal.pointsto.infrastructure.OriginalClassProvider; +import com.oracle.graal.pointsto.infrastructure.OriginalMethodProvider; +import com.oracle.graal.pointsto.meta.AnalysisField; import com.oracle.graal.pointsto.meta.AnalysisMetaAccess; +import com.oracle.graal.pointsto.meta.AnalysisMethod; import com.oracle.svm.common.meta.MultiMethod; import com.oracle.svm.core.SubstrateUtil; +import com.oracle.svm.core.bootstrap.BootstrapMethodConfiguration; +import com.oracle.svm.core.bootstrap.BootstrapMethodConfiguration.BootstrapMethodRecord; +import com.oracle.svm.core.bootstrap.BootstrapMethodInfo; +import com.oracle.svm.core.bootstrap.BootstrapMethodInfo.ExceptionWrapper; import com.oracle.svm.core.deopt.DeoptimizationSupport; import com.oracle.svm.core.graal.nodes.DeoptEntryBeginNode; import com.oracle.svm.core.graal.nodes.DeoptEntryNode; import com.oracle.svm.core.graal.nodes.DeoptEntrySupport; import com.oracle.svm.core.graal.nodes.DeoptProxyAnchorNode; +import com.oracle.svm.core.graal.nodes.LazyConstantNode; import com.oracle.svm.core.graal.nodes.LoweredDeadEndNode; +import com.oracle.svm.core.hub.DynamicHub; +import com.oracle.svm.core.meta.DirectSubstrateObjectConstant; import com.oracle.svm.core.nodes.SubstrateMethodCallTargetNode; import com.oracle.svm.core.util.UserError; import com.oracle.svm.core.util.UserError.UserException; import com.oracle.svm.core.util.VMError; import com.oracle.svm.hosted.ExceptionSynthesizer; import com.oracle.svm.hosted.LinkAtBuildTimeSupport; +import com.oracle.svm.hosted.ameta.AnalysisConstantReflectionProvider; import com.oracle.svm.hosted.code.FactoryMethodSupport; import com.oracle.svm.hosted.code.SubstrateCompilationDirectives; import com.oracle.svm.hosted.nodes.DeoptProxyNode; +import com.oracle.svm.hosted.snippets.SubstrateGraphBuilderPlugins.FieldOffsetConstantProvider; import com.oracle.svm.util.ReflectionUtil; import jdk.graal.compiler.api.replacements.Fold; +import jdk.graal.compiler.core.common.BootstrapMethodIntrospection; import jdk.graal.compiler.core.common.calc.Condition; +import jdk.graal.compiler.core.common.memory.MemoryOrderMode; +import jdk.graal.compiler.core.common.type.StampFactory; import jdk.graal.compiler.core.common.type.StampPair; +import jdk.graal.compiler.core.common.type.TypeReference; +import jdk.graal.compiler.debug.GraalError; import jdk.graal.compiler.graph.Node.NodeIntrinsic; +import jdk.graal.compiler.graph.NodeSourcePosition; import jdk.graal.compiler.java.BciBlockMapping; import jdk.graal.compiler.java.BytecodeParser; import jdk.graal.compiler.java.FrameStateBuilder; import jdk.graal.compiler.java.GraphBuilderPhase; import jdk.graal.compiler.nodes.AbstractBeginNode; import jdk.graal.compiler.nodes.BeginNode; +import jdk.graal.compiler.nodes.CallTargetNode; import jdk.graal.compiler.nodes.CallTargetNode.InvokeKind; import jdk.graal.compiler.nodes.ConstantNode; +import jdk.graal.compiler.nodes.EndNode; +import jdk.graal.compiler.nodes.FieldLocationIdentity; import jdk.graal.compiler.nodes.FixedNode; import jdk.graal.compiler.nodes.FixedWithNextNode; import jdk.graal.compiler.nodes.FrameState; import jdk.graal.compiler.nodes.IfNode; import jdk.graal.compiler.nodes.Invoke; +import jdk.graal.compiler.nodes.InvokeWithExceptionNode; +import jdk.graal.compiler.nodes.LogicNode; +import jdk.graal.compiler.nodes.MergeNode; +import jdk.graal.compiler.nodes.StateSplit; import jdk.graal.compiler.nodes.StructuredGraph; import jdk.graal.compiler.nodes.UnreachableBeginNode; import jdk.graal.compiler.nodes.ValueNode; +import jdk.graal.compiler.nodes.ValuePhiNode; import jdk.graal.compiler.nodes.calc.IsNullNode; +import jdk.graal.compiler.nodes.extended.BoxNode; import jdk.graal.compiler.nodes.extended.BranchProbabilityNode; +import jdk.graal.compiler.nodes.extended.UnboxNode; import jdk.graal.compiler.nodes.graphbuilderconf.GeneratedInvocationPlugin; import jdk.graal.compiler.nodes.graphbuilderconf.GraphBuilderConfiguration; import jdk.graal.compiler.nodes.graphbuilderconf.GraphBuilderPlugin; import jdk.graal.compiler.nodes.graphbuilderconf.IntrinsicContext; import jdk.graal.compiler.nodes.java.ExceptionObjectNode; +import jdk.graal.compiler.nodes.java.InstanceOfNode; +import jdk.graal.compiler.nodes.java.LoadFieldNode; import jdk.graal.compiler.nodes.java.MethodCallTargetNode; +import jdk.graal.compiler.nodes.java.NewArrayNode; +import jdk.graal.compiler.nodes.java.NewInstanceNode; +import jdk.graal.compiler.nodes.java.StoreIndexedNode; +import jdk.graal.compiler.nodes.java.UnsafeCompareAndSwapNode; import jdk.graal.compiler.nodes.spi.CoreProviders; import jdk.graal.compiler.phases.OptimisticOptimizations; import jdk.graal.compiler.replacements.SnippetTemplate; +import jdk.internal.org.objectweb.asm.Opcodes; import jdk.vm.ci.meta.JavaConstant; import jdk.vm.ci.meta.JavaField; import jdk.vm.ci.meta.JavaKind; import jdk.vm.ci.meta.JavaMethod; import jdk.vm.ci.meta.JavaType; import jdk.vm.ci.meta.JavaTypeProfile; +import jdk.vm.ci.meta.PrimitiveConstant; +import jdk.vm.ci.meta.ResolvedJavaField; import jdk.vm.ci.meta.ResolvedJavaMethod; import jdk.vm.ci.meta.ResolvedJavaType; @@ -114,6 +160,7 @@ public abstract static class SharedBytecodeParser extends BytecodeParser { private final boolean explicitExceptionEdges; private final boolean linkAtBuildTime; + protected final BootstrapMethodHandler bootstrapMethodHandler; protected SharedBytecodeParser(GraphBuilderPhase.Instance graphBuilderInstance, StructuredGraph graph, BytecodeParser parent, ResolvedJavaMethod method, int entryBCI, IntrinsicContext intrinsicContext, boolean explicitExceptionEdges) { @@ -125,6 +172,7 @@ protected SharedBytecodeParser(GraphBuilderPhase.Instance graphBuilderInstance, super(graphBuilderInstance, graph, parent, method, entryBCI, intrinsicContext); this.explicitExceptionEdges = explicitExceptionEdges; this.linkAtBuildTime = linkAtBuildTime; + this.bootstrapMethodHandler = new BootstrapMethodHandler(); } @Override @@ -202,18 +250,22 @@ protected JavaMethod lookupMethodInPool(int cpi, int opcode) { } @Override - protected Object lookupConstant(int cpi, int opcode, boolean allowBootstrapMethodInvocation) { + protected void genLoadConstant(int cpi, int opcode) { try { - // Native Image forces bootstrap method invocation at build time - // until support has been added for doing the invocation at runtime (GR-45806) - return super.lookupConstant(cpi, opcode, true); - } catch (BootstrapMethodError | IncompatibleClassChangeError | IllegalArgumentException ex) { - if (linkAtBuildTime) { - reportUnresolvedElement("constant", method.format("%H.%n(%P)"), ex); - } else { - replaceWithThrowingAtRuntime(this, ex); + if (super.lookupConstant(cpi, opcode, false) == null) { + Object resolvedObject = bootstrapMethodHandler.loadConstantDynamic(cpi, opcode); + if (resolvedObject instanceof ValueNode valueNode) { + JavaKind javaKind = valueNode.getStackKind(); + assert (opcode == LDC2_W) == javaKind.needsTwoSlots(); + frameState.push(javaKind, valueNode); + } else { + super.genLoadConstantHelper(resolvedObject, opcode); + } + return; } - return ex; + super.genLoadConstant(cpi, opcode); + } catch (BootstrapMethodError | IncompatibleClassChangeError | IllegalArgumentException | NoClassDefFoundError ex) { + bootstrapMethodHandler.handleBootstrapException(ex, "constant"); } } @@ -366,15 +418,25 @@ public static void replaceWithThrowingAtRuntime(SharedByte Throwable cause = throwable.getCause(); if (cause != null) { var metaAccess = (AnalysisMetaAccess) b.getMetaAccess(); - /* Invoke method that creates a cause-instance with cause-message */ - var causeCtor = ReflectionUtil.lookupConstructor(cause.getClass(), String.class); - ResolvedJavaMethod causeCtorMethod = FactoryMethodSupport.singleton().lookup(metaAccess, metaAccess.lookupJavaMethod(causeCtor), false); - ValueNode causeMessageNode = ConstantNode.forConstant(b.getConstantReflection().forString(cause.getMessage()), metaAccess, b.getGraph()); - Invoke causeCtorInvoke = (Invoke) b.appendInvoke(InvokeKind.Static, causeCtorMethod, new ValueNode[]{causeMessageNode}, null); /* * Invoke method that creates and throws throwable-instance with message and cause */ - var errorCtor = ReflectionUtil.lookupConstructor(throwable.getClass(), String.class, Throwable.class); + var errorCtor = ReflectionUtil.lookupConstructor(true, throwable.getClass(), String.class, Throwable.class); + boolean hasCause = errorCtor != null; + Invoke causeCtorInvoke = null; + if (!hasCause) { + /* + * Invoke method that creates and throws throwable-instance with message + */ + errorCtor = ReflectionUtil.lookupConstructor(throwable.getClass(), String.class); + } else { + /* Invoke method that creates a cause-instance with cause-message */ + var causeCtor = ReflectionUtil.lookupConstructor(cause.getClass(), String.class); + ResolvedJavaMethod causeCtorMethod = FactoryMethodSupport.singleton().lookup(metaAccess, metaAccess.lookupJavaMethod(causeCtor), false); + ValueNode causeMessageNode = ConstantNode.forConstant(b.getConstantReflection().forString(cause.getMessage()), metaAccess, b.getGraph()); + causeCtorInvoke = (Invoke) b.appendInvoke(InvokeKind.Static, causeCtorMethod, new ValueNode[]{causeMessageNode}, null); + } + ResolvedJavaMethod throwingMethod = FactoryMethodSupport.singleton().lookup(metaAccess, metaAccess.lookupJavaMethod(errorCtor), true); ValueNode messageNode = ConstantNode.forConstant(b.getConstantReflection().forString(throwable.getMessage()), metaAccess, b.getGraph()); /* @@ -382,7 +444,8 @@ public static void replaceWithThrowingAtRuntime(SharedByte * stack effect. */ boolean verifyStates = b.getFrameStateBuilder().disableStateVerification(); - b.appendInvoke(InvokeKind.Static, throwingMethod, new ValueNode[]{messageNode, causeCtorInvoke.asNode()}, null); + ValueNode[] args = hasCause ? new ValueNode[]{messageNode, causeCtorInvoke.asNode()} : new ValueNode[]{messageNode}; + b.appendInvoke(InvokeKind.Static, throwingMethod, args, null); b.getFrameStateBuilder().setStateVerification(verifyStates); b.add(new LoweredDeadEndNode()); } else { @@ -414,7 +477,7 @@ public static void replaceWithThrowingAtRuntime(SharedBytecodeParser b, Class[] signatureToClasses(JavaMethod method) { int paramCount = method.getSignature().getParameterCount(false); Class[] result = new Class[paramCount]; for (int i = 0; i < paramCount; i++) { - JavaType parameterType = method.getSignature().getParameterType(0, null); + JavaType parameterType = method.getSignature().getParameterType(i, null); if (parameterType instanceof ResolvedJavaType) { result[i] = OriginalClassProvider.getJavaClass((ResolvedJavaType) parameterType); } @@ -572,6 +635,11 @@ public MethodCallTargetNode createMethodCallTarget(InvokeKind invokeKind, Resolv return new SubstrateMethodCallTargetNode(invokeKind, targetMethod, args, returnStamp); } + public MethodCallTargetNode createMethodCallTarget(InvokeKind invokeKind, ResolvedJavaMethod targetMethod, ValueNode[] args, Class returnClass, JavaTypeProfile profile) { + JavaType returnType = getMetaAccess().lookupJavaType(returnClass); + return createMethodCallTarget(invokeKind, targetMethod, args, returnType, profile); + } + @Override protected void genReturn(ValueNode returnVal, JavaKind returnKind) { checkWordType(returnVal, method.getSignature().getReturnType(null), "return value"); @@ -828,5 +896,422 @@ protected boolean forceLoopPhis() { public boolean allowDeoptInPlugins() { return super.allowDeoptInPlugins(); } + + public class BootstrapMethodHandler { + + private Object loadConstantDynamic(int cpi, int opcode) { + BootstrapMethodIntrospection bootstrap; + try { + bootstrap = ((AnalysisConstantPool) constantPool).lookupBootstrapMethodIntrospection(cpi, -1); + } catch (Throwable ex) { + handleBootstrapException(ex, "constant"); + return ex; + } + if (bootstrap != null && !BootstrapMethodConfiguration.singleton().isCondyAllowedAtBuildTime(OriginalMethodProvider.getJavaMethod(bootstrap.getMethod()))) { + int parameterLength = bootstrap.getMethod().getParameters().length; + List staticArguments = bootstrap.getStaticArguments(); + boolean isVarargs = bootstrap.getMethod().isVarArgs(); + JavaConstant type = ((ImageHeapInstance) bootstrap.getType()).getHostedObject(); + DynamicHub typeClass = (DynamicHub) ((DirectSubstrateObjectConstant) type).getObject(); + boolean isPrimitive = typeClass.isPrimitive(); + + if (isBootstrapInvocationInvalid(bootstrap, parameterLength, staticArguments, isVarargs, typeClass.getHostedJavaClass())) { + /* + * The number of provided arguments does not match the signature of the + * bootstrap method or the provided type does not match the return type of + * the bootstrap method. Calling lookupConstant with + * allowBootstrapMethodInvocation set to true correctly throws the intended + * BootstrapMethodError. + */ + return SharedBytecodeParser.super.lookupConstant(cpi, opcode, true); + } + + Object resolvedObject = resolveLinkedObject(bci(), cpi, opcode, bootstrap, parameterLength, staticArguments, isVarargs, isPrimitive); + if (resolvedObject instanceof Throwable) { + return resolvedObject; + } + ValueNode resolvedObjectNode = (ValueNode) resolvedObject; + + if (typeClass.isPrimitive()) { + JavaKind constantKind = getMetaAccessExtensionProvider().getStorageKind(getMetaAccess().lookupJavaType(typeClass.getHostedJavaClass())); + resolvedObjectNode = append(UnboxNode.create(getMetaAccess(), getConstantReflection(), resolvedObjectNode, constantKind)); + } + + return resolvedObjectNode; + } + return SharedBytecodeParser.super.lookupConstant(cpi, opcode, true); + } + + /** + * Produces a graph executing the given bootstrap method and linking the result if it is + * the first execution. This corresponds to the following code: + * + *

+             * if (bootstrapMethodInfo.object == null) {
+             *     MethodHandles.Lookup lookup = MethodHandles.lookup();
+             *     try {
+             *         bootstrapMethodInfo.object = bootstrapMethod(lookup, name, type, staticArguments);
+             *     } catch (Throwable throwable) {
+             *         bootstrapMethodInfo.object = new ExceptionWrapper(throwable);
+             *     }
+             * }
+             * Object result = bootstrapMethodInfo.object;
+             * if (result instanceOf ExceptionWrapper exceptionWrapper) {
+             *     throw exceptionWrapper.throwable;
+             * }
+             * return result;
+             * 
+ */ + protected Object resolveLinkedObject(int bci, int cpi, int opcode, BootstrapMethodIntrospection bootstrap, int parameterLength, List staticArgumentsList, + boolean isVarargs, boolean isPrimitiveConstant) { + AnalysisConstantReflectionProvider analysisConstantReflection = (AnalysisConstantReflectionProvider) getConstantReflection(); + ResolvedJavaMethod bootstrapMethod = bootstrap.getMethod(); + + /* Step 1: Initialize the BootstrapMethodInfo. */ + + BootstrapMethodRecord bootstrapMethodRecord = new BootstrapMethodRecord(bci, cpi, ((AnalysisMethod) method).getMultiMethod(MultiMethod.ORIGINAL_METHOD)); + BootstrapMethodInfo bootstrapMethodInfo = BootstrapMethodConfiguration.singleton().getBootstrapMethodInfoCache().computeIfAbsent(bootstrapMethodRecord, + key -> new BootstrapMethodInfo()); + ConstantNode bootstrapMethodInfoNode = ConstantNode.forConstant(analysisConstantReflection.forObject(bootstrapMethodInfo), getMetaAccess(), getGraph()); + + /* + * Step 2: Check if the call site or the constant is linked or if it previously + * threw an exception to rethrow it. + */ + + Field bootstrapObjectField = ReflectionUtil.lookupField(BootstrapMethodInfo.class, "object"); + AnalysisField bootstrapObjectResolvedField = (AnalysisField) getMetaAccess().lookupJavaField(bootstrapObjectField); + LoadFieldNode bootstrapObjectFieldNode = append(LoadFieldNode.create(getAssumptions(), bootstrapMethodInfoNode, bootstrapObjectResolvedField, MemoryOrderMode.ACQUIRE)); + + ValueNode[] arguments = new ValueNode[parameterLength]; + + /* + * The bootstrap method can be VarArgs, which means we have to group the last static + * arguments in an array. + */ + if (isVarargs) { + JavaType varargClass = bootstrapMethod.getParameters()[parameterLength - 1].getType().getComponentType(); + arguments[arguments.length - 1] = append(new NewArrayNode(((AnalysisMetaAccess) getMetaAccess()).getUniverse().lookup(varargClass), + ConstantNode.forInt(staticArgumentsList.size() - arguments.length + 4, getGraph()), true)); + } + + /* + * Prepare the static arguments before continuing as an exception in a nested + * constant dynamic aborts the graph generation. + */ + for (int i = 0; i < staticArgumentsList.size(); ++i) { + JavaConstant constant = staticArgumentsList.get(i); + ValueNode currentNode; + if (constant instanceof PrimitiveConstant primitiveConstant) { + int argCpi = primitiveConstant.asInt(); + Object argConstant = loadConstantDynamic(argCpi, opcode == Opcodes.INVOKEDYNAMIC ? Opcodes.LDC : opcode); + if (argConstant instanceof ValueNode valueNode) { + currentNode = valueNode; + } else if (argConstant instanceof Throwable) { + /* A nested constant dynamic threw. */ + return argConstant; + } else { + currentNode = ConstantNode.forConstant(analysisConstantReflection.forObject(argConstant), getMetaAccess(), getGraph()); + } + } else { + /* + * Primitive arguments in the non vararg area have to be unboxed to match + * the parameters of the bootstrap method, which is handled by + * createConstant. The arguments in the vararg area have to stay boxed as + * they are passed as Objects. + */ + currentNode = (isVarargs && i + 4 >= parameterLength) ? ConstantNode.forConstant(constant, getMetaAccess(), getGraph()) : createConstant(constant); + } + addArgument(isVarargs, arguments, i + 3, currentNode); + } + + LogicNode condition = graph.unique(IsNullNode.create(bootstrapObjectFieldNode)); + + EndNode falseEnd = graph.add(new EndNode()); + + /* + * Step 3: If the call site or the constant is not linked, execute the bootstrap + * method and link the outputted call site or constant to the constant pool index. + * Otherwise, go to step 4. + */ + + InvokeWithExceptionNode lookup = invokeMethodAndAdd(bci, MethodHandles.class, MethodHandles.Lookup.class, "lookup", InvokeKind.Static, ValueNode.EMPTY_ARRAY); + ValueNode lookupNode = frameState.pop(JavaKind.Object); + + /* + * Step 3.1: Prepare the arguments for the bootstrap method. The first three are + * always the same. The other ones are the static arguments. + */ + + addArgument(isVarargs, arguments, 0, lookupNode); + ConstantNode bootstrapName = ConstantNode.forConstant(analysisConstantReflection.forString(bootstrap.getName()), getMetaAccess(), getGraph()); + addArgument(isVarargs, arguments, 1, bootstrapName); + addArgument(isVarargs, arguments, 2, ConstantNode.forConstant(bootstrap.getType(), getMetaAccess(), getGraph())); + + if (bootstrapMethod.isConstructor()) { + ValueNode[] oldArguments = arguments; + arguments = new ValueNode[arguments.length + 1]; + arguments[0] = graph.add(new NewInstanceNode(bootstrapMethod.getDeclaringClass(), true)); + System.arraycopy(oldArguments, 0, arguments, 1, oldArguments.length); + } + + Class returnClass = OriginalClassProvider.getJavaClass((ResolvedJavaType) bootstrapMethod.getSignature().getReturnType(null)); + + InvokeWithExceptionNode bootstrapObject; + ValueNode bootstrapObjectNode; + /* A bootstrap method can only be either static or a constructor. */ + if (bootstrapMethod.isConstructor()) { + bootstrapObject = invokeMethodAndAddCustomExceptionHandler(bci, void.class, InvokeKind.Special, arguments, bootstrapMethod); + bootstrapObjectNode = arguments[0]; + } else { + bootstrapObject = invokeMethodAndAddCustomExceptionHandler(bci, returnClass, InvokeKind.Static, arguments, bootstrapMethod); + bootstrapObjectNode = frameState.pop(bootstrapObject.getStackKind()); + } + ValueNode finalBootstrapObjectNode = bootstrapObjectNode; + FixedWithNextNode fixedFinalBootstrapObjectNode = null; + if (isPrimitiveConstant) { + fixedFinalBootstrapObjectNode = graph.add( + BoxNode.create(bootstrapObjectNode, getMetaAccess().lookupJavaType(bootstrapObjectNode.getStackKind().toBoxedJavaClass()), bootstrapObjectNode.getStackKind())); + finalBootstrapObjectNode = fixedFinalBootstrapObjectNode; + } + + /* + * If an exception occurs during the bootstrap method execution, store it in the + * BootstrapMethodInfo instead of directly throwing. + */ + InvokeWithExceptionNode exceptionWrapperNode = wrapException(bci, bootstrapObject.exceptionEdge()); + bootstrapObject.exceptionEdge().setNext(exceptionWrapperNode); + MergeNode linkMerge = graph.add(new MergeNode()); + linkMerge.setStateAfter(createFrameState(stream.nextBCI(), linkMerge)); + EndNode n = graph.add(new EndNode()); + exceptionWrapperNode.setNext(n); + linkMerge.addForwardEnd(n); + + EndNode noExceptionEnd = graph.add(new EndNode()); + finalBootstrapObjectNode = graph.unique(new ValuePhiNode(StampFactory.object(), linkMerge, exceptionWrapperNode, finalBootstrapObjectNode)); + + /* + * Step 3.2: Link the call site or the constant outputted by the bootstrap method. + */ + + ConstantNode nullConstant = ConstantNode.forConstant(JavaConstant.NULL_POINTER, getMetaAccess(), getGraph()); + ValueNode offset = graph.addOrUniqueWithInputs( + LazyConstantNode.create(StampFactory.forKind(JavaKind.Long), new FieldOffsetConstantProvider(bootstrapObjectField), SharedBytecodeParser.this)); + FieldLocationIdentity fieldLocationIdentity = new FieldLocationIdentity(bootstrapObjectResolvedField); + FixedWithNextNode linkBootstrapObject = graph.add( + new UnsafeCompareAndSwapNode(bootstrapMethodInfoNode, offset, nullConstant, finalBootstrapObjectNode, JavaKind.Object, fieldLocationIdentity, MemoryOrderMode.RELEASE)); + ((StateSplit) linkBootstrapObject).setStateAfter(createFrameState(stream.nextBCI(), (StateSplit) linkBootstrapObject)); + + NodeSourcePosition nodeSourcePosition = getGraph().currentNodeSourcePosition(); + Object reason = nodeSourcePosition == null ? "Unknown graph builder location." : nodeSourcePosition; + bootstrapObjectResolvedField.registerAsAccessed(reason); + bootstrapObjectResolvedField.registerAsUnsafeAccessed(reason); + + EndNode trueEnd = graph.add(new EndNode()); + + if (bootstrapMethod.isConstructor()) { + lookup.setNext((FixedNode) bootstrapObjectNode); + ((FixedWithNextNode) bootstrapObjectNode).setNext(bootstrapObject); + } else { + lookup.setNext(bootstrapObject); + } + if (isPrimitiveConstant) { + bootstrapObject.setNext(fixedFinalBootstrapObjectNode); + fixedFinalBootstrapObjectNode.setNext(noExceptionEnd); + } else { + bootstrapObject.setNext(noExceptionEnd); + } + linkMerge.addForwardEnd(noExceptionEnd); + linkMerge.setNext(linkBootstrapObject); + linkBootstrapObject.setNext(trueEnd); + + append(new IfNode(condition, lookup, falseEnd, BranchProbabilityNode.NOT_FREQUENT_PROFILE)); + + MergeNode mergeNode = append(new MergeNode()); + mergeNode.setStateAfter(createFrameState(stream.nextBCI(), mergeNode)); + mergeNode.addForwardEnd(trueEnd); + mergeNode.addForwardEnd(falseEnd); + + /* Step 4: Fetch the object from the BootstrapMethodInfo. */ + + LoadFieldNode result = append(LoadFieldNode.create(getAssumptions(), bootstrapMethodInfoNode, bootstrapObjectResolvedField, MemoryOrderMode.ACQUIRE)); + + /* If the object is an exception, it is thrown. */ + TypeReference exceptionWrapper = TypeReference.create(getAssumptions(), getMetaAccess().lookupJavaType(ExceptionWrapper.class)); + LogicNode instanceOfException = graph.unique(InstanceOfNode.create(exceptionWrapper, result)); + EndNode checkExceptionTrueEnd = graph.add(new EndNode()); + EndNode checkExceptionFalseEnd = graph.add(new EndNode()); + + Field exceptionWrapperField = ReflectionUtil.lookupField(ExceptionWrapper.class, "throwable"); + ResolvedJavaField exceptionWrapperResolvedField = getMetaAccess().lookupJavaField(exceptionWrapperField); + LoadFieldNode throwable = graph.add(LoadFieldNode.create(getAssumptions(), result, exceptionWrapperResolvedField)); + InvokeWithExceptionNode bootstrapMethodError = throwBootstrapMethodError(bci, throwable); + throwable.setNext(bootstrapMethodError); + bootstrapMethodError.setNext(checkExceptionTrueEnd); + + append(new IfNode(instanceOfException, throwable, checkExceptionFalseEnd, BranchProbabilityNode.NOT_FREQUENT_PROFILE)); + + MergeNode checkExceptionMergeNode = append(new MergeNode()); + checkExceptionMergeNode.setStateAfter(createFrameState(stream.nextBCI(), checkExceptionMergeNode)); + checkExceptionMergeNode.addForwardEnd(checkExceptionTrueEnd); + checkExceptionMergeNode.addForwardEnd(checkExceptionFalseEnd); + + return result; + } + + private void addArgument(boolean isVarargs, ValueNode[] arguments, int i, ValueNode currentNode) { + if (isVarargs && i >= arguments.length - 1) { + StoreIndexedNode storeIndexedNode = append(new StoreIndexedNode(arguments[arguments.length - 1], ConstantNode.forInt(i + 1 - arguments.length, getGraph()), null, null, + JavaKind.Object, currentNode)); + storeIndexedNode.setStateAfter(createFrameState(stream.nextBCI(), storeIndexedNode)); + } else { + arguments[i] = currentNode; + } + } + + private InvokeWithExceptionNode wrapException(int bci, ValueNode exception) { + Constructor exceptionWrapperCtor = ReflectionUtil.lookupConstructor(ExceptionWrapper.class, Throwable.class); + AnalysisMetaAccess metaAccess = (AnalysisMetaAccess) getMetaAccess(); + ResolvedJavaMethod exceptionWrapperMethod = FactoryMethodSupport.singleton().lookup(metaAccess, metaAccess.lookupJavaMethod(exceptionWrapperCtor), false); + InvokeWithExceptionNode exceptionWrapper = invokeMethodAndAdd(bci, ExceptionWrapper.class, InvokeKind.Static, new ValueNode[]{exception}, exceptionWrapperMethod); + frameState.pop(JavaKind.Object); + return exceptionWrapper; + } + + protected InvokeWithExceptionNode throwBootstrapMethodError(int bci, ValueNode exception) { + Constructor errorCtor = ReflectionUtil.lookupConstructor(BootstrapMethodError.class, Throwable.class); + AnalysisMetaAccess metaAccess = (AnalysisMetaAccess) getMetaAccess(); + ResolvedJavaMethod bootstrapMethodErrorMethod = FactoryMethodSupport.singleton().lookup(metaAccess, metaAccess.lookupJavaMethod(errorCtor), true); + return invokeMethodAndAdd(bci, void.class, InvokeKind.Static, new ValueNode[]{exception}, bootstrapMethodErrorMethod); + } + + /** + * Perform checks on a bootstrap method invocation. The checks verifying the number of + * arguments cannot be performed at run time as they cause build time errors when not + * met. The type checks could be replaced by run time class casts. + *

+ * HotSpot performs those checks in {@code ConstantBootstraps.makeConstant} and + * {@code CallSite.makeSite} by casting the classes and method types. Since the + * bootstrap method is converted to a {@link java.lang.invoke.MethodHandle}, incorrect + * types in the bootstrap method declaration are detected in + * {@link java.lang.invoke.MethodHandle#invoke(Object...)}. + */ + private boolean isBootstrapInvocationInvalid(BootstrapMethodIntrospection bootstrap, int parameterLength, List staticArgumentsList, boolean isVarargs, Class typeClass) { + ResolvedJavaMethod method = bootstrap.getMethod(); + return (isVarargs && parameterLength > (3 + staticArgumentsList.size())) || (!isVarargs && parameterLength != (3 + staticArgumentsList.size())) || + !(OriginalClassProvider.getJavaClass((ResolvedJavaType) method.getSignature().getReturnType(null)).isAssignableFrom(typeClass) || method.isConstructor()) || + !checkBootstrapParameters(method, bootstrap.getStaticArguments(), true); + } + + protected boolean checkBootstrapParameters(ResolvedJavaMethod bootstrapMethod, List staticArguments, boolean condy) { + int parametersLength = bootstrapMethod.getParameters().length; + Class[] parameters = signatureToClasses(bootstrapMethod); + if (bootstrapMethod.isVarArgs()) { + /* + * The mismatch in the number of arguments causes a WrongMethodTypeException in + * MethodHandle.invoke on the bootstrap method invocation. + */ + parameters[parametersLength - 1] = parameters[parametersLength - 1].getComponentType(); + } + if (!bootstrapMethod.isVarArgs() && 3 + staticArguments.size() != parameters.length) { + return false; + } + for (int i = 0; i < parametersLength; ++i) { + if (i == 0) { + /* HotSpot performs this check in ConstantBootstraps#makeConstant. */ + if (!(condy ? parameters[i].equals(MethodHandles.Lookup.class) : parameters[i].isAssignableFrom(MethodHandles.Lookup.class))) { + return false; + } + } else if (i == 1) { + /* + * This parameter is converted to a String in + * MethodHandleNatives#linkCallSite and + * MethodHandleNatives#linkDynamicConstant. Not having a String here causes + * a ClassCastException in MethodHandle.invoke. + */ + if (!parameters[i].isAssignableFrom(String.class)) { + return false; + } + } else if (i == 2) { + /* + * This parameter is converted to a Class/MethodType in + * MethodHandleNatives#linkCallSite/MethodHandleNatives#linkDynamicConstant. + * Not having a Class/MethodType here causes a ClassCastException in + * MethodHandle.invoke. + */ + if (!parameters[i].isAssignableFrom(condy ? Class.class : MethodType.class)) { + return false; + } + } else { + if (!(bootstrapMethod.isVarArgs() && staticArguments.size() == i - 3) && staticArguments.get(i - 3) instanceof ImageHeapConstant imageHeapConstant) { + Class parameterClass = OriginalClassProvider.getJavaClass(imageHeapConstant.getType(getMetaAccess())); + /* + * Having incompatible types here causes a ClassCastException in + * MethodHandle.invoke on the bootstrap method invocation. + */ + if (!(parameters[i].isAssignableFrom(parameterClass) || toUnboxedClass(parameters[i]).isAssignableFrom(toUnboxedClass(parameterClass)))) { + return false; + } + } + } + } + return true; + } + + protected void handleBootstrapException(Throwable ex, String elementKind) { + if (linkAtBuildTime) { + reportUnresolvedElement(elementKind, method.format("%H.%n(%P)"), ex); + } else { + replaceWithThrowingAtRuntime(SharedBytecodeParser.this, ex); + } + } + + protected ConstantNode createConstant(JavaConstant constant) { + JavaConstant primitiveConstant = getConstantReflection().unboxPrimitive(constant); + return ConstantNode.forConstant(primitiveConstant == null ? constant : primitiveConstant, getMetaAccess(), getGraph()); + } + + protected Invoke invokeMethodAndAppend(int bci, Class clazz, Class returnClass, String name, InvokeKind invokeKind, ValueNode[] arguments, Class... classes) { + ResolvedJavaMethod invokedMethod = lookupResolvedJavaMethod(clazz, name, classes); + CallTargetNode callTarget = graph.add(createMethodCallTarget(invokeKind, invokedMethod, arguments, returnClass, null)); + return createNonInlinedInvoke(ExceptionEdgeAction.INCLUDE_AND_HANDLE, bci, callTarget, callTarget.returnStamp().getTrustedStamp().getStackKind()); + } + + protected InvokeWithExceptionNode invokeMethodAndAdd(int bci, Class clazz, Class returnClass, String name, InvokeKind invokeKind, ValueNode[] arguments, + Class... classes) { + ResolvedJavaMethod invokedMethod = lookupResolvedJavaMethod(clazz, name, classes); + return invokeMethodAndAdd(bci, returnClass, invokeKind, arguments, invokedMethod); + } + + protected InvokeWithExceptionNode invokeMethodAndAdd(int bci, Class returnClass, InvokeKind invokeKind, ValueNode[] arguments, ResolvedJavaMethod invokedMethod) { + CallTargetNode callTarget = graph.add(createMethodCallTarget(invokeKind, invokedMethod, arguments, returnClass, null)); + InvokeWithExceptionNode invoke = graph + .add(createInvokeWithException(bci, callTarget, callTarget.returnStamp().getTrustedStamp().getStackKind(), ExceptionEdgeAction.INCLUDE_AND_HANDLE)); + invoke.setStateAfter(createFrameState(stream.nextBCI(), invoke)); + return invoke; + } + + protected InvokeWithExceptionNode invokeMethodAndAddCustomExceptionHandler(int bci, Class returnClass, InvokeKind invokeKind, ValueNode[] arguments, ResolvedJavaMethod invokedMethod) { + CallTargetNode callTarget = graph.add(createMethodCallTarget(invokeKind, invokedMethod, arguments, returnClass, null)); + ExceptionObjectNode exceptionObject = graph.add(new ExceptionObjectNode(getMetaAccess())); + FrameStateBuilder dispatchState = frameState.copy(); + dispatchState.clearStack(); + dispatchState.pushReturn(JavaKind.Object, exceptionObject); + dispatchState.setRethrowException(true); + exceptionObject.setStateAfter(dispatchState.create(stream.nextBCI(), exceptionObject)); + InvokeWithExceptionNode invoke = graph.add(new InvokeWithExceptionNode(callTarget, exceptionObject, bci)); + frameState.pushReturn(callTarget.returnStamp().getTrustedStamp().getStackKind(), invoke); + invoke.setStateAfter(createFrameState(stream.nextBCI(), invoke)); + return invoke; + } + + private ResolvedJavaMethod lookupResolvedJavaMethod(Class clazz, String name, Class... classes) { + try { + return getMetaAccess().lookupJavaMethod(clazz.getDeclaredMethod(name, classes)); + } catch (NoSuchMethodException e) { + throw GraalError.shouldNotReachHere("Could not find method in " + clazz + " named " + name); + } + } + } } } diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/snippets/SubstrateGraphBuilderPlugins.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/snippets/SubstrateGraphBuilderPlugins.java index 0730b36ebb00..909a466dc167 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/snippets/SubstrateGraphBuilderPlugins.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/snippets/SubstrateGraphBuilderPlugins.java @@ -850,11 +850,11 @@ public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Rec }); } - private static class FieldOffsetConstantProvider implements Function { + public static class FieldOffsetConstantProvider implements Function { private final Field javaField; - FieldOffsetConstantProvider(Field javaField) { + public FieldOffsetConstantProvider(Field javaField) { this.javaField = javaField; } From 6ddb9a3a421c7a11727b6b4b32a02efe66a12322 Mon Sep 17 00:00:00 2001 From: Sacha Coppey Date: Wed, 8 Nov 2023 12:12:31 +0100 Subject: [PATCH 140/593] Add LambdaSubstrateGraphBuilderPhase to be able to execute some bootstrap method at run time when finding a stable name for a lambda --- .../hotspot/test/LambdaStableNameTest.java | 24 +++-- .../jdk/graal/compiler/java/LambdaUtils.java | 51 ++--------- ...bdaProxyRenamingSubstitutionProcessor.java | 15 ++-- .../LambdaSubstrateGraphBuilderPhase.java | 90 +++++++++++++++++++ 4 files changed, 118 insertions(+), 62 deletions(-) create mode 100644 substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/lambda/LambdaSubstrateGraphBuilderPhase.java diff --git a/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/hotspot/test/LambdaStableNameTest.java b/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/hotspot/test/LambdaStableNameTest.java index c22d936a56c1..8e0f80faa413 100644 --- a/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/hotspot/test/LambdaStableNameTest.java +++ b/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/hotspot/test/LambdaStableNameTest.java @@ -25,24 +25,29 @@ package jdk.graal.compiler.hotspot.test; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; + import java.math.BigInteger; import java.util.Collections; -import jdk.vm.ci.meta.ResolvedJavaType; -import jdk.vm.ci.runtime.JVMCI; + +import org.junit.Test; +import org.objectweb.asm.Type; + import jdk.graal.compiler.api.runtime.GraalJVMCICompiler; import jdk.graal.compiler.debug.DebugContext; import jdk.graal.compiler.debug.DebugContext.Builder; import jdk.graal.compiler.hotspot.meta.HotSpotJITClassInitializationPlugin; +import jdk.graal.compiler.java.GraphBuilderPhase; import jdk.graal.compiler.java.LambdaUtils; import jdk.graal.compiler.options.OptionValues; +import jdk.graal.compiler.phases.OptimisticOptimizations; import jdk.graal.compiler.phases.util.Providers; import jdk.graal.compiler.runtime.RuntimeProvider; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertTrue; -import static org.junit.Assert.fail; -import org.junit.Test; -import org.objectweb.asm.Type; +import jdk.vm.ci.meta.ResolvedJavaType; +import jdk.vm.ci.runtime.JVMCI; public class LambdaStableNameTest { private String findStableLambdaName(ResolvedJavaType type) { @@ -51,7 +56,8 @@ private String findStableLambdaName(ResolvedJavaType type) { GraalJVMCICompiler compiler = (GraalJVMCICompiler) JVMCI.getRuntime().getCompiler(); Providers providers = compiler.getGraalRuntime().getCapability(RuntimeProvider.class).getHostBackend().getProviders(); final HotSpotJITClassInitializationPlugin initializationPlugin = new HotSpotJITClassInitializationPlugin(); - return LambdaUtils.findStableLambdaName(initializationPlugin, providers, type, options, debug, this); + return LambdaUtils.findStableLambdaName(initializationPlugin, providers, type, options, debug, this, + config -> new GraphBuilderPhase.Instance(providers, config, OptimisticOptimizations.NONE, null)); } @Test diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/java/LambdaUtils.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/java/LambdaUtils.java index 27cecb8c68f2..52a7fd119eda 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/java/LambdaUtils.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/java/LambdaUtils.java @@ -29,25 +29,23 @@ import java.security.NoSuchAlgorithmException; import java.util.Arrays; import java.util.List; +import java.util.function.Function; import java.util.regex.Matcher; import java.util.regex.Pattern; import java.util.stream.Collectors; import java.util.stream.StreamSupport; import jdk.graal.compiler.debug.DebugContext; -import jdk.graal.compiler.nodes.graphbuilderconf.GraphBuilderContext; import jdk.graal.compiler.nodes.Invoke; import jdk.graal.compiler.nodes.StructuredGraph; import jdk.graal.compiler.nodes.graphbuilderconf.ClassInitializationPlugin; import jdk.graal.compiler.nodes.graphbuilderconf.GraphBuilderConfiguration; -import jdk.graal.compiler.nodes.graphbuilderconf.IntrinsicContext; +import jdk.graal.compiler.nodes.graphbuilderconf.GraphBuilderContext; import jdk.graal.compiler.nodes.graphbuilderconf.InvocationPlugins; -import jdk.graal.compiler.nodes.spi.CoreProviders; import jdk.graal.compiler.options.OptionValues; import jdk.graal.compiler.phases.OptimisticOptimizations; import jdk.graal.compiler.phases.tiers.HighTierContext; import jdk.graal.compiler.phases.util.Providers; - import jdk.vm.ci.common.JVMCIError; import jdk.vm.ci.meta.ResolvedJavaMethod; import jdk.vm.ci.meta.ResolvedJavaType; @@ -99,7 +97,8 @@ private LambdaUtils() { * @return stable name for the lambda class */ @SuppressWarnings("try") - public static String findStableLambdaName(ClassInitializationPlugin cip, Providers providers, ResolvedJavaType lambdaType, OptionValues options, DebugContext debug, Object ctx) + public static String findStableLambdaName(ClassInitializationPlugin cip, Providers providers, ResolvedJavaType lambdaType, OptionValues options, DebugContext debug, Object ctx, + Function graphBuilderSupplier) throws RuntimeException { ResolvedJavaMethod[] lambdaProxyMethods = Arrays.stream(lambdaType.getDeclaredMethods(false)).filter(m -> !m.isBridge() && m.isPublic()).toArray(ResolvedJavaMethod[]::new); /* @@ -108,7 +107,7 @@ public static String findStableLambdaName(ClassInitializationPlugin cip, Provide */ StructuredGraph graph = new StructuredGraph.Builder(options, debug).method(lambdaProxyMethods[0]).build(); try (DebugContext.Scope ignored = debug.scope("Lambda target method analysis", graph, lambdaType, ctx)) { - GraphBuilderPhase lambdaParserPhase = new LambdaGraphBuilder(LambdaUtils.buildLambdaParserConfig(cip)); + GraphBuilderPhase.Instance lambdaParserPhase = graphBuilderSupplier.apply(buildLambdaParserConfig(cip)); HighTierContext context = new HighTierContext(providers, null, OptimisticOptimizations.NONE); lambdaParserPhase.apply(graph, context); } catch (Throwable e) { @@ -171,44 +170,4 @@ public static String digest(String value) { public static String capturingClass(String className) { return className.split(LambdaUtils.SERIALIZATION_TEST_LAMBDA_CLASS_SPLIT_PATTERN)[0]; } - - private static final class LambdaGraphBuilder extends GraphBuilderPhase { - - private LambdaGraphBuilder(GraphBuilderConfiguration config) { - super(config); - } - - @Override - protected GraphBuilderPhase.Instance createInstance(CoreProviders providers, GraphBuilderConfiguration instanceGBConfig, OptimisticOptimizations optimisticOpts, - IntrinsicContext initialIntrinsicContext) { - return new Instance(providers, instanceGBConfig, optimisticOpts, initialIntrinsicContext); - } - - private static class Instance extends GraphBuilderPhase.Instance { - Instance(CoreProviders providers, GraphBuilderConfiguration instanceGBConfig, OptimisticOptimizations optimisticOpts, IntrinsicContext initialIntrinsicContext) { - super(providers, instanceGBConfig, optimisticOpts, initialIntrinsicContext); - } - - @Override - protected BytecodeParser createBytecodeParser(StructuredGraph graph, BytecodeParser parent, ResolvedJavaMethod method, int entryBCI, IntrinsicContext intrinsicContext) { - return new LambdaBytecodeParser(this, graph, parent, method, entryBCI, intrinsicContext); - } - } - } - - private static class LambdaBytecodeParser extends BytecodeParser { - - LambdaBytecodeParser(GraphBuilderPhase.Instance instance, StructuredGraph graph, BytecodeParser parent, ResolvedJavaMethod method, int entryBCI, IntrinsicContext intrinsicContext) { - super(instance, graph, parent, method, entryBCI, intrinsicContext); - } - - @Override - protected Object lookupConstant(int cpi, int opcode, boolean allowBootstrapMethodInvocation) { - /* - * Native Image forces bootstrap method invocation at build time until support has been - * added for doing the invocation at runtime (GR-45806) - */ - return super.lookupConstant(cpi, opcode, true); - } - } } diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/lambda/LambdaProxyRenamingSubstitutionProcessor.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/lambda/LambdaProxyRenamingSubstitutionProcessor.java index b83a0841c6cd..547dd543372b 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/lambda/LambdaProxyRenamingSubstitutionProcessor.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/lambda/LambdaProxyRenamingSubstitutionProcessor.java @@ -28,18 +28,18 @@ import java.util.Set; import java.util.concurrent.ConcurrentHashMap; +import com.oracle.graal.pointsto.BigBang; +import com.oracle.graal.pointsto.infrastructure.SubstitutionProcessor; +import com.oracle.graal.pointsto.phases.NoClassInitializationPlugin; +import com.oracle.graal.pointsto.util.GraalAccess; + import jdk.graal.compiler.debug.DebugContext; import jdk.graal.compiler.debug.DebugContext.Builder; import jdk.graal.compiler.java.LambdaUtils; import jdk.graal.compiler.options.OptionValues; +import jdk.graal.compiler.phases.OptimisticOptimizations; import jdk.graal.compiler.phases.util.Providers; import jdk.graal.compiler.printer.GraalDebugHandlersFactory; - -import com.oracle.graal.pointsto.BigBang; -import com.oracle.graal.pointsto.infrastructure.SubstitutionProcessor; -import com.oracle.graal.pointsto.phases.NoClassInitializationPlugin; -import com.oracle.graal.pointsto.util.GraalAccess; - import jdk.vm.ci.meta.ResolvedJavaType; /** @@ -89,7 +89,8 @@ private LambdaSubstitutionType getSubstitution(ResolvedJavaType original) { DebugContext debug = new Builder(options, new GraalDebugHandlersFactory(bb.getSnippetReflectionProvider())).build(); Providers providers = GraalAccess.getOriginalProviders(); - String lambdaTargetName = LambdaUtils.findStableLambdaName(new NoClassInitializationPlugin(), providers, key, options, debug, this); + String lambdaTargetName = LambdaUtils.findStableLambdaName(new NoClassInitializationPlugin(), providers, key, options, debug, this, + config -> new LambdaSubstrateGraphBuilderPhase.LambdaSubstrateGraphBuilderInstance(providers, config, OptimisticOptimizations.NONE, null)); return new LambdaSubstitutionType(key, findUniqueLambdaProxyName(lambdaTargetName)); }); } diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/lambda/LambdaSubstrateGraphBuilderPhase.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/lambda/LambdaSubstrateGraphBuilderPhase.java new file mode 100644 index 000000000000..375b2372a739 --- /dev/null +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/lambda/LambdaSubstrateGraphBuilderPhase.java @@ -0,0 +1,90 @@ +/* + * Copyright (c) 2023, 2023, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.svm.hosted.lambda; + +import com.oracle.graal.pointsto.infrastructure.OriginalMethodProvider; +import com.oracle.svm.core.bootstrap.BootstrapMethodConfiguration; + +import jdk.graal.compiler.core.common.BootstrapMethodIntrospection; +import jdk.graal.compiler.java.BytecodeParser; +import jdk.graal.compiler.java.GraphBuilderPhase; +import jdk.graal.compiler.nodes.StructuredGraph; +import jdk.graal.compiler.nodes.graphbuilderconf.GraphBuilderConfiguration; +import jdk.graal.compiler.nodes.graphbuilderconf.IntrinsicContext; +import jdk.graal.compiler.nodes.spi.CoreProviders; +import jdk.graal.compiler.phases.OptimisticOptimizations; +import jdk.graal.compiler.serviceprovider.GraalServices; +import jdk.vm.ci.meta.ResolvedJavaMethod; + +public class LambdaSubstrateGraphBuilderPhase extends GraphBuilderPhase { + public LambdaSubstrateGraphBuilderPhase(GraphBuilderConfiguration config) { + super(config); + } + + @Override + protected Instance createInstance(CoreProviders providers, GraphBuilderConfiguration instanceGBConfig, OptimisticOptimizations optimisticOpts, IntrinsicContext initialIntrinsicContext) { + return new LambdaSubstrateGraphBuilderInstance(providers, instanceGBConfig, optimisticOpts, initialIntrinsicContext); + } + + public static class LambdaSubstrateGraphBuilderInstance extends GraphBuilderPhase.Instance { + LambdaSubstrateGraphBuilderInstance(CoreProviders theProviders, GraphBuilderConfiguration graphBuilderConfig, OptimisticOptimizations optimisticOpts, + IntrinsicContext initialIntrinsicContext) { + super(theProviders, graphBuilderConfig, optimisticOpts, initialIntrinsicContext); + } + + @Override + protected BytecodeParser createBytecodeParser(StructuredGraph graph, BytecodeParser parent, ResolvedJavaMethod method, int entryBCI, IntrinsicContext intrinsicContext) { + return new LambdaSubstrateBytecodeParser(this, graph, parent, method, entryBCI, intrinsicContext); + } + } + + public static class LambdaSubstrateBytecodeParser extends BytecodeParser { + protected LambdaSubstrateBytecodeParser(Instance graphBuilderInstance, StructuredGraph graph, BytecodeParser parent, ResolvedJavaMethod method, int entryBCI, + IntrinsicContext intrinsicContext) { + super(graphBuilderInstance, graph, parent, method, entryBCI, intrinsicContext); + } + + @Override + protected void genLoadConstant(int cpi, int opcode) { + Object con = lookupConstant(cpi, opcode, false); + BootstrapMethodIntrospection bootstrap = GraalServices.lookupBootstrapMethodIntrospection(constantPool, cpi, -1); + if (con == null && bootstrap != null && BootstrapMethodConfiguration.singleton().isCondyTrusted(OriginalMethodProvider.getJavaMethod(bootstrap.getMethod()))) { + /* + * With the current implementation of LambdaUtils#findStableLambdaName, each lambda + * must contain at least one method invocation to compute its name. Looking up the + * constant with allowBootstrapMethodInvocation set to false will produce null if + * the constant is dynamic. Returning it will cause a runtime exception and if the + * lambda starts with the constant lookup, the lambda will contain no method + * invocation. At this stage, the AnalysisBytecodeParser cannot be created, so the + * graph with the bootstrap method call cannot be created. Thus, at the moment, + * allowing those bootstrap method to be executed at build time is the only way to + * obtain correct lambda names. + */ + con = lookupConstant(cpi, opcode, true); + } + genLoadConstantHelper(con, opcode); + } + } +} From db30b5e069d054da7a6f1f8c09f2d0077b8092ae Mon Sep 17 00:00:00 2001 From: Sacha Coppey Date: Wed, 8 Nov 2023 12:13:34 +0100 Subject: [PATCH 141/593] Handle HotSpotJavaType returned by BootstrapMethodInvocation.getStaticArguments --- .../infrastructure/WrappedConstantPool.java | 24 ++++++++++++++++++- .../phases/AnalysisGraphBuilderPhase.java | 15 ++++++++++++ .../phases/SharedGraphBuilderPhase.java | 12 +++++++++- 3 files changed, 49 insertions(+), 2 deletions(-) diff --git a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/infrastructure/WrappedConstantPool.java b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/infrastructure/WrappedConstantPool.java index 77c40e622c03..df789714db1a 100644 --- a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/infrastructure/WrappedConstantPool.java +++ b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/infrastructure/WrappedConstantPool.java @@ -32,8 +32,10 @@ import java.util.stream.Collectors; import com.oracle.graal.pointsto.constraints.UnresolvedElementException; +import com.oracle.graal.pointsto.util.GraalAccess; import com.oracle.svm.util.ReflectionUtil; +import jdk.graal.compiler.api.replacements.SnippetReflectionProvider; import jdk.graal.compiler.core.common.BootstrapMethodIntrospection; import jdk.graal.compiler.debug.GraalError; import jdk.graal.compiler.serviceprovider.BootstrapMethodIntrospectionImpl; @@ -64,7 +66,27 @@ public int length() { } private JavaConstant lookupConstant(JavaConstant constant) { - return universe.lookup(constant); + return universe.lookup(extractResolvedType(constant)); + } + + public JavaConstant extractResolvedType(JavaConstant constant) { + if (constant != null && constant.getJavaKind().isObject() && !constant.isNull()) { + SnippetReflectionProvider snippetReflection = GraalAccess.getOriginalSnippetReflection(); + if (snippetReflection.asObject(Object.class, constant) instanceof ResolvedJavaType resolvedJavaType) { + /* + * BootstrapMethodInvocation.getStaticArguments can output a constant containing a + * HotspotJavaType when a static argument of type Class if loaded lazily in pull + * mode. In this case, the type has to be converted back to a Class, as it would + * cause a hotspot value to be reachable otherwise. + * + * If the constant contains an UnresolvedJavaType, it cannot be converted as a + * Class. It is not a problem for this type to be reachable, so those constants can + * be handled later. + */ + return snippetReflection.forObject(OriginalClassProvider.getJavaClass(resolvedJavaType)); + } + } + return constant; } /** diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/phases/AnalysisGraphBuilderPhase.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/phases/AnalysisGraphBuilderPhase.java index a538662b8981..3198a59f0707 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/phases/AnalysisGraphBuilderPhase.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/phases/AnalysisGraphBuilderPhase.java @@ -82,6 +82,7 @@ import jdk.vm.ci.meta.ResolvedJavaField; import jdk.vm.ci.meta.ResolvedJavaMethod; import jdk.vm.ci.meta.ResolvedJavaType; +import jdk.vm.ci.meta.UnresolvedJavaType; public class AnalysisGraphBuilderPhase extends SharedGraphBuilderPhase { @@ -174,6 +175,16 @@ protected void genInvokeDynamic(int cpi, int opcode) { JavaConstant type = ((ImageHeapInstance) bootstrap.getType()).getHostedObject(); MethodType methodType = (MethodType) ((DirectSubstrateObjectConstant) type).getObject(); + for (JavaConstant argument : staticArgumentsList) { + if (argument instanceof ImageHeapInstance imageHeapInstance) { + Object arg = ((DirectSubstrateObjectConstant) imageHeapInstance.getHostedObject()).getObject(); + if (arg instanceof UnresolvedJavaType unresolvedJavaType) { + handleUnresolvedType(unresolvedJavaType); + return; + } + } + } + if (!bootstrapMethodHandler.checkBootstrapParameters(bootstrap.getMethod(), staticArgumentsList, false)) { WrongMethodTypeException cause = new WrongMethodTypeException("Cannot convert " + methodType + " to correct MethodType"); replaceWithThrowingAtRuntime(this, new BootstrapMethodError("Bootstrap method initialization exception", cause)); @@ -186,6 +197,10 @@ protected void genInvokeDynamic(int cpi, int opcode) { */ Object initializedCallSite = bootstrapMethodHandler.resolveLinkedObject(bci, cpi, opcode, bootstrap, parameterLength, staticArgumentsList, isVarargs, false); + if (initializedCallSite instanceof UnresolvedJavaType unresolvedJavaType) { + handleUnresolvedType(unresolvedJavaType); + return; + } if (initializedCallSite instanceof Throwable) { return; } diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/phases/SharedGraphBuilderPhase.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/phases/SharedGraphBuilderPhase.java index 4323ed7a11ac..824f7feb9c50 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/phases/SharedGraphBuilderPhase.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/phases/SharedGraphBuilderPhase.java @@ -141,6 +141,7 @@ import jdk.vm.ci.meta.ResolvedJavaField; import jdk.vm.ci.meta.ResolvedJavaMethod; import jdk.vm.ci.meta.ResolvedJavaType; +import jdk.vm.ci.meta.UnresolvedJavaType; public abstract class SharedGraphBuilderPhase extends GraphBuilderPhase.Instance { @@ -915,6 +916,15 @@ private Object loadConstantDynamic(int cpi, int opcode) { DynamicHub typeClass = (DynamicHub) ((DirectSubstrateObjectConstant) type).getObject(); boolean isPrimitive = typeClass.isPrimitive(); + for (JavaConstant argument : staticArguments) { + if (argument instanceof ImageHeapInstance imageHeapInstance) { + Object arg = ((DirectSubstrateObjectConstant) imageHeapInstance.getHostedObject()).getObject(); + if (arg instanceof UnresolvedJavaType) { + return arg; + } + } + } + if (isBootstrapInvocationInvalid(bootstrap, parameterLength, staticArguments, isVarargs, typeClass.getHostedJavaClass())) { /* * The number of provided arguments does not match the signature of the @@ -1007,7 +1017,7 @@ protected Object resolveLinkedObject(int bci, int cpi, int opcode, BootstrapMeth Object argConstant = loadConstantDynamic(argCpi, opcode == Opcodes.INVOKEDYNAMIC ? Opcodes.LDC : opcode); if (argConstant instanceof ValueNode valueNode) { currentNode = valueNode; - } else if (argConstant instanceof Throwable) { + } else if (argConstant instanceof Throwable || argConstant instanceof UnresolvedJavaType) { /* A nested constant dynamic threw. */ return argConstant; } else { From 44cd417880012cd954ffb4074b53613f01ca01de Mon Sep 17 00:00:00 2001 From: Sacha Coppey Date: Wed, 6 Dec 2023 16:28:03 +0100 Subject: [PATCH 142/593] Execute bootstrap method at build time for Web Image until BoundMethodHandle issue is fixed --- .../svm/hosted/phases/AnalysisGraphBuilderPhase.java | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/phases/AnalysisGraphBuilderPhase.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/phases/AnalysisGraphBuilderPhase.java index 3198a59f0707..c111b4964515 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/phases/AnalysisGraphBuilderPhase.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/phases/AnalysisGraphBuilderPhase.java @@ -30,6 +30,9 @@ import java.lang.invoke.WrongMethodTypeException; import java.util.List; +import org.graalvm.nativeimage.ImageSingletons; +import org.graalvm.nativeimage.Platform; + import com.oracle.graal.pointsto.heap.ImageHeapInstance; import com.oracle.graal.pointsto.infrastructure.AnalysisConstantPool; import com.oracle.graal.pointsto.infrastructure.OriginalMethodProvider; @@ -162,8 +165,13 @@ protected void genInvokeDynamic(int cpi, int opcode) { return; } JavaMethod calleeMethod = lookupMethodInPool(cpi, opcode); + /* + * Bootstrap methods are executed at build time for Web Image due to an issue with + * BoundMethodHandle$SpeciesData + */ if (bootstrap == null || calleeMethod instanceof ResolvedJavaMethod || - BootstrapMethodConfiguration.singleton().isIndyAllowedAtBuildTime(OriginalMethodProvider.getJavaMethod(bootstrap.getMethod()))) { + BootstrapMethodConfiguration.singleton().isIndyAllowedAtBuildTime(OriginalMethodProvider.getJavaMethod(bootstrap.getMethod())) || + ImageSingletons.lookup(Platform.class).getOS().equals("js")) { super.genInvokeDynamic(cpi, opcode); return; } From 59b6bd680715aefc26b5265e7393199d81188177 Mon Sep 17 00:00:00 2001 From: Allan Gregersen Date: Thu, 7 Dec 2023 14:05:42 +0100 Subject: [PATCH 143/593] remove redundant synchronized blocks since SynchronizedCollection already internally synchronize on add/remove --- .../src/com/oracle/truffle/api/debug/Breakpoint.java | 8 ++------ .../src/com/oracle/truffle/api/debug/DebuggerSession.java | 8 ++------ 2 files changed, 4 insertions(+), 12 deletions(-) diff --git a/truffle/src/com.oracle.truffle.api.debug/src/com/oracle/truffle/api/debug/Breakpoint.java b/truffle/src/com.oracle.truffle.api.debug/src/com/oracle/truffle/api/debug/Breakpoint.java index eb0cf907f20a..c7cdc6314f5a 100644 --- a/truffle/src/com.oracle.truffle.api.debug/src/com/oracle/truffle/api/debug/Breakpoint.java +++ b/truffle/src/com.oracle.truffle.api.debug/src/com/oracle/truffle/api/debug/Breakpoint.java @@ -680,9 +680,7 @@ private void execBindingAdded(EventBinding if (newBinding != null) { execBindings.add(newBinding); for (DebuggerSession s : sessions) { - synchronized (s.allBindings) { - s.allBindings.add(newBinding); - } + s.allBindings.add(newBinding); } } // If newBinding is null, attach has failed. @@ -760,9 +758,7 @@ private void uninstallBindings(boolean execOnly) { for (EventBinding binding : execBindings) { bindings.add(binding); for (DebuggerSession s : sessions) { - synchronized (s.allBindings) { - s.allBindings.remove(binding); - } + s.allBindings.remove(binding); } } execBindings.clear(); diff --git a/truffle/src/com.oracle.truffle.api.debug/src/com/oracle/truffle/api/debug/DebuggerSession.java b/truffle/src/com.oracle.truffle.api.debug/src/com/oracle/truffle/api/debug/DebuggerSession.java index c33573fa78b3..3e14616522b9 100644 --- a/truffle/src/com.oracle.truffle.api.debug/src/com/oracle/truffle/api/debug/DebuggerSession.java +++ b/truffle/src/com.oracle.truffle.api.debug/src/com/oracle/truffle/api/debug/DebuggerSession.java @@ -678,9 +678,7 @@ public ExecutionEventNode create(EventContext context) { } } }, hasExpressionElement, syntaxTags); - synchronized (allBindings) { - allBindings.add(syntaxElementsBinding); - } + allBindings.add(syntaxElementsBinding); } } } @@ -708,9 +706,7 @@ public boolean test(Source source) { private void removeBindings() { assert Thread.holdsLock(this); if (syntaxElementsBinding != null) { - synchronized (allBindings) { - allBindings.remove(syntaxElementsBinding); - } + allBindings.remove(syntaxElementsBinding); syntaxElementsBinding.dispose(); syntaxElementsBinding = null; if (Debugger.TRACE) { From 752028feb0a45781905e96f1d3dca7da65ed4a02 Mon Sep 17 00:00:00 2001 From: Fengyun Liu Date: Thu, 7 Dec 2023 15:41:22 +0100 Subject: [PATCH 144/593] Rename tags to components --- ci.jsonnet | 24 ++++++++++++------------ ci/ci_common/common.jsonnet | 13 +++++-------- 2 files changed, 17 insertions(+), 20 deletions(-) diff --git a/ci.jsonnet b/ci.jsonnet index ca4d645e6fed..cb9554e02dde 100644 --- a/ci.jsonnet +++ b/ci.jsonnet @@ -50,18 +50,18 @@ local exclude_latest_darwin_amd64(builds) = [b for b in builds if !(import 'ci/c overlay: graal_common.ci.overlay, specVersion: "3", builds: exclude_latest_darwin_amd64([common.add_excludes_guard(b) for b in ( - common.with_tags_for_gates(compiler.builds, ["compiler"]) + - common.with_tags_for_gates(wasm.builds, ["wasm"]) + - common.with_tags_for_gates(espresso.builds, ["espresso"]) + - common.with_tags_for_gates(regex.builds, ["regex"]) + - common.with_tags_for_gates(sdk.builds, ["sdk"]) + - common.with_tags_for_gates(substratevm.builds, ["svm"]) + - common.with_tags_for_gates(sulong.builds, ["sulong"]) + - common.with_tags_for_gates(tools.builds, ["tools"]) + - common.with_tags_for_gates(truffle.builds, ["truffle"]) + - common.with_tags_for_gates(javadoc.builds, ["javadoc"]) + - common.with_tags_for_gates(vm.builds, ["vm"]) + - common.with_tags_for_gates(visualizer.builds, ["visualizer"]) + common.with_components(compiler.builds, ["compiler"]) + + common.with_components(wasm.builds, ["wasm"]) + + common.with_components(espresso.builds, ["espresso"]) + + common.with_components(regex.builds, ["regex"]) + + common.with_components(sdk.builds, ["sdk"]) + + common.with_components(substratevm.builds, ["svm"]) + + common.with_components(sulong.builds, ["sulong"]) + + common.with_components(tools.builds, ["tools"]) + + common.with_components(truffle.builds, ["truffle"]) + + common.with_components(javadoc.builds, ["javadoc"]) + + common.with_components(vm.builds, ["vm"]) + + common.with_components(visualizer.builds, ["visualizer"]) )]), assert verify_ci(self.builds), // verify that the run-spec demo works diff --git a/ci/ci_common/common.jsonnet b/ci/ci_common/common.jsonnet index f28fe2db1e59..b54ad2dc56eb 100644 --- a/ci/ci_common/common.jsonnet +++ b/ci/ci_common/common.jsonnet @@ -47,16 +47,13 @@ common + common.frequencies + { } else {} ), - # Add the specified tags to the field `tags` of builds if `build.targets` contains "gate". - with_tags_for_gates(builds, tags):: + # Add the specified components to the field `components`. + with_components(builds, components):: [ - if std.count(build.targets, "gate") > 0 then - if std.objectHas(build, "tags") then - build + { "tags" : std.setUnion(tags, build.tags) } - else - build + { "tags" : tags } + if std.objectHas(build, "components") then + build + { "components" : std.setUnion(components, build.components) } else - build + build + { "components" : components } for build in builds ], From ecfa994c35040c26667965f5fbaba950e06e69f7 Mon Sep 17 00:00:00 2001 From: Tomas Zezula Date: Wed, 6 Dec 2023 11:52:43 +0100 Subject: [PATCH 145/593] [GR-50682] Fixed classloader isolation. --- .../truffle/polyglot/EngineAccessor.java | 44 ++++++++++++------- .../truffle/polyglot/InstrumentCache.java | 11 +---- .../polyglot/InternalResourceCache.java | 12 +---- .../truffle/polyglot/LanguageCache.java | 11 +---- 4 files changed, 32 insertions(+), 46 deletions(-) diff --git a/truffle/src/com.oracle.truffle.polyglot/src/com/oracle/truffle/polyglot/EngineAccessor.java b/truffle/src/com.oracle.truffle.polyglot/src/com/oracle/truffle/polyglot/EngineAccessor.java index 45997a160608..f9b45f43b3ab 100644 --- a/truffle/src/com.oracle.truffle.polyglot/src/com/oracle/truffle/polyglot/EngineAccessor.java +++ b/truffle/src/com.oracle.truffle.polyglot/src/com/oracle/truffle/polyglot/EngineAccessor.java @@ -74,6 +74,7 @@ import java.util.logging.Level; import java.util.logging.LogRecord; +import com.oracle.truffle.api.Truffle; import org.graalvm.collections.Pair; import org.graalvm.nativeimage.ImageInfo; import org.graalvm.options.OptionKey; @@ -165,20 +166,41 @@ private static List locatorLoaders() { return suppliers; } - private static List defaultLoaders() { + private static AbstractClassLoaderSupplier defaultLoaders() { ClassLoader contextClassLoader = Thread.currentThread().getContextClassLoader(); - if (contextClassLoader != null) { - return List.of(new WeakClassLoaderSupplier(contextClassLoader)); + ClassLoader systemClassLoader = ClassLoader.getSystemClassLoader(); + if (contextClassLoader != null && isValidLoader(contextClassLoader)) { + return new WeakClassLoaderSupplier(contextClassLoader); + } else if (isValidLoader(systemClassLoader)) { + return new StrongClassLoaderSupplier(ClassLoader.getSystemClassLoader()); } else { - return List.of(new StrongClassLoaderSupplier(EngineAccessor.class.getClassLoader()), - new StrongClassLoaderSupplier(ClassLoader.getSystemClassLoader())); + /* + * This class loader is necessary for classpath isolation, enabled by the + * `-Dpolyglotimpl.DisableClassPathIsolation=false` option. It's needed because the + * system classloader does not load Truffle from a new module layer but from an unnamed + * module. + */ + return new StrongClassLoaderSupplier(EngineAccessor.class.getClassLoader()); + } + } + + /** + * Check that Truffle classes loaded by {@code loader} are the same as active Truffle runtime + * classes. + */ + private static boolean isValidLoader(ClassLoader loader) { + try { + Class truffleClassAsSeenByLoader = Class.forName(Truffle.class.getName(), true, loader); + return truffleClassAsSeenByLoader == Truffle.class; + } catch (ClassNotFoundException ex) { + return false; } } static List locatorOrDefaultLoaders() { List loaders = locatorLoaders(); if (loaders == null) { - loaders = defaultLoaders(); + loaders = List.of(defaultLoaders()); } return loaders; } @@ -306,7 +328,7 @@ public Iterable loadServices(Class type) { } for (AbstractClassLoaderSupplier loaderSupplier : EngineAccessor.locatorOrDefaultLoaders()) { ClassLoader loader = loaderSupplier.get(); - if (seesTheSameClass(loader, type)) { + if (loader != null) { // 2) Lookup implementations of a module aware interface for (T service : ServiceLoader.load(type, loader)) { if (loaderSupplier.accepts(service.getClass())) { @@ -329,14 +351,6 @@ public Iterable loadServices(Class type) { return found.values(); } - private static boolean seesTheSameClass(ClassLoader loader, Class type) { - try { - return loader != null && loader.loadClass(type.getName()) == type; - } catch (ClassNotFoundException ex) { - return false; - } - } - @Override public T lookup(InstrumentInfo info, Class serviceClass) { PolyglotInstrument instrument = (PolyglotInstrument) LANGUAGE.getPolyglotInstrument(info); diff --git a/truffle/src/com.oracle.truffle.polyglot/src/com/oracle/truffle/polyglot/InstrumentCache.java b/truffle/src/com.oracle.truffle.polyglot/src/com/oracle/truffle/polyglot/InstrumentCache.java index b83588d19099..db5c2c4cce27 100644 --- a/truffle/src/com.oracle.truffle.polyglot/src/com/oracle/truffle/polyglot/InstrumentCache.java +++ b/truffle/src/com.oracle.truffle.polyglot/src/com/oracle/truffle/polyglot/InstrumentCache.java @@ -170,7 +170,7 @@ static List doLoad(List suppliers) Map>> optionalResources = InternalResourceCache.loadOptionalInternalResources(suppliers); for (AbstractClassLoaderSupplier supplier : suppliers) { ClassLoader loader = supplier.get(); - if (loader == null || !isValidLoader(loader)) { + if (loader == null) { continue; } usesTruffleClassLoader |= truffleClassLoader == loader; @@ -249,15 +249,6 @@ private static void loadInstrumentImpl(ProviderAdapter providerAdapter, List truffleInstrumentClassAsSeenByLoader = Class.forName(TruffleInstrument.class.getName(), true, loader); - return truffleInstrumentClassAsSeenByLoader == TruffleInstrument.class; - } catch (ClassNotFoundException ex) { - return false; - } - } - String getId() { return id; } diff --git a/truffle/src/com.oracle.truffle.polyglot/src/com/oracle/truffle/polyglot/InternalResourceCache.java b/truffle/src/com.oracle.truffle.polyglot/src/com/oracle/truffle/polyglot/InternalResourceCache.java index b3a22bbc4cdf..a902e775c19a 100644 --- a/truffle/src/com.oracle.truffle.polyglot/src/com/oracle/truffle/polyglot/InternalResourceCache.java +++ b/truffle/src/com.oracle.truffle.polyglot/src/com/oracle/truffle/polyglot/InternalResourceCache.java @@ -42,7 +42,6 @@ import com.oracle.truffle.api.CompilerDirectives; import com.oracle.truffle.api.InternalResource; -import com.oracle.truffle.api.TruffleLanguage; import com.oracle.truffle.api.TruffleOptions; import com.oracle.truffle.api.provider.InternalResourceProvider; import com.oracle.truffle.polyglot.EngineAccessor.AbstractClassLoaderSupplier; @@ -384,7 +383,7 @@ private static Map>> collect Map>> cache = new HashMap<>(); for (EngineAccessor.AbstractClassLoaderSupplier supplier : suppliers) { ClassLoader loader = supplier.get(); - if (loader == null || !isValidLoader(loader)) { + if (loader == null) { continue; } StreamSupport.stream(ServiceLoader.load(InternalResourceProvider.class, loader).spliterator(), false).filter((p) -> supplier.accepts(p.getClass())).forEach((p) -> { @@ -406,15 +405,6 @@ private static boolean hasSameCodeSource(OptionalResourceSupplier first, Optiona return first.optionalResourceProvider.getClass() == second.optionalResourceProvider.getClass(); } - private static boolean isValidLoader(ClassLoader loader) { - try { - Class truffleLanguageClassAsSeenByLoader = Class.forName(TruffleLanguage.class.getName(), true, loader); - return truffleLanguageClassAsSeenByLoader == TruffleLanguage.class; - } catch (ClassNotFoundException ex) { - return false; - } - } - static RuntimeException throwDuplicateOptionalResourceException(InternalResourceCache existing, InternalResourceCache duplicate) { String message = String.format("Duplicate optional resource id %s for component %s. First optional resource [%s]. Second optional resource [%s].", existing.resourceId, diff --git a/truffle/src/com.oracle.truffle.polyglot/src/com/oracle/truffle/polyglot/LanguageCache.java b/truffle/src/com.oracle.truffle.polyglot/src/com/oracle/truffle/polyglot/LanguageCache.java index ab8b91863975..a4cbe6fd673d 100644 --- a/truffle/src/com.oracle.truffle.polyglot/src/com/oracle/truffle/polyglot/LanguageCache.java +++ b/truffle/src/com.oracle.truffle.polyglot/src/com/oracle/truffle/polyglot/LanguageCache.java @@ -270,7 +270,7 @@ private static synchronized Map createLanguages(List>> optionalResources = InternalResourceCache.loadOptionalInternalResources(suppliers); for (AbstractClassLoaderSupplier supplier : suppliers) { ClassLoader loader = supplier.get(); - if (loader == null || !isValidLoader(loader)) { + if (loader == null) { continue; } loadProviders(loader).filter((p) -> supplier.accepts(p.getProviderClass())).forEach((p) -> loadLanguageImpl(p, caches, optionalResources)); @@ -316,15 +316,6 @@ private static boolean hasSameCodeSource(LanguageCache first, LanguageCache seco return first.providerAdapter.getProviderClass() == second.providerAdapter.getProviderClass(); } - private static boolean isValidLoader(ClassLoader loader) { - try { - Class truffleLanguageClassAsSeenByLoader = Class.forName(TruffleLanguage.class.getName(), true, loader); - return truffleLanguageClassAsSeenByLoader == TruffleLanguage.class; - } catch (ClassNotFoundException ex) { - return false; - } - } - private static void loadLanguageImpl(ProviderAdapter providerAdapter, List into, Map>> optionalResources) { Class providerClass = providerAdapter.getProviderClass(); Module providerModule = providerClass.getModule(); From e6080f971ffb9482a9edcf124cf1a07969eead00 Mon Sep 17 00:00:00 2001 From: Florian Huemer Date: Thu, 7 Dec 2023 17:11:04 +0100 Subject: [PATCH 146/593] Implemented readBuffer for WasmMemory Added polyglot buffer support for custom sections. --- .../org/graalvm/wasm/test/WasmJsApiSuite.java | 120 ++++++++++++++++++ .../src/org/graalvm/wasm/utils/Assert.java | 16 ++- .../org/graalvm/wasm/api/ByteArrayBuffer.java | 85 ++++++++++++- .../wasm/memory/ByteArrayWasmMemory.java | 8 ++ .../graalvm/wasm/memory/NativeWasmMemory.java | 11 ++ .../graalvm/wasm/memory/UnsafeWasmMemory.java | 11 ++ .../org/graalvm/wasm/memory/WasmMemory.java | 25 ++-- 7 files changed, 266 insertions(+), 10 deletions(-) diff --git a/wasm/src/org.graalvm.wasm.test/src/org/graalvm/wasm/test/WasmJsApiSuite.java b/wasm/src/org.graalvm.wasm.test/src/org/graalvm/wasm/test/WasmJsApiSuite.java index 0d8a06009d58..921e94554882 100644 --- a/wasm/src/org.graalvm.wasm.test/src/org/graalvm/wasm/test/WasmJsApiSuite.java +++ b/wasm/src/org.graalvm.wasm.test/src/org/graalvm/wasm/test/WasmJsApiSuite.java @@ -965,6 +965,87 @@ public void testCustomSections() throws IOException { }); } + @Test + public void testCustomSectionBuffer() throws IOException { + runTest(context -> { + final WebAssembly wasm = new WebAssembly(context); + final WasmModule module = wasm.moduleDecode(binaryWithCustomSection); + try { + final long bufferSize = 16; + Object customSection = WebAssembly.customSections(module, "test").readArrayElement(0); + InteropLibrary interop = InteropLibrary.getUncached(customSection); + Assert.assertTrue("Custom section should have buffer elements", interop.hasBufferElements(customSection)); + Assert.assertTrue("Custom section should not have writable buffer", !interop.isBufferWritable(customSection)); + Assert.assertEquals("Custom section should have correct buffer size", 16L, interop.getBufferSize(customSection)); + Assert.assertEquals("Read first byte", (byte) 0x01, interop.readBufferByte(customSection, 0)); + Assert.assertEquals("Read last byte", (byte) 0x16, interop.readBufferByte(customSection, bufferSize - 1)); + Assert.assertEquals("Read first short LE", (short) 0x0201, interop.readBufferShort(customSection, ByteOrder.LITTLE_ENDIAN, 0)); + Assert.assertEquals("Read first short BE", (short) 0x0102, interop.readBufferShort(customSection, ByteOrder.BIG_ENDIAN, 0)); + Assert.assertEquals("Read last short LE", (short) 0x1615, interop.readBufferShort(customSection, ByteOrder.LITTLE_ENDIAN, bufferSize - 2)); + Assert.assertEquals("Read last short BE", (short) 0x1516, interop.readBufferShort(customSection, ByteOrder.BIG_ENDIAN, bufferSize - 2)); + Assert.assertEquals("Read first int LE", 0x04030201, interop.readBufferInt(customSection, ByteOrder.LITTLE_ENDIAN, 0)); + Assert.assertEquals("Read first int BE", 0x01020304, interop.readBufferInt(customSection, ByteOrder.BIG_ENDIAN, 0)); + Assert.assertEquals("Read last int LE", 0x16151413, interop.readBufferInt(customSection, ByteOrder.LITTLE_ENDIAN, bufferSize - 4)); + Assert.assertEquals("Read last int BE", 0x13141516, interop.readBufferInt(customSection, ByteOrder.BIG_ENDIAN, bufferSize - 4)); + Assert.assertEquals("Read first long LE", 0x0807060504030201L, interop.readBufferLong(customSection, ByteOrder.LITTLE_ENDIAN, 0)); + Assert.assertEquals("Read first long BE", 0x0102030405060708L, interop.readBufferLong(customSection, ByteOrder.BIG_ENDIAN, 0)); + Assert.assertEquals("Read last long LE", 0x1615141312111009L, interop.readBufferLong(customSection, ByteOrder.LITTLE_ENDIAN, bufferSize - 8)); + Assert.assertEquals("Read last long BE", 0x0910111213141516L, interop.readBufferLong(customSection, ByteOrder.BIG_ENDIAN, bufferSize - 8)); + Assert.assertEquals("Read first float LE", Float.intBitsToFloat(0x04030201), interop.readBufferFloat(customSection, ByteOrder.LITTLE_ENDIAN, 0)); + Assert.assertEquals("Read first float BE", Float.intBitsToFloat(0x01020304), interop.readBufferFloat(customSection, ByteOrder.BIG_ENDIAN, 0)); + Assert.assertEquals("Read last float LE", Float.intBitsToFloat(0x16151413), interop.readBufferFloat(customSection, ByteOrder.LITTLE_ENDIAN, bufferSize - 4)); + Assert.assertEquals("Read last float BE", Float.intBitsToFloat(0x13141516), interop.readBufferFloat(customSection, ByteOrder.BIG_ENDIAN, bufferSize - 4)); + Assert.assertEquals("Read first long LE", Double.longBitsToDouble(0x0807060504030201L), interop.readBufferDouble(customSection, ByteOrder.LITTLE_ENDIAN, 0)); + Assert.assertEquals("Read first long BE", Double.longBitsToDouble(0x0102030405060708L), interop.readBufferDouble(customSection, ByteOrder.BIG_ENDIAN, 0)); + Assert.assertEquals("Read last long LE", Double.longBitsToDouble(0x1615141312111009L), interop.readBufferDouble(customSection, ByteOrder.LITTLE_ENDIAN, bufferSize - 8)); + Assert.assertEquals("Read last long BE", Double.longBitsToDouble(0x0910111213141516L), interop.readBufferDouble(customSection, ByteOrder.BIG_ENDIAN, bufferSize - 8)); + final byte[] b = new byte[12]; + interop.readBuffer(customSection, 0, b, 0, 12); + Assert.assertArrayEquals("Read first 12 bytes", new byte[]{0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x10, 0x11, 0x12}, b); + interop.readBuffer(customSection, bufferSize - 12, b, 0, 12); + Assert.assertArrayEquals("Read last 12 bytes", new byte[]{0x05, 0x06, 0x07, 0x08, 0x09, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16}, b); + + assertThrowsIBOE(() -> interop.readBufferByte(customSection, -1)); + assertThrowsIBOE(() -> interop.readBufferShort(customSection, ByteOrder.LITTLE_ENDIAN, -1)); + assertThrowsIBOE(() -> interop.readBufferShort(customSection, ByteOrder.BIG_ENDIAN, -1)); + assertThrowsIBOE(() -> interop.readBufferInt(customSection, ByteOrder.LITTLE_ENDIAN, -1)); + assertThrowsIBOE(() -> interop.readBufferInt(customSection, ByteOrder.BIG_ENDIAN, -1)); + assertThrowsIBOE(() -> interop.readBufferLong(customSection, ByteOrder.LITTLE_ENDIAN, -1)); + assertThrowsIBOE(() -> interop.readBufferLong(customSection, ByteOrder.BIG_ENDIAN, -1)); + assertThrowsIBOE(() -> interop.readBufferFloat(customSection, ByteOrder.LITTLE_ENDIAN, -1)); + assertThrowsIBOE(() -> interop.readBufferFloat(customSection, ByteOrder.BIG_ENDIAN, -1)); + assertThrowsIBOE(() -> interop.readBufferDouble(customSection, ByteOrder.LITTLE_ENDIAN, -1)); + assertThrowsIBOE(() -> interop.readBufferDouble(customSection, ByteOrder.BIG_ENDIAN, -1)); + + assertThrowsIBOE(() -> { + final byte[] b2 = new byte[12]; + interop.readBuffer(customSection, -1, b2, 0, 8); + return null; + }); + + assertThrowsIBOE(() -> interop.readBufferByte(customSection, bufferSize)); + assertThrowsIBOE(() -> interop.readBufferShort(customSection, ByteOrder.LITTLE_ENDIAN, bufferSize - 1)); + assertThrowsIBOE(() -> interop.readBufferShort(customSection, ByteOrder.BIG_ENDIAN, bufferSize - 1)); + assertThrowsIBOE(() -> interop.readBufferInt(customSection, ByteOrder.LITTLE_ENDIAN, bufferSize - 3)); + assertThrowsIBOE(() -> interop.readBufferInt(customSection, ByteOrder.BIG_ENDIAN, bufferSize - 3)); + assertThrowsIBOE(() -> interop.readBufferLong(customSection, ByteOrder.LITTLE_ENDIAN, bufferSize - 7)); + assertThrowsIBOE(() -> interop.readBufferLong(customSection, ByteOrder.BIG_ENDIAN, bufferSize - 7)); + assertThrowsIBOE(() -> interop.readBufferFloat(customSection, ByteOrder.LITTLE_ENDIAN, bufferSize - 3)); + assertThrowsIBOE(() -> interop.readBufferFloat(customSection, ByteOrder.BIG_ENDIAN, bufferSize - 3)); + assertThrowsIBOE(() -> interop.readBufferDouble(customSection, ByteOrder.LITTLE_ENDIAN, bufferSize - 7)); + assertThrowsIBOE(() -> interop.readBufferDouble(customSection, ByteOrder.BIG_ENDIAN, bufferSize - 7)); + + assertThrowsIBOE(() -> { + final byte[] b2 = new byte[12]; + interop.readBuffer(customSection, bufferSize - 11, b2, 0, 12); + return null; + }); + } catch (InteropException ex) { + throw new RuntimeException(ex); + } + }); + } + private static void checkCustomSections(byte[][] expected, Sequence actual) throws InvalidArrayIndexException, UnsupportedMessageException { InteropLibrary interop = InteropLibrary.getUncached(actual); Assert.assertEquals("Custom section count", expected.length, (int) interop.getArraySize(actual)); @@ -1041,6 +1122,12 @@ public void testMemoryBufferMessages() throws IOException { Assert.assertEquals("Read last double LE", 0d, interop.readBufferDouble(buffer, ByteOrder.LITTLE_ENDIAN, bufferSize - 8)); Assert.assertEquals("Read last double BE", 0d, interop.readBufferDouble(buffer, ByteOrder.BIG_ENDIAN, bufferSize - 8)); + final byte[] b = new byte[12]; + interop.readBuffer(buffer, 0, b, 0, 12); + Assert.assertArrayEquals("Read first 12 bytes", new byte[]{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, b); + interop.readBuffer(buffer, bufferSize - 12, b, 0, 12); + Assert.assertArrayEquals("Read last 12 bytes", new byte[]{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, b); + interop.writeBufferByte(buffer, 0, (byte) 1); Assert.assertEquals("Read written byte", (byte) 1, interop.readBufferByte(buffer, 0)); @@ -1128,6 +1215,21 @@ public void testMemoryBufferMessages() throws IOException { Assert.assertEquals("Read byte 6 of double BE", (byte) 0x07, interop.readBufferByte(buffer, 6)); Assert.assertEquals("Read byte 7 of double BE", (byte) 0x08, interop.readBufferByte(buffer, 7)); + interop.writeBufferInt(buffer, ByteOrder.LITTLE_ENDIAN, 0, 0x01020304); + interop.writeBufferInt(buffer, ByteOrder.LITTLE_ENDIAN, 4, 0x05060708); + interop.writeBufferInt(buffer, ByteOrder.LITTLE_ENDIAN, 8, 0x09101112); + interop.writeBufferInt(buffer, ByteOrder.LITTLE_ENDIAN, 12, 0x13141516); + final byte[] b1 = new byte[12]; + final byte[] b2 = {0x04, 0x03, 0x02, 0x01, 0x08, 0x07, 0x06, 0x05, 0x12, 0x11, 0x10, 0x09}; + interop.readBuffer(buffer, 0, b1, 0, 12); + Assert.assertArrayEquals("Read first 12 bytes", b2, b1); + + final byte[] b3 = new byte[8]; + b3[0] = 0x02; + final byte[] b4 = {0x02, 0x11, 0x10, 0x09, 0x16, 0x15, 0x14, 0x13}; + interop.readBuffer(buffer, 9, b3, 1, 7); + Assert.assertArrayEquals("Read last 7 bytes", b4, b3); + // Offset too small assertThrowsIBOE(() -> interop.readBufferByte(buffer, -1)); assertThrowsIBOE(() -> interop.readBufferShort(buffer, ByteOrder.LITTLE_ENDIAN, -1)); @@ -1141,6 +1243,12 @@ public void testMemoryBufferMessages() throws IOException { assertThrowsIBOE(() -> interop.readBufferDouble(buffer, ByteOrder.LITTLE_ENDIAN, -1)); assertThrowsIBOE(() -> interop.readBufferDouble(buffer, ByteOrder.BIG_ENDIAN, -1)); + assertThrowsIBOE(() -> { + final byte[] b6 = new byte[12]; + interop.readBuffer(buffer, -1, b6, 0, 8); + return null; + }); + // Offset too large assertThrowsIBOE(() -> interop.readBufferByte(buffer, bufferSize)); assertThrowsIBOE(() -> interop.readBufferShort(buffer, ByteOrder.LITTLE_ENDIAN, bufferSize - 1)); @@ -1153,6 +1261,11 @@ public void testMemoryBufferMessages() throws IOException { assertThrowsIBOE(() -> interop.readBufferFloat(buffer, ByteOrder.BIG_ENDIAN, bufferSize - 3)); assertThrowsIBOE(() -> interop.readBufferDouble(buffer, ByteOrder.LITTLE_ENDIAN, bufferSize - 7)); assertThrowsIBOE(() -> interop.readBufferDouble(buffer, ByteOrder.BIG_ENDIAN, bufferSize - 7)); + assertThrowsIBOE(() -> { + final byte[] b6 = new byte[12]; + interop.readBuffer(buffer, bufferSize - 11, b6, 0, 12); + return null; + }); } catch (InteropException ex) { Assert.fail(ex.getMessage()); } @@ -2503,6 +2616,13 @@ public void accept(WasmContext context) { (byte) 0x00, (byte) 0x06, (byte) 0x04, (byte) 0x65, (byte) 0x76, (byte) 0x65, (byte) 0x6e, (byte) 0x06 }; + // Module with custom section: "test" (with data 0x01 0x02 0x03 0x04 0x05 0x06 0x07 0x08 0x09 + // 0x10 0x11 0x12 0x13 0x14 0x15 0x16) + private static final byte[] binaryWithCustomSection = { + 0x00, 0x61, 0x73, 0x6d, 0x01, 0x00, 0x00, 0x00, 0x00, 0x15, 0x04, 0x74, 0x65, 0x73, 0x74, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, + 0x16 + }; + // Module with an empty name (custom) section private static final byte[] binaryWithEmptyNameSection = new byte[]{ (byte) 0x00, (byte) 0x61, (byte) 0x73, (byte) 0x6d, (byte) 0x01, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x05, (byte) 0x04, (byte) 0x6e, (byte) 0x61, diff --git a/wasm/src/org.graalvm.wasm.utils/src/org/graalvm/wasm/utils/Assert.java b/wasm/src/org.graalvm.wasm.utils/src/org/graalvm/wasm/utils/Assert.java index 527e9d4936da..1ed0b3485365 100644 --- a/wasm/src/org.graalvm.wasm.utils/src/org/graalvm/wasm/utils/Assert.java +++ b/wasm/src/org.graalvm.wasm.utils/src/org/graalvm/wasm/utils/Assert.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2023, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * The Universal Permissive License (UPL), Version 1.0 @@ -71,6 +71,20 @@ public static void assertDoubleEquals(String message, Double expected, Double ac } } + public static void assertArrayEquals(String message, byte[] expected, byte[] actual) { + if (expected == actual) { + return; + } + if (expected.length != actual.length) { + fail(format("%s '%s.length' != '%s.length'", message, expected, actual)); + } + for (int i = 0; i < expected.length; i++) { + if (expected[i] != actual[i]) { + fail(format("%s '%s[%d] { %d }' != '%s[%d] { %d }'", message, expected, i, expected[i], actual, i, actual[i])); + } + } + } + public static void fail(String message) { throw new RuntimeException(message); } diff --git a/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/api/ByteArrayBuffer.java b/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/api/ByteArrayBuffer.java index 6c0700bee837..f48ca188e7be 100644 --- a/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/api/ByteArrayBuffer.java +++ b/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/api/ByteArrayBuffer.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2023, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * The Universal Permissive License (UPL), Version 1.0 @@ -45,13 +45,17 @@ import com.oracle.truffle.api.dsl.Cached; import com.oracle.truffle.api.interop.InteropLibrary; import com.oracle.truffle.api.interop.InvalidArrayIndexException; +import com.oracle.truffle.api.interop.InvalidBufferOffsetException; import com.oracle.truffle.api.interop.TruffleObject; import com.oracle.truffle.api.interop.UnsupportedMessageException; import com.oracle.truffle.api.library.ExportLibrary; import com.oracle.truffle.api.library.ExportMessage; +import com.oracle.truffle.api.memory.ByteArraySupport; import com.oracle.truffle.api.nodes.Node; import com.oracle.truffle.api.profiles.InlinedBranchProfile; +import java.nio.ByteOrder; + @ExportLibrary(InteropLibrary.class) public class ByteArrayBuffer implements TruffleObject { private final byte[] data; @@ -115,4 +119,83 @@ public Object readArrayElement(long index, final void writeArrayElement(long index, Object value) throws UnsupportedMessageException { throw UnsupportedMessageException.create(); } + + @SuppressWarnings("static-method") + @ExportMessage + final boolean hasBufferElements() { + return true; + } + + @ExportMessage + final long getBufferSize() { + return length; + } + + private void checkBufferOffset(long byteOffset, int opLength) throws InvalidBufferOffsetException { + if (byteOffset < 0 || opLength < 0 || getBufferSize() - opLength < byteOffset) { + throw InvalidBufferOffsetException.create(byteOffset, opLength); + } + } + + @ExportMessage + final void readBuffer(long byteOffset, byte[] destination, int destinationOffset, int opLength) throws InvalidBufferOffsetException { + checkBufferOffset(byteOffset, opLength); + System.arraycopy(data, offset + (int) byteOffset, destination, destinationOffset, opLength); + } + + @ExportMessage + final byte readBufferByte(long byteOffset) throws InvalidBufferOffsetException { + checkBufferOffset(byteOffset, Byte.BYTES); + return data[offset + (int) byteOffset]; + } + + @ExportMessage + final short readBufferShort(ByteOrder order, long byteOffset) throws InvalidBufferOffsetException { + checkBufferOffset(byteOffset, Short.BYTES); + if (order == ByteOrder.LITTLE_ENDIAN) { + return ByteArraySupport.littleEndian().getShort(data, offset + byteOffset); + } else { + return ByteArraySupport.bigEndian().getShort(data, offset + byteOffset); + } + } + + @ExportMessage + final int readBufferInt(ByteOrder order, long byteOffset) throws InvalidBufferOffsetException { + checkBufferOffset(byteOffset, Integer.BYTES); + if (order == ByteOrder.LITTLE_ENDIAN) { + return ByteArraySupport.littleEndian().getInt(data, offset + byteOffset); + } else { + return ByteArraySupport.bigEndian().getInt(data, offset + byteOffset); + } + } + + @ExportMessage + final long readBufferLong(ByteOrder order, long byteOffset) throws InvalidBufferOffsetException { + checkBufferOffset(byteOffset, Long.BYTES); + if (order == ByteOrder.LITTLE_ENDIAN) { + return ByteArraySupport.littleEndian().getLong(data, offset + byteOffset); + } else { + return ByteArraySupport.bigEndian().getLong(data, offset + byteOffset); + } + } + + @ExportMessage + final float readBufferFloat(ByteOrder order, long byteOffset) throws InvalidBufferOffsetException { + checkBufferOffset(byteOffset, Float.BYTES); + if (order == ByteOrder.LITTLE_ENDIAN) { + return ByteArraySupport.littleEndian().getFloat(data, offset + byteOffset); + } else { + return ByteArraySupport.bigEndian().getFloat(data, offset + byteOffset); + } + } + + @ExportMessage + final double readBufferDouble(ByteOrder order, long byteOffset) throws InvalidBufferOffsetException { + checkBufferOffset(byteOffset, Double.BYTES); + if (order == ByteOrder.LITTLE_ENDIAN) { + return ByteArraySupport.littleEndian().getDouble(data, offset + byteOffset); + } else { + return ByteArraySupport.bigEndian().getDouble(data, offset + byteOffset); + } + } } diff --git a/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/memory/ByteArrayWasmMemory.java b/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/memory/ByteArrayWasmMemory.java index 54388d575004..b8636a852cde 100644 --- a/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/memory/ByteArrayWasmMemory.java +++ b/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/memory/ByteArrayWasmMemory.java @@ -1049,6 +1049,14 @@ public void copyToStream(Node node, OutputStream stream, int offset, int length) stream.write(byteArrayBuffer.buffer(), offset, length); } + @Override + public void copyToBuffer(Node node, byte[] dst, long srcOffset, int dstOffset, int length) { + if (outOfBounds(srcOffset, length)) { + throw trapOutOfBounds(node, srcOffset, length); + } + System.arraycopy(byteArrayBuffer.buffer(), (int) srcOffset, dst, dstOffset, length); + } + private static final class WasmByteArrayBuffer { private static final int MAX_CONSTANT_ATTEMPTS = 5; diff --git a/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/memory/NativeWasmMemory.java b/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/memory/NativeWasmMemory.java index f23f50d3564f..fe8b71e29c32 100644 --- a/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/memory/NativeWasmMemory.java +++ b/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/memory/NativeWasmMemory.java @@ -996,6 +996,17 @@ public void copyToStream(Node node, OutputStream stream, int offset, int length) } } + @Override + public void copyToBuffer(Node node, byte[] dst, long srcOffset, int dstOffset, int length) { + if (outOfBounds(srcOffset, length)) { + throw trapOutOfBounds(node, srcOffset, length); + } + for (int i = 0; i < length; i++) { + byte b = unsafe.getByte(startAddress + srcOffset + i); + dst[dstOffset + i] = b; + } + } + @Override public boolean isUnsafe() { return true; diff --git a/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/memory/UnsafeWasmMemory.java b/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/memory/UnsafeWasmMemory.java index d5d8ee1e56ad..00e2a6a5abfd 100644 --- a/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/memory/UnsafeWasmMemory.java +++ b/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/memory/UnsafeWasmMemory.java @@ -1001,6 +1001,17 @@ public void copyToStream(Node node, OutputStream stream, int offset, int length) } } + @Override + public void copyToBuffer(Node node, byte[] dst, long srcOffset, int dstOffset, int length) { + if (outOfBounds(srcOffset, length)) { + throw trapOutOfBounds(node, srcOffset, length); + } + for (int i = 0; i < length; i++) { + byte b = unsafe.getByte(startAddress + srcOffset + i); + dst[dstOffset + i] = b; + } + } + @Override public boolean isUnsafe() { return true; diff --git a/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/memory/WasmMemory.java b/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/memory/WasmMemory.java index 4d0dbbaaedcf..e5201e623c17 100644 --- a/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/memory/WasmMemory.java +++ b/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/memory/WasmMemory.java @@ -624,21 +624,19 @@ private void checkOffset(Node node, long byteOffset, int opLength, InlinedBranch } @ExportMessage - final byte readBufferByte(long byteOffset, + final void readBuffer(long byteOffset, byte[] destination, int destinationOffset, int length, @Bind("$node") Node node, @Shared("errorBranch") @Cached InlinedBranchProfile errorBranch) throws InvalidBufferOffsetException { - checkOffset(node, byteOffset, Byte.BYTES, errorBranch); - return (byte) load_i32_8s(null, byteOffset); + checkOffset(node, byteOffset, length, errorBranch); + copyToBuffer(node, destination, byteOffset, destinationOffset, length); } @ExportMessage - final void readBuffer(long byteOffset, byte[] destination, int destinationOffset, int length, + final byte readBufferByte(long byteOffset, @Bind("$node") Node node, @Shared("errorBranch") @Cached InlinedBranchProfile errorBranch) throws InvalidBufferOffsetException { - checkOffset(node, byteOffset, length, errorBranch); - for (long offset = byteOffset; offset < byteOffset + length; offset++) { - destination[destinationOffset + (int) (offset - byteOffset)] = (byte) load_i32_8s(null, offset); - } + checkOffset(node, byteOffset, Byte.BYTES, errorBranch); + return (byte) load_i32_8s(null, byteOffset); } @ExportMessage @@ -892,6 +890,17 @@ protected boolean outOfBounds(long offset, long length) { */ public abstract void copyToStream(Node node, OutputStream stream, int offset, int length) throws IOException; + /** + * Copy data from memory into a byte[] array. + * + * @param node the node used for errors + * @param dst the output buffer + * @param srcOffset the offset in the memory + * @param dstOffset the offset in the byte[] array + * @param length the length of the data + */ + public abstract void copyToBuffer(Node node, byte[] dst, long srcOffset, int dstOffset, int length); + public boolean isUnsafe() { return false; } From b65967899879ec0a3eee5a1980ce3610f3a7541b Mon Sep 17 00:00:00 2001 From: Peter Hofer Date: Mon, 4 Dec 2023 18:31:30 +0100 Subject: [PATCH 147/593] Option for experimental Foreign Function and Memory API support. --- ci/common.jsonnet | 3 + compiler/mx.compiler/suite.py | 1 - .../native-image/ForeignInterface.md | 5 +- sdk/mx.sdk/suite.py | 3 +- substratevm/CHANGELOG.md | 1 + substratevm/mx.substratevm/mx_substratevm.py | 16 -- substratevm/mx.substratevm/suite.py | 51 +------ .../com/oracle/svm/core/foreign/AbiUtils.java | 12 +- .../core/foreign/ForeignFunctionsEnabled.java | 36 +++++ .../core/foreign/ForeignFunctionsRuntime.java | 4 +- ...Target_java_lang_foreign_SymbolLookup.java | 2 +- ...get_jdk_internal_foreign_SystemLookup.java | 4 +- ...internal_foreign_abi_NativeEntryPoint.java | 2 +- ..._jdk_internal_misc_ScopedMemoryAccess.java | 4 +- .../com/oracle/svm/core/SubstrateOptions.java | 3 + .../jdk/ForeignDisabledSubstitutions.java | 144 ++++++++++++++++++ .../svm/core/jdk/Target_java_lang_Module.java | 6 + ...arget_jdk_internal_reflect_Reflection.java | 9 ++ .../svm/core/jdk/Target_sun_nio_ch_Util.java | 7 + .../svm/driver/DefaultOptionHandler.java | 5 +- .../com/oracle/svm/driver/NativeImage.java | 41 ----- .../foreign/ForeignFunctionsFeature.java | 35 ++--- vm/mx.vm/mx_vm.py | 18 +-- 23 files changed, 255 insertions(+), 157 deletions(-) create mode 100644 substratevm/src/com.oracle.svm.core.foreign/src/com/oracle/svm/core/foreign/ForeignFunctionsEnabled.java create mode 100644 substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/ForeignDisabledSubstitutions.java diff --git a/ci/common.jsonnet b/ci/common.jsonnet index 43f78c8a4812..a9e64dc11602 100644 --- a/ci/common.jsonnet +++ b/ci/common.jsonnet @@ -229,6 +229,9 @@ local common_json = import "../common.json"; }, svm:: { + packages+: { + cmake: "==3.22.2", + }, environment+: { DEFAULT_VM: "server", LANG: "en_US.UTF-8", diff --git a/compiler/mx.compiler/suite.py b/compiler/mx.compiler/suite.py index 96870bee17e2..c81103331dae 100644 --- a/compiler/mx.compiler/suite.py +++ b/compiler/mx.compiler/suite.py @@ -498,7 +498,6 @@ """* to com.oracle.graal.graal_enterprise, org.graalvm.nativeimage.pointsto, org.graalvm.nativeimage.builder, - org.graalvm.nativeimage.foreign, org.graalvm.nativeimage.llvm, com.oracle.svm.svm_enterprise, com.oracle.svm_enterprise.ml_dataset, diff --git a/docs/reference-manual/native-image/ForeignInterface.md b/docs/reference-manual/native-image/ForeignInterface.md index 68cebe8a2e9d..1254b59b4ae9 100644 --- a/docs/reference-manual/native-image/ForeignInterface.md +++ b/docs/reference-manual/native-image/ForeignInterface.md @@ -7,8 +7,9 @@ permalink: /reference-manual/native-image/dynamic-features/foreign-interface/ # Foreign Function & Memory API in Native Image -The Foreign Function & Memory (FFM) API is a native interface that enables Java code to interact with native code and vice versa. -As of [JEP 442](https://openjdk.org/jeps/442){:target="_blank"}, it is a preview API of the Java platform and must be enabled with `--enable-preview`. +The Foreign Function & Memory (FFM) API is an interface that enables Java code to interact with native code and vice versa. +It has been finalized in JDK 22 with [JEP 454](https://openjdk.org/jeps/454){:target="_blank"}. +Support in Native Image is currently experimental and needs to be explicitly enabled with `-H:+ForeignAPISupport` (requiring `-H:+UnlockExperimentalVMOptions`). Modules that are permitted to perform "restricted" native operations (including creating handles for calls to or from native code) must be specified using `--enable-native-access=`. This page gives an overview of support for the FFM API in Native Image. diff --git a/sdk/mx.sdk/suite.py b/sdk/mx.sdk/suite.py index a7ceded8071e..d9fbc2637fc3 100644 --- a/sdk/mx.sdk/suite.py +++ b/sdk/mx.sdk/suite.py @@ -668,8 +668,7 @@ class UniversalDetector { com.oracle.svm.svm_enterprise, org.graalvm.extraimage.builder, org.graalvm.truffle.runtime.svm, - com.oracle.svm.enterprise.truffle, - org.graalvm.nativeimage.foreign""", + com.oracle.svm.enterprise.truffle""", "org.graalvm.nativeimage.impl.clinit to org.graalvm.nativeimage.builder", ], "uses" : [], diff --git a/substratevm/CHANGELOG.md b/substratevm/CHANGELOG.md index 638971acc057..6eda86468f0e 100644 --- a/substratevm/CHANGELOG.md +++ b/substratevm/CHANGELOG.md @@ -16,6 +16,7 @@ This changelog summarizes major changes to GraalVM Native Image. * (GR-45651) The Native Image agent now tracks calls to `ClassLoader.findSystemClass`, `ObjectInputStream.resolveClass` and `Bundles.of`, and registers resource bundles as bundle name-locale pairs. * (GR-49807) Before this change the function `System#setSecurityManager` was always halting program execution with a VM error. This was inconvenient as the VM error prints an uncomprehensible error message and prevents further continuation of the program. For cases where the program is expected to throw an exception when `System#setSecurityManager` is called, execution on Native Image was not possible. Now, `System#setSecurityManager` throws an `java.lang.UnsupportedOperationException` by default. If the property `java.security.manager` is set to anything but `disallow` at program startup this function will throw a `java.lang.SecurityException` according to the Java spec. * (GR-30433) Disallow the deprecated environment variable USE_NATIVE_IMAGE_JAVA_PLATFORM_MODULE_SYSTEM=false. +* (GR-49655) Experimental support for parts of the [Foreign Function & Memory API](https://github.com/oracle/graal/blob/master/docs/reference-manual/native-image/ForeignInterface.md) (part of "Project Panama", [JEP 454](https://openjdk.org/jeps/454)) on AMD64. Must be enabled with `-H:+ForeignAPISupport` (requiring `-H:+UnlockExperimentalVMOptions`). ## GraalVM for JDK 21 (Internal Version 23.1.0) * (GR-35746) Lower the default aligned chunk size from 1 MB to 512 KB for the serial and epsilon GCs, reducing memory usage and image size in many cases. diff --git a/substratevm/mx.substratevm/mx_substratevm.py b/substratevm/mx.substratevm/mx_substratevm.py index 0c874a4f5df3..d026fa65b01e 100644 --- a/substratevm/mx.substratevm/mx_substratevm.py +++ b/substratevm/mx.substratevm/mx_substratevm.py @@ -1074,22 +1074,6 @@ def _native_image_launcher_extra_jvm_args(): additional_ni_dependencies = [] -if mx.get_jdk(tag='default').javaCompliance >= '21': - mx_sdk_vm.register_graalvm_component(mx_sdk_vm.GraalVmJreComponent( - suite=suite, - name='SubstrateVM Foreign API Preview Feature', - short_name='svmforeign', - dir_name='svm-preview', - installable_id='native-image', - license_files=[], - third_party_license_files=[], - dependencies=['SubstrateVM'], - builder_jar_distributions=['substratevm:SVM_FOREIGN'], - installable=False, - jlink=False, - )) - additional_ni_dependencies += ['svmforeign'] - native_image = mx_sdk_vm.GraalVmJreComponent( suite=suite, name='Native Image', diff --git a/substratevm/mx.substratevm/suite.py b/substratevm/mx.substratevm/suite.py index 464dd14c3368..fa7f517de354 100644 --- a/substratevm/mx.substratevm/suite.py +++ b/substratevm/mx.substratevm/suite.py @@ -689,13 +689,11 @@ "jdk.internal.vm.ci" : [ ], }, - "javaCompliance" : "21+", - "javaPreviewNeeded": "21+", + "javaCompliance" : "22+", "annotationProcessors": [ "compiler:GRAAL_PROCESSOR", "SVM_PROCESSOR", ], - "javac.lint.overrides": "-preview", "checkstyle": "com.oracle.svm.hosted", "workingSets": "SVM", "jacoco" : "include", @@ -719,13 +717,11 @@ "jdk.vm.ci.code" ], }, - "javaCompliance" : "21+", - "javaPreviewNeeded": "21+", + "javaCompliance" : "22+", "annotationProcessors": [ "compiler:GRAAL_PROCESSOR", "SVM_PROCESSOR", ], - "javac.lint.overrides": "-preview", "checkstyle": "com.oracle.svm.hosted", "workingSets": "SVM", "jacoco" : "include", @@ -1424,6 +1420,7 @@ "dependencies": [ "com.oracle.svm.graal", "com.oracle.svm.hosted", + "com.oracle.svm.hosted.foreign", "com.oracle.svm.core", "com.oracle.svm.core.graal.amd64", "com.oracle.svm.core.graal.aarch64", @@ -1889,9 +1886,9 @@ "name" : "org.graalvm.nativeimage.base", "requires" : ["java.sql", "java.xml"],# workaround for GR-47773 on the module-path which requires java.sql (like truffle) or java.xml "exports" : [ - "com.oracle.svm.util to org.graalvm.nativeimage.pointsto,org.graalvm.nativeimage.builder,org.graalvm.nativeimage.librarysupport,org.graalvm.nativeimage.driver,org.graalvm.nativeimage.llvm,org.graalvm.nativeimage.agent.jvmtibase,org.graalvm.nativeimage.agent.tracing,org.graalvm.nativeimage.agent.diagnostics,org.graalvm.nativeimage.junitsupport,com.oracle.svm.svm_enterprise,com.oracle.svm_enterprise.ml_dataset,org.graalvm.extraimage.builder,com.oracle.svm.extraimage_enterprise,org.graalvm.extraimage.librarysupport,org.graalvm.nativeimage.foreign,org.graalvm.truffle.runtime.svm,com.oracle.truffle.enterprise.svm", - "com.oracle.svm.common.meta to org.graalvm.nativeimage.pointsto,org.graalvm.nativeimage.builder,org.graalvm.nativeimage.llvm,org.graalvm.extraimage.builder,org.graalvm.nativeimage.foreign,org.graalvm.truffle.runtime.svm,com.oracle.truffle.enterprise.svm", - "com.oracle.svm.common.option to org.graalvm.nativeimage.pointsto,org.graalvm.nativeimage.builder,org.graalvm.nativeimage.driver,org.graalvm.nativeimage.foreign,org.graalvm.truffle.runtime.svm,com.oracle.truffle.enterprise.svm", + "com.oracle.svm.util to org.graalvm.nativeimage.pointsto,org.graalvm.nativeimage.builder,org.graalvm.nativeimage.librarysupport,org.graalvm.nativeimage.driver,org.graalvm.nativeimage.llvm,org.graalvm.nativeimage.agent.jvmtibase,org.graalvm.nativeimage.agent.tracing,org.graalvm.nativeimage.agent.diagnostics,org.graalvm.nativeimage.junitsupport,com.oracle.svm.svm_enterprise,com.oracle.svm_enterprise.ml_dataset,org.graalvm.extraimage.builder,com.oracle.svm.extraimage_enterprise,org.graalvm.extraimage.librarysupport,org.graalvm.truffle.runtime.svm,com.oracle.truffle.enterprise.svm", + "com.oracle.svm.common.meta to org.graalvm.nativeimage.pointsto,org.graalvm.nativeimage.builder,org.graalvm.nativeimage.llvm,org.graalvm.extraimage.builder,org.graalvm.truffle.runtime.svm,com.oracle.truffle.enterprise.svm", + "com.oracle.svm.common.option to org.graalvm.nativeimage.pointsto,org.graalvm.nativeimage.builder,org.graalvm.nativeimage.driver,org.graalvm.truffle.runtime.svm,com.oracle.truffle.enterprise.svm", ], }, "noMavenJavadoc": True, @@ -2164,42 +2161,6 @@ }, }, - "SVM_FOREIGN": { - "subDir": "src", - "description" : "SubstrateVM support for the Foreign API", - "dependencies": [ - "com.oracle.svm.hosted.foreign", - ], - "distDependencies": [ - "compiler:GRAAL", - "SVM" - ], - "moduleInfo" : { - "name" : "org.graalvm.nativeimage.foreign", - "requires" : [ - "org.graalvm.nativeimage.builder" - ], - "exports" : [ - "* to org.graalvm.nativeimage.builder", - ], - "requiresConcealed": { - "jdk.internal.vm.ci" : [ - "jdk.vm.ci.meta", - "jdk.vm.ci.code", - "jdk.vm.ci.amd64", - ], - "java.base": [ - "jdk.internal.foreign", - "jdk.internal.foreign.abi", - "jdk.internal.foreign.abi.x64", - "jdk.internal.foreign.abi.x64.sysv", - "jdk.internal.foreign.abi.x64.windows", - ], - }, - }, - "maven" : False, - }, - "SVM_LLVM" : { "subDir" : "src", "description" : "LLVM backend for Native Image", diff --git a/substratevm/src/com.oracle.svm.core.foreign/src/com/oracle/svm/core/foreign/AbiUtils.java b/substratevm/src/com.oracle.svm.core.foreign/src/com/oracle/svm/core/foreign/AbiUtils.java index a0a3fd8565e1..883436dc93b8 100644 --- a/substratevm/src/com.oracle.svm.core.foreign/src/com/oracle/svm/core/foreign/AbiUtils.java +++ b/substratevm/src/com.oracle.svm.core.foreign/src/com/oracle/svm/core/foreign/AbiUtils.java @@ -40,9 +40,6 @@ import java.util.Objects; import java.util.stream.Stream; -import jdk.graal.compiler.api.replacements.Fold; -import jdk.graal.compiler.nodes.ValueNode; -import jdk.graal.compiler.nodes.calc.ReinterpretNode; import org.graalvm.nativeimage.ImageSingletons; import org.graalvm.nativeimage.Platform; import org.graalvm.nativeimage.Platforms; @@ -53,6 +50,9 @@ import com.oracle.svm.core.headers.WindowsAPIs; import com.oracle.svm.core.util.VMError; +import jdk.graal.compiler.api.replacements.Fold; +import jdk.graal.compiler.nodes.ValueNode; +import jdk.graal.compiler.nodes.calc.ReinterpretNode; import jdk.internal.foreign.CABI; import jdk.internal.foreign.abi.Binding; import jdk.internal.foreign.abi.CallingSequence; @@ -534,7 +534,7 @@ protected List generateAdaptations(NativeEntryPointInfo nep) @Platforms(Platform.HOSTED_ONLY.class) public void checkLibrarySupport() { String name = "SystemV (Linux AMD64)"; - VMError.guarantee(LibC.isSupported(), "Foreign functions feature requires LibC support on " + name); + VMError.guarantee(LibC.isSupported(), "Foreign functions feature requires LibC support on %s", name); } @Override @@ -587,8 +587,8 @@ protected List generateAdaptations(NativeEntryPointInfo nep) @Platforms(Platform.HOSTED_ONLY.class) public void checkLibrarySupport() { String name = "Win64 (Windows AMD64)"; - VMError.guarantee(LibC.isSupported(), "Foreign functions feature requires LibC support on" + name); - VMError.guarantee(WindowsAPIs.isSupported(), "Foreign functions feature requires Windows APIs support on" + name); + VMError.guarantee(LibC.isSupported(), "Foreign functions feature requires LibC support on %s", name); + VMError.guarantee(WindowsAPIs.isSupported(), "Foreign functions feature requires Windows APIs support on %s", name); } @Override diff --git a/substratevm/src/com.oracle.svm.core.foreign/src/com/oracle/svm/core/foreign/ForeignFunctionsEnabled.java b/substratevm/src/com.oracle.svm.core.foreign/src/com/oracle/svm/core/foreign/ForeignFunctionsEnabled.java new file mode 100644 index 000000000000..1b937c22a20d --- /dev/null +++ b/substratevm/src/com.oracle.svm.core.foreign/src/com/oracle/svm/core/foreign/ForeignFunctionsEnabled.java @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2023, 2023, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.svm.core.foreign; + +import java.util.function.BooleanSupplier; + +import com.oracle.svm.core.SubstrateOptions; + +final class ForeignFunctionsEnabled implements BooleanSupplier { + @Override + public boolean getAsBoolean() { + return SubstrateOptions.ForeignAPISupport.getValue(); + } +} diff --git a/substratevm/src/com.oracle.svm.core.foreign/src/com/oracle/svm/core/foreign/ForeignFunctionsRuntime.java b/substratevm/src/com.oracle.svm.core.foreign/src/com/oracle/svm/core/foreign/ForeignFunctionsRuntime.java index d44a0ff3e29a..1eda5453d6ef 100644 --- a/substratevm/src/com.oracle.svm.core.foreign/src/com/oracle/svm/core/foreign/ForeignFunctionsRuntime.java +++ b/substratevm/src/com.oracle.svm.core.foreign/src/com/oracle/svm/core/foreign/ForeignFunctionsRuntime.java @@ -27,7 +27,6 @@ import static jdk.graal.compiler.core.common.spi.ForeignCallDescriptor.CallSideEffect.HAS_SIDE_EFFECT; import org.graalvm.collections.EconomicMap; -import jdk.graal.compiler.api.replacements.Fold; import org.graalvm.nativeimage.ImageSingletons; import org.graalvm.nativeimage.Platform; import org.graalvm.nativeimage.Platforms; @@ -44,6 +43,7 @@ import com.oracle.svm.core.snippets.SubstrateForeignCallTarget; import com.oracle.svm.core.util.VMError; +import jdk.graal.compiler.api.replacements.Fold; import jdk.internal.foreign.abi.CapturableState; public class ForeignFunctionsRuntime { @@ -59,7 +59,7 @@ public ForeignFunctionsRuntime() { @Platforms(Platform.HOSTED_ONLY.class) public void addDowncallStubPointer(NativeEntryPointInfo nep, CFunctionPointer ptr) { - VMError.guarantee(!downcallStubs.containsKey(nep), "Seems like multiple stubs were generated for " + nep); + VMError.guarantee(!downcallStubs.containsKey(nep), "Seems like multiple stubs were generated for %s", nep); VMError.guarantee(downcallStubs.put(nep, new FunctionPointerHolder(ptr)) == null); } diff --git a/substratevm/src/com.oracle.svm.core.foreign/src/com/oracle/svm/core/foreign/Target_java_lang_foreign_SymbolLookup.java b/substratevm/src/com.oracle.svm.core.foreign/src/com/oracle/svm/core/foreign/Target_java_lang_foreign_SymbolLookup.java index ffda625c7dd8..508c7490a15f 100644 --- a/substratevm/src/com.oracle.svm.core.foreign/src/com/oracle/svm/core/foreign/Target_java_lang_foreign_SymbolLookup.java +++ b/substratevm/src/com.oracle.svm.core.foreign/src/com/oracle/svm/core/foreign/Target_java_lang_foreign_SymbolLookup.java @@ -66,7 +66,7 @@ * succeed. See * {@link com.oracle.svm.core.jdk.Target_java_lang_ClassLoader#loadLibrary(java.lang.Class, java.lang.String)} */ -@TargetClass(className = "java.lang.foreign.SymbolLookup") +@TargetClass(className = "java.lang.foreign.SymbolLookup", onlyWith = ForeignFunctionsEnabled.class) public final class Target_java_lang_foreign_SymbolLookup { @Substitute diff --git a/substratevm/src/com.oracle.svm.core.foreign/src/com/oracle/svm/core/foreign/Target_jdk_internal_foreign_SystemLookup.java b/substratevm/src/com.oracle.svm.core.foreign/src/com/oracle/svm/core/foreign/Target_jdk_internal_foreign_SystemLookup.java index abd100d719d7..3469c9fdaac3 100644 --- a/substratevm/src/com.oracle.svm.core.foreign/src/com/oracle/svm/core/foreign/Target_jdk_internal_foreign_SystemLookup.java +++ b/substratevm/src/com.oracle.svm.core.foreign/src/com/oracle/svm/core/foreign/Target_jdk_internal_foreign_SystemLookup.java @@ -36,7 +36,7 @@ * libraries. The provided libraries are not really defined in the documentation, so the best we can * do is load the exact same libraries as HotSpot. */ -@TargetClass(className = "jdk.internal.foreign.SystemLookup") +@TargetClass(className = "jdk.internal.foreign.SystemLookup", onlyWith = ForeignFunctionsEnabled.class) public final class Target_jdk_internal_foreign_SystemLookup { @Substitute public Optional find(String name) { @@ -44,7 +44,7 @@ public Optional find(String name) { } } -@TargetClass(className = "jdk.internal.foreign.SystemLookup", innerClass = "WindowsFallbackSymbols") +@TargetClass(className = "jdk.internal.foreign.SystemLookup", innerClass = "WindowsFallbackSymbols", onlyWith = ForeignFunctionsEnabled.class) @Delete final class Target_jdk_internal_foreign_SystemLookup_WindowsFallbackSymbols { } diff --git a/substratevm/src/com.oracle.svm.core.foreign/src/com/oracle/svm/core/foreign/Target_jdk_internal_foreign_abi_NativeEntryPoint.java b/substratevm/src/com.oracle.svm.core.foreign/src/com/oracle/svm/core/foreign/Target_jdk_internal_foreign_abi_NativeEntryPoint.java index 75e848d8e771..17537e990a37 100644 --- a/substratevm/src/com.oracle.svm.core.foreign/src/com/oracle/svm/core/foreign/Target_jdk_internal_foreign_abi_NativeEntryPoint.java +++ b/substratevm/src/com.oracle.svm.core.foreign/src/com/oracle/svm/core/foreign/Target_jdk_internal_foreign_abi_NativeEntryPoint.java @@ -36,7 +36,7 @@ * Packs the address of a {@link com.oracle.svm.hosted.foreign.DowncallStub} with some extra * information. */ -@TargetClass(className = "jdk.internal.foreign.abi.NativeEntryPoint") +@TargetClass(className = "jdk.internal.foreign.abi.NativeEntryPoint", onlyWith = ForeignFunctionsEnabled.class) @Substitute public final class Target_jdk_internal_foreign_abi_NativeEntryPoint { diff --git a/substratevm/src/com.oracle.svm.core.foreign/src/com/oracle/svm/core/foreign/Target_jdk_internal_misc_ScopedMemoryAccess.java b/substratevm/src/com.oracle.svm.core.foreign/src/com/oracle/svm/core/foreign/Target_jdk_internal_misc_ScopedMemoryAccess.java index ef77d680204b..811931893aa7 100644 --- a/substratevm/src/com.oracle.svm.core.foreign/src/com/oracle/svm/core/foreign/Target_jdk_internal_misc_ScopedMemoryAccess.java +++ b/substratevm/src/com.oracle.svm.core.foreign/src/com/oracle/svm/core/foreign/Target_jdk_internal_misc_ScopedMemoryAccess.java @@ -39,7 +39,7 @@ *

* It seems like this could be easily supported once thread-local handshakes are supported. */ -@TargetClass(className = "jdk.internal.misc.ScopedMemoryAccess") +@TargetClass(className = "jdk.internal.misc.ScopedMemoryAccess", onlyWith = ForeignFunctionsEnabled.class) public final class Target_jdk_internal_misc_ScopedMemoryAccess { @Substitute static void registerNatives() { @@ -80,6 +80,6 @@ boolean closeScope0(MemorySessionImpl session) { } } -@TargetClass(className = "jdk.internal.misc.ScopedMemoryAccess$ScopedAccessError", onlyWith = JDK22OrLater.class) +@TargetClass(className = "jdk.internal.misc.ScopedMemoryAccess$ScopedAccessError", onlyWith = {JDK22OrLater.class, ForeignFunctionsEnabled.class}) final class Target_jdk_internal_misc_ScopedMemoryAccess_ScopedAccessError { } diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/SubstrateOptions.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/SubstrateOptions.java index d827d45a9445..3394043aeebc 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/SubstrateOptions.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/SubstrateOptions.java @@ -1040,6 +1040,9 @@ public enum ReportingMode { @Option(help = "Include all classes, methods, fields, and resources from given paths", type = OptionType.Debug) // public static final HostedOptionKey IncludeAllFromPath = new HostedOptionKey<>(LocatableMultiOptionValue.Strings.build()); + @Option(help = "Support for calls via the Java Foreign Function and Memory API", type = Expert) // + public static final HostedOptionKey ForeignAPISupport = new HostedOptionKey<>(false); + public static class TruffleStableOptions { @Option(help = "Automatically copy the necessary language resources to the resources/languages directory next to the produced image." + diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/ForeignDisabledSubstitutions.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/ForeignDisabledSubstitutions.java new file mode 100644 index 000000000000..f0eb0b704ff4 --- /dev/null +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/ForeignDisabledSubstitutions.java @@ -0,0 +1,144 @@ +/* + * Copyright (c) 2023, 2023, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.svm.core.jdk; + +import java.io.IOException; +import java.lang.invoke.VarHandle; +import java.nio.channels.FileChannel; +import java.util.List; +import java.util.Set; +import java.util.function.BooleanSupplier; +import java.util.function.Function; + +import com.oracle.svm.core.AlwaysInline; +import com.oracle.svm.core.SubstrateOptions; +import com.oracle.svm.core.annotate.Substitute; +import com.oracle.svm.core.annotate.TargetClass; +import com.oracle.svm.core.option.SubstrateOptionsParser; +import com.oracle.svm.core.util.VMError; + +/* Substitutions for when Foreign Function and Memory (FFM) API support is disabled. */ + +final class ForeignDisabled implements BooleanSupplier { + @Override + public boolean getAsBoolean() { + return !SubstrateOptions.ForeignAPISupport.getValue(); + } +} + +@TargetClass(className = "jdk.internal.foreign.MemorySessionImpl", onlyWith = ForeignDisabled.class) +final class Target_jdk_internal_foreign_MemorySessionImpl { + @Substitute + Target_java_lang_foreign_Arena asArena() { + throw ForeignDisabledSubstitutions.fail(); + } +} + +@TargetClass(className = "java.lang.foreign.Arena", onlyWith = ForeignDisabled.class) +final class Target_java_lang_foreign_Arena { +} + +@TargetClass(className = "java.lang.foreign.Linker", onlyWith = ForeignDisabled.class) +final class Target_java_lang_foreign_Linker { +} + +@TargetClass(className = "jdk.internal.foreign.abi.SharedUtils", onlyWith = ForeignDisabled.class) +final class Target_jdk_internal_foreign_abi_SharedUtils { + @Substitute + static Target_java_lang_foreign_Arena newBoundedArena(long size) { + throw ForeignDisabledSubstitutions.fail(); + } + + @Substitute + static Target_java_lang_foreign_Arena newEmptyArena() { + throw ForeignDisabledSubstitutions.fail(); + } + + @Substitute + static Target_java_lang_foreign_Linker getSystemLinker() { + throw ForeignDisabledSubstitutions.fail(); + } +} + +@TargetClass(className = "java.lang.foreign.MemoryLayout", onlyWith = ForeignDisabled.class) +final class Target_java_lang_foreign_MemoryLayout { +} + +@TargetClass(className = "jdk.internal.foreign.FunctionDescriptorImpl", onlyWith = ForeignDisabled.class) +final class Target_jdk_internal_foreign_FunctionDescriptorImpl { + @Substitute + Target_jdk_internal_foreign_FunctionDescriptorImpl(Target_java_lang_foreign_MemoryLayout resLayout, List argLayouts) { + throw ForeignDisabledSubstitutions.fail(); + } +} + +@TargetClass(className = "jdk.internal.foreign.SegmentFactories", onlyWith = {ForeignDisabled.class, JDK22OrLater.class}) +final class Target_jdk_internal_foreign_SegmentFactories { + @Substitute + @AlwaysInline("Make remaining code in callers unreachable.") + static void ensureInitialized() { + throw ForeignDisabledSubstitutions.fail(); + } +} + +@TargetClass(className = "sun.nio.ch.FileChannelImpl", onlyWith = ForeignDisabled.class) +final class Target_sun_nio_ch_FileChannelImpl { + @Substitute + Target_java_lang_foreign_MemorySegment map(FileChannel.MapMode mode, long offset, long size, Target_java_lang_foreign_Arena arena) throws IOException { + throw ForeignDisabledSubstitutions.fail(); + } +} + +@TargetClass(className = "jdk.internal.foreign.LayoutPath", onlyWith = ForeignDisabled.class) +final class Target_jdk_internal_foreign_LayoutPath { +} + +@TargetClass(className = "java.lang.foreign.MemoryLayout", innerClass = "PathElement", onlyWith = ForeignDisabled.class) +final class Target_java_lang_foreign_MemoryLayout_PathElement { +} + +@TargetClass(className = "jdk.internal.foreign.layout.AbstractLayout", onlyWith = {ForeignDisabled.class, JDK22OrLater.class}) +final class Target_jdk_internal_foreign_layout_AbstractLayout { + @Substitute + @AlwaysInline("Make remaining code in callers unreachable.") + VarHandle varHandle(Target_java_lang_foreign_MemoryLayout_PathElement... elements) { + throw ForeignDisabledSubstitutions.fail(); + } + + @Substitute + static Z computePathOp(Target_jdk_internal_foreign_LayoutPath path, Function finalizer, + Set badKinds, Target_java_lang_foreign_MemoryLayout_PathElement... elements) { + throw ForeignDisabledSubstitutions.fail(); + } +} + +final class ForeignDisabledSubstitutions { + private static final String OPTION_NAME = SubstrateOptionsParser.commandArgument(SubstrateOptions.ForeignAPISupport, "+"); + + static RuntimeException fail() { + assert !SubstrateOptions.ForeignAPISupport.getValue(); + throw VMError.unsupportedFeature("Support for the Java Foreign Function and Memory API is not active: enable with " + OPTION_NAME); + } +} diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/Target_java_lang_Module.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/Target_java_lang_Module.java index 10996ed2d0e6..0238aac44e55 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/Target_java_lang_Module.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/Target_java_lang_Module.java @@ -37,6 +37,12 @@ @SuppressWarnings("unused") @TargetClass(value = java.lang.Module.class) public final class Target_java_lang_Module { + @Substitute + @TargetElement(onlyWith = ForeignDisabled.class) + public boolean isNativeAccessEnabled() { + throw ForeignDisabledSubstitutions.fail(); + } + @Alias @TargetElement(onlyWith = JDK21OrEarlier.class) public native void ensureNativeAccess(Class owner, String methodName); diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/Target_jdk_internal_reflect_Reflection.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/Target_jdk_internal_reflect_Reflection.java index 07473bee98dd..d63d006adb4e 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/Target_jdk_internal_reflect_Reflection.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/Target_jdk_internal_reflect_Reflection.java @@ -27,15 +27,24 @@ import org.graalvm.nativeimage.Platforms; import org.graalvm.nativeimage.impl.InternalPlatform; +import com.oracle.svm.core.AlwaysInline; import com.oracle.svm.core.NeverInline; import com.oracle.svm.core.annotate.Substitute; import com.oracle.svm.core.annotate.TargetClass; +import com.oracle.svm.core.annotate.TargetElement; import com.oracle.svm.core.hub.DynamicHub; import com.oracle.svm.core.snippets.KnownIntrinsics; @TargetClass(value = jdk.internal.reflect.Reflection.class) final class Target_jdk_internal_reflect_Reflection { + @TargetElement(onlyWith = ForeignDisabled.class) + @Substitute + @AlwaysInline("Make remaining code in callers unreachable.") + static void ensureNativeAccess(Class currentClass, Class owner, String methodName) { + throw ForeignDisabledSubstitutions.fail(); + } + @Substitute @NeverInline("Starting a stack walk in the caller frame") @Platforms(InternalPlatform.NATIVE_ONLY.class) diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/Target_sun_nio_ch_Util.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/Target_sun_nio_ch_Util.java index 641b11507d09..8e0ff99ce6a7 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/Target_sun_nio_ch_Util.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/Target_sun_nio_ch_Util.java @@ -25,16 +25,23 @@ package com.oracle.svm.core.jdk; import java.io.FileDescriptor; +import java.nio.Buffer; import java.nio.MappedByteBuffer; import com.oracle.svm.core.SubstrateUtil; import com.oracle.svm.core.annotate.Alias; import com.oracle.svm.core.annotate.Substitute; import com.oracle.svm.core.annotate.TargetClass; +import com.oracle.svm.core.annotate.TargetElement; @TargetClass(className = "java.lang.foreign.MemorySegment") @SuppressWarnings("unused") final class Target_java_lang_foreign_MemorySegment { + @TargetElement(onlyWith = ForeignDisabled.class) + @Substitute + static Target_java_lang_foreign_MemorySegment ofBuffer(Buffer buffer) { + throw ForeignDisabledSubstitutions.fail(); + } } @TargetClass(className = "java.nio.DirectByteBufferR") diff --git a/substratevm/src/com.oracle.svm.driver/src/com/oracle/svm/driver/DefaultOptionHandler.java b/substratevm/src/com.oracle.svm.driver/src/com/oracle/svm/driver/DefaultOptionHandler.java index df0cbe0bad92..5f277a36a631 100644 --- a/substratevm/src/com.oracle.svm.driver/src/com/oracle/svm/driver/DefaultOptionHandler.java +++ b/substratevm/src/com.oracle.svm.driver/src/com/oracle/svm/driver/DefaultOptionHandler.java @@ -129,7 +129,6 @@ public boolean consume(ArgumentQueue args) { case "--enable-preview": args.poll(); nativeImage.addCustomJavaArgs("--enable-preview"); - nativeImage.enablePreview(); return true; case nativeAccessOption: args.poll(); @@ -137,7 +136,7 @@ public boolean consume(ArgumentQueue args) { if (modules == null) { NativeImage.showError(nativeAccessOption + moduleSetModifierOptionErrorMessage); } - nativeImage.addCustomJavaArgs(nativeAccessOption + "=" + modules + ",org.graalvm.nativeimage.foreign"); + nativeImage.addCustomJavaArgs(nativeAccessOption + "=" + modules + ",org.graalvm.nativeimage.builder"); return true; } @@ -218,7 +217,7 @@ public boolean consume(ArgumentQueue args) { if (nativeAccessModules.isEmpty()) { NativeImage.showError(headArg + moduleSetModifierOptionErrorMessage); } - nativeImage.addCustomJavaArgs(headArg + ",org.graalvm.nativeimage.foreign"); + nativeImage.addCustomJavaArgs(headArg + ",org.graalvm.nativeimage.builder"); return true; } return false; diff --git a/substratevm/src/com.oracle.svm.driver/src/com/oracle/svm/driver/NativeImage.java b/substratevm/src/com.oracle.svm.driver/src/com/oracle/svm/driver/NativeImage.java index 1bffeeccd3ae..633937f8ff03 100644 --- a/substratevm/src/com.oracle.svm.driver/src/com/oracle/svm/driver/NativeImage.java +++ b/substratevm/src/com.oracle.svm.driver/src/com/oracle/svm/driver/NativeImage.java @@ -319,7 +319,6 @@ protected static class BuildConfiguration { protected final Path workDir; protected final Path rootDir; protected final Path libJvmciDir; - protected final Path libPreviewDir; protected final List args; BuildConfiguration(BuildConfiguration original) { @@ -328,7 +327,6 @@ protected static class BuildConfiguration { workDir = original.workDir; rootDir = original.rootDir; libJvmciDir = original.libJvmciDir; - libPreviewDir = original.libPreviewDir; args = original.args; } @@ -371,8 +369,6 @@ protected BuildConfiguration(List args) { } Path ljDir = this.rootDir.resolve(Paths.get("lib", "jvmci")); libJvmciDir = Files.exists(ljDir) ? ljDir : null; - Path lpDir = this.rootDir.resolve(Paths.get("lib", "svm-preview", "builder")); - libPreviewDir = Files.exists(lpDir) ? lpDir : null; } /** @@ -1895,43 +1891,6 @@ Path canonicalize(Path path, boolean strict) { } } - public enum PreviewFeatures { - FOREIGN(JavaVersionUtil.JAVA_SPEC >= 21, "svm-foreign"); - - private final boolean requirementsMet; - private final String libName; - - PreviewFeatures(boolean requirementsMet, String libName) { - this.requirementsMet = requirementsMet; - this.libName = libName; - } - - public boolean requirementsMet() { - return requirementsMet; - } - - public String getLibName() { - return libName; - } - } - - public void enablePreview() { - if (config.libPreviewDir == null && PreviewFeatures.values().length > 0) { - throw showError("The directory containing the preview modules was not found."); - } - - for (var preview : PreviewFeatures.values()) { - if (preview.requirementsMet()) { - Path libPath = config.libPreviewDir == null ? null : config.libPreviewDir.resolve(preview.getLibName() + ".jar"); - if (libPath != null && Files.exists(libPath)) { - addImageBuilderModulePath(libPath); - } else { - throw showError("Preview library " + preview.getLibName() + " should be enabled, but was not found."); - } - } - } - } - public void addImageBuilderModulePath(Path modulePathEntry) { imageBuilderModulePath.add(canonicalize(modulePathEntry)); } diff --git a/substratevm/src/com.oracle.svm.hosted.foreign/src/com/oracle/svm/hosted/foreign/ForeignFunctionsFeature.java b/substratevm/src/com.oracle.svm.hosted.foreign/src/com/oracle/svm/hosted/foreign/ForeignFunctionsFeature.java index aea603fa5035..24cced11e590 100644 --- a/substratevm/src/com.oracle.svm.hosted.foreign/src/com/oracle/svm/hosted/foreign/ForeignFunctionsFeature.java +++ b/substratevm/src/com.oracle.svm.hosted.foreign/src/com/oracle/svm/hosted/foreign/ForeignFunctionsFeature.java @@ -35,8 +35,6 @@ import java.util.function.Function; import org.graalvm.collections.Pair; -import jdk.graal.compiler.api.replacements.Fold; -import jdk.graal.compiler.serviceprovider.JavaVersionUtil; import org.graalvm.nativeimage.ImageSingletons; import org.graalvm.nativeimage.Platform; import org.graalvm.nativeimage.Platforms; @@ -62,7 +60,6 @@ import com.oracle.svm.core.graal.meta.SubstrateForeignCallsProvider; import com.oracle.svm.core.meta.MethodPointer; import com.oracle.svm.core.util.UserError; -import com.oracle.svm.core.util.VMError; import com.oracle.svm.hosted.ConditionalConfigurationRegistry; import com.oracle.svm.hosted.FeatureImpl; import com.oracle.svm.hosted.ProgressReporter; @@ -70,24 +67,13 @@ import com.oracle.svm.util.ModuleSupport; import com.oracle.svm.util.ReflectionUtil; +import jdk.graal.compiler.api.replacements.Fold; +import jdk.graal.compiler.serviceprovider.JavaVersionUtil; import jdk.vm.ci.meta.ResolvedJavaMethod; @AutomaticallyRegisteredFeature @Platforms(Platform.HOSTED_ONLY.class) public class ForeignFunctionsFeature implements InternalFeature { - private static boolean isPreviewEnabled() { - try { - return (boolean) ReflectionUtil.lookupMethod( - ReflectionUtil.lookupClass(false, "jdk.internal.misc.PreviewFeatures"), - "isEnabled").invoke(null); - } catch (ReflectiveOperationException e) { - throw VMError.shouldNotReachHere(e); - } - } - - private static final int FIRST_SUPPORTED_PREVIEW = 21; - private static final int FIRST_SUPPORTED_NON_PREVIEW = Integer.MAX_VALUE - 1; // TBD - private static final Map REQUIRES_CONCEALED = Map.of( "jdk.internal.vm.ci", new String[]{"jdk.vm.ci.code", "jdk.vm.ci.meta", "jdk.vm.ci.amd64"}, "java.base", new String[]{ @@ -122,8 +108,8 @@ public void registerForDowncall(ConfigurationCondition condition, FunctionDescri ForeignFunctionsFeature() { /* - * We add these exports systematically in the constructor, as to avoid access errors from - * plugins when the feature is disabled in the config. + * We intentionally add these exports in the constructor to avoid access errors from plugins + * when the feature is disabled in the config. */ for (var modulePackages : REQUIRES_CONCEALED.entrySet()) { ModuleSupport.accessPackagesToClass(ModuleSupport.Access.EXPORT, ForeignFunctionsFeature.class, false, modulePackages.getKey(), modulePackages.getValue()); @@ -132,16 +118,17 @@ public void registerForDowncall(ConfigurationCondition condition, FunctionDescri @Override public boolean isInConfiguration(IsInConfigurationAccess access) { - return SubstrateUtil.getArchitectureName().contains("amd64") && !SubstrateOptions.useLLVMBackend(); + if (!SubstrateOptions.ForeignAPISupport.getValue()) { + return false; + } + UserError.guarantee(JavaVersionUtil.JAVA_SPEC >= 22, "Support for the Foreign Function and Memory API is available only with JDK 22 and later."); + UserError.guarantee(SubstrateUtil.getArchitectureName().contains("amd64"), "Support for the Foreign Function and Memory API is currently available only on the AMD64 architecture."); + UserError.guarantee(!SubstrateOptions.useLLVMBackend(), "Support for the Foreign Function and Memory API is not available with the LLVM backend."); + return true; } @Override public void duringSetup(DuringSetupAccess a) { - assert (JavaVersionUtil.JAVA_SPEC >= FIRST_SUPPORTED_PREVIEW && isPreviewEnabled()) || - JavaVersionUtil.JAVA_SPEC >= FIRST_SUPPORTED_NON_PREVIEW; - - UserError.guarantee(!SubstrateOptions.useLLVMBackend(), "Foreign functions interface is in use, but is not supported together with the LLVM backend."); - ImageSingletons.add(AbiUtils.class, AbiUtils.create()); ImageSingletons.add(ForeignFunctionsRuntime.class, new ForeignFunctionsRuntime()); ImageSingletons.add(RuntimeForeignAccessSupport.class, accessSupport); diff --git a/vm/mx.vm/mx_vm.py b/vm/mx.vm/mx_vm.py index db4b0894d1a1..ed2bb07b0875 100644 --- a/vm/mx.vm/mx_vm.py +++ b/vm/mx.vm/mx_vm.py @@ -189,10 +189,10 @@ def local_path_to_url(args): llvm_components = ['bgraalvm-native-binutil', 'bgraalvm-native-clang', 'bgraalvm-native-clang-cl', 'bgraalvm-native-clang++', 'bgraalvm-native-flang', 'bgraalvm-native-ld'] # pylint: disable=line-too-long -ce_unchained_components = ['bnative-image-configure', 'cmp', 'lg', 'ni', 'nic', 'nil', 'nr_lib_jvmcicompiler', 'sdkc', 'sdkni', 'svm', 'svmforeign', 'svmsl', 'svmt', 'tflc', 'tflsm'] +ce_unchained_components = ['bnative-image-configure', 'cmp', 'lg', 'ni', 'nic', 'nil', 'nr_lib_jvmcicompiler', 'sdkc', 'sdkni', 'svm', 'svmsl', 'svmt', 'tflc', 'tflsm'] ce_components_minimal = ['bpolyglot', 'cmp', 'cov', 'dap', 'gu', 'gvm', 'ins', 'insight', 'insightheap', 'lg', 'libpoly', 'lsp', 'nfi-libffi', 'nfi', 'poly', 'polynative', 'pro', 'sdk', 'sdkni', 'sdkc', 'sdkl', 'spolyglot', 'tfl', 'tfla', 'tflc', 'tflm', 'truffle-json'] -ce_components = ce_components_minimal + ['nr_lib_jvmcicompiler', 'bnative-image-configure', 'ni', 'nic', 'nil', 'svm', 'svmt', 'svmnfi', 'svmsl', 'svmforeign'] -ce_win_complete_components = ['antlr4', 'bnative-image-configure', 'bpolyglot', 'cmp', 'cov', 'dap', 'ejvm', 'gu', 'gvm', 'gwa', 'gwal', 'icu4j', 'xz', 'ins', 'insight', 'insightheap', 'java', 'js', 'jsl', 'jss', 'lg', 'libpoly', 'llp', 'llrc', 'llrl', 'llrlf', 'llrn', 'lsp', 'nfi-libffi', 'nfi', 'ni', 'nic', 'nil', 'njs', 'njsl', 'poly', 'polynative', 'pro', 'pyn', 'pynl', 'rgx', 'sdk', 'sdkni', 'sdkc', 'sdkl', 'spolyglot', 'svm', 'svmt', 'svmnfi', 'svmsl', 'svmforeign', 'tfl', 'tfla', 'tflc', 'tflm', 'truffle-json', 'vvm'] +ce_components = ce_components_minimal + ['nr_lib_jvmcicompiler', 'bnative-image-configure', 'ni', 'nic', 'nil', 'svm', 'svmt', 'svmnfi', 'svmsl'] +ce_win_complete_components = ['antlr4', 'bnative-image-configure', 'bpolyglot', 'cmp', 'cov', 'dap', 'ejvm', 'gu', 'gvm', 'gwa', 'gwal', 'icu4j', 'xz', 'ins', 'insight', 'insightheap', 'java', 'js', 'jsl', 'jss', 'lg', 'libpoly', 'llp', 'llrc', 'llrl', 'llrlf', 'llrn', 'lsp', 'nfi-libffi', 'nfi', 'ni', 'nic', 'nil', 'njs', 'njsl', 'poly', 'polynative', 'pro', 'pyn', 'pynl', 'rgx', 'sdk', 'sdkni', 'sdkc', 'sdkl', 'spolyglot', 'svm', 'svmt', 'svmnfi', 'svmsl', 'tfl', 'tfla', 'tflc', 'tflm', 'truffle-json', 'vvm'] ce_aarch64_complete_components = ce_win_complete_components + ['rby', 'rbyl', 'svml'] ce_complete_components = ce_aarch64_complete_components + ['ellvm', 'R', 'bRMain', 'xz'] ce_darwin_aarch64_complete_components = list(ce_aarch64_complete_components) @@ -227,15 +227,15 @@ def local_path_to_url(args): mx_sdk_vm.register_vm_config('toolchain-only', ['antlr4', 'sdk', 'sdkni', 'sdkc', 'sdkl', 'tfl', 'tfla', 'tflc', 'tflm', 'nfi-libffi', 'nfi', 'cmp', 'llp', 'llrc', 'llrlf', 'llrn'], _suite) mx_sdk_vm.register_vm_config('libgraal-bash', llvm_components + ['cmp', 'gu', 'gvm', 'lg', 'nfi-libffi', 'nfi', 'poly', 'polynative', 'sdk', 'sdkni', 'sdkc', 'sdkl', 'tfl', 'tfla', 'tflc', 'tflm', 'bpolyglot'], _suite, env_file=False) mx_sdk_vm.register_vm_config('toolchain-only-bash', llvm_components + ['antlr4', 'tfl', 'tfla', 'tflc', 'tflm', 'gu', 'gvm', 'polynative', 'llp', 'nfi-libffi', 'nfi', 'svml', 'sdk', 'sdkni', 'sdkc', 'sdkl', 'llrc', 'llrlf', 'llrn', 'cmp'], _suite, env_file=False) -mx_sdk_vm.register_vm_config('ce', llvm_components + ['antlr4', 'java', 'libpoly', 'sjavavm', 'spolyglot', 'ejvm', 'sjsvm', 'sllvmvm', 'bnative-image', 'srubyvm', 'pynl', 'spythonvm', 'pyn', 'cmp', 'gwa', 'gwal', 'icu4j', 'xz', 'js', 'jsl', 'jss', 'lg', 'llp', 'nfi-libffi', 'nfi', 'ni', 'nil', 'pbm', 'pmh', 'pbi', 'rby', 'rbyl', 'rgx', 'sdk', 'sdkni', 'sdkc', 'sdkl', 'llrc', 'llrn', 'llrl', 'llrlf', 'snative-image-agent', 'snative-image-diagnostics-agent', 'svm', 'svmt', 'svmnfi', 'svmsl', 'svmforeign', 'swasmvm', 'tfl', 'tfla', 'tflc', 'tflm'], _suite, env_file='polybench-ce') -mx_sdk_vm.register_vm_config('ce', ['bnative-image', 'bpolybench', 'cmp', 'icu4j', 'xz', 'lg', 'nfi', 'ni', 'nil', 'pbi', 'pbm', 'pmh', 'sdk', 'sdkni', 'sdkc', 'sdkl', 'snative-image-agent', 'snative-image-diagnostics-agent', 'svm', 'svmt', 'svmnfi', 'svmsl', 'svmforeign', 'tfl', 'tfla', 'tflc', 'tflm'], _suite, dist_name='ce', env_file='polybench-ctw-ce') -mx_sdk_vm.register_vm_config('ce', ['pbm', 'pmh', 'pbi', 'ni', 'icu4j', 'xz', 'js', 'jsl', 'jss', 'lg', 'nfi-libffi', 'nfi', 'tfl', 'tfla', 'tflc', 'svm', 'svmt', 'nil', 'rgx', 'sdk', 'sdkni', 'sdkc', 'sdkl', 'cmp', 'tflm', 'svmnfi', 'svmsl', 'svmforeign', 'bnative-image', 'sjsvm', 'snative-image-agent', 'snative-image-diagnostics-agent'], _suite, env_file='polybench-nfi-ce') -mx_sdk_vm.register_vm_config('ce', llvm_components + ['antlr4', 'sllvmvm', 'bnative-image', 'cmp', 'lg', 'llrc', 'llrl', 'llrlf', 'llrn', 'nfi-libffi', 'nfi', 'ni', 'nil', 'pbm', 'pbi', 'sdk', 'sdkni', 'sdkc', 'sdkl', 'snative-image-agent', 'snative-image-diagnostics-agent', 'svm', 'svmt', 'svmnfi', 'svmsl', 'svmforeign', 'tfl', 'tfla', 'tflc', 'tflm'], _suite, env_file='polybench-sulong-ce') +mx_sdk_vm.register_vm_config('ce', llvm_components + ['antlr4', 'java', 'libpoly', 'sjavavm', 'spolyglot', 'ejvm', 'sjsvm', 'sllvmvm', 'bnative-image', 'srubyvm', 'pynl', 'spythonvm', 'pyn', 'cmp', 'gwa', 'gwal', 'icu4j', 'xz', 'js', 'jsl', 'jss', 'lg', 'llp', 'nfi-libffi', 'nfi', 'ni', 'nil', 'pbm', 'pmh', 'pbi', 'rby', 'rbyl', 'rgx', 'sdk', 'sdkni', 'sdkc', 'sdkl', 'llrc', 'llrn', 'llrl', 'llrlf', 'snative-image-agent', 'snative-image-diagnostics-agent', 'svm', 'svmt', 'svmnfi', 'svmsl', 'swasmvm', 'tfl', 'tfla', 'tflc', 'tflm'], _suite, env_file='polybench-ce') +mx_sdk_vm.register_vm_config('ce', ['bnative-image', 'bpolybench', 'cmp', 'icu4j', 'xz', 'lg', 'nfi', 'ni', 'nil', 'pbi', 'pbm', 'pmh', 'sdk', 'sdkni', 'sdkc', 'sdkl', 'snative-image-agent', 'snative-image-diagnostics-agent', 'svm', 'svmt', 'svmnfi', 'svmsl', 'tfl', 'tfla', 'tflc', 'tflm'], _suite, dist_name='ce', env_file='polybench-ctw-ce') +mx_sdk_vm.register_vm_config('ce', ['pbm', 'pmh', 'pbi', 'ni', 'icu4j', 'xz', 'js', 'jsl', 'jss', 'lg', 'nfi-libffi', 'nfi', 'tfl', 'tfla', 'tflc', 'svm', 'svmt', 'nil', 'rgx', 'sdk', 'sdkni', 'sdkc', 'sdkl', 'cmp', 'tflm', 'svmnfi', 'svmsl', 'bnative-image', 'sjsvm', 'snative-image-agent', 'snative-image-diagnostics-agent'], _suite, env_file='polybench-nfi-ce') +mx_sdk_vm.register_vm_config('ce', llvm_components + ['antlr4', 'sllvmvm', 'bnative-image', 'cmp', 'lg', 'llrc', 'llrl', 'llrlf', 'llrn', 'nfi-libffi', 'nfi', 'ni', 'nil', 'pbm', 'pbi', 'sdk', 'sdkni', 'sdkc', 'sdkl', 'snative-image-agent', 'snative-image-diagnostics-agent', 'svm', 'svmt', 'svmnfi', 'svmsl', 'tfl', 'tfla', 'tflc', 'tflm'], _suite, env_file='polybench-sulong-ce') if mx.get_os() == 'windows': - mx_sdk_vm.register_vm_config('svm', ['bnative-image', 'bnative-image-configure', 'bpolyglot', 'cmp', 'gvm', 'nfi-libffi', 'nfi', 'ni', 'nil', 'nju', 'njucp', 'nic', 'poly', 'polynative', 'rgx', 'sdk', 'sdkni', 'sdkc', 'sdkl', 'snative-image-agent', 'snative-image-diagnostics-agent', 'svm', 'svmt', 'svmnfi', 'svmsl', 'svmforeign', 'tfl', 'tfla', 'tflc', 'tflm'], _suite, env_file=False) + mx_sdk_vm.register_vm_config('svm', ['bnative-image', 'bnative-image-configure', 'bpolyglot', 'cmp', 'gvm', 'nfi-libffi', 'nfi', 'ni', 'nil', 'nju', 'njucp', 'nic', 'poly', 'polynative', 'rgx', 'sdk', 'sdkni', 'sdkc', 'sdkl', 'snative-image-agent', 'snative-image-diagnostics-agent', 'svm', 'svmt', 'svmnfi', 'svmsl', 'tfl', 'tfla', 'tflc', 'tflm'], _suite, env_file=False) else: - mx_sdk_vm.register_vm_config('svm', ['bnative-image', 'bnative-image-configure', 'bpolyglot', 'cmp', 'gu', 'gvm', 'nfi-libffi', 'nfi', 'ni', 'nil', 'nju', 'njucp', 'nic', 'poly', 'polynative', 'rgx', 'sdk', 'sdkni', 'sdkc', 'sdkl', 'snative-image-agent', 'snative-image-diagnostics-agent', 'svm', 'svmt', 'svmnfi', 'svmsl', 'svml', 'svmforeign', 'tfl', 'tfla', 'tflc', 'tflm'], _suite, env_file=False) + mx_sdk_vm.register_vm_config('svm', ['bnative-image', 'bnative-image-configure', 'bpolyglot', 'cmp', 'gu', 'gvm', 'nfi-libffi', 'nfi', 'ni', 'nil', 'nju', 'njucp', 'nic', 'poly', 'polynative', 'rgx', 'sdk', 'sdkni', 'sdkc', 'sdkl', 'snative-image-agent', 'snative-image-diagnostics-agent', 'svm', 'svmt', 'svmnfi', 'svmsl', 'svml', 'tfl', 'tfla', 'tflc', 'tflm'], _suite, env_file=False) # pylint: enable=line-too-long From 4f147efeafc6687e3690a9100d6b38b762e83185 Mon Sep 17 00:00:00 2001 From: Josef Eisl Date: Wed, 6 Dec 2023 13:40:30 +0100 Subject: [PATCH 148/593] svm: reintroduce SVM_FOREIGN distribution --- compiler/mx.compiler/suite.py | 1 + sdk/mx.sdk/suite.py | 3 +- substratevm/mx.substratevm/mx_substratevm.py | 2 +- substratevm/mx.substratevm/suite.py | 43 ++++++++++++++++++-- 4 files changed, 43 insertions(+), 6 deletions(-) diff --git a/compiler/mx.compiler/suite.py b/compiler/mx.compiler/suite.py index c81103331dae..96870bee17e2 100644 --- a/compiler/mx.compiler/suite.py +++ b/compiler/mx.compiler/suite.py @@ -498,6 +498,7 @@ """* to com.oracle.graal.graal_enterprise, org.graalvm.nativeimage.pointsto, org.graalvm.nativeimage.builder, + org.graalvm.nativeimage.foreign, org.graalvm.nativeimage.llvm, com.oracle.svm.svm_enterprise, com.oracle.svm_enterprise.ml_dataset, diff --git a/sdk/mx.sdk/suite.py b/sdk/mx.sdk/suite.py index d9fbc2637fc3..a7ceded8071e 100644 --- a/sdk/mx.sdk/suite.py +++ b/sdk/mx.sdk/suite.py @@ -668,7 +668,8 @@ class UniversalDetector { com.oracle.svm.svm_enterprise, org.graalvm.extraimage.builder, org.graalvm.truffle.runtime.svm, - com.oracle.svm.enterprise.truffle""", + com.oracle.svm.enterprise.truffle, + org.graalvm.nativeimage.foreign""", "org.graalvm.nativeimage.impl.clinit to org.graalvm.nativeimage.builder", ], "uses" : [], diff --git a/substratevm/mx.substratevm/mx_substratevm.py b/substratevm/mx.substratevm/mx_substratevm.py index d026fa65b01e..0f81e6c83e62 100644 --- a/substratevm/mx.substratevm/mx_substratevm.py +++ b/substratevm/mx.substratevm/mx_substratevm.py @@ -1005,7 +1005,7 @@ def native_image_context_run(func, func_args=None, config=None, build_if_missing 'substratevm:OBJECTFILE', 'substratevm:POINTSTO', 'substratevm:NATIVE_IMAGE_BASE', - ], + ] + (['substratevm:SVM_FOREIGN'] if mx_sdk_vm.base_jdk().javaCompliance >= '22' else []), support_distributions=['substratevm:SVM_GRAALVM_SUPPORT'], stability="earlyadopter", jlink=False, diff --git a/substratevm/mx.substratevm/suite.py b/substratevm/mx.substratevm/suite.py index fa7f517de354..ff63e6e642c9 100644 --- a/substratevm/mx.substratevm/suite.py +++ b/substratevm/mx.substratevm/suite.py @@ -1420,7 +1420,6 @@ "dependencies": [ "com.oracle.svm.graal", "com.oracle.svm.hosted", - "com.oracle.svm.hosted.foreign", "com.oracle.svm.core", "com.oracle.svm.core.graal.amd64", "com.oracle.svm.core.graal.aarch64", @@ -1886,9 +1885,9 @@ "name" : "org.graalvm.nativeimage.base", "requires" : ["java.sql", "java.xml"],# workaround for GR-47773 on the module-path which requires java.sql (like truffle) or java.xml "exports" : [ - "com.oracle.svm.util to org.graalvm.nativeimage.pointsto,org.graalvm.nativeimage.builder,org.graalvm.nativeimage.librarysupport,org.graalvm.nativeimage.driver,org.graalvm.nativeimage.llvm,org.graalvm.nativeimage.agent.jvmtibase,org.graalvm.nativeimage.agent.tracing,org.graalvm.nativeimage.agent.diagnostics,org.graalvm.nativeimage.junitsupport,com.oracle.svm.svm_enterprise,com.oracle.svm_enterprise.ml_dataset,org.graalvm.extraimage.builder,com.oracle.svm.extraimage_enterprise,org.graalvm.extraimage.librarysupport,org.graalvm.truffle.runtime.svm,com.oracle.truffle.enterprise.svm", - "com.oracle.svm.common.meta to org.graalvm.nativeimage.pointsto,org.graalvm.nativeimage.builder,org.graalvm.nativeimage.llvm,org.graalvm.extraimage.builder,org.graalvm.truffle.runtime.svm,com.oracle.truffle.enterprise.svm", - "com.oracle.svm.common.option to org.graalvm.nativeimage.pointsto,org.graalvm.nativeimage.builder,org.graalvm.nativeimage.driver,org.graalvm.truffle.runtime.svm,com.oracle.truffle.enterprise.svm", + "com.oracle.svm.util to org.graalvm.nativeimage.pointsto,org.graalvm.nativeimage.builder,org.graalvm.nativeimage.librarysupport,org.graalvm.nativeimage.driver,org.graalvm.nativeimage.llvm,org.graalvm.nativeimage.agent.jvmtibase,org.graalvm.nativeimage.agent.tracing,org.graalvm.nativeimage.agent.diagnostics,org.graalvm.nativeimage.junitsupport,com.oracle.svm.svm_enterprise,com.oracle.svm_enterprise.ml_dataset,org.graalvm.extraimage.builder,com.oracle.svm.extraimage_enterprise,org.graalvm.extraimage.librarysupport,org.graalvm.nativeimage.foreign,org.graalvm.truffle.runtime.svm,com.oracle.truffle.enterprise.svm", + "com.oracle.svm.common.meta to org.graalvm.nativeimage.pointsto,org.graalvm.nativeimage.builder,org.graalvm.nativeimage.llvm,org.graalvm.extraimage.builder,org.graalvm.nativeimage.foreign,org.graalvm.truffle.runtime.svm,com.oracle.truffle.enterprise.svm", + "com.oracle.svm.common.option to org.graalvm.nativeimage.pointsto,org.graalvm.nativeimage.builder,org.graalvm.nativeimage.driver,org.graalvm.nativeimage.foreign,org.graalvm.truffle.runtime.svm,com.oracle.truffle.enterprise.svm", ], }, "noMavenJavadoc": True, @@ -2161,6 +2160,42 @@ }, }, + "SVM_FOREIGN": { + "subDir": "src", + "description" : "SubstrateVM support for the Foreign API", + "dependencies": [ + "com.oracle.svm.hosted.foreign", + ], + "distDependencies": [ + "compiler:GRAAL", + "SVM" + ], + "moduleInfo" : { + "name" : "org.graalvm.nativeimage.foreign", + "requires" : [ + "org.graalvm.nativeimage.builder" + ], + "exports" : [ + "* to org.graalvm.nativeimage.builder" + ], + "requiresConcealed": { + "jdk.internal.vm.ci" : [ + "jdk.vm.ci.meta", + "jdk.vm.ci.code", + "jdk.vm.ci.amd64", + ], + "java.base": [ + "jdk.internal.foreign", + "jdk.internal.foreign.abi", + "jdk.internal.foreign.abi.x64", + "jdk.internal.foreign.abi.x64.sysv", + "jdk.internal.foreign.abi.x64.windows", + ], + }, + }, + "maven" : False, + }, + "SVM_LLVM" : { "subDir" : "src", "description" : "LLVM backend for Native Image", From 4ae0ab02d2ddf76aa9e66d8dc7ea40ca5e710f8d Mon Sep 17 00:00:00 2001 From: ol-automation_ww Date: Thu, 7 Dec 2023 20:46:55 +0000 Subject: [PATCH 149/593] [GR-5369] Periodic update of the Graal import. PullRequest: fastr/2871 --- vm/mx.vm/suite.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vm/mx.vm/suite.py b/vm/mx.vm/suite.py index 7581a192e3f2..e2e62577e788 100644 --- a/vm/mx.vm/suite.py +++ b/vm/mx.vm/suite.py @@ -57,7 +57,7 @@ }, { "name": "fastr", - "version": "b2a89213702af91dc6f84994a2affda90aaceafe", + "version": "e67d35460eb33d47cfe1a2d535b64524eacfed81", "dynamic": True, "urls": [ {"url": "https://github.com/oracle/fastr.git", "kind": "git"}, From 43edeb9598ea6aa3764239f14a48474018c6364b Mon Sep 17 00:00:00 2001 From: Codrut Stancu Date: Thu, 7 Dec 2023 23:17:55 +0100 Subject: [PATCH 150/593] Preserve the cause for `UserException`. --- .../src/com/oracle/svm/core/util/UserError.java | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/util/UserError.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/util/UserError.java index b4608f9ed03f..5b66261674e1 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/util/UserError.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/util/UserError.java @@ -57,6 +57,15 @@ protected UserException(Iterable messages) { this.messages = messages; } + public UserException(String msg, Throwable throwable) { + this(Collections.singletonList(msg), throwable); + } + + protected UserException(Iterable messages, Throwable throwable) { + super(String.join(System.lineSeparator(), messages), throwable); + this.messages = messages; + } + public Iterable getMessages() { return messages; } From 9dcd6b7f0e016cd0afc9f83c293fef2a5cdb9a65 Mon Sep 17 00:00:00 2001 From: Codrut Stancu Date: Thu, 7 Dec 2023 23:44:26 +0100 Subject: [PATCH 151/593] Revert "Avoid using record for Resources.includePatterns." This reverts commit 8a22812b2078338c1365beee04929bd050228c10. --- .../src/com/oracle/svm/core/jdk/Resources.java | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/Resources.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/Resources.java index 6cd1121717d9..60ac9ec96d0a 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/Resources.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/Resources.java @@ -88,7 +88,10 @@ public static Resources singleton() { * com.oracle.svm.hosted.ModuleLayerFeature}. */ private final EconomicMap, ResourceStorageEntryBase> resources = ImageHeapMap.create(); - private final EconomicMap, Boolean> includePatterns = ImageHeapMap.create(); + private final EconomicMap includePatterns = ImageHeapMap.create(); + + public record ModuleResourcePair(String module, String resource) { + } /** * The object used to mark a resource as reachable according to the metadata. It can be obtained @@ -256,7 +259,7 @@ public void registerIncludePattern(String module, String pattern) { assert MissingRegistrationUtils.throwMissingRegistrationErrors(); synchronized (includePatterns) { updateTimeStamp(); - includePatterns.put(Pair.create(module, handleEscapedCharacters(pattern)), Boolean.TRUE); + includePatterns.put(new ModuleResourcePair(module, handleEscapedCharacters(pattern)), Boolean.TRUE); } } @@ -315,11 +318,11 @@ public ResourceStorageEntryBase get(Module module, String resourceName, boolean ResourceStorageEntryBase entry = resources.get(createStorageKey(module, canonicalResourceName)); if (entry == null) { if (MissingRegistrationUtils.throwMissingRegistrationErrors()) { - MapCursor, Boolean> cursor = includePatterns.getEntries(); + MapCursor cursor = includePatterns.getEntries(); while (cursor.advance()) { - Pair moduleResourcePair = cursor.getKey(); - if (Objects.equals(moduleName, moduleResourcePair.getLeft()) && - (matchResource(moduleResourcePair.getRight(), resourceName) || matchResource(moduleResourcePair.getRight(), canonicalResourceName))) { + ModuleResourcePair moduleResourcePair = cursor.getKey(); + if (Objects.equals(moduleName, moduleResourcePair.module) && + (matchResource(moduleResourcePair.resource, resourceName) || matchResource(moduleResourcePair.resource, canonicalResourceName))) { return null; } } From c4e157ca314c6caaccf908b80424747399f18c1c Mon Sep 17 00:00:00 2001 From: Christian Wimmer Date: Tue, 5 Dec 2023 07:41:42 -0800 Subject: [PATCH 152/593] Improve typing of GraphProvider and signatures --- .../graal/compiler/java/BytecodeParser.java | 2 +- .../compiler/java/FrameStateBuilder.java | 14 +- .../replacements/IntrinsicGraphBuilder.java | 2 +- .../graal/pointsto/PointsToAnalysis.java | 9 +- .../pointsto/flow/MethodTypeFlowBuilder.java | 24 ++- .../infrastructure/GraphProvider.java | 4 +- .../infrastructure/ResolvedSignature.java | 10 + .../graal/pointsto/meta/AnalysisMethod.java | 39 ++-- .../graal/pointsto/meta/AnalysisType.java | 4 +- .../pointsto/meta/PointsToAnalysisMethod.java | 4 +- .../InlineBeforeAnalysisGraphDecoder.java | 30 +-- ...nlineBeforeAnalysisInlineInvokePlugin.java | 6 +- .../phases/InlineBeforeAnalysisPolicy.java | 29 ++- .../pointsto/reports/CallTreePrinter.java | 20 +- .../DirectMethodProcessingHandler.java | 16 +- .../SimpleInMemoryMethodSummaryProvider.java | 20 +- .../graal/replacements/SubstrateGraphKit.java | 32 +--- .../hosted/GraalGraphObjectReplacer.java | 12 +- .../ParseOnceRuntimeCompilationFeature.java | 12 +- .../svm/hosted/foreign/DowncallStub.java | 22 +-- .../hosted/cenum/CEnumCallWrapperMethod.java | 16 +- .../SimulateClassInitializerPolicy.java | 14 +- .../svm/hosted/code/CCallStubMethod.java | 58 +++--- .../code/CEntryPointCallStubMethod.java | 180 +++++++++--------- .../code/CEntryPointJavaCallStubMethod.java | 9 +- .../hosted/code/CFunctionCallStubMethod.java | 28 ++- .../code/CFunctionPointerCallStubMethod.java | 25 ++- .../oracle/svm/hosted/code/CompileQueue.java | 20 -- .../oracle/svm/hosted/code/FactoryMethod.java | 15 +- .../svm/hosted/code/FactoryMethodSupport.java | 6 +- ...IncompatibleClassChangeFallbackMethod.java | 5 +- .../svm/hosted/code/SimpleSignature.java | 124 ------------ .../heap/PodFactorySubstitutionMethod.java | 47 ++--- .../oracle/svm/hosted/image/NativeImage.java | 10 +- .../hosted/image/NativeImageCodeCache.java | 11 +- .../NativeImageDebugInfoProviderBase.java | 20 +- .../svm/hosted/jni/JNIAccessFeature.java | 12 +- .../hosted/jni/JNICallTrampolineMethod.java | 3 +- .../hosted/jni/JNIFieldAccessorMethod.java | 21 +- .../oracle/svm/hosted/jni/JNIGraphKit.java | 17 ++ .../jni/JNIJavaCallVariantWrapperMethod.java | 31 +-- .../hosted/jni/JNIJavaCallWrapperMethod.java | 70 ++++--- .../jni/JNINativeCallWrapperMethod.java | 42 ++-- .../jni/JNIPrimitiveArrayOperationMethod.java | 26 +-- .../oracle/svm/hosted/meta/HostedMethod.java | 29 +-- .../svm/hosted/meta/HostedUniverse.java | 8 +- .../svm/hosted/meta/UniverseBuilder.java | 3 +- .../svm/hosted/phases/CInterfaceEnumTool.java | 37 ++-- .../phases/CInterfaceInvocationPlugin.java | 42 ++-- .../phases/InjectedAccessorsPlugin.java | 45 ++--- .../InlineBeforeAnalysisPolicyImpl.java | 12 +- .../InlineBeforeAnalysisPolicyUtils.java | 63 +++--- .../ReflectionExpandSignatureMethod.java | 63 +++--- .../ReflectionMetadataEncoderImpl.java | 6 +- .../hosted/substitute/AnnotatedMethod.java | 15 +- .../svm/hosted/substitute/DeletedMethod.java | 22 +-- .../PolymorphicSignatureWrapperMethod.java | 20 +- .../hosted/substitute/SubstitutionMethod.java | 16 +- 58 files changed, 645 insertions(+), 857 deletions(-) delete mode 100644 substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/code/SimpleSignature.java diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/java/BytecodeParser.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/java/BytecodeParser.java index 770d22fc45fb..028745acca5d 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/java/BytecodeParser.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/java/BytecodeParser.java @@ -1022,7 +1022,7 @@ public FixedWithNextNode getBeforeUnwindNode() { @SuppressWarnings("try") protected void buildRootMethod() { FrameStateBuilder startFrameState = new FrameStateBuilder(this, code, graph, graphBuilderConfig.retainLocalVariables()); - startFrameState.initializeForMethodStart(graph.getAssumptions(), graphBuilderConfig.eagerResolving() || intrinsicContext != null, graphBuilderConfig.getPlugins()); + startFrameState.initializeForMethodStart(graph.getAssumptions(), graphBuilderConfig.eagerResolving() || intrinsicContext != null, graphBuilderConfig.getPlugins(), null); try (IntrinsicScope s = intrinsicContext != null ? new IntrinsicScope(this) : null) { build(graph.start(), startFrameState); diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/java/FrameStateBuilder.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/java/FrameStateBuilder.java index 2938fd9bde84..3e4ed0d8ca71 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/java/FrameStateBuilder.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/java/FrameStateBuilder.java @@ -207,7 +207,7 @@ public void initializeFromArgumentsArray(ValueNode[] arguments) { } } - public void initializeForMethodStart(Assumptions assumptions, boolean eagerResolve, Plugins plugins) { + public void initializeForMethodStart(Assumptions assumptions, boolean eagerResolve, Plugins plugins, List collectParameterNodes) { int javaIndex = 0; int index = 0; @@ -236,7 +236,11 @@ public void initializeForMethodStart(Assumptions assumptions, boolean eagerResol receiver = new ParameterNode(javaIndex, receiverStamp); } - locals[javaIndex] = graph.addOrUniqueWithInputs(receiver); + receiver = graph.addOrUniqueWithInputs(receiver); + locals[javaIndex] = receiver; + if (collectParameterNodes != null) { + collectParameterNodes.add(receiver); + } javaIndex = 1; index = 1; } @@ -275,7 +279,11 @@ public void initializeForMethodStart(Assumptions assumptions, boolean eagerResol param = new ParameterNode(index, stamp); } - locals[javaIndex] = graph.addOrUniqueWithInputs(param); + param = graph.addOrUniqueWithInputs(param); + locals[javaIndex] = param; + if (collectParameterNodes != null) { + collectParameterNodes.add(param); + } javaIndex++; if (kind.needsTwoSlots()) { locals[javaIndex] = TWO_SLOT_MARKER; diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/replacements/IntrinsicGraphBuilder.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/replacements/IntrinsicGraphBuilder.java index 624e328ca286..48a2c18e41bb 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/replacements/IntrinsicGraphBuilder.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/replacements/IntrinsicGraphBuilder.java @@ -93,7 +93,7 @@ public class IntrinsicGraphBuilder extends CoreProvidersDelegate implements Grap private FrameState createStateAfterStartOfReplacementGraph(ResolvedJavaMethod original, GraphBuilderConfiguration graphBuilderConfig) { FrameStateBuilder startFrameState = new FrameStateBuilder(this, code, graph, graphBuilderConfig.retainLocalVariables()); - startFrameState.initializeForMethodStart(graph.getAssumptions(), false, graphBuilderConfig.getPlugins()); + startFrameState.initializeForMethodStart(graph.getAssumptions(), false, graphBuilderConfig.getPlugins(), null); return startFrameState.createInitialIntrinsicFrameState(original); } diff --git a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/PointsToAnalysis.java b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/PointsToAnalysis.java index 4889e621ce3c..5def0656c55f 100644 --- a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/PointsToAnalysis.java +++ b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/PointsToAnalysis.java @@ -87,7 +87,6 @@ import jdk.vm.ci.meta.JavaKind; import jdk.vm.ci.meta.JavaType; import jdk.vm.ci.meta.ResolvedJavaField; -import jdk.vm.ci.meta.Signature; public abstract class PointsToAnalysis extends AbstractAnalysisEngine { /** The type of {@link java.lang.Object}. */ @@ -321,10 +320,8 @@ public AnalysisMethod addRootMethod(Executable method, boolean invokeSpecial, Ob public AnalysisMethod addRootMethod(AnalysisMethod aMethod, boolean invokeSpecial, Object reason, MultiMethod.MultiMethodKey... otherRoots) { assert !universe.sealed() : "Cannot register root methods after analysis universe is sealed."; AnalysisError.guarantee(aMethod.isOriginalMethod()); - AnalysisType declaringClass = aMethod.getDeclaringClass(); boolean isStatic = aMethod.isStatic(); - Signature signature = aMethod.getSignature(); - int paramCount = signature.getParameterCount(!isStatic); + int paramCount = aMethod.getSignature().getParameterCount(!isStatic); PointsToAnalysisMethod originalPTAMethod = assertPointsToAnalysisMethod(aMethod); if (isStatic) { @@ -339,7 +336,7 @@ public AnalysisMethod addRootMethod(AnalysisMethod aMethod, boolean invokeSpecia pointsToMethod.registerAsImplementationInvoked(reason.toString()); MethodFlowsGraphInfo flowInfo = analysisPolicy.staticRootMethodGraph(this, pointsToMethod); for (int idx = 0; idx < paramCount; idx++) { - AnalysisType declaredParamType = (AnalysisType) signature.getParameterType(idx, declaringClass); + AnalysisType declaredParamType = aMethod.getSignature().getParameterType(idx); FormalParamTypeFlow parameter = flowInfo.getParameter(idx); processParam(declaredParamType, parameter); } @@ -399,7 +396,7 @@ public AnalysisMethod addRootMethod(AnalysisMethod aMethod, boolean invokeSpecia * type below we use idx-1 but when accessing the actual parameter flow we * simply use idx. */ - AnalysisType declaredParamType = (AnalysisType) signature.getParameterType(idx - 1, declaringClass); + AnalysisType declaredParamType = aMethod.getSignature().getParameterType(idx - 1); TypeFlow actualParameterFlow = invoke.getActualParameter(idx); processParam(declaredParamType, actualParameterFlow); } diff --git a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/flow/MethodTypeFlowBuilder.java b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/flow/MethodTypeFlowBuilder.java index 931d698dcf9c..c5c67b3d951f 100644 --- a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/flow/MethodTypeFlowBuilder.java +++ b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/flow/MethodTypeFlowBuilder.java @@ -148,7 +148,6 @@ import jdk.vm.ci.meta.Constant; import jdk.vm.ci.meta.JavaConstant; import jdk.vm.ci.meta.JavaKind; -import jdk.vm.ci.meta.JavaType; import jdk.vm.ci.meta.ResolvedJavaMethod; import jdk.vm.ci.meta.VMConstant; @@ -411,7 +410,7 @@ private static void registerForeignCall(PointsToAnalysis bb, ForeignCallsProvide private boolean handleNodeIntrinsic() { if (AnnotationAccess.isAnnotationPresent(method, NodeIntrinsic.class)) { graph.getDebug().log("apply MethodTypeFlow on node intrinsic %s", method); - AnalysisType returnType = (AnalysisType) method.getSignature().getReturnType(method.getDeclaringClass()); + AnalysisType returnType = method.getSignature().getReturnType(); if (bb.isSupportedJavaKind(returnType.getJavaKind())) { /* * This is a method used in a snippet, so most likely the return value does not @@ -436,7 +435,7 @@ private boolean handleNodeIntrinsic() { private void insertAllInstantiatedTypesReturn() { AnalysisError.guarantee(flowsGraph.getReturnFlow() == null, "Expected null return flow"); - AnalysisType returnType = TypeFlow.filterUncheckedInterface((AnalysisType) method.getSignature().getReturnType(method.getDeclaringClass())); + AnalysisType returnType = TypeFlow.filterUncheckedInterface(method.getSignature().getReturnType()); AnalysisError.guarantee(returnType.getJavaKind().isObject(), "Unexpected return type: %s", returnType); BytecodePosition position = AbstractAnalysisEngine.syntheticSourcePosition(null, method); @@ -451,15 +450,14 @@ private void insertAllInstantiatedTypesReturn() { * Placeholder flows are placed in the graph for any missing flows. */ private void insertPlaceholderParamAndReturnFlows() { - boolean isStatic = Modifier.isStatic(method.getModifiers()); - JavaType[] paramTypes = method.getSignature().toParameterTypes(isStatic ? null : method.getDeclaringClass()); + var paramTypes = method.toParameterList(); BytecodePosition position = AbstractAnalysisEngine.syntheticSourcePosition(null, method); - for (int index = 0; index < paramTypes.length; index++) { + for (int index = 0; index < paramTypes.size(); index++) { if (flowsGraph.getParameter(index) == null) { - if (bb.isSupportedJavaKind(paramTypes[index].getJavaKind())) { - AnalysisType paramType = (AnalysisType) paramTypes[index]; + if (bb.isSupportedJavaKind(paramTypes.get(index).getJavaKind())) { + AnalysisType paramType = paramTypes.get(index); FormalParamTypeFlow parameter; - if (!isStatic && index == 0) { + if (index == 0 && !method.isStatic()) { assert paramType.equals(method.getDeclaringClass()) : paramType + ", " + method; parameter = new FormalReceiverTypeFlow(position, paramType); } else { @@ -471,7 +469,7 @@ private void insertPlaceholderParamAndReturnFlows() { } if (flowsGraph.getReturnFlow() == null) { - AnalysisType returnType = (AnalysisType) method.getSignature().getReturnType(method.getDeclaringClass()); + AnalysisType returnType = method.getSignature().getReturnType(); if (bb.isSupportedJavaKind(returnType.getJavaKind())) { flowsGraph.setReturnFlow(new FormalReturnTypeFlow(position, returnType)); } @@ -501,7 +499,7 @@ private void createTypeFlow() { parameter = new FormalReceiverTypeFlow(AbstractAnalysisEngine.sourcePosition(node), paramType); } else { int offset = isStatic ? 0 : 1; - AnalysisType paramType = (AnalysisType) method.getSignature().getParameterType(index - offset, method.getDeclaringClass()); + AnalysisType paramType = method.getSignature().getParameterType(index - offset); parameter = new FormalParamTypeFlow(AbstractAnalysisEngine.sourcePosition(node), paramType, index); } flowsGraph.setParameter(index, parameter); @@ -772,7 +770,7 @@ class NodeIterator extends PostOrderNodeIterator { */ private TypeFlowBuilder uniqueReturnFlowBuilder(ReturnNode node) { if (returnBuilder == null) { - AnalysisType returnType = (AnalysisType) method.getSignature().getReturnType(method.getDeclaringClass()); + AnalysisType returnType = method.getSignature().getReturnType(); if (bb.isSupportedJavaKind(returnType.getJavaKind())) { returnBuilder = TypeFlowBuilder.create(bb, node, FormalReturnTypeFlow.class, () -> { FormalReturnTypeFlow returnFlow = flowsGraph.getReturnFlow(); @@ -1538,7 +1536,7 @@ protected void processMethodInvocation(TypeFlowsOfNodes state, ValueNode invoke, if (!createDeoptInvokeTypeFlow && bb.isSupportedJavaKind(invoke.asNode().getStackKind())) { /* Create the actual return builder. */ - AnalysisType returnType = (AnalysisType) targetMethod.getSignature().getReturnType(null); + AnalysisType returnType = targetMethod.getSignature().getReturnType(); TypeFlowBuilder actualReturnBuilder = TypeFlowBuilder.create(bb, invoke.asNode(), ActualReturnTypeFlow.class, () -> { InvokeTypeFlow invokeFlow = invokeBuilder.get(); ActualReturnTypeFlow actualReturn = new ActualReturnTypeFlow(invokeFlow.source, returnType); diff --git a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/infrastructure/GraphProvider.java b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/infrastructure/GraphProvider.java index f4c3ef594311..0d8d99e9ec34 100644 --- a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/infrastructure/GraphProvider.java +++ b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/infrastructure/GraphProvider.java @@ -24,11 +24,11 @@ */ package com.oracle.graal.pointsto.infrastructure; +import com.oracle.graal.pointsto.meta.AnalysisMethod; import com.oracle.graal.pointsto.meta.HostedProviders; import jdk.graal.compiler.debug.DebugContext; import jdk.graal.compiler.nodes.StructuredGraph; -import jdk.vm.ci.meta.ResolvedJavaMethod; public interface GraphProvider { enum Purpose { @@ -36,7 +36,7 @@ enum Purpose { PREPARE_RUNTIME_COMPILATION, } - StructuredGraph buildGraph(DebugContext debug, ResolvedJavaMethod method, HostedProviders providers, Purpose purpose); + StructuredGraph buildGraph(DebugContext debug, AnalysisMethod method, HostedProviders providers, Purpose purpose); /** * Returns true if a graph can be provided for {@link Purpose#PREPARE_RUNTIME_COMPILATION}. Note diff --git a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/infrastructure/ResolvedSignature.java b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/infrastructure/ResolvedSignature.java index 173ef1962207..4b55a2df1a2d 100644 --- a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/infrastructure/ResolvedSignature.java +++ b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/infrastructure/ResolvedSignature.java @@ -93,6 +93,11 @@ public int getParameterCount(boolean withReceiver) { return parameterTypes.size() + (withReceiver ? 1 : 0); } + /* + * Use the version without the accessingClass when calling methods directly on + * ResolvedSignature. + */ + @Deprecated @Override public T getParameterType(int index, ResolvedJavaType accessingClass) { return getParameterType(index); @@ -102,6 +107,11 @@ public T getParameterType(int index) { return parameterTypes.get(index); } + /* + * Use the version without the accessingClass when calling methods directly on + * ResolvedSignature. + */ + @Deprecated @Override public T getReturnType(ResolvedJavaType accessingClass) { return getReturnType(); diff --git a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/meta/AnalysisMethod.java b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/meta/AnalysisMethod.java index 108cb2b118e6..d360780d45ac 100644 --- a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/meta/AnalysisMethod.java +++ b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/meta/AnalysisMethod.java @@ -72,6 +72,7 @@ import jdk.graal.compiler.nodes.graphbuilderconf.InvocationPlugin; import jdk.vm.ci.code.Architecture; import jdk.vm.ci.code.BytecodePosition; +import jdk.vm.ci.common.JVMCIError; import jdk.vm.ci.meta.Constant; import jdk.vm.ci.meta.ConstantPool; import jdk.vm.ci.meta.ExceptionHandler; @@ -221,7 +222,6 @@ protected AnalysisMethod(AnalysisUniverse universe, ResolvedJavaMethod wrapped, if (PointstoOptions.TrackAccessChain.getValue(declaringClass.universe.hostVM().options())) { startTrackInvocations(); } - registerSignatureTypes(); parsingContextMaxDepth = PointstoOptions.ParsingContextMaxDepth.getValue(declaringClass.universe.hostVM.options()); } @@ -257,22 +257,6 @@ private static String createName(ResolvedJavaMethod wrapped, MultiMethodKey mult return aName; } - /** - * Lookup the parameters and return type so that they are added to the universe even if the - * method is never linked and parsed. - */ - private void registerSignatureTypes() { - boolean isStatic = Modifier.isStatic(getModifiers()); - int parameterCount = getSignature().getParameterCount(!isStatic); - - int offset = isStatic ? 0 : 1; - for (int i = offset; i < parameterCount; i++) { - getSignature().getParameterType(i - offset, getDeclaringClass()); - } - - getSignature().getReturnType(getDeclaringClass()); - } - public String getQualifiedName() { return qualifiedName; } @@ -630,22 +614,31 @@ public String getName() { } @Override - public jdk.vm.ci.meta.Signature getSignature() { + public ResolvedSignature getSignature() { return signature; } @Override - public StructuredGraph buildGraph(DebugContext debug, ResolvedJavaMethod method, HostedProviders providers, Purpose purpose) { - if (wrapped instanceof GraphProvider) { - return ((GraphProvider) wrapped).buildGraph(debug, method, providers, purpose); + public JavaType[] toParameterTypes() { + throw JVMCIError.shouldNotReachHere("ResolvedJavaMethod.toParameterTypes returns the wrong result for constructors. Use toParameterList instead."); + } + + public List toParameterList() { + return getSignature().toParameterList(isStatic() ? null : getDeclaringClass()); + } + + @Override + public StructuredGraph buildGraph(DebugContext debug, AnalysisMethod method, HostedProviders providers, Purpose purpose) { + if (wrapped instanceof GraphProvider graphProvider) { + return graphProvider.buildGraph(debug, method, providers, purpose); } return null; } @Override public boolean allowRuntimeCompilation() { - if (wrapped instanceof GraphProvider) { - return ((GraphProvider) wrapped).allowRuntimeCompilation(); + if (wrapped instanceof GraphProvider graphProvider) { + return graphProvider.allowRuntimeCompilation(); } return true; } diff --git a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/meta/AnalysisType.java b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/meta/AnalysisType.java index 66c0cbc87dfd..d7f368549859 100644 --- a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/meta/AnalysisType.java +++ b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/meta/AnalysisType.java @@ -40,7 +40,6 @@ import java.util.function.Consumer; import java.util.function.Function; -import jdk.graal.compiler.debug.GraalError; import org.graalvm.nativeimage.hosted.Feature.DuringAnalysisAccess; import org.graalvm.word.WordBase; @@ -64,6 +63,7 @@ import com.oracle.svm.util.LogUtils; import com.oracle.svm.util.UnsafePartitionKind; +import jdk.graal.compiler.debug.GraalError; import jdk.vm.ci.code.BytecodePosition; import jdk.vm.ci.meta.Assumptions.AssumptionResult; import jdk.vm.ci.meta.JavaConstant; @@ -899,7 +899,7 @@ public final JavaKind getJavaKind() { } @Override - public final AnalysisType resolve(ResolvedJavaType accessingClass) { + public final ResolvedJavaType resolve(ResolvedJavaType accessingClass) { return this; } diff --git a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/meta/PointsToAnalysisMethod.java b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/meta/PointsToAnalysisMethod.java index d5eafbf9689e..65fb8401e5a7 100644 --- a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/meta/PointsToAnalysisMethod.java +++ b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/meta/PointsToAnalysisMethod.java @@ -195,10 +195,10 @@ private static InvokeTypeFlow createContextInsensitiveInvoke(PointsToAnalysis bb actualParameters[0] = receiverFlow; for (int i = 1; i < actualParameters.length; i++) { - actualParameters[i] = new ActualParameterTypeFlow((AnalysisType) method.getSignature().getParameterType(i - 1, null)); + actualParameters[i] = new ActualParameterTypeFlow(method.getSignature().getParameterType(i - 1)); } ActualReturnTypeFlow actualReturn = null; - AnalysisType returnType = (AnalysisType) method.getSignature().getReturnType(null); + AnalysisType returnType = method.getSignature().getReturnType(); if (bb.isSupportedJavaKind(returnType.getStorageKind())) { actualReturn = new ActualReturnTypeFlow(returnType); } diff --git a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/phases/InlineBeforeAnalysisGraphDecoder.java b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/phases/InlineBeforeAnalysisGraphDecoder.java index 17cfc981e4db..308b33edc49c 100644 --- a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/phases/InlineBeforeAnalysisGraphDecoder.java +++ b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/phases/InlineBeforeAnalysisGraphDecoder.java @@ -32,6 +32,16 @@ import java.util.concurrent.ConcurrentHashMap; import org.graalvm.collections.EconomicSet; + +import com.oracle.graal.pointsto.BigBang; +import com.oracle.graal.pointsto.flow.AnalysisParsedGraph; +import com.oracle.graal.pointsto.meta.AnalysisField; +import com.oracle.graal.pointsto.meta.AnalysisMethod; +import com.oracle.graal.pointsto.meta.HostedProviders; +import com.oracle.graal.pointsto.util.AnalysisError; +import com.oracle.graal.pointsto.util.GraalAccess; +import com.oracle.svm.util.ReflectionUtil; + import jdk.graal.compiler.bytecode.BytecodeProvider; import jdk.graal.compiler.debug.GraalError; import jdk.graal.compiler.graph.Node; @@ -59,16 +69,6 @@ import jdk.graal.compiler.replacements.PEGraphDecoder; import jdk.graal.compiler.replacements.nodes.MethodHandleWithExceptionNode; import jdk.graal.compiler.replacements.nodes.ResolvedMethodHandleCallTargetNode; - -import com.oracle.graal.pointsto.BigBang; -import com.oracle.graal.pointsto.flow.AnalysisParsedGraph; -import com.oracle.graal.pointsto.meta.AnalysisField; -import com.oracle.graal.pointsto.meta.AnalysisMethod; -import com.oracle.graal.pointsto.meta.HostedProviders; -import com.oracle.graal.pointsto.util.AnalysisError; -import com.oracle.graal.pointsto.util.GraalAccess; -import com.oracle.svm.util.ReflectionUtil; - import jdk.vm.ci.meta.JavaConstant; import jdk.vm.ci.meta.ResolvedJavaField; import jdk.vm.ci.meta.ResolvedJavaMethod; @@ -88,7 +88,7 @@ public class InlineBeforeAnalysisMethodScope extends PEMethodScope { */ private final EconomicSet encodedGraphs; - InlineBeforeAnalysisMethodScope(StructuredGraph targetGraph, PEMethodScope caller, LoopScope callerLoopScope, EncodedGraph encodedGraph, ResolvedJavaMethod method, + InlineBeforeAnalysisMethodScope(StructuredGraph targetGraph, PEMethodScope caller, LoopScope callerLoopScope, EncodedGraph encodedGraph, AnalysisMethod method, InvokeData invokeData, int inliningDepth, ValueNode[] arguments) { super(targetGraph, caller, callerLoopScope, encodedGraph, method, invokeData, inliningDepth, arguments); @@ -166,7 +166,7 @@ protected void cleanupGraph(MethodScope ms) { @Override protected PEMethodScope createMethodScope(StructuredGraph targetGraph, PEMethodScope caller, LoopScope callerLoopScope, EncodedGraph encodedGraph, ResolvedJavaMethod method, InvokeData invokeData, int inliningDepth, ValueNode[] arguments) { - return new InlineBeforeAnalysisMethodScope(targetGraph, caller, callerLoopScope, encodedGraph, method, invokeData, inliningDepth, arguments); + return new InlineBeforeAnalysisMethodScope(targetGraph, caller, callerLoopScope, encodedGraph, (AnalysisMethod) method, invokeData, inliningDepth, arguments); } @Override @@ -205,7 +205,7 @@ protected final Node canonicalizeFixedNode(MethodScope methodScope, LoopScope lo @Override protected boolean shouldOmitIntermediateMethodInStates(ResolvedJavaMethod method) { - return policy.shouldOmitIntermediateMethodInState(method); + return policy.shouldOmitIntermediateMethodInState((AnalysisMethod) method); } @SuppressWarnings("unused") @@ -312,7 +312,7 @@ protected void maybeAbortInlining(MethodScope ms, @SuppressWarnings("unused") Lo if (graph.getDebug().isLogEnabled()) { graph.getDebug().logv(" ".repeat(methodScope.inliningDepth) + " node " + node + ": " + methodScope.policyScope); } - if (!methodScope.policyScope.processNode(bb.getMetaAccess(), methodScope.method, node)) { + if (!methodScope.policyScope.processNode(bb.getMetaAccess(), (AnalysisMethod) methodScope.method, node)) { abortInlining(methodScope); } } @@ -502,6 +502,6 @@ protected InlineBeforeAnalysisMethodScope cast(MethodScope methodScope) { protected FixedWithNextNode afterMethodScopeCreation(PEMethodScope is, FixedWithNextNode predecessor) { InlineBeforeAnalysisMethodScope inlineScope = cast(is); var sourcePosition = inlineScope.invokeData.invoke.asNode().getNodeSourcePosition(); - return policy.processInvokeArgs(inlineScope.method, predecessor, inlineScope.getArguments(), sourcePosition); + return policy.processInvokeArgs((AnalysisMethod) inlineScope.method, predecessor, inlineScope.getArguments(), sourcePosition); } } diff --git a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/phases/InlineBeforeAnalysisInlineInvokePlugin.java b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/phases/InlineBeforeAnalysisInlineInvokePlugin.java index a4cbd9a2ea3b..d24fe0429d9e 100644 --- a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/phases/InlineBeforeAnalysisInlineInvokePlugin.java +++ b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/phases/InlineBeforeAnalysisInlineInvokePlugin.java @@ -24,10 +24,11 @@ */ package com.oracle.graal.pointsto.phases; +import com.oracle.graal.pointsto.meta.AnalysisMethod; + import jdk.graal.compiler.nodes.ValueNode; import jdk.graal.compiler.nodes.graphbuilderconf.GraphBuilderContext; import jdk.graal.compiler.nodes.graphbuilderconf.InlineInvokePlugin; - import jdk.vm.ci.meta.ResolvedJavaMethod; final class InlineBeforeAnalysisInlineInvokePlugin implements InlineInvokePlugin { @@ -39,7 +40,8 @@ final class InlineBeforeAnalysisInlineInvokePlugin implements InlineInvokePlugin } @Override - public InlineInfo shouldInlineInvoke(GraphBuilderContext b, ResolvedJavaMethod method, ValueNode[] args) { + public InlineInfo shouldInlineInvoke(GraphBuilderContext b, ResolvedJavaMethod m, ValueNode[] args) { + AnalysisMethod method = (AnalysisMethod) m; if (policy.shouldInlineInvoke(b, method, args)) { return policy.createInvokeInfo(method); } else { diff --git a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/phases/InlineBeforeAnalysisPolicy.java b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/phases/InlineBeforeAnalysisPolicy.java index 0f9af9a140d2..c13fad407ee2 100644 --- a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/phases/InlineBeforeAnalysisPolicy.java +++ b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/phases/InlineBeforeAnalysisPolicy.java @@ -24,6 +24,10 @@ */ package com.oracle.graal.pointsto.phases; +import com.oracle.graal.pointsto.meta.AnalysisMetaAccess; +import com.oracle.graal.pointsto.meta.AnalysisMethod; +import com.oracle.graal.pointsto.util.AnalysisError; + import jdk.graal.compiler.graph.Node; import jdk.graal.compiler.graph.NodeSourcePosition; import jdk.graal.compiler.nodes.FixedWithNextNode; @@ -32,11 +36,6 @@ import jdk.graal.compiler.nodes.graphbuilderconf.InlineInvokePlugin.InlineInfo; import jdk.graal.compiler.nodes.graphbuilderconf.NodePlugin; -import com.oracle.graal.pointsto.meta.AnalysisMetaAccess; -import com.oracle.graal.pointsto.util.AnalysisError; - -import jdk.vm.ci.meta.ResolvedJavaMethod; - /** * Provides the policy which methods are inlined by {@link InlineBeforeAnalysis}. If * {@link #shouldInlineInvoke} returns true for an invocation, the graph decoding goes into callees @@ -77,7 +76,7 @@ protected AbstractPolicyScope(int inliningDepth) { * available. But usages have not been decoded yet, so the implementation must not base any * decision on the current list of usages. The list of usages is often but not always empty. */ - public abstract boolean processNode(AnalysisMetaAccess metaAccess, ResolvedJavaMethod method, Node node); + public abstract boolean processNode(AnalysisMetaAccess metaAccess, AnalysisMethod method, Node node); } protected final NodePlugin[] nodePlugins; @@ -86,35 +85,35 @@ protected InlineBeforeAnalysisPolicy(NodePlugin[] nodePlugins) { this.nodePlugins = nodePlugins; } - protected abstract boolean shouldInlineInvoke(GraphBuilderContext b, ResolvedJavaMethod method, ValueNode[] args); + protected abstract boolean shouldInlineInvoke(GraphBuilderContext b, AnalysisMethod method, ValueNode[] args); - protected abstract InlineInfo createInvokeInfo(ResolvedJavaMethod method); + protected abstract InlineInfo createInvokeInfo(AnalysisMethod method); protected abstract boolean needsExplicitExceptions(); protected abstract boolean tryInvocationPlugins(); - protected abstract FixedWithNextNode processInvokeArgs(ResolvedJavaMethod targetMethod, FixedWithNextNode insertionPoint, ValueNode[] arguments, NodeSourcePosition sourcePosition); + protected abstract FixedWithNextNode processInvokeArgs(AnalysisMethod targetMethod, FixedWithNextNode insertionPoint, ValueNode[] arguments, NodeSourcePosition sourcePosition); protected abstract AbstractPolicyScope createRootScope(); protected abstract AbstractPolicyScope openCalleeScope(AbstractPolicyScope outer, AnalysisMetaAccess metaAccess, - ResolvedJavaMethod method, boolean[] constArgsWithReceiver, boolean intrinsifiedMethodHandle); + AnalysisMethod method, boolean[] constArgsWithReceiver, boolean intrinsifiedMethodHandle); /** @see InlineBeforeAnalysisGraphDecoder#shouldOmitIntermediateMethodInStates */ - protected boolean shouldOmitIntermediateMethodInState(ResolvedJavaMethod method) { + protected boolean shouldOmitIntermediateMethodInState(AnalysisMethod method) { return false; } public static final InlineBeforeAnalysisPolicy NO_INLINING = new InlineBeforeAnalysisPolicy(new NodePlugin[0]) { @Override - protected boolean shouldInlineInvoke(GraphBuilderContext b, ResolvedJavaMethod method, ValueNode[] args) { + protected boolean shouldInlineInvoke(GraphBuilderContext b, AnalysisMethod method, ValueNode[] args) { return false; } @Override - protected InlineInfo createInvokeInfo(ResolvedJavaMethod method) { + protected InlineInfo createInvokeInfo(AnalysisMethod method) { throw AnalysisError.shouldNotReachHere("NO_INLINING policy should not try to inline"); } @@ -133,7 +132,7 @@ protected boolean tryInvocationPlugins() { } @Override - protected FixedWithNextNode processInvokeArgs(ResolvedJavaMethod targetMethod, FixedWithNextNode insertionPoint, ValueNode[] arguments, NodeSourcePosition sourcePosition) { + protected FixedWithNextNode processInvokeArgs(AnalysisMethod targetMethod, FixedWithNextNode insertionPoint, ValueNode[] arguments, NodeSourcePosition sourcePosition) { throw AnalysisError.shouldNotReachHere("NO_INLINING policy should not try to inline"); } @@ -145,7 +144,7 @@ protected AbstractPolicyScope createRootScope() { @Override protected AbstractPolicyScope openCalleeScope(AbstractPolicyScope outer, AnalysisMetaAccess metaAccess, - ResolvedJavaMethod method, boolean[] constArgsWithReceiver, boolean intrinsifiedMethodHandle) { + AnalysisMethod method, boolean[] constArgsWithReceiver, boolean intrinsifiedMethodHandle) { throw AnalysisError.shouldNotReachHere("NO_INLINING policy should not try to inline"); } }; diff --git a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/reports/CallTreePrinter.java b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/reports/CallTreePrinter.java index 74a1a0cedf72..d1e53852971f 100644 --- a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/reports/CallTreePrinter.java +++ b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/reports/CallTreePrinter.java @@ -57,17 +57,15 @@ import java.util.stream.Collectors; import java.util.stream.Stream; -import jdk.graal.compiler.java.LambdaUtils; - import com.oracle.graal.pointsto.BigBang; import com.oracle.graal.pointsto.meta.AnalysisMethod; +import com.oracle.graal.pointsto.meta.AnalysisType; import com.oracle.graal.pointsto.meta.InvokeInfo; import com.oracle.graal.pointsto.util.AnalysisError; +import jdk.graal.compiler.java.LambdaUtils; import jdk.vm.ci.code.BytecodePosition; import jdk.vm.ci.meta.JavaKind; -import jdk.vm.ci.meta.ResolvedJavaMethod; -import jdk.vm.ci.meta.ResolvedJavaType; public final class CallTreePrinter { @@ -315,7 +313,7 @@ private static void printCallTreeNode(PrintWriter out, String prefix, MethodNode private void printUsedMethods(PrintWriter out) { List methodsList = new ArrayList<>(); - for (ResolvedJavaMethod method : methodToNode.keySet()) { + for (AnalysisMethod method : methodToNode.keySet()) { methodsList.add(method.format("%H.%n(%p):%r")); } methodsList.sort(null); @@ -334,7 +332,7 @@ private void printClasses(PrintWriter out, boolean packageNameOnly) { public Set classesSet(boolean packageNameOnly) { Set classSet = new HashSet<>(); - for (ResolvedJavaMethod method : methodToNode.keySet()) { + for (AnalysisMethod method : methodToNode.keySet()) { String name = method.getDeclaringClass().toJavaName(true); if (packageNameOnly) { name = packagePrefix(name); @@ -536,7 +534,7 @@ private static List virtualMethodInfo(AnalysisMethod method) { return resolvedJavaMethodInfo(null, method); } - private static List resolvedJavaMethodInfo(Integer id, ResolvedJavaMethod method) { + private static List resolvedJavaMethodInfo(Integer id, AnalysisMethod method) { // TODO method parameter types are opaque, but could in the future be split out and link // together // e.g. each method could BELONG to a type, and a method could have PARAMETER relationships @@ -552,13 +550,13 @@ private static List resolvedJavaMethodInfo(Integer id, ResolvedJavaMetho method.getName(), method.getDeclaringClass().toJavaName(true), parameters, - method.getSignature().getReturnType(null).toJavaName(true), + method.getSignature().getReturnType().toJavaName(true), display(method), flags(method)); } - private static String display(ResolvedJavaMethod method) { - final ResolvedJavaType type = method.getDeclaringClass(); + private static String display(AnalysisMethod method) { + final AnalysisType type = method.getDeclaringClass(); final String typeName = type.toJavaName(true); if (type.getJavaKind() == JavaKind.Object) { List matchResults = new ArrayList<>(); @@ -573,7 +571,7 @@ private static String display(ResolvedJavaMethod method) { return typeName + "." + method.getName(); } - private static String flags(ResolvedJavaMethod method) { + private static String flags(AnalysisMethod method) { StringBuilder sb = new StringBuilder(); if (method.isPublic()) { sb.append('p'); diff --git a/substratevm/src/com.oracle.graal.reachability/src/com/oracle/graal/reachability/DirectMethodProcessingHandler.java b/substratevm/src/com.oracle.graal.reachability/src/com/oracle/graal/reachability/DirectMethodProcessingHandler.java index e168faffdea1..149d33ca0267 100644 --- a/substratevm/src/com.oracle.graal.reachability/src/com/oracle/graal/reachability/DirectMethodProcessingHandler.java +++ b/substratevm/src/com.oracle.graal.reachability/src/com/oracle/graal/reachability/DirectMethodProcessingHandler.java @@ -27,6 +27,12 @@ import java.lang.reflect.Modifier; import java.util.Optional; +import org.graalvm.nativeimage.AnnotationAccess; + +import com.oracle.graal.pointsto.AbstractAnalysisEngine; +import com.oracle.graal.pointsto.meta.AnalysisMethod; +import com.oracle.svm.common.meta.MultiMethod; + import jdk.graal.compiler.core.common.spi.ForeignCallDescriptor; import jdk.graal.compiler.core.common.spi.ForeignCallSignature; import jdk.graal.compiler.core.common.spi.ForeignCallsProvider; @@ -48,12 +54,6 @@ import jdk.graal.compiler.replacements.nodes.BinaryMathIntrinsicNode; import jdk.graal.compiler.replacements.nodes.MacroInvokable; import jdk.graal.compiler.replacements.nodes.UnaryMathIntrinsicNode; -import org.graalvm.nativeimage.AnnotationAccess; - -import com.oracle.graal.pointsto.AbstractAnalysisEngine; -import com.oracle.graal.pointsto.meta.AnalysisMethod; -import com.oracle.svm.common.meta.MultiMethod; - import jdk.vm.ci.code.BytecodePosition; import jdk.vm.ci.meta.JavaConstant; import jdk.vm.ci.meta.ResolvedJavaMethod; @@ -82,11 +82,11 @@ private static void analyzeStructuredGraph(ReachabilityAnalysisEngine bb, Reacha int parameterCount = method.getSignature().getParameterCount(!isStatic); int offset = isStatic ? 0 : 1; for (int i = offset; i < parameterCount; i++) { - bb.registerTypeAsReachable((ReachabilityAnalysisType) method.getSignature().getParameterType(i - offset, method.getDeclaringClass()), + bb.registerTypeAsReachable(method.getSignature().getParameterType(i - offset), "Parameter type for " + method.format("%H.%n(%p)")); } - bb.registerTypeAsReachable((ReachabilityAnalysisType) method.getSignature().getReturnType(method.getDeclaringClass()), "Return type for " + method.format("%H.%n(%p)")); + bb.registerTypeAsReachable(method.getSignature().getReturnType(), "Return type for " + method.format("%H.%n(%p)")); } for (Node n : graph.getNodes()) { diff --git a/substratevm/src/com.oracle.graal.reachability/src/com/oracle/graal/reachability/SimpleInMemoryMethodSummaryProvider.java b/substratevm/src/com.oracle.graal.reachability/src/com/oracle/graal/reachability/SimpleInMemoryMethodSummaryProvider.java index 2009522063ea..a8797640f858 100644 --- a/substratevm/src/com.oracle.graal.reachability/src/com/oracle/graal/reachability/SimpleInMemoryMethodSummaryProvider.java +++ b/substratevm/src/com.oracle.graal.reachability/src/com/oracle/graal/reachability/SimpleInMemoryMethodSummaryProvider.java @@ -28,6 +28,14 @@ import java.util.Optional; import org.graalvm.collections.EconomicSet; +import org.graalvm.nativeimage.AnnotationAccess; + +import com.oracle.graal.pointsto.AbstractAnalysisEngine; +import com.oracle.graal.pointsto.meta.AnalysisField; +import com.oracle.graal.pointsto.meta.AnalysisMethod; +import com.oracle.graal.pointsto.meta.AnalysisType; +import com.oracle.svm.common.meta.MultiMethod; + import jdk.graal.compiler.core.common.spi.ForeignCallDescriptor; import jdk.graal.compiler.core.common.spi.ForeignCallSignature; import jdk.graal.compiler.core.common.spi.ForeignCallsProvider; @@ -49,14 +57,6 @@ import jdk.graal.compiler.replacements.nodes.BinaryMathIntrinsicNode; import jdk.graal.compiler.replacements.nodes.MacroInvokable; import jdk.graal.compiler.replacements.nodes.UnaryMathIntrinsicNode; -import org.graalvm.nativeimage.AnnotationAccess; - -import com.oracle.graal.pointsto.AbstractAnalysisEngine; -import com.oracle.graal.pointsto.meta.AnalysisField; -import com.oracle.graal.pointsto.meta.AnalysisMethod; -import com.oracle.graal.pointsto.meta.AnalysisType; -import com.oracle.svm.common.meta.MultiMethod; - import jdk.vm.ci.meta.JavaConstant; import jdk.vm.ci.meta.ResolvedJavaMethod; import jdk.vm.ci.meta.ResolvedJavaType; @@ -94,10 +94,10 @@ private static MethodSummary createSummaryFromGraph(ReachabilityAnalysisEngine b int parameterCount = method.getSignature().getParameterCount(!isStatic); int offset = isStatic ? 0 : 1; for (int i = offset; i < parameterCount; i++) { - accessedTypes.add((ReachabilityAnalysisType) method.getSignature().getParameterType(i - offset, method.getDeclaringClass())); + accessedTypes.add(method.getSignature().getParameterType(i - offset)); } - accessedTypes.add((ReachabilityAnalysisType) method.getSignature().getReturnType(method.getDeclaringClass())); + accessedTypes.add(method.getSignature().getReturnType()); } for (Node n : graph.getNodes()) { diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/graal/replacements/SubstrateGraphKit.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/graal/replacements/SubstrateGraphKit.java index 16388d5513c1..6ce0a602447c 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/graal/replacements/SubstrateGraphKit.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/graal/replacements/SubstrateGraphKit.java @@ -25,6 +25,7 @@ package com.oracle.svm.core.graal.replacements; import java.util.ArrayList; +import java.util.Collections; import java.util.List; import com.oracle.svm.core.graal.code.SubstrateCallingConventionKind; @@ -95,6 +96,7 @@ public class SubstrateGraphKit extends GraphKit { private final FrameStateBuilder frameState; private int nextBCI; + private final List arguments; @SuppressWarnings("this-escape") public SubstrateGraphKit(DebugContext debug, ResolvedJavaMethod stubMethod, Providers providers, @@ -104,7 +106,9 @@ public SubstrateGraphKit(DebugContext debug, ResolvedJavaMethod stubMethod, Prov frameState = new FrameStateBuilder(this, stubMethod, graph); frameState.disableKindVerification(); frameState.disableStateVerification(); - frameState.initializeForMethodStart(null, true, graphBuilderPlugins); + List collectedArguments = new ArrayList<>(); + frameState.initializeForMethodStart(null, true, graphBuilderPlugins, collectedArguments); + arguments = Collections.unmodifiableList(collectedArguments); graph.start().setStateAfter(frameState.create(bci(), graph.start())); } @@ -133,21 +137,7 @@ public void storeLocal(int index, JavaKind slotKind, ValueNode value) { frameState.storeLocal(index, slotKind, value); } - public List loadArguments(JavaType[] paramTypes) { - List arguments = new ArrayList<>(); - int numOfParams = paramTypes.length; - int javaIndex = 0; - - for (int i = 0; i < numOfParams; i++) { - JavaType type = paramTypes[i]; - JavaKind kind = type.getJavaKind(); - - assert frameState.loadLocal(javaIndex, kind) != null; - arguments.add(frameState.loadLocal(javaIndex, kind)); - - javaIndex += kind.getSlotCount(); - } - + public List getInitialArguments() { return arguments; } @@ -387,15 +377,9 @@ protected T appendWithUnwind(T withExceptionNode, return withExceptionNode; } - public void appendStateSplitProxy(FrameState state) { - StateSplitProxyNode proxy = new StateSplitProxyNode(); - append(proxy); - proxy.setStateAfter(state); - } - - public void appendStateSplitProxy(FrameStateBuilder stateBuilder) { + public void appendStateSplitProxy() { StateSplitProxyNode proxy = new StateSplitProxyNode(); append(proxy); - proxy.setStateAfter(stateBuilder.create(bci(), proxy)); + proxy.setStateAfter(frameState.create(bci(), proxy)); } } diff --git a/substratevm/src/com.oracle.svm.graal/src/com/oracle/svm/graal/hosted/GraalGraphObjectReplacer.java b/substratevm/src/com.oracle.svm.graal/src/com/oracle/svm/graal/hosted/GraalGraphObjectReplacer.java index a9e45602485b..cc3ed6852370 100644 --- a/substratevm/src/com.oracle.svm.graal/src/com/oracle/svm/graal/hosted/GraalGraphObjectReplacer.java +++ b/substratevm/src/com.oracle.svm.graal/src/com/oracle/svm/graal/hosted/GraalGraphObjectReplacer.java @@ -34,6 +34,7 @@ import com.oracle.graal.pointsto.constraints.UnsupportedFeatureException; import com.oracle.graal.pointsto.heap.ImageHeapConstant; +import com.oracle.graal.pointsto.infrastructure.ResolvedSignature; import com.oracle.graal.pointsto.meta.AnalysisField; import com.oracle.graal.pointsto.meta.AnalysisMethod; import com.oracle.graal.pointsto.meta.AnalysisType; @@ -88,7 +89,6 @@ import jdk.vm.ci.meta.ResolvedJavaField; import jdk.vm.ci.meta.ResolvedJavaMethod; import jdk.vm.ci.meta.ResolvedJavaType; -import jdk.vm.ci.meta.Signature; /** * Replaces Graal related objects during analysis in the universe. @@ -106,7 +106,7 @@ public static class Options { private final ConcurrentMap fields = new ConcurrentHashMap<>(); private final ConcurrentMap fieldLocationIdentities = new ConcurrentHashMap<>(); private final ConcurrentMap types = new ConcurrentHashMap<>(); - private final ConcurrentMap signatures = new ConcurrentHashMap<>(); + private final ConcurrentMap, SubstrateSignature> signatures = new ConcurrentHashMap<>(); private final SubstrateProviders sProviders; private final SubstrateUniverseFactory universeFactory; private SubstrateGraalRuntime sGraalRuntime; @@ -369,9 +369,7 @@ private SubstrateField[] createAllInstanceFields(ResolvedJavaType originalType) return sFields; } - private synchronized SubstrateSignature createSignature(Signature original) { - assert !(original instanceof SubstrateSignature) : original; - + private synchronized SubstrateSignature createSignature(ResolvedSignature original) { SubstrateSignature sSignature = signatures.get(original); if (sSignature == null) { SubstrateSignature newSignature = new SubstrateSignature(); @@ -381,13 +379,13 @@ private synchronized SubstrateSignature createSignature(Signature original) { SubstrateType[] parameterTypes = new SubstrateType[original.getParameterCount(false)]; for (int index = 0; index < original.getParameterCount(false); index++) { - parameterTypes[index] = createType(original.getParameterType(index, null)); + parameterTypes[index] = createType(original.getParameterType(index)); } /* * The links to other meta objects must be set after adding to the signatures to * avoid infinite recursion. */ - sSignature.setTypes(parameterTypes, createType(original.getReturnType(null))); + sSignature.setTypes(parameterTypes, createType(original.getReturnType())); } } return sSignature; diff --git a/substratevm/src/com.oracle.svm.graal/src/com/oracle/svm/graal/hosted/ParseOnceRuntimeCompilationFeature.java b/substratevm/src/com.oracle.svm.graal/src/com/oracle/svm/graal/hosted/ParseOnceRuntimeCompilationFeature.java index 849a5928a849..a77c64d41a88 100644 --- a/substratevm/src/com.oracle.svm.graal/src/com/oracle/svm/graal/hosted/ParseOnceRuntimeCompilationFeature.java +++ b/substratevm/src/com.oracle.svm.graal/src/com/oracle/svm/graal/hosted/ParseOnceRuntimeCompilationFeature.java @@ -1010,7 +1010,7 @@ protected boolean needsExplicitExceptions() { } @Override - protected FixedWithNextNode processInvokeArgs(ResolvedJavaMethod targetMethod, FixedWithNextNode insertionPoint, ValueNode[] arguments, NodeSourcePosition sourcePosition) { + protected FixedWithNextNode processInvokeArgs(AnalysisMethod targetMethod, FixedWithNextNode insertionPoint, ValueNode[] arguments, NodeSourcePosition sourcePosition) { StructuredGraph graph = insertionPoint.graph(); InlinedInvokeArgumentsNode newNode = graph.add(new InlinedInvokeArgumentsNode(targetMethod, arguments)); newNode.setNodeSourcePosition(sourcePosition); @@ -1019,7 +1019,7 @@ protected FixedWithNextNode processInvokeArgs(ResolvedJavaMethod targetMethod, F } @Override - protected boolean shouldInlineInvoke(GraphBuilderContext b, ResolvedJavaMethod method, ValueNode[] args) { + protected boolean shouldInlineInvoke(GraphBuilderContext b, AnalysisMethod method, ValueNode[] args) { if (inliningUtils.alwaysInlineInvoke((AnalysisMetaAccess) b.getMetaAccess(), method)) { return true; } @@ -1042,13 +1042,13 @@ protected boolean shouldInlineInvoke(GraphBuilderContext b, ResolvedJavaMethod m } @Override - protected InlineInvokePlugin.InlineInfo createInvokeInfo(ResolvedJavaMethod method) { + protected InlineInvokePlugin.InlineInfo createInvokeInfo(AnalysisMethod method) { /* * Set this graph initially to a stub. If there are no explicit calls to this method * (i.e., all calls to this method are inlined), then the method's full flow will not * need to be created. */ - AnalysisMethod runtimeMethod = ((AnalysisMethod) method).getOrCreateMultiMethod(RUNTIME_COMPILED_METHOD, (newMethod) -> ((PointsToAnalysisMethod) newMethod).getTypeFlow().setAsStubFlow()); + AnalysisMethod runtimeMethod = method.getOrCreateMultiMethod(RUNTIME_COMPILED_METHOD, (newMethod) -> ((PointsToAnalysisMethod) newMethod).getTypeFlow().setAsStubFlow()); return InlineInvokePlugin.InlineInfo.createStandardInlineInfo(runtimeMethod); } @@ -1060,7 +1060,7 @@ protected AbstractPolicyScope createRootScope() { @Override protected AbstractPolicyScope openCalleeScope(AbstractPolicyScope outer, AnalysisMetaAccess metaAccess, - ResolvedJavaMethod method, boolean[] constArgsWithReceiver, boolean intrinsifiedMethodHandle) { + AnalysisMethod method, boolean[] constArgsWithReceiver, boolean intrinsifiedMethodHandle) { if (outer instanceof AccumulativeInlineScope accOuter) { /* * once the accumulative policy is activated, then we cannot return to the trivial @@ -1072,7 +1072,7 @@ protected AbstractPolicyScope openCalleeScope(AbstractPolicyScope outer, Analysi assert outer == null || outer instanceof AlwaysInlineScope : "unexpected outer scope: " + outer; // check if trivial is possible - boolean trivialInlineAllowed = hostVM.isAnalysisTrivialMethod((AnalysisMethod) method); + boolean trivialInlineAllowed = hostVM.isAnalysisTrivialMethod(method); int inliningDepth = outer == null ? 1 : outer.inliningDepth + 1; if (trivialInlineAllowed && inliningDepth <= trivialAllowingInliningDepth) { return new AlwaysInlineScope(inliningDepth); diff --git a/substratevm/src/com.oracle.svm.hosted.foreign/src/com/oracle/svm/hosted/foreign/DowncallStub.java b/substratevm/src/com.oracle.svm.hosted.foreign/src/com/oracle/svm/hosted/foreign/DowncallStub.java index 044a42b381b5..b124ca82cde9 100644 --- a/substratevm/src/com.oracle.svm.hosted.foreign/src/com/oracle/svm/hosted/foreign/DowncallStub.java +++ b/substratevm/src/com.oracle.svm.hosted.foreign/src/com/oracle/svm/hosted/foreign/DowncallStub.java @@ -26,15 +26,12 @@ import java.util.List; -import jdk.graal.compiler.core.common.spi.ForeignCallDescriptor; -import jdk.graal.compiler.debug.DebugContext; -import jdk.graal.compiler.java.FrameStateBuilder; -import jdk.graal.compiler.nodes.StructuredGraph; -import jdk.graal.compiler.nodes.ValueNode; import org.graalvm.nativeimage.Platform; import org.graalvm.nativeimage.Platforms; import org.graalvm.nativeimage.c.function.CFunction; +import com.oracle.graal.pointsto.infrastructure.ResolvedSignature; +import com.oracle.graal.pointsto.meta.AnalysisMethod; import com.oracle.graal.pointsto.meta.HostedProviders; import com.oracle.svm.common.meta.MultiMethod; import com.oracle.svm.core.foreign.AbiUtils; @@ -48,12 +45,15 @@ import com.oracle.svm.core.graal.snippets.CFunctionSnippets; import com.oracle.svm.core.thread.VMThreads; import com.oracle.svm.hosted.code.NonBytecodeMethod; -import com.oracle.svm.hosted.code.SimpleSignature; import com.oracle.svm.util.ReflectionUtil; +import jdk.graal.compiler.core.common.spi.ForeignCallDescriptor; +import jdk.graal.compiler.debug.DebugContext; +import jdk.graal.compiler.java.FrameStateBuilder; +import jdk.graal.compiler.nodes.StructuredGraph; +import jdk.graal.compiler.nodes.ValueNode; import jdk.vm.ci.meta.JavaKind; import jdk.vm.ci.meta.MetaAccessProvider; -import jdk.vm.ci.meta.ResolvedJavaMethod; import jdk.vm.ci.meta.Signature; /** @@ -86,7 +86,7 @@ @Platforms(Platform.HOSTED_ONLY.class) class DowncallStub extends NonBytecodeMethod { public static Signature createSignature(MetaAccessProvider metaAccess) { - return SimpleSignature.fromKinds(new JavaKind[]{JavaKind.Object}, JavaKind.Object, metaAccess); + return ResolvedSignature.fromKinds(new JavaKind[]{JavaKind.Object}, JavaKind.Object, metaAccess); } private final NativeEntryPointInfo nep; @@ -106,11 +106,11 @@ public static Signature createSignature(MetaAccessProvider metaAccess) { * {@link LinkToNativeSupportImpl#linkToNative(Object...)}. */ @Override - public StructuredGraph buildGraph(DebugContext debug, ResolvedJavaMethod method, HostedProviders providers, Purpose purpose) { + public StructuredGraph buildGraph(DebugContext debug, AnalysisMethod method, HostedProviders providers, Purpose purpose) { ForeignGraphKit kit = new ForeignGraphKit(debug, providers, method, purpose); FrameStateBuilder state = kit.getFrameState(); boolean deoptimizationTarget = MultiMethod.isDeoptTarget(method); - List arguments = kit.loadArguments(getSignature().toParameterTypes(null)); + List arguments = kit.getInitialArguments(); assert arguments.size() == 1; var argumentsAndNep = kit.unpackArgumentsAndExtractNEP(arguments.get(0), nep.methodType()); @@ -139,7 +139,7 @@ public StructuredGraph buildGraph(DebugContext debug, ResolvedJavaMethod method, ValueNode returnValue = kit.createCFunctionCallWithCapture( callAddress, adapted.arguments(), - SimpleSignature.fromMethodType(adapted.callType(), kit.getMetaAccess()), + ResolvedSignature.fromMethodType(adapted.callType(), kit.getMetaAccess()), VMThreads.StatusSupport.getNewThreadStatus(transition), deoptimizationTarget, cc, diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/cenum/CEnumCallWrapperMethod.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/cenum/CEnumCallWrapperMethod.java index a7946c3648a2..2cea176fbfc5 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/cenum/CEnumCallWrapperMethod.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/cenum/CEnumCallWrapperMethod.java @@ -29,6 +29,8 @@ import org.graalvm.nativeimage.c.constant.CEnumLookup; import org.graalvm.nativeimage.c.constant.CEnumValue; +import com.oracle.graal.pointsto.meta.AnalysisMethod; +import com.oracle.graal.pointsto.meta.AnalysisType; import com.oracle.graal.pointsto.meta.HostedProviders; import com.oracle.svm.core.util.VMError; import com.oracle.svm.hosted.annotation.CustomSubstitutionMethod; @@ -72,15 +74,13 @@ public boolean isSynthetic() { } @Override - public StructuredGraph buildGraph(DebugContext debug, ResolvedJavaMethod method, HostedProviders providers, Purpose purpose) { - + public StructuredGraph buildGraph(DebugContext debug, AnalysisMethod method, HostedProviders providers, Purpose purpose) { HostedGraphKit kit = new HostedGraphKit(debug, providers, method); - StructuredGraph graph = kit.getGraph(); - ResolvedJavaType returnType = (ResolvedJavaType) method.getSignature().getReturnType(null); - ValueNode arg = kit.loadArguments(method.toParameterTypes()).get(0); + AnalysisType returnType = method.getSignature().getReturnType(); + ValueNode arg = kit.getInitialArguments().get(0); - CInterfaceEnumTool tool = new CInterfaceEnumTool(providers.getMetaAccess(), providers.getSnippetReflection()); + CInterfaceEnumTool tool = new CInterfaceEnumTool(kit.getMetaAccess(), kit.getSnippetReflection()); JavaKind pushKind = CInterfaceInvocationPlugin.pushKind(method); ValueNode returnValue; @@ -93,9 +93,9 @@ public StructuredGraph buildGraph(DebugContext debug, ResolvedJavaMethod method, EnumInfo enumInfo = (EnumInfo) nativeLibraries.findElementInfo(declaringType); ValueNode invoke = tool.createEnumValueInvoke(kit, enumInfo, returnType.getJavaKind(), arg); - ValueNode adapted = CInterfaceInvocationPlugin.adaptPrimitiveType(graph, invoke, invoke.stamp(NodeView.DEFAULT).getStackKind(), returnType.getJavaKind(), false); + ValueNode adapted = CInterfaceInvocationPlugin.adaptPrimitiveType(kit.getGraph(), invoke, invoke.stamp(NodeView.DEFAULT).getStackKind(), returnType.getJavaKind(), false); Stamp originalStamp = StampFactory.forKind(returnType.getJavaKind()); - returnValue = CInterfaceInvocationPlugin.adaptPrimitiveType(graph, adapted, returnType.getJavaKind(), originalStamp.getStackKind(), false); + returnValue = CInterfaceInvocationPlugin.adaptPrimitiveType(kit.getGraph(), adapted, returnType.getJavaKind(), originalStamp.getStackKind(), false); } else { throw VMError.shouldNotReachHereUnexpectedInput(method); // ExcludeFromJacocoGeneratedReport } diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/classinitialization/SimulateClassInitializerPolicy.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/classinitialization/SimulateClassInitializerPolicy.java index e1b48fc71639..e697a824b451 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/classinitialization/SimulateClassInitializerPolicy.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/classinitialization/SimulateClassInitializerPolicy.java @@ -24,10 +24,10 @@ */ package com.oracle.svm.hosted.classinitialization; -import jdk.graal.compiler.graph.NodeSourcePosition; import org.graalvm.nativeimage.AnnotationAccess; import com.oracle.graal.pointsto.meta.AnalysisMetaAccess; +import com.oracle.graal.pointsto.meta.AnalysisMethod; import com.oracle.graal.pointsto.phases.InlineBeforeAnalysis; import com.oracle.graal.pointsto.phases.InlineBeforeAnalysisPolicy; import com.oracle.svm.core.ParsingReason; @@ -37,12 +37,12 @@ import com.oracle.svm.hosted.phases.InlineBeforeAnalysisPolicyUtils; import jdk.graal.compiler.graph.Node; +import jdk.graal.compiler.graph.NodeSourcePosition; import jdk.graal.compiler.nodes.FixedWithNextNode; import jdk.graal.compiler.nodes.ValueNode; import jdk.graal.compiler.nodes.graphbuilderconf.GraphBuilderContext; import jdk.graal.compiler.nodes.graphbuilderconf.InlineInvokePlugin; import jdk.graal.compiler.nodes.graphbuilderconf.NodePlugin; -import jdk.vm.ci.meta.ResolvedJavaMethod; /** * This class is necessary because simulation of class initializer is based on @@ -87,7 +87,7 @@ public void abortCalleeScope(InlineBeforeAnalysisPolicy.AbstractPolicyScope call } @Override - public boolean processNode(AnalysisMetaAccess metaAccess, ResolvedJavaMethod method, Node node) { + public boolean processNode(AnalysisMetaAccess metaAccess, AnalysisMethod method, Node node) { return true; } @@ -108,7 +108,7 @@ public String toString() { } @Override - protected boolean shouldInlineInvoke(GraphBuilderContext b, ResolvedJavaMethod method, ValueNode[] args) { + protected boolean shouldInlineInvoke(GraphBuilderContext b, AnalysisMethod method, ValueNode[] args) { if (b.getDepth() > support.maxInlineDepth) { /* Safeguard against excessive inlining, for example endless recursion. */ return false; @@ -135,12 +135,12 @@ protected boolean needsExplicitExceptions() { } @Override - protected InlineInvokePlugin.InlineInfo createInvokeInfo(ResolvedJavaMethod method) { + protected InlineInvokePlugin.InlineInfo createInvokeInfo(AnalysisMethod method) { return InlineInvokePlugin.InlineInfo.createStandardInlineInfo(method); } @Override - protected FixedWithNextNode processInvokeArgs(ResolvedJavaMethod targetMethod, FixedWithNextNode insertionPoint, ValueNode[] arguments, NodeSourcePosition sourcePosition) { + protected FixedWithNextNode processInvokeArgs(AnalysisMethod targetMethod, FixedWithNextNode insertionPoint, ValueNode[] arguments, NodeSourcePosition sourcePosition) { // No action is needed return insertionPoint; } @@ -155,7 +155,7 @@ protected AbstractPolicyScope createRootScope() { @Override protected AbstractPolicyScope openCalleeScope(AbstractPolicyScope o, AnalysisMetaAccess metaAccess, - ResolvedJavaMethod method, boolean[] constArgsWithReceiver, boolean intrinsifiedMethodHandle) { + AnalysisMethod method, boolean[] constArgsWithReceiver, boolean intrinsifiedMethodHandle) { var outer = (SimulateClassInitializerInlineScope) o; return new SimulateClassInitializerInlineScope(outer.accumulativeCounters, outer.inliningDepth + 1); } diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/code/CCallStubMethod.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/code/CCallStubMethod.java index 1ae0c7087cdd..54e23a7debda 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/code/CCallStubMethod.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/code/CCallStubMethod.java @@ -24,11 +24,15 @@ */ package com.oracle.svm.hosted.code; +import java.util.ArrayList; import java.util.List; import org.graalvm.nativeimage.c.constant.CEnum; import org.graalvm.nativeimage.c.constant.CEnumLookup; +import com.oracle.graal.pointsto.infrastructure.ResolvedSignature; +import com.oracle.graal.pointsto.meta.AnalysisMethod; +import com.oracle.graal.pointsto.meta.AnalysisType; import com.oracle.graal.pointsto.meta.HostedProviders; import com.oracle.svm.common.meta.MultiMethod; import com.oracle.svm.core.util.UserError; @@ -46,10 +50,7 @@ import jdk.graal.compiler.nodes.ValueNode; import jdk.vm.ci.meta.JavaKind; import jdk.vm.ci.meta.JavaType; -import jdk.vm.ci.meta.MetaAccessProvider; import jdk.vm.ci.meta.ResolvedJavaMethod; -import jdk.vm.ci.meta.ResolvedJavaType; -import jdk.vm.ci.meta.Signature; public abstract class CCallStubMethod extends CustomSubstitutionMethod { private static final JavaKind cEnumKind = JavaKind.Int; @@ -64,47 +65,42 @@ public abstract class CCallStubMethod extends CustomSubstitutionMethod { protected abstract String getCorrespondingAnnotationName(); @Override - public StructuredGraph buildGraph(DebugContext debug, ResolvedJavaMethod method, HostedProviders providers, Purpose purpose) { + public StructuredGraph buildGraph(DebugContext debug, AnalysisMethod method, HostedProviders providers, Purpose purpose) { NativeLibraries nativeLibraries = CEntryPointCallStubSupport.singleton().getNativeLibraries(); boolean deoptimizationTarget = MultiMethod.isDeoptTarget(method); HostedGraphKit kit = new HostedGraphKit(debug, providers, method); FrameStateBuilder state = kit.getFrameState(); - List arguments = kit.loadArguments(getParameterTypesForLoad(method)); - ValueNode callAddress = createTargetAddressNode(kit, providers, arguments); - Signature signature = adaptSignatureAndConvertArguments(providers, nativeLibraries, kit, method, - method.getSignature().getReturnType(null), method.toParameterTypes(), arguments); + List arguments = new ArrayList<>(kit.getInitialArguments()); + ValueNode callAddress = createTargetAddressNode(kit, arguments); + AnalysisType[] paramTypes = method.toParameterList().toArray(AnalysisType[]::new); + var signature = adaptSignatureAndConvertArguments(nativeLibraries, kit, method, method.getSignature().getReturnType(), paramTypes, arguments); state.clearLocals(); ValueNode returnValue = kit.createCFunctionCall(callAddress, arguments, signature, newThreadStatus, deoptimizationTarget); - returnValue = adaptReturnValue(method, providers, nativeLibraries, kit, returnValue); + returnValue = adaptReturnValue(method, nativeLibraries, kit, returnValue); kit.createReturn(returnValue, signature.getReturnKind()); return kit.finalizeGraph(); } - protected abstract ValueNode createTargetAddressNode(HostedGraphKit kit, HostedProviders providers, List arguments); + protected abstract ValueNode createTargetAddressNode(HostedGraphKit kit, List arguments); - protected static boolean isPrimitiveOrWord(HostedProviders providers, JavaType type) { - return type.getJavaKind().isPrimitive() || providers.getWordTypes().isWord(type); + protected static boolean isPrimitiveOrWord(HostedGraphKit kit, JavaType type) { + return type.getJavaKind().isPrimitive() || kit.getWordTypes().isWord(type); } - protected JavaType[] getParameterTypesForLoad(ResolvedJavaMethod method) { - return method.getSignature().toParameterTypes(/* exclude receiver parameter */ null); - } - - protected Signature adaptSignatureAndConvertArguments(HostedProviders providers, NativeLibraries nativeLibraries, - HostedGraphKit kit, @SuppressWarnings("unused") ResolvedJavaMethod method, JavaType returnType, JavaType[] parameterTypes, List arguments) { + protected ResolvedSignature adaptSignatureAndConvertArguments(NativeLibraries nativeLibraries, + HostedGraphKit kit, @SuppressWarnings("unused") AnalysisMethod method, AnalysisType returnType, AnalysisType[] parameterTypes, List arguments) { - MetaAccessProvider metaAccess = providers.getMetaAccess(); for (int i = 0; i < parameterTypes.length; i++) { - if (!isPrimitiveOrWord(providers, parameterTypes[i])) { - ElementInfo typeInfo = nativeLibraries.findElementInfo((ResolvedJavaType) parameterTypes[i]); + if (!isPrimitiveOrWord(kit, parameterTypes[i])) { + ElementInfo typeInfo = nativeLibraries.findElementInfo(parameterTypes[i]); if (typeInfo instanceof EnumInfo) { ValueNode argumentValue = kit.maybeCreateExplicitNullCheck(arguments.get(i)); - CInterfaceEnumTool tool = new CInterfaceEnumTool(metaAccess, providers.getSnippetReflection()); + CInterfaceEnumTool tool = new CInterfaceEnumTool(kit.getMetaAccess(), kit.getSnippetReflection()); argumentValue = tool.createEnumValueInvoke(kit, (EnumInfo) typeInfo, cEnumKind, argumentValue); arguments.set(i, argumentValue); - parameterTypes[i] = metaAccess.lookupJavaType(cEnumKind.toJavaClass()); + parameterTypes[i] = kit.getMetaAccess().lookupJavaType(cEnumKind.toJavaClass()); } else { throw UserError.abort("@%s parameter types are restricted to primitive types, word types and enumerations (@%s): %s", getCorrespondingAnnotationName(), CEnum.class.getSimpleName(), getOriginal()); @@ -112,17 +108,17 @@ protected Signature adaptSignatureAndConvertArguments(HostedProviders providers, } } /* Actual checks and conversion are in adaptReturnValue() */ - JavaType actualReturnType = isPrimitiveOrWord(providers, returnType) ? returnType : providers.getWordTypes().getWordImplType(); - return new SimpleSignature(parameterTypes, actualReturnType); + AnalysisType actualReturnType = isPrimitiveOrWord(kit, returnType) ? returnType : (AnalysisType) kit.getWordTypes().getWordImplType(); + return ResolvedSignature.fromArray(parameterTypes, actualReturnType); } - private ValueNode adaptReturnValue(ResolvedJavaMethod method, HostedProviders providers, NativeLibraries nativeLibraries, HostedGraphKit kit, ValueNode invokeValue) { + private ValueNode adaptReturnValue(AnalysisMethod method, NativeLibraries nativeLibraries, HostedGraphKit kit, ValueNode invokeValue) { ValueNode returnValue = invokeValue; - JavaType declaredReturnType = method.getSignature().getReturnType(null); - if (isPrimitiveOrWord(providers, declaredReturnType)) { + AnalysisType declaredReturnType = method.getSignature().getReturnType(); + if (isPrimitiveOrWord(kit, declaredReturnType)) { return returnValue; } - ElementInfo typeInfo = nativeLibraries.findElementInfo((ResolvedJavaType) declaredReturnType); + ElementInfo typeInfo = nativeLibraries.findElementInfo(declaredReturnType); if (typeInfo instanceof EnumInfo) { UserError.guarantee(typeInfo.getChildren().stream().anyMatch(EnumLookupInfo.class::isInstance), "Enum class %s needs a method that is annotated with @%s because it is used as the return type of a method annotated with @%s: %s", @@ -133,8 +129,8 @@ private ValueNode adaptReturnValue(ResolvedJavaMethod method, HostedProviders pr // We take a word return type because checks expect word type replacements, but it is // narrowed to cEnumKind here. - CInterfaceEnumTool tool = new CInterfaceEnumTool(providers.getMetaAccess(), providers.getSnippetReflection()); - returnValue = tool.createEnumLookupInvoke(kit, (ResolvedJavaType) declaredReturnType, (EnumInfo) typeInfo, cEnumKind, returnValue); + CInterfaceEnumTool tool = new CInterfaceEnumTool(kit.getMetaAccess(), kit.getSnippetReflection()); + returnValue = tool.createEnumLookupInvoke(kit, declaredReturnType, (EnumInfo) typeInfo, cEnumKind, returnValue); } else { throw UserError.abort("Return types of methods annotated with @%s are restricted to primitive types, word types and enumerations (@%s): %s", getCorrespondingAnnotationName(), CEnum.class.getSimpleName(), getOriginal()); diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/code/CEntryPointCallStubMethod.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/code/CEntryPointCallStubMethod.java index ef4a6ae5eee6..71065a6d71a5 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/code/CEntryPointCallStubMethod.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/code/CEntryPointCallStubMethod.java @@ -25,8 +25,9 @@ package com.oracle.svm.hosted.code; import java.lang.annotation.Annotation; -import java.util.Arrays; +import java.util.ArrayList; import java.util.Iterator; +import java.util.List; import org.graalvm.nativeimage.Isolate; import org.graalvm.nativeimage.IsolateThread; @@ -36,6 +37,7 @@ import org.graalvm.nativeimage.c.function.CEntryPoint.IsolateContext; import org.graalvm.nativeimage.c.function.CEntryPoint.IsolateThreadContext; +import com.oracle.graal.pointsto.infrastructure.ResolvedSignature; import com.oracle.graal.pointsto.meta.AnalysisMetaAccess; import com.oracle.graal.pointsto.meta.AnalysisMethod; import com.oracle.graal.pointsto.meta.AnalysisType; @@ -84,11 +86,9 @@ import jdk.vm.ci.code.BytecodeFrame; import jdk.vm.ci.meta.ConstantPool; import jdk.vm.ci.meta.JavaKind; -import jdk.vm.ci.meta.JavaType; import jdk.vm.ci.meta.MetaAccessProvider; import jdk.vm.ci.meta.ResolvedJavaMethod; import jdk.vm.ci.meta.ResolvedJavaType; -import jdk.vm.ci.meta.Signature; public final class CEntryPointCallStubMethod extends EntryPointCallStubMethod { static CEntryPointCallStubMethod create(AnalysisMethod targetMethod, CEntryPointData entryPointData, AnalysisMetaAccess aMetaAccess) { @@ -102,7 +102,7 @@ static CEntryPointCallStubMethod create(AnalysisMethod targetMethod, CEntryPoint private final CEntryPointData entryPointData; private final ResolvedJavaMethod targetMethod; - private final Signature targetSignature; + private final ResolvedSignature targetSignature; private CEntryPointCallStubMethod(CEntryPointData entryPointData, AnalysisMethod targetMethod, ResolvedJavaType holderClass, ConstantPool holderConstantPool, JavaKind wordKind, MetaAccessProvider metaAccess) { @@ -119,20 +119,18 @@ private CEntryPointCallStubMethod(CEntryPointData entryPointData, AnalysisMethod * return type is transformed into the word type. * * @see CEnum - * @see CEntryPointCallStubMethod#adaptParameterTypes(HostedProviders, NativeLibraries, - * HostedGraphKit, JavaType[], JavaType[]) - * @see CEntryPointCallStubMethod#adaptReturnValue(HostedProviders, HostedGraphKit, ValueNode) + * @see CEntryPointCallStubMethod#adaptParameterTypes + * @see CEntryPointCallStubMethod#adaptReturnValue(HostedGraphKit, ValueNode) */ - private static SimpleSignature createSignature(AnalysisMethod targetMethod, JavaKind wordKind, MetaAccessProvider metaAccess) { - JavaType[] paramTypes = Arrays.stream(targetMethod.toParameterTypes()) - .map(it -> ((AnalysisType) it)) + private static ResolvedSignature createSignature(AnalysisMethod targetMethod, JavaKind wordKind, MetaAccessProvider metaAccess) { + ResolvedJavaType[] paramTypes = targetMethod.toParameterList().stream() .map(type -> type.getAnnotation(CEnum.class) != null ? metaAccess.lookupJavaType(cEnumParameterKind.toJavaClass()) : type.getWrapped()) - .toArray(JavaType[]::new); - ResolvedJavaType returnType = ((AnalysisType) targetMethod.getSignature().getReturnType(null)).getWrapped(); + .toArray(ResolvedJavaType[]::new); + ResolvedJavaType returnType = targetMethod.getSignature().getReturnType().getWrapped(); if (returnType.getAnnotation(CEnum.class) != null) { returnType = metaAccess.lookupJavaType(wordKind.toJavaClass()); } - return new SimpleSignature(paramTypes, returnType); + return ResolvedSignature.fromArray(paramTypes, returnType); } @Override @@ -145,24 +143,23 @@ AnalysisMethod lookupTargetMethod(AnalysisMetaAccess metaAccess) { } @Override - public StructuredGraph buildGraph(DebugContext debug, ResolvedJavaMethod method, HostedProviders providers, Purpose purpose) { + public StructuredGraph buildGraph(DebugContext debug, AnalysisMethod method, HostedProviders providers, Purpose purpose) { if (entryPointData.getBuiltin() != CEntryPointData.DEFAULT_BUILTIN) { return buildBuiltinGraph(debug, method, providers); } - AnalysisMetaAccess aMetaAccess = (AnalysisMetaAccess) providers.getMetaAccess(); - NativeLibraries nativeLibraries = CEntryPointCallStubSupport.singleton().getNativeLibraries(); HostedGraphKit kit = new HostedGraphKit(debug, providers, method); + NativeLibraries nativeLibraries = CEntryPointCallStubSupport.singleton().getNativeLibraries(); - JavaType[] parameterTypes = targetSignature.toParameterTypes(null); - JavaType[] parameterLoadTypes = Arrays.copyOf(parameterTypes, parameterTypes.length); + List parameterTypes = new ArrayList<>(targetSignature.toParameterList(null)); + List parameterLoadTypes = new ArrayList<>(parameterTypes); EnumInfo[] parameterEnumInfos; - parameterEnumInfos = adaptParameterTypes(providers, nativeLibraries, kit, parameterTypes, parameterLoadTypes); + parameterEnumInfos = adaptParameterTypes(nativeLibraries, kit, parameterTypes, parameterLoadTypes); - ValueNode[] args = kit.loadArguments(parameterLoadTypes).toArray(ValueNode.EMPTY_ARRAY); + ValueNode[] args = kit.getInitialArguments().toArray(ValueNode.EMPTY_ARRAY); - InvokeWithExceptionNode invokePrologue = generatePrologue(providers, kit, parameterLoadTypes, targetMethod.getParameterAnnotations(), args); + InvokeWithExceptionNode invokePrologue = generatePrologue(kit, parameterLoadTypes, targetMethod.getParameterAnnotations(), args); if (invokePrologue != null) { ResolvedJavaMethod prologueMethod = invokePrologue.callTarget().targetMethod(); JavaKind prologueReturnKind = prologueMethod.getSignature().getReturnKind(); @@ -187,7 +184,7 @@ public StructuredGraph buildGraph(DebugContext debug, ResolvedJavaMethod method, } if (!createdReturnNode) { - ResolvedJavaMethod[] bailoutMethods = providers.getMetaAccess().lookupJavaType(bailoutCustomizer).getDeclaredMethods(false); + AnalysisMethod[] bailoutMethods = kit.getMetaAccess().lookupJavaType(bailoutCustomizer).getDeclaredMethods(false); UserError.guarantee(bailoutMethods.length == 1 && bailoutMethods[0].isStatic(), "Prologue bailout customization class must declare exactly one static method: %s -> %s", targetMethod, bailoutCustomizer); @@ -203,9 +200,9 @@ public StructuredGraph buildGraph(DebugContext debug, ResolvedJavaMethod method, } } - adaptArgumentValues(providers, kit, parameterTypes, parameterEnumInfos, args); + adaptArgumentValues(kit, parameterTypes, parameterEnumInfos, args); - AnalysisMethod aTargetMethod = aMetaAccess.getUniverse().lookup(targetMethod); + AnalysisMethod aTargetMethod = kit.getMetaAccess().getUniverse().lookup(targetMethod); kit.emitEnsureInitializedCall(aTargetMethod.getDeclaringClass()); int invokeBci = kit.bci(); @@ -221,16 +218,16 @@ public StructuredGraph buildGraph(DebugContext debug, ResolvedJavaMethod method, patchNodeSourcePosition(invoke); kit.exceptionPart(); ExceptionObjectNode exception = kit.exceptionObject(); - generateExceptionHandler(providers, kit, exception, invoke.getStackKind()); + generateExceptionHandler(kit, exception, invoke.getStackKind()); kit.endInvokeWithException(); - generateEpilogueAndReturn(providers, kit, invoke); + generateEpilogueAndReturn(kit, invoke); return kit.finalizeGraph(); } - private void generateEpilogueAndReturn(HostedProviders providers, HostedGraphKit kit, ValueNode value) { - ValueNode returnValue = adaptReturnValue(providers, kit, value); - generateEpilogue(providers, kit); + private void generateEpilogueAndReturn(HostedGraphKit kit, ValueNode value) { + ValueNode returnValue = adaptReturnValue(kit, value); + generateEpilogue(kit); kit.createReturn(returnValue, returnValue.getStackKind()); } @@ -241,9 +238,9 @@ private static void patchNodeSourcePosition(InvokeWithExceptionNode invoke) { } } - private StructuredGraph buildBuiltinGraph(DebugContext debug, ResolvedJavaMethod method, HostedProviders providers) { - AnalysisMetaAccess aMetaAccess = (AnalysisMetaAccess) providers.getMetaAccess(); - AnalysisMethod aTargetMethod = aMetaAccess.getUniverse().lookup(targetMethod); + private StructuredGraph buildBuiltinGraph(DebugContext debug, AnalysisMethod method, HostedProviders providers) { + HostedGraphKit kit = new HostedGraphKit(debug, providers, method); + AnalysisMethod aTargetMethod = kit.getMetaAccess().getUniverse().lookup(targetMethod); UserError.guarantee(entryPointData.getPrologue() == CEntryPointData.DEFAULT_PROLOGUE, "@%s method declared as built-in must not have a custom prologue: %s", CEntryPoint.class.getSimpleName(), aTargetMethod); @@ -252,13 +249,11 @@ private StructuredGraph buildBuiltinGraph(DebugContext debug, ResolvedJavaMethod UserError.guarantee(entryPointData.getExceptionHandler() == CEntryPointData.DEFAULT_EXCEPTION_HANDLER, "@%s method declared as built-in must not have a custom exception handler: %s", CEntryPoint.class.getSimpleName(), aTargetMethod); - HostedGraphKit kit = new HostedGraphKit(debug, providers, method); - - ExecutionContextParameters executionContext = findExecutionContextParameters(providers, aTargetMethod.toParameterTypes(), aTargetMethod.getParameterAnnotations()); + ExecutionContextParameters executionContext = findExecutionContextParameters(kit, aTargetMethod.toParameterList(), aTargetMethod.getParameterAnnotations()); final CEntryPoint.Builtin builtin = entryPointData.getBuiltin(); - ResolvedJavaMethod builtinCallee = null; - for (ResolvedJavaMethod candidate : aMetaAccess.lookupJavaType(CEntryPointBuiltins.class).getDeclaredMethods(false)) { + AnalysisMethod builtinCallee = null; + for (AnalysisMethod candidate : kit.getMetaAccess().lookupJavaType(CEntryPointBuiltins.class).getDeclaredMethods(false)) { CEntryPointBuiltinImplementation annotation = candidate.getAnnotation(CEntryPointBuiltinImplementation.class); if (annotation != null && annotation.builtin().equals(builtin)) { VMError.guarantee(builtinCallee == null, "More than one candidate for @%s built-in %s", CEntryPoint.class.getSimpleName(), builtin); @@ -267,13 +262,13 @@ private StructuredGraph buildBuiltinGraph(DebugContext debug, ResolvedJavaMethod } VMError.guarantee(builtinCallee != null, "No candidate for @%s built-in %s", CEntryPoint.class.getSimpleName(), builtin); - ResolvedJavaType isolateType = providers.getMetaAccess().lookupJavaType(Isolate.class); - ResolvedJavaType threadType = providers.getMetaAccess().lookupJavaType(IsolateThread.class); + AnalysisType isolateType = kit.getMetaAccess().lookupJavaType(Isolate.class); + AnalysisType threadType = kit.getMetaAccess().lookupJavaType(IsolateThread.class); int builtinIsolateIndex = -1; int builtinThreadIndex = -1; - JavaType[] builtinParamTypes = builtinCallee.toParameterTypes(); - for (int i = 0; i < builtinParamTypes.length; i++) { - ResolvedJavaType type = (ResolvedJavaType) builtinParamTypes[i]; + List builtinParamTypes = builtinCallee.toParameterList(); + for (int i = 0; i < builtinParamTypes.size(); i++) { + AnalysisType type = builtinParamTypes.get(i); if (isolateType.isAssignableFrom(type)) { VMError.guarantee(builtinIsolateIndex == -1, "@%s built-in with more than one %s parameter: %s", CEntryPoint.class.getSimpleName(), Isolate.class.getSimpleName(), builtinCallee); @@ -288,9 +283,9 @@ private StructuredGraph buildBuiltinGraph(DebugContext debug, ResolvedJavaMethod } } - ValueNode[] args = kit.loadArguments(method.toParameterTypes()).toArray(ValueNode.EMPTY_ARRAY); + ValueNode[] args = kit.getInitialArguments().toArray(ValueNode.EMPTY_ARRAY); - ValueNode[] builtinArgs = new ValueNode[builtinParamTypes.length]; + ValueNode[] builtinArgs = new ValueNode[builtinParamTypes.size()]; if (builtinIsolateIndex != -1) { VMError.guarantee(executionContext.designatedIsolateIndex != -1 || executionContext.isolateCount == 1, "@%s built-in %s needs exactly one %s parameter: %s", CEntryPoint.class.getSimpleName(), entryPointData.getBuiltin(), Isolate.class.getSimpleName(), builtinCallee); @@ -309,7 +304,7 @@ private StructuredGraph buildBuiltinGraph(DebugContext debug, ResolvedJavaMethod kit.exceptionPart(); ExceptionObjectNode exception = kit.exceptionObject(); - generateExceptionHandler(providers, kit, exception, invoke.getStackKind()); + generateExceptionHandler(kit, exception, invoke.getStackKind()); kit.endInvokeWithException(); kit.createReturn(invoke, aTargetMethod.getSignature().getReturnKind()); @@ -317,26 +312,24 @@ private StructuredGraph buildBuiltinGraph(DebugContext debug, ResolvedJavaMethod return kit.finalizeGraph(); } - private EnumInfo[] adaptParameterTypes(HostedProviders providers, NativeLibraries nativeLibraries, HostedGraphKit kit, - JavaType[] parameterTypes, JavaType[] parameterLoadTypes) { - + private EnumInfo[] adaptParameterTypes(NativeLibraries nativeLibraries, HostedGraphKit kit, List parameterTypes, List parameterLoadTypes) { EnumInfo[] parameterEnumInfos = null; - for (int i = 0; i < parameterTypes.length; i++) { - if (!parameterTypes[i].getJavaKind().isPrimitive() && !providers.getWordTypes().isWord(parameterTypes[i])) { - ElementInfo typeInfo = nativeLibraries.findElementInfo((ResolvedJavaType) parameterTypes[i]); + for (int i = 0; i < parameterTypes.size(); i++) { + if (!parameterTypes.get(i).getJavaKind().isPrimitive() && !kit.getWordTypes().isWord(parameterTypes.get(i))) { + ElementInfo typeInfo = nativeLibraries.findElementInfo(parameterTypes.get(i)); if (typeInfo instanceof EnumInfo) { UserError.guarantee(typeInfo.getChildren().stream().anyMatch(EnumLookupInfo.class::isInstance), "Enum class %s needs a method that is annotated with @%s because it is used as a parameter of an entry point method: %s", - parameterTypes[i], + parameterTypes.get(i), CEnumLookup.class.getSimpleName(), targetMethod); if (parameterEnumInfos == null) { - parameterEnumInfos = new EnumInfo[parameterTypes.length]; + parameterEnumInfos = new EnumInfo[parameterTypes.size()]; } parameterEnumInfos[i] = (EnumInfo) typeInfo; - parameterLoadTypes[i] = providers.getMetaAccess().lookupJavaType(cEnumParameterKind.toJavaClass()); + parameterLoadTypes.set(i, kit.getMetaAccess().lookupJavaType(cEnumParameterKind.toJavaClass())); final int parameterIndex = i; FrameState initialState = kit.getGraph().start().stateAfter(); @@ -346,26 +339,26 @@ private EnumInfo[] adaptParameterTypes(HostedProviders providers, NativeLibrarie parameterNode.setStamp(StampFactory.forKind(cEnumParameterKind)); } else { throw UserError.abort("Entry point method parameter types are restricted to primitive types, word types and enumerations (@%s): %s, given type was %s", - CEnum.class.getSimpleName(), targetMethod, parameterTypes[i]); + CEnum.class.getSimpleName(), targetMethod, parameterTypes.get(i)); } } } return parameterEnumInfos; } - private static void adaptArgumentValues(HostedProviders providers, HostedGraphKit kit, JavaType[] parameterTypes, EnumInfo[] parameterEnumInfos, ValueNode[] args) { + private static void adaptArgumentValues(HostedGraphKit kit, List parameterTypes, EnumInfo[] parameterEnumInfos, ValueNode[] args) { if (parameterEnumInfos != null) { // These methods must be called after the prologue established a safe context for (int i = 0; i < parameterEnumInfos.length; i++) { if (parameterEnumInfos[i] != null) { - CInterfaceEnumTool tool = new CInterfaceEnumTool(providers.getMetaAccess(), providers.getSnippetReflection()); - args[i] = tool.createEnumLookupInvoke(kit, (ResolvedJavaType) parameterTypes[i], parameterEnumInfos[i], cEnumParameterKind, args[i]); + CInterfaceEnumTool tool = new CInterfaceEnumTool(kit.getMetaAccess(), kit.getSnippetReflection()); + args[i] = tool.createEnumLookupInvoke(kit, parameterTypes.get(i), parameterEnumInfos[i], cEnumParameterKind, args[i]); } } } } - private InvokeWithExceptionNode generatePrologue(HostedProviders providers, SubstrateGraphKit kit, JavaType[] parameterTypes, Annotation[][] parameterAnnotations, ValueNode[] args) { + private InvokeWithExceptionNode generatePrologue(HostedGraphKit kit, List parameterTypes, Annotation[][] parameterAnnotations, ValueNode[] args) { Class prologueClass = entryPointData.getPrologue(); if (prologueClass == NoPrologue.class) { UserError.guarantee(Uninterruptible.Utils.isUninterruptible(targetMethod), @@ -377,20 +370,20 @@ private InvokeWithExceptionNode generatePrologue(HostedProviders providers, Subs return null; } if (prologueClass != CEntryPointOptions.AutomaticPrologue.class) { - ResolvedJavaType prologue = providers.getMetaAccess().lookupJavaType(prologueClass); - ResolvedJavaMethod[] prologueMethods = prologue.getDeclaredMethods(false); + AnalysisType prologue = kit.getMetaAccess().lookupJavaType(prologueClass); + AnalysisMethod[] prologueMethods = prologue.getDeclaredMethods(false); UserError.guarantee(prologueMethods.length == 1 && prologueMethods[0].isStatic(), "Prologue class must declare exactly one static method: %s -> %s", targetMethod, prologue); UserError.guarantee(Uninterruptible.Utils.isUninterruptible(prologueMethods[0]), "Prologue method must be annotated with @%s: %s", Uninterruptible.class.getSimpleName(), prologueMethods[0]); - ValueNode[] prologueArgs = matchPrologueParameters(providers, parameterTypes, args, prologueMethods[0]); + ValueNode[] prologueArgs = matchPrologueParameters(kit, parameterTypes, args, prologueMethods[0]); return generatePrologueOrEpilogueInvoke(kit, prologueMethods[0], prologueArgs); } // Automatically choose prologue from signature and annotations and call - ExecutionContextParameters executionContext = findExecutionContextParameters(providers, parameterTypes, parameterAnnotations); + ExecutionContextParameters executionContext = findExecutionContextParameters(kit, parameterTypes, parameterAnnotations); int contextIndex = -1; if (executionContext.designatedThreadIndex != -1) { contextIndex = executionContext.designatedThreadIndex; @@ -402,12 +395,12 @@ private InvokeWithExceptionNode generatePrologue(HostedProviders providers, Subs } ValueNode contextValue = args[contextIndex]; prologueClass = CEntryPointSetup.EnterPrologue.class; - ResolvedJavaMethod[] prologueMethods = providers.getMetaAccess().lookupJavaType(prologueClass).getDeclaredMethods(false); + AnalysisMethod[] prologueMethods = kit.getMetaAccess().lookupJavaType(prologueClass).getDeclaredMethods(false); assert prologueMethods.length == 1 && prologueMethods[0].isStatic() : "Prologue class must declare exactly one static method"; return generatePrologueOrEpilogueInvoke(kit, prologueMethods[0], contextValue); } - private static InvokeWithExceptionNode generatePrologueOrEpilogueInvoke(SubstrateGraphKit kit, ResolvedJavaMethod method, ValueNode... args) { + private static InvokeWithExceptionNode generatePrologueOrEpilogueInvoke(SubstrateGraphKit kit, AnalysisMethod method, ValueNode... args) { VMError.guarantee(Uninterruptible.Utils.isUninterruptible(method), "The method %s must be uninterruptible as it is used for a prologue or epilogue.", method); InvokeWithExceptionNode invoke = kit.startInvokeWithException(method, InvokeKind.Static, kit.getFrameState(), kit.bci(), args); kit.exceptionPart(); @@ -426,13 +419,13 @@ private static class ExecutionContextParameters { int designatedThreadIndex = -1; } - private ExecutionContextParameters findExecutionContextParameters(HostedProviders providers, JavaType[] parameterTypes, Annotation[][] parameterAnnotations) { - ResolvedJavaType isolateType = providers.getMetaAccess().lookupJavaType(Isolate.class); - ResolvedJavaType threadType = providers.getMetaAccess().lookupJavaType(IsolateThread.class); + private ExecutionContextParameters findExecutionContextParameters(HostedGraphKit kit, List parameterTypes, Annotation[][] parameterAnnotations) { + AnalysisType isolateType = kit.getMetaAccess().lookupJavaType(Isolate.class); + AnalysisType threadType = kit.getMetaAccess().lookupJavaType(IsolateThread.class); ExecutionContextParameters result = new ExecutionContextParameters(); - for (int i = 0; i < parameterTypes.length; i++) { - ResolvedJavaType declaredType = (ResolvedJavaType) parameterTypes[i]; + for (int i = 0; i < parameterTypes.size(); i++) { + AnalysisType declaredType = parameterTypes.get(i); boolean isIsolate = isolateType.isAssignableFrom(declaredType); boolean isThread = threadType.isAssignableFrom(declaredType); boolean isLong = declaredType.getJavaKind() == JavaKind.Long; @@ -486,20 +479,19 @@ private ExecutionContextParameters findExecutionContextParameters(HostedProvider return result; } - private ValueNode[] matchPrologueParameters(HostedProviders providers, JavaType[] types, ValueNode[] values, ResolvedJavaMethod prologueMethod) { - JavaType[] prologueTypes = prologueMethod.toParameterTypes(); - ValueNode[] prologueValues = new ValueNode[prologueTypes.length]; + private ValueNode[] matchPrologueParameters(HostedGraphKit kit, List types, ValueNode[] values, AnalysisMethod prologueMethod) { + ValueNode[] prologueValues = new ValueNode[prologueMethod.getSignature().getParameterCount(false)]; int i = 0; - for (int p = 0; p < prologueTypes.length; p++) { - ResolvedJavaType prologueType = (ResolvedJavaType) prologueTypes[p]; - UserError.guarantee(prologueType.isPrimitive() || providers.getWordTypes().isWord(prologueType), + for (int p = 0; p < prologueValues.length; p++) { + AnalysisType prologueType = prologueMethod.getSignature().getParameterType(p); + UserError.guarantee(prologueType.isPrimitive() || kit.getWordTypes().isWord(prologueType), "Prologue method parameter types are restricted to primitive types and word types: %s -> %s", targetMethod, prologueMethod); - while (i < types.length && !prologueType.isAssignableFrom((ResolvedJavaType) types[i])) { + while (i < types.size() && !prologueType.isAssignableFrom(types.get(i))) { i++; } - if (i >= types.length) { + if (i >= types.size()) { throw UserError.abort("Unable to match signature of entry point method to that of prologue method: %s -> %s", targetMethod, prologueMethod); @@ -510,22 +502,22 @@ private ValueNode[] matchPrologueParameters(HostedProviders providers, JavaType[ return prologueValues; } - private void generateExceptionHandler(HostedProviders providers, HostedGraphKit kit, ExceptionObjectNode exception, JavaKind returnKind) { + private void generateExceptionHandler(HostedGraphKit kit, ExceptionObjectNode exception, JavaKind returnKind) { if (entryPointData.getExceptionHandler() == CEntryPoint.FatalExceptionHandler.class) { CEntryPointLeaveNode leave = new CEntryPointLeaveNode(LeaveAction.ExceptionAbort, exception); kit.append(leave); kit.append(new LoweredDeadEndNode()); } else { - ResolvedJavaType throwable = providers.getMetaAccess().lookupJavaType(Throwable.class); - ResolvedJavaType handler = providers.getMetaAccess().lookupJavaType(entryPointData.getExceptionHandler()); - ResolvedJavaMethod[] handlerMethods = handler.getDeclaredMethods(false); + AnalysisType throwable = kit.getMetaAccess().lookupJavaType(Throwable.class); + AnalysisType handler = kit.getMetaAccess().lookupJavaType(entryPointData.getExceptionHandler()); + AnalysisMethod[] handlerMethods = handler.getDeclaredMethods(false); UserError.guarantee(handlerMethods.length == 1 && handlerMethods[0].isStatic(), "Exception handler class must declare exactly one static method: %s -> %s", targetMethod, handler); UserError.guarantee(Uninterruptible.Utils.isUninterruptible(handlerMethods[0]), "Exception handler method must be annotated with @%s: %s", Uninterruptible.class.getSimpleName(), handlerMethods[0]); - JavaType[] handlerParameterTypes = handlerMethods[0].toParameterTypes(); - UserError.guarantee(handlerParameterTypes.length == 1 && - ((ResolvedJavaType) handlerParameterTypes[0]).isAssignableFrom(throwable), + List handlerParameterTypes = handlerMethods[0].toParameterList(); + UserError.guarantee(handlerParameterTypes.size() == 1 && + handlerParameterTypes.get(0).isAssignableFrom(throwable), "Exception handler method must have exactly one parameter of type Throwable: %s -> %s", targetMethod, handlerMethods[0]); InvokeWithExceptionNode handlerInvoke = kit.startInvokeWithException(handlerMethods[0], InvokeKind.Static, kit.getFrameState(), kit.bci(), exception); kit.noExceptionPart(); @@ -545,7 +537,7 @@ private void generateExceptionHandler(HostedProviders providers, HostedGraphKit } /* The exception is handled, we can continue with the normal epilogue. */ - generateEpilogueAndReturn(providers, kit, returnValue); + generateEpilogueAndReturn(kit, returnValue); kit.exceptionPart(); // fail-safe for exceptions in exception handler kit.append(new CEntryPointLeaveNode(LeaveAction.ExceptionAbort, kit.exceptionObject())); @@ -554,20 +546,20 @@ private void generateExceptionHandler(HostedProviders providers, HostedGraphKit } } - private ValueNode adaptReturnValue(HostedProviders providers, HostedGraphKit kit, ValueNode value) { + private ValueNode adaptReturnValue(HostedGraphKit kit, ValueNode value) { ValueNode returnValue = value; if (returnValue.getStackKind().isPrimitive()) { return returnValue; } - JavaType returnType = targetSignature.getReturnType(null); + AnalysisType returnType = targetSignature.getReturnType(); NativeLibraries nativeLibraries = CEntryPointCallStubSupport.singleton().getNativeLibraries(); - ElementInfo typeInfo = nativeLibraries.findElementInfo((ResolvedJavaType) returnType); + ElementInfo typeInfo = nativeLibraries.findElementInfo(returnType); if (typeInfo instanceof EnumInfo) { // Always return enum values as a signed word because it should never be a problem if // the caller expects a narrower integer type and the various checks already handle // replacements with word types. - CInterfaceEnumTool tool = new CInterfaceEnumTool(providers.getMetaAccess(), providers.getSnippetReflection()); - JavaKind cEnumReturnType = providers.getWordTypes().getWordKind(); + CInterfaceEnumTool tool = new CInterfaceEnumTool(kit.getMetaAccess(), kit.getSnippetReflection()); + JavaKind cEnumReturnType = kit.getWordTypes().getWordKind(); assert !cEnumReturnType.isUnsigned() : "requires correct representation of signed values"; returnValue = tool.startEnumValueInvokeWithException(kit, (EnumInfo) typeInfo, cEnumReturnType, returnValue); kit.exceptionPart(); @@ -582,7 +574,7 @@ private ValueNode adaptReturnValue(HostedProviders providers, HostedGraphKit kit return returnValue; } - private void generateEpilogue(HostedProviders providers, SubstrateGraphKit kit) { + private void generateEpilogue(HostedGraphKit kit) { Class epilogueClass = entryPointData.getEpilogue(); if (epilogueClass == NoEpilogue.class) { UserError.guarantee(Uninterruptible.Utils.isUninterruptible(targetMethod), @@ -593,8 +585,8 @@ private void generateEpilogue(HostedProviders providers, SubstrateGraphKit kit) targetMethod); return; } - ResolvedJavaType epilogue = providers.getMetaAccess().lookupJavaType(epilogueClass); - ResolvedJavaMethod[] epilogueMethods = epilogue.getDeclaredMethods(false); + AnalysisType epilogue = kit.getMetaAccess().lookupJavaType(epilogueClass); + AnalysisMethod[] epilogueMethods = epilogue.getDeclaredMethods(false); UserError.guarantee(epilogueMethods.length == 1 && epilogueMethods[0].isStatic() && epilogueMethods[0].getSignature().getParameterCount(false) == 0, "Epilogue class must declare exactly one static method without parameters: %s -> %s", targetMethod, epilogue); UserError.guarantee(Uninterruptible.Utils.isUninterruptible(epilogueMethods[0]), diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/code/CEntryPointJavaCallStubMethod.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/code/CEntryPointJavaCallStubMethod.java index 9e5f4e18ac25..5db0aa2c2a72 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/code/CEntryPointJavaCallStubMethod.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/code/CEntryPointJavaCallStubMethod.java @@ -27,17 +27,16 @@ import java.lang.reflect.AnnotatedElement; import java.util.List; -import jdk.graal.compiler.nodes.ConstantNode; -import jdk.graal.compiler.nodes.ValueNode; -import jdk.graal.compiler.nodes.java.LoadFieldNode; import org.graalvm.nativeimage.c.function.CEntryPoint; import org.graalvm.nativeimage.c.function.CFunctionPointer; -import com.oracle.graal.pointsto.meta.HostedProviders; import com.oracle.svm.core.c.BoxedRelocatedPointer; import com.oracle.svm.core.thread.VMThreads.StatusSupport; import com.oracle.svm.hosted.phases.HostedGraphKit; +import jdk.graal.compiler.nodes.ConstantNode; +import jdk.graal.compiler.nodes.ValueNode; +import jdk.graal.compiler.nodes.java.LoadFieldNode; import jdk.vm.ci.meta.ResolvedJavaMethod; import jdk.vm.ci.meta.ResolvedJavaType; @@ -74,7 +73,7 @@ protected String getCorrespondingAnnotationName() { } @Override - protected ValueNode createTargetAddressNode(HostedGraphKit kit, HostedProviders providers, List arguments) { + protected ValueNode createTargetAddressNode(HostedGraphKit kit, List arguments) { /* * We currently cannot handle {@link MethodPointer} as a constant in the code, so we use an diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/code/CFunctionCallStubMethod.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/code/CFunctionCallStubMethod.java index 59d29d9e537f..d9d26d99996e 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/code/CFunctionCallStubMethod.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/code/CFunctionCallStubMethod.java @@ -27,11 +27,11 @@ import java.util.Arrays; import java.util.List; -import jdk.graal.compiler.debug.DebugContext; -import jdk.graal.compiler.nodes.StructuredGraph; -import jdk.graal.compiler.nodes.ValueNode; import org.graalvm.nativeimage.c.function.CFunction; +import com.oracle.graal.pointsto.infrastructure.ResolvedSignature; +import com.oracle.graal.pointsto.meta.AnalysisMethod; +import com.oracle.graal.pointsto.meta.AnalysisType; import com.oracle.graal.pointsto.meta.HostedProviders; import com.oracle.svm.core.graal.code.CGlobalDataInfo; import com.oracle.svm.core.graal.nodes.CGlobalDataLoadAddressNode; @@ -41,9 +41,10 @@ import com.oracle.svm.hosted.phases.HostedGraphKit; import com.oracle.svm.util.ClassUtil; -import jdk.vm.ci.meta.JavaType; +import jdk.graal.compiler.debug.DebugContext; +import jdk.graal.compiler.nodes.StructuredGraph; +import jdk.graal.compiler.nodes.ValueNode; import jdk.vm.ci.meta.ResolvedJavaMethod; -import jdk.vm.ci.meta.Signature; /** * Call stub for invoking C functions via methods annotated with {@link CFunction}. @@ -82,31 +83,26 @@ public boolean allowRuntimeCompilation() { } @Override - public StructuredGraph buildGraph(DebugContext debug, ResolvedJavaMethod method, HostedProviders providers, Purpose purpose) { + public StructuredGraph buildGraph(DebugContext debug, AnalysisMethod method, HostedProviders providers, Purpose purpose) { assert purpose != Purpose.PREPARE_RUNTIME_COMPILATION || allowRuntimeCompilation(); return super.buildGraph(debug, method, providers, purpose); } @Override - protected ValueNode createTargetAddressNode(HostedGraphKit kit, HostedProviders providers, List arguments) { + protected ValueNode createTargetAddressNode(HostedGraphKit kit, List arguments) { return kit.unique(new CGlobalDataLoadAddressNode(linkage)); } @Override - protected JavaType[] getParameterTypesForLoad(ResolvedJavaMethod method) { - return method.toParameterTypes(); // include a potential receiver - } - - @Override - protected Signature adaptSignatureAndConvertArguments(HostedProviders providers, NativeLibraries nativeLibraries, - HostedGraphKit kit, ResolvedJavaMethod method, JavaType returnType, JavaType[] paramTypes, List arguments) { - JavaType[] adaptedParamTypes = paramTypes; + protected ResolvedSignature adaptSignatureAndConvertArguments(NativeLibraries nativeLibraries, + HostedGraphKit kit, AnalysisMethod method, AnalysisType returnType, AnalysisType[] paramTypes, List arguments) { + var adaptedParamTypes = paramTypes; if (method.hasReceiver()) { // For non-static methods, we ignore the receiver. arguments.remove(0); adaptedParamTypes = Arrays.copyOfRange(adaptedParamTypes, 1, adaptedParamTypes.length); } - return super.adaptSignatureAndConvertArguments(providers, nativeLibraries, kit, method, returnType, adaptedParamTypes, arguments); + return super.adaptSignatureAndConvertArguments(nativeLibraries, kit, method, returnType, adaptedParamTypes, arguments); } } diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/code/CFunctionPointerCallStubMethod.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/code/CFunctionPointerCallStubMethod.java index eb11296acf92..ba2af8a72645 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/code/CFunctionPointerCallStubMethod.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/code/CFunctionPointerCallStubMethod.java @@ -28,17 +28,19 @@ import java.util.Arrays; import java.util.List; -import jdk.graal.compiler.debug.DebugContext; -import jdk.graal.compiler.nodes.StructuredGraph; -import jdk.graal.compiler.nodes.ValueNode; import org.graalvm.nativeimage.c.function.InvokeCFunctionPointer; +import com.oracle.graal.pointsto.infrastructure.ResolvedSignature; import com.oracle.graal.pointsto.meta.AnalysisMethod; +import com.oracle.graal.pointsto.meta.AnalysisType; import com.oracle.graal.pointsto.meta.HostedProviders; import com.oracle.svm.core.thread.VMThreads.StatusSupport; import com.oracle.svm.hosted.c.NativeLibraries; import com.oracle.svm.hosted.phases.HostedGraphKit; +import jdk.graal.compiler.debug.DebugContext; +import jdk.graal.compiler.nodes.StructuredGraph; +import jdk.graal.compiler.nodes.ValueNode; import jdk.vm.ci.meta.JavaType; import jdk.vm.ci.meta.ResolvedJavaMethod; import jdk.vm.ci.meta.ResolvedJavaType; @@ -127,28 +129,23 @@ public boolean allowRuntimeCompilation() { } @Override - public StructuredGraph buildGraph(DebugContext debug, ResolvedJavaMethod method, HostedProviders providers, Purpose purpose) { + public StructuredGraph buildGraph(DebugContext debug, AnalysisMethod method, HostedProviders providers, Purpose purpose) { assert purpose != Purpose.PREPARE_RUNTIME_COMPILATION || allowRuntimeCompilation(); return super.buildGraph(debug, method, providers, purpose); } @Override - protected JavaType[] getParameterTypesForLoad(ResolvedJavaMethod method) { - return method.toParameterTypes(); // include receiver = call target address - } - - @Override - protected ValueNode createTargetAddressNode(HostedGraphKit kit, HostedProviders providers, List arguments) { + protected ValueNode createTargetAddressNode(HostedGraphKit kit, List arguments) { return arguments.get(0); } @Override - protected Signature adaptSignatureAndConvertArguments(HostedProviders providers, NativeLibraries nativeLibraries, - HostedGraphKit kit, ResolvedJavaMethod method, JavaType returnType, JavaType[] paramTypes, List arguments) { + protected ResolvedSignature adaptSignatureAndConvertArguments(NativeLibraries nativeLibraries, + HostedGraphKit kit, AnalysisMethod method, AnalysisType returnType, AnalysisType[] paramTypes, List arguments) { // First argument is the call target address, not an actual argument arguments.remove(0); - JavaType[] paramTypesNoReceiver = Arrays.copyOfRange(paramTypes, 1, paramTypes.length); - return super.adaptSignatureAndConvertArguments(providers, nativeLibraries, kit, method, returnType, paramTypesNoReceiver, arguments); + var paramTypesNoReceiver = Arrays.copyOfRange(paramTypes, 1, paramTypes.length); + return super.adaptSignatureAndConvertArguments(nativeLibraries, kit, method, returnType, paramTypesNoReceiver, arguments); } } diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/code/CompileQueue.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/code/CompileQueue.java index dc1f6fa2b35a..3f7628962290 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/code/CompileQueue.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/code/CompileQueue.java @@ -48,7 +48,6 @@ import com.oracle.graal.pointsto.util.CompletionExecutor.DebugContextRunnable; import com.oracle.svm.common.meta.MultiMethod; import com.oracle.svm.core.SubstrateOptions; -import com.oracle.svm.core.SubstrateOptions.OptimizationLevel; import com.oracle.svm.core.Uninterruptible; import com.oracle.svm.core.config.ConfigurationValues; import com.oracle.svm.core.deopt.DeoptTest; @@ -116,8 +115,6 @@ import jdk.graal.compiler.nodes.StructuredGraph; import jdk.graal.compiler.nodes.ValueNode; import jdk.graal.compiler.nodes.graphbuilderconf.GeneratedFoldInvocationPlugin; -import jdk.graal.compiler.nodes.graphbuilderconf.GraphBuilderConfiguration; -import jdk.graal.compiler.nodes.graphbuilderconf.GraphBuilderConfiguration.BytecodeExceptionMode; import jdk.graal.compiler.nodes.graphbuilderconf.GraphBuilderContext; import jdk.graal.compiler.nodes.graphbuilderconf.InlineInvokePlugin; import jdk.graal.compiler.nodes.java.MethodCallTargetNode; @@ -1044,23 +1041,6 @@ protected OptionValues getCustomizedOptions(@SuppressWarnings("unused") HostedMe return debug.getOptions(); } - protected GraphBuilderConfiguration createHostedGraphBuilderConfiguration(HostedProviders providers, HostedMethod method) { - GraphBuilderConfiguration gbConf = GraphBuilderConfiguration.getDefault(providers.getGraphBuilderPlugins()).withBytecodeExceptionMode(BytecodeExceptionMode.CheckAll); - - if (SubstrateOptions.optimizationLevel() == OptimizationLevel.O0 && !method.isDeoptTarget()) { - /* - * Disabling liveness analysis preserves the values of local variables beyond the - * bytecode-liveness. This greatly helps debugging. When local variable numbers are - * reused by javac, local variables can still get illegal values. Since we cannot - * "restore" such illegal values during deoptimization, we cannot disable liveness - * analysis for deoptimization target methods. - */ - gbConf = gbConf.withRetainLocalVariables(true); - } - - return gbConf; - } - protected boolean canBeUsedForInlining(Invoke invoke) { HostedMethod caller = (HostedMethod) invoke.asNode().graph().method(); HostedMethod callee = (HostedMethod) invoke.callTarget().targetMethod(); diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/code/FactoryMethod.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/code/FactoryMethod.java index 2b6a0695a31c..2ebe820aca98 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/code/FactoryMethod.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/code/FactoryMethod.java @@ -26,7 +26,6 @@ import org.graalvm.nativeimage.ImageSingletons; -import com.oracle.graal.pointsto.meta.AnalysisMetaAccess; import com.oracle.graal.pointsto.meta.AnalysisMethod; import com.oracle.graal.pointsto.meta.HostedProviders; import com.oracle.svm.core.NeverInlineTrivial; @@ -81,16 +80,15 @@ public AnnotationValue[] getInjectedAnnotations() { } @Override - public StructuredGraph buildGraph(DebugContext debug, ResolvedJavaMethod method, HostedProviders providers, Purpose purpose) { + public StructuredGraph buildGraph(DebugContext debug, AnalysisMethod method, HostedProviders providers, Purpose purpose) { + HostedGraphKit kit = new HostedGraphKit(debug, providers, method); FactoryMethodSupport support = ImageSingletons.lookup(FactoryMethodSupport.class); - AnalysisMetaAccess aMetaAccess = (AnalysisMetaAccess) providers.getMetaAccess(); - AnalysisMethod aTargetConstructor = aMetaAccess.getUniverse().lookup(targetConstructor); - HostedGraphKit kit = new HostedGraphKit(debug, providers, method); + AnalysisMethod aTargetConstructor = kit.getMetaAccess().getUniverse().lookup(targetConstructor); AbstractNewObjectNode newInstance = support.createNewInstance(kit, aTargetConstructor.getDeclaringClass(), true); - ValueNode[] originalArgs = kit.loadArguments(method.toParameterTypes()).toArray(ValueNode.EMPTY_ARRAY); + ValueNode[] originalArgs = kit.getInitialArguments().toArray(ValueNode.EMPTY_ARRAY); ValueNode[] invokeArgs = new ValueNode[originalArgs.length + 1]; invokeArgs[0] = newInstance; System.arraycopy(originalArgs, 0, invokeArgs, 1, originalArgs.length); @@ -107,9 +105,4 @@ public StructuredGraph buildGraph(DebugContext debug, ResolvedJavaMethod method, public ResolvedJavaMethod getTargetConstructor() { return targetConstructor; } - - @Override - public ResolvedJavaType getDeclaringClass() { - return super.getDeclaringClass(); - } } diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/code/FactoryMethodSupport.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/code/FactoryMethodSupport.java index 64084526336e..e56cc3e54846 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/code/FactoryMethodSupport.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/code/FactoryMethodSupport.java @@ -29,9 +29,9 @@ import org.graalvm.nativeimage.ImageSingletons; +import com.oracle.graal.pointsto.infrastructure.ResolvedSignature; import com.oracle.graal.pointsto.meta.AnalysisMetaAccess; import com.oracle.graal.pointsto.meta.AnalysisMethod; -import com.oracle.graal.pointsto.meta.AnalysisType; import com.oracle.svm.core.SubstrateUtil; import com.oracle.svm.core.code.FactoryMethodHolder; import com.oracle.svm.core.code.FactoryThrowMethodHolder; @@ -71,10 +71,10 @@ public AnalysisMethod lookup(AnalysisMetaAccess aMetaAccess, AnalysisMethod aCon */ ResolvedJavaType[] unwrappedParameterTypes = new ResolvedJavaType[aConstructor.getSignature().getParameterCount(false)]; for (int i = 0; i < unwrappedParameterTypes.length; i++) { - unwrappedParameterTypes[i] = ((AnalysisType) aConstructor.getSignature().getParameterType(i, null)).getWrapped(); + unwrappedParameterTypes[i] = aConstructor.getSignature().getParameterType(i).getWrapped(); } ResolvedJavaType unwrappedReturnType = (throwAllocatedObject ? aMetaAccess.lookupJavaType(void.class) : aConstructor.getDeclaringClass()).getWrapped(); - Signature unwrappedSignature = new SimpleSignature(unwrappedParameterTypes, unwrappedReturnType); + Signature unwrappedSignature = ResolvedSignature.fromArray(unwrappedParameterTypes, unwrappedReturnType); ResolvedJavaMethod unwrappedConstructor = aConstructor.getWrapped(); ResolvedJavaType unwrappedDeclaringClass = (aMetaAccess.lookupJavaType(throwAllocatedObject ? FactoryThrowMethodHolder.class : FactoryMethodHolder.class)).getWrapped(); ConstantPool unwrappedConstantPool = unwrappedConstructor.getConstantPool(); diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/code/IncompatibleClassChangeFallbackMethod.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/code/IncompatibleClassChangeFallbackMethod.java index 05433c56074a..ec74defc72db 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/code/IncompatibleClassChangeFallbackMethod.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/code/IncompatibleClassChangeFallbackMethod.java @@ -24,6 +24,7 @@ */ package com.oracle.svm.hosted.code; +import com.oracle.graal.pointsto.meta.AnalysisMethod; import com.oracle.graal.pointsto.meta.HostedProviders; import com.oracle.svm.hosted.analysis.NativeImagePointsToAnalysis; import com.oracle.svm.hosted.phases.HostedGraphKit; @@ -67,9 +68,9 @@ public ResolvedJavaMethod getOriginal() { } @Override - public StructuredGraph buildGraph(DebugContext debug, ResolvedJavaMethod method, HostedProviders providers, Purpose purpose) { + public StructuredGraph buildGraph(DebugContext debug, AnalysisMethod method, HostedProviders providers, Purpose purpose) { HostedGraphKit kit = new HostedGraphKit(debug, providers, method); - ResolvedJavaMethod constructor = providers.getMetaAccess().lookupJavaMethod(ReflectionUtil.lookupConstructor(resolutionError)); + AnalysisMethod constructor = kit.getMetaAccess().lookupJavaMethod(ReflectionUtil.lookupConstructor(resolutionError)); AbstractNewObjectNode newInstance = kit.append(new NewInstanceNode(constructor.getDeclaringClass(), true)); kit.createInvokeWithExceptionAndUnwind(constructor, InvokeKind.Special, kit.getFrameState(), kit.bci(), newInstance); diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/code/SimpleSignature.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/code/SimpleSignature.java deleted file mode 100644 index 17aacf9f159c..000000000000 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/code/SimpleSignature.java +++ /dev/null @@ -1,124 +0,0 @@ -/* - * Copyright (c) 2017, 2017, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.oracle.svm.hosted.code; - -import java.lang.invoke.MethodType; -import java.util.Arrays; -import java.util.List; -import java.util.Objects; -import java.util.stream.Collectors; - -import com.oracle.svm.core.SubstrateUtil; - -import jdk.vm.ci.meta.JavaKind; -import jdk.vm.ci.meta.JavaType; -import jdk.vm.ci.meta.MetaAccessProvider; -import jdk.vm.ci.meta.ResolvedJavaType; -import jdk.vm.ci.meta.Signature; - -/** - * A straightforward implementation of {@link Signature}. - */ -public class SimpleSignature implements Signature { - public static SimpleSignature fromKinds(JavaKind[] paramKinds, JavaKind returnKind, MetaAccessProvider metaAccess) { - ResolvedJavaType[] paramTypes = new ResolvedJavaType[paramKinds.length]; - for (int i = 0; i < paramKinds.length; i++) { - paramTypes[i] = SimpleSignature.resolveType(paramKinds[i], metaAccess); - } - JavaType returnType = SimpleSignature.resolveType(returnKind, metaAccess); - return new SimpleSignature(paramTypes, returnType); - } - - public static SimpleSignature fromMethodType(MethodType mt, MetaAccessProvider metaAccess) { - return new SimpleSignature( - Arrays.stream(mt.parameterArray()).map(metaAccess::lookupJavaType).collect(Collectors.toList()), - metaAccess.lookupJavaType(mt.returnType())); - } - - private static ResolvedJavaType resolveType(JavaKind kind, MetaAccessProvider metaAccess) { - return metaAccess.lookupJavaType(kind.isObject() ? Object.class : kind.toJavaClass()); - } - - private final JavaType[] parameterTypes; - private final JavaType returnType; - - public SimpleSignature(JavaType[] parameterTypes, JavaType returnType) { - this.parameterTypes = parameterTypes; - this.returnType = returnType; - } - - public SimpleSignature(List parameterTypes, JavaType returnType) { - this(parameterTypes.toArray(new JavaType[0]), returnType); - } - - @Override - public int getParameterCount(boolean receiver) { - return parameterTypes.length; - } - - @Override - public JavaType getParameterType(int index, ResolvedJavaType accessingClass) { - return parameterTypes[index]; - } - - @Override - public JavaType getReturnType(ResolvedJavaType accessingClass) { - return returnType; - } - - public String getIdentifier() { - StringBuilder sb = new StringBuilder(1 + parameterTypes.length); - boolean digest = false; - for (JavaType type : parameterTypes) { - if (type.getJavaKind().isPrimitive() || (type instanceof ResolvedJavaType && ((ResolvedJavaType) type).isJavaLangObject())) { - sb.append(type.getJavaKind().getTypeChar()); - } else { - sb.append(type.toClassName()); - digest = true; - } - } - sb.append('_').append(returnType.getJavaKind().getTypeChar()); - return digest ? SubstrateUtil.digest(sb.toString()) : sb.toString(); - } - - @Override - public boolean equals(Object obj) { - if (this != obj && obj instanceof SimpleSignature) { - var other = (SimpleSignature) obj; - return Arrays.equals(parameterTypes, other.parameterTypes) && Objects.equals(returnType, other.returnType); - } - return (this == obj); - } - - @Override - public int hashCode() { - return Arrays.hashCode(parameterTypes) * 31 + Objects.hashCode(returnType); - } - - @Override - public String toString() { - return getIdentifier(); - } -} diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/heap/PodFactorySubstitutionMethod.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/heap/PodFactorySubstitutionMethod.java index 5f8376567a7b..3c68a2fad589 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/heap/PodFactorySubstitutionMethod.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/heap/PodFactorySubstitutionMethod.java @@ -32,6 +32,9 @@ import org.graalvm.nativeimage.AnnotationAccess; import com.oracle.graal.pointsto.infrastructure.SubstitutionProcessor; +import com.oracle.graal.pointsto.meta.AnalysisField; +import com.oracle.graal.pointsto.meta.AnalysisMethod; +import com.oracle.graal.pointsto.meta.AnalysisType; import com.oracle.graal.pointsto.meta.HostedProviders; import com.oracle.svm.common.meta.MultiMethod; import com.oracle.svm.core.deopt.DeoptTest; @@ -65,9 +68,7 @@ import jdk.graal.compiler.nodes.ValueNode; import jdk.graal.compiler.nodes.java.ExceptionObjectNode; import jdk.vm.ci.meta.JavaKind; -import jdk.vm.ci.meta.ResolvedJavaField; import jdk.vm.ci.meta.ResolvedJavaMethod; -import jdk.vm.ci.meta.ResolvedJavaType; final class PodFactorySubstitutionProcessor extends SubstitutionProcessor { private final ConcurrentMap substitutions = new ConcurrentHashMap<>(); @@ -119,17 +120,17 @@ public int getModifiers() { } @Override - public StructuredGraph buildGraph(DebugContext debug, ResolvedJavaMethod method, HostedProviders providers, Purpose purpose) { + public StructuredGraph buildGraph(DebugContext debug, AnalysisMethod method, HostedProviders providers, Purpose purpose) { HostedGraphKit kit = new HostedGraphKit(debug, providers, method); DeoptInfoProvider deoptInfo = null; if (MultiMethod.isDeoptTarget(method)) { - deoptInfo = new DeoptInfoProvider((MultiMethod) method); + deoptInfo = new DeoptInfoProvider(method); } - ResolvedJavaType factoryType = method.getDeclaringClass(); + AnalysisType factoryType = method.getDeclaringClass(); PodFactory annotation = factoryType.getAnnotation(PodFactory.class); - ResolvedJavaType podConcreteType = kit.getMetaAccess().lookupJavaType(annotation.podClass()); - ResolvedJavaMethod targetCtor = findMatchingConstructor(method, podConcreteType.getSuperclass()); + AnalysisType podConcreteType = kit.getMetaAccess().lookupJavaType(annotation.podClass()); + AnalysisMethod targetCtor = findMatchingConstructor(method, podConcreteType.getSuperclass()); /* * The graph must be safe for runtime compilation and so for compilation as a deoptimization @@ -138,11 +139,11 @@ public StructuredGraph buildGraph(DebugContext debug, ResolvedJavaMethod method, */ int instanceLocal = kit.getFrameState().localsSize() - 1; // reserved when generating class int nextDeoptIndex = startMethod(kit, deoptInfo, 0); - instantiatePod(kit, providers, factoryType, podConcreteType, instanceLocal); + instantiatePod(kit, factoryType, podConcreteType, instanceLocal); if (isAnnotationPresent(DeoptTest.class)) { kit.append(new TestDeoptimizeNode()); } - nextDeoptIndex = invokeConstructor(kit, method, deoptInfo, nextDeoptIndex, targetCtor, instanceLocal); + nextDeoptIndex = invokeConstructor(kit, deoptInfo, nextDeoptIndex, targetCtor, instanceLocal); kit.createReturn(kit.loadLocal(instanceLocal, JavaKind.Object), JavaKind.Object); return kit.finalizeGraph(); @@ -154,8 +155,8 @@ public StructuredGraph buildGraph(DebugContext debug, ResolvedJavaMethod method, * * @throws GraalError if no matching constructor found */ - private ResolvedJavaMethod findMatchingConstructor(ResolvedJavaMethod method, ResolvedJavaType typeToSearch) { - for (ResolvedJavaMethod ctor : typeToSearch.getDeclaredConstructors(false)) { + private AnalysisMethod findMatchingConstructor(AnalysisMethod method, AnalysisType typeToSearch) { + for (AnalysisMethod ctor : typeToSearch.getDeclaredConstructors(false)) { if (parameterTypesMatch(method, ctor)) { return ctor; } @@ -180,31 +181,31 @@ private static int startMethod(HostedGraphKit kit, DeoptInfoProvider deoptInfo, return nextDeoptIndex; } - private static void instantiatePod(HostedGraphKit kit, HostedProviders providers, ResolvedJavaType factoryType, ResolvedJavaType podConcreteType, int instanceLocal) { - ResolvedJavaType podType = kit.getMetaAccess().lookupJavaType(Pod.class); + private static void instantiatePod(HostedGraphKit kit, AnalysisType factoryType, AnalysisType podConcreteType, int instanceLocal) { + AnalysisType podType = kit.getMetaAccess().lookupJavaType(Pod.class); ValueNode receiver = kit.loadLocal(0, JavaKind.Object); ValueNode pod = loadNonNullField(kit, receiver, findField(factoryType, "pod")); ValueNode arrayLength = kit.createLoadField(pod, findField(podType, "arrayLength")); ValueNode refMap = loadNonNullField(kit, pod, findField(podType, "referenceMap")); - ConstantNode hub = kit.createConstant(providers.getConstantReflection().asObjectHub(podConcreteType), JavaKind.Object); + ConstantNode hub = kit.createConstant(kit.getConstantReflection().asObjectHub(podConcreteType), JavaKind.Object); ValueNode instance = kit.append(new NewPodInstanceNode(podConcreteType, hub, arrayLength, refMap)); kit.storeLocal(instanceLocal, JavaKind.Object, instance); } - private static ValueNode loadNonNullField(HostedGraphKit kit, ValueNode object, ResolvedJavaField field) { + private static ValueNode loadNonNullField(HostedGraphKit kit, ValueNode object, AnalysisField field) { return kit.append(PiNode.create(kit.createLoadField(object, field), StampFactory.objectNonNull())); } - private static int invokeConstructor(HostedGraphKit kit, ResolvedJavaMethod method, DeoptInfoProvider deoptInfo, int nextDeoptIndex, ResolvedJavaMethod targetCtor, int instanceLocal) { + private static int invokeConstructor(HostedGraphKit kit, DeoptInfoProvider deoptInfo, int nextDeoptIndex, AnalysisMethod targetCtor, int instanceLocal) { ValueNode instance = kit.loadLocal(instanceLocal, JavaKind.Object); - ValueNode[] originalArgs = kit.loadArguments(method.toParameterTypes()).toArray(ValueNode.EMPTY_ARRAY); + ValueNode[] originalArgs = kit.getInitialArguments().toArray(ValueNode.EMPTY_ARRAY); ValueNode[] invokeArgs = Arrays.copyOf(originalArgs, originalArgs.length); invokeArgs[0] = instance; return invokeWithDeoptAndExceptionUnwind(kit, deoptInfo, nextDeoptIndex, targetCtor, InvokeKind.Special, invokeArgs); } /** @see com.oracle.svm.hosted.phases.SharedGraphBuilderPhase */ - private static int invokeWithDeoptAndExceptionUnwind(HostedGraphKit kit, DeoptInfoProvider deoptInfo, int initialNextDeoptIndex, ResolvedJavaMethod target, InvokeKind invokeKind, + private static int invokeWithDeoptAndExceptionUnwind(HostedGraphKit kit, DeoptInfoProvider deoptInfo, int initialNextDeoptIndex, AnalysisMethod target, InvokeKind invokeKind, ValueNode... args) { int bci = kit.bci(); InvokeWithExceptionNode invoke = kit.startInvokeWithException(target, invokeKind, kit.getFrameState(), bci, args); @@ -293,22 +294,22 @@ private static ValueNode createDeoptProxy(HostedGraphKit kit, int nextDeoptIndex return kit.getGraph().addOrUniqueWithInputs(DeoptProxyNode.create(value, deoptTarget, nextDeoptIndex)); } - private static boolean parameterTypesMatch(ResolvedJavaMethod method, ResolvedJavaMethod ctor) { + private static boolean parameterTypesMatch(AnalysisMethod method, AnalysisMethod ctor) { int paramsCount = method.getSignature().getParameterCount(false); if (paramsCount != ctor.getSignature().getParameterCount(false)) { return false; } for (int i = 0; i < paramsCount; i++) { - if (!ctor.getSignature().getParameterType(i, ctor.getDeclaringClass()) - .equals(method.getSignature().getParameterType(i, method.getDeclaringClass()))) { + if (!ctor.getSignature().getParameterType(i).equals(method.getSignature().getParameterType(i))) { return false; } } return true; } - private static ResolvedJavaField findField(ResolvedJavaType type, String name) { - for (ResolvedJavaField field : type.getInstanceFields(false)) { + private static AnalysisField findField(AnalysisType type, String name) { + for (var f : type.getInstanceFields(false)) { + AnalysisField field = (AnalysisField) f; if (field.getName().equals(name)) { return field; } diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/NativeImage.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/NativeImage.java index dd949466ad9e..db3d31bca211 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/NativeImage.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/NativeImage.java @@ -105,6 +105,7 @@ import com.oracle.svm.hosted.image.RelocatableBuffer.Info; import com.oracle.svm.hosted.meta.HostedMetaAccess; import com.oracle.svm.hosted.meta.HostedMethod; +import com.oracle.svm.hosted.meta.HostedType; import com.oracle.svm.hosted.meta.HostedUniverse; import com.oracle.svm.util.ReflectionUtil; import com.oracle.svm.util.ReflectionUtil.ReflectionUtilError; @@ -123,7 +124,6 @@ import jdk.vm.ci.meta.JavaConstant; import jdk.vm.ci.meta.ResolvedJavaMethod; import jdk.vm.ci.meta.ResolvedJavaMethod.Parameter; -import jdk.vm.ci.meta.ResolvedJavaType; public abstract class NativeImage extends AbstractImage { public static final long RWDATA_CGLOBALS_PARTITION_OFFSET = 0; @@ -323,7 +323,7 @@ private void writeMethodHeader(HostedMethod m, CSourceCodeWriter writer, boolean AnnotatedType annotatedReturnType = getAnnotatedReturnType(m); writer.append(CSourceCodeWriter.toCTypeName(m, - (ResolvedJavaType) m.getSignature().getReturnType(m.getDeclaringClass()), + m.getSignature().getReturnType(), Optional.ofNullable(annotatedReturnType.getAnnotation(CTypedef.class)).map(CTypedef::name), false, isUnsigned(annotatedReturnType), @@ -347,7 +347,7 @@ private void writeMethodHeader(HostedMethod m, CSourceCodeWriter writer, boolean writer.append(sep); sep = ", "; writer.append(CSourceCodeWriter.toCTypeName(m, - (ResolvedJavaType) m.getSignature().getParameterType(i, m.getDeclaringClass()), + m.getSignature().getParameterType(i), Optional.ofNullable(annotatedParameterTypes[i].getAnnotation(CTypedef.class)).map(CTypedef::name), annotatedParameterTypes[i].isAnnotationPresent(CConst.class), isUnsigned(annotatedParameterTypes[i]), @@ -919,8 +919,8 @@ protected void writeTextSection(DebugContext debug, final Section textSection, f * We've hit a signature with multiple methods. Choose the "more specific" * of the two methods, i.e. the overriding covariant signature. */ - final ResolvedJavaType existingReturnType = existing.getSignature().getReturnType(null).resolve(existing.getDeclaringClass()); - final ResolvedJavaType currentReturnType = current.getSignature().getReturnType(null).resolve(current.getDeclaringClass()); + HostedType existingReturnType = existing.getSignature().getReturnType(); + HostedType currentReturnType = current.getSignature().getReturnType(); if (existingReturnType.isAssignableFrom(currentReturnType)) { /* current is more specific than existing */ final HostedMethod replaced = methodsBySignature.put(signatureString, current); diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/NativeImageCodeCache.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/NativeImageCodeCache.java index a0f94651c576..73575d220ac7 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/NativeImageCodeCache.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/NativeImageCodeCache.java @@ -117,7 +117,6 @@ import jdk.vm.ci.meta.Constant; import jdk.vm.ci.meta.JavaConstant; import jdk.vm.ci.meta.JavaKind; -import jdk.vm.ci.meta.JavaType; import jdk.vm.ci.meta.MetaAccessProvider; import jdk.vm.ci.meta.ResolvedJavaMethod; import jdk.vm.ci.meta.VMConstant; @@ -382,13 +381,11 @@ protected void buildRuntimeMetadata(DebugContext debug, SnippetReflectionProvide if (includedMethods.add(analysisMethod)) { HostedType declaringType = hUniverse.lookup(analysisMethod.getDeclaringClass()); String name = analysisMethod.getName(); - JavaType[] analysisParameterTypes = analysisMethod.getSignature().toParameterTypes(null); - HostedType[] parameterTypes = new HostedType[analysisParameterTypes.length]; - for (int i = 0; i < analysisParameterTypes.length; ++i) { - parameterTypes[i] = hUniverse.lookup(analysisParameterTypes[i]); - } + HostedType[] parameterTypes = analysisMethod.getSignature().toParameterList(null).stream() + .map(aType -> hUniverse.lookup(aType)) + .toArray(HostedType[]::new); int modifiers = analysisMethod.getModifiers(); - HostedType returnType = hUniverse.lookup(analysisMethod.getSignature().getReturnType(null)); + HostedType returnType = hUniverse.lookup(analysisMethod.getSignature().getReturnType()); reflectionMetadataEncoder.addHidingMethodMetadata(analysisMethod, declaringType, name, parameterTypes, modifiers, returnType); } } diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/NativeImageDebugInfoProviderBase.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/NativeImageDebugInfoProviderBase.java index 46d60ffd40c2..87ca9b83eabe 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/NativeImageDebugInfoProviderBase.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/NativeImageDebugInfoProviderBase.java @@ -25,10 +25,17 @@ */ package com.oracle.svm.hosted.image; +import static com.oracle.svm.hosted.c.info.AccessorInfo.AccessorKind.ADDRESS; +import static com.oracle.svm.hosted.c.info.AccessorInfo.AccessorKind.GETTER; +import static com.oracle.svm.hosted.c.info.AccessorInfo.AccessorKind.SETTER; + import java.nio.file.FileSystems; import java.nio.file.Path; import java.util.HashMap; +import org.graalvm.nativeimage.ImageSingletons; +import org.graalvm.word.WordBase; + import com.oracle.svm.core.StaticFieldsSupport; import com.oracle.svm.core.SubstrateOptions; import com.oracle.svm.core.config.ConfigurationValues; @@ -55,6 +62,7 @@ import com.oracle.svm.hosted.substitute.InjectedFieldsType; import com.oracle.svm.hosted.substitute.SubstitutionMethod; import com.oracle.svm.hosted.substitute.SubstitutionType; + import jdk.graal.compiler.core.common.CompressEncoding; import jdk.graal.compiler.core.target.Backend; import jdk.vm.ci.code.RegisterConfig; @@ -63,14 +71,6 @@ import jdk.vm.ci.meta.JavaType; import jdk.vm.ci.meta.ResolvedJavaMethod; import jdk.vm.ci.meta.ResolvedJavaType; -import jdk.vm.ci.meta.Signature; - -import org.graalvm.nativeimage.ImageSingletons; -import org.graalvm.word.WordBase; - -import static com.oracle.svm.hosted.c.info.AccessorInfo.AccessorKind.ADDRESS; -import static com.oracle.svm.hosted.c.info.AccessorInfo.AccessorKind.GETTER; -import static com.oracle.svm.hosted.c.info.AccessorInfo.AccessorKind.SETTER; /** * Abstract base class for implementation of DebugInfoProvider API providing a suite of useful @@ -448,12 +448,12 @@ protected SubstrateCallingConvention getCallingConvention(HostedMethod method) { SubstrateCallingConventionKind callingConventionKind = method.getCallingConventionKind(); HostedType declaringClass = method.getDeclaringClass(); HostedType receiverType = method.isStatic() ? null : declaringClass; - Signature signature = method.getSignature(); + var signature = method.getSignature(); SubstrateCallingConventionType type = callingConventionKind.toType(false); Backend backend = runtimeConfiguration.lookupBackend(method); RegisterConfig registerConfig = backend.getCodeCache().getRegisterConfig(); assert registerConfig instanceof SubstrateRegisterConfig; - return (SubstrateCallingConvention) registerConfig.getCallingConvention(type, signature.getReturnType(null), signature.toParameterTypes(receiverType), backend); + return (SubstrateCallingConvention) registerConfig.getCallingConvention(type, signature.getReturnType(), signature.toParameterTypes(receiverType), backend); } /* diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/jni/JNIAccessFeature.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/jni/JNIAccessFeature.java index 285dd7e7462f..b09b2e537aa3 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/jni/JNIAccessFeature.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/jni/JNIAccessFeature.java @@ -52,6 +52,7 @@ import org.graalvm.word.WordFactory; import com.oracle.graal.pointsto.BigBang; +import com.oracle.graal.pointsto.infrastructure.ResolvedSignature; import com.oracle.graal.pointsto.infrastructure.WrappedJavaType; import com.oracle.graal.pointsto.meta.AnalysisField; import com.oracle.graal.pointsto.meta.AnalysisMethod; @@ -83,7 +84,6 @@ import com.oracle.svm.hosted.ProgressReporter; import com.oracle.svm.hosted.code.CEntryPointData; import com.oracle.svm.hosted.code.FactoryMethodSupport; -import com.oracle.svm.hosted.code.SimpleSignature; import com.oracle.svm.hosted.config.ConfigurationParserUtils; import com.oracle.svm.hosted.config.HybridLayout; import com.oracle.svm.hosted.meta.HostedField; @@ -154,9 +154,9 @@ static final class JNICallableJavaMethod { private boolean sealed = false; private final Map trampolineMethods = new ConcurrentHashMap<>(); - private final Map javaCallWrapperMethods = new ConcurrentHashMap<>(); - private final Map callVariantWrappers = new ConcurrentHashMap<>(); - private final Map nonvirtualCallVariantWrappers = new ConcurrentHashMap<>(); + private final Map, JNIJavaCallWrapperMethod> javaCallWrapperMethods = new ConcurrentHashMap<>(); + private final Map, JNIJavaCallVariantWrapperGroup> callVariantWrappers = new ConcurrentHashMap<>(); + private final Map, JNIJavaCallVariantWrapperGroup> nonvirtualCallVariantWrappers = new ConcurrentHashMap<>(); private final List calledJavaMethods = new ArrayList<>(); private int loadedConfigurations; @@ -378,7 +378,7 @@ private void addMethod(Executable method, DuringAnalysisAccessImpl access) { newObjectMethod = aFactoryMethod.getWrapped(); } - SimpleSignature compatibleSignature = JNIJavaCallWrapperMethod.getGeneralizedSignatureForTarget(targetMethod, originalMetaAccess); + var compatibleSignature = JNIJavaCallWrapperMethod.getGeneralizedSignatureForTarget(targetMethod, originalMetaAccess); JNIJavaCallWrapperMethod callWrapperMethod = javaCallWrapperMethods.computeIfAbsent(compatibleSignature, signature -> factory.create(signature, originalMetaAccess, access.getBigBang().getWordTypes())); access.registerAsRoot(universe.lookup(callWrapperMethod), true, "JNI call wrapper, registered in " + JNIAccessFeature.class); @@ -394,7 +394,7 @@ private void addMethod(Executable method, DuringAnalysisAccessImpl access) { }); } - private JNIJavaCallVariantWrapperGroup createJavaCallVariantWrappers(DuringAnalysisAccessImpl access, SimpleSignature wrapperSignature, boolean nonVirtual) { + private JNIJavaCallVariantWrapperGroup createJavaCallVariantWrappers(DuringAnalysisAccessImpl access, ResolvedSignature wrapperSignature, boolean nonVirtual) { var map = nonVirtual ? nonvirtualCallVariantWrappers : callVariantWrappers; return map.computeIfAbsent(wrapperSignature, signature -> { MetaAccessProvider originalMetaAccess = access.getUniverse().getOriginalMetaAccess(); diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/jni/JNICallTrampolineMethod.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/jni/JNICallTrampolineMethod.java index 6570f6022478..73a3aabe985f 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/jni/JNICallTrampolineMethod.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/jni/JNICallTrampolineMethod.java @@ -30,6 +30,7 @@ import org.graalvm.nativeimage.ImageSingletons; +import com.oracle.graal.pointsto.meta.AnalysisMethod; import com.oracle.graal.pointsto.meta.AnalysisUniverse; import com.oracle.graal.pointsto.meta.HostedProviders; import com.oracle.svm.core.SubstrateOptions; @@ -90,7 +91,7 @@ public int getModifiers() { } @Override - public StructuredGraph buildGraph(DebugContext debug, ResolvedJavaMethod method, HostedProviders providers, Purpose purpose) { + public StructuredGraph buildGraph(DebugContext debug, AnalysisMethod method, HostedProviders providers, Purpose purpose) { HostedGraphKit kit = new JNIGraphKit(debug, providers, method); kit.append(new LoweredDeadEndNode()); diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/jni/JNIFieldAccessorMethod.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/jni/JNIFieldAccessorMethod.java index c85051b33080..9543c42e7490 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/jni/JNIFieldAccessorMethod.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/jni/JNIFieldAccessorMethod.java @@ -32,6 +32,8 @@ import org.graalvm.nativeimage.c.function.CEntryPoint.Publish; import org.graalvm.word.LocationIdentity; +import com.oracle.graal.pointsto.infrastructure.ResolvedSignature; +import com.oracle.graal.pointsto.meta.AnalysisMethod; import com.oracle.graal.pointsto.meta.HostedProviders; import com.oracle.svm.core.c.function.CEntryPointOptions.AutomaticPrologueBailout; import com.oracle.svm.core.c.function.CEntryPointOptions.NoEpilogue; @@ -45,7 +47,6 @@ import com.oracle.svm.core.util.VMError; import com.oracle.svm.hosted.code.CEntryPointData; import com.oracle.svm.hosted.code.EntryPointCallStubMethod; -import com.oracle.svm.hosted.code.SimpleSignature; import jdk.graal.compiler.debug.DebugContext; import jdk.graal.compiler.java.FrameStateBuilder; @@ -55,9 +56,7 @@ import jdk.graal.compiler.nodes.extended.RawStoreNode; import jdk.vm.ci.meta.ConstantPool; import jdk.vm.ci.meta.JavaKind; -import jdk.vm.ci.meta.JavaType; import jdk.vm.ci.meta.MetaAccessProvider; -import jdk.vm.ci.meta.ResolvedJavaMethod; import jdk.vm.ci.meta.ResolvedJavaType; /** @@ -149,13 +148,13 @@ private static String createName(JavaKind fieldKind, boolean isSetter, boolean i return sb.toString(); } - private static SimpleSignature createSignature(JavaKind fieldKind, boolean isSetter, MetaAccessProvider metaAccess) { + private static ResolvedSignature createSignature(JavaKind fieldKind, boolean isSetter, MetaAccessProvider metaAccess) { Class valueClass = fieldKind.toJavaClass(); if (fieldKind.isObject()) { valueClass = JNIObjectHandle.class; } ResolvedJavaType objectHandle = metaAccess.lookupJavaType(JNIObjectHandle.class); - List args = new ArrayList<>(); + List args = new ArrayList<>(); args.add(metaAccess.lookupJavaType(JNIEnvironment.class)); args.add(objectHandle); // this (instance field) or class (static field) args.add(metaAccess.lookupJavaType(JNIFieldId.class)); @@ -168,23 +167,19 @@ private static SimpleSignature createSignature(JavaKind fieldKind, boolean isSet } else { returnType = metaAccess.lookupJavaType(valueClass); } - return new SimpleSignature(args, returnType); + return ResolvedSignature.fromList(args, returnType); } @Override - public StructuredGraph buildGraph(DebugContext debug, ResolvedJavaMethod method, HostedProviders providers, Purpose purpose) { + public StructuredGraph buildGraph(DebugContext debug, AnalysisMethod method, HostedProviders providers, Purpose purpose) { JNIGraphKit kit = new JNIGraphKit(debug, providers, method); - StructuredGraph graph = kit.getGraph(); - FrameStateBuilder state = new FrameStateBuilder(null, method, graph); - state.initializeForMethodStart(null, true, providers.getGraphBuilderPlugins()); ValueNode vmThread = kit.loadLocal(0, getSignature().getParameterKind(0)); kit.append(CEntryPointEnterNode.enter(vmThread)); - List arguments = kit.loadArguments(getSignature().toParameterTypes(null)); - ValueNode returnValue = buildGraphBody(kit, arguments, state, providers.getMetaAccess()); + ValueNode returnValue = buildGraphBody(kit, kit.getInitialArguments(), kit.getFrameState(), kit.getMetaAccess()); - kit.appendStateSplitProxy(state); + kit.appendStateSplitProxy(); CEntryPointLeaveNode leave = new CEntryPointLeaveNode(LeaveAction.Leave); kit.append(leave); JavaKind returnKind = isSetter ? JavaKind.Void : fieldKind; diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/jni/JNIGraphKit.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/jni/JNIGraphKit.java index 75a98c8d4a19..e16e55261242 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/jni/JNIGraphKit.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/jni/JNIGraphKit.java @@ -24,7 +24,9 @@ */ package com.oracle.svm.hosted.jni; +import com.oracle.graal.pointsto.infrastructure.ResolvedSignature; import com.oracle.graal.pointsto.meta.HostedProviders; +import com.oracle.svm.core.SubstrateUtil; import com.oracle.svm.core.jni.JNIGeneratedMethodSupport; import com.oracle.svm.core.jni.access.JNIAccessibleMethod; import com.oracle.svm.core.jni.access.JNIReflectionDictionary; @@ -66,6 +68,21 @@ public class JNIGraphKit extends HostedGraphKit { super(debug, providers, method); } + public static String signatureToIdentifier(ResolvedSignature signature) { + StringBuilder sb = new StringBuilder(); + boolean digest = false; + for (var type : signature.toParameterList(null)) { + if (type.getJavaKind().isPrimitive() || type.isJavaLangObject()) { + sb.append(type.getJavaKind().getTypeChar()); + } else { + sb.append(type.toClassName()); + digest = true; + } + } + sb.append('_').append(signature.getReturnType().getJavaKind().getTypeChar()); + return digest ? SubstrateUtil.digest(sb.toString()) : sb.toString(); + } + public ValueNode checkObjectType(ValueNode uncheckedValue, ResolvedJavaType type, boolean checkNonNull) { ValueNode value = uncheckedValue; if (checkNonNull) { diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/jni/JNIJavaCallVariantWrapperMethod.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/jni/JNIJavaCallVariantWrapperMethod.java index 1cf25dd9970e..98b62c38ae82 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/jni/JNIJavaCallVariantWrapperMethod.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/jni/JNIJavaCallVariantWrapperMethod.java @@ -30,7 +30,9 @@ import org.graalvm.nativeimage.Platform; import org.graalvm.word.LocationIdentity; -import com.oracle.graal.pointsto.meta.AnalysisMetaAccess; +import com.oracle.graal.pointsto.infrastructure.ResolvedSignature; +import com.oracle.graal.pointsto.meta.AnalysisMethod; +import com.oracle.graal.pointsto.meta.AnalysisType; import com.oracle.graal.pointsto.meta.HostedProviders; import com.oracle.svm.core.graal.code.SubstrateCallingConventionKind; import com.oracle.svm.core.graal.nodes.CEntryPointEnterNode; @@ -43,7 +45,6 @@ import com.oracle.svm.core.jni.JNIJavaCallVariantWrapperHolder; import com.oracle.svm.core.util.VMError; import com.oracle.svm.hosted.code.EntryPointCallStubMethod; -import com.oracle.svm.hosted.code.SimpleSignature; import jdk.graal.compiler.core.common.calc.FloatConvert; import jdk.graal.compiler.core.common.memory.BarrierType; @@ -70,7 +71,7 @@ import jdk.vm.ci.meta.JavaConstant; import jdk.vm.ci.meta.JavaKind; import jdk.vm.ci.meta.MetaAccessProvider; -import jdk.vm.ci.meta.ResolvedJavaMethod; +import jdk.vm.ci.meta.ResolvedJavaType; import jdk.vm.ci.meta.Signature; /** @@ -84,7 +85,8 @@ public class JNIJavaCallVariantWrapperMethod extends EntryPointCallStubMethod { private final CallVariant callVariant; private final boolean nonVirtual; - public JNIJavaCallVariantWrapperMethod(SimpleSignature callWrapperSignature, CallVariant callVariant, boolean nonVirtual, MetaAccessProvider originalMetaAccess, WordTypes wordTypes) { + public JNIJavaCallVariantWrapperMethod(ResolvedSignature callWrapperSignature, CallVariant callVariant, boolean nonVirtual, MetaAccessProvider originalMetaAccess, + WordTypes wordTypes) { super(createName(callWrapperSignature, callVariant, nonVirtual), originalMetaAccess.lookupJavaType(JNIJavaCallVariantWrapperHolder.class), createSignature(callWrapperSignature, callVariant, nonVirtual, originalMetaAccess, wordTypes), @@ -94,8 +96,8 @@ public JNIJavaCallVariantWrapperMethod(SimpleSignature callWrapperSignature, Cal this.nonVirtual = nonVirtual; } - private static String createName(SimpleSignature targetSignature, CallVariant callVariant, boolean nonVirtual) { - return "invoke" + targetSignature.getIdentifier() + "_" + callVariant.name() + (nonVirtual ? "_Nonvirtual" : ""); + private static String createName(ResolvedSignature targetSignature, CallVariant callVariant, boolean nonVirtual) { + return "invoke" + JNIGraphKit.signatureToIdentifier(targetSignature) + "_" + callVariant.name() + (nonVirtual ? "_Nonvirtual" : ""); } private static Signature createSignature(Signature callWrapperSignature, CallVariant callVariant, boolean nonVirtual, MetaAccessProvider originalMetaAccess, WordTypes wordTypes) { @@ -133,17 +135,16 @@ private static Signature createSignature(Signature callWrapperSignature, CallVar if (returnType.isObject()) { returnType = wordKind; // handle } - return SimpleSignature.fromKinds(args.toArray(JavaKind[]::new), returnType, originalMetaAccess); + return ResolvedSignature.fromKinds(args.toArray(JavaKind[]::new), returnType, originalMetaAccess); } @Override - public StructuredGraph buildGraph(DebugContext debug, ResolvedJavaMethod method, HostedProviders providers, Purpose purpose) { - AnalysisMetaAccess aMetaAccess = (AnalysisMetaAccess) providers.getMetaAccess(); + public StructuredGraph buildGraph(DebugContext debug, AnalysisMethod method, HostedProviders providers, Purpose purpose) { JNIGraphKit kit = new JNIGraphKit(debug, providers, method); - Signature invokeSignature = aMetaAccess.getUniverse().lookup(callWrapperSignature, getDeclaringClass()); + var invokeSignature = kit.getMetaAccess().getUniverse().lookup(callWrapperSignature, getDeclaringClass()); - JavaKind wordKind = providers.getWordTypes().getWordKind(); + JavaKind wordKind = kit.getWordTypes().getWordKind(); int slotIndex = 0; ValueNode env = kit.loadLocal(slotIndex, wordKind); slotIndex += wordKind.getSlotCount(); @@ -162,11 +163,11 @@ public StructuredGraph buildGraph(DebugContext debug, ResolvedJavaMethod method, args.add(receiverOrClassHandle); args.add(methodId); args.add(kit.createInt(nonVirtual ? 1 : 0)); - args.addAll(loadArguments(kit, providers, invokeSignature, args.size(), slotIndex)); + args.addAll(loadArguments(kit, invokeSignature, args.size(), slotIndex)); ValueNode formerPendingException = kit.getAndClearPendingException(); - StampPair returnStamp = StampFactory.forDeclaredType(kit.getAssumptions(), invokeSignature.getReturnType(null), false); + StampPair returnStamp = StampFactory.forDeclaredType(kit.getAssumptions(), invokeSignature.getReturnType(), false); CallTargetNode callTarget = new IndirectCallTargetNode(callAddress, args.toArray(ValueNode[]::new), returnStamp, invokeSignature.toParameterTypes(null), null, SubstrateCallingConventionKind.Java.toType(true), InvokeKind.Static); @@ -205,8 +206,8 @@ public StructuredGraph buildGraph(DebugContext debug, ResolvedJavaMethod method, * * @return List of created argument nodes and their type */ - private List loadArguments(JNIGraphKit kit, HostedProviders providers, Signature invokeSignature, int firstParamIndex, int firstSlotIndex) { - JavaKind wordKind = providers.getWordTypes().getWordKind(); + private List loadArguments(JNIGraphKit kit, ResolvedSignature invokeSignature, int firstParamIndex, int firstSlotIndex) { + JavaKind wordKind = kit.getWordTypes().getWordKind(); List args = new ArrayList<>(); int slotIndex = firstSlotIndex; int count = invokeSignature.getParameterCount(false); diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/jni/JNIJavaCallWrapperMethod.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/jni/JNIJavaCallWrapperMethod.java index 59b7d3104064..b1a31fbc63bc 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/jni/JNIJavaCallWrapperMethod.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/jni/JNIJavaCallWrapperMethod.java @@ -27,7 +27,9 @@ import java.lang.reflect.Constructor; import java.util.List; -import com.oracle.graal.pointsto.meta.AnalysisMetaAccess; +import com.oracle.graal.pointsto.infrastructure.ResolvedSignature; +import com.oracle.graal.pointsto.meta.AnalysisMethod; +import com.oracle.graal.pointsto.meta.AnalysisType; import com.oracle.graal.pointsto.meta.HostedProviders; import com.oracle.svm.core.graal.code.SubstrateCallingConventionKind; import com.oracle.svm.core.graal.nodes.LoweredDeadEndNode; @@ -35,7 +37,6 @@ import com.oracle.svm.core.jni.access.JNIAccessibleMethod; import com.oracle.svm.hosted.code.FactoryMethodSupport; import com.oracle.svm.hosted.code.NonBytecodeMethod; -import com.oracle.svm.hosted.code.SimpleSignature; import com.oracle.svm.util.ReflectionUtil; import jdk.graal.compiler.core.common.type.Stamp; @@ -82,7 +83,7 @@ public class JNIJavaCallWrapperMethod extends NonBytecodeMethod { private static final Constructor INSTANTIATION_EXCEPTION_CONSTRUCTOR = ReflectionUtil.lookupConstructor(InstantiationException.class); public static class Factory { - public JNIJavaCallWrapperMethod create(SimpleSignature targetSignature, MetaAccessProvider originalMetaAccess, WordTypes wordTypes) { + public JNIJavaCallWrapperMethod create(ResolvedSignature targetSignature, MetaAccessProvider originalMetaAccess, WordTypes wordTypes) { return new JNIJavaCallWrapperMethod(targetSignature, originalMetaAccess, wordTypes); } @@ -92,15 +93,10 @@ public boolean canInvokeConstructorOnObject(ResolvedJavaMethod constructor, Meta } } - public static SimpleSignature getGeneralizedSignatureForTarget(ResolvedJavaMethod targetMethod, MetaAccessProvider originalMetaAccess) { - ResolvedJavaType objectType = originalMetaAccess.lookupJavaType(Object.class); - JavaType[] paramTypes = targetMethod.getSignature().toParameterTypes(null); - // Note: does not include the receiver. - for (int i = 0; i < paramTypes.length; i++) { - if (paramTypes[i].getJavaKind().isObject()) { - paramTypes[i] = objectType; - } - } + public static ResolvedSignature getGeneralizedSignatureForTarget(ResolvedJavaMethod targetMethod, MetaAccessProvider originalMetaAccess) { + /* Note: does not include the receiver. */ + JavaKind[] paramKinds = targetMethod.getSignature().toParameterKinds(false); + JavaKind returnKind = targetMethod.getSignature().getReturnKind(); if (targetMethod.isConstructor()) { returnKind = JavaKind.Object; // return new (or previously allocated) object @@ -109,19 +105,19 @@ public static SimpleSignature getGeneralizedSignatureForTarget(ResolvedJavaMetho // wrappers. This is fine with our supported 64-bit calling conventions. returnKind = JavaKind.Long; } - JavaType returnType = returnKind.isObject() ? objectType : originalMetaAccess.lookupJavaType(returnKind.toJavaClass()); - return new SimpleSignature(paramTypes, returnType); + + return ResolvedSignature.fromKinds(paramKinds, returnKind, originalMetaAccess); } private final Signature targetSignature; - protected JNIJavaCallWrapperMethod(SimpleSignature targetSignature, MetaAccessProvider metaAccess, WordTypes wordTypes) { - super("invoke_" + targetSignature.getIdentifier(), true, metaAccess.lookupJavaType(JNIJavaCallWrapperHolder.class), + protected JNIJavaCallWrapperMethod(ResolvedSignature targetSignature, MetaAccessProvider metaAccess, WordTypes wordTypes) { + super("invoke_" + JNIGraphKit.signatureToIdentifier(targetSignature), true, metaAccess.lookupJavaType(JNIJavaCallWrapperHolder.class), createSignature(targetSignature, metaAccess, wordTypes), JNIJavaCallWrapperHolder.getConstantPool(metaAccess)); this.targetSignature = targetSignature; } - private static SimpleSignature createSignature(Signature targetSignature, MetaAccessProvider originalMetaAccess, WordTypes wordTypes) { + private static ResolvedSignature createSignature(Signature targetSignature, MetaAccessProvider originalMetaAccess, WordTypes wordTypes) { JavaKind wordKind = wordTypes.getWordKind(); int count = targetSignature.getParameterCount(false); JavaKind[] args = new JavaKind[3 + count]; @@ -147,22 +143,22 @@ private static SimpleSignature createSignature(Signature targetSignature, MetaAc if (returnKind.isObject()) { returnKind = wordKind; // handle } - return SimpleSignature.fromKinds(args, returnKind, originalMetaAccess); + return ResolvedSignature.fromKinds(args, returnKind, originalMetaAccess); } @Override - public SimpleSignature getSignature() { - return (SimpleSignature) super.getSignature(); + @SuppressWarnings("unchecked") + public ResolvedSignature getSignature() { + return (ResolvedSignature) super.getSignature(); } @Override - public StructuredGraph buildGraph(DebugContext debug, ResolvedJavaMethod method, HostedProviders providers, Purpose purpose) { - AnalysisMetaAccess aMetaAccess = (AnalysisMetaAccess) providers.getMetaAccess(); + public StructuredGraph buildGraph(DebugContext debug, AnalysisMethod method, HostedProviders providers, Purpose purpose) { JNIGraphKit kit = new JNIGraphKit(debug, providers, method); - Signature invokeSignature = aMetaAccess.getUniverse().lookup(targetSignature, getDeclaringClass()); + var invokeSignature = kit.getMetaAccess().getUniverse().lookup(targetSignature, getDeclaringClass()); - JavaKind wordKind = providers.getWordTypes().getWordKind(); + JavaKind wordKind = kit.getWordTypes().getWordKind(); int slotIndex = 0; ValueNode receiverOrClassHandle = kit.loadLocal(slotIndex, wordKind); ValueNode receiverOrClass = kit.unboxHandle(receiverOrClassHandle); @@ -172,7 +168,7 @@ public StructuredGraph buildGraph(DebugContext debug, ResolvedJavaMethod method, ValueNode nonVirtual = kit.loadLocal(slotIndex, JavaKind.Boolean.getStackKind()); slotIndex += JavaKind.Boolean.getStackKind().getSlotCount(); - ValueNode[] args = loadAndUnboxArguments(kit, providers, invokeSignature, slotIndex); + ValueNode[] args = loadAndUnboxArguments(kit, invokeSignature, slotIndex); ValueNode returnValue = createCall(kit, invokeSignature, methodId, receiverOrClass, nonVirtual, args); JavaKind returnKind = returnValue.getStackKind(); @@ -183,7 +179,7 @@ public StructuredGraph buildGraph(DebugContext debug, ResolvedJavaMethod method, return kit.finalizeGraph(); } - private ValueNode createCall(JNIGraphKit kit, Signature invokeSignature, ValueNode methodId, ValueNode receiverOrClass, ValueNode nonVirtual, ValueNode[] args) { + private ValueNode createCall(JNIGraphKit kit, ResolvedSignature invokeSignature, ValueNode methodId, ValueNode receiverOrClass, ValueNode nonVirtual, ValueNode[] args) { ValueNode declaringClass = kit.getDeclaringClassForMethod(methodId); if (!invokeSignature.getReturnKind().isObject()) { return createRegularMethodCall(kit, invokeSignature, methodId, receiverOrClass, nonVirtual, args); @@ -199,7 +195,7 @@ private ValueNode createCall(JNIGraphKit kit, Signature invokeSignature, ValueNo return mergeValues(kit, merge, kit.bci(), methodReturnValue, receiverOrCreatedObject); } - private static ValueNode createRegularMethodCall(JNIGraphKit kit, Signature invokeSignature, ValueNode methodId, + private static ValueNode createRegularMethodCall(JNIGraphKit kit, ResolvedSignature invokeSignature, ValueNode methodId, ValueNode receiverOrClass, ValueNode nonVirtual, ValueNode[] args) { ValueNode methodAddress = kit.getJavaCallAddress(methodId, receiverOrClass, nonVirtual); ValueNode isStatic = kit.isStaticMethod(methodId); @@ -207,12 +203,12 @@ private static ValueNode createRegularMethodCall(JNIGraphKit kit, Signature invo kit.thenPart(); ValueNode nonstaticResult = createMethodCallWithReceiver(kit, invokeSignature, methodAddress, receiverOrClass, args); kit.elsePart(); - ValueNode staticResult = createMethodCall(kit, invokeSignature.getReturnType(null), invokeSignature.toParameterTypes(null), methodAddress, args); + ValueNode staticResult = createMethodCall(kit, invokeSignature.getReturnType(), invokeSignature.toParameterTypes(null), methodAddress, args); AbstractMergeNode merge = kit.endIf(); return mergeValues(kit, merge, kit.bci(), nonstaticResult, staticResult); } - protected ValueNode createNewObjectOrConstructorCall(JNIGraphKit kit, Signature invokeSignature, ValueNode methodId, + protected ValueNode createNewObjectOrConstructorCall(JNIGraphKit kit, ResolvedSignature invokeSignature, ValueNode methodId, ValueNode declaringClass, ValueNode newObjectAddress, ValueNode receiverOrClass, ValueNode[] args) { /* * The called function could either be NewObject or CallMethod with a constructor @@ -234,21 +230,21 @@ protected ValueNode createNewObjectOrConstructorCall(JNIGraphKit kit, Signature return mergeValues(kit, merge, kit.bci(), createdObject, receiverOrClass); } - protected ValueNode createConstructorCall(JNIGraphKit kit, Signature invokeSignature, ValueNode methodId, + protected ValueNode createConstructorCall(JNIGraphKit kit, ResolvedSignature invokeSignature, ValueNode methodId, @SuppressWarnings("unused") ValueNode declaringClass, ValueNode receiverOrClass, ValueNode[] args) { ValueNode methodAddress = kit.getJavaCallAddress(methodId, receiverOrClass, kit.createInt(1)); return createMethodCallWithReceiver(kit, invokeSignature, methodAddress, receiverOrClass, args); } - private static ValueNode createMethodCallWithReceiver(JNIGraphKit kit, Signature invokeSignature, ValueNode methodAddress, ValueNode receiver, ValueNode[] args) { + private static ValueNode createMethodCallWithReceiver(JNIGraphKit kit, ResolvedSignature invokeSignature, ValueNode methodAddress, ValueNode receiver, ValueNode[] args) { ValueNode[] argsWithReceiver = new ValueNode[1 + args.length]; argsWithReceiver[0] = kit.maybeCreateExplicitNullCheck(receiver); System.arraycopy(args, 0, argsWithReceiver, 1, args.length); JavaType[] paramTypes = invokeSignature.toParameterTypes(kit.getMetaAccess().lookupJavaType(Object.class)); - return createMethodCall(kit, invokeSignature.getReturnType(null), paramTypes, methodAddress, argsWithReceiver); + return createMethodCall(kit, invokeSignature.getReturnType(), paramTypes, methodAddress, argsWithReceiver); } - private static ValueNode createNewObjectCall(JNIGraphKit kit, Signature invokeSignature, ValueNode newObjectAddress, ValueNode[] args) { + private static ValueNode createNewObjectCall(JNIGraphKit kit, ResolvedSignature invokeSignature, ValueNode newObjectAddress, ValueNode[] args) { ConstantNode abstractTypeSentinel = kit.createWord(JNIAccessibleMethod.NEW_OBJECT_INVALID_FOR_ABSTRACT_TYPE); kit.startIf(IntegerEqualsNode.create(newObjectAddress, abstractTypeSentinel, NodeView.DEFAULT), BranchProbabilityNode.SLOW_PATH_PROFILE); kit.thenPart(); @@ -258,7 +254,7 @@ private static ValueNode createNewObjectCall(JNIGraphKit kit, Signature invokeSi kit.append(new LoweredDeadEndNode()); kit.endIf(); - return createMethodCall(kit, invokeSignature.getReturnType(null), invokeSignature.toParameterTypes(null), newObjectAddress, args); + return createMethodCall(kit, invokeSignature.getReturnType(), invokeSignature.toParameterTypes(null), newObjectAddress, args); } private static ValueNode createMethodCall(JNIGraphKit kit, JavaType returnType, JavaType[] paramTypes, ValueNode methodAddress, ValueNode[] args) { @@ -284,16 +280,16 @@ private static ValueNode mergeValues(JNIGraphKit kit, AbstractMergeNode merge, i return returnValue; } - private static ValueNode[] loadAndUnboxArguments(JNIGraphKit kit, HostedProviders providers, Signature invokeSignature, int firstSlotIndex) { + private static ValueNode[] loadAndUnboxArguments(JNIGraphKit kit, ResolvedSignature invokeSignature, int firstSlotIndex) { int slotIndex = firstSlotIndex; int count = invokeSignature.getParameterCount(false); ValueNode[] args = new ValueNode[count]; for (int i = 0; i < args.length; i++) { - ResolvedJavaType type = (ResolvedJavaType) invokeSignature.getParameterType(i, null); + AnalysisType type = invokeSignature.getParameterType(i); JavaKind kind = type.getJavaKind(); JavaKind loadKind = kind; if (kind.isObject()) { - loadKind = providers.getWordTypes().getWordKind(); + loadKind = kit.getWordTypes().getWordKind(); } else if (kind != kind.getStackKind()) { // We widened the kind in the signature for better reusability of call variant // wrappers (read above) and need to mask extra bits below. diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/jni/JNINativeCallWrapperMethod.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/jni/JNINativeCallWrapperMethod.java index 40e26eb3ba01..58b3a71ac3fe 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/jni/JNINativeCallWrapperMethod.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/jni/JNINativeCallWrapperMethod.java @@ -30,7 +30,10 @@ import java.util.List; import java.util.function.Function; +import com.oracle.graal.pointsto.infrastructure.ResolvedSignature; import com.oracle.graal.pointsto.infrastructure.WrappedJavaMethod; +import com.oracle.graal.pointsto.meta.AnalysisMethod; +import com.oracle.graal.pointsto.meta.AnalysisType; import com.oracle.graal.pointsto.meta.HostedProviders; import com.oracle.svm.core.c.CGlobalDataFactory; import com.oracle.svm.core.graal.code.CGlobalDataInfo; @@ -41,7 +44,6 @@ import com.oracle.svm.core.thread.VMThreads.StatusSupport; import com.oracle.svm.hosted.annotation.CustomSubstitutionMethod; import com.oracle.svm.hosted.c.CGlobalDataFeature; -import com.oracle.svm.hosted.code.SimpleSignature; import com.oracle.svm.hosted.heap.SVMImageHeapScanner; import com.oracle.svm.util.ReflectionUtil; @@ -54,11 +56,8 @@ import jdk.graal.compiler.nodes.java.MonitorExitNode; import jdk.graal.compiler.nodes.java.MonitorIdNode; import jdk.vm.ci.meta.JavaConstant; -import jdk.vm.ci.meta.JavaType; import jdk.vm.ci.meta.LineNumberTable; import jdk.vm.ci.meta.ResolvedJavaMethod; -import jdk.vm.ci.meta.ResolvedJavaType; -import jdk.vm.ci.meta.Signature; /** * Generated code for calling a specific native method from Java code. The wrapper takes care of @@ -106,9 +105,8 @@ public StackTraceElement asStackTraceElement(int bci) { } @Override - public StructuredGraph buildGraph(DebugContext debug, ResolvedJavaMethod method, HostedProviders providers, Purpose purpose) { + public StructuredGraph buildGraph(DebugContext debug, AnalysisMethod method, HostedProviders providers, Purpose purpose) { JNIGraphKit kit = new JNIGraphKit(debug, providers, method); - StructuredGraph graph = kit.getGraph(); InvokeWithExceptionNode handleFrame = kit.nativeCallPrologue(); @@ -124,27 +122,27 @@ public StructuredGraph buildGraph(DebugContext debug, ResolvedJavaMethod method, ValueNode environment = kit.environment(); - JavaType javaReturnType = method.getSignature().getReturnType(null); - JavaType[] javaArgumentTypes = method.toParameterTypes(); - List javaArguments = kit.loadArguments(javaArgumentTypes); + AnalysisType javaReturnType = method.getSignature().getReturnType(); + List javaArgumentTypes = method.toParameterList(); + List javaArguments = kit.getInitialArguments(); List jniArguments = new ArrayList<>(2 + javaArguments.size()); - List jniArgumentTypes = new ArrayList<>(2 + javaArguments.size()); - JavaType environmentType = providers.getMetaAccess().lookupJavaType(JNIEnvironment.class); - JavaType objectHandleType = providers.getMetaAccess().lookupJavaType(JNIObjectHandle.class); + List jniArgumentTypes = new ArrayList<>(2 + javaArguments.size()); + AnalysisType environmentType = kit.getMetaAccess().lookupJavaType(JNIEnvironment.class); + AnalysisType objectHandleType = kit.getMetaAccess().lookupJavaType(JNIObjectHandle.class); jniArguments.add(environment); jniArgumentTypes.add(environmentType); if (method.isStatic()) { - JavaConstant clazz = providers.getConstantReflection().asJavaClass(method.getDeclaringClass()); - ConstantNode clazzNode = ConstantNode.forConstant(clazz, providers.getMetaAccess(), graph); + JavaConstant clazz = kit.getConstantReflection().asJavaClass(method.getDeclaringClass()); + ConstantNode clazzNode = ConstantNode.forConstant(clazz, kit.getMetaAccess(), kit.getGraph()); ValueNode box = kit.boxObjectInLocalHandle(clazzNode); jniArguments.add(box); jniArgumentTypes.add(objectHandleType); } for (int i = 0; i < javaArguments.size(); i++) { ValueNode arg = javaArguments.get(i); - JavaType argType = javaArgumentTypes[i]; - if (javaArgumentTypes[i].getJavaKind().isObject()) { + AnalysisType argType = javaArgumentTypes.get(i); + if (argType.getJavaKind().isObject()) { ValueNode obj = javaArguments.get(i); arg = kit.boxObjectInLocalHandle(obj); argType = objectHandleType; @@ -153,7 +151,7 @@ public StructuredGraph buildGraph(DebugContext debug, ResolvedJavaMethod method, jniArgumentTypes.add(argType); } assert jniArguments.size() == jniArgumentTypes.size(); - JavaType jniReturnType = javaReturnType; + AnalysisType jniReturnType = javaReturnType; if (jniReturnType.getJavaKind().isObject()) { jniReturnType = objectHandleType; } @@ -161,12 +159,12 @@ public StructuredGraph buildGraph(DebugContext debug, ResolvedJavaMethod method, if (getOriginal().isSynchronized()) { ValueNode monitorObject; if (method.isStatic()) { - JavaConstant hubConstant = (JavaConstant) providers.getConstantReflection().asObjectHub(method.getDeclaringClass()); - monitorObject = ConstantNode.forConstant(hubConstant, providers.getMetaAccess(), graph); + JavaConstant hubConstant = (JavaConstant) kit.getConstantReflection().asObjectHub(method.getDeclaringClass()); + monitorObject = ConstantNode.forConstant(hubConstant, kit.getMetaAccess(), kit.getGraph()); } else { monitorObject = kit.maybeCreateExplicitNullCheck(javaArguments.get(0)); } - MonitorIdNode monitorId = graph.add(new MonitorIdNode(kit.getFrameState().lockDepth(false))); + MonitorIdNode monitorId = kit.getGraph().add(new MonitorIdNode(kit.getFrameState().lockDepth(false))); MonitorEnterNode monitorEnter = kit.append(new MonitorEnterNode(monitorObject, monitorId)); kit.getFrameState().pushLock(monitorEnter.object(), monitorEnter.getMonitorId()); monitorEnter.setStateAfter(kit.getFrameState().create(kit.bci(), monitorEnter)); @@ -174,7 +172,7 @@ public StructuredGraph buildGraph(DebugContext debug, ResolvedJavaMethod method, kit.getFrameState().clearLocals(); - Signature jniSignature = new SimpleSignature(jniArgumentTypes, jniReturnType); + var jniSignature = ResolvedSignature.fromList(jniArgumentTypes, jniReturnType); ValueNode returnValue = kit.createCFunctionCall(callAddress, jniArguments, jniSignature, StatusSupport.STATUS_IN_NATIVE, false); if (getOriginal().isSynchronized()) { @@ -191,7 +189,7 @@ public StructuredGraph buildGraph(DebugContext debug, ResolvedJavaMethod method, kit.rethrowPendingException(); if (javaReturnType.getJavaKind().isObject()) { // Just before return to always run the epilogue and never suppress a pending exception - returnValue = kit.checkObjectType(returnValue, (ResolvedJavaType) javaReturnType, false); + returnValue = kit.checkObjectType(returnValue, javaReturnType, false); } kit.createReturn(returnValue, javaReturnType.getJavaKind()); diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/jni/JNIPrimitiveArrayOperationMethod.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/jni/JNIPrimitiveArrayOperationMethod.java index b83fbd4773aa..9e3cedb3e40b 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/jni/JNIPrimitiveArrayOperationMethod.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/jni/JNIPrimitiveArrayOperationMethod.java @@ -33,6 +33,8 @@ import org.graalvm.nativeimage.c.type.CCharPointer; import org.graalvm.nativeimage.c.type.WordPointer; +import com.oracle.graal.pointsto.infrastructure.ResolvedSignature; +import com.oracle.graal.pointsto.meta.AnalysisMethod; import com.oracle.graal.pointsto.meta.HostedProviders; import com.oracle.svm.core.c.function.CEntryPointOptions.AutomaticPrologueBailout; import com.oracle.svm.core.c.function.CEntryPointOptions.NoEpilogue; @@ -45,19 +47,15 @@ import com.oracle.svm.core.util.VMError; import com.oracle.svm.hosted.code.CEntryPointData; import com.oracle.svm.hosted.code.EntryPointCallStubMethod; -import com.oracle.svm.hosted.code.SimpleSignature; import jdk.graal.compiler.debug.DebugContext; -import jdk.graal.compiler.java.FrameStateBuilder; import jdk.graal.compiler.nodes.FixedWithNextNode; import jdk.graal.compiler.nodes.MergeNode; import jdk.graal.compiler.nodes.StructuredGraph; import jdk.graal.compiler.nodes.ValueNode; import jdk.vm.ci.meta.ConstantPool; import jdk.vm.ci.meta.JavaKind; -import jdk.vm.ci.meta.JavaType; import jdk.vm.ci.meta.MetaAccessProvider; -import jdk.vm.ci.meta.ResolvedJavaMethod; import jdk.vm.ci.meta.ResolvedJavaType; /** @@ -148,11 +146,11 @@ private static String createName(JavaKind elementKind, Operation operation) { return sb.toString(); } - private static SimpleSignature createSignature(Operation operation, MetaAccessProvider metaAccess) { + private static ResolvedSignature createSignature(Operation operation, MetaAccessProvider metaAccess) { ResolvedJavaType objectHandleType = metaAccess.lookupJavaType(JNIObjectHandle.class); ResolvedJavaType intType = metaAccess.lookupJavaType(int.class); ResolvedJavaType returnType; - List args = new ArrayList<>(); + List args = new ArrayList<>(); args.add(metaAccess.lookupJavaType(JNIEnvironment.class)); args.add(objectHandleType); // jArray array; if (operation == Operation.GET_ELEMENTS) { @@ -170,21 +168,17 @@ private static SimpleSignature createSignature(Operation operation, MetaAccessPr } else { throw VMError.shouldNotReachHereUnexpectedInput(operation); // ExcludeFromJacocoGeneratedReport } - return new SimpleSignature(args, returnType); + return ResolvedSignature.fromList(args, returnType); } @Override - public StructuredGraph buildGraph(DebugContext debug, ResolvedJavaMethod method, HostedProviders providers, Purpose purpose) { + public StructuredGraph buildGraph(DebugContext debug, AnalysisMethod method, HostedProviders providers, Purpose purpose) { JNIGraphKit kit = new JNIGraphKit(debug, providers, method); - StructuredGraph graph = kit.getGraph(); - FrameStateBuilder state = new FrameStateBuilder(null, method, graph); - state.initializeForMethodStart(null, true, providers.getGraphBuilderPlugins()); - ValueNode vmThread = kit.loadLocal(0, getSignature().getParameterKind(0)); + List arguments = kit.getInitialArguments(); + ValueNode vmThread = arguments.get(0); kit.append(CEntryPointEnterNode.enter(vmThread)); - List arguments = kit.loadArguments(getSignature().toParameterTypes(null)); - ValueNode result = null; switch (operation) { case GET_ELEMENTS: { @@ -215,14 +209,14 @@ public StructuredGraph buildGraph(DebugContext debug, ResolvedJavaMethod method, } if (fwn instanceof MergeNode) { MergeNode merge = (MergeNode) fwn; - ((MergeNode) fwn).setStateAfter(state.create(kit.bci(), merge)); + ((MergeNode) fwn).setStateAfter(kit.getFrameState().create(kit.bci(), merge)); } break; } default: throw VMError.shouldNotReachHereUnexpectedInput(operation); // ExcludeFromJacocoGeneratedReport } - kit.appendStateSplitProxy(state); + kit.appendStateSplitProxy(); CEntryPointLeaveNode leave = new CEntryPointLeaveNode(LeaveAction.Leave); kit.append(leave); kit.createReturn(result, (result != null) ? result.getStackKind() : JavaKind.Void); diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/meta/HostedMethod.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/meta/HostedMethod.java index 130d135f3f11..0f0ddb28b80d 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/meta/HostedMethod.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/meta/HostedMethod.java @@ -44,11 +44,10 @@ import org.graalvm.nativeimage.Platforms; import com.oracle.graal.pointsto.constraints.UnsupportedFeatureException; -import com.oracle.graal.pointsto.infrastructure.GraphProvider; import com.oracle.graal.pointsto.infrastructure.OriginalMethodProvider; +import com.oracle.graal.pointsto.infrastructure.ResolvedSignature; import com.oracle.graal.pointsto.infrastructure.WrappedJavaMethod; import com.oracle.graal.pointsto.meta.AnalysisMethod; -import com.oracle.graal.pointsto.meta.HostedProviders; import com.oracle.svm.common.meta.MultiMethod; import com.oracle.svm.core.AlwaysInline; import com.oracle.svm.core.SubstrateUtil; @@ -71,11 +70,10 @@ import com.oracle.svm.hosted.code.SubstrateCompilationDirectives; import jdk.graal.compiler.api.replacements.Snippet; -import jdk.graal.compiler.debug.DebugContext; import jdk.graal.compiler.debug.JavaMethodContext; import jdk.graal.compiler.java.StableMethodNameFormatter; -import jdk.graal.compiler.nodes.StructuredGraph; import jdk.internal.vm.annotation.ForceInline; +import jdk.vm.ci.common.JVMCIError; import jdk.vm.ci.meta.Constant; import jdk.vm.ci.meta.ConstantPool; import jdk.vm.ci.meta.ExceptionHandler; @@ -85,19 +83,17 @@ import jdk.vm.ci.meta.Local; import jdk.vm.ci.meta.LocalVariableTable; import jdk.vm.ci.meta.ProfilingInfo; -import jdk.vm.ci.meta.ResolvedJavaMethod; import jdk.vm.ci.meta.ResolvedJavaType; -import jdk.vm.ci.meta.Signature; import jdk.vm.ci.meta.SpeculationLog; -public final class HostedMethod extends HostedElement implements SharedMethod, WrappedJavaMethod, GraphProvider, JavaMethodContext, OriginalMethodProvider, MultiMethod { +public final class HostedMethod extends HostedElement implements SharedMethod, WrappedJavaMethod, JavaMethodContext, OriginalMethodProvider, MultiMethod { public static final String METHOD_NAME_COLLISION_SEPARATOR = "%"; public final AnalysisMethod wrapped; private final HostedType holder; - private final Signature signature; + private final ResolvedSignature signature; private final ConstantPool constantPool; private final ExceptionHandler[] handlers; int vtableIndex = -1; @@ -140,14 +136,14 @@ public final class HostedMethod extends HostedElement implements SharedMethod, W public static final HostedMethod[] EMPTY_ARRAY = new HostedMethod[0]; - static HostedMethod create(HostedUniverse universe, AnalysisMethod wrapped, HostedType holder, Signature signature, + static HostedMethod create(HostedUniverse universe, AnalysisMethod wrapped, HostedType holder, ResolvedSignature signature, ConstantPool constantPool, ExceptionHandler[] handlers) { LocalVariableTable localVariableTable = createLocalVariableTable(universe, wrapped); return create0(wrapped, holder, signature, constantPool, handlers, wrapped.getMultiMethodKey(), null, localVariableTable); } - private static HostedMethod create0(AnalysisMethod wrapped, HostedType holder, Signature signature, + private static HostedMethod create0(AnalysisMethod wrapped, HostedType holder, ResolvedSignature signature, ConstantPool constantPool, ExceptionHandler[] handlers, MultiMethodKey key, Map multiMethodMap, LocalVariableTable localVariableTable) { Function> nameGenerator = (collisionCount) -> { String name = wrapped.wrapped.getName(); // want name w/o any multimethodkey suffix @@ -190,7 +186,7 @@ private static LocalVariableTable createLocalVariableTable(HostedUniverse univer } } - private HostedMethod(AnalysisMethod wrapped, HostedType holder, Signature signature, ConstantPool constantPool, + private HostedMethod(AnalysisMethod wrapped, HostedType holder, ResolvedSignature signature, ConstantPool constantPool, ExceptionHandler[] handlers, String name, String uniqueShortName, LocalVariableTable localVariableTable, MultiMethodKey multiMethodKey, Map multiMethodMap) { this.wrapped = wrapped; @@ -369,18 +365,13 @@ public String getName() { } @Override - public Signature getSignature() { + public ResolvedSignature getSignature() { return signature; } @Override - public StructuredGraph buildGraph(DebugContext debug, ResolvedJavaMethod method, HostedProviders providers, Purpose purpose) { - return wrapped.buildGraph(debug, method, providers, purpose); - } - - @Override - public boolean allowRuntimeCompilation() { - return wrapped.allowRuntimeCompilation(); + public JavaType[] toParameterTypes() { + throw JVMCIError.shouldNotReachHere("ResolvedJavaMethod.toParameterTypes returns the wrong result for constructors."); } @Override diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/meta/HostedUniverse.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/meta/HostedUniverse.java index cfbecee9c656..7b575b747bd0 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/meta/HostedUniverse.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/meta/HostedUniverse.java @@ -601,8 +601,8 @@ public int compare(HostedMethod o1, HostedMethod o2) { return result; } - Signature signature1 = o1.getSignature(); - Signature signature2 = o2.getSignature(); + ResolvedSignature signature1 = o1.getSignature(); + ResolvedSignature signature2 = o2.getSignature(); int parameterCount1 = signature1.getParameterCount(false); result = Integer.compare(parameterCount1, signature2.getParameterCount(false)); if (result != 0) { @@ -610,13 +610,13 @@ public int compare(HostedMethod o1, HostedMethod o2) { } for (int i = 0; i < parameterCount1; i++) { - result = typeComparator.compare((HostedType) signature1.getParameterType(i, null), (HostedType) signature2.getParameterType(i, null)); + result = typeComparator.compare(signature1.getParameterType(i), signature2.getParameterType(i)); if (result != 0) { return result; } } - result = typeComparator.compare((HostedType) signature1.getReturnType(null), (HostedType) signature2.getReturnType(null)); + result = typeComparator.compare(signature1.getReturnType(), signature2.getReturnType()); if (result != 0) { return result; } diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/meta/UniverseBuilder.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/meta/UniverseBuilder.java index 6ec22dca79c4..9aace5aa2b1a 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/meta/UniverseBuilder.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/meta/UniverseBuilder.java @@ -293,8 +293,7 @@ private static boolean sameObject(Object x, Object y) { private HostedMethod makeMethod(AnalysisMethod aMethod) { AnalysisType aDeclaringClass = aMethod.getDeclaringClass(); HostedType hDeclaringClass = lookupType(aDeclaringClass); - @SuppressWarnings("unchecked") - var signature = makeSignature((ResolvedSignature) aMethod.getSignature()); + ResolvedSignature signature = makeSignature(aMethod.getSignature()); ConstantPool constantPool = makeConstantPool(aMethod.getConstantPool(), aDeclaringClass); ExceptionHandler[] aHandlers = aMethod.getExceptionHandlers(); diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/phases/CInterfaceEnumTool.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/phases/CInterfaceEnumTool.java index 16c0f6df0e7b..b62dea3abe53 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/phases/CInterfaceEnumTool.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/phases/CInterfaceEnumTool.java @@ -26,6 +26,13 @@ import java.lang.reflect.Modifier; +import com.oracle.graal.pointsto.meta.AnalysisMetaAccess; +import com.oracle.graal.pointsto.meta.AnalysisMethod; +import com.oracle.graal.pointsto.meta.AnalysisType; +import com.oracle.svm.core.c.enums.EnumRuntimeData; +import com.oracle.svm.core.util.VMError; +import com.oracle.svm.hosted.c.info.EnumInfo; + import jdk.graal.compiler.api.replacements.SnippetReflectionProvider; import jdk.graal.compiler.core.common.type.ObjectStamp; import jdk.graal.compiler.core.common.type.StampFactory; @@ -43,19 +50,11 @@ import jdk.graal.compiler.nodes.graphbuilderconf.GraphBuilderTool; import jdk.graal.compiler.nodes.java.InstanceOfNode; import jdk.graal.compiler.nodes.java.MethodCallTargetNode; - -import com.oracle.svm.core.c.enums.EnumRuntimeData; -import com.oracle.svm.core.util.VMError; -import com.oracle.svm.hosted.c.info.EnumInfo; - import jdk.vm.ci.meta.JavaKind; -import jdk.vm.ci.meta.MetaAccessProvider; -import jdk.vm.ci.meta.ResolvedJavaMethod; -import jdk.vm.ci.meta.ResolvedJavaType; public class CInterfaceEnumTool { interface CallTargetFactory { - MethodCallTargetNode createMethodCallTarget(InvokeKind invokeKind, ResolvedJavaMethod targetMethod, ValueNode[] args, StampPair returnStamp, int bci); + MethodCallTargetNode createMethodCallTarget(InvokeKind invokeKind, AnalysisMethod targetMethod, ValueNode[] args, StampPair returnStamp, int bci); static CallTargetFactory from(BytecodeParser p) { return (invokeKind, targetMethod, args, returnStamp, bci) -> p.createMethodCallTarget(invokeKind, targetMethod, args, returnStamp, null); @@ -67,11 +66,11 @@ static CallTargetFactory from(HostedGraphKit kit) { } private final SnippetReflectionProvider snippetReflection; - private final ResolvedJavaMethod convertJavaToCLongMethod; - private final ResolvedJavaMethod convertJavaToCIntMethod; - private final ResolvedJavaMethod convertCToJavaMethod; + private final AnalysisMethod convertJavaToCLongMethod; + private final AnalysisMethod convertJavaToCIntMethod; + private final AnalysisMethod convertCToJavaMethod; - public CInterfaceEnumTool(MetaAccessProvider metaAccess, SnippetReflectionProvider snippetReflection) { + public CInterfaceEnumTool(AnalysisMetaAccess metaAccess, SnippetReflectionProvider snippetReflection) { this.snippetReflection = snippetReflection; try { convertJavaToCLongMethod = metaAccess.lookupJavaMethod(EnumRuntimeData.class.getDeclaredMethod("convertJavaToCLong", Enum.class)); @@ -82,7 +81,7 @@ public CInterfaceEnumTool(MetaAccessProvider metaAccess, SnippetReflectionProvid } } - private ResolvedJavaMethod getValueMethodForKind(JavaKind kind) { + private AnalysisMethod getValueMethodForKind(JavaKind kind) { return (kind == JavaKind.Long) ? convertJavaToCLongMethod : convertJavaToCIntMethod; } @@ -99,8 +98,8 @@ public ValueNode startEnumValueInvokeWithException(HostedGraphKit kit, EnumInfo } private MethodCallTargetNode invokeEnumValue(GraphBuilderTool b, CallTargetFactory callTargetFactory, int bci, EnumInfo enumInfo, JavaKind resultKind, ValueNode arg) { - ResolvedJavaMethod valueMethod = getValueMethodForKind(resultKind); - ResolvedJavaType returnType = (ResolvedJavaType) valueMethod.getSignature().getReturnType(null); + AnalysisMethod valueMethod = getValueMethodForKind(resultKind); + AnalysisType returnType = valueMethod.getSignature().getReturnType(); ValueNode[] args = new ValueNode[2]; args[0] = ConstantNode.forConstant(snippetReflection.forObject(enumInfo.getRuntimeData()), b.getMetaAccess(), b.getGraph()); args[1] = arg; @@ -109,7 +108,7 @@ private MethodCallTargetNode invokeEnumValue(GraphBuilderTool b, CallTargetFacto return b.append(callTargetFactory.createMethodCallTarget(InvokeKind.Virtual, valueMethod, args, returnStamp, bci)); } - public ValueNode createEnumLookupInvoke(HostedGraphKit kit, ResolvedJavaType enumType, EnumInfo enumInfo, JavaKind parameterKind, ValueNode arg) { + public ValueNode createEnumLookupInvoke(HostedGraphKit kit, AnalysisType enumType, EnumInfo enumInfo, JavaKind parameterKind, ValueNode arg) { // Create the invoke to the actual target method: EnumRuntimeData.convertCToJava int invokeBci = kit.bci(); MethodCallTargetNode callTarget = invokeEnumLookup(kit, CallTargetFactory.from(kit), invokeBci, enumInfo, parameterKind, arg); @@ -129,10 +128,10 @@ private MethodCallTargetNode invokeEnumLookup(GraphBuilderTool b, CallTargetFact ValueNode[] args = new ValueNode[2]; args[0] = ConstantNode.forConstant(snippetReflection.forObject(enumInfo.getRuntimeData()), b.getMetaAccess(), b.getGraph()); assert !Modifier.isStatic(convertCToJavaMethod.getModifiers()) && convertCToJavaMethod.getSignature().getParameterCount(false) == 1; - JavaKind expectedKind = convertCToJavaMethod.getSignature().getParameterType(0, null).getJavaKind(); + JavaKind expectedKind = convertCToJavaMethod.getSignature().getParameterType(0).getJavaKind(); args[1] = CInterfaceInvocationPlugin.adaptPrimitiveType(b.getGraph(), arg, parameterKind, expectedKind, false); - ResolvedJavaType convertReturnType = (ResolvedJavaType) convertCToJavaMethod.getSignature().getReturnType(null); + AnalysisType convertReturnType = convertCToJavaMethod.getSignature().getReturnType(); StampPair returnStamp = StampFactory.forDeclaredType(null, convertReturnType, false); return b.append(callTargetFactory.createMethodCallTarget(InvokeKind.Virtual, convertCToJavaMethod, args, returnStamp, bci)); } diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/phases/CInterfaceInvocationPlugin.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/phases/CInterfaceInvocationPlugin.java index 596cf4254251..5f5383dd2ff2 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/phases/CInterfaceInvocationPlugin.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/phases/CInterfaceInvocationPlugin.java @@ -35,6 +35,7 @@ import org.graalvm.word.LocationIdentity; import com.oracle.graal.pointsto.meta.AnalysisMethod; +import com.oracle.graal.pointsto.meta.AnalysisType; import com.oracle.svm.core.FrameAccess; import com.oracle.svm.core.c.InvokeJavaFunctionPointer; import com.oracle.svm.core.c.struct.CInterfaceLocationIdentity; @@ -56,8 +57,6 @@ import com.oracle.svm.hosted.code.CEntryPointCallStubSupport; import com.oracle.svm.hosted.code.CEntryPointJavaCallStubMethod; import com.oracle.svm.hosted.code.CFunctionPointerCallStubSupport; -import com.oracle.svm.hosted.meta.HostedMetaAccess; -import com.oracle.svm.hosted.meta.HostedMethod; import jdk.graal.compiler.api.replacements.SnippetReflectionProvider; import jdk.graal.compiler.core.common.calc.FloatConvert; @@ -111,7 +110,8 @@ public CInterfaceInvocationPlugin(MetaAccessProvider metaAccess, SnippetReflecti } @Override - public boolean handleInvoke(GraphBuilderContext b, ResolvedJavaMethod method, ValueNode[] args) { + public boolean handleInvoke(GraphBuilderContext b, ResolvedJavaMethod m, ValueNode[] args) { + AnalysisMethod method = (AnalysisMethod) m; ElementInfo methodInfo = nativeLibs.findElementInfo(method); if (methodInfo instanceof AccessorInfo) { ElementInfo parentInfo = methodInfo.getParent(); @@ -136,13 +136,8 @@ public boolean handleInvoke(GraphBuilderContext b, ResolvedJavaMethod method, Va } else if (method.getAnnotation(InvokeJavaFunctionPointer.class) != null) { return replaceJavaFunctionPointerInvoke(b, method, args); } else if (method.getAnnotation(CEntryPoint.class) != null) { - AnalysisMethod aMethod = (AnalysisMethod) (method instanceof HostedMethod ? ((HostedMethod) method).getWrapped() : method); - assert !(aMethod.getWrapped() instanceof CEntryPointJavaCallStubMethod) : "Call stub should never have a @CEntryPoint annotation"; - ResolvedJavaMethod stub = CEntryPointCallStubSupport.singleton().registerJavaStubForMethod(aMethod); - if (method instanceof HostedMethod) { - HostedMetaAccess hMetaAccess = (HostedMetaAccess) b.getMetaAccess(); - stub = hMetaAccess.getUniverse().lookup(stub); - } + assert !(method.getWrapped() instanceof CEntryPointJavaCallStubMethod) : "Call stub should never have a @CEntryPoint annotation"; + AnalysisMethod stub = CEntryPointCallStubSupport.singleton().registerJavaStubForMethod(method); assert !b.getMethod().equals(stub) : "Plugin should not be called for the invoke in the stub itself"; b.handleReplacedInvoke(InvokeKind.Static, stub, args, false); return true; @@ -151,7 +146,7 @@ public boolean handleInvoke(GraphBuilderContext b, ResolvedJavaMethod method, Va } } - private boolean replaceOffsetOf(GraphBuilderContext b, ResolvedJavaMethod method, ValueNode[] args, AccessorInfo accessorInfo, int displacement) { + private boolean replaceOffsetOf(GraphBuilderContext b, AnalysisMethod method, ValueNode[] args, AccessorInfo accessorInfo, int displacement) { /* * A method annotated with @OffsetOf can be static, but does not need to be. If it is * non-static, we just ignore the receiver. @@ -163,7 +158,7 @@ private boolean replaceOffsetOf(GraphBuilderContext b, ResolvedJavaMethod method return true; } - private boolean replaceAccessor(GraphBuilderContext b, ResolvedJavaMethod method, ValueNode[] args, AccessorInfo accessorInfo, int displacement) { + private boolean replaceAccessor(GraphBuilderContext b, AnalysisMethod method, ValueNode[] args, AccessorInfo accessorInfo, int displacement) { StructuredGraph graph = b.getGraph(); SizableInfo sizableInfo = (SizableInfo) accessorInfo.getParent(); int elementSize = sizableInfo.getSizeInfo().getProperty(); @@ -228,7 +223,7 @@ private boolean replaceAccessor(GraphBuilderContext b, ResolvedJavaMethod method } } - private boolean replaceBitfieldAccessor(GraphBuilderContext b, ResolvedJavaMethod method, ValueNode[] args, StructBitfieldInfo bitfieldInfo, AccessorInfo accessorInfo) { + private boolean replaceBitfieldAccessor(GraphBuilderContext b, AnalysisMethod method, ValueNode[] args, StructBitfieldInfo bitfieldInfo, AccessorInfo accessorInfo) { int byteOffset = bitfieldInfo.getByteOffsetInfo().getProperty(); int startBit = bitfieldInfo.getStartBitInfo().getProperty(); int endBit = bitfieldInfo.getEndBitInfo().getProperty(); @@ -385,7 +380,7 @@ private static AddressNode makeOffsetAddress(StructuredGraph graph, ValueNode[] return graph.addOrUniqueWithInputs(new OffsetAddressNode(base, makeOffset(graph, args, accessorInfo, displacement, indexScaling))); } - private static LocationIdentity makeLocationIdentity(GraphBuilderContext b, SnippetReflectionProvider snippetReflection, ResolvedJavaMethod method, ValueNode[] args, AccessorInfo accessorInfo) { + private static LocationIdentity makeLocationIdentity(GraphBuilderContext b, SnippetReflectionProvider snippetReflection, AnalysisMethod method, ValueNode[] args, AccessorInfo accessorInfo) { LocationIdentity locationIdentity; if (accessorInfo.hasLocationIdentityParameter()) { ValueNode locationIdentityNode = args[accessorInfo.locationIdentityParameterNumber(true)]; @@ -467,7 +462,7 @@ private static JavaKind kindFromSize(int sizeInBytes, JavaKind matchingKind) { throw shouldNotReachHere("Unsupported size: " + sizeInBytes); } - private boolean replaceConstant(GraphBuilderContext b, ResolvedJavaMethod method, ConstantInfo constantInfo) { + private boolean replaceConstant(GraphBuilderContext b, AnalysisMethod method, ConstantInfo constantInfo) { Object value = constantInfo.getValueInfo().getProperty(); JavaKind kind = b.getWordTypes().asKind(b.getInvokeReturnType()); @@ -495,10 +490,8 @@ private boolean replaceConstant(GraphBuilderContext b, ResolvedJavaMethod method return true; } - private boolean replaceCFunctionPointerInvoke(GraphBuilderContext b, ResolvedJavaMethod method, ValueNode[] args) { - boolean hosted = method instanceof HostedMethod; - AnalysisMethod aMethod = (AnalysisMethod) (hosted ? ((HostedMethod) method).getWrapped() : method); - if (CFunctionPointerCallStubSupport.singleton().isStub(aMethod)) { + private boolean replaceCFunctionPointerInvoke(GraphBuilderContext b, AnalysisMethod method, ValueNode[] args) { + if (CFunctionPointerCallStubSupport.singleton().isStub(method)) { return false; } if (!functionPointerType.isAssignableFrom(method.getDeclaringClass())) { @@ -506,15 +499,12 @@ private boolean replaceCFunctionPointerInvoke(GraphBuilderContext b, ResolvedJav " must be in a type that extends " + CFunctionPointer.class.getSimpleName(), method).getMessage()); } assert b.getInvokeKind() == InvokeKind.Interface; - ResolvedJavaMethod stub = CFunctionPointerCallStubSupport.singleton().getOrCreateStubForMethod(aMethod); - if (hosted) { - stub = ((HostedMetaAccess) b.getMetaAccess()).getUniverse().lookup(stub); - } + AnalysisMethod stub = CFunctionPointerCallStubSupport.singleton().getOrCreateStubForMethod(method); b.handleReplacedInvoke(InvokeKind.Static, stub, args, false); return true; } - private boolean replaceJavaFunctionPointerInvoke(GraphBuilderContext b, ResolvedJavaMethod method, ValueNode[] args) { + private boolean replaceJavaFunctionPointerInvoke(GraphBuilderContext b, AnalysisMethod method, ValueNode[] args) { if (!functionPointerType.isAssignableFrom(method.getDeclaringClass())) { throw UserError.abort(new CInterfaceError("Function pointer invocation method " + method.format("%H.%n(%p)") + " must be in a type that extends " + CFunctionPointer.class.getSimpleName(), method).getMessage()); @@ -530,7 +520,7 @@ private boolean replaceJavaFunctionPointerInvoke(GraphBuilderContext b, Resolved Stamp returnStamp; if (b.getWordTypes().isWord(b.getInvokeReturnType())) { - returnStamp = b.getWordTypes().getWordStamp((ResolvedJavaType) b.getInvokeReturnType()); + returnStamp = b.getWordTypes().getWordStamp((AnalysisType) b.getInvokeReturnType()); } else { returnStamp = b.getInvokeReturnStamp(null).getTrustedStamp(); } @@ -541,7 +531,7 @@ private boolean replaceJavaFunctionPointerInvoke(GraphBuilderContext b, Resolved return true; } - public static JavaKind pushKind(ResolvedJavaMethod method) { + public static JavaKind pushKind(AnalysisMethod method) { return method.getSignature().getReturnKind().getStackKind(); } } diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/phases/InjectedAccessorsPlugin.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/phases/InjectedAccessorsPlugin.java index 060804123006..acac1156467f 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/phases/InjectedAccessorsPlugin.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/phases/InjectedAccessorsPlugin.java @@ -27,56 +27,57 @@ import java.util.ArrayList; import java.util.List; +import com.oracle.graal.pointsto.meta.AnalysisField; +import com.oracle.graal.pointsto.meta.AnalysisMetaAccess; +import com.oracle.graal.pointsto.meta.AnalysisMethod; +import com.oracle.graal.pointsto.meta.AnalysisType; +import com.oracle.svm.core.annotate.InjectAccessors; +import com.oracle.svm.core.util.VMError; + import jdk.graal.compiler.nodes.CallTargetNode.InvokeKind; import jdk.graal.compiler.nodes.ValueNode; import jdk.graal.compiler.nodes.graphbuilderconf.GraphBuilderContext; import jdk.graal.compiler.nodes.graphbuilderconf.NodePlugin; - -import com.oracle.svm.core.annotate.InjectAccessors; -import com.oracle.svm.core.util.VMError; - -import jdk.vm.ci.meta.JavaType; import jdk.vm.ci.meta.ResolvedJavaField; -import jdk.vm.ci.meta.ResolvedJavaMethod; -import jdk.vm.ci.meta.ResolvedJavaType; public final class InjectedAccessorsPlugin implements NodePlugin { @Override public boolean handleLoadField(GraphBuilderContext b, ValueNode object, ResolvedJavaField field) { - return handleField(b, field, false, object, true, null); + return handleField(b, (AnalysisField) field, false, object, true, null); } @Override public boolean handleLoadStaticField(GraphBuilderContext b, ResolvedJavaField field) { - return handleField(b, field, true, null, true, null); + return handleField(b, (AnalysisField) field, true, null, true, null); } @Override public boolean handleStoreField(GraphBuilderContext b, ValueNode object, ResolvedJavaField field, ValueNode value) { - return handleField(b, field, false, object, false, value); + return handleField(b, (AnalysisField) field, false, object, false, value); } @Override public boolean handleStoreStaticField(GraphBuilderContext b, ResolvedJavaField field, ValueNode value) { - return handleField(b, field, true, null, false, value); + return handleField(b, (AnalysisField) field, true, null, false, value); } - private static boolean handleField(GraphBuilderContext b, ResolvedJavaField field, boolean isStatic, ValueNode receiver, boolean isGet, ValueNode value) { + private static boolean handleField(GraphBuilderContext b, AnalysisField field, boolean isStatic, ValueNode receiver, boolean isGet, ValueNode value) { InjectAccessors injectAccesors = field.getAnnotation(InjectAccessors.class); if (injectAccesors == null) { return false; } + var metaAccess = (AnalysisMetaAccess) b.getMetaAccess(); Class accessorsClass = injectAccesors.value(); - ResolvedJavaType accessorsType = b.getMetaAccess().lookupJavaType(accessorsClass); + AnalysisType accessorsType = metaAccess.lookupJavaType(accessorsClass); String shortName = isGet ? "get" : "set"; String fieldName = field.getName(); String longName = shortName + Character.toUpperCase(fieldName.charAt(0)) + fieldName.substring(1); - ResolvedJavaMethod foundMethod = null; - for (ResolvedJavaMethod method : accessorsType.getDeclaredMethods(false)) { + AnalysisMethod foundMethod = null; + for (AnalysisMethod method : accessorsType.getDeclaredMethods(false)) { if (method.getName().equals(shortName) || method.getName().equals(longName)) { if (foundMethod != null) { error(field, accessorsType, null, "found two methods " + foundMethod.format("%n(%p)") + " and " + method.format("%n(%p)")); @@ -98,10 +99,10 @@ private static boolean handleField(GraphBuilderContext b, ResolvedJavaField fiel error(field, accessorsType, foundMethod, "not enough parameters"); } - JavaType actualReceiver = foundMethod.getSignature().getParameterType(paramIdx, null); - ResolvedJavaType expectedReceiver = field.getDeclaringClass(); + AnalysisType actualReceiver = foundMethod.getSignature().getParameterType(paramIdx); + AnalysisType expectedReceiver = field.getDeclaringClass(); boolean match = false; - for (ResolvedJavaType cur = expectedReceiver; cur != null; cur = cur.getSuperclass()) { + for (AnalysisType cur = expectedReceiver; cur != null; cur = cur.getSuperclass()) { if (actualReceiver.equals(cur)) { match = true; break; @@ -113,9 +114,9 @@ private static boolean handleField(GraphBuilderContext b, ResolvedJavaField fiel paramIdx++; } - JavaType expectedValue = field.getType(); + AnalysisType expectedValue = field.getType(); if (isGet) { - JavaType actualValue = foundMethod.getSignature().getReturnType(null); + AnalysisType actualValue = foundMethod.getSignature().getReturnType(); if (!actualValue.equals(expectedValue)) { error(field, accessorsType, foundMethod, "wrong return type: expected " + expectedValue.toJavaName(true) + ", found " + actualValue.toJavaName(true)); } @@ -125,7 +126,7 @@ private static boolean handleField(GraphBuilderContext b, ResolvedJavaField fiel error(field, accessorsType, foundMethod, "not enough parameters"); } - JavaType actualValue = foundMethod.getSignature().getParameterType(paramIdx, null); + AnalysisType actualValue = foundMethod.getSignature().getParameterType(paramIdx); if (!actualValue.equals(expectedValue)) { error(field, accessorsType, foundMethod, "wrong value type: expected " + expectedValue.toJavaName(true) + ", found " + actualValue.toJavaName(true)); } @@ -148,7 +149,7 @@ private static boolean handleField(GraphBuilderContext b, ResolvedJavaField fiel return true; } - private static void error(ResolvedJavaField field, ResolvedJavaType accessorsType, ResolvedJavaMethod method, String msg) { + private static void error(AnalysisField field, AnalysisType accessorsType, AnalysisMethod method, String msg) { throw VMError.shouldNotReachHere("Error in @" + InjectAccessors.class.getSimpleName() + " handling of field " + field.format("%H.%n") + ", accessors class " + accessorsType.toJavaName(true) + (method == null ? "" : ", method " + method.format("%n(%p)")) + ": " + msg); } diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/phases/InlineBeforeAnalysisPolicyImpl.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/phases/InlineBeforeAnalysisPolicyImpl.java index 92129f854ccf..85f5563d6b47 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/phases/InlineBeforeAnalysisPolicyImpl.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/phases/InlineBeforeAnalysisPolicyImpl.java @@ -25,6 +25,7 @@ package com.oracle.svm.hosted.phases; import com.oracle.graal.pointsto.meta.AnalysisMetaAccess; +import com.oracle.graal.pointsto.meta.AnalysisMethod; import com.oracle.graal.pointsto.phases.InlineBeforeAnalysisPolicy; import com.oracle.svm.core.ParsingReason; import com.oracle.svm.hosted.SVMHost; @@ -35,7 +36,6 @@ import jdk.graal.compiler.nodes.graphbuilderconf.GraphBuilderContext; import jdk.graal.compiler.nodes.graphbuilderconf.InlineInvokePlugin.InlineInfo; import jdk.graal.compiler.nodes.graphbuilderconf.NodePlugin; -import jdk.vm.ci.meta.ResolvedJavaMethod; /** * The defaults for node limits are very conservative. Only small methods should be inlined. The @@ -65,7 +65,7 @@ public InlineBeforeAnalysisPolicyImpl(SVMHost hostVM, InlineBeforeAnalysisPolicy } @Override - protected boolean shouldInlineInvoke(GraphBuilderContext b, ResolvedJavaMethod method, ValueNode[] args) { + protected boolean shouldInlineInvoke(GraphBuilderContext b, AnalysisMethod method, ValueNode[] args) { if (inliningUtils.alwaysInlineInvoke((AnalysisMetaAccess) b.getMetaAccess(), method)) { return true; } @@ -81,7 +81,7 @@ protected boolean shouldInlineInvoke(GraphBuilderContext b, ResolvedJavaMethod m } @Override - protected InlineInfo createInvokeInfo(ResolvedJavaMethod method) { + protected InlineInfo createInvokeInfo(AnalysisMethod method) { return InlineInfo.createStandardInlineInfo(method); } @@ -107,17 +107,17 @@ protected AbstractPolicyScope createRootScope() { @Override protected AbstractPolicyScope openCalleeScope(AbstractPolicyScope outer, AnalysisMetaAccess metaAccess, - ResolvedJavaMethod method, boolean[] constArgsWithReceiver, boolean intrinsifiedMethodHandle) { + AnalysisMethod method, boolean[] constArgsWithReceiver, boolean intrinsifiedMethodHandle) { return inliningUtils.createAccumulativeInlineScope((InlineBeforeAnalysisPolicyUtils.AccumulativeInlineScope) outer, metaAccess, method, constArgsWithReceiver, intrinsifiedMethodHandle); } @Override - protected boolean shouldOmitIntermediateMethodInState(ResolvedJavaMethod method) { + protected boolean shouldOmitIntermediateMethodInState(AnalysisMethod method) { return inliningUtils.shouldOmitIntermediateMethodInState(method); } @Override - protected FixedWithNextNode processInvokeArgs(ResolvedJavaMethod targetMethod, FixedWithNextNode insertionPoint, ValueNode[] arguments, NodeSourcePosition sourcePosition) { + protected FixedWithNextNode processInvokeArgs(AnalysisMethod targetMethod, FixedWithNextNode insertionPoint, ValueNode[] arguments, NodeSourcePosition sourcePosition) { // No action is needed return insertionPoint; } diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/phases/InlineBeforeAnalysisPolicyUtils.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/phases/InlineBeforeAnalysisPolicyUtils.java index 9aecd9816ca3..3fe948fee521 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/phases/InlineBeforeAnalysisPolicyUtils.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/phases/InlineBeforeAnalysisPolicyUtils.java @@ -30,6 +30,23 @@ import java.util.Map; import java.util.Set; +import org.graalvm.nativeimage.AnnotationAccess; + +import com.oracle.graal.pointsto.infrastructure.OriginalClassProvider; +import com.oracle.graal.pointsto.meta.AnalysisMetaAccess; +import com.oracle.graal.pointsto.meta.AnalysisMethod; +import com.oracle.graal.pointsto.meta.AnalysisType; +import com.oracle.graal.pointsto.phases.InlineBeforeAnalysisPolicy; +import com.oracle.svm.core.Uninterruptible; +import com.oracle.svm.core.heap.RestrictHeapAccess; +import com.oracle.svm.core.jdk.VarHandleFeature; +import com.oracle.svm.core.option.HostedOptionKey; +import com.oracle.svm.core.util.VMError; +import com.oracle.svm.hosted.ReachabilityRegistrationNode; +import com.oracle.svm.hosted.SVMHost; +import com.oracle.svm.hosted.methodhandles.MethodHandleInvokerRenamingSubstitutionProcessor; +import com.oracle.svm.util.ReflectionUtil; + import jdk.graal.compiler.api.replacements.Fold; import jdk.graal.compiler.graph.Node; import jdk.graal.compiler.nodes.AbstractBeginNode; @@ -56,25 +73,6 @@ import jdk.graal.compiler.nodes.virtual.VirtualObjectNode; import jdk.graal.compiler.options.Option; import jdk.graal.compiler.replacements.nodes.MethodHandleWithExceptionNode; -import org.graalvm.nativeimage.AnnotationAccess; - -import com.oracle.graal.pointsto.infrastructure.OriginalClassProvider; -import com.oracle.graal.pointsto.meta.AnalysisMetaAccess; -import com.oracle.graal.pointsto.meta.AnalysisMethod; -import com.oracle.graal.pointsto.meta.AnalysisType; -import com.oracle.graal.pointsto.phases.InlineBeforeAnalysisPolicy; -import com.oracle.svm.core.Uninterruptible; -import com.oracle.svm.core.heap.RestrictHeapAccess; -import com.oracle.svm.core.jdk.VarHandleFeature; -import com.oracle.svm.core.option.HostedOptionKey; -import com.oracle.svm.core.util.VMError; -import com.oracle.svm.hosted.ReachabilityRegistrationNode; -import com.oracle.svm.hosted.SVMHost; -import com.oracle.svm.hosted.methodhandles.MethodHandleInvokerRenamingSubstitutionProcessor; -import com.oracle.svm.util.ReflectionUtil; - -import jdk.vm.ci.meta.ResolvedJavaMethod; -import jdk.vm.ci.meta.ResolvedJavaType; public class InlineBeforeAnalysisPolicyUtils { public static class Options { @@ -108,9 +106,8 @@ public static class Options { private AnalysisType methodHandleType; private AnalysisType varHandleGuardsType; - public static boolean inliningAllowed(SVMHost hostVM, GraphBuilderContext b, ResolvedJavaMethod method) { + public static boolean inliningAllowed(SVMHost hostVM, GraphBuilderContext b, AnalysisMethod callee) { AnalysisMethod caller = (AnalysisMethod) b.getMethod(); - AnalysisMethod callee = (AnalysisMethod) method; if (hostVM.neverInlineTrivial(caller, callee)) { return false; } @@ -143,7 +140,7 @@ public static boolean inliningAllowed(SVMHost hostVM, GraphBuilderContext b, Res return true; } - public boolean alwaysInlineInvoke(@SuppressWarnings("unused") AnalysisMetaAccess metaAccess, @SuppressWarnings("unused") ResolvedJavaMethod method) { + public boolean alwaysInlineInvoke(@SuppressWarnings("unused") AnalysisMetaAccess metaAccess, @SuppressWarnings("unused") AnalysisMethod method) { return false; } @@ -173,7 +170,7 @@ public void abortCalleeScope(InlineBeforeAnalysisPolicy.AbstractPolicyScope call } @Override - public boolean processNode(AnalysisMetaAccess metaAccess, ResolvedJavaMethod method, Node node) { + public boolean processNode(AnalysisMetaAccess metaAccess, AnalysisMethod method, Node node) { // always inlining return true; } @@ -222,7 +219,7 @@ private AccumulativeCounters(int maxNodes, int maxInvokes, int maxInliningDepth, * aborted. */ public AccumulativeInlineScope createAccumulativeInlineScope(AccumulativeInlineScope outer, AnalysisMetaAccess metaAccess, - ResolvedJavaMethod method, boolean[] constArgsWithReceiver, boolean intrinsifiedMethodHandle) { + AnalysisMethod method, boolean[] constArgsWithReceiver, boolean intrinsifiedMethodHandle) { AccumulativeCounters accumulativeCounters; int depth; if (outer == null) { @@ -264,11 +261,11 @@ public AccumulativeInlineScope createAccumulativeInlineScope(AccumulativeInlineS return new AccumulativeInlineScope(accumulativeCounters, depth); } - private boolean isMethodHandleIntrinsificationRoot(AnalysisMetaAccess metaAccess, ResolvedJavaMethod method, boolean[] constArgsWithReceiver) { + private boolean isMethodHandleIntrinsificationRoot(AnalysisMetaAccess metaAccess, AnalysisMethod method, boolean[] constArgsWithReceiver) { return (isVarHandleMethod(metaAccess, method) || hasConstantMethodHandleParameter(metaAccess, method, constArgsWithReceiver)) && !isIgnoredMethodHandleMethod(method); } - private boolean hasConstantMethodHandleParameter(AnalysisMetaAccess metaAccess, ResolvedJavaMethod method, boolean[] constArgsWithReceiver) { + private boolean hasConstantMethodHandleParameter(AnalysisMetaAccess metaAccess, AnalysisMethod method, boolean[] constArgsWithReceiver) { if (methodHandleType == null) { methodHandleType = metaAccess.lookupJavaType(MethodHandle.class); } @@ -280,7 +277,7 @@ private boolean hasConstantMethodHandleParameter(AnalysisMetaAccess metaAccess, return false; } - private static ResolvedJavaType getParameterType(ResolvedJavaMethod method, int index) { + private static AnalysisType getParameterType(AnalysisMethod method, int index) { int i = index; if (!method.isStatic()) { if (i == 0) { // receiver @@ -288,7 +285,7 @@ private static ResolvedJavaType getParameterType(ResolvedJavaMethod method, int } i--; } - return (ResolvedJavaType) method.getSignature().getParameterType(i, null); + return method.getSignature().getParameterType(i); } /** @@ -299,14 +296,14 @@ private static ResolvedJavaType getParameterType(ResolvedJavaMethod method, int * See the documentation in {@link VarHandleFeature} for more information on the overall * VarHandle support. */ - private boolean isVarHandleMethod(AnalysisMetaAccess metaAccess, ResolvedJavaMethod method) { + private boolean isVarHandleMethod(AnalysisMetaAccess metaAccess, AnalysisMethod method) { if (varHandleGuardsType == null) { varHandleGuardsType = metaAccess.lookupJavaType(ReflectionUtil.lookupClass(false, "java.lang.invoke.VarHandleGuards")); } return method.getDeclaringClass().equals(varHandleGuardsType); } - private static boolean isIgnoredMethodHandleMethod(ResolvedJavaMethod method) { + private static boolean isIgnoredMethodHandleMethod(AnalysisMethod method) { Class declaringClass = OriginalClassProvider.getJavaClass(method.getDeclaringClass()); Set ignoredMethods = IGNORED_METHOD_HANDLE_METHODS.get(declaringClass); return ignoredMethods != null && ignoredMethods.contains(method.getName()); @@ -363,7 +360,7 @@ public void abortCalleeScope(InlineBeforeAnalysisPolicy.AbstractPolicyScope call } @Override - public boolean processNode(AnalysisMetaAccess metaAccess, ResolvedJavaMethod method, Node node) { + public boolean processNode(AnalysisMetaAccess metaAccess, AnalysisMethod method, Node node) { if (node instanceof StartNode || node instanceof ParameterNode || node instanceof ReturnNode || node instanceof UnwindNode || node instanceof CallTargetNode || node instanceof MethodHandleWithExceptionNode) { /* @@ -471,7 +468,7 @@ public String toString() { } } - private static boolean inlineForMethodHandleIntrinsification(ResolvedJavaMethod method) { + private static boolean inlineForMethodHandleIntrinsification(AnalysisMethod method) { String className = method.getDeclaringClass().toJavaName(true); if (className.startsWith("java.lang.invoke") && !className.contains("InvokerBytecodeGenerator")) { /* @@ -493,7 +490,7 @@ private static boolean inlineForMethodHandleIntrinsification(ResolvedJavaMethod * * @see MethodHandleInvokerRenamingSubstitutionProcessor */ - protected boolean shouldOmitIntermediateMethodInState(ResolvedJavaMethod method) { + protected boolean shouldOmitIntermediateMethodInState(AnalysisMethod method) { return method.isAnnotationPresent(COMPILED_LAMBDA_FORM_ANNOTATION); } } diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/reflect/ReflectionExpandSignatureMethod.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/reflect/ReflectionExpandSignatureMethod.java index c7729a701ed0..209788203da8 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/reflect/ReflectionExpandSignatureMethod.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/reflect/ReflectionExpandSignatureMethod.java @@ -24,6 +24,15 @@ */ package com.oracle.svm.hosted.reflect; +import com.oracle.graal.pointsto.meta.AnalysisMethod; +import com.oracle.graal.pointsto.meta.AnalysisType; +import com.oracle.graal.pointsto.meta.HostedProviders; +import com.oracle.svm.core.graal.code.SubstrateCallingConventionKind; +import com.oracle.svm.core.reflect.ReflectionAccessorHolder.MethodInvokeFunctionPointer; +import com.oracle.svm.core.reflect.SubstrateConstructorAccessor; +import com.oracle.svm.core.reflect.SubstrateMethodAccessor; +import com.oracle.svm.hosted.code.NonBytecodeMethod; + import jdk.graal.compiler.core.common.type.StampFactory; import jdk.graal.compiler.core.common.type.StampPair; import jdk.graal.compiler.debug.DebugContext; @@ -33,14 +42,6 @@ import jdk.graal.compiler.nodes.InvokeWithExceptionNode; import jdk.graal.compiler.nodes.StructuredGraph; import jdk.graal.compiler.nodes.ValueNode; - -import com.oracle.graal.pointsto.meta.HostedProviders; -import com.oracle.svm.core.graal.code.SubstrateCallingConventionKind; -import com.oracle.svm.core.reflect.ReflectionAccessorHolder.MethodInvokeFunctionPointer; -import com.oracle.svm.core.reflect.SubstrateConstructorAccessor; -import com.oracle.svm.core.reflect.SubstrateMethodAccessor; -import com.oracle.svm.hosted.code.NonBytecodeMethod; - import jdk.vm.ci.meta.JavaKind; import jdk.vm.ci.meta.ResolvedJavaMethod; import jdk.vm.ci.meta.ResolvedJavaType; @@ -75,18 +76,18 @@ public ReflectionExpandSignatureMethod(String name, ResolvedJavaMethod prototype * in different classes. */ @Override - public StructuredGraph buildGraph(DebugContext ctx, ResolvedJavaMethod m, HostedProviders providers, Purpose purpose) { - ReflectionGraphKit graphKit = new ReflectionGraphKit(ctx, providers, m, purpose); + public StructuredGraph buildGraph(DebugContext ctx, AnalysisMethod method, HostedProviders providers, Purpose purpose) { + ReflectionGraphKit kit = new ReflectionGraphKit(ctx, providers, method, purpose); - ValueNode receiver = graphKit.loadLocal(0, JavaKind.Object); - ValueNode argumentArray = graphKit.loadLocal(1, JavaKind.Object); + ValueNode receiver = kit.loadLocal(0, JavaKind.Object); + ValueNode argumentArray = kit.loadLocal(1, JavaKind.Object); /* The invokedMethod is a Word type, so not yet a primitive in the signature. */ - ValueNode invokedMethod = graphKit.loadLocal(2, JavaKind.Object); + ValueNode invokedMethod = kit.loadLocal(2, JavaKind.Object); /* Caller-sensitive-adapter methods have an additional Class parameter. */ - ValueNode callerClass = callerSensitiveAdapter ? graphKit.loadLocal(3, JavaKind.Object) : null; + ValueNode callerClass = callerSensitiveAdapter ? kit.loadLocal(3, JavaKind.Object) : null; /* Clear all locals, so that they are not alive and spilled at method calls. */ - graphKit.getFrameState().clearLocals(); + kit.getFrameState().clearLocals(); int receiverOffset = isStatic ? 0 : 1; int argsCount = argTypes.length + receiverOffset + (callerSensitiveAdapter ? 1 : 0); @@ -97,42 +98,42 @@ public StructuredGraph buildGraph(DebugContext ctx, ResolvedJavaMethod m, Hosted * The receiver is already null-checked and type-checked at the call site in * SubstrateMethodAccessor. */ - signature[0] = providers.getMetaAccess().lookupJavaType(Object.class); + signature[0] = kit.getMetaAccess().lookupJavaType(Object.class); args[0] = receiver; } if (callerSensitiveAdapter) { - signature[argsCount - 1] = providers.getMetaAccess().lookupJavaType(Class.class); + signature[argsCount - 1] = kit.getMetaAccess().lookupJavaType(Class.class); args[argsCount - 1] = callerClass; } - graphKit.fillArgsArray(argumentArray, receiverOffset, args, argTypes); + kit.fillArgsArray(argumentArray, receiverOffset, args, argTypes); for (int i = 0; i < argTypes.length; i++) { - signature[i + receiverOffset] = providers.getMetaAccess().lookupJavaType(argTypes[i]); + signature[i + receiverOffset] = kit.getMetaAccess().lookupJavaType(argTypes[i]); } - CallTargetNode callTarget = graphKit.append(new IndirectCallTargetNode(invokedMethod, args, StampPair.createSingle(StampFactory.forKind(returnKind)), signature, null, + CallTargetNode callTarget = kit.append(new IndirectCallTargetNode(invokedMethod, args, StampPair.createSingle(StampFactory.forKind(returnKind)), signature, null, SubstrateCallingConventionKind.Java.toType(true), InvokeKind.Static)); - InvokeWithExceptionNode invoke = graphKit.startInvokeWithException(callTarget, graphKit.getFrameState(), graphKit.bci()); - graphKit.exceptionPart(); - graphKit.branchToInvocationTargetException(graphKit.exceptionObject()); - graphKit.endInvokeWithException(); + InvokeWithExceptionNode invoke = kit.startInvokeWithException(callTarget, kit.getFrameState(), kit.bci()); + kit.exceptionPart(); + kit.branchToInvocationTargetException(kit.exceptionObject()); + kit.endInvokeWithException(); ValueNode returnValue; if (returnKind == JavaKind.Void) { - returnValue = graphKit.createObject(null); + returnValue = kit.createObject(null); } else { returnValue = invoke; if (returnKind.isPrimitive()) { - ResolvedJavaType boxedRetType = graphKit.getMetaAccess().lookupJavaType(returnKind.toBoxedJavaClass()); - returnValue = graphKit.createBoxing(returnValue, returnKind, boxedRetType); + AnalysisType boxedRetType = kit.getMetaAccess().lookupJavaType(returnKind.toBoxedJavaClass()); + returnValue = kit.createBoxing(returnValue, returnKind, boxedRetType); } } - graphKit.createReturn(returnValue, JavaKind.Object); + kit.createReturn(returnValue, JavaKind.Object); - graphKit.emitIllegalArgumentException(isStatic ? null : receiver, argumentArray); - graphKit.emitInvocationTargetException(); + kit.emitIllegalArgumentException(isStatic ? null : receiver, argumentArray); + kit.emitInvocationTargetException(); - return graphKit.finalizeGraph(); + return kit.finalizeGraph(); } } diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/reflect/ReflectionMetadataEncoderImpl.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/reflect/ReflectionMetadataEncoderImpl.java index e4ce764a378a..91366490cf79 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/reflect/ReflectionMetadataEncoderImpl.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/reflect/ReflectionMetadataEncoderImpl.java @@ -403,7 +403,7 @@ public void addReflectionExecutableMetadata(MetaAccessProvider metaAccess, Hoste HostedType[] parameterTypes = getParameterTypes(hostedMethod); /* Reflect method because substitution of Object.hashCode() is private */ int modifiers = reflectMethod.getModifiers(); - HostedType returnType = (HostedType) hostedMethod.getSignature().getReturnType(null); + HostedType returnType = hostedMethod.getSignature().getReturnType(); HostedType[] exceptionTypes = getExceptionTypes(metaAccess, reflectMethod); String signature = getSignature(reflectMethod); @@ -636,7 +636,7 @@ public void addNegativeConstructorQueryMetadata(HostedType declaringClass, Hoste private static HostedType[] getParameterTypes(HostedMethod method) { HostedType[] parameterTypes = new HostedType[method.getSignature().getParameterCount(false)]; for (int i = 0; i < parameterTypes.length; ++i) { - parameterTypes[i] = (HostedType) method.getSignature().getParameterType(i, null); + parameterTypes[i] = method.getSignature().getParameterType(i); } return parameterTypes; } @@ -644,7 +644,7 @@ private static HostedType[] getParameterTypes(HostedMethod method) { private static String[] getParameterTypeNames(HostedMethod method) { String[] parameterTypeNames = new String[method.getSignature().getParameterCount(false)]; for (int i = 0; i < parameterTypeNames.length; ++i) { - parameterTypeNames[i] = method.getSignature().getParameterType(i, null).toJavaName(); + parameterTypeNames[i] = method.getSignature().getParameterType(i).toJavaName(); } return parameterTypeNames; } diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/substitute/AnnotatedMethod.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/substitute/AnnotatedMethod.java index d7b03ca04a42..b6fa64198f48 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/substitute/AnnotatedMethod.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/substitute/AnnotatedMethod.java @@ -30,18 +30,19 @@ import java.lang.reflect.Type; import java.util.Arrays; -import jdk.graal.compiler.debug.DebugContext; -import jdk.graal.compiler.nodes.StructuredGraph; import org.graalvm.nativeimage.AnnotationAccess; import com.oracle.graal.pointsto.infrastructure.GraphProvider; import com.oracle.graal.pointsto.infrastructure.OriginalMethodProvider; +import com.oracle.graal.pointsto.meta.AnalysisMethod; import com.oracle.graal.pointsto.meta.HostedProviders; import com.oracle.svm.core.util.VMError; import com.oracle.svm.hosted.annotation.AnnotationValue; import com.oracle.svm.hosted.annotation.AnnotationWrapper; import com.oracle.svm.hosted.annotation.SubstrateAnnotationExtractor; +import jdk.graal.compiler.debug.DebugContext; +import jdk.graal.compiler.nodes.StructuredGraph; import jdk.vm.ci.meta.Constant; import jdk.vm.ci.meta.ConstantPool; import jdk.vm.ci.meta.ExceptionHandler; @@ -84,17 +85,17 @@ public Signature getSignature() { } @Override - public StructuredGraph buildGraph(DebugContext debug, ResolvedJavaMethod method, HostedProviders providers, Purpose purpose) { - if (original instanceof GraphProvider) { - return ((GraphProvider) original).buildGraph(debug, method, providers, purpose); + public StructuredGraph buildGraph(DebugContext debug, AnalysisMethod method, HostedProviders providers, Purpose purpose) { + if (original instanceof GraphProvider graphProvider) { + return graphProvider.buildGraph(debug, method, providers, purpose); } return null; } @Override public boolean allowRuntimeCompilation() { - if (original instanceof GraphProvider) { - return ((GraphProvider) original).allowRuntimeCompilation(); + if (original instanceof GraphProvider graphProvider) { + return graphProvider.allowRuntimeCompilation(); } return true; } diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/substitute/DeletedMethod.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/substitute/DeletedMethod.java index 3f079b169e83..8c698dacf7b2 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/substitute/DeletedMethod.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/substitute/DeletedMethod.java @@ -27,6 +27,7 @@ import java.lang.reflect.Method; import java.lang.reflect.Modifier; +import com.oracle.graal.pointsto.meta.AnalysisMethod; import com.oracle.graal.pointsto.meta.HostedProviders; import com.oracle.svm.core.annotate.Delete; import com.oracle.svm.core.option.SubstrateOptionsParser; @@ -38,7 +39,6 @@ import com.oracle.svm.util.ReflectionUtil; import jdk.graal.compiler.debug.DebugContext; -import jdk.graal.compiler.java.FrameStateBuilder; import jdk.graal.compiler.nodes.CallTargetNode.InvokeKind; import jdk.graal.compiler.nodes.ConstantNode; import jdk.graal.compiler.nodes.StructuredGraph; @@ -78,26 +78,18 @@ public int getModifiers() { } @Override - public StructuredGraph buildGraph(DebugContext debug, ResolvedJavaMethod method, HostedProviders providers, Purpose purpose) { - return buildGraph(debug, method, providers, message, purpose); + public StructuredGraph buildGraph(DebugContext debug, AnalysisMethod method, HostedProviders providers, Purpose purpose) { + return buildGraph(debug, method, providers, message); } - public static StructuredGraph buildGraph(DebugContext debug, ResolvedJavaMethod method, HostedProviders providers, String message, Purpose purpose) { + public static StructuredGraph buildGraph(DebugContext debug, AnalysisMethod method, HostedProviders providers, String message) { HostedGraphKit kit = new HostedGraphKit(debug, providers, method); - StructuredGraph graph = kit.getGraph(); - FrameStateBuilder state = new FrameStateBuilder(null, method, graph); - state.initializeForMethodStart(null, true, providers.getGraphBuilderPlugins()); - /* - * A random, but unique and consistent, number for every invoke. This is necessary because - * we, e.g., look up static analysis results by bci. - */ - int bci = 0; - graph.start().setStateAfter(state.create(bci++, graph.start())); + kit.getGraph().start().setStateAfter(kit.getFrameState().create(kit.bci(), kit.getGraph().start())); String msg = AnnotationSubstitutionProcessor.deleteErrorMessage(method, message, false); - ValueNode msgNode = ConstantNode.forConstant(providers.getConstantReflection().forString(msg), providers.getMetaAccess(), graph); - ValueNode exceptionNode = kit.createInvokeWithExceptionAndUnwind(providers.getMetaAccess().lookupJavaMethod(reportErrorMethod), InvokeKind.Static, state, bci++, msgNode); + ValueNode msgNode = ConstantNode.forConstant(kit.getConstantReflection().forString(msg), kit.getMetaAccess(), kit.getGraph()); + ValueNode exceptionNode = kit.createInvokeWithExceptionAndUnwind(kit.getMetaAccess().lookupJavaMethod(reportErrorMethod), InvokeKind.Static, kit.getFrameState(), kit.bci(), msgNode); kit.append(new UnwindNode(exceptionNode)); return kit.finalizeGraph(); diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/substitute/PolymorphicSignatureWrapperMethod.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/substitute/PolymorphicSignatureWrapperMethod.java index 0a433748e3eb..3dd291cd1be9 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/substitute/PolymorphicSignatureWrapperMethod.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/substitute/PolymorphicSignatureWrapperMethod.java @@ -31,10 +31,11 @@ import java.lang.invoke.MethodHandle; import java.lang.reflect.AnnotatedElement; import java.lang.reflect.Type; +import java.util.ArrayList; import java.util.List; import com.oracle.graal.pointsto.infrastructure.GraphProvider; -import com.oracle.graal.pointsto.meta.AnalysisMetaAccess; +import com.oracle.graal.pointsto.meta.AnalysisMethod; import com.oracle.graal.pointsto.meta.HostedProviders; import com.oracle.svm.core.invoke.MethodHandleUtils; import com.oracle.svm.core.invoke.Target_java_lang_invoke_MemberName; @@ -82,28 +83,27 @@ public class PolymorphicSignatureWrapperMethod implements ResolvedJavaMethod, Gr } @Override - public StructuredGraph buildGraph(DebugContext debug, ResolvedJavaMethod method, HostedProviders providers, Purpose purpose) { - AnalysisMetaAccess metaAccess = (AnalysisMetaAccess) providers.getMetaAccess(); + public StructuredGraph buildGraph(DebugContext debug, AnalysisMethod method, HostedProviders providers, Purpose purpose) { HostedGraphKit kit = new HostedGraphKit(debug, providers, method); - List args = kit.loadArguments(method.toParameterTypes()); + List args = new ArrayList<>(kit.getInitialArguments()); ValueNode receiver = null; if (!substitutionBaseMethod.isStatic()) { receiver = args.remove(0); } - ValueNode parameterArray = kit.append(new NewArrayNode(metaAccess.lookupJavaType(Object.class), kit.createInt(args.size()), true)); + ValueNode parameterArray = kit.append(new NewArrayNode(kit.getMetaAccess().lookupJavaType(Object.class), kit.createInt(args.size()), true)); for (int i = 0; i < args.size(); ++i) { ValueNode arg = args.get(i); if (arg.getStackKind().isPrimitive()) { - arg = kit.createBoxing(arg, arg.getStackKind(), metaAccess.lookupJavaType(arg.getStackKind().toBoxedJavaClass())); + arg = kit.createBoxing(arg, arg.getStackKind(), kit.getMetaAccess().lookupJavaType(arg.getStackKind().toBoxedJavaClass())); } StateSplit storeIndexedNode = (StateSplit) kit.createStoreIndexed(parameterArray, i, JavaKind.Object, arg); storeIndexedNode.setStateAfter(kit.getFrameState().create(kit.bci(), storeIndexedNode)); } - ResolvedJavaMethod invokeTarget = metaAccess.getUniverse().lookup(substitutionBaseMethod.getOriginal()); + AnalysisMethod invokeTarget = kit.getMetaAccess().getUniverse().lookup(substitutionBaseMethod.getOriginal()); InvokeWithExceptionNode invoke; if (substitutionBaseMethod.isStatic()) { invoke = kit.createInvokeWithExceptionAndUnwind(invokeTarget, CallTargetNode.InvokeKind.Static, kit.getFrameState(), kit.bci(), parameterArray); @@ -141,7 +141,7 @@ public StructuredGraph buildGraph(DebugContext debug, ResolvedJavaMethod method, case Int: case Long: ValueNode methodHandleOrMemberName; - ResolvedJavaMethod unboxMethod; + AnalysisMethod unboxMethod; try { String unboxMethodName = returnKind.toString() + "Unbox"; switch (substitutionBaseMethod.getName()) { @@ -149,7 +149,7 @@ public StructuredGraph buildGraph(DebugContext debug, ResolvedJavaMethod method, case "invokeExact": case "invoke": methodHandleOrMemberName = receiver; - unboxMethod = metaAccess.lookupJavaMethod( + unboxMethod = kit.getMetaAccess().lookupJavaMethod( MethodHandleUtils.class.getMethod(unboxMethodName, Object.class, MethodHandle.class)); break; case "linkToVirtual": @@ -157,7 +157,7 @@ public StructuredGraph buildGraph(DebugContext debug, ResolvedJavaMethod method, case "linkToInterface": case "linkToSpecial": methodHandleOrMemberName = args.get(args.size() - 1); - unboxMethod = metaAccess.lookupJavaMethod( + unboxMethod = kit.getMetaAccess().lookupJavaMethod( MethodHandleUtils.class.getMethod(unboxMethodName, Object.class, Target_java_lang_invoke_MemberName.class)); break; default: diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/substitute/SubstitutionMethod.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/substitute/SubstitutionMethod.java index 3a41c9d2a0f8..aec7d8df4c1b 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/substitute/SubstitutionMethod.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/substitute/SubstitutionMethod.java @@ -32,14 +32,14 @@ import java.lang.reflect.Executable; import java.lang.reflect.Type; -import jdk.graal.compiler.debug.DebugContext; -import jdk.graal.compiler.nodes.StructuredGraph; - import com.oracle.graal.pointsto.infrastructure.GraphProvider; import com.oracle.graal.pointsto.infrastructure.OriginalMethodProvider; +import com.oracle.graal.pointsto.meta.AnalysisMethod; import com.oracle.graal.pointsto.meta.HostedProviders; import com.oracle.svm.hosted.annotation.AnnotationWrapper; +import jdk.graal.compiler.debug.DebugContext; +import jdk.graal.compiler.nodes.StructuredGraph; import jdk.vm.ci.meta.Constant; import jdk.vm.ci.meta.ConstantPool; import jdk.vm.ci.meta.ExceptionHandler; @@ -113,17 +113,17 @@ public Signature getSignature() { } @Override - public StructuredGraph buildGraph(DebugContext debug, ResolvedJavaMethod method, HostedProviders providers, Purpose purpose) { - if (annotated instanceof GraphProvider) { - return ((GraphProvider) annotated).buildGraph(debug, method, providers, purpose); + public StructuredGraph buildGraph(DebugContext debug, AnalysisMethod method, HostedProviders providers, Purpose purpose) { + if (annotated instanceof GraphProvider graphProvider) { + return graphProvider.buildGraph(debug, method, providers, purpose); } return null; } @Override public boolean allowRuntimeCompilation() { - if (annotated instanceof GraphProvider) { - return ((GraphProvider) annotated).allowRuntimeCompilation(); + if (annotated instanceof GraphProvider graphProvider) { + return graphProvider.allowRuntimeCompilation(); } return true; } From 228fe44653185712553db903d3c8225c2fe88dcc Mon Sep 17 00:00:00 2001 From: Allan Gregersen Date: Fri, 8 Dec 2023 10:03:38 +0100 Subject: [PATCH 153/593] stop collecting subtypes of j.l.Object for redefinition purposes, since that class cannot change at runtime --- .../src/com/oracle/truffle/espresso/impl/ObjectKlass.java | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/impl/ObjectKlass.java b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/impl/ObjectKlass.java index 4107c4982c69..602381286431 100644 --- a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/impl/ObjectKlass.java +++ b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/impl/ObjectKlass.java @@ -238,6 +238,10 @@ private static boolean isEnumValuesField(LinkedField lkStaticFields) { private void addSubType(ObjectKlass objectKlass) { // We only build subtypes model iff jdwp is enabled if (getContext().getEspressoEnv().JDWPOptions != null) { + if (this == getMeta().java_lang_Object) { + // skip collecting subtypes for j.l.Object because that can't ever change at runtime + return; + } if (subTypes == null) { synchronized (this) { // double-checked locking @@ -254,6 +258,7 @@ private void addSubType(ObjectKlass objectKlass) { public void removeAsSubType() { if (getSuperKlass() != getMeta().java_lang_Object) { + // we're not collecting subtypes of j.l.Object because that can't ever change at runtime getSuperKlass().removeSubType(this); } for (ObjectKlass superInterface : getSuperInterfaces()) { From 431303dd0010a6c562f60cb1ef114e5d029e1a89 Mon Sep 17 00:00:00 2001 From: Tomas Zezula Date: Thu, 7 Dec 2023 16:44:31 +0100 Subject: [PATCH 154/593] [GR-50682] Fixed espresso-meta-hello-world gate. --- sdk/CHANGELOG.md | 2 ++ .../oracle/truffle/polyglot/EngineAccessor.java | 14 +++++++++++--- 2 files changed, 13 insertions(+), 3 deletions(-) diff --git a/sdk/CHANGELOG.md b/sdk/CHANGELOG.md index 267ccb5eb63a..71385af4d5aa 100644 --- a/sdk/CHANGELOG.md +++ b/sdk/CHANGELOG.md @@ -8,6 +8,8 @@ This changelog summarizes major changes between GraalVM SDK versions. The main f * (GR-49386) Added the ability to use `Value#as(ByteSequence.class)` to map guest language byte buffers (`Value#hasBufferElements()`) to the read-only `ByteSequence` interface in order to access the bytes without copying the guest language buffer. * (GR-49386) Custom implementations of `ByteSequence`, like the values returned by `ByteSequence.create(byte[])`, are now interpreted by guest languages as buffers. * (GR-38404) Added the ability to use `Value#as(Collection.class)` to map guest language arrays (`Value#hasArrayElements()`) to the `Collection` interface in order to access the array elements without copying the guest language array. +* (GR-50682) For languages and instruments loading, the context classloader of the thread that initiates the Engine creation is employed. The system classloader is used only if the context classloader is not set. Originally both classloaders were used. + ## Version 23.1.0 * (GR-43819) The GraalVM SDK was split into several more fine-grained modules. The use of the graalvm-sdk module is now deprecated. Please update your Maven and module dependencies accordingly. Note that all APIs remain compatible. The following new modules are available: diff --git a/truffle/src/com.oracle.truffle.polyglot/src/com/oracle/truffle/polyglot/EngineAccessor.java b/truffle/src/com.oracle.truffle.polyglot/src/com/oracle/truffle/polyglot/EngineAccessor.java index f9b45f43b3ab..f985b9ddf89a 100644 --- a/truffle/src/com.oracle.truffle.polyglot/src/com/oracle/truffle/polyglot/EngineAccessor.java +++ b/truffle/src/com.oracle.truffle.polyglot/src/com/oracle/truffle/polyglot/EngineAccessor.java @@ -158,10 +158,18 @@ private static List locatorLoaders() { return null; } List suppliers = new ArrayList<>(2 + loaders.size()); - suppliers.add(new ModulePathLoaderSupplier(ClassLoader.getSystemClassLoader())); - suppliers.add(new WeakModulePathLoaderSupplier(Thread.currentThread().getContextClassLoader())); + ClassLoader systemClassLoader = ClassLoader.getSystemClassLoader(); + if (isValidLoader(systemClassLoader)) { + suppliers.add(new ModulePathLoaderSupplier(systemClassLoader)); + } + ClassLoader contextClassLoader = Thread.currentThread().getContextClassLoader(); + if (isValidLoader(contextClassLoader)) { + suppliers.add(new WeakModulePathLoaderSupplier(contextClassLoader)); + } for (ClassLoader loader : loaders) { - suppliers.add(new StrongClassLoaderSupplier(loader)); + if (isValidLoader(loader)) { + suppliers.add(new StrongClassLoaderSupplier(loader)); + } } return suppliers; } From c0275b0d840ee609e3312d9ccaca1c1a1f56c39b Mon Sep 17 00:00:00 2001 From: Tomas Zezula Date: Fri, 8 Dec 2023 11:49:13 +0100 Subject: [PATCH 155/593] [GR-50785] Redundant condition in nativebridge. --- .../src/org/graalvm/nativebridge/BinaryOutput.java | 5 ++--- .../src/com/oracle/svm/truffle/isolated/BinaryOutput.java | 5 ++--- .../truffle/runtime/hotspot/libgraal/BinaryOutput.java | 5 ++--- 3 files changed, 6 insertions(+), 9 deletions(-) diff --git a/sdk/src/org.graalvm.nativebridge/src/org/graalvm/nativebridge/BinaryOutput.java b/sdk/src/org.graalvm.nativebridge/src/org/graalvm/nativebridge/BinaryOutput.java index 6146c9a9b00a..4a24cb3d07d3 100644 --- a/sdk/src/org.graalvm.nativebridge/src/org/graalvm/nativebridge/BinaryOutput.java +++ b/sdk/src/org.graalvm.nativebridge/src/org/graalvm/nativebridge/BinaryOutput.java @@ -270,7 +270,7 @@ public static boolean isTypedValue(Object value) { if (value == null) { return true; } - return value instanceof Object[] || value == null || value instanceof Boolean || value instanceof Byte || + return value instanceof Object[] || value instanceof Boolean || value instanceof Byte || value instanceof Short || value instanceof Character || value instanceof Integer || value instanceof Long || value instanceof Float || value instanceof Double || value instanceof String; } @@ -285,8 +285,7 @@ public static boolean isTypedValue(Object value) { * @see #isTypedValue(Object) to find out whether a value can be serialized. */ public final void writeTypedValue(Object value) throws IllegalArgumentException { - if (value instanceof Object[]) { - Object[] arr = (Object[]) value; + if (value instanceof Object[] arr) { writeByte(ARRAY); writeInt(arr.length); for (Object arrElement : arr) { diff --git a/substratevm/src/com.oracle.svm.truffle/src/com/oracle/svm/truffle/isolated/BinaryOutput.java b/substratevm/src/com.oracle.svm.truffle/src/com/oracle/svm/truffle/isolated/BinaryOutput.java index 8c251b193196..fa12e30c4b82 100644 --- a/substratevm/src/com.oracle.svm.truffle/src/com/oracle/svm/truffle/isolated/BinaryOutput.java +++ b/substratevm/src/com.oracle.svm.truffle/src/com/oracle/svm/truffle/isolated/BinaryOutput.java @@ -248,7 +248,7 @@ public static boolean isTypedValue(Object value) { if (value == null) { return true; } - return value instanceof Object[] || value == null || value instanceof Boolean || value instanceof Byte || + return value instanceof Object[] || value instanceof Boolean || value instanceof Byte || value instanceof Short || value instanceof Character || value instanceof Integer || value instanceof Long || value instanceof Float || value instanceof Double || value instanceof String; } @@ -263,8 +263,7 @@ public static boolean isTypedValue(Object value) { * @see #isTypedValue(Object) to find out whether a value can be serialized. */ public final void writeTypedValue(Object value) throws IllegalArgumentException { - if (value instanceof Object[]) { - Object[] arr = (Object[]) value; + if (value instanceof Object[] arr) { writeByte(ARRAY); writeInt(arr.length); for (Object arrElement : arr) { diff --git a/truffle/src/com.oracle.truffle.runtime/src/com/oracle/truffle/runtime/hotspot/libgraal/BinaryOutput.java b/truffle/src/com.oracle.truffle.runtime/src/com/oracle/truffle/runtime/hotspot/libgraal/BinaryOutput.java index c127987fdda9..17e037e5bd32 100644 --- a/truffle/src/com.oracle.truffle.runtime/src/com/oracle/truffle/runtime/hotspot/libgraal/BinaryOutput.java +++ b/truffle/src/com.oracle.truffle.runtime/src/com/oracle/truffle/runtime/hotspot/libgraal/BinaryOutput.java @@ -269,7 +269,7 @@ public static boolean isTypedValue(Object value) { if (value == null) { return true; } - return value instanceof Object[] || value == null || value instanceof Boolean || value instanceof Byte || + return value instanceof Object[] || value instanceof Boolean || value instanceof Byte || value instanceof Short || value instanceof Character || value instanceof Integer || value instanceof Long || value instanceof Float || value instanceof Double || value instanceof String; } @@ -284,8 +284,7 @@ public static boolean isTypedValue(Object value) { * @see #isTypedValue(Object) to find out whether a value can be serialized. */ public final void writeTypedValue(Object value) throws IllegalArgumentException { - if (value instanceof Object[]) { - Object[] arr = (Object[]) value; + if (value instanceof Object[] arr) { writeByte(ARRAY); writeInt(arr.length); for (Object arrElement : arr) { From 0cffe2818d0aaf7e74b7c69ea4232684e8fec579 Mon Sep 17 00:00:00 2001 From: Gilles Duboscq Date: Fri, 8 Dec 2023 17:52:51 +0100 Subject: [PATCH 156/593] Improve double-checked locking for call targets --- .../oracle/truffle/espresso/impl/Method.java | 40 ++++++++++--------- 1 file changed, 22 insertions(+), 18 deletions(-) diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/impl/Method.java b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/impl/Method.java index d4bb9f1961d8..ad5c2980fd9b 100644 --- a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/impl/Method.java +++ b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/impl/Method.java @@ -42,6 +42,7 @@ import static com.oracle.truffle.espresso.classfile.Constants.REF_invokeVirtual; import java.io.PrintStream; +import java.lang.invoke.VarHandle; import java.lang.reflect.Modifier; import java.util.ArrayList; import java.util.Arrays; @@ -1229,6 +1230,8 @@ public RuntimeConstantPool getPool() { return pool; } + @SuppressFBWarnings(value = "DC_DOUBLECHECK", // + justification = "Publication uses a release fence, assuming data dependency ordering on the reader side.") private CallTarget getCallTargetNoSubstitution() { CompilerAsserts.neverPartOfCompilation(); EspressoError.guarantee(getSubstitutions().hasSubstitutionFor(getMethod()), @@ -1236,7 +1239,9 @@ private CallTarget getCallTargetNoSubstitution() { if (callTargetNoSubstitutions == null) { synchronized (this) { if (callTargetNoSubstitutions == null) { - callTargetNoSubstitutions = findCallTarget(); + CallTarget target = findCallTarget(); + VarHandle.releaseFence(); + callTargetNoSubstitutions = target; } } } @@ -1261,27 +1266,26 @@ private void resolveCallTarget() { if (callTarget != null) { return; } + CallTarget target; if (proxy != Method.this) { - this.callTarget = proxy.getCallTarget(); - return; - } - - /* - * The substitution factory does the validation e.g. some substitutions only apply - * for classes/methods in the boot or platform class loaders. A warning is logged if - * the validation fails. - */ - EspressoRootNode redirectedMethod = getSubstitutions().get(getMethod()); - if (redirectedMethod != null) { - callTarget = redirectedMethod.getCallTarget(); - return; + target = proxy.getCallTarget(); + } else { + /* + * The substitution factory does the validation e.g. some substitutions only + * apply for classes/methods in the boot or platform class loaders. A warning is + * logged if the validation fails. + */ + EspressoRootNode redirectedMethod = getSubstitutions().get(getMethod()); + if (redirectedMethod != null) { + target = redirectedMethod.getCallTarget(); + } else { + assert callTargetNoSubstitutions == null; + target = findCallTarget(); + } } - assert callTargetNoSubstitutions == null; - - CallTarget target = findCallTarget(); if (target != null) { + VarHandle.releaseFence(); callTarget = target; - return; } } } From 3871b946ab132a5ecea85683fbcb9c130b7a687b Mon Sep 17 00:00:00 2001 From: Andreas Woess Date: Thu, 7 Dec 2023 20:11:20 +0100 Subject: [PATCH 157/593] PhiTransformPhase: only narrow phis that are narrowed by FrameWithoutBoxing or don't have state usages. --- .../compiler/truffle/TruffleCompilerImpl.java | 8 ++- .../compiler/truffle/nodes/AnyNarrowNode.java | 66 +++++++++++++++++++ .../truffle/phases/PhiTransformPhase.java | 45 +++++++++++-- .../TruffleGraphBuilderPlugins.java | 18 +++-- .../truffle/api/impl/FrameWithoutBoxing.java | 26 +++++--- 5 files changed, 140 insertions(+), 23 deletions(-) create mode 100644 compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/truffle/nodes/AnyNarrowNode.java diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/truffle/TruffleCompilerImpl.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/truffle/TruffleCompilerImpl.java index 7cd3f92d0c05..02b783c2d2ab 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/truffle/TruffleCompilerImpl.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/truffle/TruffleCompilerImpl.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 2023, 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 @@ -81,6 +81,7 @@ import jdk.graal.compiler.lir.phases.LIRSuites; import jdk.graal.compiler.nodes.NodeView; import jdk.graal.compiler.nodes.StructuredGraph; +import jdk.graal.compiler.nodes.calc.NarrowNode; import jdk.graal.compiler.nodes.calc.ZeroExtendNode; import jdk.graal.compiler.nodes.graphbuilderconf.GraphBuilderConfiguration; import jdk.graal.compiler.nodes.graphbuilderconf.GraphBuilderConfiguration.BytecodeExceptionMode; @@ -96,6 +97,7 @@ import jdk.graal.compiler.phases.util.Providers; import jdk.graal.compiler.serviceprovider.GraalServices; import jdk.graal.compiler.truffle.nodes.AnyExtendNode; +import jdk.graal.compiler.truffle.nodes.AnyNarrowNode; import jdk.graal.compiler.truffle.nodes.TruffleAssumption; import jdk.graal.compiler.truffle.phases.InstrumentPhase; import jdk.graal.compiler.truffle.phases.InstrumentationSuite; @@ -565,6 +567,10 @@ private static void replaceAnyExtendNodes(StructuredGraph graph) { for (AnyExtendNode node : graph.getNodes(AnyExtendNode.TYPE)) { node.replaceAndDelete(graph.addOrUnique(ZeroExtendNode.create(node.getValue(), 64, NodeView.DEFAULT))); } + // replace all AnyNarrowNodes with NarrowNodes + for (AnyNarrowNode node : graph.getNodes(AnyNarrowNode.TYPE)) { + node.replaceAndDelete(graph.addOrUnique(NarrowNode.create(node.getValue(), 32, NodeView.DEFAULT))); + } } /** diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/truffle/nodes/AnyNarrowNode.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/truffle/nodes/AnyNarrowNode.java new file mode 100644 index 000000000000..26d2b7ff43d0 --- /dev/null +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/truffle/nodes/AnyNarrowNode.java @@ -0,0 +1,66 @@ +/* + * Copyright (c) 2023, 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 jdk.graal.compiler.truffle.nodes; + +import static jdk.graal.compiler.nodeinfo.NodeCycles.CYCLES_1; + +import jdk.graal.compiler.core.common.type.IntegerStamp; +import jdk.graal.compiler.core.common.type.Stamp; +import jdk.graal.compiler.core.common.type.StampFactory; +import jdk.graal.compiler.graph.IterableNodeType; +import jdk.graal.compiler.graph.NodeClass; +import jdk.graal.compiler.nodeinfo.NodeInfo; +import jdk.graal.compiler.nodeinfo.NodeSize; +import jdk.graal.compiler.nodes.NodeView; +import jdk.graal.compiler.nodes.ValueNode; +import jdk.graal.compiler.nodes.calc.FloatingNode; +import jdk.graal.compiler.nodes.calc.NarrowNode; +import jdk.vm.ci.meta.JavaKind; + +/** + * The {@code AnyNarrowNode} narrows an i64 integer to an i32 integer. This node itself cannot + * produce code, it needs to be converted to a {@link NarrowNode} explicitly. + */ +@NodeInfo(cycles = CYCLES_1, size = NodeSize.SIZE_1) +public final class AnyNarrowNode extends FloatingNode implements IterableNodeType { + + public static final NodeClass TYPE = NodeClass.create(AnyNarrowNode.class); + + public static final int INPUT_BITS = 64; + public static final int OUTPUT_BITS = 32; + + @Input protected ValueNode value; + + public AnyNarrowNode(ValueNode value) { + super(TYPE, StampFactory.forKind(JavaKind.Int)); + Stamp stamp2 = value.stamp(NodeView.DEFAULT); + assert stamp2 instanceof IntegerStamp : stamp2; + this.value = value; + } + + public ValueNode getValue() { + return value; + } +} diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/truffle/phases/PhiTransformPhase.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/truffle/phases/PhiTransformPhase.java index bf526b8b912b..e70dc55fa467 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/truffle/phases/PhiTransformPhase.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/truffle/phases/PhiTransformPhase.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2023, 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 @@ -54,6 +54,7 @@ import jdk.graal.compiler.phases.common.CanonicalizerPhase; import jdk.graal.compiler.phases.common.util.EconomicSetNodeEventListener; import jdk.graal.compiler.truffle.nodes.AnyExtendNode; +import jdk.graal.compiler.truffle.nodes.AnyNarrowNode; import jdk.vm.ci.meta.ResolvedJavaType; /** @@ -137,15 +138,20 @@ private static ValidTransformation collectNodes(ValueNode node, EconomicSet Date: Fri, 8 Dec 2023 17:29:14 +0100 Subject: [PATCH 158/593] Fix PhiTransformTest. --- .../compiler/truffle/test/PhiTransformTest.java | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/truffle/test/PhiTransformTest.java b/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/truffle/test/PhiTransformTest.java index 1d2e23cf420c..6e0e5fba1320 100644 --- a/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/truffle/test/PhiTransformTest.java +++ b/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/truffle/test/PhiTransformTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2023, 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 @@ -42,6 +42,7 @@ import jdk.graal.compiler.phases.tiers.HighTierContext; import jdk.graal.compiler.phases.tiers.Suites; import jdk.graal.compiler.truffle.nodes.AnyExtendNode; +import jdk.graal.compiler.truffle.nodes.AnyNarrowNode; import jdk.graal.compiler.truffle.phases.PhiTransformPhase; import jdk.graal.compiler.virtual.phases.ea.PartialEscapePhase; import org.junit.Assert; @@ -251,7 +252,14 @@ static final class ToAnyExtendsPhase extends BasePhase { protected void run(StructuredGraph graph, CoreProviders context) { if (!graph.toString().contains("deoptSnippet")) { for (ZeroExtendNode node : graph.getNodes().filter(ZeroExtendNode.class)) { - node.replaceAndDelete(graph.unique(new AnyExtendNode(node.getValue()))); + if (node.getInputBits() == AnyExtendNode.INPUT_BITS && node.getResultBits() == AnyExtendNode.OUTPUT_BITS) { + node.replaceAndDelete(graph.unique(new AnyExtendNode(node.getValue()))); + } + } + for (NarrowNode node : graph.getNodes().filter(NarrowNode.class)) { + if (node.getInputBits() == AnyNarrowNode.INPUT_BITS && node.getResultBits() == AnyNarrowNode.OUTPUT_BITS) { + node.replaceAndDelete(graph.unique(new AnyNarrowNode(node.getValue()))); + } } } } @@ -264,6 +272,9 @@ protected void run(StructuredGraph graph, CoreProviders context) { for (AnyExtendNode node : graph.getNodes().filter(AnyExtendNode.class)) { node.replaceAndDelete(graph.addOrUnique(ZeroExtendNode.create(node.getValue(), 64, NodeView.DEFAULT))); } + for (AnyNarrowNode node : graph.getNodes().filter(AnyNarrowNode.class)) { + node.replaceAndDelete(graph.addOrUnique(NarrowNode.create(node.getValue(), 32, NodeView.DEFAULT))); + } } } } From d4f8b98baad5da792cc885c87db7fd3b11f4f34c Mon Sep 17 00:00:00 2001 From: Andreas Woess Date: Fri, 8 Dec 2023 18:18:46 +0100 Subject: [PATCH 159/593] Extend PhiTransformTest.deopt to only replace extends and narrows, respectively. --- .../truffle/test/PhiTransformTest.java | 58 +++++++++++++++++-- 1 file changed, 52 insertions(+), 6 deletions(-) diff --git a/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/truffle/test/PhiTransformTest.java b/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/truffle/test/PhiTransformTest.java index 6e0e5fba1320..92ca52227b45 100644 --- a/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/truffle/test/PhiTransformTest.java +++ b/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/truffle/test/PhiTransformTest.java @@ -27,6 +27,9 @@ import java.util.ListIterator; +import org.junit.Assert; +import org.junit.Test; + import jdk.graal.compiler.api.directives.GraalDirectives; import jdk.graal.compiler.core.test.GraalCompilerTest; import jdk.graal.compiler.nodes.NodeView; @@ -45,8 +48,6 @@ import jdk.graal.compiler.truffle.nodes.AnyNarrowNode; import jdk.graal.compiler.truffle.phases.PhiTransformPhase; import jdk.graal.compiler.virtual.phases.ea.PartialEscapePhase; -import org.junit.Assert; -import org.junit.Test; public class PhiTransformTest extends GraalCompilerTest { @@ -106,6 +107,7 @@ public void succeed2() { Assert.assertTrue(graph.getNodes().filter(ReinterpretNode.class).count() + graph.getNodes().filter(NarrowNode.class).count() == 0); } + @BytecodeParserForceInline public static float deoptSnippet(int count) { /* * This test will fail with a wrong result if the phi transformation happens, since the @@ -128,10 +130,52 @@ public static float deoptSnippet(int count) { return s; } + public static float deoptSnippetKeepExtend(int count) { + return deoptSnippet(count); + } + + public static float deoptSnippetKeepNarrow(int count) { + return deoptSnippet(count); + } + + @Test + public void deoptKeepExtend() { + StructuredGraph graph = createGraph("deoptSnippetKeepExtend"); + Assert.assertEquals(1, graph.getNodes().filter(ReinterpretNode.class).count() + graph.getNodes().filter(NarrowNode.class).count()); + } + + @Test + public void deoptKeepNarrow() { + StructuredGraph graph = createGraph("deoptSnippetKeepNarrow"); + Assert.assertEquals(1, graph.getNodes().filter(ReinterpretNode.class).count() + graph.getNodes().filter(NarrowNode.class).count()); + } + + public static float deoptOKSnippet(int count) { + /* + * This test will not fail with a wrong result if the phi transformation happens, since the + * upper 32 bits of the int-in-long are not observed after the deopt. + */ + long[] values = new long[2]; + float s = 0; + do { + values[0] = ((int) values[0] + 1) & 0xffffffffL; + s++; + GraalDirectives.sideEffect(); + if (s > 30) { + // value is used as i64 after deopt: + GraalDirectives.deoptimize(); + if ((int) values[0] < 0 || (int) values[0] >= count) { + break; + } + } + } while ((int) values[0] < count); + return s; + } + @Test - public void deopt() { - StructuredGraph graph = createGraph("deoptSnippet"); - Assert.assertTrue(graph.getNodes().filter(ReinterpretNode.class).count() + graph.getNodes().filter(NarrowNode.class).count() == 1); + public void deoptOK() { + StructuredGraph graph = createGraph("deoptOKSnippet"); + Assert.assertEquals(0, graph.getNodes().filter(ReinterpretNode.class).count() + graph.getNodes().filter(NarrowNode.class).count()); } public static float fail1Snippet(int count) { @@ -250,12 +294,14 @@ static final class ToAnyExtendsPhase extends BasePhase { @Override protected void run(StructuredGraph graph, CoreProviders context) { - if (!graph.toString().contains("deoptSnippet")) { + if (!graph.toString().contains("deoptSnippetKeepExtend")) { for (ZeroExtendNode node : graph.getNodes().filter(ZeroExtendNode.class)) { if (node.getInputBits() == AnyExtendNode.INPUT_BITS && node.getResultBits() == AnyExtendNode.OUTPUT_BITS) { node.replaceAndDelete(graph.unique(new AnyExtendNode(node.getValue()))); } } + } + if (!graph.toString().contains("deoptSnippetKeepNarrow")) { for (NarrowNode node : graph.getNodes().filter(NarrowNode.class)) { if (node.getInputBits() == AnyNarrowNode.INPUT_BITS && node.getResultBits() == AnyNarrowNode.OUTPUT_BITS) { node.replaceAndDelete(graph.unique(new AnyNarrowNode(node.getValue()))); From 57398da9c3189da52085391991756b6b9fdc73cd Mon Sep 17 00:00:00 2001 From: ol-automation_ww Date: Fri, 8 Dec 2023 21:07:49 +0000 Subject: [PATCH 160/593] Update truffleruby import. --- vm/mx.vm/suite.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vm/mx.vm/suite.py b/vm/mx.vm/suite.py index e2e62577e788..9937a51d7e06 100644 --- a/vm/mx.vm/suite.py +++ b/vm/mx.vm/suite.py @@ -49,7 +49,7 @@ }, { "name": "truffleruby", - "version": "4cd14c48852b7bdb51070b42b50b702dc5a2d7d2", + "version": "b7cb7fec62d04436dbba79b1b80a5a76c80a7a1b", "dynamic": True, "urls": [ {"url": "https://github.com/oracle/truffleruby.git", "kind": "git"}, From a48157ada43a96b8a48832fba3a6aa156d7e65b5 Mon Sep 17 00:00:00 2001 From: ol-automation_ww Date: Fri, 8 Dec 2023 22:16:12 +0000 Subject: [PATCH 161/593] update to 22+27-jvmci-b01 --- common.json | 14 +++++++------- .../graal/compiler/hotspot/JVMCIVersionCheck.java | 4 ++-- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/common.json b/common.json index e9b51bd96972..31c590854b1e 100644 --- a/common.json +++ b/common.json @@ -44,13 +44,13 @@ "labsjdk-ee-21Debug": {"name": "labsjdk", "version": "ee-21.0.1+11-jvmci-23.1-b26-debug", "platformspecific": true }, "labsjdk-ee-21-llvm": {"name": "labsjdk", "version": "ee-21.0.1+11-jvmci-23.1-b26-sulong", "platformspecific": true }, - "oraclejdk-latest": {"name": "jpg-jdk", "version": "22", "build_id": "26", "release": true, "platformspecific": true, "extrabundles": ["static-libs"]}, - "labsjdk-ce-latest": {"name": "labsjdk", "version": "ce-22+26-jvmci-b01", "platformspecific": true }, - "labsjdk-ce-latestDebug": {"name": "labsjdk", "version": "ce-22+26-jvmci-b01-debug", "platformspecific": true }, - "labsjdk-ce-latest-llvm": {"name": "labsjdk", "version": "ce-22+26-jvmci-b01-sulong", "platformspecific": true }, - "labsjdk-ee-latest": {"name": "labsjdk", "version": "ee-22+26-jvmci-b01", "platformspecific": true }, - "labsjdk-ee-latestDebug": {"name": "labsjdk", "version": "ee-22+26-jvmci-b01-debug", "platformspecific": true }, - "labsjdk-ee-latest-llvm": {"name": "labsjdk", "version": "ee-22+26-jvmci-b01-sulong", "platformspecific": true } + "oraclejdk-latest": {"name": "jpg-jdk", "version": "22", "build_id": "27", "release": true, "platformspecific": true, "extrabundles": ["static-libs"]}, + "labsjdk-ce-latest": {"name": "labsjdk", "version": "ce-22+27-jvmci-b01-20231208220320-8ab1810893", "platformspecific": true }, + "labsjdk-ce-latestDebug": {"name": "labsjdk", "version": "ce-22+27-jvmci-b01-20231208220320-8ab1810893-debug", "platformspecific": true }, + "labsjdk-ce-latest-llvm": {"name": "labsjdk", "version": "ce-22+27-jvmci-b01-20231208220320-8ab1810893-sulong", "platformspecific": true }, + "labsjdk-ee-latest": {"name": "labsjdk", "version": "ee-22+27-jvmci-b01-20231208220320-8ab1810893+eed28ebffa", "platformspecific": true }, + "labsjdk-ee-latestDebug": {"name": "labsjdk", "version": "ee-22+27-jvmci-b01-20231208220320-8ab1810893+eed28ebffa-debug", "platformspecific": true }, + "labsjdk-ee-latest-llvm": {"name": "labsjdk", "version": "ee-22+27-jvmci-b01-20231208220320-8ab1810893+eed28ebffa-sulong", "platformspecific": true } }, "eclipse": { diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/JVMCIVersionCheck.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/JVMCIVersionCheck.java index e60a914778e5..0c0f071047e4 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/JVMCIVersionCheck.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/JVMCIVersionCheck.java @@ -54,8 +54,8 @@ public final class JVMCIVersionCheck { private static final Map> JVMCI_MIN_VERSIONS = Map.of( "21", Map.of(DEFAULT_VENDOR_ENTRY, new Version(23, 1, 26)), "22", Map.of( - "Oracle Corporation", new Version("22+26", 1), - DEFAULT_VENDOR_ENTRY, new Version("22+26", 1))); + "Oracle Corporation", new Version("22+27", 1), + DEFAULT_VENDOR_ENTRY, new Version("22+27", 1))); private static final int NA = 0; /** * Minimum Java release supported by Graal. From 550fb03302767ec83bcbb218208ae51fb937c560 Mon Sep 17 00:00:00 2001 From: jovanstevanovic Date: Thu, 7 Dec 2023 13:08:45 +0100 Subject: [PATCH 162/593] Refactor JDK adopted profiles extraction. --- vm/mx.vm/mx_vm_benchmark.py | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/vm/mx.vm/mx_vm_benchmark.py b/vm/mx.vm/mx_vm_benchmark.py index 1f21dd5d52bf..c3f4d6d4d21e 100644 --- a/vm/mx.vm/mx_vm_benchmark.py +++ b/vm/mx.vm/mx_vm_benchmark.py @@ -934,7 +934,7 @@ def run_stage_instrument_image(self, config, stages, out, i, instrumentation_ima pgo_args += svm_experimental_options(['-H:' + ('+' if self.pgo_context_sensitive else '-') + 'PGOContextSensitivityEnabled']) instrument_args = ['--pgo-instrument', '-R:ProfilesDumpFile=' + profile_path] + ([] if i == 0 else pgo_args) if self.jdk_profiles_collect: - instrument_args += svm_experimental_options(['-H:+ProfilingEnabled', '-H:+AOTPriorityInline', '-H:-SamplingCollect', f'-H:ProfilingPackagePrefixes={self.generate_profiling_package_prefixes()}']) + instrument_args += svm_experimental_options(['-H:+AOTPriorityInline', '-H:-SamplingCollect', f'-H:ProfilingPackagePrefixes={self.generate_profiling_package_prefixes()}']) with stages.set_command(config.base_image_build_args + executable_name_args + instrument_args) as s: s.execute_command() @@ -994,10 +994,7 @@ def run_stage_image(self, config, stages, out): jdk_profiles = f"JDK{jdk_version}_PROFILES" adopted_profiles_lib = mx.library(jdk_profiles, fatalIfMissing=False) if adopted_profiles_lib: - adopted_profiles_zip = adopted_profiles_lib.get_path(True) - adopted_profiles_dir = os.path.dirname(adopted_profiles_zip) - with zipfile.ZipFile(adopted_profiles_zip, 'r') as zip_ref: - zip_ref.extractall(adopted_profiles_dir) + adopted_profiles_dir = adopted_profiles_lib.get_path(True) adopted_profile = os.path.join(adopted_profiles_dir, 'jdk_profile.iprof') else: mx.warn(f'SubstrateVM Enterprise with JDK{jdk_version} does not contain JDK profiles.') From 55d9e083e5d0b9a293f3965c6b9355a324d55ff8 Mon Sep 17 00:00:00 2001 From: Josef Eisl Date: Sat, 9 Dec 2023 15:39:16 +0100 Subject: [PATCH 163/593] svm: adopt "JDK-8315458 Implement JEP 463: Implicitly Declared Classes and Instance Main Method (Second Preview)" --- .../src/com/oracle/svm/core/hub/DynamicHub.java | 6 +++++- .../com/oracle/svm/hosted/NativeImageGeneratorRunner.java | 4 +++- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/hub/DynamicHub.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/hub/DynamicHub.java index e2ba26a408ed..3831707a1691 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/hub/DynamicHub.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/hub/DynamicHub.java @@ -73,7 +73,6 @@ import java.util.Optional; import java.util.StringJoiner; -import com.oracle.svm.core.jdk.JDK21OrEarlier; import org.graalvm.nativeimage.AnnotationAccess; import org.graalvm.nativeimage.ImageSingletons; import org.graalvm.nativeimage.Platform; @@ -101,6 +100,7 @@ import com.oracle.svm.core.config.ObjectLayout; import com.oracle.svm.core.heap.UnknownObjectField; import com.oracle.svm.core.heap.UnknownPrimitiveField; +import com.oracle.svm.core.jdk.JDK21OrEarlier; import com.oracle.svm.core.jdk.JDK22OrLater; import com.oracle.svm.core.jdk.Resources; import com.oracle.svm.core.meta.SharedType; @@ -1750,6 +1750,10 @@ private Class[] getPermittedSubclasses0() { @KeepOriginal private native GenericsFactory getFactory(); + @KeepOriginal + @TargetElement(onlyWith = JDK22OrLater.class) + native Method findMethod(boolean publicOnly, String name, Class... parameterTypes); + @KeepOriginal private native Method getMethod0(String methodName, Class[] parameterTypes); diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/NativeImageGeneratorRunner.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/NativeImageGeneratorRunner.java index 6e17b1d78ff6..5e152088dc05 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/NativeImageGeneratorRunner.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/NativeImageGeneratorRunner.java @@ -79,6 +79,7 @@ import com.oracle.svm.util.ReflectionUtil.ReflectionUtilError; import jdk.graal.compiler.options.OptionValues; +import jdk.graal.compiler.serviceprovider.JavaVersionUtil; import jdk.vm.ci.aarch64.AArch64; import jdk.vm.ci.amd64.AMD64; import jdk.vm.ci.code.Architecture; @@ -472,7 +473,8 @@ private int buildImage(ImageClassLoader classLoader) { * * MainMethodFinder will perform all the necessary checks */ - Class mainMethodFinder = ReflectionUtil.lookupClass(false, "jdk.internal.misc.MainMethodFinder"); + String mainMethodFinderClassName = JavaVersionUtil.JAVA_SPEC >= 22 ? "jdk.internal.misc.MethodFinder" : "jdk.internal.misc.MainMethodFinder"; + Class mainMethodFinder = ReflectionUtil.lookupClass(false, mainMethodFinderClassName); Method findMainMethod = ReflectionUtil.lookupMethod(mainMethodFinder, "findMainMethod", Class.class); javaMainMethod = (Method) findMainMethod.invoke(null, mainClass); } catch (InvocationTargetException ex) { From a86fc2b36c78a9c4c015f0eb3402f6c4f4aed313 Mon Sep 17 00:00:00 2001 From: Jakub Chaloupka Date: Mon, 11 Dec 2023 08:59:39 +0100 Subject: [PATCH 164/593] Increase time limit for truffle unchained CE native build. --- vm/ci/ci_includes/vm-native.jsonnet | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/vm/ci/ci_includes/vm-native.jsonnet b/vm/ci/ci_includes/vm-native.jsonnet index c134fcc96214..b6e65a94b4a3 100644 --- a/vm/ci/ci_includes/vm-native.jsonnet +++ b/vm/ci/ci_includes/vm-native.jsonnet @@ -8,8 +8,8 @@ local vm_common = import '../ci_common/common.jsonnet'; ['export', 'SVM_SUITE=' + vm.svm_suite], ['mx', '--env', 'ce', '--native-images=lib:jvmcicompiler', 'gate', '--no-warning-as-error', '--tags', 'build,truffle-unchained'], ], - notify_emails: ["christian.humer@oracle.com", "jakub.chaloupka@oracle.com"], - timelimit: '30:00', + notify_emails: ["christian.humer@oracle.com", "tomas.zezula@oracle.com", "jakub.chaloupka@oracle.com"], + timelimit: '50:00', name: self.targets[0] + '-vm-ce-truffle-unchained-labs' + self.jdk_name + '-linux-amd64', }, From 595ac63036c8888330cc1f4eb4e381f5c70629f3 Mon Sep 17 00:00:00 2001 From: Josef Eisl Date: Sat, 9 Dec 2023 15:50:52 +0100 Subject: [PATCH 165/593] svm: adopt "JDK-8321270: Virtual Thread.yield consumes parking permit" [GR-50851] https://github.com/openjdk/jdk/commit/29d7a22348e43cba253d0483c4c05922368f6b8a --- .../core/thread/Target_java_lang_VirtualThread.java | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/thread/Target_java_lang_VirtualThread.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/thread/Target_java_lang_VirtualThread.java index b982a5af67e5..b1e050cb558b 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/thread/Target_java_lang_VirtualThread.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/thread/Target_java_lang_VirtualThread.java @@ -45,6 +45,7 @@ import com.oracle.svm.core.annotate.Substitute; import com.oracle.svm.core.annotate.TargetClass; import com.oracle.svm.core.annotate.TargetElement; +import com.oracle.svm.core.jdk.JDK21OrEarlier; import com.oracle.svm.core.jdk.JDK22OrLater; import com.oracle.svm.core.jfr.HasJfrSupport; import com.oracle.svm.core.jfr.SubstrateJVM; @@ -60,17 +61,20 @@ public final class Target_java_lang_VirtualThread { // Checkstyle: stop @Alias static int NEW; @Alias static int STARTED; - @Alias static int RUNNABLE; + @Alias // + @TargetElement(onlyWith = JDK21OrEarlier.class) static int RUNNABLE; @Alias static int RUNNING; @Alias static int PARKING; @Alias static int PARKED; @Alias static int PINNED; @Alias static int YIELDING; + @TargetElement(onlyWith = JDK22OrLater.class) @Alias static int YIELDED; @Alias static int TERMINATED; @Alias static int SUSPENDED; @TargetElement(onlyWith = JDK22OrLater.class) @Alias static int TIMED_PARKING; @TargetElement(onlyWith = JDK22OrLater.class) @Alias static int TIMED_PARKED; @TargetElement(onlyWith = JDK22OrLater.class) @Alias static int TIMED_PINNED; + @TargetElement(onlyWith = JDK22OrLater.class) @Alias static int UNPARKED; @Alias static Target_jdk_internal_vm_ContinuationScope VTHREAD_SCOPE; /** @@ -300,7 +304,9 @@ Thread.State threadState() { } else { return Thread.State.RUNNABLE; } - } else if (state == RUNNABLE) { + } else if (JavaVersionUtil.JAVA_SPEC < 22 && state == RUNNABLE) { + return Thread.State.RUNNABLE; + } else if (JavaVersionUtil.JAVA_SPEC >= 22 && (state == UNPARKED || state == YIELDED)) { return Thread.State.RUNNABLE; } else if (state == RUNNING) { Object token = VirtualThreadHelper.acquireInterruptLockMaybeSwitch(this); From 319275395845c3943d0ef18ac4c37372bea3e647 Mon Sep 17 00:00:00 2001 From: Josef Eisl Date: Sun, 10 Dec 2023 14:17:56 +0100 Subject: [PATCH 166/593] svm: adopt "JDK-8321159: SymbolLookup.libraryLookup(Path, Arena) Assumes default Filesystem" --- .../core/foreign/Target_java_lang_foreign_SymbolLookup.java | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/substratevm/src/com.oracle.svm.core.foreign/src/com/oracle/svm/core/foreign/Target_java_lang_foreign_SymbolLookup.java b/substratevm/src/com.oracle.svm.core.foreign/src/com/oracle/svm/core/foreign/Target_java_lang_foreign_SymbolLookup.java index ffda625c7dd8..bf57b9cb08f3 100644 --- a/substratevm/src/com.oracle.svm.core.foreign/src/com/oracle/svm/core/foreign/Target_java_lang_foreign_SymbolLookup.java +++ b/substratevm/src/com.oracle.svm.core.foreign/src/com/oracle/svm/core/foreign/Target_java_lang_foreign_SymbolLookup.java @@ -27,6 +27,7 @@ import java.lang.foreign.Arena; import java.lang.foreign.MemorySegment; import java.lang.foreign.SymbolLookup; +import java.nio.file.FileSystems; import java.nio.file.Path; import java.util.ArrayList; import java.util.List; @@ -85,6 +86,9 @@ static SymbolLookup libraryLookup(String name, Arena arena) { @NeverInline("Starting a stack walk in the caller frame") static SymbolLookup libraryLookup(Path path, Arena arena) { Util_java_lang_foreign_SymbolLookup.ensureNativeAccess(StackTraceUtils.getCallerClass(KnownIntrinsics.readCallerStackPointer(), true), SymbolLookup.class, "libraryLookup"); + if (path.getFileSystem() != FileSystems.getDefault()) { + throw new IllegalArgumentException("Path not in default file system: " + path); + } return Util_java_lang_foreign_SymbolLookup.libraryLookup(LookupNativeLibraries::loadLibraryPlatformSpecific, arena, List.of(path)); } From dd8eb7436ca2ce323a74667805dd7736c6ccc972 Mon Sep 17 00:00:00 2001 From: Josef Eisl Date: Sun, 10 Dec 2023 14:42:15 +0100 Subject: [PATCH 167/593] svm: adopt "JDK-8211238: @Deprecated JFR event" --- .../oracle/svm/core/jfr/Target_jdk_jfr_internal_JVM.java | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jfr/Target_jdk_jfr_internal_JVM.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jfr/Target_jdk_jfr_internal_JVM.java index 8d70ddce6a4a..362de09ddc0a 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jfr/Target_jdk_jfr_internal_JVM.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jfr/Target_jdk_jfr_internal_JVM.java @@ -168,6 +168,12 @@ public static void unregisterStackFilter(long stackFilterId) { throw VMError.unimplemented("JFR StackFilters are not yet supported."); } + @Substitute + @TargetElement(onlyWith = JDK22OrLater.class) + public static void setMiscellaneous(long eventTypeId, long value) { + throw VMError.unimplemented("JFR StackFilters are not yet supported."); + } + /** See {@link JVM#getThreadId}. */ @Substitute @TargetElement(onlyWith = JDK22OrLater.class) From 7d127daf0a1b94e3473f2ab420d2c0a3bf80d479 Mon Sep 17 00:00:00 2001 From: Marouane El Hallaoui Date: Mon, 11 Dec 2023 11:44:47 +0100 Subject: [PATCH 168/593] deploy labsjdk snapshots --- common.json | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/common.json b/common.json index 31c590854b1e..cd0200f711d7 100644 --- a/common.json +++ b/common.json @@ -45,12 +45,12 @@ "labsjdk-ee-21-llvm": {"name": "labsjdk", "version": "ee-21.0.1+11-jvmci-23.1-b26-sulong", "platformspecific": true }, "oraclejdk-latest": {"name": "jpg-jdk", "version": "22", "build_id": "27", "release": true, "platformspecific": true, "extrabundles": ["static-libs"]}, - "labsjdk-ce-latest": {"name": "labsjdk", "version": "ce-22+27-jvmci-b01-20231208220320-8ab1810893", "platformspecific": true }, - "labsjdk-ce-latestDebug": {"name": "labsjdk", "version": "ce-22+27-jvmci-b01-20231208220320-8ab1810893-debug", "platformspecific": true }, - "labsjdk-ce-latest-llvm": {"name": "labsjdk", "version": "ce-22+27-jvmci-b01-20231208220320-8ab1810893-sulong", "platformspecific": true }, - "labsjdk-ee-latest": {"name": "labsjdk", "version": "ee-22+27-jvmci-b01-20231208220320-8ab1810893+eed28ebffa", "platformspecific": true }, - "labsjdk-ee-latestDebug": {"name": "labsjdk", "version": "ee-22+27-jvmci-b01-20231208220320-8ab1810893+eed28ebffa-debug", "platformspecific": true }, - "labsjdk-ee-latest-llvm": {"name": "labsjdk", "version": "ee-22+27-jvmci-b01-20231208220320-8ab1810893+eed28ebffa-sulong", "platformspecific": true } + "labsjdk-ce-latest": {"name": "labsjdk", "version": "ce-22+27-jvmci-b01", "platformspecific": true }, + "labsjdk-ce-latestDebug": {"name": "labsjdk", "version": "ce-22+27-jvmci-b01-debug", "platformspecific": true }, + "labsjdk-ce-latest-llvm": {"name": "labsjdk", "version": "ce-22+27-jvmci-b01-sulong", "platformspecific": true }, + "labsjdk-ee-latest": {"name": "labsjdk", "version": "ee-22+27-jvmci-b01", "platformspecific": true }, + "labsjdk-ee-latestDebug": {"name": "labsjdk", "version": "ee-22+27-jvmci-b01-debug", "platformspecific": true }, + "labsjdk-ee-latest-llvm": {"name": "labsjdk", "version": "ee-22+27-jvmci-b01-sulong", "platformspecific": true } }, "eclipse": { From 02de9801a06fffccc56dc7bc52518c81f788dfd9 Mon Sep 17 00:00:00 2001 From: Jirka Marsik Date: Mon, 11 Dec 2023 14:48:51 +0100 Subject: [PATCH 169/593] Run the PureNFATransitionGenerator in reverse for lookbehinds --- .../truffle/regex/tregex/test/JsTests.java | 5 ++ .../regex/tregex/nfa/ASTStepVisitor.java | 5 ++ .../truffle/regex/tregex/nfa/PureNFA.java | 40 +----------- .../regex/tregex/nfa/PureNFAGenerator.java | 65 ++++++++++++++----- .../regex/tregex/nfa/PureNFAState.java | 24 +++---- .../nfa/PureNFATransitionGenerator.java | 43 ++++++++---- .../TRegexBacktrackingNFAExecutorNode.java | 65 +++++++++---------- .../regex/tregex/parser/ast/MatchFound.java | 5 ++ .../tregex/parser/ast/PositionAssertion.java | 5 ++ .../regex/tregex/parser/ast/RegexASTNode.java | 2 +- .../parser/ast/RegexASTSubtreeRootNode.java | 8 +++ .../MarkLookBehindEntriesVisitor.java | 7 +- .../visitors/NFATraversalRegexASTVisitor.java | 49 +++++++------- 13 files changed, 184 insertions(+), 139 deletions(-) diff --git a/regex/src/com.oracle.truffle.regex.test/src/com/oracle/truffle/regex/tregex/test/JsTests.java b/regex/src/com.oracle.truffle.regex.test/src/com/oracle/truffle/regex/tregex/test/JsTests.java index a41c9bc2abf1..265895ece5b0 100644 --- a/regex/src/com.oracle.truffle.regex.test/src/com/oracle/truffle/regex/tregex/test/JsTests.java +++ b/regex/src/com.oracle.truffle.regex.test/src/com/oracle/truffle/regex/tregex/test/JsTests.java @@ -263,4 +263,9 @@ public void gr48586() { true, 0, 3, 0, 3, 0, 1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 2, 3); } + + @Test + public void gr50807() { + test("(?<=%b{1,4}?)foo", "", "%bbbbfoo", 0, true, 5, 8); + } } diff --git a/regex/src/com.oracle.truffle.regex/src/com/oracle/truffle/regex/tregex/nfa/ASTStepVisitor.java b/regex/src/com.oracle.truffle.regex/src/com/oracle/truffle/regex/tregex/nfa/ASTStepVisitor.java index cca5f37df281..40577040030b 100644 --- a/regex/src/com.oracle.truffle.regex/src/com/oracle/truffle/regex/tregex/nfa/ASTStepVisitor.java +++ b/regex/src/com.oracle.truffle.regex/src/com/oracle/truffle/regex/tregex/nfa/ASTStepVisitor.java @@ -238,4 +238,9 @@ public int hashCode() { protected boolean isBuildingDFA() { return true; } + + @Override + protected boolean canPruneAfterUnconditionalFinalState() { + return true; + } } diff --git a/regex/src/com.oracle.truffle.regex/src/com/oracle/truffle/regex/tregex/nfa/PureNFA.java b/regex/src/com.oracle.truffle.regex/src/com/oracle/truffle/regex/tregex/nfa/PureNFA.java index 92ff3ad499f0..3323ef3c5186 100644 --- a/regex/src/com.oracle.truffle.regex/src/com/oracle/truffle/regex/tregex/nfa/PureNFA.java +++ b/regex/src/com.oracle.truffle.regex/src/com/oracle/truffle/regex/tregex/nfa/PureNFA.java @@ -83,10 +83,6 @@ public PureNFA(RegexASTSubtreeRootNode astSubRoot, assert this.states[s.getId()] == null; this.states[s.getId()] = s; for (PureNFATransition t : s.getSuccessors()) { - if (s.getId() != 0) { - // don't link the dummy initial state as predecessor of initial states. - t.getTarget().addPredecessor(t); - } assert this.transitions[t.getId()] == null || (s.getId() == 0 && this.transitions[t.getId()] == t); this.transitions[t.getId()] = t; } @@ -118,19 +114,13 @@ public RegexASTSubtreeRootNode getASTSubtree(RegexAST ast) { * transitions, we need pseudo-transitions to the NFA's initial states as entry points for the * DFA generator. The dummy initial state provides these transitions, in a fixed layout: The * first half of its {@link PureNFAState#getSuccessors() successors} lead to the NFA's anchored - * initial states, and the second half leads to the unanchored initial states. The dummy initial - * state's {@link PureNFAState#getPredecessors() predecessors} are the NFA's anchored and - * unanchored final state, in that order. They serve as entry points for reverse DFAs. + * initial states, and the second half leads to the unanchored initial states. */ public PureNFAState getDummyInitialState() { - assert states[0].getSuccessors().length == 2 && states[0].getPredecessors().length == 2; + assert states[0].getSuccessors().length == 2; return states[0]; } - public int getNumberOfEntryPoints() { - return getDummyInitialState().getSuccessors().length / 2; - } - public PureNFATransition getAnchoredEntry() { return getDummyInitialState().getSuccessors()[0]; } @@ -147,30 +137,6 @@ public PureNFAState getAnchoredInitialState() { return getAnchoredEntry().getTarget(); } - public PureNFATransition getReverseAnchoredEntry() { - return getDummyInitialState().getPredecessors()[0]; - } - - public PureNFATransition getReverseUnAnchoredEntry() { - return getDummyInitialState().getPredecessors()[1]; - } - - public PureNFAState getUnAnchoredFinalState() { - return getReverseUnAnchoredEntry().getSource(); - } - - public PureNFAState getAnchoredFinalState() { - return getReverseAnchoredEntry().getSource(); - } - - public PureNFAState getUnAnchoredInitialState(boolean forward) { - return forward ? getUnAnchoredInitialState() : getUnAnchoredFinalState(); - } - - public PureNFAState getAnchoredInitialState(boolean forward) { - return forward ? getAnchoredInitialState() : getAnchoredFinalState(); - } - public PureNFAState[] getStates() { return states; } @@ -252,7 +218,7 @@ private static boolean mergeInitialStateMatcher(RegexAST ast, PureNFA nfa, CodeP @TruffleBoundary public JsonValue toJson(RegexAST ast) { return Json.obj(Json.prop("states", - Arrays.stream(states).map(x -> x == null || x == getDummyInitialState() || (x.isAnchoredFinalState() && !x.hasPredecessors()) ? Json.nullValue() : x.toJson(ast))), + Arrays.stream(states).map(x -> x == null || x == getDummyInitialState() ? Json.nullValue() : x.toJson(ast))), Json.prop("transitions", Arrays.stream(transitions).map(x -> x == null || x.getSource() == getDummyInitialState() ? Json.nullValue() : x.toJson(ast))), Json.prop("subtrees", Arrays.stream(subtrees).map(x -> x == null ? Json.nullValue() : x.toJson(ast))), Json.prop("anchoredEntry", Json.array(Json.val(getAnchoredInitialState().getId()))), diff --git a/regex/src/com.oracle.truffle.regex/src/com/oracle/truffle/regex/tregex/nfa/PureNFAGenerator.java b/regex/src/com.oracle.truffle.regex/src/com/oracle/truffle/regex/tregex/nfa/PureNFAGenerator.java index f281dcb56840..fea051f80aa0 100644 --- a/regex/src/com.oracle.truffle.regex/src/com/oracle/truffle/regex/tregex/nfa/PureNFAGenerator.java +++ b/regex/src/com.oracle.truffle.regex/src/com/oracle/truffle/regex/tregex/nfa/PureNFAGenerator.java @@ -56,6 +56,8 @@ public final class PureNFAGenerator { private final RegexAST ast; private final Counter.ThresholdCounter stateID = new Counter.ThresholdCounter(TRegexOptions.TRegexMaxPureNFASize, "PureNFA explosion"); private final Counter.ThresholdCounter transitionID = new Counter.ThresholdCounter(TRegexOptions.TRegexMaxPureNFATransitions, "NFA transition explosion"); + private PureNFAState anchoredInitialState; + private PureNFAState unAnchoredInitialState; private PureNFAState anchoredFinalState; private PureNFAState unAnchoredFinalState; private final Deque expansionQueue = new ArrayDeque<>(); @@ -66,6 +68,7 @@ private PureNFAGenerator(RegexAST ast) { this.ast = ast; this.nfaStates = new PureNFAState[ast.getNumberOfStates()]; transitionGen = new PureNFATransitionGenerator(ast, this); + transitionGen.setCanTraverseCaret(true); } public static PureNFA mapToNFA(RegexAST ast) { @@ -95,6 +98,14 @@ public Counter.ThresholdCounter getTransitionIdCounter() { return transitionID; } + public PureNFAState getAnchoredInitialState() { + return anchoredInitialState; + } + + public PureNFAState getUnAnchoredInitialState() { + return unAnchoredInitialState; + } + public PureNFAState getAnchoredFinalState() { return anchoredFinalState; } @@ -120,29 +131,51 @@ private PureNFA createNFA(RegexASTSubtreeRootNode root) { Arrays.fill(nfaStates, null); stateID.reset(); transitionID.reset(); + transitionGen.setReverse(root.isLookBehindAssertion()); + PureNFAState dummyInitialState = new PureNFAState(stateID.inc(), ast.getWrappedRoot()); nfaStates[ast.getWrappedRoot().getId()] = dummyInitialState; - if (!root.hasDollar()) { - anchoredFinalState = null; + assert dummyInitialState.getId() == 0; + + if (root.isLookBehindAssertion()) { + if (root.hasCaret()) { + anchoredFinalState = createFinalState(root.getAnchoredInitialState(), false); + anchoredFinalState.setAnchoredFinalState(); + } else { + anchoredFinalState = null; + } + unAnchoredFinalState = createFinalState(root.getUnAnchoredInitialState(), false); + unAnchoredFinalState.setUnAnchoredFinalState(); + unAnchoredInitialState = createUnAnchoredInitialState(root.getMatchFound()); + if (root.hasDollar()) { + anchoredInitialState = createAnchoredInitialState(root.getAnchoredFinalState()); + } else { + anchoredInitialState = null; + } } else { - anchoredFinalState = createFinalState(root.getAnchoredFinalState(), false); - anchoredFinalState.setAnchoredFinalState(); + if (root.hasDollar()) { + anchoredFinalState = createFinalState(root.getAnchoredFinalState(), false); + anchoredFinalState.setAnchoredFinalState(); + } else { + anchoredFinalState = null; + } + unAnchoredFinalState = createFinalState(root.getMatchFound(), false); + unAnchoredFinalState.setUnAnchoredFinalState(); + unAnchoredInitialState = createUnAnchoredInitialState(root.getUnAnchoredInitialState()); + if (root.hasCaret()) { + anchoredInitialState = createAnchoredInitialState(root.getAnchoredInitialState()); + } else { + anchoredInitialState = null; + } } - unAnchoredFinalState = createFinalState(root.getMatchFound(), false); - unAnchoredFinalState.setUnAnchoredFinalState(); - PureNFATransition initialStateTransition = createEmptyTransition(dummyInitialState, createUnAnchoredInitialState(root.getUnAnchoredInitialState())); - if (root.hasCaret()) { - dummyInitialState.setSuccessors(new PureNFATransition[]{createEmptyTransition(dummyInitialState, createAnchoredInitialState(root.getAnchoredInitialState())), initialStateTransition}); + + PureNFATransition initialStateTransition = createEmptyTransition(dummyInitialState, unAnchoredInitialState); + if (anchoredInitialState != null) { + dummyInitialState.setSuccessors(new PureNFATransition[]{createEmptyTransition(dummyInitialState, anchoredInitialState), initialStateTransition}); } else { dummyInitialState.setSuccessors(new PureNFATransition[]{initialStateTransition, initialStateTransition}); } - PureNFATransition finalStateTransition = createEmptyTransition(unAnchoredFinalState, dummyInitialState); - if (root.hasDollar()) { - dummyInitialState.setPredecessors(new PureNFATransition[]{createEmptyTransition(anchoredFinalState, dummyInitialState), finalStateTransition}); - } else { - dummyInitialState.setPredecessors(new PureNFATransition[]{finalStateTransition, finalStateTransition}); - } - assert dummyInitialState.getId() == 0; + expandAllStates(); return new PureNFA(root, nfaStates, stateID, transitionID); } diff --git a/regex/src/com.oracle.truffle.regex/src/com/oracle/truffle/regex/tregex/nfa/PureNFAState.java b/regex/src/com.oracle.truffle.regex/src/com/oracle/truffle/regex/tregex/nfa/PureNFAState.java index 846b8c8127ba..75136ec49c73 100644 --- a/regex/src/com.oracle.truffle.regex/src/com/oracle/truffle/regex/tregex/nfa/PureNFAState.java +++ b/regex/src/com.oracle.truffle.regex/src/com/oracle/truffle/regex/tregex/nfa/PureNFAState.java @@ -212,10 +212,10 @@ public void setRecursiveReference(boolean value) { /** * A state is considered "deterministic" iff it either has only one successor, or all of its - * successors/predecessors (depending on {@code forward}) represent {@link #isCharacterClass() - * character classes}, and none of those character classes intersect. + * successors represent {@link #isCharacterClass() character classes}, and none of those + * character classes intersect. * - * @see #initIsDeterministic(boolean, CompilationBuffer) + * @see #initIsDeterministic(CompilationBuffer) */ public boolean isDeterministic() { return getFlag(FLAG_IS_DETERMINISTIC); @@ -226,33 +226,33 @@ public void setDeterministic(boolean value) { } /** - * Initializes this state's {@link #isDeterministic()}-property, depending on {@code forward}. + * Initializes this state's {@link #isDeterministic()}-property. */ - public void initIsDeterministic(boolean forward, CompilationBuffer compilationBuffer) { - setDeterministic(calcIsDeterministic(forward, compilationBuffer)); + public void initIsDeterministic(CompilationBuffer compilationBuffer) { + setDeterministic(calcIsDeterministic(compilationBuffer)); } - private boolean calcIsDeterministic(boolean forward, CompilationBuffer compilationBuffer) { - PureNFATransition[] successors = getSuccessors(forward); + private boolean calcIsDeterministic(CompilationBuffer compilationBuffer) { + PureNFATransition[] successors = getSuccessors(); if (successors.length <= 1) { return true; } - if (!successors[0].getTarget(forward).isCharacterClass()) { + if (!successors[0].getTarget().isCharacterClass()) { return false; } CodePointSetAccumulator acc = compilationBuffer.getCodePointSetAccumulator1(); if (successors.length > 8) { - acc.addSet(successors[0].getTarget(forward).getCharSet()); + acc.addSet(successors[0].getTarget().getCharSet()); } for (int i = 1; i < successors.length; i++) { - PureNFAState target = successors[i].getTarget(forward); + PureNFAState target = successors[i].getTarget(); if (!target.isCharacterClass()) { return false; } if (successors.length <= 8) { // avoid calculating union sets on low number of successors for (int j = 0; j < i; j++) { - if (successors[j].getTarget(forward).getCharSet().intersects(target.getCharSet())) { + if (successors[j].getTarget().getCharSet().intersects(target.getCharSet())) { return false; } } diff --git a/regex/src/com.oracle.truffle.regex/src/com/oracle/truffle/regex/tregex/nfa/PureNFATransitionGenerator.java b/regex/src/com.oracle.truffle.regex/src/com/oracle/truffle/regex/tregex/nfa/PureNFATransitionGenerator.java index d86d6f2ea6c8..fb4618728218 100644 --- a/regex/src/com.oracle.truffle.regex/src/com/oracle/truffle/regex/tregex/nfa/PureNFATransitionGenerator.java +++ b/regex/src/com.oracle.truffle.regex/src/com/oracle/truffle/regex/tregex/nfa/PureNFATransitionGenerator.java @@ -66,7 +66,6 @@ public PureNFATransitionGenerator(RegexAST ast, PureNFAGenerator nfaGen) { public void generateTransitions(PureNFAState state) { this.curState = state; Term root = state.getAstNode(ast); - setCanTraverseCaret(state.isAnchoredInitialState() || state.canMatchZeroWidth()); transitionBuffer.clear(); run(root); curState.setSuccessors(transitionBuffer.toArray(new PureNFATransition[transitionBuffer.length()])); @@ -82,14 +81,11 @@ protected void visit(RegexASTNode target) { PureNFAState targetState; if (target instanceof MatchFound) { - targetState = dollarsOnPath() ? nfaGen.getAnchoredFinalState() : nfaGen.getUnAnchoredFinalState(); + targetState = (isReverse() && caretsOnPath() || !isReverse() && dollarsOnPath()) ? nfaGen.getAnchoredFinalState() : nfaGen.getUnAnchoredFinalState(); } else { targetState = nfaGen.getOrCreateState((Term) target); } - targetState.incPredecessors(); - transitionBuffer.add(new PureNFATransition(nfaGen.getTransitionIdCounter().inc(), curState, targetState, getGroupBoundaries(), - curState.canMatchZeroWidth() || target.isGroup() ? caretsOnPath() : false, - target.isCharacterClass() ? false : dollarsOnPath(), getQuantifierGuardsOnPath())); + transitionBuffer.add(new PureNFATransition(nfaGen.getTransitionIdCounter().inc(), curState, targetState, getGroupBoundaries(), caretsOnPath(), dollarsOnPath(), getQuantifierGuardsOnPath())); } @Override @@ -101,15 +97,29 @@ protected void leaveLookAhead(LookAheadAssertion assertion) { } private boolean pruneLookarounds(RegexASTNode target) { - if (curState.isLookAhead(ast) && target.isCharacterClass()) { - LookAheadAssertion la = curState.getAstNode(ast).asLookAheadAssertion(); - if (!la.isNegated() && la.startsWithCharClass()) { - return !la.getGroup().getFirstAlternative().getFirstTerm().asCharacterClass().getCharSet().intersects(target.asCharacterClass().getCharSet()); + if (isReverse()) { + if (curState.isLookBehind(ast) && target.isCharacterClass()) { + LookBehindAssertion lb = curState.getAstNode(ast).asLookBehindAssertion(); + if (!lb.isNegated() && lb.endsWithCharClass()) { + return !lb.getGroup().getFirstAlternative().getLastTerm().asCharacterClass().getCharSet().intersects(target.asCharacterClass().getCharSet()); + } + } else if (curState.isCharacterClass() && target instanceof LookAheadAssertion) { + LookAheadAssertion la = (LookAheadAssertion) target; + if (!la.isNegated() && la.startsWithCharClass()) { + return !la.getGroup().getFirstAlternative().getFirstTerm().asCharacterClass().getCharSet().intersects(curState.getCharSet()); + } } - } else if (curState.isCharacterClass() && target instanceof LookBehindAssertion) { - LookBehindAssertion lb = (LookBehindAssertion) target; - if (!lb.isNegated() && lb.endsWithCharClass()) { - return !lb.getGroup().getFirstAlternative().getLastTerm().asCharacterClass().getCharSet().intersects(curState.getCharSet()); + } else { + if (curState.isLookAhead(ast) && target.isCharacterClass()) { + LookAheadAssertion la = curState.getAstNode(ast).asLookAheadAssertion(); + if (!la.isNegated() && la.startsWithCharClass()) { + return !la.getGroup().getFirstAlternative().getFirstTerm().asCharacterClass().getCharSet().intersects(target.asCharacterClass().getCharSet()); + } + } else if (curState.isCharacterClass() && target instanceof LookBehindAssertion) { + LookBehindAssertion lb = (LookBehindAssertion) target; + if (!lb.isNegated() && lb.endsWithCharClass()) { + return !lb.getGroup().getFirstAlternative().getLastTerm().asCharacterClass().getCharSet().intersects(curState.getCharSet()); + } } } return false; @@ -119,4 +129,9 @@ private boolean pruneLookarounds(RegexASTNode target) { protected boolean isBuildingDFA() { return false; } + + @Override + protected boolean canPruneAfterUnconditionalFinalState() { + return true; + } } diff --git a/regex/src/com.oracle.truffle.regex/src/com/oracle/truffle/regex/tregex/nodes/nfa/TRegexBacktrackingNFAExecutorNode.java b/regex/src/com.oracle.truffle.regex/src/com/oracle/truffle/regex/tregex/nodes/nfa/TRegexBacktrackingNFAExecutorNode.java index 9fc1fee4b98a..ad8f699ee3ad 100644 --- a/regex/src/com.oracle.truffle.regex/src/com/oracle/truffle/regex/tregex/nodes/nfa/TRegexBacktrackingNFAExecutorNode.java +++ b/regex/src/com.oracle.truffle.regex/src/com/oracle/truffle/regex/tregex/nodes/nfa/TRegexBacktrackingNFAExecutorNode.java @@ -156,8 +156,8 @@ public TRegexBacktrackingNFAExecutorNode(RegexAST ast, PureNFA nfa, int numberOf if (s.isCharacterClass()) { matchers[i] = CharMatchers.createMatcher(s.getCharSet(), compilationBuffer); } - maxTransitions = Math.max(maxTransitions, s.getSuccessors(isForward()).length); - s.initIsDeterministic(isForward(), compilationBuffer); + maxTransitions = Math.max(maxTransitions, s.getSuccessors().length); + s.initIsDeterministic(compilationBuffer); } for (TRegexExecutorBaseNode subExecutor : subExecutors) { if (subExecutor instanceof TRegexBacktrackingNFAExecutorNode) { @@ -335,11 +335,11 @@ private void runMergeExplode(VirtualFrame frame, TRegexBacktrackingNFAExecutorLo /* * Begin of the regex match. Here, we select the inital state based on "^". */ - if (nfa.getAnchoredInitialState(isForward()) != nfa.getUnAnchoredInitialState(isForward()) && inputAtBegin(locals)) { - ip = nfa.getAnchoredInitialState(isForward()).getId(); + if (nfa.getAnchoredInitialState() != nfa.getUnAnchoredInitialState() && inputAtBegin(locals)) { + ip = nfa.getAnchoredInitialState().getId(); continue; } else { - ip = nfa.getUnAnchoredInitialState(isForward()).getId(); + ip = nfa.getUnAnchoredInitialState().getId(); continue; } } else if (ip == IP_BACKTRACK) { @@ -390,7 +390,7 @@ private void runMergeExplode(VirtualFrame frame, TRegexBacktrackingNFAExecutorLo } locals.setLastInitialStateIndex(locals.getIndex()); locals.resetToInitialState(); - ip = nfa.getUnAnchoredInitialState(isForward()).getId(); + ip = nfa.getUnAnchoredInitialState().getId(); continue; } else { break; @@ -419,12 +419,12 @@ private void runMergeExplode(VirtualFrame frame, TRegexBacktrackingNFAExecutorLo */ final PureNFAState curState = nfa.getState(ip); CompilerAsserts.partialEvaluationConstant(curState); - final PureNFATransition[] successors = curState.getSuccessors(isForward()); + final PureNFATransition[] successors = curState.getSuccessors(); CompilerAsserts.partialEvaluationConstant(successors); CompilerAsserts.partialEvaluationConstant(successors.length); final int nextIp = runState(frame, locals, codeRange, curState); for (int i = 0; i < successors.length; i++) { - int targetIp = successors[i].getTarget(isForward()).getId(); + int targetIp = successors[i].getTarget().getId(); if (targetIp == nextIp) { CompilerAsserts.partialEvaluationConstant(targetIp); ip = targetIp; @@ -479,7 +479,7 @@ private int runState(VirtualFrame frame, TRegexBacktrackingNFAExecutorLocals loc locals.setIndex(backrefResult); } } - PureNFATransition[] successors = curState.getSuccessors(isForward()); + PureNFATransition[] successors = curState.getSuccessors(); CompilerAsserts.partialEvaluationConstant(successors); CompilerAsserts.partialEvaluationConstant(successors.length); boolean atEnd = inputAtEnd(locals); @@ -499,7 +499,7 @@ private int runState(VirtualFrame frame, TRegexBacktrackingNFAExecutorLocals loc CompilerAsserts.partialEvaluationConstant(transition); if (tryUpdateState(frame, locals, codeRange, transition, index, atEnd, c)) { locals.restoreIndex(); - return transition.getTarget(isForward()).getId(); + return transition.getTarget().getId(); } else { locals.writeFrame(currentFrame); } @@ -512,7 +512,7 @@ private int runState(VirtualFrame frame, TRegexBacktrackingNFAExecutorLocals loc if (transitionMatches(frame, locals, codeRange, transition, index, atEnd, c)) { updateState(locals, transition, index); locals.restoreIndex(); - return transition.getTarget(isForward()).getId(); + return transition.getTarget().getId(); } } return IP_BACKTRACK; @@ -529,7 +529,7 @@ private int runState(VirtualFrame frame, TRegexBacktrackingNFAExecutorLocals loc CompilerAsserts.partialEvaluationConstant(transition); if (tryUpdateState(frame, locals, codeRange, transition, index, atEnd, c)) { hasMatchingTransition = true; - PureNFAState target = transition.getTarget(isForward()); + PureNFAState target = transition.getTarget(); CompilerAsserts.partialEvaluationConstant(target); if (isAcceptableFinalState(target, locals)) { locals.setResult(); @@ -607,7 +607,7 @@ private int runState(VirtualFrame frame, TRegexBacktrackingNFAExecutorLocals loc * will ever be popped. Therefore, we have a dedicated slot in our "locals" * object that represents the last pushed final state. */ - if (isAcceptableFinalState(transition.getTarget(isForward()), locals)) { + if (isAcceptableFinalState(transition.getTarget(), locals)) { locals.setResult(); lastFinal = i; nMatched--; @@ -635,7 +635,7 @@ private int runState(VirtualFrame frame, TRegexBacktrackingNFAExecutorLocals loc for (int i = iStart; i > iEnd; i--) { PureNFATransition transition = successors[i]; CompilerAsserts.partialEvaluationConstant(transition); - PureNFAState target = transition.getTarget(isForward()); + PureNFAState target = transition.getTarget(); CompilerAsserts.partialEvaluationConstant(target); if ((bs & 1) != 0) { if (isAcceptableFinalState(target, locals)) { @@ -664,7 +664,7 @@ private int runState(VirtualFrame frame, TRegexBacktrackingNFAExecutorLocals loc } private boolean isAcceptableFinalState(PureNFAState state, TRegexBacktrackingNFAExecutorLocals locals) { - return state.isFinalState(isForward()) && !(isMustAdvance() && locals.getIndex() == locals.getFromIndex()); + return state.isFinalState() && !(isMustAdvance() && locals.getIndex() == locals.getFromIndex()); } /** @@ -722,7 +722,7 @@ protected static boolean subMatchFailed(PureNFAState curState, Object subMatchRe @ExplodeLoop protected boolean transitionMatches(VirtualFrame frame, TRegexBacktrackingNFAExecutorLocals locals, TruffleString.CodeRange codeRange, PureNFATransition transition, int index, boolean atEnd, int c) { - PureNFAState target = transition.getTarget(isForward()); + PureNFAState target = transition.getTarget(); CompilerAsserts.partialEvaluationConstant(target); if (transition.hasCaretGuard() && index != 0) { return false; @@ -730,13 +730,11 @@ protected boolean transitionMatches(VirtualFrame frame, TRegexBacktrackingNFAExe if (transition.hasDollarGuard() && index < locals.getMaxIndex()) { return false; } - int nGuards = transition.getQuantifierGuards().length; - for (int i = isForward() ? 0 : nGuards - 1; isForward() ? i < nGuards : i >= 0; i = inputIncRaw(i)) { - QuantifierGuard guard = transition.getQuantifierGuards()[i]; + for (QuantifierGuard guard : transition.getQuantifierGuards()) { CompilerAsserts.partialEvaluationConstant(guard); Quantifier q = guard.getQuantifier(); CompilerAsserts.partialEvaluationConstant(q); - switch (isForward() ? guard.getKind() : guard.getKindReverse()) { + switch (guard.getKind()) { case loop: // retreat if quantifier count is at maximum if (locals.getQuantifierCount(q) == q.getMax()) { @@ -786,8 +784,8 @@ protected boolean transitionMatches(VirtualFrame frame, TRegexBacktrackingNFAExe } switch (target.getKind()) { case PureNFAState.KIND_INITIAL_OR_FINAL_STATE: - assert !target.isInitialState(isForward()); - return target.isAnchoredFinalState(isForward()) ? atEnd : true; + assert !target.isInitialState(); + return target.isAnchoredFinalState() ? atEnd : true; case PureNFAState.KIND_CHARACTER_CLASS: return !atEnd && matchers[target.getId()].match(c); case PureNFAState.KIND_SUB_MATCHER: @@ -817,7 +815,6 @@ protected static int getBackRefBoundary(TRegexBacktrackingNFAExecutorLocals loca @ExplodeLoop protected void updateState(TRegexBacktrackingNFAExecutorLocals locals, PureNFATransition transition, int index) { CompilerAsserts.partialEvaluationConstant(transition); - int nGuards = transition.getQuantifierGuards().length; if (isRecursiveBackreferences()) { /* * Note: Updating the recursive back-reference boundaries before all other quantifier @@ -825,8 +822,7 @@ protected void updateState(TRegexBacktrackingNFAExecutorLocals locals, PureNFATr * OracleDBFlavor. */ assert isForward(); - for (int i = 0; i < nGuards; i++) { - QuantifierGuard guard = transition.getQuantifierGuards()[i]; + for (QuantifierGuard guard : transition.getQuantifierGuards()) { CompilerAsserts.partialEvaluationConstant(guard); if (guard.getKind() == QuantifierGuard.Kind.updateRecursiveBackrefPointer) { locals.saveRecursiveBackrefGroupStart(guard.getIndex()); @@ -834,12 +830,11 @@ protected void updateState(TRegexBacktrackingNFAExecutorLocals locals, PureNFATr } } locals.apply(transition, index); - for (int i = isForward() ? 0 : nGuards - 1; isForward() ? i < nGuards : i >= 0; i += (isForward() ? 1 : -1)) { - QuantifierGuard guard = transition.getQuantifierGuards()[i]; + for (QuantifierGuard guard : transition.getQuantifierGuards()) { CompilerAsserts.partialEvaluationConstant(guard); Quantifier q = guard.getQuantifier(); CompilerAsserts.partialEvaluationConstant(q); - switch (isForward() ? guard.getKind() : guard.getKindReverse()) { + switch (guard.getKind()) { case enter: case loop: case loopInc: @@ -864,7 +859,7 @@ protected void updateState(TRegexBacktrackingNFAExecutorLocals locals, PureNFATr break; } } - locals.saveIndex(getNewIndex(locals, transition.getTarget(isForward()), index)); + locals.saveIndex(getNewIndex(locals, transition.getTarget(), index)); } /** @@ -893,7 +888,7 @@ protected void updateState(TRegexBacktrackingNFAExecutorLocals locals, PureNFATr protected boolean tryUpdateState(VirtualFrame frame, TRegexBacktrackingNFAExecutorLocals locals, TruffleString.CodeRange codeRange, PureNFATransition transition, int index, boolean atEnd, int c) { CompilerAsserts.partialEvaluationConstant(transition); - PureNFAState target = transition.getTarget(isForward()); + PureNFAState target = transition.getTarget(); CompilerAsserts.partialEvaluationConstant(target); if (transition.hasCaretGuard() && index != 0) { return false; @@ -903,8 +898,8 @@ protected boolean tryUpdateState(VirtualFrame frame, TRegexBacktrackingNFAExecut } switch (target.getKind()) { case PureNFAState.KIND_INITIAL_OR_FINAL_STATE: - assert !target.isInitialState(isForward()); - if (target.isAnchoredFinalState(isForward()) && !atEnd) { + assert !target.isInitialState(); + if (target.isAnchoredFinalState() && !atEnd) { return false; } break; @@ -930,13 +925,11 @@ protected boolean tryUpdateState(VirtualFrame frame, TRegexBacktrackingNFAExecut default: throw CompilerDirectives.shouldNotReachHere(); } - int nGuards = transition.getQuantifierGuards().length; - for (int i = isForward() ? 0 : nGuards - 1; isForward() ? i < nGuards : i >= 0; i = inputIncRaw(i)) { - QuantifierGuard guard = transition.getQuantifierGuards()[i]; + for (QuantifierGuard guard : transition.getQuantifierGuards()) { CompilerAsserts.partialEvaluationConstant(guard); Quantifier q = guard.getQuantifier(); CompilerAsserts.partialEvaluationConstant(q); - switch (isForward() ? guard.getKind() : guard.getKindReverse()) { + switch (guard.getKind()) { case enter: case loopInc: locals.incQuantifierCount(q); diff --git a/regex/src/com.oracle.truffle.regex/src/com/oracle/truffle/regex/tregex/parser/ast/MatchFound.java b/regex/src/com.oracle.truffle.regex/src/com/oracle/truffle/regex/tregex/parser/ast/MatchFound.java index a4b7c5975f64..e1165225b6af 100644 --- a/regex/src/com.oracle.truffle.regex/src/com/oracle/truffle/regex/tregex/parser/ast/MatchFound.java +++ b/regex/src/com.oracle.truffle.regex/src/com/oracle/truffle/regex/tregex/parser/ast/MatchFound.java @@ -79,6 +79,11 @@ public MatchFound copyRecursive(RegexAST ast, CompilationBuffer compilationBuffe throw CompilerDirectives.shouldNotReachHere(); } + /** + * Points to the body of a regular expression when this node is treated as an initial state of + * an NFA. If this node represents an initial state, then this points to the first expression. + * If this node represents a final state, then this points to the last expression. + */ public RegexASTNode getNext() { return next; } diff --git a/regex/src/com.oracle.truffle.regex/src/com/oracle/truffle/regex/tregex/parser/ast/PositionAssertion.java b/regex/src/com.oracle.truffle.regex/src/com/oracle/truffle/regex/tregex/parser/ast/PositionAssertion.java index 214b75d736dc..3fe8e36522e9 100644 --- a/regex/src/com.oracle.truffle.regex/src/com/oracle/truffle/regex/tregex/parser/ast/PositionAssertion.java +++ b/regex/src/com.oracle.truffle.regex/src/com/oracle/truffle/regex/tregex/parser/ast/PositionAssertion.java @@ -103,6 +103,11 @@ public Term copyRecursive(RegexAST ast, CompilationBuffer compilationBuffer) { return copy(ast); } + /** + * Points to the body of a regular expression when this node is treated as an initial state of + * an NFA. If this {@link #isCaret()}, then this returns the next expression. If this + * {@link #isDollar()}, then this returns the previous expression. + */ public RegexASTNode getNext() { return next; } diff --git a/regex/src/com.oracle.truffle.regex/src/com/oracle/truffle/regex/tregex/parser/ast/RegexASTNode.java b/regex/src/com.oracle.truffle.regex/src/com/oracle/truffle/regex/tregex/parser/ast/RegexASTNode.java index dde325714e7b..9f1213a5ad40 100644 --- a/regex/src/com.oracle.truffle.regex/src/com/oracle/truffle/regex/tregex/parser/ast/RegexASTNode.java +++ b/regex/src/com.oracle.truffle.regex/src/com/oracle/truffle/regex/tregex/parser/ast/RegexASTNode.java @@ -237,7 +237,7 @@ public void setHasCaret(boolean hasCaret) { } /** - * Subexpression contains {@link #isCaret() "$"}. + * Subexpression contains {@link #isDollar() "$"}. */ public boolean hasDollar() { return isFlagSet(FLAG_HAS_DOLLAR); diff --git a/regex/src/com.oracle.truffle.regex/src/com/oracle/truffle/regex/tregex/parser/ast/RegexASTSubtreeRootNode.java b/regex/src/com.oracle.truffle.regex/src/com/oracle/truffle/regex/tregex/parser/ast/RegexASTSubtreeRootNode.java index 47f5c7c0b046..cd9b96d754f5 100644 --- a/regex/src/com.oracle.truffle.regex/src/com/oracle/truffle/regex/tregex/parser/ast/RegexASTSubtreeRootNode.java +++ b/regex/src/com.oracle.truffle.regex/src/com/oracle/truffle/regex/tregex/parser/ast/RegexASTSubtreeRootNode.java @@ -137,6 +137,12 @@ public void setGroup(Group group) { if (unAnchoredInitialState != null) { unAnchoredInitialState.setNext(group); } + if (anchoredFinalState != null) { + anchoredFinalState.setNext(group); + } + if (matchFound != null) { + matchFound.setNext(group); + } } /** @@ -149,6 +155,7 @@ public MatchFound getMatchFound() { public void setMatchFound(MatchFound matchFound) { this.matchFound = matchFound; matchFound.setParent(this); + matchFound.setNext(group); } public Term getAnchoredInitialState() { @@ -178,6 +185,7 @@ public Term getAnchoredFinalState() { public void setAnchoredFinalState(PositionAssertion anchoredFinalState) { this.anchoredFinalState = anchoredFinalState; anchoredFinalState.setParent(this); + anchoredFinalState.setNext(group); } @Override diff --git a/regex/src/com.oracle.truffle.regex/src/com/oracle/truffle/regex/tregex/parser/ast/visitors/MarkLookBehindEntriesVisitor.java b/regex/src/com.oracle.truffle.regex/src/com/oracle/truffle/regex/tregex/parser/ast/visitors/MarkLookBehindEntriesVisitor.java index 8f4772efa84b..5af417cdfacd 100644 --- a/regex/src/com.oracle.truffle.regex/src/com/oracle/truffle/regex/tregex/parser/ast/visitors/MarkLookBehindEntriesVisitor.java +++ b/regex/src/com.oracle.truffle.regex/src/com/oracle/truffle/regex/tregex/parser/ast/visitors/MarkLookBehindEntriesVisitor.java @@ -80,7 +80,7 @@ public MarkLookBehindEntriesVisitor(RegexAST ast) { curLookAheadBoundariesHit = StateSet.create(ast); newLookAheadBoundariesHit = StateSet.create(ast); setCanTraverseCaret(false); - setReverse(); + setReverse(true); } public void run() { @@ -163,4 +163,9 @@ protected void leaveLookAhead(LookAheadAssertion assertion) { protected boolean isBuildingDFA() { return true; } + + @Override + protected boolean canPruneAfterUnconditionalFinalState() { + return false; + } } diff --git a/regex/src/com.oracle.truffle.regex/src/com/oracle/truffle/regex/tregex/parser/ast/visitors/NFATraversalRegexASTVisitor.java b/regex/src/com.oracle.truffle.regex/src/com/oracle/truffle/regex/tregex/parser/ast/visitors/NFATraversalRegexASTVisitor.java index 0594e2139522..413a28e5e675 100644 --- a/regex/src/com.oracle.truffle.regex/src/com/oracle/truffle/regex/tregex/parser/ast/visitors/NFATraversalRegexASTVisitor.java +++ b/regex/src/com.oracle.truffle.regex/src/com/oracle/truffle/regex/tregex/parser/ast/visitors/NFATraversalRegexASTVisitor.java @@ -161,7 +161,7 @@ public abstract class NFATraversalRegexASTVisitor { * equivalent, they must be equal in the following parameters: *

    *
  • the {@link #cur current node}
  • - *
  • the set of traversed {@link PositionAssertion dollar-assertions}
  • + *
  • the set of traversed {@link PositionAssertion position assertions}
  • *
  • the set of traversed {@link LookAroundAssertion}s
  • *
  • the {@link QuantifierGuard}s incurred by the traversal
  • *
  • the resulting {@link GroupBoundaries} (updates, clears, last group)
  • @@ -256,12 +256,18 @@ protected TBitSet getCurrentMatchedConditionGroups() { return currentMatchedConditionGroups; } - public void setReverse() { - this.forward = false; + protected boolean isReverse() { + return !forward; + } + + public void setReverse(boolean reverse) { + this.forward = !reverse; } protected abstract boolean isBuildingDFA(); + protected abstract boolean canPruneAfterUnconditionalFinalState(); + private boolean canTraverseLookArounds() { return isBuildingDFA(); } @@ -308,7 +314,7 @@ protected void run(Term runRoot) { } RegexASTNode target = pathGetNode(curPath.peek()); visit(target); - if (target.isMatchFound() && forward && !dollarsOnPath() && lookAroundsOnPath.isEmpty() && !hasQuantifierGuards() && !caretsOnPath()) { + if (canPruneAfterUnconditionalFinalState() && target.isMatchFound() && !dollarsOnPath() && !caretsOnPath() && lookAroundsOnPath.isEmpty() && !hasQuantifierGuards()) { /* * Transitions after an unconditional final state transition will never be taken, so * it is safe to prune them. @@ -496,9 +502,8 @@ private boolean doAdvance() { } } else { assert cur.isCharacterClass() || cur.isBackReference() || cur.isMatchFound() || cur.isAtomicGroup() || (!canTraverseLookArounds() && cur.isLookAroundAssertion()); - if (forward && dollarsOnPath() && cur.isCharacterClass()) { - // don't visit CharacterClass nodes if we traversed dollar - PositionAssertions - // already + if ((forward && dollarsOnPath() || !forward && caretsOnPath()) && cur.isCharacterClass()) { + // don't visit CharacterClass nodes if we traversed PositionAssertions already return retreat(); } return true; @@ -672,7 +677,7 @@ private boolean deduplicatePath(boolean internal) { boolean captureGroupsMatter = ast.getOptions().getFlavor().backreferencesToUnmatchedGroupsFail() || (isBuildingDFA() && ast.getProperties().hasConditionalBackReferences()); DeduplicationKey key = new DeduplicationKey(cur, lookAroundsOnPath, - dollarsOnPath, + forward ? dollarsOnPath : caretsOnPath, quantifierGuards, internal ? insideEmptyGuardGroup : null, captureGroupsMatter ? captureGroupUpdates : null, @@ -815,7 +820,7 @@ private void pushGroupEnter(Group group, int groupAltIndex) { curPath.add(createPathElement(group) | (groupAltIndex << PATH_GROUP_ALT_INDEX_OFFSET) | PATH_GROUP_ACTION_ENTER); // Capture groups if (group.isCapturing()) { - captureGroupUpdate(group.getBoundaryIndexStart()); + captureGroupUpdate(forward ? group.getBoundaryIndexStart() : group.getBoundaryIndexEnd()); } if (!ast.getOptions().getFlavor().nestedCaptureGroupsKeptOnLoopReentry() && group.hasQuantifier() && group.hasEnclosedCaptureGroups()) { int lo = Group.groupNumberToBoundaryIndexStart(group.getEnclosedCaptureGroupsLow()); @@ -838,7 +843,7 @@ private void pushGroupEnter(Group group, int groupAltIndex) { } } if (ast.getOptions().getFlavor().matchesTransitionsStepByStep() && group.isCapturing()) { - pushQuantifierGuard(QuantifierGuard.createUpdateCG(group.getBoundaryIndexStart())); + pushQuantifierGuard(QuantifierGuard.createUpdateCG(forward ? group.getBoundaryIndexStart() : group.getBoundaryIndexEnd())); } if (group.isConditionalBackReferenceGroup()) { pushQuantifierGuard(getConditionalBackReferenceGroupQuantifierGuard(group, groupAltIndex)); @@ -855,7 +860,7 @@ private int popGroupEnter(Group group) { popQuantifierGuard(getConditionalBackReferenceGroupQuantifierGuard(group, groupAltIndex)); } if (ast.getOptions().getFlavor().matchesTransitionsStepByStep() && group.isCapturing()) { - popQuantifierGuard(QuantifierGuard.createUpdateCG(group.getBoundaryIndexStart())); + popQuantifierGuard(QuantifierGuard.createUpdateCG(forward ? group.getBoundaryIndexStart() : group.getBoundaryIndexEnd())); } if (group.hasQuantifier()) { Quantifier quantifier = group.getQuantifier(); @@ -896,7 +901,7 @@ private void pushGroupExit(Group group) { curPath.add(createPathElement(group) | PATH_GROUP_ACTION_EXIT); // Capture groups if (group.isCapturing()) { - captureGroupUpdate(group.getBoundaryIndexEnd()); + captureGroupUpdate(forward ? group.getBoundaryIndexEnd() : group.getBoundaryIndexStart()); if (ast.getOptions().getFlavor().usesLastGroupResultField() && group.getGroupNumber() != 0) { lastGroupUpdate(group.getGroupNumber()); } @@ -916,7 +921,7 @@ private void pushGroupExit(Group group) { } pushRecursiveBackrefUpdates(group); if (ast.getOptions().getFlavor().matchesTransitionsStepByStep() && group.isCapturing()) { - pushQuantifierGuard(QuantifierGuard.createUpdateCG(group.getBoundaryIndexEnd())); + pushQuantifierGuard(QuantifierGuard.createUpdateCG(forward ? group.getBoundaryIndexEnd() : group.getBoundaryIndexStart())); } } } @@ -926,7 +931,7 @@ private void popGroupExit(Group group) { // Quantifier guards if (useQuantifierGuards()) { if (ast.getOptions().getFlavor().matchesTransitionsStepByStep() && group.isCapturing()) { - popQuantifierGuard(QuantifierGuard.createUpdateCG(group.getBoundaryIndexEnd())); + popQuantifierGuard(QuantifierGuard.createUpdateCG(forward ? group.getBoundaryIndexEnd() : group.getBoundaryIndexStart())); } popRecursiveBackrefUpdates(group); if (group.hasQuantifier()) { @@ -983,8 +988,8 @@ private void pushGroupPassThrough(Group group, int groupAltIndex) { } pushRecursiveBackrefUpdates(group); if (ast.getOptions().getFlavor().matchesTransitionsStepByStep() && group.isCapturing()) { - pushQuantifierGuard(QuantifierGuard.createUpdateCG(group.getBoundaryIndexStart())); - pushQuantifierGuard(QuantifierGuard.createUpdateCG(group.getBoundaryIndexEnd())); + pushQuantifierGuard(QuantifierGuard.createUpdateCG(forward ? group.getBoundaryIndexStart() : group.getBoundaryIndexEnd())); + pushQuantifierGuard(QuantifierGuard.createUpdateCG(forward ? group.getBoundaryIndexEnd() : group.getBoundaryIndexStart())); } if (group.isConditionalBackReferenceGroup()) { pushQuantifierGuard(getConditionalBackReferenceGroupQuantifierGuard(group, groupAltIndex)); @@ -1000,8 +1005,8 @@ private int popGroupPassThrough(Group group) { popQuantifierGuard(getConditionalBackReferenceGroupQuantifierGuard(group, groupAltIndex)); } if (ast.getOptions().getFlavor().matchesTransitionsStepByStep() && group.isCapturing()) { - popQuantifierGuard(QuantifierGuard.createUpdateCG(group.getBoundaryIndexEnd())); - popQuantifierGuard(QuantifierGuard.createUpdateCG(group.getBoundaryIndexStart())); + popQuantifierGuard(QuantifierGuard.createUpdateCG(forward ? group.getBoundaryIndexEnd() : group.getBoundaryIndexStart())); + popQuantifierGuard(QuantifierGuard.createUpdateCG(forward ? group.getBoundaryIndexStart() : group.getBoundaryIndexEnd())); } popRecursiveBackrefUpdates(group); if (group.hasQuantifier()) { @@ -1043,7 +1048,7 @@ private void pushGroupEscape(Group group) { } } if (ast.getOptions().getFlavor().matchesTransitionsStepByStep() && group.isCapturing()) { - pushQuantifierGuard(QuantifierGuard.createUpdateCG(group.getBoundaryIndexEnd())); + pushQuantifierGuard(QuantifierGuard.createUpdateCG(forward ? group.getBoundaryIndexEnd() : group.getBoundaryIndexStart())); } } } @@ -1053,7 +1058,7 @@ private void popGroupEscape(Group group) { // Quantifier guards if (useQuantifierGuards()) { if (ast.getOptions().getFlavor().matchesTransitionsStepByStep() && group.isCapturing()) { - popQuantifierGuard(QuantifierGuard.createUpdateCG(group.getBoundaryIndexEnd())); + popQuantifierGuard(QuantifierGuard.createUpdateCG(forward ? group.getBoundaryIndexEnd() : group.getBoundaryIndexStart())); } if (group.hasQuantifier()) { Quantifier quantifier = group.getQuantifier(); @@ -1187,10 +1192,10 @@ private static final class DeduplicationKey { private final int lastGroup; private final int hashCode; - DeduplicationKey(RegexASTNode targetNode, StateSet lookAroundsOnPath, StateSet dollarsOnPath, + DeduplicationKey(RegexASTNode targetNode, StateSet lookAroundsOnPath, StateSet positionAssertionsOnPath, QuantifierGuardsLinkedList quantifierGuards, StateSet insideEmptyGuardGroup, TBitSet captureGroupUpdates, TBitSet captureGroupClears, int lastGroup) { this.nodesInvolved = lookAroundsOnPath.copy(); - this.nodesInvolved.addAll(dollarsOnPath); + this.nodesInvolved.addAll(positionAssertionsOnPath); this.nodesInvolved.add(targetNode); this.quantifierGuards = quantifierGuards; this.insideEmptyGuardGroup = insideEmptyGuardGroup == null ? null : insideEmptyGuardGroup.copy(); From c2d163de335dfb7e5816fabcac2aadd4c33c3a40 Mon Sep 17 00:00:00 2001 From: Christian Haeubl Date: Tue, 5 Dec 2023 13:03:18 +0100 Subject: [PATCH 170/593] Minor simplifications and cleanups. --- .../com/oracle/svm/core/deopt/SubstrateSpeculationLog.java | 6 +++--- .../com/oracle/svm/core/heap/RuntimeCodeCacheCleaner.java | 2 +- .../src/com/oracle/svm/core/stack/JavaStackWalker.java | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/deopt/SubstrateSpeculationLog.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/deopt/SubstrateSpeculationLog.java index 9a4cd050a44e..c279479b1628 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/deopt/SubstrateSpeculationLog.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/deopt/SubstrateSpeculationLog.java @@ -65,11 +65,11 @@ private LogEntry(SpeculationReason reason, LogEntry next) { public void addFailedSpeculation(SpeculationReason speculation) { /* - * This method is called from inside the VMOperation that performs deoptimization, and - * thefore must not be synchronization free. Note that this even precludes using a + * This method may be called from inside a VMOperation that performs deoptimization, and + * therefore must be synchronization free. Note that this even precludes using a * ConcurrentHashMap, because it also has some code paths that require synchronization. * - * Therefore we use our own very simple atomic linked list. + * Therefore, we use our own very simple atomic linked list. */ while (true) { LogEntry oldHead = addedFailedSpeculationsHead; diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/heap/RuntimeCodeCacheCleaner.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/heap/RuntimeCodeCacheCleaner.java index af6ca78c2898..384438ec486c 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/heap/RuntimeCodeCacheCleaner.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/heap/RuntimeCodeCacheCleaner.java @@ -50,7 +50,7 @@ public final class RuntimeCodeCacheCleaner implements CodeInfoVisitor { *
      *
    • {@link SpeculationReason} objects are embedded in the code and only needed when a * deoptimization is triggered.
    • - *
    • {@link SharedRuntimeMethod} objects are sometimes used as artifical methods (e.g., for + *
    • {@link SharedRuntimeMethod} objects are sometimes used as artificial methods (e.g., for * adapter code) and are located in the frame info object constants.
    • *
    */ diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/stack/JavaStackWalker.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/stack/JavaStackWalker.java index a8923223c386..9814ebcf0b97 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/stack/JavaStackWalker.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/stack/JavaStackWalker.java @@ -251,7 +251,7 @@ public static boolean continueWalk(JavaStackWalk walk, SimpleCodeInfoQueryResult @Uninterruptible(reason = "Not really uninterruptible, but we are about to fatally fail.", calleeMustBe = false) public static RuntimeException reportUnknownFrameEncountered(Pointer sp, CodePointer ip, DeoptimizedFrame deoptFrame) { Log log = Log.log().string("Stack walk must walk only frames of known code:"); - log.string(" sp=").hex(sp).string(" ip=").hex(ip); + log.string(" sp=").zhex(sp).string(" ip=").zhex(ip); if (DeoptimizationSupport.enabled()) { log.string(" deoptFrame=").object(deoptFrame); } From ecb1ede1a0bf6272efd174826d11cb4cc62731cf Mon Sep 17 00:00:00 2001 From: Tomas Zezula Date: Mon, 11 Dec 2023 15:30:03 +0100 Subject: [PATCH 171/593] [GR-50867] Fixed mvn-simplelanguage, mvn-simpletool gates to use the unchained build. --- truffle/ci/ci.jsonnet | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/truffle/ci/ci.jsonnet b/truffle/ci/ci.jsonnet index 7275bc2e2609..89e27e10cd2c 100644 --- a/truffle/ci/ci.jsonnet +++ b/truffle/ci/ci.jsonnet @@ -55,7 +55,7 @@ packages+: { maven: "==3.3.9" }, - mx_cmd: ["mx", "-p", "../vm", "--dynamicimports", "/graal-js"], + mx_cmd: ["mx", "-p", "../vm", "--env", "ce", "--dynamicimports", "/graal-js", "--native-images=none"], run+: [ ["set-export", "ROOT_DIR", ["pwd"]], self.mx_cmd + ["build"], @@ -76,12 +76,12 @@ maven: "==3.3.9", ruby: ">=2.1.0", }, - mx_cmd: ["mx", "-p", "../vm", "--dynamicimports", "/substratevm", "--native-images=none"], + mx_cmd: ["mx", "-p", "../vm", "--env", "ce", "--native-images=none"], run+: [ ["set-export", "ROOT_DIR", ["pwd"]], self.mx_cmd + ["build"], ["mkdir", "mxbuild/tmp_mvn_repo"], - ["mx", "maven-install", "--all-suites", "--repo", "mxbuild/tmp_mvn_repo", "--version-string", self.mx_cmd + ["graalvm-version"]], + self.mx_cmd + ["maven-deploy", "--tags=public", "--all-suites", "--all-distribution-types", "--validate=full", "--licenses=EPL-2.0,PSF-License,GPLv2-CPE,ICU,GPLv2,BSD-simplified,BSD-new,UPL,MIT", "--version-string", self.mx_cmd + ["graalvm-version"], "--suppress-javadoc", "local", "file://$ROOT_DIR/mxbuild/tmp_mvn_repo"], ["set-export", "JAVA_HOME", self.mx_cmd + ["--quiet", "--no-warning", "graalvm-home"]], ["cd", "external_repos"], ["python", "populate.py"], @@ -105,7 +105,6 @@ builds: std.flattenArrays([ [ linux_amd64 + jdk + sigtest + guard, - linux_amd64 + jdk + simple_tool_maven_project_gate + common.mach5_target, # JDK latest only works on MacOS Ventura (GR-49652) # darwin_amd64 + jdk + truffle_weekly + gate_lite + guard, darwin_aarch64 + jdk + truffle_weekly + gate_lite + guard, @@ -117,6 +116,9 @@ # The simple_language_maven_project_gate uses native-image, so we must run on labsjdk rather than oraclejdk linux_amd64 + common.labsjdk21 + simple_language_maven_project_gate, linux_amd64 + common.labsjdkLatest + simple_language_maven_project_gate, + # The simple_tool_maven_project_gate builds compiler, so we must run on labsjdk rather than oraclejdk because of compiler module rename + linux_amd64 + common.labsjdk21 + simple_tool_maven_project_gate, + linux_amd64 + common.labsjdkLatest + simple_tool_maven_project_gate, linux_amd64 + common.oraclejdk21 + truffle_gate + guard + {timelimit: "45:00"}, linux_amd64 + common.oraclejdkLatest + truffle_gate + guard + {environment+: {DISABLE_DSL_STATE_BITS_TESTS: "true"}}, From ea024db53af136fcf9198b78a85890a2d5a0441a Mon Sep 17 00:00:00 2001 From: Codrut Stancu Date: Mon, 11 Dec 2023 18:51:28 +0100 Subject: [PATCH 172/593] Refactor TranslateFieldOffset. Read field offset via ReflectionSubstitutionSupport. --- .../svm/hosted/NativeImageGenerator.java | 1 - .../AnalysisConstantReflectionProvider.java | 24 ++--------- .../svm/hosted/ameta/ReadableJavaField.java | 7 ++-- .../svm/hosted/substitute/AnnotatedField.java | 5 +-- .../hosted/substitute/ComputedValueField.java | 42 +++++++++---------- .../hosted/substitute/SubstitutionField.java | 7 ++-- 6 files changed, 32 insertions(+), 54 deletions(-) diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/NativeImageGenerator.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/NativeImageGenerator.java index fbce62ddb497..577a0139c5df 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/NativeImageGenerator.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/NativeImageGenerator.java @@ -583,7 +583,6 @@ protected void doRun(Map entryPoints, JavaMainSupport j hUniverse = new HostedUniverse(bb); hMetaAccess = new HostedMetaAccess(hUniverse, bb.getMetaAccess()); - ((AnalysisConstantReflectionProvider) bb.getConstantReflectionProvider()).setHostedMetaAccess(hMetaAccess); BeforeUniverseBuildingAccessImpl beforeUniverseBuildingConfig = new BeforeUniverseBuildingAccessImpl(featureHandler, loader, debug, hMetaAccess); featureHandler.forEachFeature(feature -> feature.beforeUniverseBuilding(beforeUniverseBuildingConfig)); diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/ameta/AnalysisConstantReflectionProvider.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/ameta/AnalysisConstantReflectionProvider.java index 3b8a93abedda..5df7adc0a78f 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/ameta/AnalysisConstantReflectionProvider.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/ameta/AnalysisConstantReflectionProvider.java @@ -47,7 +47,6 @@ import com.oracle.svm.core.FrameAccess; import com.oracle.svm.core.RuntimeAssertionsSupport; import com.oracle.svm.core.annotate.InjectAccessors; -import com.oracle.svm.core.annotate.RecomputeFieldValue; import com.oracle.svm.core.graal.meta.SharedConstantReflectionProvider; import com.oracle.svm.core.hub.DynamicHub; import com.oracle.svm.core.meta.ObjectConstantEquality; @@ -56,9 +55,7 @@ import com.oracle.svm.hosted.SVMHost; import com.oracle.svm.hosted.classinitialization.ClassInitializationSupport; import com.oracle.svm.hosted.classinitialization.SimulateClassInitializerSupport; -import com.oracle.svm.hosted.meta.HostedField; import com.oracle.svm.hosted.meta.HostedLookupSnippetReflectionProvider; -import com.oracle.svm.hosted.meta.HostedMetaAccess; import com.oracle.svm.hosted.meta.RelocatableConstant; import jdk.graal.compiler.core.common.type.TypedConstant; @@ -76,7 +73,6 @@ public class AnalysisConstantReflectionProvider extends SharedConstantReflectionProvider implements ConstantReflectionProviderExtension { private final AnalysisUniverse universe; protected final UniverseMetaAccess metaAccess; - private HostedMetaAccess hMetaAccess; private final ClassInitializationSupport classInitializationSupport; private final AnalysisMethodHandleAccessProvider methodHandleAccess; private SimulateClassInitializerSupport simulateClassInitializerSupport; @@ -88,10 +84,6 @@ public AnalysisConstantReflectionProvider(AnalysisUniverse universe, UniverseMet this.methodHandleAccess = new AnalysisMethodHandleAccessProvider(universe); } - public void setHostedMetaAccess(HostedMetaAccess hMetaAccess) { - this.hMetaAccess = hMetaAccess; - } - @Override public Boolean constantEquals(Constant x, Constant y) { if (x == y) { @@ -255,7 +247,7 @@ public JavaConstant readValue(UniverseMetaAccess suppliedMetaAccess, AnalysisFie public ValueSupplier readHostedFieldValue(AnalysisField field, JavaConstant receiver) { if (ReadableJavaField.isValueAvailable(field)) { /* Materialize and return the value. */ - return ValueSupplier.eagerValue(doReadValue(field, receiver, metaAccess)); + return ValueSupplier.eagerValue(doReadValue(field, receiver)); } /* * Return a lazy value. First, this applies to fields annotated with @@ -272,21 +264,11 @@ public ValueSupplier readHostedFieldValue(AnalysisField field, Jav /** Returns the hosted field value. The receiver must be a hosted constant. */ @Override public JavaConstant readHostedFieldValue(UniverseMetaAccess access, AnalysisField field, JavaConstant receiver) { - return interceptValue(access, field, doReadValue(field, universe.toHosted(receiver), access)); + return interceptValue(access, field, doReadValue(field, universe.toHosted(receiver))); } - /** - * The {@link HostedMetaAccess} is used to access the {@link HostedField} in the re-computation - * of {@link RecomputeFieldValue.Kind#AtomicFieldUpdaterOffset} and - * {@link RecomputeFieldValue.Kind#TranslateFieldOffset} annotated fields . - */ private JavaConstant doReadValue(AnalysisField field, JavaConstant receiver) { - Objects.requireNonNull(hMetaAccess); - return doReadValue(field, receiver, hMetaAccess); - } - - private JavaConstant doReadValue(AnalysisField field, JavaConstant receiver, UniverseMetaAccess access) { - return universe.fromHosted(ReadableJavaField.readFieldValue(access, classInitializationSupport, field.wrapped, receiver)); + return universe.fromHosted(ReadableJavaField.readFieldValue(classInitializationSupport, field.wrapped, receiver)); } /** diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/ameta/ReadableJavaField.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/ameta/ReadableJavaField.java index c183cefdf031..8d8588e0151c 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/ameta/ReadableJavaField.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/ameta/ReadableJavaField.java @@ -33,7 +33,6 @@ import com.oracle.svm.hosted.meta.HostedField; import jdk.vm.ci.meta.JavaConstant; -import jdk.vm.ci.meta.MetaAccessProvider; import jdk.vm.ci.meta.ResolvedJavaField; public interface ReadableJavaField extends ResolvedJavaField { @@ -45,7 +44,7 @@ static boolean isValueAvailable(AnalysisField field) { return field.isValueAvailable(); } - static JavaConstant readFieldValue(MetaAccessProvider metaAccess, ClassInitializationSupport classInitializationSupport, ResolvedJavaField field, JavaConstant receiver) { + static JavaConstant readFieldValue(ClassInitializationSupport classInitializationSupport, ResolvedJavaField field, JavaConstant receiver) { assert !(field instanceof AnalysisField) && !(field instanceof HostedField) : "must have been unwrapped"; if (field instanceof ReadableJavaField readableField) { @@ -55,7 +54,7 @@ static JavaConstant readFieldValue(MetaAccessProvider metaAccess, ClassInitializ * below. */ assert readableField.isValueAvailable() : "Field " + readableField.format("%H.%n") + " value not available for reading."; - return readableField.readValue(metaAccess, classInitializationSupport, receiver); + return readableField.readValue(classInitializationSupport, receiver); } else if (!classInitializationSupport.maybeInitializeAtBuildTime(field.getDeclaringClass())) { /* @@ -94,7 +93,7 @@ static JavaConstant readFieldValue(MetaAccessProvider metaAccess, ClassInitializ } } - JavaConstant readValue(MetaAccessProvider metaAccess, ClassInitializationSupport classInitializationSupport, JavaConstant receiver); + JavaConstant readValue(ClassInitializationSupport classInitializationSupport, JavaConstant receiver); /** * When this method returns true, image heap snapshotting can access the value before analysis. diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/substitute/AnnotatedField.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/substitute/AnnotatedField.java index ff5b90e160a6..ef199ce0def2 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/substitute/AnnotatedField.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/substitute/AnnotatedField.java @@ -37,7 +37,6 @@ import jdk.vm.ci.meta.JavaConstant; import jdk.vm.ci.meta.JavaType; -import jdk.vm.ci.meta.MetaAccessProvider; import jdk.vm.ci.meta.ResolvedJavaField; import jdk.vm.ci.meta.ResolvedJavaType; @@ -62,8 +61,8 @@ public AnnotationValue[] getInjectedAnnotations() { } @Override - public JavaConstant readValue(MetaAccessProvider metaAccess, ClassInitializationSupport classInitializationSupport, JavaConstant receiver) { - return ReadableJavaField.readFieldValue(metaAccess, classInitializationSupport, original, receiver); + public JavaConstant readValue(ClassInitializationSupport classInitializationSupport, JavaConstant receiver) { + return ReadableJavaField.readFieldValue(classInitializationSupport, original, receiver); } @Override diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/substitute/ComputedValueField.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/substitute/ComputedValueField.java index 0a7724cb6da3..353413539823 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/substitute/ComputedValueField.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/substitute/ComputedValueField.java @@ -43,6 +43,7 @@ import java.util.concurrent.locks.ReentrantReadWriteLock.WriteLock; import org.graalvm.collections.EconomicMap; +import org.graalvm.nativeimage.ImageSingletons; import org.graalvm.nativeimage.hosted.FieldValueTransformer; import com.oracle.graal.pointsto.infrastructure.OriginalFieldProvider; @@ -55,12 +56,12 @@ import com.oracle.svm.core.config.ConfigurationValues; import com.oracle.svm.core.fieldvaluetransformer.FieldValueTransformerWithAvailability; import com.oracle.svm.core.fieldvaluetransformer.FieldValueTransformerWithAvailability.ValueAvailability; +import com.oracle.svm.core.reflect.target.ReflectionSubstitutionSupport; import com.oracle.svm.core.util.UserError; import com.oracle.svm.core.util.VMError; import com.oracle.svm.hosted.ameta.ReadableJavaField; import com.oracle.svm.hosted.annotation.AnnotationWrapper; import com.oracle.svm.hosted.classinitialization.ClassInitializationSupport; -import com.oracle.svm.hosted.meta.HostedField; import com.oracle.svm.hosted.meta.HostedMetaAccess; import com.oracle.svm.util.ReflectionUtil; import com.oracle.svm.util.ReflectionUtil.ReflectionUtilError; @@ -71,7 +72,6 @@ import jdk.vm.ci.meta.JavaConstant; import jdk.vm.ci.meta.JavaKind; import jdk.vm.ci.meta.JavaType; -import jdk.vm.ci.meta.MetaAccessProvider; import jdk.vm.ci.meta.ResolvedJavaField; import jdk.vm.ci.meta.ResolvedJavaType; @@ -278,19 +278,19 @@ public void processSubstrate(HostedMetaAccess metaAccess) { } @Override - public JavaConstant readValue(MetaAccessProvider metaAccess, ClassInitializationSupport classInitializationSupport, JavaConstant receiver) { + public JavaConstant readValue(ClassInitializationSupport classInitializationSupport, JavaConstant receiver) { if (constantValue != null) { return constantValue; } switch (kind) { case None: case Manual: - return ReadableJavaField.readFieldValue(metaAccess, classInitializationSupport, original, receiver); + return ReadableJavaField.readFieldValue(classInitializationSupport, original, receiver); case FromAlias: assert Modifier.isStatic(annotated.getModifiers()) : "Cannot use " + kind + " on non-static alias " + annotated.format("%H.%n"); annotated.getDeclaringClass().initialize(); - constantValue = ReadableJavaField.readFieldValue(metaAccess, classInitializationSupport, annotated, null); + constantValue = ReadableJavaField.readFieldValue(classInitializationSupport, annotated, null); return constantValue; case ArrayBaseOffset: @@ -334,7 +334,7 @@ public JavaConstant readValue(MetaAccessProvider metaAccess, ClassInitialization * Note that the value computation must be inside the lock, because we want to guarantee * that field-value computers are only executed once per unique receiver. */ - result = computeValue(metaAccess, classInitializationSupport, receiver); + result = computeValue(classInitializationSupport, receiver); putCached(receiver, result); return result; } finally { @@ -342,28 +342,28 @@ public JavaConstant readValue(MetaAccessProvider metaAccess, ClassInitialization } } - private JavaConstant computeValue(MetaAccessProvider metaAccess, ClassInitializationSupport classInitializationSupport, JavaConstant receiver) { + private JavaConstant computeValue(ClassInitializationSupport classInitializationSupport, JavaConstant receiver) { assert isValueAvailable() : "Field " + format("%H.%n") + " value not available for reading."; SnippetReflectionProvider originalSnippetReflection = GraalAccess.getOriginalSnippetReflection(); JavaConstant result; Object originalValue; switch (kind) { case NewInstanceWhenNotNull: - originalValue = fetchOriginalValue(metaAccess, classInitializationSupport, receiver, originalSnippetReflection); + originalValue = fetchOriginalValue(classInitializationSupport, receiver, originalSnippetReflection); result = originalValue == null ? originalSnippetReflection.forObject(null) : createNewInstance(originalSnippetReflection); break; case NewInstance: result = createNewInstance(originalSnippetReflection); break; case AtomicFieldUpdaterOffset: - result = computeAtomicFieldUpdaterOffset(metaAccess, classInitializationSupport, receiver); + result = computeAtomicFieldUpdaterOffset(classInitializationSupport, receiver); break; case TranslateFieldOffset: - result = translateFieldOffset(metaAccess, classInitializationSupport, receiver, targetClass); + result = translateFieldOffset(classInitializationSupport, receiver, targetClass); break; case Custom: Object receiverValue = receiver == null ? null : originalSnippetReflection.asObject(Object.class, receiver); - originalValue = fetchOriginalValue(metaAccess, classInitializationSupport, receiver, originalSnippetReflection); + originalValue = fetchOriginalValue(classInitializationSupport, receiver, originalSnippetReflection); Object newValue = fieldValueTransformer.transform(receiverValue, originalValue); checkValue(newValue); result = originalSnippetReflection.forBoxed(original.getJavaKind(), newValue); @@ -411,9 +411,9 @@ private JavaConstant createNewInstance(SnippetReflectionProvider originalSnippet return result; } - private Object fetchOriginalValue(MetaAccessProvider metaAccess, ClassInitializationSupport classInitializationSupport, JavaConstant receiver, + private Object fetchOriginalValue(ClassInitializationSupport classInitializationSupport, JavaConstant receiver, SnippetReflectionProvider originalSnippetReflection) { - JavaConstant originalValueConstant = ReadableJavaField.readFieldValue(metaAccess, classInitializationSupport, original, receiver); + JavaConstant originalValueConstant = ReadableJavaField.readFieldValue(classInitializationSupport, original, receiver); if (originalValueConstant == null) { /* * The class is still uninitialized, so static fields cannot be read. Or it is an @@ -460,23 +460,23 @@ public boolean injectFinalForRuntimeCompilation() { return ReadableJavaField.injectFinalForRuntimeCompilation(original); } - private JavaConstant translateFieldOffset(MetaAccessProvider metaAccess, ClassInitializationSupport classInitializationSupport, JavaConstant receiver, Class tclass) { - long searchOffset = ReadableJavaField.readFieldValue(metaAccess, classInitializationSupport, original, receiver).asLong(); + private JavaConstant translateFieldOffset(ClassInitializationSupport classInitializationSupport, JavaConstant receiver, Class tclass) { + long searchOffset = ReadableJavaField.readFieldValue(classInitializationSupport, original, receiver).asLong(); // search the declared fields for a field with a matching offset for (Field f : tclass.getDeclaredFields()) { if (!Modifier.isStatic(f.getModifiers())) { long fieldOffset = Unsafe.getUnsafe().objectFieldOffset(f); if (fieldOffset == searchOffset) { - HostedField sf = (HostedField) metaAccess.lookupJavaField(f); - guarantee(sf.isAccessed() && sf.getLocation() > 0, "Field not marked as accessed: %s", sf); - return JavaConstant.forLong(sf.getLocation()); + int location = ImageSingletons.lookup(ReflectionSubstitutionSupport.class).getFieldOffset(f, true); + VMError.guarantee(location > 0, "Location is missing for field whose offset is stored: %s.", f); + return JavaConstant.forLong(location); } } } throw shouldNotReachHere("unknown field offset class: " + tclass + ", offset = " + searchOffset); } - private JavaConstant computeAtomicFieldUpdaterOffset(MetaAccessProvider metaAccess, ClassInitializationSupport classInitializationSupport, JavaConstant receiver) { + private JavaConstant computeAtomicFieldUpdaterOffset(ClassInitializationSupport classInitializationSupport, JavaConstant receiver) { assert !Modifier.isStatic(original.getModifiers()); assert receiver.isNonNull(); @@ -489,8 +489,8 @@ private JavaConstant computeAtomicFieldUpdaterOffset(MetaAccessProvider metaAcce */ ResolvedJavaField tclassField = findField(original.getDeclaringClass(), "tclass"); SnippetReflectionProvider originalSnippetReflection = GraalAccess.getOriginalSnippetReflection(); - Class tclass = originalSnippetReflection.asObject(Class.class, ReadableJavaField.readFieldValue(metaAccess, classInitializationSupport, tclassField, receiver)); - return translateFieldOffset(metaAccess, classInitializationSupport, receiver, tclass); + Class tclass = originalSnippetReflection.asObject(Class.class, ReadableJavaField.readFieldValue(classInitializationSupport, tclassField, receiver)); + return translateFieldOffset(classInitializationSupport, receiver, tclass); } private static ResolvedJavaField findField(ResolvedJavaType declaringClass, String name) { diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/substitute/SubstitutionField.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/substitute/SubstitutionField.java index 96c5da3e5ef9..0c12e1b87c37 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/substitute/SubstitutionField.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/substitute/SubstitutionField.java @@ -34,7 +34,6 @@ import jdk.vm.ci.meta.JavaConstant; import jdk.vm.ci.meta.JavaType; -import jdk.vm.ci.meta.MetaAccessProvider; import jdk.vm.ci.meta.ResolvedJavaField; import jdk.vm.ci.meta.ResolvedJavaType; @@ -66,15 +65,15 @@ public boolean injectFinalForRuntimeCompilation() { } @Override - public JavaConstant readValue(MetaAccessProvider metaAccess, ClassInitializationSupport classInitializationSupport, JavaConstant receiver) { + public JavaConstant readValue(ClassInitializationSupport classInitializationSupport, JavaConstant receiver) { /* First try reading the value using the original field. */ - JavaConstant value = ReadableJavaField.readFieldValue(metaAccess, classInitializationSupport, original, receiver); + JavaConstant value = ReadableJavaField.readFieldValue(classInitializationSupport, original, receiver); if (value == null) { /* * If the original field didn't yield a value, try reading using the annotated field. * The value can be null only if the receiver doesn't contain the field. */ - value = ReadableJavaField.readFieldValue(metaAccess, classInitializationSupport, annotated, receiver); + value = ReadableJavaField.readFieldValue(classInitializationSupport, annotated, receiver); } return value; } From b2dc8c4312d140248666353e4aa4e60c982a5cbe Mon Sep 17 00:00:00 2001 From: Florian Huemer Date: Tue, 12 Dec 2023 09:30:46 +0100 Subject: [PATCH 173/593] Removed Assert.java. Use org.junit.Assert instead. Moved all test suites to org.junit.Assert. Removed constant store policy in gate tasks (This has no longer has any effect). Copying to a buffer is now implemented via unsafe.copyMemory in UnsafeWasmMemory. WasmJsApiSuite now executes memory tests with and without option UseUnsafeMemory. Code cleanup. --- wasm/mx.wasm/mx_wasm.py | 11 +- wasm/mx.wasm/suite.py | 1 + .../benchmark/WasmBenchmarkSuiteBase.java | 5 +- .../org/graalvm/wasm/test/WasmFileSuite.java | 6 +- .../org/graalvm/wasm/test/WasmJsApiSuite.java | 113 +++++++++--------- .../wasm/test/WasmPolyglotTestSuite.java | 38 +++--- .../bytecode/MultiInstantiationSuite.java | 2 +- .../ReferenceTypesValidationSuite.java | 2 +- .../test/suites/wasi/WasiOptionsSuite.java | 26 ++-- .../src/org/graalvm/wasm/utils/Assert.java | 96 --------------- .../graalvm/wasm/utils/WasmBinaryTools.java | 9 +- .../org/graalvm/wasm/utils/WasmResource.java | 4 +- .../graalvm/wasm/utils/cases/WasmCase.java | 14 +-- .../graalvm/wasm/memory/UnsafeWasmMemory.java | 5 +- 14 files changed, 107 insertions(+), 225 deletions(-) delete mode 100644 wasm/src/org.graalvm.wasm.utils/src/org/graalvm/wasm/utils/Assert.java diff --git a/wasm/mx.wasm/mx_wasm.py b/wasm/mx.wasm/mx_wasm.py index 5ad66fba05eb..982ed2318068 100644 --- a/wasm/mx.wasm/mx_wasm.py +++ b/wasm/mx.wasm/mx_wasm.py @@ -48,10 +48,10 @@ import mx import mx_benchmark import mx_sdk_vm +import mx_unittest # noinspection PyUnresolvedReferences import mx_wasm_benchmark # pylint: disable=unused-import from mx_gate import Task, add_gate_runner -import mx_unittest from mx_unittest import unittest _suite = mx.suite("wasm") @@ -89,8 +89,6 @@ def get_jdk(forBuild=False): class GraalWasmDefaultTags: buildall = "buildall" wasmtest = "wasmtest" - wasmconstantspolicytest = "wasmconstantspolicytest" - wasmconstantspolicyextratest = "wasmconstantspolicyextratest" wasmextratest = "wasmextratest" wasmbenchtest = "wasmbenchtest" coverage = "coverage" @@ -116,16 +114,9 @@ def graal_wasm_gate_runner(args, tasks): unittest([*wabt_test_args(), "WasmTestSuite"], test_report_tags={'task': t.title}) unittest([*wabt_test_args(), "-Dwasmtest.sharedEngine=true", "WasmTestSuite"], test_report_tags={'task': t.title}) - with Task("ConstantsPolicyUnitTests", tasks, tags=[GraalWasmDefaultTags.wasmconstantspolicytest], report=True) as t: - if t: - unittest([*wabt_test_args(), "-Dwasmtest.storeConstantsPolicy=LARGE_ONLY", "WasmTestSuite"], test_report_tags={'task': t.title}) - with Task("ExtraUnitTests", tasks, tags=[GraalWasmDefaultTags.wasmextratest, GraalWasmDefaultTags.coverage], report=True) as t: if t: unittest(["--suite", "wasm", "CSuite", "WatSuite"], test_report_tags={'task': t.title}) - with Task("ConstantsPolicyExtraUnitTests", tasks, tags=[GraalWasmDefaultTags.wasmconstantspolicyextratest], report=True) as t: - if t: - unittest(["--suite", "wasm", "-Dwasmtest.storeConstantsPolicy=LARGE_ONLY", "CSuite", "WatSuite"], test_report_tags={'task': t.title}) # This is a gate used to test that all the benchmarks return the correct results. It does not upload anything, # and does not run on a dedicated machine. diff --git a/wasm/mx.wasm/suite.py b/wasm/mx.wasm/suite.py index 8f59c3649b79..bdd955f76f32 100644 --- a/wasm/mx.wasm/suite.py +++ b/wasm/mx.wasm/suite.py @@ -111,6 +111,7 @@ "dependencies" : [ "org.graalvm.wasm", "truffle:TRUFFLE_API", + "mx:JUNIT", ], "checkstyle" : "org.graalvm.wasm", "javaCompliance" : "17+", diff --git a/wasm/src/org.graalvm.wasm.benchmark/src/org/graalvm/wasm/benchmark/WasmBenchmarkSuiteBase.java b/wasm/src/org.graalvm.wasm.benchmark/src/org/graalvm/wasm/benchmark/WasmBenchmarkSuiteBase.java index be09687676a1..b804c847f654 100644 --- a/wasm/src/org.graalvm.wasm.benchmark/src/org/graalvm/wasm/benchmark/WasmBenchmarkSuiteBase.java +++ b/wasm/src/org.graalvm.wasm.benchmark/src/org/graalvm/wasm/benchmark/WasmBenchmarkSuiteBase.java @@ -50,7 +50,6 @@ import org.graalvm.polyglot.Context; import org.graalvm.polyglot.Value; import org.graalvm.wasm.WasmLanguage; -import org.graalvm.wasm.utils.Assert; import org.graalvm.wasm.utils.WasmBinaryTools; import org.graalvm.wasm.utils.cases.WasmCase; import org.openjdk.jmh.annotations.Fork; @@ -99,7 +98,9 @@ public void setup() throws IOException, InterruptedException { benchmarkSetupEach = benchmarkModule.getMember("benchmarkSetupEach"); benchmarkTeardownEach = benchmarkModule.getMember("benchmarkTeardownEach"); benchmarkRun = benchmarkModule.getMember("benchmarkRun"); - Assert.assertNotNull(String.format("No benchmarkRun method in %s.", benchmarkCase.name()), benchmarkRun); + if (benchmarkRun == null) { + throw new RuntimeException(String.format("No benchmarkRun method in %s.", benchmarkCase.name())); + } if (benchmarkSetupOnce != null) { benchmarkSetupOnce.execute(); diff --git a/wasm/src/org.graalvm.wasm.test/src/org/graalvm/wasm/test/WasmFileSuite.java b/wasm/src/org.graalvm.wasm.test/src/org/graalvm/wasm/test/WasmFileSuite.java index a67e405b74d6..9df54c0faecf 100644 --- a/wasm/src/org.graalvm.wasm.test/src/org/graalvm/wasm/test/WasmFileSuite.java +++ b/wasm/src/org.graalvm.wasm.test/src/org/graalvm/wasm/test/WasmFileSuite.java @@ -309,10 +309,6 @@ private WasmTestStatus runTestCase(WasmCase testCase, Engine sharedEngine) { contextBuilder.option("log.wasm.level", WasmTestOptions.LOG_LEVEL); } - if (WasmTestOptions.STORE_CONSTANTS_POLICY != null && !WasmTestOptions.STORE_CONSTANTS_POLICY.equals("")) { - contextBuilder.option("wasm.StoreConstantsPolicy", WasmTestOptions.STORE_CONSTANTS_POLICY); - System.out.println("wasm.StoreConstantsPolicy: " + WasmTestOptions.STORE_CONSTANTS_POLICY); - } contextBuilder.option("wasm.Builtins", includedExternalModules()); contextBuilder.option("wasm.WasiConstantRandomGet", "true"); final String commandLineArgs = testCase.options().getProperty("command-line-args"); @@ -371,7 +367,7 @@ private WasmTestStatus runTestCase(WasmCase testCase, Engine sharedEngine) { runInContexts(testCase, contextBuilder, sources, sharedEngine, testOut); } catch (InterruptedException | IOException e) { - Assert.fail(String.format("Test %s failed: %s", testCase.name(), e.getMessage())); + throw new RuntimeException(String.format("Test %s failed: %s", testCase.name(), e.getMessage())); } finally { if (tempWorkingDirectory != null) { deleteFolder(tempWorkingDirectory.toFile()); diff --git a/wasm/src/org.graalvm.wasm.test/src/org/graalvm/wasm/test/WasmJsApiSuite.java b/wasm/src/org.graalvm.wasm.test/src/org/graalvm/wasm/test/WasmJsApiSuite.java index 921e94554882..edc2baf88684 100644 --- a/wasm/src/org.graalvm.wasm.test/src/org/graalvm/wasm/test/WasmJsApiSuite.java +++ b/wasm/src/org.graalvm.wasm.test/src/org/graalvm/wasm/test/WasmJsApiSuite.java @@ -78,7 +78,7 @@ import org.graalvm.wasm.globals.WasmGlobal; import org.graalvm.wasm.memory.WasmMemory; import org.graalvm.wasm.predefined.testutil.TestutilModule; -import org.graalvm.wasm.utils.Assert; +import org.junit.Assert; import org.junit.Test; import com.oracle.truffle.api.exception.AbstractTruffleException; @@ -159,7 +159,7 @@ public void testInstantiateWithImports() throws IOException { @Test public void testInstantiateWithImportMemory() throws IOException { - runTest(context -> { + runMemoryTest(context -> { final WebAssembly wasm = new WebAssembly(context); final WasmMemory memory = WebAssembly.memAlloc(4, 8, false); final Dictionary importObject = Dictionary.create(new Object[]{ @@ -181,7 +181,7 @@ public void testInstantiateWithImportMemory() throws IOException { @Test public void testInstantiateWithExportMemory() throws IOException { - runTest(context -> { + runMemoryTest(context -> { final WebAssembly wasm = new WebAssembly(context); WasmInstance instance = moduleInstantiate(wasm, binaryWithMemoryExport, null); try { @@ -322,7 +322,7 @@ private static void disableRefTypes(Context.Builder builder) { @Test public void testCreateAnyfuncGlobalRefTypesDisabled() throws IOException { - runTest(builder -> disableRefTypes(builder), context -> { + runTest(WasmJsApiSuite::disableRefTypes, context -> { final WebAssembly wasm = new WebAssembly(context); try { wasm.globalAlloc(ValueType.anyfunc, false, WasmConstant.NULL); @@ -335,7 +335,7 @@ public void testCreateAnyfuncGlobalRefTypesDisabled() throws IOException { @Test public void testCreateExternrefGlobalRefTypesDisabled() throws IOException { - runTest(builder -> disableRefTypes(builder), context -> { + runTest(WasmJsApiSuite::disableRefTypes, context -> { final WebAssembly wasm = new WebAssembly(context); try { wasm.globalAlloc(ValueType.externref, false, WasmConstant.NULL); @@ -481,7 +481,7 @@ public void testGlobalWriteNull() throws IOException { @Test public void testGlobalWriteAnyfuncRefTypesDisabled() throws IOException { - runTest(builder -> disableRefTypes(builder), context -> { + runTest(WasmJsApiSuite::disableRefTypes, context -> { final WebAssembly wasm = new WebAssembly(context); final WasmGlobal global = new DefaultWasmGlobal(ValueType.anyfunc, true, WasmConstant.NULL); try { @@ -495,7 +495,7 @@ public void testGlobalWriteAnyfuncRefTypesDisabled() throws IOException { @Test public void testGlobalWriteExternrefRefTypesDisabled() throws IOException { - runTest(builder -> disableRefTypes(builder), context -> { + runTest(WasmJsApiSuite::disableRefTypes, context -> { final WebAssembly wasm = new WebAssembly(context); final WasmGlobal global = new DefaultWasmGlobal(ValueType.externref, true, WasmConstant.NULL); try { @@ -576,7 +576,7 @@ public void testInstantiateWithUnicodeExport() throws IOException { @Test public void testExportMemoryTwice() throws IOException, InterruptedException { final byte[] exportMemoryTwice = compileWat("exportMemoryTwice", "(memory 1) (export \"a\" (memory 0)) (export \"b\" (memory 0))"); - runTest(context -> { + runMemoryTest(context -> { final WebAssembly wasm = new WebAssembly(context); final WasmInstance instance = moduleInstantiate(wasm, exportMemoryTwice, null); try { @@ -628,7 +628,7 @@ public void testExportSameFunctionWithDifferentNames() throws IOException, Inter final WasmInstance instance = moduleInstantiate(wasm, sameFunctionWithDifferentNames, null); final Object f1 = WebAssembly.instanceExport(instance, "f1"); final Object f2 = WebAssembly.instanceExport(instance, "f2"); - Assert.assertTrue("Returned function instances must be reference equal", f1 == f2); + Assert.assertSame("Returned function instances must be reference equal", f1, f2); }); } @@ -642,7 +642,7 @@ public void testExportSameFunctionInAndOutsideTable() throws IOException, Interr final Object f = WebAssembly.instanceExport(instance, "f"); final WasmTable t = (WasmTable) WebAssembly.instanceExport(instance, "t"); final Object fInTable = WebAssembly.tableRead(t, 0); - Assert.assertTrue("Returned function instances must be reference equal", f == fInTable); + Assert.assertSame("Returned function instances must be reference equal", f, fInTable); }); } @@ -656,7 +656,7 @@ public void testExportSameFunctionAtDifferentTableIndices() throws IOException, final WasmTable t = (WasmTable) WebAssembly.instanceExport(instance, "t"); final Object f1 = WebAssembly.tableRead(t, 0); final Object f2 = WebAssembly.tableRead(t, 1); - Assert.assertTrue("Returned function instances must be reference equal", f1 == f2); + Assert.assertSame("Returned function instances must be reference equal", f1, f2); }); } @@ -676,7 +676,7 @@ public void testExportSameFunctionInDifferentModules() throws IOException, Inter })); final WasmInstance m2Instance = moduleInstantiate(wasm, m2, d); final Object m2Function = WebAssembly.instanceExport(m2Instance, "f"); - Assert.assertTrue("Returned function instances must be reference equal", m1Function == m2Function); + Assert.assertSame("Returned function instances must be reference equal", m1Function, m2Function); final Object m1Value = lib.execute(m1Function); final Object m2Value = lib.execute(m2Function); Assert.assertEquals("Return value of functions is equal", m1Value, m2Value); @@ -706,7 +706,7 @@ public void testExportImportedFunctionInDifferentModules() throws IOException, I })); final WasmInstance m2Instance = moduleInstantiate(wasm, m2, d); final Object m2Function = WebAssembly.instanceExport(m2Instance, "f"); - Assert.assertTrue("Returned function instances must be reference equal", m1Function == m2Function); + Assert.assertSame("Returned function instances must be reference equal", m1Function, m2Function); final Object m1Value = lib.execute(m1Function); final Object m2Value = lib.execute(m2Function); Assert.assertEquals("Return value of functions is equal", m1Value, m2Value); @@ -734,7 +734,7 @@ public void testExportSameFunctionInDifferentModuleTables() throws IOException, final WasmInstance m2Instance = moduleInstantiate(wasm, m2, d); final Object m2Table = WebAssembly.instanceExport(m2Instance, "t"); final Object m2Function = WebAssembly.tableRead((WasmTable) m2Table, 0); - Assert.assertTrue("Returned function instances must be reference equal", m1Function == m2Function); + Assert.assertSame("Returned function instances must be reference equal", m1Function, m2Function); final Object m1Value = lib.execute(m1Function); final Object m2Value = lib.execute(m2Function); Assert.assertEquals("Return value of functions is equal", m1Value, m2Value); @@ -761,7 +761,7 @@ public void testExportSameFunctionInDifferentModuleTable() throws IOException, I final WasmInstance m2Instance = moduleInstantiate(wasm, m2, d); final Object m2Table = WebAssembly.instanceExport(m2Instance, "t"); final Object m2Function = WebAssembly.tableRead((WasmTable) m2Table, 0); - Assert.assertTrue("Returned function instances must be reference equal", m1Function == m2Function); + Assert.assertSame("Returned function instances must be reference equal", m1Function, m2Function); final Object m1Value = lib.execute(m1Function); final Object m2Value = lib.execute(m2Function); Assert.assertEquals("Return value of functions is equal", m1Value, m2Value); @@ -787,7 +787,7 @@ public void testExportImportedFunctionInDifferentModuleTable() throws IOExceptio final Object m1Function = WebAssembly.instanceExport(m1Instance, "f"); final Object m1Table = WebAssembly.instanceExport(m1Instance, "t"); final Object m1TableFunction = WebAssembly.tableRead((WasmTable) m1Table, 0); - Assert.assertTrue("Returned function instances must be reference equal", m1Function == m1TableFunction); + Assert.assertSame("Returned function instances must be reference equal", m1Function, m1TableFunction); Object m1Value = lib.execute(m1Function); final Object m1TableValue = lib.execute(m1TableFunction); Assert.assertEquals("Return value of functions is equal", m1Value, m1TableValue); @@ -799,7 +799,7 @@ public void testExportImportedFunctionInDifferentModuleTable() throws IOExceptio final WasmInstance m2Instance = moduleInstantiate(wasm, m2, d); final Object m2Table = WebAssembly.instanceExport(m2Instance, "t"); final Object m2Function = WebAssembly.tableRead((WasmTable) m2Table, 0); - Assert.assertTrue("Returned function instances must be reference equal", m1Function == m2Function); + Assert.assertSame("Returned function instances must be reference equal", m1Function, m2Function); m1Value = lib.execute(m1Function); final Object m2Value = lib.execute(m2Function); Assert.assertEquals("Return value of functions is equal", m1Value, m2Value); @@ -975,7 +975,7 @@ public void testCustomSectionBuffer() throws IOException { Object customSection = WebAssembly.customSections(module, "test").readArrayElement(0); InteropLibrary interop = InteropLibrary.getUncached(customSection); Assert.assertTrue("Custom section should have buffer elements", interop.hasBufferElements(customSection)); - Assert.assertTrue("Custom section should not have writable buffer", !interop.isBufferWritable(customSection)); + Assert.assertFalse("Custom section should not have writable buffer", interop.isBufferWritable(customSection)); Assert.assertEquals("Custom section should have correct buffer size", 16L, interop.getBufferSize(customSection)); Assert.assertEquals("Read first byte", (byte) 0x01, interop.readBufferByte(customSection, 0)); Assert.assertEquals("Read last byte", (byte) 0x16, interop.readBufferByte(customSection, bufferSize - 1)); @@ -991,14 +991,14 @@ public void testCustomSectionBuffer() throws IOException { Assert.assertEquals("Read first long BE", 0x0102030405060708L, interop.readBufferLong(customSection, ByteOrder.BIG_ENDIAN, 0)); Assert.assertEquals("Read last long LE", 0x1615141312111009L, interop.readBufferLong(customSection, ByteOrder.LITTLE_ENDIAN, bufferSize - 8)); Assert.assertEquals("Read last long BE", 0x0910111213141516L, interop.readBufferLong(customSection, ByteOrder.BIG_ENDIAN, bufferSize - 8)); - Assert.assertEquals("Read first float LE", Float.intBitsToFloat(0x04030201), interop.readBufferFloat(customSection, ByteOrder.LITTLE_ENDIAN, 0)); - Assert.assertEquals("Read first float BE", Float.intBitsToFloat(0x01020304), interop.readBufferFloat(customSection, ByteOrder.BIG_ENDIAN, 0)); - Assert.assertEquals("Read last float LE", Float.intBitsToFloat(0x16151413), interop.readBufferFloat(customSection, ByteOrder.LITTLE_ENDIAN, bufferSize - 4)); - Assert.assertEquals("Read last float BE", Float.intBitsToFloat(0x13141516), interop.readBufferFloat(customSection, ByteOrder.BIG_ENDIAN, bufferSize - 4)); - Assert.assertEquals("Read first long LE", Double.longBitsToDouble(0x0807060504030201L), interop.readBufferDouble(customSection, ByteOrder.LITTLE_ENDIAN, 0)); - Assert.assertEquals("Read first long BE", Double.longBitsToDouble(0x0102030405060708L), interop.readBufferDouble(customSection, ByteOrder.BIG_ENDIAN, 0)); - Assert.assertEquals("Read last long LE", Double.longBitsToDouble(0x1615141312111009L), interop.readBufferDouble(customSection, ByteOrder.LITTLE_ENDIAN, bufferSize - 8)); - Assert.assertEquals("Read last long BE", Double.longBitsToDouble(0x0910111213141516L), interop.readBufferDouble(customSection, ByteOrder.BIG_ENDIAN, bufferSize - 8)); + Assert.assertEquals("Read first float LE", Float.intBitsToFloat(0x04030201), interop.readBufferFloat(customSection, ByteOrder.LITTLE_ENDIAN, 0), 0.001f); + Assert.assertEquals("Read first float BE", Float.intBitsToFloat(0x01020304), interop.readBufferFloat(customSection, ByteOrder.BIG_ENDIAN, 0), 0.001f); + Assert.assertEquals("Read last float LE", Float.intBitsToFloat(0x16151413), interop.readBufferFloat(customSection, ByteOrder.LITTLE_ENDIAN, bufferSize - 4), 0.001f); + Assert.assertEquals("Read last float BE", Float.intBitsToFloat(0x13141516), interop.readBufferFloat(customSection, ByteOrder.BIG_ENDIAN, bufferSize - 4), 0.001f); + Assert.assertEquals("Read first long LE", Double.longBitsToDouble(0x0807060504030201L), interop.readBufferDouble(customSection, ByteOrder.LITTLE_ENDIAN, 0), 0.001); + Assert.assertEquals("Read first long BE", Double.longBitsToDouble(0x0102030405060708L), interop.readBufferDouble(customSection, ByteOrder.BIG_ENDIAN, 0), 0.001); + Assert.assertEquals("Read last long LE", Double.longBitsToDouble(0x1615141312111009L), interop.readBufferDouble(customSection, ByteOrder.LITTLE_ENDIAN, bufferSize - 8), 0.001); + Assert.assertEquals("Read last long BE", Double.longBitsToDouble(0x0910111213141516L), interop.readBufferDouble(customSection, ByteOrder.BIG_ENDIAN, bufferSize - 8), 0.001); final byte[] b = new byte[12]; interop.readBuffer(customSection, 0, b, 0, 12); Assert.assertArrayEquals("Read first 12 bytes", new byte[]{0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x10, 0x11, 0x12}, b); @@ -1087,7 +1087,7 @@ private static void assertThrowsIBOE(Callable callable) { @Test public void testMemoryBufferMessages() throws IOException { - runTest(context -> { + runMemoryTest(context -> { WebAssembly wasm = new WebAssembly(context); WasmModule module = wasm.moduleDecode(binaryWithMemoryExport); WasmInstance instance = wasm.moduleInstantiate(module, new Dictionary()); @@ -1113,14 +1113,14 @@ public void testMemoryBufferMessages() throws IOException { Assert.assertEquals("Read first long BE", 0L, interop.readBufferLong(buffer, ByteOrder.BIG_ENDIAN, 0)); Assert.assertEquals("Read last long LE", 0L, interop.readBufferLong(buffer, ByteOrder.LITTLE_ENDIAN, bufferSize - 8)); Assert.assertEquals("Read last long BE", 0L, interop.readBufferLong(buffer, ByteOrder.BIG_ENDIAN, bufferSize - 8)); - Assert.assertEquals("Read first float LE", (float) 0, interop.readBufferFloat(buffer, ByteOrder.LITTLE_ENDIAN, 0)); - Assert.assertEquals("Read first float BE", (float) 0, interop.readBufferFloat(buffer, ByteOrder.BIG_ENDIAN, 0)); - Assert.assertEquals("Read last float LE", (float) 0, interop.readBufferFloat(buffer, ByteOrder.LITTLE_ENDIAN, bufferSize - 4)); - Assert.assertEquals("Read last float BE", (float) 0, interop.readBufferFloat(buffer, ByteOrder.BIG_ENDIAN, bufferSize - 4)); - Assert.assertEquals("Read first double LE", 0d, interop.readBufferDouble(buffer, ByteOrder.LITTLE_ENDIAN, 0)); - Assert.assertEquals("Read first double BE", 0d, interop.readBufferDouble(buffer, ByteOrder.BIG_ENDIAN, 0)); - Assert.assertEquals("Read last double LE", 0d, interop.readBufferDouble(buffer, ByteOrder.LITTLE_ENDIAN, bufferSize - 8)); - Assert.assertEquals("Read last double BE", 0d, interop.readBufferDouble(buffer, ByteOrder.BIG_ENDIAN, bufferSize - 8)); + Assert.assertEquals("Read first float LE", 0f, interop.readBufferFloat(buffer, ByteOrder.LITTLE_ENDIAN, 0), 0.001f); + Assert.assertEquals("Read first float BE", 0f, interop.readBufferFloat(buffer, ByteOrder.BIG_ENDIAN, 0), 0.001f); + Assert.assertEquals("Read last float LE", 0f, interop.readBufferFloat(buffer, ByteOrder.LITTLE_ENDIAN, bufferSize - 4), 0.001f); + Assert.assertEquals("Read last float BE", 0f, interop.readBufferFloat(buffer, ByteOrder.BIG_ENDIAN, bufferSize - 4), 0.001f); + Assert.assertEquals("Read first double LE", 0d, interop.readBufferDouble(buffer, ByteOrder.LITTLE_ENDIAN, 0), 0.001); + Assert.assertEquals("Read first double BE", 0d, interop.readBufferDouble(buffer, ByteOrder.BIG_ENDIAN, 0), 0.001); + Assert.assertEquals("Read last double LE", 0d, interop.readBufferDouble(buffer, ByteOrder.LITTLE_ENDIAN, bufferSize - 8), 0.001); + Assert.assertEquals("Read last double BE", 0d, interop.readBufferDouble(buffer, ByteOrder.BIG_ENDIAN, bufferSize - 8), 0.001); final byte[] b = new byte[12]; interop.readBuffer(buffer, 0, b, 0, 12); @@ -1179,14 +1179,14 @@ public void testMemoryBufferMessages() throws IOException { float f = Float.intBitsToFloat(0x01020304); interop.writeBufferFloat(buffer, ByteOrder.LITTLE_ENDIAN, 0, f); - Assert.assertEquals("Read written float LE", f, interop.readBufferFloat(buffer, ByteOrder.LITTLE_ENDIAN, 0)); + Assert.assertEquals("Read written float LE", f, interop.readBufferFloat(buffer, ByteOrder.LITTLE_ENDIAN, 0), 0.001f); Assert.assertEquals("Read byte 0 of float LE", (byte) 0x04, interop.readBufferByte(buffer, 0)); Assert.assertEquals("Read byte 1 of float LE", (byte) 0x03, interop.readBufferByte(buffer, 1)); Assert.assertEquals("Read byte 2 of float LE", (byte) 0x02, interop.readBufferByte(buffer, 2)); Assert.assertEquals("Read byte 3 of float LE", (byte) 0x01, interop.readBufferByte(buffer, 3)); interop.writeBufferFloat(buffer, ByteOrder.BIG_ENDIAN, 0, f); - Assert.assertEquals("Read written float BE", f, interop.readBufferFloat(buffer, ByteOrder.BIG_ENDIAN, 0)); + Assert.assertEquals("Read written float BE", f, interop.readBufferFloat(buffer, ByteOrder.BIG_ENDIAN, 0), 0.001f); Assert.assertEquals("Read byte 0 of float BE", (byte) 0x01, interop.readBufferByte(buffer, 0)); Assert.assertEquals("Read byte 1 of float BE", (byte) 0x02, interop.readBufferByte(buffer, 1)); Assert.assertEquals("Read byte 2 of float BE", (byte) 0x03, interop.readBufferByte(buffer, 2)); @@ -1194,7 +1194,7 @@ public void testMemoryBufferMessages() throws IOException { double d = Double.longBitsToDouble(0x0102030405060708L); interop.writeBufferDouble(buffer, ByteOrder.LITTLE_ENDIAN, 0, d); - Assert.assertEquals("Read written double LE", d, interop.readBufferDouble(buffer, ByteOrder.LITTLE_ENDIAN, 0)); + Assert.assertEquals("Read written double LE", d, interop.readBufferDouble(buffer, ByteOrder.LITTLE_ENDIAN, 0), 0.001); Assert.assertEquals("Read byte 0 of double LE", (byte) 0x08, interop.readBufferByte(buffer, 0)); Assert.assertEquals("Read byte 1 of double LE", (byte) 0x07, interop.readBufferByte(buffer, 1)); Assert.assertEquals("Read byte 2 of double LE", (byte) 0x06, interop.readBufferByte(buffer, 2)); @@ -1205,7 +1205,7 @@ public void testMemoryBufferMessages() throws IOException { Assert.assertEquals("Read byte 7 of double LE", (byte) 0x01, interop.readBufferByte(buffer, 7)); interop.writeBufferDouble(buffer, ByteOrder.BIG_ENDIAN, 0, d); - Assert.assertEquals("Read written double BE", d, interop.readBufferDouble(buffer, ByteOrder.BIG_ENDIAN, 0)); + Assert.assertEquals("Read written double BE", d, interop.readBufferDouble(buffer, ByteOrder.BIG_ENDIAN, 0), 0.001); Assert.assertEquals("Read byte 0 of double BE", (byte) 0x01, interop.readBufferByte(buffer, 0)); Assert.assertEquals("Read byte 1 of double BE", (byte) 0x02, interop.readBufferByte(buffer, 1)); Assert.assertEquals("Read byte 2 of double BE", (byte) 0x03, interop.readBufferByte(buffer, 2)); @@ -1322,7 +1322,7 @@ public void testTableImport() throws IOException, InterruptedException { public void testMemoryAllocationFailure() throws IOException { // Memory allocation should either succeed or throw an interop // exception (not an internal error like OutOfMemoryError). - runTest(context -> { + runMemoryTest(context -> { try { Object[] memories = new Object[5]; for (int i = 0; i < memories.length; i++) { @@ -1406,9 +1406,7 @@ public void testMultiValueReferencePassThrough() throws IOException, Interrupted """); runTest(context -> { final WebAssembly wasm = new WebAssembly(context); - final var func = new Executable((args) -> { - return 0; - }); + final var func = new Executable((args) -> 0); final var f = new Executable((args) -> { final Object[] result = new Object[2]; result[0] = func; @@ -1434,7 +1432,7 @@ public void testMultiValueReferencePassThrough() throws IOException, Interrupted @Test public void testInitialMemorySizeOutOfBounds() throws IOException { - runTest(context -> { + runMemoryTest(context -> { try { WebAssembly.memAlloc(32768, 32770, false); Assert.fail("Should have failed - initial memory size exceeds implementation limit"); @@ -1446,7 +1444,7 @@ public void testInitialMemorySizeOutOfBounds() throws IOException { @Test public void testMinMemorySizeExceedsMaxSize() throws IOException { - runTest(context -> { + runMemoryTest(context -> { try { WebAssembly.memAlloc(2, 1, false); Assert.fail("Should have failed - min memory size bigger than max size"); @@ -1458,7 +1456,7 @@ public void testMinMemorySizeExceedsMaxSize() throws IOException { @Test public void testMemoryGrowLimit() throws IOException { - runTest(context -> { + runMemoryTest(context -> { try { WasmMemory memory = WebAssembly.memAlloc(1, 1, false); WebAssembly.memGrow(memory, 1); @@ -1540,7 +1538,7 @@ public void testTableInitExternref() throws IOException { @Test public void testTableAlloc1Param() throws IOException { - runTest(builder -> disableRefTypes(builder), context -> { + runTest(WasmJsApiSuite::disableRefTypes, context -> { final WebAssembly wasm = new WebAssembly(context); final InteropLibrary lib = InteropLibrary.getUncached(); try { @@ -1688,7 +1686,7 @@ public void testGlobalEmbedderData() throws IOException { @Test public void testMemoryEmbedderData() throws IOException { - runTest(context -> { + runMemoryTest(context -> { WasmMemory memory = WebAssembly.memAlloc(1, 1, false); checkEmbedderData(memory); }); @@ -1775,9 +1773,7 @@ public void testImportMultiValueNotArray() throws IOException, InterruptedExcept """); runTest(context -> { final WebAssembly wasm = new WebAssembly(context); - final Object f = new Executable((args) -> { - return 0; - }); + final Object f = new Executable((args) -> 0); final Dictionary d = new Dictionary(); d.addMember("m", Dictionary.create(new Object[]{ "f", f @@ -1813,9 +1809,7 @@ public void testImportMultiValueInvalidArraySize() throws IOException, Interrupt runTest(context -> { final WebAssembly wasm = new WebAssembly(context); - final Object f = new Executable((args) -> { - return InteropArray.create(new Object[]{1, 2}); - }); + final Object f = new Executable((args) -> InteropArray.create(new Object[]{1, 2})); final Dictionary d = new Dictionary(); d.addMember("m", Dictionary.create(new Object[]{ "f", f @@ -1851,9 +1845,7 @@ public void testImportMultiValueTypeMismatch() throws IOException, InterruptedEx runTest(context -> { final WebAssembly wasm = new WebAssembly(context); - final Object f = new Executable((args) -> { - return InteropArray.create(new Object[]{0, 1.1, 2}); - }); + final Object f = new Executable((args) -> InteropArray.create(new Object[]{0, 1.1, 2})); final Dictionary d = new Dictionary(); d.addMember("m", Dictionary.create(new Object[]{ "f", f @@ -2063,7 +2055,7 @@ public void testValidFunctionBody() throws IOException { private static void runValidationInvalid(byte[] data) throws IOException { runTest(context -> { WebAssembly wasm = new WebAssembly(context); - Assert.assertTrue("Should have failed - invalid module", !wasm.moduleValidate(data)); + Assert.assertFalse("Should have failed - invalid module", wasm.moduleValidate(data)); }); } @@ -2279,6 +2271,11 @@ public void testInstantiateModuleWithBrIfTwice() throws IOException, Interrupted }); } + private static void runMemoryTest(Consumer testCase) throws IOException { + runTest(null, testCase); + runTest(options -> options.option("wasm.UseUnsafeMemory", "true"), testCase); + } + private static void runTest(Consumer testCase) throws IOException { runTest(null, testCase); } diff --git a/wasm/src/org.graalvm.wasm.test/src/org/graalvm/wasm/test/WasmPolyglotTestSuite.java b/wasm/src/org.graalvm.wasm.test/src/org/graalvm/wasm/test/WasmPolyglotTestSuite.java index 554ef403fb01..77a266192ab4 100644 --- a/wasm/src/org.graalvm.wasm.test/src/org/graalvm/wasm/test/WasmPolyglotTestSuite.java +++ b/wasm/src/org.graalvm.wasm.test/src/org/graalvm/wasm/test/WasmPolyglotTestSuite.java @@ -40,7 +40,12 @@ */ package org.graalvm.wasm.test; -import com.oracle.truffle.api.TruffleLanguage; +import static org.graalvm.wasm.test.WasmTestUtils.hexStringToByteArray; +import static org.graalvm.wasm.utils.WasmBinaryTools.compileWat; + +import java.io.IOException; +import java.util.Set; + import org.graalvm.polyglot.Context; import org.graalvm.polyglot.PolyglotException; import org.graalvm.polyglot.Source; @@ -49,14 +54,10 @@ import org.graalvm.wasm.WasmContext; import org.graalvm.wasm.WasmLanguage; import org.graalvm.wasm.memory.UnsafeWasmMemory; -import org.graalvm.wasm.utils.Assert; +import org.junit.Assert; import org.junit.Test; -import java.io.IOException; -import java.util.Set; - -import static org.graalvm.wasm.test.WasmTestUtils.hexStringToByteArray; -import static org.graalvm.wasm.utils.WasmBinaryTools.compileWat; +import com.oracle.truffle.api.TruffleLanguage; public class WasmPolyglotTestSuite { @Test @@ -65,7 +66,7 @@ public void testEmpty() throws IOException { context.parse(Source.newBuilder(WasmLanguage.ID, ByteSequence.create(new byte[0]), "someName").build()); } catch (PolyglotException pex) { Assert.assertTrue("Must be a syntax error.", pex.isSyntaxError()); - Assert.assertTrue("Must not be an internal error.", !pex.isInternalError()); + Assert.assertFalse("Must not be an internal error.", pex.isInternalError()); } } @@ -100,7 +101,7 @@ public void unsafeMemoryFreed() throws IOException { mainModule.getMember("main").execute(); final TruffleLanguage.Env env = WasmContext.get(null).environment(); final UnsafeWasmMemory memory = (UnsafeWasmMemory) env.asGuestValue(mainModule.getMember("memory")); - Assert.assertTrue("Memory should have been allocated.", !memory.freed()); + Assert.assertFalse("Memory should have been allocated.", memory.freed()); context.close(); Assert.assertTrue("Memory should have been freed.", memory.freed()); } @@ -133,7 +134,7 @@ public void divisionByZeroStressTest() throws IOException, InterruptedException mainFunction.execute(); Assert.fail("Should have thrown"); } catch (PolyglotException pex) { - Assert.assertTrue("Should not throw internal error", !pex.isInternalError()); + Assert.assertFalse("Should not throw internal error", pex.isInternalError()); } } } @@ -157,19 +158,14 @@ public void extractKeys() throws IOException { @Test public void deeplyNestedBrIf() throws IOException, InterruptedException { // This code resembles the deeply nested br_if in WebAssembly part of undici - StringBuilder wat = new StringBuilder(); int depth = 256; - wat.append("(module (func (export \"main\") (result i32) (block $my_block "); - for (int i = 0; i < depth; i++) { - wat.append("(block "); - } - wat.append("i32.const 0 br_if $my_block i32.const 35 i32.const 0 drop drop"); - for (int i = 0; i < depth; i++) { - wat.append(")"); - } - wat.append(") i32.const 42))"); + final String wat = "(module (func (export \"main\") (result i32) (block $my_block " + + "(block ".repeat(depth) + + "i32.const 0 br_if $my_block i32.const 35 i32.const 0 drop drop" + + ")".repeat(depth) + + ") i32.const 42))"; - ByteSequence bytes = ByteSequence.create(compileWat("test", wat.toString())); + ByteSequence bytes = ByteSequence.create(compileWat("test", wat)); Source source = Source.newBuilder(WasmLanguage.ID, bytes, "main").build(); try (Context context = Context.create(WasmLanguage.ID)) { context.eval(source); diff --git a/wasm/src/org.graalvm.wasm.test/src/org/graalvm/wasm/test/suites/bytecode/MultiInstantiationSuite.java b/wasm/src/org.graalvm.wasm.test/src/org/graalvm/wasm/test/suites/bytecode/MultiInstantiationSuite.java index 129906114c4b..0e3d40a06041 100644 --- a/wasm/src/org.graalvm.wasm.test/src/org/graalvm/wasm/test/suites/bytecode/MultiInstantiationSuite.java +++ b/wasm/src/org.graalvm.wasm.test/src/org/graalvm/wasm/test/suites/bytecode/MultiInstantiationSuite.java @@ -67,8 +67,8 @@ import org.graalvm.wasm.globals.WasmGlobal; import org.graalvm.wasm.memory.WasmMemory; import org.graalvm.wasm.predefined.testutil.TestutilModule; -import org.graalvm.wasm.utils.Assert; import org.graalvm.wasm.utils.WasmBinaryTools; +import org.junit.Assert; import org.junit.Test; import com.oracle.truffle.api.interop.ArityException; diff --git a/wasm/src/org.graalvm.wasm.test/src/org/graalvm/wasm/test/suites/validation/ReferenceTypesValidationSuite.java b/wasm/src/org.graalvm.wasm.test/src/org/graalvm/wasm/test/suites/validation/ReferenceTypesValidationSuite.java index e8361f111460..3dac4f6bee37 100644 --- a/wasm/src/org.graalvm.wasm.test/src/org/graalvm/wasm/test/suites/validation/ReferenceTypesValidationSuite.java +++ b/wasm/src/org.graalvm.wasm.test/src/org/graalvm/wasm/test/suites/validation/ReferenceTypesValidationSuite.java @@ -48,7 +48,7 @@ import org.graalvm.wasm.WasmType; import org.graalvm.wasm.constants.GlobalModifier; import org.graalvm.wasm.test.AbstractBinarySuite; -import org.graalvm.wasm.utils.Assert; +import org.junit.Assert; import org.junit.Test; public class ReferenceTypesValidationSuite extends AbstractBinarySuite { diff --git a/wasm/src/org.graalvm.wasm.test/src/org/graalvm/wasm/test/suites/wasi/WasiOptionsSuite.java b/wasm/src/org.graalvm.wasm.test/src/org/graalvm/wasm/test/suites/wasi/WasiOptionsSuite.java index 9454a99e59c9..85bf1c52f31b 100644 --- a/wasm/src/org.graalvm.wasm.test/src/org/graalvm/wasm/test/suites/wasi/WasiOptionsSuite.java +++ b/wasm/src/org.graalvm.wasm.test/src/org/graalvm/wasm/test/suites/wasi/WasiOptionsSuite.java @@ -40,19 +40,6 @@ */ package org.graalvm.wasm.test.suites.wasi; -import org.graalvm.polyglot.Context; -import org.graalvm.polyglot.Source; -import org.graalvm.polyglot.Value; -import org.graalvm.polyglot.io.ByteSequence; -import org.graalvm.polyglot.io.FileSystem; -import org.graalvm.polyglot.io.IOAccess; -import org.graalvm.wasm.WasmLanguage; -import org.graalvm.wasm.utils.Assert; -import org.graalvm.wasm.utils.WasmBinaryTools; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.junit.runners.Parameterized; - import java.io.IOException; import java.net.URI; import java.nio.channels.SeekableByteChannel; @@ -65,6 +52,19 @@ import java.util.Map; import java.util.Set; +import org.graalvm.polyglot.Context; +import org.graalvm.polyglot.Source; +import org.graalvm.polyglot.Value; +import org.graalvm.polyglot.io.ByteSequence; +import org.graalvm.polyglot.io.FileSystem; +import org.graalvm.polyglot.io.IOAccess; +import org.graalvm.wasm.WasmLanguage; +import org.graalvm.wasm.utils.WasmBinaryTools; +import org.junit.Assert; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.Parameterized; + @RunWith(Parameterized.class) public class WasiOptionsSuite { @Parameterized.Parameter() public String dir; diff --git a/wasm/src/org.graalvm.wasm.utils/src/org/graalvm/wasm/utils/Assert.java b/wasm/src/org.graalvm.wasm.utils/src/org/graalvm/wasm/utils/Assert.java deleted file mode 100644 index 1ed0b3485365..000000000000 --- a/wasm/src/org.graalvm.wasm.utils/src/org/graalvm/wasm/utils/Assert.java +++ /dev/null @@ -1,96 +0,0 @@ -/* - * Copyright (c) 2019, 2023, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * The Universal Permissive License (UPL), Version 1.0 - * - * Subject to the condition set forth below, permission is hereby granted to any - * person obtaining a copy of this software, associated documentation and/or - * data (collectively the "Software"), free of charge and under any and all - * copyright rights in the Software, and any and all patent rights owned or - * freely licensable by each licensor hereunder covering either (i) the - * unmodified Software as contributed to or provided by such licensor, or (ii) - * the Larger Works (as defined below), to deal in both - * - * (a) the Software, and - * - * (b) any piece of software and/or hardware listed in the lrgrwrks.txt file if - * one is included with the Software each a "Larger Work" to which the Software - * is contributed by such licensors), - * - * without restriction, including without limitation the rights to copy, create - * derivative works of, display, perform, and distribute the Software and make, - * use, sell, offer for sale, import, export, have made, and have sold the - * Software and the Larger Work(s), and to sublicense the foregoing rights on - * either these or other terms. - * - * This license is subject to the following condition: - * - * The above copyright notice and either this complete permission notice or at a - * minimum a reference to the UPL must be included in all copies or substantial - * portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ -package org.graalvm.wasm.utils; - -import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary; - -public class Assert { - public static void assertTrue(String message, boolean condition) { - if (!condition) { - fail(message); - } - } - - public static void assertNotNull(String message, Object object) { - assertTrue(message, object != null); - } - - public static void assertEquals(String message, Object expected, Object actual) { - if (!actual.equals(expected)) { - fail(format("%s '%s' != '%s'", message, expected, actual)); - } - } - - public static void assertFloatEquals(String message, Float expected, Float actual, Float epsilon) { - if (Math.abs(actual - expected) > epsilon) { - fail(format("%s %s \u2209 %s +/- %s", message, actual, expected, epsilon)); - } - } - - public static void assertDoubleEquals(String message, Double expected, Double actual, Double epsilon) { - if (Math.abs(actual - expected) > epsilon) { - fail(format("%s %s \u2209 %s +/- %s", message, actual, expected, epsilon)); - } - } - - public static void assertArrayEquals(String message, byte[] expected, byte[] actual) { - if (expected == actual) { - return; - } - if (expected.length != actual.length) { - fail(format("%s '%s.length' != '%s.length'", message, expected, actual)); - } - for (int i = 0; i < expected.length; i++) { - if (expected[i] != actual[i]) { - fail(format("%s '%s[%d] { %d }' != '%s[%d] { %d }'", message, expected, i, expected[i], actual, i, actual[i])); - } - } - } - - public static void fail(String message) { - throw new RuntimeException(message); - } - - @TruffleBoundary - public static String format(String format, Object... args) { - return String.format(format, args); - } -} diff --git a/wasm/src/org.graalvm.wasm.utils/src/org/graalvm/wasm/utils/WasmBinaryTools.java b/wasm/src/org.graalvm.wasm.utils/src/org/graalvm/wasm/utils/WasmBinaryTools.java index e1e300d18739..70b12f3a7002 100644 --- a/wasm/src/org.graalvm.wasm.utils/src/org/graalvm/wasm/utils/WasmBinaryTools.java +++ b/wasm/src/org.graalvm.wasm.utils/src/org/graalvm/wasm/utils/WasmBinaryTools.java @@ -130,7 +130,7 @@ private static byte[] runExternalToolAndVerify(String message, String[] commandL stdout.close(); if (exitCode != 0) { String output = input == null ? stdout.get() : "(binary data)"; - Assert.fail(String.format("%s ('%s', exit code %d)\nstderr:\n%s\nstdout:\n%s", message, String.join(" ", commandLine), exitCode, stderr.get(), output)); + throw new RuntimeException(String.format("%s ('%s', exit code %d)\nstderr:\n%s\nstdout:\n%s", message, String.join(" ", commandLine), exitCode, stderr.get(), output)); } return stdout.getBytes(); } @@ -192,10 +192,9 @@ private static String findWat2WasmExecutable() { return pathAsString; } } - - Assert.assertNotNull( - String.format("The %s property must be set in order to be able to compile .wat to .wasm", SystemProperties.WAT_TO_WASM_EXECUTABLE_PROPERTY_NAME), - executable); + if (executable == null) { + throw new RuntimeException(String.format("The %s property must be set in order to be able to compile .wat to .wasm", SystemProperties.WAT_TO_WASM_EXECUTABLE_PROPERTY_NAME)); + } return executable; } diff --git a/wasm/src/org.graalvm.wasm.utils/src/org/graalvm/wasm/utils/WasmResource.java b/wasm/src/org.graalvm.wasm.utils/src/org/graalvm/wasm/utils/WasmResource.java index 54acadd9cbc1..7448c5f73b68 100644 --- a/wasm/src/org.graalvm.wasm.utils/src/org/graalvm/wasm/utils/WasmResource.java +++ b/wasm/src/org.graalvm.wasm.utils/src/org/graalvm/wasm/utils/WasmResource.java @@ -60,7 +60,7 @@ public static byte[] getResourceAsBytes(String resourceName, boolean fail) throw InputStream stream = WasmResource.class.getResourceAsStream(resourceName); if (stream == null) { if (fail) { - Assert.fail(String.format("Could not find resource: %s", resourceName)); + throw new RuntimeException(String.format("Could not find resource: %s", resourceName)); } else { return null; } @@ -85,7 +85,7 @@ public static Object getResourceAsTest(String baseName, boolean fail) throws IOE return text; } if (fail) { - Assert.fail(String.format("Could not find test (neither .wasm or .wat): %s", baseName)); + throw new RuntimeException(String.format("Could not find test (neither .wasm or .wat): %s", baseName)); } return null; } diff --git a/wasm/src/org.graalvm.wasm.utils/src/org/graalvm/wasm/utils/cases/WasmCase.java b/wasm/src/org.graalvm.wasm.utils/src/org/graalvm/wasm/utils/cases/WasmCase.java index 22a8ad9c0330..ee86ea331b7c 100644 --- a/wasm/src/org.graalvm.wasm.utils/src/org/graalvm/wasm/utils/cases/WasmCase.java +++ b/wasm/src/org.graalvm.wasm.utils/src/org/graalvm/wasm/utils/cases/WasmCase.java @@ -58,10 +58,10 @@ import org.graalvm.polyglot.Value; import org.graalvm.polyglot.io.ByteSequence; import org.graalvm.wasm.WasmLanguage; -import org.graalvm.wasm.utils.Assert; import org.graalvm.wasm.utils.SystemProperties; import org.graalvm.wasm.utils.WasmBinaryTools; import org.graalvm.wasm.utils.WasmResource; +import org.junit.Assert; /** * Instances of this class are used for WebAssembly test/benchmark cases. @@ -131,11 +131,11 @@ public static WasmCaseData expected(Object expectedValue) { } public static WasmCaseData expectedFloat(float expectedValue, float delta) { - return new WasmCaseData((Value result, String output) -> Assert.assertFloatEquals("Failure: result:", expectedValue, result.as(Float.class), delta)); + return new WasmCaseData((Value result, String output) -> Assert.assertEquals("Failure: result:", expectedValue, result.as(Float.class), delta)); } public static WasmCaseData expectedDouble(double expectedValue, double delta) { - return new WasmCaseData((Value result, String output) -> Assert.assertDoubleEquals("Failure: result:", expectedValue, result.as(Double.class), delta)); + return new WasmCaseData((Value result, String output) -> Assert.assertEquals("Failure: result:", expectedValue, result.as(Double.class), delta)); } public static WasmCaseData expectedThrows(String expectedErrorMessage, WasmCaseData.ErrorType phase) { @@ -245,7 +245,7 @@ public static WasmCase collectFileCase(String type, String resource, String case caseData = WasmCase.expectedThrows(resultValue, WasmCaseData.ErrorType.Runtime); break; default: - Assert.fail(String.format("Unknown type in result specification: %s", resultType)); + throw new RuntimeException(String.format("Unknown type in result specification: %s", resultType)); } if (mainContents.size() == 1) { @@ -255,7 +255,7 @@ public static WasmCase collectFileCase(String type, String resource, String case } else if (content instanceof byte[]) { return WasmCase.create(caseName, caseData, (byte[]) content, options); } else { - Assert.fail("Unknown content type: " + content.getClass()); + throw new RuntimeException("Unknown content type: " + content.getClass()); } } else if (mainContents.size() > 1) { return new WasmMultiCase(caseName, caseData, mainContents, options); @@ -268,7 +268,7 @@ public static WasmCase loadBenchmarkCase(String resource) throws IOException { final String name = SystemProperties.BENCHMARK_NAME; Assert.assertNotNull("Please select a benchmark by setting -D" + SystemProperties.BENCHMARK_NAME_PROPERTY_NAME, name); - Assert.assertTrue("Benchmark name must not be empty", !name.trim().isEmpty()); + Assert.assertFalse("Benchmark name must not be empty", name.trim().isEmpty()); final WasmCase result = WasmCase.collectFileCase("bench", resource, name); Assert.assertNotNull(String.format("Benchmark %s.%s not found", name, name), result); @@ -280,7 +280,7 @@ public static void validateResult(BiConsumer validator, Value res if (validator != null) { validator.accept(result, capturedStdout.toString(StandardCharsets.UTF_8)); } else { - Assert.fail("Test was not expected to return a value."); + throw new RuntimeException("Test was not expected to return a value."); } } diff --git a/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/memory/UnsafeWasmMemory.java b/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/memory/UnsafeWasmMemory.java index 00e2a6a5abfd..3197667cd0cb 100644 --- a/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/memory/UnsafeWasmMemory.java +++ b/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/memory/UnsafeWasmMemory.java @@ -1006,10 +1006,7 @@ public void copyToBuffer(Node node, byte[] dst, long srcOffset, int dstOffset, i if (outOfBounds(srcOffset, length)) { throw trapOutOfBounds(node, srcOffset, length); } - for (int i = 0; i < length; i++) { - byte b = unsafe.getByte(startAddress + srcOffset + i); - dst[dstOffset + i] = b; - } + unsafe.copyMemory(null, startAddress + srcOffset, dst, Unsafe.ARRAY_BYTE_BASE_OFFSET + dstOffset * Unsafe.ARRAY_BYTE_INDEX_SCALE, length); } @Override From e56fb11c0a708c605ade6bd7de2c5e2be646c7f8 Mon Sep 17 00:00:00 2001 From: Josef Haider Date: Tue, 12 Dec 2023 10:04:44 +0100 Subject: [PATCH 174/593] Fix javadoc in AArch64ASIMDAssembler --- .../asm/aarch64/AArch64ASIMDAssembler.java | 42 +++++++++---------- 1 file changed, 21 insertions(+), 21 deletions(-) diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/asm/aarch64/AArch64ASIMDAssembler.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/asm/aarch64/AArch64ASIMDAssembler.java index a806c7c4fc80..960dd4be0ebf 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/asm/aarch64/AArch64ASIMDAssembler.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/asm/aarch64/AArch64ASIMDAssembler.java @@ -3559,26 +3559,7 @@ public void umaxVVV(ASIMDSize size, ElementSize eSize, Register dst, Register sr } /** - * C7.2.362 Unsigned maximum across vector.
    - * - * dst = uint_max(src[0], ..., src[n]). - * - * @param size register size. - * @param elementSize width of each operand. - * @param dst SIMD register. - * @param src SIMD register. - */ - public void umaxvSV(ASIMDSize size, ElementSize elementSize, Register dst, Register src) { - assert dst.getRegisterCategory().equals(SIMD) : dst; - assert src.getRegisterCategory().equals(SIMD) : src; - assert !(size == ASIMDSize.HalfReg && elementSize == ElementSize.Word) : "Invalid size and lane combination for umaxv"; - assert elementSize != ElementSize.DoubleWord : "Invalid lane width for umaxv"; - - acrossLanesEncoding(ASIMDInstruction.UMAXV, size, elemSizeXX(elementSize), dst, src); - } - - /** - * C7.2.344 Unsigned maximum pairwise.
    + * C7.2.361 Unsigned maximum pairwise.
    * * * concat = src2:src1 @@ -3602,6 +3583,25 @@ public void umaxpVVV(ASIMDSize size, ElementSize eSize, Register dst, Register s threeSameEncoding(ASIMDInstruction.UMAXP, size, elemSizeXX(eSize), dst, src1, src2); } + /** + * C7.2.362 Unsigned maximum across vector.
    + * + * dst = uint_max(src[0], ..., src[n]). + * + * @param size register size. + * @param elementSize width of each operand. + * @param dst SIMD register. + * @param src SIMD register. + */ + public void umaxvSV(ASIMDSize size, ElementSize elementSize, Register dst, Register src) { + assert dst.getRegisterCategory().equals(SIMD) : dst; + assert src.getRegisterCategory().equals(SIMD) : src; + assert !(size == ASIMDSize.HalfReg && elementSize == ElementSize.Word) : "Invalid size and lane combination for umaxv"; + assert elementSize != ElementSize.DoubleWord : "Invalid lane width for umaxv"; + + acrossLanesEncoding(ASIMDInstruction.UMAXV, size, elemSizeXX(elementSize), dst, src); + } + /** * C7.2.363 Unsigned minimum.
    * @@ -3625,7 +3625,7 @@ public void uminVVV(ASIMDSize size, ElementSize eSize, Register dst, Register sr } /** - * C7.2.347 Unsigned minimum pairwise.
    + * C7.2.364 Unsigned minimum pairwise.
    * * * concat = src2:src1 From 1fef7039c9aecdf92a03fbec7faefa4c217a660e Mon Sep 17 00:00:00 2001 From: Josef Eisl Date: Tue, 12 Dec 2023 10:45:48 +0100 Subject: [PATCH 175/593] vm/compiler: disable systemic compilation problem detection for libgraal OOME gate --- vm/mx.vm/mx_vm_gate.py | 1 + 1 file changed, 1 insertion(+) diff --git a/vm/mx.vm/mx_vm_gate.py b/vm/mx.vm/mx_vm_gate.py index 13c388fce2e6..e3e9a3c17185 100644 --- a/vm/mx.vm/mx_vm_gate.py +++ b/vm/mx.vm/mx_vm_gate.py @@ -295,6 +295,7 @@ def _test_libgraal_oome_dumping(): vmargs = ['-Djdk.libgraal.CrashAt=*', '-Djdk.libgraal.Xmx128M', '-Djdk.libgraal.PrintGC=true', + '-Djdk.libgraal.SystemicCompilationFailureRate=0', '-Djdk.libgraal.HeapDumpOnOutOfMemoryError=true', f'-Djdk.libgraal.HeapDumpPath={n}', '-Djdk.libgraal.CrashAtThrowsOOME=true'] From 5e692e7de73ae7d9275c3e00b1a226740d2a53a8 Mon Sep 17 00:00:00 2001 From: Josef Eisl Date: Tue, 12 Dec 2023 12:05:48 +0100 Subject: [PATCH 176/593] compiler: adapt "JDK-8319111: Mismatched MemorySegment heap access is not consistently intrinsified" --- .../compiler/hotspot/meta/UnimplementedGraalIntrinsics.java | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/meta/UnimplementedGraalIntrinsics.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/meta/UnimplementedGraalIntrinsics.java index eff867e7c52c..13528009a4e9 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/meta/UnimplementedGraalIntrinsics.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/meta/UnimplementedGraalIntrinsics.java @@ -127,12 +127,14 @@ public UnimplementedGraalIntrinsics() { "jdk/internal/vm/vector/VectorSupport.indexPartiallyInUpperRange(Ljava/lang/Class;Ljava/lang/Class;IJJLjdk/internal/vm/vector/VectorSupport$IndexPartiallyInUpperRangeOperation;)Ljdk/internal/vm/vector/VectorSupport$VectorMask;", "jdk/internal/vm/vector/VectorSupport.indexVector(Ljava/lang/Class;Ljava/lang/Class;ILjdk/internal/vm/vector/VectorSupport$Vector;ILjdk/internal/vm/vector/VectorSupport$VectorSpecies;Ljdk/internal/vm/vector/VectorSupport$IndexOperation;)Ljdk/internal/vm/vector/VectorSupport$Vector;", "jdk/internal/vm/vector/VectorSupport.insert(Ljava/lang/Class;Ljava/lang/Class;ILjdk/internal/vm/vector/VectorSupport$Vector;IJLjdk/internal/vm/vector/VectorSupport$VecInsertOp;)Ljdk/internal/vm/vector/VectorSupport$Vector;", - "jdk/internal/vm/vector/VectorSupport.loadMasked(Ljava/lang/Class;Ljava/lang/Class;Ljava/lang/Class;ILjava/lang/Object;JLjdk/internal/vm/vector/VectorSupport$VectorMask;ILjava/lang/Object;JLjdk/internal/vm/vector/VectorSupport$VectorSpecies;Ljdk/internal/vm/vector/VectorSupport$LoadVectorMaskedOperation;)Ljdk/internal/vm/vector/VectorSupport$Vector;", + jdk == 21 ? "jdk/internal/vm/vector/VectorSupport.loadMasked(Ljava/lang/Class;Ljava/lang/Class;Ljava/lang/Class;ILjava/lang/Object;JLjdk/internal/vm/vector/VectorSupport$VectorMask;ILjava/lang/Object;JLjdk/internal/vm/vector/VectorSupport$VectorSpecies;Ljdk/internal/vm/vector/VectorSupport$LoadVectorMaskedOperation;)Ljdk/internal/vm/vector/VectorSupport$Vector;": + "jdk/internal/vm/vector/VectorSupport.loadMasked(Ljava/lang/Class;Ljava/lang/Class;Ljava/lang/Class;ILjava/lang/Object;JZLjdk/internal/vm/vector/VectorSupport$VectorMask;ILjava/lang/Object;JLjdk/internal/vm/vector/VectorSupport$VectorSpecies;Ljdk/internal/vm/vector/VectorSupport$LoadVectorMaskedOperation;)Ljdk/internal/vm/vector/VectorSupport$Vector;", "jdk/internal/vm/vector/VectorSupport.loadWithMap(Ljava/lang/Class;Ljava/lang/Class;Ljava/lang/Class;ILjava/lang/Class;Ljava/lang/Object;JLjdk/internal/vm/vector/VectorSupport$Vector;Ljdk/internal/vm/vector/VectorSupport$VectorMask;Ljava/lang/Object;I[IILjdk/internal/vm/vector/VectorSupport$VectorSpecies;Ljdk/internal/vm/vector/VectorSupport$LoadVectorOperationWithMap;)Ljdk/internal/vm/vector/VectorSupport$Vector;", "jdk/internal/vm/vector/VectorSupport.maskReductionCoerced(ILjava/lang/Class;Ljava/lang/Class;ILjdk/internal/vm/vector/VectorSupport$VectorMask;Ljdk/internal/vm/vector/VectorSupport$VectorMaskOp;)J", "jdk/internal/vm/vector/VectorSupport.maybeRebox(Ljdk/internal/vm/vector/VectorSupport$VectorPayload;)Ljdk/internal/vm/vector/VectorSupport$VectorPayload;", "jdk/internal/vm/vector/VectorSupport.rearrangeOp(Ljava/lang/Class;Ljava/lang/Class;Ljava/lang/Class;Ljava/lang/Class;ILjdk/internal/vm/vector/VectorSupport$Vector;Ljdk/internal/vm/vector/VectorSupport$VectorShuffle;Ljdk/internal/vm/vector/VectorSupport$VectorMask;Ljdk/internal/vm/vector/VectorSupport$VectorRearrangeOp;)Ljdk/internal/vm/vector/VectorSupport$Vector;", - "jdk/internal/vm/vector/VectorSupport.storeMasked(Ljava/lang/Class;Ljava/lang/Class;Ljava/lang/Class;ILjava/lang/Object;JLjdk/internal/vm/vector/VectorSupport$Vector;Ljdk/internal/vm/vector/VectorSupport$VectorMask;Ljava/lang/Object;JLjdk/internal/vm/vector/VectorSupport$StoreVectorMaskedOperation;)V", + jdk == 21 ? "jdk/internal/vm/vector/VectorSupport.storeMasked(Ljava/lang/Class;Ljava/lang/Class;Ljava/lang/Class;ILjava/lang/Object;JLjdk/internal/vm/vector/VectorSupport$Vector;Ljdk/internal/vm/vector/VectorSupport$VectorMask;Ljava/lang/Object;JLjdk/internal/vm/vector/VectorSupport$StoreVectorMaskedOperation;)V": + "jdk/internal/vm/vector/VectorSupport.storeMasked(Ljava/lang/Class;Ljava/lang/Class;Ljava/lang/Class;ILjava/lang/Object;JZLjdk/internal/vm/vector/VectorSupport$Vector;Ljdk/internal/vm/vector/VectorSupport$VectorMask;Ljava/lang/Object;JLjdk/internal/vm/vector/VectorSupport$StoreVectorMaskedOperation;)V", "jdk/internal/vm/vector/VectorSupport.storeWithMap(Ljava/lang/Class;Ljava/lang/Class;Ljava/lang/Class;ILjava/lang/Class;Ljava/lang/Object;JLjdk/internal/vm/vector/VectorSupport$Vector;Ljdk/internal/vm/vector/VectorSupport$Vector;Ljdk/internal/vm/vector/VectorSupport$VectorMask;Ljava/lang/Object;I[IILjdk/internal/vm/vector/VectorSupport$StoreVectorOperationWithMap;)V", "jdk/internal/vm/vector/VectorSupport.ternaryOp(ILjava/lang/Class;Ljava/lang/Class;Ljava/lang/Class;ILjdk/internal/vm/vector/VectorSupport$Vector;Ljdk/internal/vm/vector/VectorSupport$Vector;Ljdk/internal/vm/vector/VectorSupport$Vector;Ljdk/internal/vm/vector/VectorSupport$VectorMask;Ljdk/internal/vm/vector/VectorSupport$TernaryOperation;)Ljdk/internal/vm/vector/VectorSupport$Vector;" // @formatter:on From 841716acedd099790c45f471263a46ac4b967473 Mon Sep 17 00:00:00 2001 From: Josef Eisl Date: Tue, 12 Dec 2023 11:30:08 +0000 Subject: [PATCH 177/593] svm: fix error message --- .../com/oracle/svm/core/jfr/Target_jdk_jfr_internal_JVM.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jfr/Target_jdk_jfr_internal_JVM.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jfr/Target_jdk_jfr_internal_JVM.java index 362de09ddc0a..103ff7276ce0 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jfr/Target_jdk_jfr_internal_JVM.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jfr/Target_jdk_jfr_internal_JVM.java @@ -171,7 +171,7 @@ public static void unregisterStackFilter(long stackFilterId) { @Substitute @TargetElement(onlyWith = JDK22OrLater.class) public static void setMiscellaneous(long eventTypeId, long value) { - throw VMError.unimplemented("JFR StackFilters are not yet supported."); + throw VMError.unimplemented("@Deprecated JFR events are not yet supported."); } /** See {@link JVM#getThreadId}. */ From 6bbd58025a3abd0087b265ff59330cd0a5f335f7 Mon Sep 17 00:00:00 2001 From: Josef Eisl Date: Tue, 12 Dec 2023 13:23:36 +0100 Subject: [PATCH 178/593] compiler: adapt "JDK-8319111: Mismatched MemorySegment heap access is not consistently intrinsified" (cont) --- .../compiler/hotspot/meta/UnimplementedGraalIntrinsics.java | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/meta/UnimplementedGraalIntrinsics.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/meta/UnimplementedGraalIntrinsics.java index 13528009a4e9..6f1c57d11738 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/meta/UnimplementedGraalIntrinsics.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/meta/UnimplementedGraalIntrinsics.java @@ -166,11 +166,13 @@ public UnimplementedGraalIntrinsics() { "jdk/internal/vm/vector/VectorSupport.compare(ILjava/lang/Class;Ljava/lang/Class;Ljava/lang/Class;ILjdk/internal/vm/vector/VectorSupport$Vector;Ljdk/internal/vm/vector/VectorSupport$Vector;Ljdk/internal/vm/vector/VectorSupport$VectorMask;Ljdk/internal/vm/vector/VectorSupport$VectorCompareOp;)Ljdk/internal/vm/vector/VectorSupport$VectorMask;", "jdk/internal/vm/vector/VectorSupport.convert(ILjava/lang/Class;Ljava/lang/Class;ILjava/lang/Class;Ljava/lang/Class;ILjdk/internal/vm/vector/VectorSupport$VectorPayload;Ljdk/internal/vm/vector/VectorSupport$VectorSpecies;Ljdk/internal/vm/vector/VectorSupport$VectorConvertOp;)Ljdk/internal/vm/vector/VectorSupport$VectorPayload;", "jdk/internal/vm/vector/VectorSupport.fromBitsCoerced(Ljava/lang/Class;Ljava/lang/Class;IJILjdk/internal/vm/vector/VectorSupport$VectorSpecies;Ljdk/internal/vm/vector/VectorSupport$FromBitsCoercedOperation;)Ljdk/internal/vm/vector/VectorSupport$VectorPayload;", - "jdk/internal/vm/vector/VectorSupport.load(Ljava/lang/Class;Ljava/lang/Class;ILjava/lang/Object;JLjava/lang/Object;JLjdk/internal/vm/vector/VectorSupport$VectorSpecies;Ljdk/internal/vm/vector/VectorSupport$LoadOperation;)Ljdk/internal/vm/vector/VectorSupport$VectorPayload;", + jdk == 21 ? "jdk/internal/vm/vector/VectorSupport.load(Ljava/lang/Class;Ljava/lang/Class;ILjava/lang/Object;JLjava/lang/Object;JLjdk/internal/vm/vector/VectorSupport$VectorSpecies;Ljdk/internal/vm/vector/VectorSupport$LoadOperation;)Ljdk/internal/vm/vector/VectorSupport$VectorPayload;": + "jdk/internal/vm/vector/VectorSupport.load(Ljava/lang/Class;Ljava/lang/Class;ILjava/lang/Object;JZLjava/lang/Object;JLjdk/internal/vm/vector/VectorSupport$VectorSpecies;Ljdk/internal/vm/vector/VectorSupport$LoadOperation;)Ljdk/internal/vm/vector/VectorSupport$VectorPayload;", "jdk/internal/vm/vector/VectorSupport.reductionCoerced(ILjava/lang/Class;Ljava/lang/Class;Ljava/lang/Class;ILjdk/internal/vm/vector/VectorSupport$Vector;Ljdk/internal/vm/vector/VectorSupport$VectorMask;Ljdk/internal/vm/vector/VectorSupport$ReductionOperation;)J", "jdk/internal/vm/vector/VectorSupport.shuffleIota(Ljava/lang/Class;Ljava/lang/Class;Ljdk/internal/vm/vector/VectorSupport$VectorSpecies;IIIILjdk/internal/vm/vector/VectorSupport$ShuffleIotaOperation;)Ljdk/internal/vm/vector/VectorSupport$VectorShuffle;", "jdk/internal/vm/vector/VectorSupport.shuffleToVector(Ljava/lang/Class;Ljava/lang/Class;Ljava/lang/Class;Ljdk/internal/vm/vector/VectorSupport$VectorShuffle;ILjdk/internal/vm/vector/VectorSupport$ShuffleToVectorOperation;)Ljdk/internal/vm/vector/VectorSupport$Vector;", - "jdk/internal/vm/vector/VectorSupport.store(Ljava/lang/Class;Ljava/lang/Class;ILjava/lang/Object;JLjdk/internal/vm/vector/VectorSupport$VectorPayload;Ljava/lang/Object;JLjdk/internal/vm/vector/VectorSupport$StoreVectorOperation;)V", + jdk == 21 ? "jdk/internal/vm/vector/VectorSupport.store(Ljava/lang/Class;Ljava/lang/Class;ILjava/lang/Object;JLjdk/internal/vm/vector/VectorSupport$VectorPayload;Ljava/lang/Object;JLjdk/internal/vm/vector/VectorSupport$StoreVectorOperation;)V": + "jdk/internal/vm/vector/VectorSupport.store(Ljava/lang/Class;Ljava/lang/Class;ILjava/lang/Object;JZLjdk/internal/vm/vector/VectorSupport$VectorPayload;Ljava/lang/Object;JLjdk/internal/vm/vector/VectorSupport$StoreVectorOperation;)V", "jdk/internal/vm/vector/VectorSupport.test(ILjava/lang/Class;Ljava/lang/Class;ILjdk/internal/vm/vector/VectorSupport$VectorMask;Ljdk/internal/vm/vector/VectorSupport$VectorMask;Ljava/util/function/BiFunction;)Z", "jdk/internal/vm/vector/VectorSupport.unaryOp(ILjava/lang/Class;Ljava/lang/Class;Ljava/lang/Class;ILjdk/internal/vm/vector/VectorSupport$Vector;Ljdk/internal/vm/vector/VectorSupport$VectorMask;Ljdk/internal/vm/vector/VectorSupport$UnaryOperation;)Ljdk/internal/vm/vector/VectorSupport$Vector;" // @formatter:on From 641ee2d67b6cfa8e309a1e3e07578a1d862a5bcf Mon Sep 17 00:00:00 2001 From: Josef Eisl Date: Tue, 12 Dec 2023 15:35:46 +0100 Subject: [PATCH 179/593] Revert "vm/ci: add DisableSubstitutionReturnTypeCheck option to quarkus benchmarks [GR-48152]" This reverts commit d73a31055b9a6a63d257b1c67c52a52be1c30d20. --- java-benchmarks/mx.java-benchmarks/mx_java_benchmarks.py | 1 - 1 file changed, 1 deletion(-) diff --git a/java-benchmarks/mx.java-benchmarks/mx_java_benchmarks.py b/java-benchmarks/mx.java-benchmarks/mx_java_benchmarks.py index e2ef50afe467..769e248b3de5 100644 --- a/java-benchmarks/mx.java-benchmarks/mx_java_benchmarks.py +++ b/java-benchmarks/mx.java-benchmarks/mx_java_benchmarks.py @@ -347,7 +347,6 @@ def extra_image_build_argument(self, benchmark, args): '-H:+AllowFoldMethods', '-H:-UseServiceLoaderFeature', '-H:+AllowDeprecatedBuilderClassesOnImageClasspath', # needs to be removed once GR-41746 is fixed - '-H:+DisableSubstitutionReturnTypeCheck', # remove once Quarkus fixed their substitutions (GR-48152) ]) + super(BaseQuarkusBenchmarkSuite, self).extra_image_build_argument(benchmark, args) From a4e914f8cd1dde32e89148b5ce55fdba525e738f Mon Sep 17 00:00:00 2001 From: Josef Eisl Date: Tue, 12 Dec 2023 15:36:40 +0100 Subject: [PATCH 180/593] Revert "svm: add DisableSubstitutionReturnTypeCheck option [GR-48152]" This reverts commit d01ff88512e0bc6682cce1ef0912a2678f59c5e5. --- .../src/com/oracle/svm/hosted/NativeImageOptions.java | 3 --- .../svm/hosted/substitute/AnnotationSubstitutionProcessor.java | 3 +-- 2 files changed, 1 insertion(+), 5 deletions(-) diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/NativeImageOptions.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/NativeImageOptions.java index 56cd319598a5..10f0ee1798a3 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/NativeImageOptions.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/NativeImageOptions.java @@ -150,9 +150,6 @@ protected void onValueUpdate(EconomicMap, Object> values, Boolean o @Option(help = "Deprecated", type = User)// static final HostedOptionKey AllowIncompleteClasspath = new HostedOptionKey<>(false); - @Option(help = "Disable substitution return type checking", type = Debug, deprecated = true, stability = OptionStability.EXPERIMENTAL, deprecationMessage = "This option will be removed soon and the return type check will be mandatory.")// - public static final HostedOptionKey DisableSubstitutionReturnTypeCheck = new HostedOptionKey<>(false); - @SuppressWarnings("all") private static boolean areAssertionsEnabled() { boolean assertsEnabled = false; diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/substitute/AnnotationSubstitutionProcessor.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/substitute/AnnotationSubstitutionProcessor.java index 8970ee6efc23..5d5e98b49f2d 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/substitute/AnnotationSubstitutionProcessor.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/substitute/AnnotationSubstitutionProcessor.java @@ -861,8 +861,7 @@ private ResolvedJavaMethod findOriginalMethod(Executable annotatedMethod, Class< Method originalMethod = originalClass.getDeclaredMethod(originalName, originalParams); guarantee(Modifier.isStatic(annotatedMethod.getModifiers()) == Modifier.isStatic(originalMethod.getModifiers()), "Static modifier mismatch: %s, %s", annotatedMethod, originalMethod); - - guarantee(NativeImageOptions.DisableSubstitutionReturnTypeCheck.getValue() || getTargetClass(((Method) annotatedMethod).getReturnType()).equals(originalMethod.getReturnType()), + guarantee(getTargetClass(((Method) annotatedMethod).getReturnType()).equals(originalMethod.getReturnType()), "Return type mismatch:%n %s%n %s", annotatedMethod, originalMethod); return metaAccess.lookupJavaMethod(originalMethod); From 77e3cc15ea38555ad8ed27ef2d232111bbfebbaa Mon Sep 17 00:00:00 2001 From: Florian Huemer Date: Tue, 12 Dec 2023 17:02:56 +0100 Subject: [PATCH 181/593] Use Unsafe#copyMemory in NativeWasmMemory. --- .../src/org/graalvm/wasm/memory/NativeWasmMemory.java | 7 ++----- .../src/org/graalvm/wasm/memory/UnsafeWasmMemory.java | 2 +- 2 files changed, 3 insertions(+), 6 deletions(-) diff --git a/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/memory/NativeWasmMemory.java b/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/memory/NativeWasmMemory.java index fe8b71e29c32..24a3345c296b 100644 --- a/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/memory/NativeWasmMemory.java +++ b/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/memory/NativeWasmMemory.java @@ -48,10 +48,10 @@ import java.lang.reflect.Field; import java.nio.ByteBuffer; -import com.oracle.truffle.api.CompilerDirectives; import org.graalvm.wasm.exception.Failure; import org.graalvm.wasm.exception.WasmException; +import com.oracle.truffle.api.CompilerDirectives; import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary; import com.oracle.truffle.api.nodes.Node; @@ -1001,10 +1001,7 @@ public void copyToBuffer(Node node, byte[] dst, long srcOffset, int dstOffset, i if (outOfBounds(srcOffset, length)) { throw trapOutOfBounds(node, srcOffset, length); } - for (int i = 0; i < length; i++) { - byte b = unsafe.getByte(startAddress + srcOffset + i); - dst[dstOffset + i] = b; - } + unsafe.copyMemory(null, startAddress + srcOffset, dst, Unsafe.ARRAY_BYTE_BASE_OFFSET + (long) dstOffset * Unsafe.ARRAY_BYTE_INDEX_SCALE, length); } @Override diff --git a/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/memory/UnsafeWasmMemory.java b/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/memory/UnsafeWasmMemory.java index 3197667cd0cb..04fd36e01151 100644 --- a/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/memory/UnsafeWasmMemory.java +++ b/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/memory/UnsafeWasmMemory.java @@ -1006,7 +1006,7 @@ public void copyToBuffer(Node node, byte[] dst, long srcOffset, int dstOffset, i if (outOfBounds(srcOffset, length)) { throw trapOutOfBounds(node, srcOffset, length); } - unsafe.copyMemory(null, startAddress + srcOffset, dst, Unsafe.ARRAY_BYTE_BASE_OFFSET + dstOffset * Unsafe.ARRAY_BYTE_INDEX_SCALE, length); + unsafe.copyMemory(null, startAddress + srcOffset, dst, Unsafe.ARRAY_BYTE_BASE_OFFSET + (long) dstOffset * Unsafe.ARRAY_BYTE_INDEX_SCALE, length); } @Override From 6647934cbc24e3aaa9a91ce9085945a3e130704e Mon Sep 17 00:00:00 2001 From: Tomas Zezula Date: Mon, 11 Dec 2023 11:49:14 +0100 Subject: [PATCH 182/593] [GR-50814] Add option to log internal resource operations. --- .../test/polyglot/InternalResourceTest.java | 136 ++++++++++++++++++ .../polyglot/InternalResourceCache.java | 26 +++- .../polyglot/InternalResourceRoots.java | 81 +++++++---- 3 files changed, 218 insertions(+), 25 deletions(-) diff --git a/truffle/src/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/polyglot/InternalResourceTest.java b/truffle/src/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/polyglot/InternalResourceTest.java index e442baec8844..5c90461d430b 100644 --- a/truffle/src/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/polyglot/InternalResourceTest.java +++ b/truffle/src/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/polyglot/InternalResourceTest.java @@ -41,8 +41,10 @@ package com.oracle.truffle.api.test.polyglot; import java.io.BufferedReader; +import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.InputStreamReader; +import java.io.PrintStream; import java.nio.channels.Channels; import java.nio.charset.StandardCharsets; import java.nio.file.DirectoryStream; @@ -58,6 +60,7 @@ import java.util.List; import java.util.Objects; import java.util.Set; +import java.util.regex.Pattern; import com.oracle.truffle.api.CompilerDirectives; import com.oracle.truffle.api.InstrumentInfo; @@ -917,6 +920,139 @@ public void testGetTruffleFileInternal() { } } + @Registration(/* ... */internalResources = {SourcesResource.class, LibraryResource.class}) + public static class TestLogging extends AbstractExecutableTestLanguage { + @Override + @TruffleBoundary + @SuppressWarnings("try") + protected Object execute(RootNode node, Env env, Object[] contextArguments, Object[] frameArguments) throws Exception { + try (TemporaryResourceCacheRoot cache = new TemporaryResourceCacheRoot()) { + env.getInternalResource(SourcesResource.ID); + env.getInternalResource(LibraryResource.ID); + } + return ""; + } + } + + @Test + public void testLogging() { + Assume.assumeFalse("Cannot run as native unittest", ImageInfo.inImageRuntimeCode()); + PrintStream originalErr = System.err; + ByteArrayOutputStream testErr = new ByteArrayOutputStream(); + System.setErr(new PrintStream(testErr)); + System.setProperty("polyglotimpl.TraceInternalResources", "true"); + try (Context context = Context.create()) { + String languageId = TestUtils.getDefaultLanguageId(TestLogging.class); + AbstractExecutableTestLanguage.execute(context, TestLogging.class); + String[] lines = testErr.toString().split("\n"); + String line = findLine("^\\[engine\\]\\[resource\\].*" + languageId + "::" + SourcesResource.ID, lines); + assertNotNull(line); + line = findLine("^\\[engine\\]\\[resource\\].*" + languageId + "::" + LibraryResource.ID, lines); + assertNotNull(line); + } finally { + System.getProperties().remove("polyglotimpl.TraceInternalResources"); + System.setErr(originalErr); + } + } + + @Test + public void testLoggingOverriddenCacheRoot() throws IOException { + Assume.assumeFalse("Cannot run as native unittest", ImageInfo.inImageRuntimeCode()); + PrintStream originalErr = System.err; + ByteArrayOutputStream testErr = new ByteArrayOutputStream(); + Path tmpDir = Files.createTempDirectory("resources"); + String languageId = TestUtils.getDefaultLanguageId(TestLogging.class); + Engine.copyResources(tmpDir, languageId); + System.setErr(new PrintStream(testErr)); + System.setProperty("polyglotimpl.TraceInternalResources", "true"); + System.setProperty("polyglot.engine.resourcePath", tmpDir.toString()); + try (Context context = Context.create()) { + AbstractExecutableTestLanguage.execute(context, TestLogging.class); + String[] lines = testErr.toString().split("\n"); + String line = findLine("^\\[engine\\]\\[resource\\].*" + languageId + "::" + SourcesResource.ID, lines); + assertNotNull(line); + assertTrue(line.contains(tmpDir.toString())); + line = findLine("^\\[engine\\]\\[resource\\].*" + languageId + "::" + LibraryResource.ID, lines); + assertNotNull(line); + assertTrue(line.contains(tmpDir.toString())); + } finally { + System.getProperties().remove("polyglot.engine.resourcePath"); + System.getProperties().remove("polyglotimpl.TraceInternalResources"); + System.setErr(originalErr); + delete(tmpDir); + } + } + + @Test + public void testLoggingOverriddenComponentRoot() throws IOException { + Assume.assumeFalse("Cannot run as native unittest", ImageInfo.inImageRuntimeCode()); + PrintStream originalErr = System.err; + ByteArrayOutputStream testErr = new ByteArrayOutputStream(); + Path tmpDir = Files.createTempDirectory("resources"); + String languageId = TestUtils.getDefaultLanguageId(TestLogging.class); + String overridePropName = "polyglot.engine.resourcePath." + languageId; + Path languageResources = tmpDir.resolve(languageId); + Engine.copyResources(tmpDir, languageId); + System.setErr(new PrintStream(testErr)); + System.setProperty("polyglotimpl.TraceInternalResources", "true"); + System.setProperty(overridePropName, languageResources.toString()); + try (Context context = Context.create()) { + AbstractExecutableTestLanguage.execute(context, TestLogging.class); + String[] lines = testErr.toString().split("\n"); + String line = findLine("^\\[engine\\]\\[resource\\].*" + languageId + "::" + SourcesResource.ID, lines); + assertNotNull(line); + assertTrue(line.contains(languageResources.toString())); + line = findLine("^\\[engine\\]\\[resource\\].*" + languageId + "::" + LibraryResource.ID, lines); + assertNotNull(line); + assertTrue(line.contains(languageResources.toString())); + } finally { + System.getProperties().remove(overridePropName); + System.getProperties().remove("polyglotimpl.TraceInternalResources"); + System.setErr(originalErr); + delete(tmpDir); + } + } + + @Test + public void testLoggingOverriddenResourceRoot() throws IOException { + Assume.assumeFalse("Cannot run as native unittest", ImageInfo.inImageRuntimeCode()); + PrintStream originalErr = System.err; + ByteArrayOutputStream testErr = new ByteArrayOutputStream(); + Path tmpDir = Files.createTempDirectory("resources"); + String languageId = TestUtils.getDefaultLanguageId(TestLogging.class); + String overridePropName = "polyglot.engine.resourcePath." + languageId + '.' + SourcesResource.ID; + Engine.copyResources(tmpDir, languageId); + Path sourceResource = tmpDir.resolve(languageId).resolve(SourcesResource.ID); + System.setErr(new PrintStream(testErr)); + System.setProperty("polyglotimpl.TraceInternalResources", "true"); + System.setProperty(overridePropName, sourceResource.toString()); + try (Context context = Context.create()) { + AbstractExecutableTestLanguage.execute(context, TestLogging.class); + String[] lines = testErr.toString().split("\n"); + String line = findLine("^\\[engine\\]\\[resource\\].*" + languageId + "::" + SourcesResource.ID, lines); + assertNotNull(line); + assertTrue(line.contains(sourceResource.toString())); + line = findLine("^\\[engine\\]\\[resource\\].*" + languageId + "::" + LibraryResource.ID, lines); + assertNotNull(line); + assertFalse(line.contains(sourceResource.toString())); + } finally { + System.getProperties().remove(overridePropName); + System.getProperties().remove("polyglotimpl.TraceInternalResources"); + System.setErr(originalErr); + delete(tmpDir); + } + } + + private static String findLine(String pattern, String[] lines) { + Pattern p = Pattern.compile(pattern); + for (String line : lines) { + if (p.matcher(line).find()) { + return line; + } + } + return null; + } + private static boolean hasResource(Path folder, Class language, Class resource) { return hasResource(folder, TestUtils.getDefaultLanguageId(language), resource); } diff --git a/truffle/src/com.oracle.truffle.polyglot/src/com/oracle/truffle/polyglot/InternalResourceCache.java b/truffle/src/com.oracle.truffle.polyglot/src/com/oracle/truffle/polyglot/InternalResourceCache.java index b3a22bbc4cdf..ff91710f3fc2 100644 --- a/truffle/src/com.oracle.truffle.polyglot/src/com/oracle/truffle/polyglot/InternalResourceCache.java +++ b/truffle/src/com.oracle.truffle.polyglot/src/com/oracle/truffle/polyglot/InternalResourceCache.java @@ -150,6 +150,22 @@ void initializeOwningRoot(InternalResourceRoots.Root root) { case UNVERSIONED -> findStandaloneResourceRoot(root.path()); case VERSIONED -> null; }; + if (path != null && InternalResourceRoots.isTraceInternalResourceEvents()) { + /* + * The path for the VERSIONED resource is logged when the resource is requested. + * Computation of this path is expensive and involves a call to + * InternalResource#versionHash(). Additionally, we log whether the resource was + * unpacked or reused. + */ + String hint = switch (root.kind()) { + case RESOURCE -> InternalResourceRoots.overriddenResourceRootProperty(id, resourceId) + " system property"; + case COMPONENT -> InternalResourceRoots.overriddenComponentRootProperty(id) + " system property"; + case UNVERSIONED -> "internal resource cache root directory"; + default -> throw CompilerDirectives.shouldNotReachHere(root.kind().name()); + }; + InternalResourceRoots.logInternalResourceEvent("Resolved a pre-created directory for the internal resource %s::%s to: %s, determined by the %s with the value %s.", + id, resourceId, path, hint, root.path()); + } } /** @@ -170,7 +186,12 @@ void clearCache() { static Path installRuntimeResource(InternalResource resource) throws IOException { InternalResourceCache cache = createRuntimeResourceCache(resource); synchronized (cache) { - return cache.installResource(InternalResourceCache::createInternalResourceEnvReflectively); + Path result = cache.path; + if (result == null) { + result = cache.installResource(InternalResourceCache::createInternalResourceEnvReflectively); + cache.path = result; + } + return result; } } @@ -205,6 +226,7 @@ private Path installResource(Function re } Path target = owningRoot.path().resolve(Path.of(sanitize(id), sanitize(resourceId), sanitize(versionHash))); if (!Files.exists(target)) { + InternalResourceRoots.logInternalResourceEvent("Resolved a directory for the internal resource %s::%s to: %s, unpacking resource files.", id, resourceId, target); Path parent = target.getParent(); if (parent == null) { throw CompilerDirectives.shouldNotReachHere("Target must have a parent directory but was " + target); @@ -226,6 +248,8 @@ private Path installResource(Function re } } } else { + InternalResourceRoots.logInternalResourceEvent("Resolved a directory for the internal resource %s::%s to: %s, using existing resource files.", + id, resourceId, target); verifyResourceRoot(target); } return target; diff --git a/truffle/src/com.oracle.truffle.polyglot/src/com/oracle/truffle/polyglot/InternalResourceRoots.java b/truffle/src/com.oracle.truffle.polyglot/src/com/oracle/truffle/polyglot/InternalResourceRoots.java index 46d91ea31340..8a2ffbbe1158 100644 --- a/truffle/src/com.oracle.truffle.polyglot/src/com/oracle/truffle/polyglot/InternalResourceRoots.java +++ b/truffle/src/com.oracle.truffle.polyglot/src/com/oracle/truffle/polyglot/InternalResourceRoots.java @@ -62,8 +62,22 @@ final class InternalResourceRoots { private static final String OVERRIDDEN_CACHE_ROOT = "polyglot.engine.resourcePath"; - private static final String OVERRIDDEN_COMPONENT_ROOT = "polyglot.engine.resourcePath."; - private static final String OVERRIDDEN_RESOURCE_ROOT = "polyglot.engine.resourcePath."; + + static String overriddenComponentRootProperty(String componentId) { + StringBuilder builder = new StringBuilder(OVERRIDDEN_CACHE_ROOT); + builder.append('.'); + builder.append(componentId); + return builder.toString(); + } + + static String overriddenResourceRootProperty(String componentId, String resourceId) { + StringBuilder builder = new StringBuilder(OVERRIDDEN_CACHE_ROOT); + builder.append('.'); + builder.append(componentId); + builder.append('.'); + builder.append(resourceId); + return builder.toString(); + } /** * This field is reset to {@code null} by the {@code TruffleBaseFeature} before writing the @@ -192,11 +206,12 @@ private static Set computeRoots(Pair defaultRoot) { } private static Pair findDefaultRoot() { - Path root; + ResolvedCacheFolder root; Root.Kind kind; String overriddenRoot = System.getProperty(OVERRIDDEN_CACHE_ROOT); if (overriddenRoot != null) { - root = Path.of(overriddenRoot); + Path overriddenRootPath = Path.of(overriddenRoot).toAbsolutePath(); + root = new ResolvedCacheFolder(overriddenRootPath, OVERRIDDEN_CACHE_ROOT + " system property", overriddenRootPath); kind = Root.Kind.UNVERSIONED; } else if (ImageInfo.inImageRuntimeCode()) { root = findCacheRootOnNativeImage(); @@ -205,40 +220,36 @@ private static Pair findDefaultRoot() { root = findCacheRootOnHotSpot(); kind = Root.Kind.VERSIONED; } - return Pair.create(root, kind); + logInternalResourceEvent("Resolved the root directory for the internal resource cache to: %s, determined by the %s with the value %s.", + root.path(), root.hint(), root.hintValue()); + return Pair.create(root.path(), kind); } private static void collectRoots(String componentId, Path componentRoot, Root.Kind componentKind, Collection resources, Map, List> collector) { Path useRoot = componentRoot; Root.Kind useKind = componentKind; - StringBuilder builder = new StringBuilder(OVERRIDDEN_COMPONENT_ROOT); - builder.append(componentId); - String overriddenRoot = System.getProperty(builder.toString()); + String overriddenRoot = System.getProperty(overriddenComponentRootProperty(componentId)); if (overriddenRoot != null) { - useRoot = Path.of(overriddenRoot); + useRoot = Path.of(overriddenRoot).toAbsolutePath(); useKind = Root.Kind.COMPONENT; } for (InternalResourceCache resource : resources) { Path resourceRoot = useRoot; Root.Kind resourceKind = useKind; - builder = new StringBuilder(OVERRIDDEN_RESOURCE_ROOT); - builder.append(componentId); - builder.append('.'); - builder.append(resource.getResourceId()); - overriddenRoot = System.getProperty(builder.toString()); + overriddenRoot = System.getProperty(overriddenResourceRootProperty(componentId, resource.getResourceId())); if (overriddenRoot != null) { - resourceRoot = Path.of(overriddenRoot); + resourceRoot = Path.of(overriddenRoot).toAbsolutePath(); resourceKind = Root.Kind.RESOURCE; } collector.computeIfAbsent(Pair.create(resourceRoot, resourceKind), (k) -> new ArrayList<>()).add(resource); } } - private static Path findCacheRootOnNativeImage() { + private static ResolvedCacheFolder findCacheRootOnNativeImage() { assert ImageInfo.inImageRuntimeCode() : "Can be called only in the native-image execution time."; Path executable = getExecutablePath(); - return executable.resolveSibling("resources"); + return new ResolvedCacheFolder(executable.resolveSibling("resources"), "executable location", executable); } private static Path getExecutablePath() { @@ -252,16 +263,16 @@ private static Path getExecutablePath() { } } - private static Path findCacheRootOnHotSpot() { + private static ResolvedCacheFolder findCacheRootOnHotSpot() { String userHomeValue = System.getProperty("user.home"); if (userHomeValue == null) { throw CompilerDirectives.shouldNotReachHere("The 'user.home' system property is not set."); } Path userHome = Paths.get(userHomeValue); - Path container = switch (InternalResource.OS.getCurrent()) { - case DARWIN -> userHome.resolve(Path.of("Library", "Caches")); + ResolvedCacheFolder container = switch (InternalResource.OS.getCurrent()) { + case DARWIN -> new ResolvedCacheFolder(userHome.resolve(Path.of("Library", "Caches")), "user home", userHome); case LINUX -> { - Path userCacheDir = null; + ResolvedCacheFolder userCacheDir = null; String xdgCacheValue = System.getenv("XDG_CACHE_HOME"); if (xdgCacheValue != null) { try { @@ -269,7 +280,7 @@ private static Path findCacheRootOnHotSpot() { // Do not fail when XDG_CACHE_HOME value is invalid. Fall back to // $HOME/.cache. if (xdgCacheDir.isAbsolute()) { - userCacheDir = xdgCacheDir; + userCacheDir = new ResolvedCacheFolder(xdgCacheDir, "XDG_CACHE_HOME env variable", xdgCacheDir); } else { emitWarning("The value of the environment variable 'XDG_CACHE_HOME' is not an absolute path. Using the default cache folder '%s'.", userHome.resolve(".cache")); } @@ -278,15 +289,30 @@ private static Path findCacheRootOnHotSpot() { } } if (userCacheDir == null) { - userCacheDir = userHome.resolve(".cache"); + userCacheDir = new ResolvedCacheFolder(userHome.resolve(".cache"), "user home", userHome); } yield userCacheDir; } - case WINDOWS -> userHome.resolve(Path.of("AppData", "Local")); + case WINDOWS -> new ResolvedCacheFolder(userHome.resolve(Path.of("AppData", "Local")), "user home", userHome); }; return container.resolve("org.graalvm.polyglot"); } + static boolean isTraceInternalResourceEvents() { + /* + * Internal resources are utilized before the Engine is created; hence, we cannot leverage + * engine options and engine logger. + */ + return Boolean.getBoolean("polyglotimpl.TraceInternalResources"); + } + + static void logInternalResourceEvent(String message, Object... args) { + if (isTraceInternalResourceEvents()) { + PrintStream out = System.err; + out.printf("[engine][resource] " + message + "%n", args); + } + } + private static void emitWarning(String message, Object... args) { PrintStream out = System.err; out.printf(message + "%n", args); @@ -301,4 +327,11 @@ enum Kind { VERSIONED, } } + + private record ResolvedCacheFolder(Path path, String hint, Path hintValue) { + + ResolvedCacheFolder resolve(String file) { + return new ResolvedCacheFolder(path.resolve(file), hint, hintValue); + } + } } From 9867608b0eb11ef8fc7e6b5ddc6c273b40ff7c92 Mon Sep 17 00:00:00 2001 From: Christian Humer Date: Tue, 12 Dec 2023 16:30:30 +0000 Subject: [PATCH 183/593] [GR-50682] Resolved review comments. --- sdk/CHANGELOG.md | 2 +- .../src/com/oracle/truffle/polyglot/EngineAccessor.java | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/sdk/CHANGELOG.md b/sdk/CHANGELOG.md index 71385af4d5aa..8c4922462a3b 100644 --- a/sdk/CHANGELOG.md +++ b/sdk/CHANGELOG.md @@ -8,7 +8,7 @@ This changelog summarizes major changes between GraalVM SDK versions. The main f * (GR-49386) Added the ability to use `Value#as(ByteSequence.class)` to map guest language byte buffers (`Value#hasBufferElements()`) to the read-only `ByteSequence` interface in order to access the bytes without copying the guest language buffer. * (GR-49386) Custom implementations of `ByteSequence`, like the values returned by `ByteSequence.create(byte[])`, are now interpreted by guest languages as buffers. * (GR-38404) Added the ability to use `Value#as(Collection.class)` to map guest language arrays (`Value#hasArrayElements()`) to the `Collection` interface in order to access the array elements without copying the guest language array. -* (GR-50682) For languages and instruments loading, the context classloader of the thread that initiates the Engine creation is employed. The system classloader is used only if the context classloader is not set. Originally both classloaders were used. +* (GR-50682) The Truffle languages and instrument implementations are now loaded exclusively using the context class loader if it is set and Truffle is found there. If the context class loader is not set or Truffle is not found, then the system class loader is used instead. Previously, the context and system class loader were used to load Truffle languages and instruments which causes issues if the context class loader does not delegate to the system class loader and classes are loaded from both. Context class loaders that do not delegate to the system class loader are commonly used to implement hot-reload functionality. ## Version 23.1.0 diff --git a/truffle/src/com.oracle.truffle.polyglot/src/com/oracle/truffle/polyglot/EngineAccessor.java b/truffle/src/com.oracle.truffle.polyglot/src/com/oracle/truffle/polyglot/EngineAccessor.java index f985b9ddf89a..9ec3721901a6 100644 --- a/truffle/src/com.oracle.truffle.polyglot/src/com/oracle/truffle/polyglot/EngineAccessor.java +++ b/truffle/src/com.oracle.truffle.polyglot/src/com/oracle/truffle/polyglot/EngineAccessor.java @@ -174,7 +174,7 @@ private static List locatorLoaders() { return suppliers; } - private static AbstractClassLoaderSupplier defaultLoaders() { + private static AbstractClassLoaderSupplier defaultLoader() { ClassLoader contextClassLoader = Thread.currentThread().getContextClassLoader(); ClassLoader systemClassLoader = ClassLoader.getSystemClassLoader(); if (contextClassLoader != null && isValidLoader(contextClassLoader)) { @@ -208,7 +208,7 @@ private static boolean isValidLoader(ClassLoader loader) { static List locatorOrDefaultLoaders() { List loaders = locatorLoaders(); if (loaders == null) { - loaders = List.of(defaultLoaders()); + loaders = List.of(defaultLoader()); } return loaders; } From e06de2f06e0187f0405de39ff0fb1b72998440e0 Mon Sep 17 00:00:00 2001 From: Josef Eisl Date: Wed, 13 Dec 2023 13:33:42 +0100 Subject: [PATCH 184/593] ci/galahad: do not run deploy/post-merge jobs --- ci/ci_common/galahad-common.libsonnet | 26 ++++++++++++++++---------- 1 file changed, 16 insertions(+), 10 deletions(-) diff --git a/ci/ci_common/galahad-common.libsonnet b/ci/ci_common/galahad-common.libsonnet index 81b06f7c4634..690856049007 100644 --- a/ci/ci_common/galahad-common.libsonnet +++ b/ci/ci_common/galahad-common.libsonnet @@ -5,10 +5,18 @@ local galahad_jdk = common_json.jdks["galahad-jdk"]; local utils = import "common-utils.libsonnet"; { local GALAHAD_PROPERTY = "_galahad_include", + local arrContains(arr, needle) = + std.find(needle, arr) != [] + , # Return true if this is a gate job. local is_gate(b) = std.find("gate", b.targets) != [] , + local gate_or_postmerge_targets = ["gate", "post-merge", "deploy"], + # Return true if this is a gate or post-merge/deployment job. + local is_gate_or_postmerge(b) = + std.setInter(gate_or_postmerge_targets, b.targets) != [] + , local finalize(b) = std.parseJson(std.manifestJson(b)), # Converts a gate job into an ondemand job. local convert_gate_to_ondemand(jsonnetBuildObject) = @@ -28,10 +36,13 @@ local utils = import "common-utils.libsonnet"; else {} ; - assert is_gate(b) : "Not a gate job: " + b.name; + assert is_gate_or_postmerge(b) : "Not a gate or postmerge job: " + b.name; b + { - name: std.strReplace(b.name, "gate", "ondemand"), - targets: [if t == "gate" then "ondemand" else t for t in b.targets], + name: "non-galahad-" + b.name, + # replace gate or postmerge targets with ondemand + targets: std.set(std.setDiff(b.targets, gate_or_postmerge_targets) + ["ondemand"]), + # remove runAfter + runAfter: [], } , # Replaces labsjdk-ce-latest and labsjdk-ee-latest with galahad-jdk @@ -51,7 +62,7 @@ local utils = import "common-utils.libsonnet"; # This is preferred over removing irrelevant jobs because it does not introduce problems # with respect to dependent jobs (artifacts). local transform_galahad_job(b) = - if !is_gate(b) then + if !is_gate_or_postmerge(b) then b else local include = std.foldr(function(x, y) x && y, utils.std_get(b, GALAHAD_PROPERTY, [false]), true); @@ -63,7 +74,7 @@ local utils = import "common-utils.libsonnet"; , # Verify that a job really makes sense for galahad local verify_galahad_job(b) = - if !is_gate(b) then + if !is_gate_or_postmerge(b) then # we only care about gate jobs b else @@ -87,11 +98,6 @@ local utils = import "common-utils.libsonnet"; ####### Public API - # Return true if this is a gate job. - is_gate(b):: is_gate(b), - # Converts a gate job into an ondemand job. - convert_gate_to_ondemand(b):: convert_gate_to_ondemand(b), - # Include a jobs in the galahad gate include:: { # There seems to be a problem with sjsonnet when merging boolean fields. From 2fcdee4f21e1d15682cb29ba683c0ca14cf9afac Mon Sep 17 00:00:00 2001 From: Andrej Pecimuth Date: Wed, 13 Dec 2023 14:05:34 +0100 Subject: [PATCH 185/593] Emit the optimization log in compiler tests after compilation or graph equality check. --- .../compiler/core/test/GraalCompilerTest.java | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/core/test/GraalCompilerTest.java b/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/core/test/GraalCompilerTest.java index 893dc76a7de7..fa410ecc3d87 100644 --- a/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/core/test/GraalCompilerTest.java +++ b/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/core/test/GraalCompilerTest.java @@ -79,6 +79,7 @@ import jdk.graal.compiler.hotspot.HotSpotGraphBuilderPhase; import jdk.graal.compiler.java.BytecodeParser; import jdk.graal.compiler.java.GraphBuilderPhase; +import jdk.graal.compiler.java.StableMethodNameFormatter; import jdk.graal.compiler.lir.asm.CompilationResultBuilderFactory; import jdk.graal.compiler.lir.phases.LIRSuites; import jdk.graal.compiler.loop.phases.ConvertDeoptimizeToGuardPhase; @@ -486,6 +487,11 @@ protected void assertEquals(StructuredGraph expected, StructuredGraph actual, bo } /** + * Asserts that two graphs are equal. + *

    + * If the {@link jdk.graal.compiler.nodes.OptimizationLog} is enabled, the logs of the "actual" + * graph are emitted. + * * @param addGaphsToDebugContext if true, a scope is opened that contains {@code expected} and * {@code actual} in its context so that these graphs are dumped when the comparison * fails and {@code DumpOnError=true} @@ -496,12 +502,14 @@ protected void assertEquals(StructuredGraph expected, boolean excludeVirtual, boolean checkConstants, boolean addGaphsToDebugContext) { + DebugContext debug = actual.getDebug(); + actual.getOptimizationLog().emit(new StableMethodNameFormatter(getProviders(), debug)); + String expectedString = getCanonicalGraphString(expected, excludeVirtual, checkConstants); String actualString = getCanonicalGraphString(actual, excludeVirtual, checkConstants); String mismatchString = compareGraphStrings(expected, expectedString, actual, actualString); // Open a scope so that `expected` and `actual` are dumped if DumpOnError=true - DebugContext debug = actual.getDebug(); try (DebugContext.Scope scope = addGaphsToDebugContext ? debug.scope("GraphEqualsTest", expected, actual) : null) { if (!excludeVirtual && getNodeCountExcludingUnusedConstants(expected) != getNodeCountExcludingUnusedConstants(actual)) { debug.dump(DebugContext.BASIC_LEVEL, expected, "Node count not matching - expected"); @@ -1229,6 +1237,9 @@ protected final CompilationResult compile(ResolvedJavaMethod installedCodeOwner, /** * Compiles a given method. + *

    + * Emits the {@link jdk.graal.compiler.nodes.OptimizationLog} of the compilation if the log is + * enabled. * * @param installedCodeOwner the method the compiled code will be associated with when installed * @param graph the graph to be compiled for {@code installedCodeOwner}. If null, a graph will @@ -1251,7 +1262,9 @@ protected CompilationResult compile(ResolvedJavaMethod installedCodeOwner, Struc Request request = new Request<>(graphToCompile, installedCodeOwner, getProviders(), getBackend(), getDefaultGraphBuilderSuite(), getOptimisticOptimizations(), graphToCompile.getProfilingInfo(), suites, createLIRSuites(options), compilationResult, CompilationResultBuilderFactory.Default, null, true); - return GraalCompiler.compile(request); + CompilationResult result = GraalCompiler.compile(request); + graphToCompile.getOptimizationLog().emit(new StableMethodNameFormatter(getProviders(), graphToCompile.getDebug())); + return result; } catch (Throwable e) { throw debug.handle(e); } From b5dd3ef48d7d4e26a99cb115be7dd2f322603533 Mon Sep 17 00:00:00 2001 From: Josef Eisl Date: Wed, 13 Dec 2023 14:09:11 +0100 Subject: [PATCH 186/593] ci: update galahad-jdk to 22+27 --- common.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/common.json b/common.json index e9b51bd96972..a7aecbe0dd0a 100644 --- a/common.json +++ b/common.json @@ -8,7 +8,7 @@ "COMMENT.jdks": "When adding or removing JDKs keep in sync with JDKs in ci/common.jsonnet", "jdks": { - "galahad-jdk": {"name": "jpg-jdk", "version": "22", "build_id": "jdk-22+25", "platformspecific": true, "extrabundles": ["static-libs"]}, + "galahad-jdk": {"name": "jpg-jdk", "version": "22", "build_id": "jdk-22+27", "platformspecific": true, "extrabundles": ["static-libs"]}, "oraclejdk11": {"name": "jpg-jdk", "version": "11.0.11", "build_id": "9", "release": true, "platformspecific": true, "extrabundles": ["static-libs"] }, From 737641af61e1aabeb93584da4700d1a465e43dac Mon Sep 17 00:00:00 2001 From: Vojtech Horky Date: Wed, 13 Dec 2023 14:11:05 +0100 Subject: [PATCH 187/593] Bump overlay revision (GR-50139) --- graal-common.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/graal-common.json b/graal-common.json index 955938b47ed6..4a13a395c72c 100644 --- a/graal-common.json +++ b/graal-common.json @@ -1,6 +1,6 @@ { "README": "This file contains definitions that are useful for the jsonnet CI files of the graal and graal-enterprise repositories.", "ci": { - "overlay": "8a3ad79620a470a48e5b23ecc47a212c8b32da7f" + "overlay": "2dd50c6b85991f42f6e20f05bf33da84b1e1610c" } } From 4d226e47afd32cebe3cff2cfb52f3ff97f429d4a Mon Sep 17 00:00:00 2001 From: Andrej Pecimuth Date: Wed, 13 Dec 2023 15:09:23 +0100 Subject: [PATCH 188/593] Calculate file offsets in profdiff based on character encodings. --- .../src/org/graalvm/profdiff/parser/FileView.java | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/compiler/src/org.graalvm.profdiff/src/org/graalvm/profdiff/parser/FileView.java b/compiler/src/org.graalvm.profdiff/src/org/graalvm/profdiff/parser/FileView.java index 83ab551079c1..bf19ba8b950c 100644 --- a/compiler/src/org.graalvm.profdiff/src/org/graalvm/profdiff/parser/FileView.java +++ b/compiler/src/org.graalvm.profdiff/src/org/graalvm/profdiff/parser/FileView.java @@ -24,6 +24,8 @@ */ package org.graalvm.profdiff.parser; +import jdk.graal.compiler.nodes.OptimizationLogImpl; + import java.io.BufferedReader; import java.io.File; import java.io.FileInputStream; @@ -31,6 +33,7 @@ import java.io.IOException; import java.io.InputStreamReader; import java.nio.channels.FileChannel; +import java.nio.charset.Charset; import java.util.function.BiConsumer; /** @@ -52,15 +55,14 @@ public String getSymbolicPath() { @Override public void forEachLine(BiConsumer consumer) throws IOException { - try (FileInputStream inputStream = new FileInputStream(file); - InputStreamReader streamReader = new InputStreamReader(inputStream); - BufferedReader bufferedReader = new BufferedReader(streamReader)) { + long lineSeparatorLength = String.valueOf(OptimizationLogImpl.LINE_SEPARATOR).getBytes(Charset.defaultCharset()).length; + try (FileReader fileReader = new FileReader(file); + BufferedReader bufferedReader = new BufferedReader(fileReader)) { long position = 0; String line; while ((line = bufferedReader.readLine()) != null) { long lineStartPosition = position; - // assume that line separators are '\n' on all platforms - position += line.length() + 1; + position += line.getBytes(Charset.defaultCharset()).length + lineSeparatorLength; consumer.accept(line, FileView.fromFileLineAtPosition(file, lineStartPosition)); } } @@ -93,7 +95,7 @@ private static FileView fromFileLineAtPosition(File file, long linePosition) { return new FileView() { @Override public String getSymbolicPath() { - return file.getAbsolutePath(); + return file.getAbsolutePath() + "@ offset " + linePosition; } @Override From 765f06233604fd10679b03ed6172cef780b1c565 Mon Sep 17 00:00:00 2001 From: Petar Dekanovic Date: Wed, 13 Dec 2023 15:58:08 +0100 Subject: [PATCH 189/593] Create additional artifacts only on successful build. --- .../hosted/NativeImageGeneratorRunner.java | 6 ++--- .../oracle/svm/hosted/ProgressReporter.java | 22 +++++++++++-------- .../svm/hosted/ProgressReporterFeature.java | 2 +- 3 files changed, 17 insertions(+), 13 deletions(-) diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/NativeImageGeneratorRunner.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/NativeImageGeneratorRunner.java index 6e17b1d78ff6..5622371ac0c6 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/NativeImageGeneratorRunner.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/NativeImageGeneratorRunner.java @@ -572,15 +572,15 @@ private int buildImage(ImageClassLoader classLoader) { vmError = e; return ExitStatus.BUILDER_ERROR.getValue(); } finally { - reportEpilog(imageName, reporter, classLoader, vmError, parsedHostedOptions); + reportEpilog(imageName, reporter, classLoader, wasSuccessfulBuild, vmError, parsedHostedOptions); NativeImageGenerator.clearSystemPropertiesForImage(); ImageSingletonsSupportImpl.HostedManagement.clear(); } return ExitStatus.OK.getValue(); } - protected void reportEpilog(String imageName, ProgressReporter reporter, ImageClassLoader classLoader, Throwable vmError, OptionValues parsedHostedOptions) { - reporter.printEpilog(Optional.ofNullable(imageName), Optional.ofNullable(generator), classLoader, Optional.ofNullable(vmError), parsedHostedOptions); + protected void reportEpilog(String imageName, ProgressReporter reporter, ImageClassLoader classLoader, boolean wasSuccessfulBuild, Throwable vmError, OptionValues parsedHostedOptions) { + reporter.printEpilog(Optional.ofNullable(imageName), Optional.ofNullable(generator), classLoader, wasSuccessfulBuild, Optional.ofNullable(vmError), parsedHostedOptions); } protected NativeImageGenerator createImageGenerator(ImageClassLoader classLoader, HostedOptionParser optionParser, Pair mainEntryPointData, ProgressReporter reporter) { diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/ProgressReporter.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/ProgressReporter.java index 8afa083a69d8..acad1a7a38dc 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/ProgressReporter.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/ProgressReporter.java @@ -685,8 +685,8 @@ private void printRecommendations() { } } - public void printEpilog(Optional optionalImageName, Optional optionalGenerator, ImageClassLoader classLoader, Optional optionalError, - OptionValues parsedHostedOptions) { + public void printEpilog(Optional optionalImageName, Optional optionalGenerator, ImageClassLoader classLoader, boolean wasSuccessfulBuild, + Optional optionalError, OptionValues parsedHostedOptions) { executor.shutdown(); if (optionalError.isPresent()) { @@ -712,7 +712,7 @@ public void printEpilog(Optional optionalImageName, Optional optionalError, OptionValues p } } - private void createAdditionalArtifacts(String imageName, NativeImageGenerator generator, Optional error, OptionValues parsedHostedOptions) { + private void createAdditionalArtifacts(String imageName, NativeImageGenerator generator, boolean wasSuccessfulBuild, OptionValues parsedHostedOptions) { BuildArtifacts artifacts = BuildArtifacts.singleton(); + if (wasSuccessfulBuild) { + createAdditionalArtifactsOnSuccess(artifacts, generator, parsedHostedOptions); + } + BuildArtifactsExporter.run(imageName, artifacts, generator.getBuildArtifacts()); + } + + private void createAdditionalArtifactsOnSuccess(BuildArtifacts artifacts, NativeImageGenerator generator, OptionValues parsedHostedOptions) { Optional buildOutputJSONFile = SubstrateOptions.BuildOutputJSONFile.getValue(parsedHostedOptions).lastValue(); - if (error.isEmpty() && buildOutputJSONFile.isPresent()) { + if (buildOutputJSONFile.isPresent()) { artifacts.add(ArtifactType.BUILD_INFO, reportBuildOutput(buildOutputJSONFile.get())); } if (generator.getBigbang() != null && ImageBuildStatistics.Options.CollectImageBuildStatistics.getValue(parsedHostedOptions)) { artifacts.add(ArtifactType.BUILD_INFO, reportImageBuildStatistics()); } - if (error.isEmpty()) { - ImageSingletons.lookup(ProgressReporterFeature.class).createAdditionalArtifacts(artifacts); - } - BuildArtifactsExporter.run(imageName, artifacts, generator.getBuildArtifacts()); + ImageSingletons.lookup(ProgressReporterFeature.class).createAdditionalArtifactsOnSuccess(artifacts); } private void printArtifacts(Map> artifacts) { diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/ProgressReporterFeature.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/ProgressReporterFeature.java index a8b3a53d5035..66e44e88b66a 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/ProgressReporterFeature.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/ProgressReporterFeature.java @@ -86,7 +86,7 @@ public void afterBreakdowns() { } } - public void createAdditionalArtifacts(@SuppressWarnings("unused") BuildArtifacts artifacts) { + public void createAdditionalArtifactsOnSuccess(@SuppressWarnings("unused") BuildArtifacts artifacts) { } protected List getRecommendations() { From 23253d88fb395e2ae59570679d80dc916acb742c Mon Sep 17 00:00:00 2001 From: Loic Ottet Date: Mon, 30 Oct 2023 13:45:03 +0100 Subject: [PATCH 190/593] Rethrow reflection linkage errors at run-time --- substratevm/CHANGELOG.md | 1 + .../target/ReflectionMetadataDecoderImpl.java | 5 +- .../hosted/image/NativeImageCodeCache.java | 28 +++++++++ .../hosted/reflect/ReflectionDataBuilder.java | 42 +++++++++++--- .../reflect/ReflectionHostedSupport.java | 8 +++ .../ReflectionMetadataEncoderImpl.java | 58 ++++++++++++++++--- 6 files changed, 124 insertions(+), 18 deletions(-) diff --git a/substratevm/CHANGELOG.md b/substratevm/CHANGELOG.md index 6eda86468f0e..9542ed34d5be 100644 --- a/substratevm/CHANGELOG.md +++ b/substratevm/CHANGELOG.md @@ -17,6 +17,7 @@ This changelog summarizes major changes to GraalVM Native Image. * (GR-49807) Before this change the function `System#setSecurityManager` was always halting program execution with a VM error. This was inconvenient as the VM error prints an uncomprehensible error message and prevents further continuation of the program. For cases where the program is expected to throw an exception when `System#setSecurityManager` is called, execution on Native Image was not possible. Now, `System#setSecurityManager` throws an `java.lang.UnsupportedOperationException` by default. If the property `java.security.manager` is set to anything but `disallow` at program startup this function will throw a `java.lang.SecurityException` according to the Java spec. * (GR-30433) Disallow the deprecated environment variable USE_NATIVE_IMAGE_JAVA_PLATFORM_MODULE_SYSTEM=false. * (GR-49655) Experimental support for parts of the [Foreign Function & Memory API](https://github.com/oracle/graal/blob/master/docs/reference-manual/native-image/ForeignInterface.md) (part of "Project Panama", [JEP 454](https://openjdk.org/jeps/454)) on AMD64. Must be enabled with `-H:+ForeignAPISupport` (requiring `-H:+UnlockExperimentalVMOptions`). +* (GR-46407) Correctly rethrow build-time linkage errors at run-time for registered reflection queries. ## GraalVM for JDK 21 (Internal Version 23.1.0) * (GR-35746) Lower the default aligned chunk size from 1 MB to 512 KB for the serial and epsilon GCs, reducing memory usage and image size in many cases. diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/reflect/target/ReflectionMetadataDecoderImpl.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/reflect/target/ReflectionMetadataDecoderImpl.java index fb0b1143841c..11ec3d6795b0 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/reflect/target/ReflectionMetadataDecoderImpl.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/reflect/target/ReflectionMetadataDecoderImpl.java @@ -684,7 +684,10 @@ private static Object decodeObject(UnsafeArrayTypeReader buf) { */ @SuppressWarnings("unchecked") private static T[] decodeArray(UnsafeArrayTypeReader buf, Class elementType, Function elementDecoder) { - int length = buf.getUVInt(); + int length = buf.getSVInt(); + if (isErrorIndex(length)) { + decodeAndThrowError(length); + } T[] result = (T[]) Array.newInstance(elementType, length); int valueCount = 0; for (int i = 0; i < length; ++i) { diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/NativeImageCodeCache.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/NativeImageCodeCache.java index 73575d220ac7..90c5ddf576c6 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/NativeImageCodeCache.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/NativeImageCodeCache.java @@ -331,6 +331,26 @@ protected void buildRuntimeMetadata(DebugContext debug, SnippetReflectionProvide } } + reflectionSupport.getClassLookupErrors().forEach((clazz, error) -> { + HostedType type = hMetaAccess.lookupJavaType(clazz); + reflectionMetadataEncoder.addClassLookupError(type, error); + }); + + reflectionSupport.getFieldLookupErrors().forEach((clazz, error) -> { + HostedType type = hMetaAccess.lookupJavaType(clazz); + reflectionMetadataEncoder.addFieldLookupError(type, error); + }); + + reflectionSupport.getMethodLookupErrors().forEach((clazz, error) -> { + HostedType type = hMetaAccess.lookupJavaType(clazz); + reflectionMetadataEncoder.addMethodLookupError(type, error); + }); + + reflectionSupport.getConstructorLookupErrors().forEach((clazz, error) -> { + HostedType type = hMetaAccess.lookupJavaType(clazz); + reflectionMetadataEncoder.addConstructorLookupError(type, error); + }); + Set includedFields = new HashSet<>(); Set includedMethods = new HashSet<>(); Map configurationFields = reflectionSupport.getReflectionFields(); @@ -768,6 +788,14 @@ public interface ReflectionMetadataEncoder extends EncodedReflectionMetadataSupp void addNegativeConstructorQueryMetadata(HostedType declaringClass, HostedType[] parameterTypes); + void addClassLookupError(HostedType declaringClass, Throwable exception); + + void addFieldLookupError(HostedType declaringClass, Throwable exception); + + void addMethodLookupError(HostedType declaringClass, Throwable exception); + + void addConstructorLookupError(HostedType declaringClass, Throwable exception); + void encodeAllAndInstall(); Method getRoot = ReflectionUtil.lookupMethod(AccessibleObject.class, "getRoot"); diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/reflect/ReflectionDataBuilder.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/reflect/ReflectionDataBuilder.java index 4eefd9dff3f4..5577a361dfa5 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/reflect/ReflectionDataBuilder.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/reflect/ReflectionDataBuilder.java @@ -130,6 +130,12 @@ public class ReflectionDataBuilder extends ConditionalConfigurationRegistry impl private final Map> negativeMethodLookups = new ConcurrentHashMap<>(); private final Map> negativeConstructorLookups = new ConcurrentHashMap<>(); + // Linkage error handling + private final Map, Throwable> classLookupExceptions = new ConcurrentHashMap<>(); + private final Map, Throwable> fieldLookupExceptions = new ConcurrentHashMap<>(); + private final Map, Throwable> methodLookupExceptions = new ConcurrentHashMap<>(); + private final Map, Throwable> constructorLookupExceptions = new ConcurrentHashMap<>(); + // Intermediate bookkeeping private final Map> processedTypes = new ConcurrentHashMap<>(); private final Map, Set> pendingRecordClasses; @@ -189,7 +195,7 @@ public void registerAllClassesQuery(ConfigurationCondition condition, Class c registerClass(innerClass, false, !MissingRegistrationUtils.throwMissingRegistrationErrors()); } } catch (LinkageError e) { - /* Ignore the error */ + classLookupExceptions.put(clazz, e); } } @@ -203,7 +209,7 @@ public void registerAllDeclaredClassesQuery(ConfigurationCondition condition, Cl registerClass(innerClass, false, !MissingRegistrationUtils.throwMissingRegistrationErrors()); } } catch (LinkageError e) { - /* Ignore the error */ + classLookupExceptions.put(clazz, e); } } @@ -326,7 +332,7 @@ public void registerAllMethodsQuery(ConfigurationCondition condition, boolean qu try { register(condition, queriedOnly, clazz.getMethods()); } catch (LinkageError e) { - /* Ignore the error */ + methodLookupExceptions.put(clazz, e); } } @@ -337,7 +343,7 @@ public void registerAllDeclaredMethodsQuery(ConfigurationCondition condition, bo try { register(condition, queriedOnly, clazz.getDeclaredMethods()); } catch (LinkageError e) { - /* Ignore the error */ + methodLookupExceptions.put(clazz, e); } } @@ -351,7 +357,7 @@ public void registerAllConstructorsQuery(ConfigurationCondition condition, boole try { register(condition, queriedOnly, clazz.getConstructors()); } catch (LinkageError e) { - /* Ignore the error */ + constructorLookupExceptions.put(clazz, e); } } @@ -362,7 +368,7 @@ public void registerAllDeclaredConstructorsQuery(ConfigurationCondition conditio try { register(condition, queriedOnly, clazz.getDeclaredConstructors()); } catch (LinkageError e) { - /* Ignore the error */ + constructorLookupExceptions.put(clazz, e); } } @@ -459,7 +465,7 @@ public void registerAllFieldsQuery(ConfigurationCondition condition, Class cl try { registerInternal(condition, clazz.getFields()); } catch (LinkageError e) { - /* Ignore the error */ + fieldLookupExceptions.put(clazz, e); } } @@ -470,7 +476,7 @@ public void registerAllDeclaredFieldsQuery(ConfigurationCondition condition, Cla try { registerInternal(condition, clazz.getDeclaredFields()); } catch (LinkageError e) { - /* Ignore the error */ + fieldLookupExceptions.put(clazz, e); } } @@ -1072,6 +1078,26 @@ public Map> getNegativeConstructorQueries() { return Collections.unmodifiableMap(negativeConstructorLookups); } + @Override + public Map, Throwable> getClassLookupErrors() { + return Collections.unmodifiableMap(classLookupExceptions); + } + + @Override + public Map, Throwable> getFieldLookupErrors() { + return Collections.unmodifiableMap(fieldLookupExceptions); + } + + @Override + public Map, Throwable> getMethodLookupErrors() { + return Collections.unmodifiableMap(methodLookupExceptions); + } + + @Override + public Map, Throwable> getConstructorLookupErrors() { + return Collections.unmodifiableMap(constructorLookupExceptions); + } + private static final AnnotationValue[] NO_ANNOTATIONS = new AnnotationValue[0]; public AnnotationValue[] getAnnotationData(AnnotatedElement element) { diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/reflect/ReflectionHostedSupport.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/reflect/ReflectionHostedSupport.java index 3c177c0d4c83..95181691bc20 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/reflect/ReflectionHostedSupport.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/reflect/ReflectionHostedSupport.java @@ -76,6 +76,14 @@ public interface ReflectionHostedSupport { Map> getNegativeConstructorQueries(); + Map, Throwable> getClassLookupErrors(); + + Map, Throwable> getFieldLookupErrors(); + + Map, Throwable> getMethodLookupErrors(); + + Map, Throwable> getConstructorLookupErrors(); + int getReflectionMethodsCount(); int getReflectionFieldsCount(); diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/reflect/ReflectionMetadataEncoderImpl.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/reflect/ReflectionMetadataEncoderImpl.java index 91366490cf79..6c12807fd529 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/reflect/ReflectionMetadataEncoderImpl.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/reflect/ReflectionMetadataEncoderImpl.java @@ -148,6 +148,11 @@ public ReflectionMetadataEncoder create(SnippetReflectionProvider snippetReflect private final Map> methodData = new HashMap<>(); private final Map> constructorData = new HashMap<>(); + private final Map classLookupErrors = new HashMap<>(); + private final Map fieldLookupErrors = new HashMap<>(); + private final Map methodLookupErrors = new HashMap<>(); + private final Map constructorLookupErrors = new HashMap<>(); + private final Set heapData = new HashSet<>(); private final Map annotationsEncodings = new HashMap<>(); @@ -633,6 +638,34 @@ public void addNegativeConstructorQueryMetadata(HostedType declaringClass, Hoste registerConstructor(declaringClass, parameterTypes, new ConstructorMetadata(declaringClass, parameterTypes)); } + @Override + public void addClassLookupError(HostedType declaringClass, Throwable exception) { + addType(declaringClass); + registerError(exception); + classLookupErrors.put(declaringClass, exception); + } + + @Override + public void addFieldLookupError(HostedType declaringClass, Throwable exception) { + addType(declaringClass); + registerError(exception); + fieldLookupErrors.put(declaringClass, exception); + } + + @Override + public void addMethodLookupError(HostedType declaringClass, Throwable exception) { + addType(declaringClass); + registerError(exception); + methodLookupErrors.put(declaringClass, exception); + } + + @Override + public void addConstructorLookupError(HostedType declaringClass, Throwable exception) { + addType(declaringClass); + registerError(exception); + constructorLookupErrors.put(declaringClass, exception); + } + private static HostedType[] getParameterTypes(HostedMethod method) { HostedType[] parameterTypes = new HostedType[method.getSignature().getParameterCount(false)]; for (int i = 0; i < parameterTypes.length; ++i) { @@ -712,7 +745,7 @@ public void encodeAllAndInstall() { : addElement(buf, encodeEnclosingMethodInfo((Object[]) classMetadata.enclosingMethodInfo)); int annotationsIndex = addEncodedElement(buf, encodeAnnotations(classMetadata.annotations)); int typeAnnotationsIndex = addEncodedElement(buf, encodeTypeAnnotations(classMetadata.typeAnnotations)); - int classesEncodingIndex = encodeAndAddCollection(buf, classMetadata.classes, this::encodeType, false); + int classesEncodingIndex = encodeAndAddCollection(buf, classMetadata.classes, classLookupErrors.get(declaringType), this::encodeType, false); int permittedSubclassesIndex = encodeAndAddCollection(buf, classMetadata.permittedSubclasses, this::encodeType, true); int nestMembersEncodingIndex = encodeAndAddCollection(buf, classMetadata.nestMembers, this::encodeType, true); int signersEncodingIndex = encodeAndAddCollection(buf, classMetadata.signers, this::encodeObject, true); @@ -720,9 +753,9 @@ public void encodeAllAndInstall() { hub.setHubMetadata(enclosingMethodInfoIndex, annotationsIndex, typeAnnotationsIndex, classesEncodingIndex, permittedSubclassesIndex, nestMembersEncodingIndex, signersEncodingIndex); } - int fieldsIndex = encodeAndAddCollection(buf, getFields(declaringType), this::encodeField, false); - int methodsIndex = encodeAndAddCollection(buf, getMethods(declaringType), this::encodeExecutable, false); - int constructorsIndex = encodeAndAddCollection(buf, getConstructors(declaringType), this::encodeExecutable, false); + int fieldsIndex = encodeAndAddCollection(buf, getFields(declaringType), fieldLookupErrors.get(declaringType), this::encodeField, false); + int methodsIndex = encodeAndAddCollection(buf, getMethods(declaringType), methodLookupErrors.get(declaringType), this::encodeExecutable, false); + int constructorsIndex = encodeAndAddCollection(buf, getConstructors(declaringType), constructorLookupErrors.get(declaringType), this::encodeExecutable, false); int recordComponentsIndex = encodeAndAddCollection(buf, classMetadata.recordComponents, this::encodeRecordComponent, true); int classFlags = classMetadata.flags; if (anySet(fieldsIndex, methodsIndex, constructorsIndex, recordComponentsIndex) || classFlags != hub.getModifiers()) { @@ -755,16 +788,23 @@ private int encodeErrorIndex(Throwable error) { return encodedIndex; } - private static int encodeAndAddCollection(UnsafeArrayTypeWriter buf, T[] data, BiConsumer encodeCallback, boolean canBeNull) { - if (data == null || (!canBeNull && data.length == 0)) { + private int encodeAndAddCollection(UnsafeArrayTypeWriter buf, T[] data, BiConsumer encodeCallback, boolean canBeNull) { + return encodeAndAddCollection(buf, data, null, encodeCallback, canBeNull); + } + + private int encodeAndAddCollection(UnsafeArrayTypeWriter buf, T[] data, Throwable lookupError, BiConsumer encodeCallback, boolean canBeNull) { + int offset = TypeConversion.asS4(buf.getBytesWritten()); + if (lookupError != null) { + buf.putSV(encodeErrorIndex(lookupError)); + } else if (data == null || (!canBeNull && data.length == 0)) { /* * We must encode a zero-length array if it does not have the same meaning as a null * array (e.g. for permitted classes) */ return NO_DATA; + } else { + encodeArray(buf, data, element -> encodeCallback.accept(buf, element)); } - int offset = TypeConversion.asS4(buf.getBytesWritten()); - encodeArray(buf, data, element -> encodeCallback.accept(buf, element)); return offset; } @@ -889,7 +929,7 @@ private void encodeObject(UnsafeArrayTypeWriter buf, JavaConstant object) { } private static void encodeArray(UnsafeArrayTypeWriter buf, T[] array, Consumer elementEncoder) { - buf.putUV(array.length); + buf.putSV(array.length); for (T elem : array) { elementEncoder.accept(elem); } From 66a678a5aa12ed813d16a6cb2ea743216316a0cf Mon Sep 17 00:00:00 2001 From: ol-automation_ww Date: Wed, 13 Dec 2023 15:48:07 +0000 Subject: [PATCH 191/593] update to 23+1-jvmci-b01 --- common.json | 22 +++++++++++++------ .../compiler/hotspot/JVMCIVersionCheck.java | 6 ++++- 2 files changed, 20 insertions(+), 8 deletions(-) diff --git a/common.json b/common.json index cd0200f711d7..561adcf2abff 100644 --- a/common.json +++ b/common.json @@ -44,13 +44,21 @@ "labsjdk-ee-21Debug": {"name": "labsjdk", "version": "ee-21.0.1+11-jvmci-23.1-b26-debug", "platformspecific": true }, "labsjdk-ee-21-llvm": {"name": "labsjdk", "version": "ee-21.0.1+11-jvmci-23.1-b26-sulong", "platformspecific": true }, - "oraclejdk-latest": {"name": "jpg-jdk", "version": "22", "build_id": "27", "release": true, "platformspecific": true, "extrabundles": ["static-libs"]}, - "labsjdk-ce-latest": {"name": "labsjdk", "version": "ce-22+27-jvmci-b01", "platformspecific": true }, - "labsjdk-ce-latestDebug": {"name": "labsjdk", "version": "ce-22+27-jvmci-b01-debug", "platformspecific": true }, - "labsjdk-ce-latest-llvm": {"name": "labsjdk", "version": "ce-22+27-jvmci-b01-sulong", "platformspecific": true }, - "labsjdk-ee-latest": {"name": "labsjdk", "version": "ee-22+27-jvmci-b01", "platformspecific": true }, - "labsjdk-ee-latestDebug": {"name": "labsjdk", "version": "ee-22+27-jvmci-b01-debug", "platformspecific": true }, - "labsjdk-ee-latest-llvm": {"name": "labsjdk", "version": "ee-22+27-jvmci-b01-sulong", "platformspecific": true } + "oraclejdk22": {"name": "jpg-jdk", "version": "22", "build_id": "27", "release": true, "platformspecific": true, "extrabundles": ["static-libs"]}, + "labsjdk-ce-22": {"name": "labsjdk", "version": "ce-22+27-jvmci-b01", "platformspecific": true }, + "labsjdk-ce-22Debug": {"name": "labsjdk", "version": "ce-22+27-jvmci-b01-debug", "platformspecific": true }, + "labsjdk-ce-22-llvm": {"name": "labsjdk", "version": "ce-22+27-jvmci-b01-sulong", "platformspecific": true }, + "labsjdk-ee-22": {"name": "labsjdk", "version": "ee-22+27-jvmci-b01", "platformspecific": true }, + "labsjdk-ee-22Debug": {"name": "labsjdk", "version": "ee-22+27-jvmci-b01-debug", "platformspecific": true }, + "labsjdk-ee-22-llvm": {"name": "labsjdk", "version": "ee-22+27-jvmci-b01-sulong", "platformspecific": true }, + + "oraclejdk-latest": {"name": "jpg-jdk", "version": "23", "build_id": "1", "release": true, "platformspecific": true, "extrabundles": ["static-libs"]}, + "labsjdk-ce-latest": {"name": "labsjdk", "version": "ce-23+1-jvmci-b01-20231213123324-6bfc73c47c", "platformspecific": true }, + "labsjdk-ce-latestDebug": {"name": "labsjdk", "version": "ce-23+1-jvmci-b01-20231213123324-6bfc73c47c-debug", "platformspecific": true }, + "labsjdk-ce-latest-llvm": {"name": "labsjdk", "version": "ce-23+1-jvmci-b01-20231213123324-6bfc73c47c-sulong", "platformspecific": true }, + "labsjdk-ee-latest": {"name": "labsjdk", "version": "ee-23+1-jvmci-b01-20231213123324-6bfc73c47c+c0ce404a4b", "platformspecific": true }, + "labsjdk-ee-latestDebug": {"name": "labsjdk", "version": "ee-23+1-jvmci-b01-20231213123324-6bfc73c47c+c0ce404a4b-debug", "platformspecific": true }, + "labsjdk-ee-latest-llvm": {"name": "labsjdk", "version": "ee-23+1-jvmci-b01-20231213123324-6bfc73c47c+c0ce404a4b-sulong", "platformspecific": true } }, "eclipse": { diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/JVMCIVersionCheck.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/JVMCIVersionCheck.java index 0c0f071047e4..a69363869238 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/JVMCIVersionCheck.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/JVMCIVersionCheck.java @@ -55,7 +55,11 @@ public final class JVMCIVersionCheck { "21", Map.of(DEFAULT_VENDOR_ENTRY, new Version(23, 1, 26)), "22", Map.of( "Oracle Corporation", new Version("22+27", 1), - DEFAULT_VENDOR_ENTRY, new Version("22+27", 1))); + DEFAULT_VENDOR_ENTRY, new Version("22+27", 1)), + "23", Map.of( + "Oracle Corporation", new Version("23+1", 1), + DEFAULT_VENDOR_ENTRY, new Version("23+1", 1)) + ); private static final int NA = 0; /** * Minimum Java release supported by Graal. From 5fb40286b11c21bd11e020db99954ee529197c05 Mon Sep 17 00:00:00 2001 From: Christian Haeubl Date: Mon, 11 Dec 2023 17:28:14 +0100 Subject: [PATCH 192/593] Change code lifecycle. --- .../genscavenge/RuntimeCodeCacheWalker.java | 5 +-- .../RuntimeCodeInfoGCSupportImpl.java | 12 ------- .../svm/core/IsolateArgumentParser.java | 3 +- .../com/oracle/svm/core/code/CodeInfo.java | 19 +++++------ .../oracle/svm/core/code/CodeInfoAccess.java | 4 +-- .../oracle/svm/core/code/CodeInfoImpl.java | 11 +++--- .../oracle/svm/core/code/CodeInfoTable.java | 2 +- .../svm/core/code/RuntimeCodeCache.java | 19 ++++++----- .../svm/core/code/RuntimeCodeInfoAccess.java | 34 ++++++------------- .../svm/core/code/RuntimeCodeInfoMemory.java | 3 +- .../core/heap/RuntimeCodeCacheCleaner.java | 4 +-- .../core/heap/RuntimeCodeInfoGCSupport.java | 16 --------- 12 files changed, 48 insertions(+), 84 deletions(-) diff --git a/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/RuntimeCodeCacheWalker.java b/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/RuntimeCodeCacheWalker.java index fda60443dca2..848ee08019d2 100644 --- a/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/RuntimeCodeCacheWalker.java +++ b/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/RuntimeCodeCacheWalker.java @@ -24,7 +24,6 @@ */ package com.oracle.svm.core.genscavenge; -import jdk.graal.compiler.word.Word; import org.graalvm.nativeimage.Platform; import org.graalvm.nativeimage.Platforms; @@ -37,6 +36,8 @@ import com.oracle.svm.core.heap.ObjectReferenceVisitor; import com.oracle.svm.core.util.DuplicatedInNativeCode; +import jdk.graal.compiler.word.Word; + /** * References from the runtime compiled code to the Java heap must be considered either strong or * weak references, depending on whether the code is currently on the execution stack. Otherwise, @@ -75,7 +76,7 @@ public boolean visitCode(CodeInfo codeInfo) { Object tether = UntetheredCodeInfoAccess.getTetherUnsafe(codeInfo); if (tether != null && !isReachable(tether)) { int state = CodeInfoAccess.getState(codeInfo); - if (state == CodeInfo.STATE_PARTIALLY_FREED) { + if (state == CodeInfo.STATE_INVALIDATED) { /* * The tether object is not reachable and the CodeInfo was already invalidated, so * we only need to visit references that will be accessed before the unmanaged diff --git a/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/RuntimeCodeInfoGCSupportImpl.java b/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/RuntimeCodeInfoGCSupportImpl.java index a0f7c43b3d59..b3d37bc1d829 100644 --- a/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/RuntimeCodeInfoGCSupportImpl.java +++ b/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/RuntimeCodeInfoGCSupportImpl.java @@ -59,16 +59,4 @@ public void registerFrameMetadata(CodeInfo codeInfo) { public void registerDeoptMetadata(CodeInfo codeInfo) { // nothing to do (see above) } - - @Override - @Uninterruptible(reason = "Called when freeing code.", callerMustBe = true) - public void unregisterCodeConstants(CodeInfo codeInfo) { - // nothing to do (see above) - } - - @Override - @Uninterruptible(reason = "Called when freeing code.", callerMustBe = true) - public void unregisterRuntimeCodeInfo(CodeInfo codeInfo) { - // nothing to do (see above) - } } diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/IsolateArgumentParser.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/IsolateArgumentParser.java index 0440b8703d2b..598ae00f97e0 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/IsolateArgumentParser.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/IsolateArgumentParser.java @@ -28,7 +28,6 @@ import java.nio.ByteOrder; import java.nio.charset.StandardCharsets; -import jdk.graal.compiler.api.replacements.Fold; import org.graalvm.nativeimage.ImageSingletons; import org.graalvm.nativeimage.Platform; import org.graalvm.nativeimage.Platforms; @@ -48,6 +47,8 @@ import com.oracle.svm.core.option.RuntimeOptionKey; import com.oracle.svm.core.util.VMError; +import jdk.graal.compiler.api.replacements.Fold; + /** * Parses a small subset of the runtime arguments before the image heap is mapped and before the * isolate is fully started. diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/code/CodeInfo.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/code/CodeInfo.java index c7b4adb9f7ef..4094497c4893 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/code/CodeInfo.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/code/CodeInfo.java @@ -75,23 +75,22 @@ public interface CodeInfo extends UntetheredCodeInfo { int STATE_READY_FOR_INVALIDATION = STATE_NON_ENTRANT + 1; /** - * Indicates that this {@link CodeInfo} object was invalidated and parts of its data (including - * the code memory) were freed. The remaining data will be freed by the GC once the tether - * object becomes unreachable. Until then, the GC must continue visiting all heap references - * (except for the code constants as the code is no longer installed). + * Indicates that this {@link CodeInfo} object was invalidated. The data will be freed by the GC + * once the tether object becomes unreachable. Until then, the GC must continue visiting all + * heap references, including code constants that are directly embedded into the machine code. */ @DuplicatedInNativeCode // - int STATE_PARTIALLY_FREED = STATE_READY_FOR_INVALIDATION + 1; + int STATE_INVALIDATED = STATE_READY_FOR_INVALIDATION + 1; /** * This state is only a temporary state when the VM is at a safepoint. It indicates that a - * previously already partially freed {@link CodeInfo} object is no longer reachable from the GC - * point of view. The GC will free the {@link CodeInfo} object during the current safepoint. It - * is crucial that the GC still visits all heap references that may be accessed while freeing - * the {@link CodeInfo} object (i.e., all object fields). + * previously invalidated {@link CodeInfo} object is no longer reachable from the GC point of + * view. The GC will free the {@link CodeInfo} object during the current safepoint. It is + * crucial that the GC still visits all heap references that may be accessed while freeing the + * {@link CodeInfo} object (i.e., all object fields). */ @DuplicatedInNativeCode // - int STATE_UNREACHABLE = STATE_PARTIALLY_FREED + 1; + int STATE_UNREACHABLE = STATE_INVALIDATED + 1; /** * Indicates that the {@link CodeInfo} object was already freed. This state should never be diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/code/CodeInfoAccess.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/code/CodeInfoAccess.java index 0e391a5c34e9..bfb2d6194adb 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/code/CodeInfoAccess.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/code/CodeInfoAccess.java @@ -157,8 +157,8 @@ public static String stateToString(int codeInfoState) { return "non-entrant"; case CodeInfo.STATE_READY_FOR_INVALIDATION: return "ready for invalidation"; - case CodeInfo.STATE_PARTIALLY_FREED: - return "partially freed"; + case CodeInfo.STATE_INVALIDATED: + return "invalidated"; case CodeInfo.STATE_UNREACHABLE: return "unreachable"; case CodeInfo.STATE_FREED: diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/code/CodeInfoImpl.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/code/CodeInfoImpl.java index d3abe8b94d8d..67172d1f53ab 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/code/CodeInfoImpl.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/code/CodeInfoImpl.java @@ -24,7 +24,6 @@ */ package com.oracle.svm.core.code; -import jdk.graal.compiler.word.Word; import org.graalvm.nativeimage.c.function.CodePointer; import org.graalvm.nativeimage.c.struct.RawField; import org.graalvm.nativeimage.c.struct.RawFieldOffset; @@ -39,6 +38,7 @@ import com.oracle.svm.core.util.DuplicatedInNativeCode; import com.oracle.svm.core.util.VMError; +import jdk.graal.compiler.word.Word; import jdk.vm.ci.code.InstalledCode; /** @@ -49,9 +49,12 @@ * As {@link CodeInfo} objects have a complicated life-cycle that also involves the GC, it is * crucial that all places that access or use this data observe the following rules: *

      - *
    • When heap objects are stored into native-memory that is referenced by a {@link CodeInfo} - * object, then it is necessary to notify the GC about that (see - * {@link RuntimeCodeInfoGCSupport}).
    • + *
    • {@link CodeInfo} objects use native memory and store references to Java heap objects in that + * native-memory. The VM must notify the GC about all Java heap references (see + * {@link RuntimeCodeInfoGCSupport}) so that the GC can update the references when it moves objects. + * Once the VM notified the GC about a Java heap reference in native memory, the VM must no longer + * overwrite, null-out, or free that memory (only the GC is allowed to do that during code unloading + * at a safepoint).
    • *
    • NEVER do a direct cast from {@link UntetheredCodeInfo} or {@link CodeInfo} to * {@link CodeInfoImpl}. For more details, refer to the {@link CodeInfoAccess} documentation.
    • *
    diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/code/CodeInfoTable.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/code/CodeInfoTable.java index 87b821c755d9..4328ae0ace38 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/code/CodeInfoTable.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/code/CodeInfoTable.java @@ -217,7 +217,7 @@ private static void invalidateInstalledCodeAtSafepoint(SubstrateInstalledCode in if (CodeInfoAccess.isAlive(info)) { invalidateCodeAtSafepoint0(info); } - assert CodeInfoAccess.getState(info) == CodeInfo.STATE_PARTIALLY_FREED; + assert CodeInfoAccess.getState(info) == CodeInfo.STATE_INVALIDATED; } finally { CodeInfoAccess.releaseTether(untetheredInfo, tether); } diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/code/RuntimeCodeCache.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/code/RuntimeCodeCache.java index ab304e8edca8..20bfca0c158a 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/code/RuntimeCodeCache.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/code/RuntimeCodeCache.java @@ -28,9 +28,6 @@ import static com.oracle.svm.core.snippets.KnownIntrinsics.readCallerStackPointer; import org.graalvm.collections.EconomicMap; -import jdk.graal.compiler.options.Option; -import jdk.graal.compiler.options.OptionKey; -import jdk.graal.compiler.options.OptionType; import org.graalvm.nativeimage.CurrentIsolate; import org.graalvm.nativeimage.IsolateThread; import org.graalvm.nativeimage.Platform; @@ -57,6 +54,10 @@ import com.oracle.svm.core.thread.VMThreads; import com.oracle.svm.core.util.Counter; +import jdk.graal.compiler.options.Option; +import jdk.graal.compiler.options.OptionKey; +import jdk.graal.compiler.options.OptionType; + public class RuntimeCodeCache { public static class Options { @@ -210,14 +211,14 @@ protected void invalidateMethod(CodeInfo info) { */ Deoptimizer.deoptimizeInRange(CodeInfoAccess.getCodeStart(info), CodeInfoAccess.getCodeEnd(info), false); - finishInvalidation(info, true); + finishInvalidation(info); } protected void invalidateNonStackMethod(CodeInfo info) { assert VMOperation.isGCInProgress() : "may only be called by the GC"; prepareInvalidation(info); assert codeNotOnStackVerifier.verify(info); - finishInvalidation(info, false); + finishInvalidation(info); } private void prepareInvalidation(CodeInfo info) { @@ -236,14 +237,14 @@ private void prepareInvalidation(CodeInfo info) { } } - private void finishInvalidation(CodeInfo info, boolean notifyGC) { + private void finishInvalidation(CodeInfo info) { InstalledCodeObserverSupport.removeObservers(RuntimeCodeInfoAccess.getCodeObserverHandles(info)); - finishInvalidation0(info, notifyGC); + finishInvalidation0(info); RuntimeCodeInfoHistory.singleton().logInvalidate(info); } @Uninterruptible(reason = "Modifying code tables that are used by the GC") - private void finishInvalidation0(CodeInfo info, boolean notifyGC) { + private void finishInvalidation0(CodeInfo info) { /* * Now it is guaranteed that the InstalledCode is not on the stack and cannot be invoked * anymore, so we can free the code and all metadata. @@ -256,7 +257,7 @@ private void finishInvalidation0(CodeInfo info, boolean notifyGC) { numCodeInfos--; NonmovableArrays.setWord(codeInfos, numCodeInfos, WordFactory.nullPointer()); - RuntimeCodeInfoAccess.freePartially(info, notifyGC); + RuntimeCodeInfoAccess.markAsInvalidated(info); assert verifyTable(); } diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/code/RuntimeCodeInfoAccess.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/code/RuntimeCodeInfoAccess.java index 762942332d12..e27a627fe3f6 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/code/RuntimeCodeInfoAccess.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/code/RuntimeCodeInfoAccess.java @@ -204,23 +204,11 @@ public static CodeInfo allocateMethodInfo(NonmovableObjectArray objectDa } @Uninterruptible(reason = "Prevent the GC from running - otherwise, it could accidentally visit the freed memory.") - static void freePartially(CodeInfo info, boolean notifyGC) { + static void markAsInvalidated(CodeInfo info) { CodeInfoImpl impl = cast(info); assert CodeInfoAccess.isAliveState(impl.getState()) || impl.getState() == CodeInfo.STATE_READY_FOR_INVALIDATION : "unexpected state (probably already released)"; - if (notifyGC) { - // Notify the GC as long as the object data is still valid. - Heap.getHeap().getRuntimeCodeInfoGCSupport().unregisterCodeConstants(info); - } - - NonmovableArrays.releaseUnmanagedArray(impl.getCodeObserverHandles()); - impl.setCodeObserverHandles(NonmovableArrays.nullArray()); - - releaseCodeMemory(impl.getCodeStart(), impl.getCodeAndDataMemorySize()); - /* - * Note that we must not null-out any CodeInfo metadata as it can be accessed in a stack - * walk even when the CodeInfo data is already partially freed. - */ - CodeInfoAccess.setState(info, CodeInfo.STATE_PARTIALLY_FREED); + /* We can't free any data because only the GC is allowed to free CodeInfo data. */ + CodeInfoAccess.setState(info, CodeInfo.STATE_INVALIDATED); } public static CodePointer allocateCodeMemory(UnsignedWord size) { @@ -245,7 +233,7 @@ static void releaseMethodInfoOnTearDown(CodeInfo info) { InstalledCodeObserverSupport.removeObserversOnTearDown(getCodeObserverHandles(info)); assert ((CodeInfoTether) UntetheredCodeInfoAccess.getTetherUnsafe(info)).getCount() == 1 : "CodeInfo tether must not be referenced by non-teardown code."; - free(info, true); + free(info); } public interface NonmovableArrayAction { @@ -262,16 +250,14 @@ public void apply(NonmovableArray array) { }; @Uninterruptible(reason = "Called from uninterruptible code.", mayBeInlined = true) - public static void free(CodeInfo info, boolean notifyGC) { + public static void free(CodeInfo info) { CodeInfoImpl impl = cast(info); - if (CodeInfoAccess.isAliveState(impl.getState()) || impl.getState() == CodeInfo.STATE_READY_FOR_INVALIDATION) { - freePartially(info, notifyGC); - } - if (notifyGC) { - // Notify the GC as long as the object data is still valid. - Heap.getHeap().getRuntimeCodeInfoGCSupport().unregisterRuntimeCodeInfo(info); - } + /* Free the code observers handles unconditionally (they are never in the image heap). */ + NonmovableArrays.releaseUnmanagedArray(impl.getCodeObserverHandles()); + impl.setCodeObserverHandles(NonmovableArrays.nullArray()); + + releaseCodeMemory(impl.getCodeStart(), impl.getCodeAndDataMemorySize()); if (!impl.getAllObjectsAreInImageHeap()) { forEachArray(info, RELEASE_ACTION); diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/code/RuntimeCodeInfoMemory.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/code/RuntimeCodeInfoMemory.java index 192394d06ab4..677a26df2e17 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/code/RuntimeCodeInfoMemory.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/code/RuntimeCodeInfoMemory.java @@ -26,7 +26,6 @@ import java.util.concurrent.locks.ReentrantLock; -import jdk.graal.compiler.api.replacements.Fold; import org.graalvm.nativeimage.ImageSingletons; import org.graalvm.nativeimage.Platform; import org.graalvm.nativeimage.Platforms; @@ -46,6 +45,8 @@ import com.oracle.svm.core.thread.VMOperation; import com.oracle.svm.core.util.VMError; +import jdk.graal.compiler.api.replacements.Fold; + /** * Keeps track of {@link CodeInfo} structures of runtime-compiled methods (including invalidated and * not yet freed ones) and releases their memory on tear-down. diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/heap/RuntimeCodeCacheCleaner.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/heap/RuntimeCodeCacheCleaner.java index 384438ec486c..d81daf130498 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/heap/RuntimeCodeCacheCleaner.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/heap/RuntimeCodeCacheCleaner.java @@ -72,7 +72,7 @@ public boolean visitCode(CodeInfo codeInfo) { } else if (state == CodeInfo.STATE_READY_FOR_INVALIDATION) { // All objects that are accessed during invalidation must still be reachable. CodeInfoTable.invalidateNonStackCodeAtSafepoint(codeInfo); - assert CodeInfoAccess.getState(codeInfo) == CodeInfo.STATE_PARTIALLY_FREED; + assert CodeInfoAccess.getState(codeInfo) == CodeInfo.STATE_INVALIDATED; freeMemory(codeInfo); } return true; @@ -82,6 +82,6 @@ private static void freeMemory(CodeInfo codeInfo) { boolean removed = RuntimeCodeInfoMemory.singleton().removeDuringGC(codeInfo); assert removed : "must have been present"; RuntimeCodeInfoHistory.singleton().logFree(codeInfo); - RuntimeCodeInfoAccess.free(codeInfo, false); + RuntimeCodeInfoAccess.free(codeInfo); } } diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/heap/RuntimeCodeInfoGCSupport.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/heap/RuntimeCodeInfoGCSupport.java index 5f2198e1e5c7..e02a237a08fa 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/heap/RuntimeCodeInfoGCSupport.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/heap/RuntimeCodeInfoGCSupport.java @@ -53,20 +53,4 @@ public abstract class RuntimeCodeInfoGCSupport { */ @Uninterruptible(reason = "Called when installing code.", callerMustBe = true) public abstract void registerDeoptMetadata(CodeInfo codeInfo); - - /** - * Notify the GC that the application is going to invalidate run-time compiled code that has - * embedded references to Java heap objects. This notification must not be triggered if the GC - * itself frees a code metadata object. - */ - @Uninterruptible(reason = "Called when freeing code.", callerMustBe = true) - public abstract void unregisterCodeConstants(CodeInfo codeInfo); - - /** - * Notify the GC that the application is going to free a code metadata object that references - * Java heap objects from native-memory. This notification must not be triggered if the GC - * itself frees a code metadata object. - */ - @Uninterruptible(reason = "Called when freeing code.", callerMustBe = true) - public abstract void unregisterRuntimeCodeInfo(CodeInfo codeInfo); } From ccd632bd5fbf5f20be41d877b06ab2033365113a Mon Sep 17 00:00:00 2001 From: Andreas Woess Date: Tue, 12 Dec 2023 15:48:01 +0100 Subject: [PATCH 193/593] Add pseudo code description of vectorizedHashCode intrinsic. --- .../aarch64/AArch64VectorizedHashCodeOp.java | 67 ++++++++++++++++--- 1 file changed, 56 insertions(+), 11 deletions(-) diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/aarch64/AArch64VectorizedHashCodeOp.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/aarch64/AArch64VectorizedHashCodeOp.java index 14f551be4e43..9b5a5120cfd9 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/aarch64/AArch64VectorizedHashCodeOp.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/aarch64/AArch64VectorizedHashCodeOp.java @@ -135,6 +135,62 @@ private static void arraysHashcodeElload(AArch64MacroAssembler masm, Register ds 1, }; + /** + * Emits an unrolled x16 vector loop + an unrolled x2 scalar loop + a final single scalar case + * to compute the array or string hash code. + * + * Roughly equivalent to the following vector pseudo code: + * + *
    +     * final var I128 = VectorSpecies.of(int.class, VectorShape.S_128_BIT);
    +     * final int vlen = vspecies.length();
    +     * final int N = 4 * vlen;
    +     * final int[] POW31BW = new int[N]{31**(N-1), ..., 31**1, 31**0};
    +     * assert N == 16;
    +     *
    +     * int result = initialValue;
    +     * int bound = data.length & ~(N - 1);
    +     * // UNROLLED (x16) VECTOR LOOP
    +     * if (data.length >= N) {
    +     *     var vresult1 = IntVector.zero(I128);
    +     *     var vresult2 = IntVector.zero(I128);
    +     *     var vresult3 = IntVector.zero(I128);
    +     *     var vresult4 = IntVector.zero(I128);
    +     *     int inext = 31 ** N;
    +     *     var vnext = IntVector.broadcast(I128, inext);
    +     *     for (int i = 0; i < bound; i += N) {
    +     *         result *= inext;
    +     *         // load 4x4 zero-extended-to-32-bit int values
    +     *         var vtmp1 = IntVector.fromArray(I128, data, i + 0 * vlen);
    +     *         var vtmp2 = IntVector.fromArray(I128, data, i + 1 * vlen);
    +     *         var vtmp3 = IntVector.fromArray(I128, data, i + 2 * vlen);
    +     *         var vtmp4 = IntVector.fromArray(I128, data, i + 3 * vlen);
    +     *         vresult1 = vresult1.mul(vnext).add(vtmp1);
    +     *         vresult2 = vresult2.mul(vnext).add(vtmp2);
    +     *         vresult3 = vresult3.mul(vnext).add(vtmp3);
    +     *         vresult4 = vresult4.mul(vnext).add(vtmp4);
    +     *     }
    +     *     vresult1 = vresult1.mul(IntVector.fromArray(I128, POW31BW, 0 * vlen));
    +     *     vresult2 = vresult2.mul(IntVector.fromArray(I128, POW31BW, 1 * vlen));
    +     *     vresult3 = vresult3.mul(IntVector.fromArray(I128, POW31BW, 2 * vlen));
    +     *     vresult4 = vresult4.mul(IntVector.fromArray(I128, POW31BW, 3 * vlen));
    +     *     var vresult = vresult1.add(vresult2).add(vresult3).add(vresult4);
    +     *     result += vresult.reduceLanes(ADD);
    +     * }
    +     * // UNROLLED (x2) SCALAR LOOP
    +     * int i = 1;
    +     * for (; i < data.length - bound; i += 2) {
    +     *     result *= 31 * 31;
    +     *     result += data[i - 1] * 31 + data[i];
    +     * }
    +     * // LAST REMAINING SCALAR (if length is odd)
    +     * if (i == data.length - bound) {
    +     *     result *= 31;
    +     *     result += data[i - 1];
    +     * }
    +     * return result;
    +     * 
    + */ @Override public void emitCode(CompilationResultBuilder crb, AArch64MacroAssembler masm) { Label labelShortUnrolledBegin = new Label(); @@ -188,17 +244,6 @@ public void emitCode(CompilationResultBuilder crb, AArch64MacroAssembler masm) { int consecutiveRegs = Math.max(maxConsecutiveRegs / extensionFactor, 1); int regsFilledPerLoad = consecutiveRegs * extensionFactor; - // @formatter:off - // elementsPerIteration = 16; - // if (cnt1 >= elementsPerIteration) { - // UNROLLED VECTOR LOOP - // } - // if (cnt1 >= 2) { - // UNROLLED SCALAR LOOP - // } - // SINGLE SCALAR - // @formatter:on - // if (cnt1 >= elementsPerIteration) && generate_vectorized_loop masm.compare(32, cnt1, elementsPerIteration); masm.branchConditionally(ConditionFlag.LO, labelShortUnrolledBegin); From 4dddbc6e4a8f444db5d9b285f6294cf06337ab42 Mon Sep 17 00:00:00 2001 From: Andreas Woess Date: Tue, 12 Dec 2023 17:10:31 +0100 Subject: [PATCH 194/593] Fuse vertical vector reduction with coefficient multiplications. --- .../aarch64/AArch64VectorizedHashCodeOp.java | 34 ++++++------------- 1 file changed, 11 insertions(+), 23 deletions(-) diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/aarch64/AArch64VectorizedHashCodeOp.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/aarch64/AArch64VectorizedHashCodeOp.java index 9b5a5120cfd9..3be06ab2555e 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/aarch64/AArch64VectorizedHashCodeOp.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/aarch64/AArch64VectorizedHashCodeOp.java @@ -316,13 +316,19 @@ public void emitCode(CompilationResultBuilder crb, AArch64MacroAssembler masm) { loadConsecutiveVectors(masm, ASIMDSize.FullReg, ASIMDSize.FullReg.bits(), ElementSize.Word, coefAddrReg, vcoef, i, maxConsecutiveRegs, postIndex, false); } - // vresult *= vcoef; - for (int idx = 0; idx < nRegs; idx++) { - masm.neon.mulVVV(ASIMDSize.FullReg, ElementSize.Word, vresult[idx], vresult[idx], vcoef[idx]); + // fused multiply (vresult[i] * vcoef[i]) and vertical add reduction + // vresult[0] = vresult[0] * vcoef[0]; + // vresult[0] += vresult[i] * vcoef[i] for i > 0; + for (int i = 0; i < nRegs; i++) { + if (i == 0) { + masm.neon.mulVVV(ASIMDSize.FullReg, ElementSize.Word, vresult[0], vresult[i], vcoef[i]); + } else { + masm.neon.mlaVVV(ASIMDSize.FullReg, ElementSize.Word, vresult[0], vresult[i], vcoef[i]); + } } - // accumulate horizontal vector sum in result - reduceVectorLanes(masm, ASIMDSize.FullReg, vresult, nRegs); + // result += vresult[0].reduceLanes(ADD); (horizontal lane-wise add reduction) + masm.neon.addvSV(ASIMDSize.FullReg, ElementSize.Word, vresult[0], vresult[0]); masm.fmov(32, tmp2, vresult[0]); // umovGX(Word, tmp2, vresult[0], 0); masm.add(32, result, result, tmp2); @@ -496,24 +502,6 @@ private static void extendPairwise(AArch64MacroAssembler masm, boolean unsigned, } } - /** - * Reduces elements from multiple vectors to a single vector and then reduces that vector's - * lanes to a single scalar value in {@code vresult[0]}. - */ - private static void reduceVectorLanes(AArch64MacroAssembler masm, ASIMDSize vsize, Register[] vresult, int vresultLen) { - // reduce vectors pairwise until there's only a single vector left - for (int nRegs = vresultLen, stride = 1; nRegs >= 2; nRegs /= 2, stride *= 2) { - for (int i = 0; i < vresult.length - stride; i += 2 * stride) { - masm.neon.addVVV(vsize, ElementSize.Word, vresult[i], vresult[i], vresult[i + stride]); - } - if (nRegs % 2 != 0) { - masm.neon.addVVV(vsize, ElementSize.Word, vresult[0], vresult[0], vresult[(nRegs - 1) * stride]); - } - } - // reduce vector lanes horizontally to a scalar value (vresult.reduceLanes(ADD)) - masm.neon.addvSV(vsize, ElementSize.Word, vresult[0], vresult[0]); - } - private static void xtlVV(AArch64MacroAssembler masm, boolean unsigned, ElementSize elementSize, Register dst, Register src) { if (unsigned) { masm.neon.uxtlVV(elementSize, dst, src); From d8121493feaac0fe86c6bba15e72d4f85def6aa0 Mon Sep 17 00:00:00 2001 From: Andreas Woess Date: Tue, 12 Dec 2023 19:23:08 +0100 Subject: [PATCH 195/593] Combine CMP and AND to ANDS, and use post-index address instead of relative index. --- .../aarch64/AArch64VectorizedHashCodeOp.java | 55 ++++++++++--------- 1 file changed, 28 insertions(+), 27 deletions(-) diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/aarch64/AArch64VectorizedHashCodeOp.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/aarch64/AArch64VectorizedHashCodeOp.java index 3be06ab2555e..5643c806dbbb 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/aarch64/AArch64VectorizedHashCodeOp.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/aarch64/AArch64VectorizedHashCodeOp.java @@ -36,7 +36,9 @@ import jdk.graal.compiler.asm.aarch64.AArch64Address; import jdk.graal.compiler.asm.aarch64.AArch64Address.AddressingMode; import jdk.graal.compiler.asm.aarch64.AArch64Assembler.ConditionFlag; +import jdk.graal.compiler.asm.aarch64.AArch64Assembler.ShiftType; import jdk.graal.compiler.asm.aarch64.AArch64MacroAssembler; +import jdk.graal.compiler.core.common.Stride; import jdk.graal.compiler.debug.GraalError; import jdk.graal.compiler.lir.LIRInstructionClass; import jdk.graal.compiler.lir.Opcode; @@ -199,6 +201,11 @@ public void emitCode(CompilationResultBuilder crb, AArch64MacroAssembler masm) { Label labelUnrolledVectorLoopBegin = new Label(); Label labelEnd = new Label(); + // Parameters (immutable, alive) + Register lengthParam = asRegister(length); + Register arrayStartParam = asRegister(arrayStart); + Register initialValueParam = asRegister(initialValue); + // Result (def) and temp registers Register result = asRegister(resultValue); Register ary1 = asRegister(temp[0]); Register cnt1 = asRegister(temp[1]); @@ -206,9 +213,9 @@ public void emitCode(CompilationResultBuilder crb, AArch64MacroAssembler masm) { Register tmp3 = asRegister(temp[3]); Register index = asRegister(temp[4]); - masm.mov(64, ary1, asRegister(arrayStart)); - masm.mov(32, cnt1, asRegister(length)); - masm.mov(32, result, asRegister(initialValue)); + masm.mov(64, ary1, arrayStartParam); + masm.mov(32, cnt1, lengthParam); + masm.mov(32, result, initialValueParam); Register vnext = asRegister(vectorTemp[0]); Register[] vcoef = IntStream.range(1, 1 + nRegs).mapToObj(i -> asRegister(vectorTemp[i])).toArray(Register[]::new); @@ -222,6 +229,7 @@ public void emitCode(CompilationResultBuilder crb, AArch64MacroAssembler masm) { case Int -> ElementSize.Word; default -> throw GraalError.shouldNotReachHereUnexpectedValue(arrayKind); }; + final Stride stride = Stride.fromJavaKind(arrayKind); GraalError.guarantee(nRegs == 2 || nRegs == 4 || nRegs == 8, "number of vectors must be either 2, 4, or 8"); final int elementsPerVector = ASIMDSize.FullReg.bytes() / ElementSize.Word.bytes(); @@ -244,20 +252,19 @@ public void emitCode(CompilationResultBuilder crb, AArch64MacroAssembler masm) { int consecutiveRegs = Math.max(maxConsecutiveRegs / extensionFactor, 1); int regsFilledPerLoad = consecutiveRegs * extensionFactor; - // if (cnt1 >= elementsPerIteration) && generate_vectorized_loop - masm.compare(32, cnt1, elementsPerIteration); - masm.branchConditionally(ConditionFlag.LO, labelShortUnrolledBegin); + Register bound = tmp2; + Register next = tmp3; + + // bound = length & ~(N - 1); + masm.ands(32, bound, cnt1, ~(elementsPerIteration - 1)); + // if (bound != 0) { // (EQ = Z flag set) + masm.branchConditionally(ConditionFlag.EQ, labelShortUnrolledBegin); - // index = 0; - masm.mov(index, 0); // vresult[i] = IntVector.zero(I128); for (int idx = 0; idx < nRegs; idx++) { masm.neon.moviVI(ASIMDSize.FullReg, vresult[idx], 0); } - Register bound = tmp2; - Register next = tmp3; - // vnext = IntVector.broadcast(I128, power_of_31_backwards[0]); // Throws AIOOBE if there are not enough elements in the array but allows more. int powersOf31Start = POWERS_OF_31_BACKWARDS.length - elementsPerIteration; @@ -265,8 +272,10 @@ public void emitCode(CompilationResultBuilder crb, AArch64MacroAssembler masm) { masm.mov(next, nextPow31); masm.neon.dupVG(ASIMDSize.FullReg, ElementSize.Word, vnext, next); - // bound = cnt1 & ~(elementsPerIteration - 1); - masm.and(32, bound, cnt1, ~(elementsPerIteration - 1)); + // cnt1 -= bound; + masm.sub(32, cnt1, cnt1, bound); + // bound = arrayStart + bound * elSize.bytes(); + masm.add(64, bound, ary1, bound, ShiftType.LSL, stride.log2); // for (; index < bound; index += elementsPerIteration) { masm.align(AArch64MacroAssembler.PREFERRED_LOOP_ALIGNMENT); @@ -293,17 +302,10 @@ public void emitCode(CompilationResultBuilder crb, AArch64MacroAssembler masm) { masm.neon.moveVV(ASIMDSize.FullReg, vresult[idx], vtmp[idx]); } - // increment index by the number of elements read in this iteration - masm.add(32, index, index, elementsPerIteration); - - // index < bound; - masm.cmp(32, index, bound); + // if (ary1 |<| bound) continue; else break; + masm.cmp(64, ary1, bound); masm.branchConditionally(ConditionFlag.LO, labelUnrolledVectorLoopBegin); // } - - // assert index == bound && ary1 == &ary[bound]; - // cnt1 -= bound; - masm.sub(32, cnt1, cnt1, bound); // release bound // vcoef = IntVector.fromArray(I128, power_of_31_backwards, 1); @@ -331,16 +333,15 @@ public void emitCode(CompilationResultBuilder crb, AArch64MacroAssembler masm) { masm.neon.addvSV(ASIMDSize.FullReg, ElementSize.Word, vresult[0], vresult[0]); masm.fmov(32, tmp2, vresult[0]); // umovGX(Word, tmp2, vresult[0], 0); masm.add(32, result, result, tmp2); - - // } else if (cnt1 < elementsPerIteration) { + // } masm.align(AArch64MacroAssembler.PREFERRED_BRANCH_TARGET_ALIGNMENT); masm.bind(labelShortUnrolledBegin); - // int i = 1; - masm.mov(index, 1); AArch64Address postIndexAddr = AArch64Address.createImmediateAddress(elSize.bits(), AddressingMode.IMMEDIATE_POST_INDEXED, ary1, elSize.bytes()); + // int i = 1; + masm.mov(index, 1); masm.cmp(32, index, cnt1); masm.branchConditionally(ConditionFlag.HS, labelShortUnrolledLoopExit); @@ -375,8 +376,8 @@ public void emitCode(CompilationResultBuilder crb, AArch64MacroAssembler masm) { masm.mov(tmp31, 31); arraysHashcodeElload(masm, tmp3, postIndexAddr, arrayKind); // index-1 masm.madd(32, result, result, tmp31, tmp3); + // } } - // } masm.bind(labelEnd); } From dfc82bc120b906a285ae747197a7a7efaaef0d55 Mon Sep 17 00:00:00 2001 From: Martin Entlicher Date: Wed, 13 Dec 2023 19:30:26 +0100 Subject: [PATCH 196/593] Do not depend on browser-actions/setup-chrome@v1 action and lines corrected. (GR-50921) --- .github/workflows/cdt-inspect.yml | 8 +- .../CDTInspectorTest/scripts/StepTest.js.out | 28 +-- .../workflowtest/DownloadChromiumDev.java | 163 ++++++++++++++++++ .../chromeinspector/workflowtest/Test.java | 17 +- .../workflowtest/TestCDTBasics.java | 4 +- 5 files changed, 194 insertions(+), 26 deletions(-) create mode 100644 vm/tests/gh_workflows/CDTInspectorTest/src/main/java/com/oracle/truffle/tools/chromeinspector/workflowtest/DownloadChromiumDev.java diff --git a/.github/workflows/cdt-inspect.yml b/.github/workflows/cdt-inspect.yml index af1ca18ef122..64ce823c3fee 100644 --- a/.github/workflows/cdt-inspect.yml +++ b/.github/workflows/cdt-inspect.yml @@ -57,10 +57,6 @@ jobs: runs-on: ubuntu-latest steps: - - uses: browser-actions/setup-chrome@v1 - with: - chrome-version: dev - id: setup-chrome - name: Checkout oracle/graal uses: actions/checkout@v4 with: @@ -90,10 +86,8 @@ jobs: mkdir jdk-dl ${MX_PATH}/mx --java-home= fetch-jdk --jdk-id labsjdk-ce-${JDK_VERSION} --to jdk-dl --alias ${JAVA_HOME} - run: | - echo Installed chromium version: ${{ steps.setup-chrome.outputs.chrome-version }} - ${{ steps.setup-chrome.outputs.chrome-path }} --version cd ${{ github.workspace }}/graal/vm ${MX_PATH}/mx --dy /tools,graal-js build cd tests/gh_workflows/CDTInspectorTest mvn -q compile - mvn -q exec:exec -Dtestargs="${{ github.workspace }}/graal/sdk/latest_graalvm_home/bin/js scripts/StepTest.js ${{ steps.setup-chrome.outputs.chrome-path }} ${{ steps.setup-chrome.outputs.chrome-version }}" + mvn -q exec:exec -Dtestargs="${{ github.workspace }}/graal/sdk/latest_graalvm_home/bin/js scripts/StepTest.js" diff --git a/vm/tests/gh_workflows/CDTInspectorTest/scripts/StepTest.js.out b/vm/tests/gh_workflows/CDTInspectorTest/scripts/StepTest.js.out index 269a1af63ef7..1a061f0bd4da 100644 --- a/vm/tests/gh_workflows/CDTInspectorTest/scripts/StepTest.js.out +++ b/vm/tests/gh_workflows/CDTInspectorTest/scripts/StepTest.js.out @@ -23,26 +23,26 @@ # Opened file: StepTest.js Stack (1) -:program StepTest.js:8 +:program StepTest.js:28 Scope (3) Local this : Object global{Object: function Object() { global Global Stack (1) -:program StepTest.js:27 +:program StepTest.js:47 Scope (3) Local this : Object global{Object: function Object() { global Global Stack (1) -:program StepTest.js:29 +:program StepTest.js:49 Scope (3) Local this : Object global{Object: function Object() { global Global Stack (2) -binarySearch StepTest.js:11 -:program StepTest.js:29 +binarySearch StepTest.js:31 +:program StepTest.js:49 Scope (5) Local this : Object global{Object: function Object() { @@ -50,8 +50,8 @@ array : \(10\) \[1, 2, 3, 5, 8,.* element : 12 global Global Stack (2) -binarySearch StepTest.js:12 -:program StepTest.js:29 +binarySearch StepTest.js:32 +:program StepTest.js:49 Scope (6) Local this : Object global{Object: function Object() { @@ -60,8 +60,8 @@ element : 12 i1 : 0 global Global Stack (2) -binarySearch StepTest.js:13 -:program StepTest.js:29 +binarySearch StepTest.js:33 +:program StepTest.js:49 Scope (7) Local this : Object global{Object: function Object() { @@ -71,8 +71,8 @@ i1 : 0 i2 : 9 global Global Stack (2) -binarySearch StepTest.js:16 -:program StepTest.js:29 +binarySearch StepTest.js:36 +:program StepTest.js:49 Scope (10) Block diff : -4 @@ -85,8 +85,8 @@ i1 : 0 i2 : 9 global Global Stack (2) -binarySearch StepTest.js:18 -:program StepTest.js:29 +binarySearch StepTest.js:38 +:program StepTest.js:49 Scope (10) Block diff : -4 @@ -99,7 +99,7 @@ i1 : 0 i2 : 9 global Global Stack (1) -:program StepTest.js:29 +:program StepTest.js:49 Scope (3) Local this : Object global{Object: function Object() { diff --git a/vm/tests/gh_workflows/CDTInspectorTest/src/main/java/com/oracle/truffle/tools/chromeinspector/workflowtest/DownloadChromiumDev.java b/vm/tests/gh_workflows/CDTInspectorTest/src/main/java/com/oracle/truffle/tools/chromeinspector/workflowtest/DownloadChromiumDev.java new file mode 100644 index 000000000000..2f28fbe3c695 --- /dev/null +++ b/vm/tests/gh_workflows/CDTInspectorTest/src/main/java/com/oracle/truffle/tools/chromeinspector/workflowtest/DownloadChromiumDev.java @@ -0,0 +1,163 @@ +/* + * Copyright (c) 2023, 2023, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.truffle.tools.chromeinspector.workflowtest; + +import java.io.BufferedReader; +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.net.InetSocketAddress; +import java.net.Proxy; +import java.net.URI; +import java.nio.file.FileSystem; +import java.nio.file.FileSystems; +import java.nio.file.FileVisitResult; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.SimpleFileVisitor; +import java.nio.file.StandardCopyOption; +import java.nio.file.attribute.BasicFileAttributes; +import java.nio.file.attribute.PosixFileAttributes; +import java.util.Collections; +import java.util.Map; + +/** + * Download and expand the latest dev version of Chromium. + */ +public final class DownloadChromiumDev { + + private static final String DIR_NAME = "CHROME"; + private static final String LAST_VERSION_URL = "https://www.googleapis.com/download/storage/v1/b/chromium-browser-snapshots/o/Linux_x64%2FLAST_CHANGE?alt=media"; + private static final String ZIP_URL = "https://www.googleapis.com/download/storage/v1/b/chromium-browser-snapshots/o/Linux_x64%2FVERSION%2Fchrome-linux.zip?alt=media"; + private static final String CHROMIUM_ZIP_FILE = "chrome-linux.zip"; + + public static void main(String[] args) throws IOException { + File localDir; + if (args.length > 0) { + localDir = new File(args[0]); + localDir.mkdirs(); + } else { + localDir = new File(""); + } + downloadLinux(localDir.getAbsoluteFile().getCanonicalFile()); + } + + public static String[] download() throws IOException { + File tmp; + String runnerTemp = System.getenv("RUNNER_TEMP"); + if (runnerTemp != null) { + tmp = new File(runnerTemp, DIR_NAME); + tmp.mkdir(); + } else { + tmp = Files.createTempDirectory(DIR_NAME).toFile(); + } + tmp = tmp.getCanonicalFile(); + return downloadLinux(tmp); + } + + private static InputStream openURL(String url) throws IOException { + String httpsProxy = System.getenv("HTTPS_PROXY"); + if (httpsProxy == null) { + return URI.create(url).toURL().openStream(); + } + int colonIndex = httpsProxy.lastIndexOf(':'); + String host = httpsProxy.substring(0, colonIndex); + int protocolIndex = host.indexOf("://"); + if (protocolIndex > 0) { + host = host.substring(protocolIndex + 3); + } + int port = Integer.parseInt(httpsProxy.substring(colonIndex + 1)); + Proxy proxy = new Proxy(Proxy.Type.HTTP, new InetSocketAddress(host, port)); + return URI.create(url).toURL().openConnection(proxy).getInputStream(); + } + + private static String[] downloadLinux(File localDir) throws IOException { + String version; + try (BufferedReader reader = new BufferedReader(new InputStreamReader(openURL(LAST_VERSION_URL)))) { + version = reader.readLine(); + } + System.err.println("Downloading Chromium " + version + " to " + localDir); + String zipUrl = ZIP_URL.replace("VERSION", version); + File zipFile = new File(localDir, CHROMIUM_ZIP_FILE).getAbsoluteFile(); + Files.copy(openURL(zipUrl), zipFile.toPath(), StandardCopyOption.REPLACE_EXISTING); + + URI zipLocalUri = URI.create("jar:" + zipFile.toURI()); + Map env = Collections.singletonMap("enablePosixFileAttributes", Boolean.TRUE); + + try(FileSystem zipFs = FileSystems.newFileSystem(zipLocalUri, env)) { + Path localRootPath = localDir.toPath(); + for (Path root : zipFs.getRootDirectories()) { + Files.walkFileTree(root, new SimpleFileVisitor() { + @Override + public FileVisitResult visitFile(Path filePath, BasicFileAttributes attrs) throws IOException { + if (!attrs.isDirectory()) { + String name = root.relativize(filePath).toString(); + Path targetPath = localRootPath.resolve(name); + Files.createDirectories(targetPath.getParent()); + Files.copy(filePath, targetPath, StandardCopyOption.COPY_ATTRIBUTES, StandardCopyOption.REPLACE_EXISTING); + if (attrs instanceof PosixFileAttributes pattrs) { + Files.setPosixFilePermissions(targetPath, pattrs.permissions()); + } + } + return FileVisitResult.CONTINUE; + } + }); + } + } + zipFile.delete(); + System.err.println("Chromium " + version + " expanded to " + localDir); + String chromePath = new File(localDir, "chrome-linux/chrome").getCanonicalPath(); + System.out.println("Chromium binary is at " + new File(localDir, "chrome-linux/chrome").getCanonicalPath()); + version = getChromeVersion(chromePath); + String[] chrome = new String[2]; + chrome[0] = chromePath; // Chrome binary + chrome[1] = version; // Chrome version + return chrome; + } + + private static String getChromeVersion(String chromePath) throws IOException { + ProcessBuilder pb = new ProcessBuilder(chromePath, "--version"); + pb.redirectError(ProcessBuilder.Redirect.INHERIT); + Process p = pb.start(); + String versionLine; + try (BufferedReader br = new BufferedReader(new InputStreamReader(p.getInputStream()))) { + versionLine = br.readLine(); + } + try { + p.waitFor(); + } catch (InterruptedException ex) { + // skip + } + System.out.println("Version: " + versionLine); + int i1 = 0; + while (i1 < versionLine.length() && !Character.isDigit(versionLine.charAt(i1))) { + i1++; + } + int i2 = versionLine.indexOf('.', i1); + return versionLine.substring(i1, i2); + } + +} diff --git a/vm/tests/gh_workflows/CDTInspectorTest/src/main/java/com/oracle/truffle/tools/chromeinspector/workflowtest/Test.java b/vm/tests/gh_workflows/CDTInspectorTest/src/main/java/com/oracle/truffle/tools/chromeinspector/workflowtest/Test.java index d97aa65f14f9..6bf76faa9c43 100644 --- a/vm/tests/gh_workflows/CDTInspectorTest/src/main/java/com/oracle/truffle/tools/chromeinspector/workflowtest/Test.java +++ b/vm/tests/gh_workflows/CDTInspectorTest/src/main/java/com/oracle/truffle/tools/chromeinspector/workflowtest/Test.java @@ -49,8 +49,16 @@ public static void main(String[] args) throws Exception { } String graalLauncher = args[0]; String scriptFile = args[1]; - String chromeBin = args[2]; - String chromeVersion = args[3].substring(0, args[3].indexOf('.')); + String chromeBin; + String chromeVersion; + if (args.length > 2) { + chromeBin = args[2]; + chromeVersion = args[3].substring(0, args[3].indexOf('.')); + } else { + String[] chrome = DownloadChromiumDev.download(); + chromeBin = chrome[0]; + chromeVersion = chrome[1]; + } WebDriver driver = createDriver(chromeBin, chromeVersion); List goldenLines = Files.readAllLines(Paths.get(scriptFile + ".out")); @@ -91,7 +99,10 @@ private static class OutputComparator implements Consumer { @Override public void accept(String line) { - String goldenLine = goldenLines.get(index++); + String goldenLine; + do { + goldenLine = goldenLines.get(index++); + } while (goldenLine.startsWith("#") || line.isBlank()); line = line.trim(); if (!goldenLine.equals(line)) { if (!Pattern.matches(goldenLine, line)) { diff --git a/vm/tests/gh_workflows/CDTInspectorTest/src/main/java/com/oracle/truffle/tools/chromeinspector/workflowtest/TestCDTBasics.java b/vm/tests/gh_workflows/CDTInspectorTest/src/main/java/com/oracle/truffle/tools/chromeinspector/workflowtest/TestCDTBasics.java index e755e0b8c4e4..3f637eb5461b 100644 --- a/vm/tests/gh_workflows/CDTInspectorTest/src/main/java/com/oracle/truffle/tools/chromeinspector/workflowtest/TestCDTBasics.java +++ b/vm/tests/gh_workflows/CDTInspectorTest/src/main/java/com/oracle/truffle/tools/chromeinspector/workflowtest/TestCDTBasics.java @@ -83,7 +83,7 @@ public static void test(WebDriver driver, Consumer output) throws Timeou printScope(scope, output); EditorGutter gutter = new EditorGutter(driver); - gutter.clickAt(16); // Set breakpoint at line 16 + gutter.clickAt(36); // Set breakpoint at line 36 actions.click(Action.PAUSE_RESUME); actions.waitTillEnabled(Action.STEP, true, TIMEOUT); @@ -102,7 +102,7 @@ public static void test(WebDriver driver, Consumer output) throws Timeou printStack(callFrames, 1, output); printScope(scope, output); - gutter.clickAt(16); // Remove breakpoint at line 16 + gutter.clickAt(36); // Remove breakpoint at line 36 actions.click(Action.PAUSE_RESUME); From 180d000c7e0609fdb2273210057ba6c62643cee6 Mon Sep 17 00:00:00 2001 From: Andreas Woess Date: Wed, 13 Dec 2023 18:03:08 +0100 Subject: [PATCH 197/593] Extract helper method for applying asRegister on a Value[] slice. --- .../lir/aarch64/AArch64VectorizedHashCodeOp.java | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/aarch64/AArch64VectorizedHashCodeOp.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/aarch64/AArch64VectorizedHashCodeOp.java index 5643c806dbbb..d4a6271503a6 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/aarch64/AArch64VectorizedHashCodeOp.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/aarch64/AArch64VectorizedHashCodeOp.java @@ -27,7 +27,6 @@ import static jdk.vm.ci.code.ValueUtil.asRegister; import java.util.Arrays; -import java.util.stream.IntStream; import jdk.graal.compiler.asm.Label; import jdk.graal.compiler.asm.aarch64.AArch64ASIMDAssembler.ASIMDInstruction; @@ -90,6 +89,14 @@ public AArch64VectorizedHashCodeOp(LIRGeneratorTool tool, this.vectorTemp = allocateVectorRegisters(tool, 1 + 2 * nRegs); } + private static Register[] asRegisterSlice(Value[] registerValues, int start, int end) { + Register[] regs = new Register[end - start]; + for (int fromIndex = start, toIndex = 0; fromIndex < end; fromIndex++, toIndex++) { + regs[toIndex] = asRegister(registerValues[fromIndex]); + } + return regs; + } + private static void arraysHashcodeElload(AArch64MacroAssembler masm, Register dst, AArch64Address src, JavaKind eltype) { switch (eltype) { case Boolean -> masm.ldr(8, dst, src); @@ -218,8 +225,8 @@ public void emitCode(CompilationResultBuilder crb, AArch64MacroAssembler masm) { masm.mov(32, result, initialValueParam); Register vnext = asRegister(vectorTemp[0]); - Register[] vcoef = IntStream.range(1, 1 + nRegs).mapToObj(i -> asRegister(vectorTemp[i])).toArray(Register[]::new); - Register[] vresult = IntStream.range(1 + nRegs, 1 + 2 * nRegs).mapToObj(i -> asRegister(vectorTemp[i])).toArray(Register[]::new); + Register[] vcoef = asRegisterSlice(vectorTemp, 1, 1 + nRegs); + Register[] vresult = asRegisterSlice(vectorTemp, 1 + nRegs, 1 + 2 * nRegs); Register[] vtmp = vcoef; final boolean unsigned = arrayKind == JavaKind.Boolean || arrayKind == JavaKind.Char; From 788a9d1c3f633167821d78978da0aa890f75a720 Mon Sep 17 00:00:00 2001 From: Andreas Woess Date: Wed, 13 Dec 2023 18:06:08 +0100 Subject: [PATCH 198/593] Restructure AArch64VectorizedHashCodeOp.emitCode for readability. --- .../aarch64/AArch64VectorizedHashCodeOp.java | 232 +++++++++--------- 1 file changed, 120 insertions(+), 112 deletions(-) diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/aarch64/AArch64VectorizedHashCodeOp.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/aarch64/AArch64VectorizedHashCodeOp.java index d4a6271503a6..49a6b472ec40 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/aarch64/AArch64VectorizedHashCodeOp.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/aarch64/AArch64VectorizedHashCodeOp.java @@ -200,12 +200,10 @@ private static void arraysHashcodeElload(AArch64MacroAssembler masm, Register ds * return result; * */ + @SuppressWarnings("unused") // unused block labels @Override public void emitCode(CompilationResultBuilder crb, AArch64MacroAssembler masm) { Label labelShortUnrolledBegin = new Label(); - Label labelShortUnrolledLoopBegin = new Label(); - Label labelShortUnrolledLoopExit = new Label(); - Label labelUnrolledVectorLoopBegin = new Label(); Label labelEnd = new Label(); // Parameters (immutable, alive) @@ -260,130 +258,140 @@ public void emitCode(CompilationResultBuilder crb, AArch64MacroAssembler masm) { int regsFilledPerLoad = consecutiveRegs * extensionFactor; Register bound = tmp2; - Register next = tmp3; - // bound = length & ~(N - 1); masm.ands(32, bound, cnt1, ~(elementsPerIteration - 1)); // if (bound != 0) { // (EQ = Z flag set) masm.branchConditionally(ConditionFlag.EQ, labelShortUnrolledBegin); + vectorBranch: { + // vresult[i] = IntVector.zero(I128); + for (int idx = 0; idx < nRegs; idx++) { + masm.neon.moviVI(ASIMDSize.FullReg, vresult[idx], 0); + } - // vresult[i] = IntVector.zero(I128); - for (int idx = 0; idx < nRegs; idx++) { - masm.neon.moviVI(ASIMDSize.FullReg, vresult[idx], 0); - } - - // vnext = IntVector.broadcast(I128, power_of_31_backwards[0]); - // Throws AIOOBE if there are not enough elements in the array but allows more. - int powersOf31Start = POWERS_OF_31_BACKWARDS.length - elementsPerIteration; - int nextPow31 = POWERS_OF_31_BACKWARDS[powersOf31Start - 1]; - masm.mov(next, nextPow31); - masm.neon.dupVG(ASIMDSize.FullReg, ElementSize.Word, vnext, next); - - // cnt1 -= bound; - masm.sub(32, cnt1, cnt1, bound); - // bound = arrayStart + bound * elSize.bytes(); - masm.add(64, bound, ary1, bound, ShiftType.LSL, stride.log2); - - // for (; index < bound; index += elementsPerIteration) { - masm.align(AArch64MacroAssembler.PREFERRED_LOOP_ALIGNMENT); - masm.bind(labelUnrolledVectorLoopBegin); - // result *= next; - masm.mul(32, result, result, next); - - // loop fission to upfront the cost of fetching from memory, - // OOO execution can then hopefully do a better job of prefetching - // load next 16 elements into 4 data vector registers - // vtmp = ary1[index:index+elementsPerIteration]; - for (int ldVi = 0; ldVi < nRegs; ldVi += regsFilledPerLoad) { - boolean postIndex = true; - loadConsecutiveVectors(masm, loadVecSize, loadVecBits, elSize, ary1, vtmp, ldVi, consecutiveRegs, postIndex, false); - extendVectorsToWord(masm, unsigned, loadVecBits, elSize, vtmp, ldVi, consecutiveRegs); - } + // vnext = IntVector.broadcast(I128, power_of_31_backwards[0]); + // Throws AIOOBE if there are not enough elements in the array but allows more. + int powersOf31Start = POWERS_OF_31_BACKWARDS.length - elementsPerIteration; + int nextPow31 = POWERS_OF_31_BACKWARDS[powersOf31Start - 1]; + Register next = tmp3; + masm.mov(next, nextPow31); + masm.neon.dupVG(ASIMDSize.FullReg, ElementSize.Word, vnext, next); + + // cnt1 -= bound; + masm.sub(32, cnt1, cnt1, bound); + // bound = arrayStart + bound * elSize.bytes(); + masm.add(64, bound, ary1, bound, ShiftType.LSL, stride.log2); + + vectorLoop: { // for (; index |<| (length & ~(N - 1)); index += N) { + Label labelUnrolledVectorLoopBegin = new Label(); + masm.align(AArch64MacroAssembler.PREFERRED_LOOP_ALIGNMENT); + masm.bind(labelUnrolledVectorLoopBegin); + + // result *= next; + masm.mul(32, result, result, next); + + /* + * Load the next 16 data elements, zero-extended to 32-bit, into 4 vector registers. + * By grouping the loads and fetching from memory up front (loop fission), we can + * combine multiple loads into one instruction, and out-of-order execution can + * hopefully do a better job of prefetching, while also allowing subsequent + * instructions to be executed while data are still being fetched. + */ + // vtmp = ary1[index:index+elementsPerIteration]; + for (int ldVi = 0; ldVi < nRegs; ldVi += regsFilledPerLoad) { + boolean postIndex = true; + loadConsecutiveVectors(masm, loadVecSize, loadVecBits, elSize, ary1, vtmp, ldVi, consecutiveRegs, postIndex, false); + extendVectorsToWord(masm, unsigned, loadVecBits, elSize, vtmp, ldVi, consecutiveRegs); + } - // vresult[i] = vresult[i] * vnext + vtmp[i]; - // (desugared to: vtmp[i] += vresult[i] * vnext, vresult[i] = vtmp[i]) - for (int idx = 0; idx < nRegs; idx++) { - masm.neon.mlaVVV(ASIMDSize.FullReg, ElementSize.Word, vtmp[idx], vresult[idx], vnext); - } - for (int idx = 0; idx < nRegs; idx++) { - masm.neon.moveVV(ASIMDSize.FullReg, vresult[idx], vtmp[idx]); - } + // vresult[i] = vresult[i] * vnext + vtmp[i]; + // (desugared to: vtmp[i] += vresult[i] * vnext, vresult[i] = vtmp[i]) + for (int idx = 0; idx < nRegs; idx++) { + masm.neon.mlaVVV(ASIMDSize.FullReg, ElementSize.Word, vtmp[idx], vresult[idx], vnext); + } + for (int idx = 0; idx < nRegs; idx++) { + masm.neon.moveVV(ASIMDSize.FullReg, vresult[idx], vtmp[idx]); + } - // if (ary1 |<| bound) continue; else break; - masm.cmp(64, ary1, bound); - masm.branchConditionally(ConditionFlag.LO, labelUnrolledVectorLoopBegin); - // } - // release bound - - // vcoef = IntVector.fromArray(I128, power_of_31_backwards, 1); - var powersOf31 = new ArrayDataPointerConstant(Arrays.copyOfRange(POWERS_OF_31_BACKWARDS, powersOf31Start, POWERS_OF_31_BACKWARDS.length), 16); - crb.recordDataReferenceInCode(powersOf31); - Register coefAddrReg = tmp2; - masm.adrpAdd(coefAddrReg); - for (int i = 0; i < nRegs; i += maxConsecutiveRegs) { - boolean postIndex = maxConsecutiveRegs < nRegs; - loadConsecutiveVectors(masm, ASIMDSize.FullReg, ASIMDSize.FullReg.bits(), ElementSize.Word, coefAddrReg, vcoef, i, maxConsecutiveRegs, postIndex, false); - } + // if (ary1 |<| bound) continue; else break; + masm.cmp(64, ary1, bound); + masm.branchConditionally(ConditionFlag.LO, labelUnrolledVectorLoopBegin); + } + // release bound/tmp2 + + // vcoef = IntVector.fromArray(I128, power_of_31_backwards, 1); + var powersOf31 = new ArrayDataPointerConstant(Arrays.copyOfRange(POWERS_OF_31_BACKWARDS, powersOf31Start, POWERS_OF_31_BACKWARDS.length), 16); + crb.recordDataReferenceInCode(powersOf31); + Register coefAddrReg = tmp2; + masm.adrpAdd(coefAddrReg); + for (int i = 0; i < nRegs; i += maxConsecutiveRegs) { + boolean postIndex = maxConsecutiveRegs < nRegs; + loadConsecutiveVectors(masm, ASIMDSize.FullReg, ASIMDSize.FullReg.bits(), ElementSize.Word, coefAddrReg, vcoef, i, maxConsecutiveRegs, postIndex, false); + } - // fused multiply (vresult[i] * vcoef[i]) and vertical add reduction - // vresult[0] = vresult[0] * vcoef[0]; - // vresult[0] += vresult[i] * vcoef[i] for i > 0; - for (int i = 0; i < nRegs; i++) { - if (i == 0) { - masm.neon.mulVVV(ASIMDSize.FullReg, ElementSize.Word, vresult[0], vresult[i], vcoef[i]); - } else { - masm.neon.mlaVVV(ASIMDSize.FullReg, ElementSize.Word, vresult[0], vresult[i], vcoef[i]); + // fused multiply (vresult[i] * vcoef[i]) and vertical add reduction + // vresult[0] = vresult[0] * vcoef[0]; + // vresult[0] += vresult[i] * vcoef[i] for i > 0; + for (int i = 0; i < nRegs; i++) { + if (i == 0) { + masm.neon.mulVVV(ASIMDSize.FullReg, ElementSize.Word, vresult[0], vresult[i], vcoef[i]); + } else { + masm.neon.mlaVVV(ASIMDSize.FullReg, ElementSize.Word, vresult[0], vresult[i], vcoef[i]); + } } - } - // result += vresult[0].reduceLanes(ADD); (horizontal lane-wise add reduction) - masm.neon.addvSV(ASIMDSize.FullReg, ElementSize.Word, vresult[0], vresult[0]); - masm.fmov(32, tmp2, vresult[0]); // umovGX(Word, tmp2, vresult[0], 0); - masm.add(32, result, result, tmp2); - // } + // result += vresult[0].reduceLanes(ADD); (horizontal lane-wise add reduction) + masm.neon.addvSV(ASIMDSize.FullReg, ElementSize.Word, vresult[0], vresult[0]); + masm.fmov(32, tmp2, vresult[0]); // umovGX(Word, tmp2, vresult[0], 0); + masm.add(32, result, result, tmp2); + } masm.align(AArch64MacroAssembler.PREFERRED_BRANCH_TARGET_ALIGNMENT); masm.bind(labelShortUnrolledBegin); + shortUnrolledBranch: { + Label labelShortUnrolledLoopExit = new Label(); + AArch64Address postIndexAddr = AArch64Address.createImmediateAddress(elSize.bits(), AddressingMode.IMMEDIATE_POST_INDEXED, ary1, elSize.bytes()); - AArch64Address postIndexAddr = AArch64Address.createImmediateAddress(elSize.bits(), AddressingMode.IMMEDIATE_POST_INDEXED, ary1, elSize.bytes()); - - // int i = 1; - masm.mov(index, 1); - masm.cmp(32, index, cnt1); - masm.branchConditionally(ConditionFlag.HS, labelShortUnrolledLoopExit); - - try (var scratch1 = masm.getScratchRegister(); var scratch2 = masm.getScratchRegister()) { - var tmp31 = scratch1.getRegister(); - var tmp961 = scratch2.getRegister(); - masm.mov(tmp31, 31); - masm.mov(tmp961, 961); - - // for (; i < cnt1 ; i += 2) { - masm.align(AArch64MacroAssembler.PREFERRED_LOOP_ALIGNMENT); - masm.bind(labelShortUnrolledLoopBegin); - // result *= 31**2; - // result += ary1[index-1] * 31 + ary1[index] - arraysHashcodeElload(masm, tmp2, postIndexAddr, arrayKind); // index-1 - arraysHashcodeElload(masm, tmp3, postIndexAddr, arrayKind); // index - masm.madd(32, tmp3, tmp2, tmp31, tmp3); - masm.madd(32, result, result, tmp961, tmp3); - // i += 2 - masm.add(32, index, index, 2); - + // int index = 1; + masm.mov(index, 1); masm.cmp(32, index, cnt1); - masm.branchConditionally(ConditionFlag.LO, labelShortUnrolledLoopBegin); - - // } - // if (i >= cnt1) { - masm.bind(labelShortUnrolledLoopExit); - // masm.cmp(32, index, cnt1); // already compared right above and before the jump here - masm.branchConditionally(ConditionFlag.HI, labelEnd); - // result *= 31; - // result += ary1[index - 1] - masm.mov(tmp31, 31); - arraysHashcodeElload(masm, tmp3, postIndexAddr, arrayKind); // index-1 - masm.madd(32, result, result, tmp31, tmp3); - // } + masm.branchConditionally(ConditionFlag.HS, labelShortUnrolledLoopExit); + try (var scratch1 = masm.getScratchRegister(); var scratch2 = masm.getScratchRegister()) { + var tmp31 = scratch1.getRegister(); + var tmp961 = scratch2.getRegister(); + masm.mov(tmp31, 31); + masm.mov(tmp961, 961); + + shortUnrolledLoop: { // for (; index < cnt1; index += 2) { + Label labelShortUnrolledLoopBegin = new Label(); + masm.align(AArch64MacroAssembler.PREFERRED_LOOP_ALIGNMENT); + masm.bind(labelShortUnrolledLoopBegin); + + // result *= 31**2; + // result += ary1[index-1] * 31 + ary1[index] + arraysHashcodeElload(masm, tmp2, postIndexAddr, arrayKind); // index-1 + arraysHashcodeElload(masm, tmp3, postIndexAddr, arrayKind); // index + masm.madd(32, tmp3, tmp2, tmp31, tmp3); + masm.madd(32, result, result, tmp961, tmp3); + // i += 2 + masm.add(32, index, index, 2); + + masm.cmp(32, index, cnt1); + masm.branchConditionally(ConditionFlag.LO, labelShortUnrolledLoopBegin); + } + + // if (index >= cnt1) { + masm.bind(labelShortUnrolledLoopExit); + // already compared right above and before the jump here, no need to repeat: + // masm.cmp(32, index, cnt1); + masm.branchConditionally(ConditionFlag.HI, labelEnd); + lastElementBranch: { // if (index == cnt1) { + // result *= 31; + // result += ary1[index - 1] + masm.mov(tmp31, 31); + arraysHashcodeElload(masm, tmp3, postIndexAddr, arrayKind); // index-1 + masm.madd(32, result, result, tmp31, tmp3); + } + } } masm.bind(labelEnd); } From 51b470a83844fb9d024ea0df7b0f823b8b6ca875 Mon Sep 17 00:00:00 2001 From: Andreas Woess Date: Wed, 13 Dec 2023 19:06:07 +0100 Subject: [PATCH 199/593] Rephrase comment. --- .../compiler/lir/amd64/AMD64VectorizedHashCodeOp.java | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/amd64/AMD64VectorizedHashCodeOp.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/amd64/AMD64VectorizedHashCodeOp.java index 182acde59ba7..552aca6bfd70 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/amd64/AMD64VectorizedHashCodeOp.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/amd64/AMD64VectorizedHashCodeOp.java @@ -334,8 +334,12 @@ public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) { masm.bind(labelUnrolledVectorLoopBegin); // result *= next; masm.imull(result, next); - // loop fission to upfront the cost of fetching from memory, OOO execution - // can then hopefully do a better job of prefetching + /* + * Load the next 32 data elements into 4 vector registers. By grouping the loads and + * fetching from memory up front (loop fission), out-of-order execution can hopefully do a + * better job of prefetching, while also allowing subsequent instructions to be executed + * while data are still being fetched. + */ for (int idx = 0; idx < 4; idx++) { loadVector(masm, vtmp[idx], new AMD64Address(ary1, index, stride, 8 * idx * elsize), elsize * 8); } From 0477be9ab0e0e9c3a1bc5c6a7e2a4c5c94e82d78 Mon Sep 17 00:00:00 2001 From: Cosmin Basca Date: Thu, 14 Dec 2023 00:37:56 +0000 Subject: [PATCH 200/593] [GR-21590] update imports. PullRequest: graalpython/3101 --- vm/mx.vm/suite.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vm/mx.vm/suite.py b/vm/mx.vm/suite.py index e2e62577e788..4a31dacf5fdb 100644 --- a/vm/mx.vm/suite.py +++ b/vm/mx.vm/suite.py @@ -65,7 +65,7 @@ }, { "name": "graalpython", - "version": "868076dbd9d86080d86966f55b21831807cd35f0", + "version": "b997a4beb1392e459502712ffa7cdd8f227dc1b4", "dynamic": True, "urls": [ {"url": "https://github.com/graalvm/graalpython.git", "kind": "git"}, From 4ae5d1eb6d63f84b942cccb1ba755e55b5ca6b06 Mon Sep 17 00:00:00 2001 From: Josef Eisl Date: Thu, 14 Dec 2023 08:47:24 +0100 Subject: [PATCH 201/593] ci: remove labsjdk-*-22 entries --- common.json | 8 -------- 1 file changed, 8 deletions(-) diff --git a/common.json b/common.json index 561adcf2abff..37d8ee191165 100644 --- a/common.json +++ b/common.json @@ -44,14 +44,6 @@ "labsjdk-ee-21Debug": {"name": "labsjdk", "version": "ee-21.0.1+11-jvmci-23.1-b26-debug", "platformspecific": true }, "labsjdk-ee-21-llvm": {"name": "labsjdk", "version": "ee-21.0.1+11-jvmci-23.1-b26-sulong", "platformspecific": true }, - "oraclejdk22": {"name": "jpg-jdk", "version": "22", "build_id": "27", "release": true, "platformspecific": true, "extrabundles": ["static-libs"]}, - "labsjdk-ce-22": {"name": "labsjdk", "version": "ce-22+27-jvmci-b01", "platformspecific": true }, - "labsjdk-ce-22Debug": {"name": "labsjdk", "version": "ce-22+27-jvmci-b01-debug", "platformspecific": true }, - "labsjdk-ce-22-llvm": {"name": "labsjdk", "version": "ce-22+27-jvmci-b01-sulong", "platformspecific": true }, - "labsjdk-ee-22": {"name": "labsjdk", "version": "ee-22+27-jvmci-b01", "platformspecific": true }, - "labsjdk-ee-22Debug": {"name": "labsjdk", "version": "ee-22+27-jvmci-b01-debug", "platformspecific": true }, - "labsjdk-ee-22-llvm": {"name": "labsjdk", "version": "ee-22+27-jvmci-b01-sulong", "platformspecific": true }, - "oraclejdk-latest": {"name": "jpg-jdk", "version": "23", "build_id": "1", "release": true, "platformspecific": true, "extrabundles": ["static-libs"]}, "labsjdk-ce-latest": {"name": "labsjdk", "version": "ce-23+1-jvmci-b01-20231213123324-6bfc73c47c", "platformspecific": true }, "labsjdk-ce-latestDebug": {"name": "labsjdk", "version": "ce-23+1-jvmci-b01-20231213123324-6bfc73c47c-debug", "platformspecific": true }, From e18d04e756a5815e8e6989dc8ff0ce58da36146b Mon Sep 17 00:00:00 2001 From: Josef Eisl Date: Thu, 14 Dec 2023 08:47:46 +0100 Subject: [PATCH 202/593] compiler: remove JDK 22 from JVMCIVersionCheck --- .../src/jdk/graal/compiler/hotspot/JVMCIVersionCheck.java | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/JVMCIVersionCheck.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/JVMCIVersionCheck.java index a69363869238..096962ee1485 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/JVMCIVersionCheck.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/JVMCIVersionCheck.java @@ -53,13 +53,9 @@ public final class JVMCIVersionCheck { */ private static final Map> JVMCI_MIN_VERSIONS = Map.of( "21", Map.of(DEFAULT_VENDOR_ENTRY, new Version(23, 1, 26)), - "22", Map.of( - "Oracle Corporation", new Version("22+27", 1), - DEFAULT_VENDOR_ENTRY, new Version("22+27", 1)), "23", Map.of( "Oracle Corporation", new Version("23+1", 1), - DEFAULT_VENDOR_ENTRY, new Version("23+1", 1)) - ); + DEFAULT_VENDOR_ENTRY, new Version("23+1", 1))); private static final int NA = 0; /** * Minimum Java release supported by Graal. From 450e48c2e26c96efb76771e2befaa48ab88d37ad Mon Sep 17 00:00:00 2001 From: Christian Haeubl Date: Wed, 13 Dec 2023 16:36:24 +0100 Subject: [PATCH 203/593] For JIT compiled code that is on the stack, only walk the tether. --- .../com/oracle/svm/core/genscavenge/GCImpl.java | 11 ++++------- .../svm/core/code/RuntimeCodeInfoAccess.java | 15 +++++++++++++++ 2 files changed, 19 insertions(+), 7 deletions(-) diff --git a/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/GCImpl.java b/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/GCImpl.java index 1ec895dbb792..0bfc16bfd4a7 100644 --- a/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/GCImpl.java +++ b/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/GCImpl.java @@ -875,14 +875,11 @@ private void walkStack(JavaStackWalk walk) { if (RuntimeCompilation.isEnabled() && codeInfo != CodeInfoTable.getImageCodeInfo()) { /* - * For runtime-compiled code that is currently on the stack, we need to treat all - * the references to Java heap objects as strong references. It is important that we - * really walk *all* those references here. Otherwise, RuntimeCodeCacheWalker might - * decide to invalidate too much code, depending on the order in which the CodeInfo - * objects are visited. + * Runtime-compiled code that is currently on the stack must be kept alive. So, we + * mark the tether as strongly reachable. The RuntimeCodeCacheWalker will handle all + * other object references later on. */ - RuntimeCodeInfoAccess.walkStrongReferences(codeInfo, greyToBlackObjRefVisitor); - RuntimeCodeInfoAccess.walkWeakReferences(codeInfo, greyToBlackObjRefVisitor); + RuntimeCodeInfoAccess.walkTether(codeInfo, greyToBlackObjRefVisitor); } if (!JavaStackWalker.continueWalk(walk, queryResult, deoptFrame)) { diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/code/RuntimeCodeInfoAccess.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/code/RuntimeCodeInfoAccess.java index e27a627fe3f6..334672f9fc6a 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/code/RuntimeCodeInfoAccess.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/code/RuntimeCodeInfoAccess.java @@ -179,6 +179,21 @@ public static boolean walkWeakReferences(CodeInfo info, ObjectReferenceVisitor v return continueVisiting; } + /** + * This method only walks the tether. You typically want to use {@link #walkStrongReferences} + * and/or {@link #walkWeakReferences} instead. + */ + @Uninterruptible(reason = "Called from uninterruptible code.", mayBeInlined = true) + public static boolean walkTether(CodeInfo info, ObjectReferenceVisitor visitor) { + Pointer address = NonmovableArrays.addressOf(cast(info).getObjectFields(), CodeInfoImpl.TETHER_OBJFIELD); + return callVisitor(visitor, address); + } + + @Uninterruptible(reason = "Bridge between uninterruptible and potentially interruptible code.", mayBeInlined = true, calleeMustBe = false) + private static boolean callVisitor(ObjectReferenceVisitor visitor, Pointer address) { + return visitor.visitObjectReference(address, true, null); + } + /** * This method only visits a very specific subset of all the references, so you typically want * to use {@link #walkStrongReferences} and/or {@link #walkWeakReferences} instead. From c64f5b39a3d0940c46629197c4e68e46e171d091 Mon Sep 17 00:00:00 2001 From: Josef Eisl Date: Thu, 14 Dec 2023 10:53:03 +0100 Subject: [PATCH 204/593] compiler: do not look at JDK_BUILD in GraalHotSpotVMConfig --- .../compiler/hotspot/GraalHotSpotVMConfig.java | 14 +++++++------- .../hotspot/GraalHotSpotVMConfigAccess.java | 2 -- 2 files changed, 7 insertions(+), 9 deletions(-) diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/GraalHotSpotVMConfig.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/GraalHotSpotVMConfig.java index 0f186e831211..e3fcd487cd36 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/GraalHotSpotVMConfig.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/GraalHotSpotVMConfig.java @@ -129,9 +129,9 @@ private HotSpotGraalRuntime.HotSpotGC getSelectedGC() throws GraalError { // of the mark word. public final int lockingMode = getFlag("LockingMode", Integer.class); - public final int lockingModeMonitor = getConstant("LockingMode::LM_MONITOR", Integer.class, 0, JDK >= 22 && JDK_BUILD >= 18); - public final int lockingModeStack = getConstant("LockingMode::LM_LEGACY", Integer.class, 1, JDK >= 22 && JDK_BUILD >= 18); - public final int lockingModeLightweight = getConstant("LockingMode::LM_LIGHTWEIGHT", Integer.class, 2, JDK >= 22 && JDK_BUILD >= 18); + public final int lockingModeMonitor = getConstant("LockingMode::LM_MONITOR", Integer.class, 0, JDK >= 22); + public final int lockingModeStack = getConstant("LockingMode::LM_LEGACY", Integer.class, 1, JDK >= 22); + public final int lockingModeLightweight = getConstant("LockingMode::LM_LIGHTWEIGHT", Integer.class, 2, JDK >= 22); public final boolean foldStableValues = getFlag("FoldStableValues", Boolean.class); public final int maxVectorSize = getFlag("MaxVectorSize", Integer.class); @@ -350,7 +350,7 @@ public int threadLastJavaFpOffset() { public final int objectMonitorEntryList = getFieldOffset("ObjectMonitor::_EntryList", Integer.class, "ObjectWaiter*"); public final int objectMonitorSucc = getFieldOffset("ObjectMonitor::_succ", Integer.class, "JavaThread*"); - public final long objectMonitorAnonymousOwner = getConstant("ObjectMonitor::ANONYMOUS_OWNER", Long.class, 1L, JDK >= 22 && JDK_BUILD >= 18); + public final long objectMonitorAnonymousOwner = getConstant("ObjectMonitor::ANONYMOUS_OWNER", Long.class, 1L, JDK >= 22); public final int markWordNoHashInPlace = getConstant("markWord::no_hash_in_place", Integer.class); public final int markWordNoLockInPlace = getConstant("markWord::no_lock_in_place", Integer.class); @@ -598,9 +598,9 @@ private long getZGCAddressField(String name) { // Tracking of the number of monitors held by the current thread. This is used by loom but in // JDK 20 was enabled by default to ensure it was correctly implemented. public final int threadHeldMonitorCountOffset = getFieldOffset("JavaThread::_held_monitor_count", Integer.class, JDK >= 22 ? "intx" : "int64_t"); - public final int threadLockStackOffset = getFieldOffset("JavaThread::_lock_stack", Integer.class, "LockStack", -1, JDK >= 22 && JDK_BUILD >= 18); - public final int lockStackTopOffset = getFieldOffset("LockStack::_top", Integer.class, "uint32_t", -1, JDK >= 22 && JDK_BUILD >= 18); - public final int lockStackEndOffset = getConstant("LockStack::_end_offset", Integer.class, -1, JDK >= 22 && JDK_BUILD >= 18); + public final int threadLockStackOffset = getFieldOffset("JavaThread::_lock_stack", Integer.class, "LockStack", -1, JDK >= 22); + public final int lockStackTopOffset = getFieldOffset("LockStack::_top", Integer.class, "uint32_t", -1, JDK >= 22); + public final int lockStackEndOffset = getConstant("LockStack::_end_offset", Integer.class, -1, JDK >= 22); public final long throwAndPostJvmtiExceptionAddress = getAddress("JVMCIRuntime::throw_and_post_jvmti_exception"); public final long throwKlassExternalNameExceptionAddress = getAddress("JVMCIRuntime::throw_klass_external_name_exception"); diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/GraalHotSpotVMConfigAccess.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/GraalHotSpotVMConfigAccess.java index 6ce3cce83510..d3ffa824f76f 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/GraalHotSpotVMConfigAccess.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/GraalHotSpotVMConfigAccess.java @@ -37,7 +37,6 @@ import java.util.stream.Collectors; import jdk.graal.compiler.debug.Assertions; - import jdk.vm.ci.common.JVMCIError; import jdk.vm.ci.hotspot.HotSpotVMConfigAccess; import jdk.vm.ci.hotspot.HotSpotVMConfigStore; @@ -114,7 +113,6 @@ public static boolean jvmciGE(JVMCIVersionCheck.Version v) { } public static final int JDK = Runtime.version().feature(); - public static final int JDK_BUILD = Runtime.version().build().orElse(0); public static final JVMCIVersionCheck.Version JVMCI_VERSION; public static final boolean JVMCI; public static final boolean JDK_PRERELEASE; From 6de718fc93971b7c5d593ce391c7314380b493df Mon Sep 17 00:00:00 2001 From: Josef Eisl Date: Thu, 14 Dec 2023 10:57:32 +0100 Subject: [PATCH 205/593] svm: new JDK versions should by default use the same graal flags as JDK 21 --- substratevm/mx.substratevm/mx_substratevm.py | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/substratevm/mx.substratevm/mx_substratevm.py b/substratevm/mx.substratevm/mx_substratevm.py index 5f0929ff3c71..9f1bb2bb213f 100644 --- a/substratevm/mx.substratevm/mx_substratevm.py +++ b/substratevm/mx.substratevm/mx_substratevm.py @@ -1910,12 +1910,17 @@ def compute_graal_compiler_flags_map(self): required_exports = mx_javamodules.requiredExports(distributions_transitive, get_jdk()) exports_flags = mx_sdk_vm.AbstractNativeImageConfig.get_add_exports_list(required_exports) - graal_compiler_flags_map['21'] = exports_flags - # Currently JDK 22 has the same flags - graal_compiler_flags_map['22'] = graal_compiler_flags_map['21'] + min_version = 21 + graal_compiler_flags_map[str(min_version)] = exports_flags + + feature_version = get_jdk().javaCompliance.value + if str(feature_version) not in graal_compiler_flags_map and feature_version > min_version: + # Unless specified otherwise, newer JDK versions use the same flags as JDK 21 + graal_compiler_flags_map[str(feature_version)] = graal_compiler_flags_map[str(min_version)] + # DO NOT ADD ANY NEW ADD-OPENS OR ADD-EXPORTS HERE! # - # Instead provide the correct requiresConcealed entries in the moduleInfo + # Instead, provide the correct requiresConcealed entries in the moduleInfo # section of org.graalvm.nativeimage.builder in the substratevm suite.py. graal_compiler_flags_base = [ From c0568400425b835eeb1f92b39dd8c21679e63cb7 Mon Sep 17 00:00:00 2001 From: Loic Ottet Date: Thu, 14 Dec 2023 11:03:10 +0100 Subject: [PATCH 206/593] Respect link-at-build-time on reflective linkage errors --- .../hosted/reflect/ReflectionDataBuilder.java | 25 +++++++++++++------ 1 file changed, 17 insertions(+), 8 deletions(-) diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/reflect/ReflectionDataBuilder.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/reflect/ReflectionDataBuilder.java index 5577a361dfa5..ddbff63a6361 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/reflect/ReflectionDataBuilder.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/reflect/ReflectionDataBuilder.java @@ -85,6 +85,7 @@ import com.oracle.svm.core.util.VMError; import com.oracle.svm.hosted.ConditionalConfigurationRegistry; import com.oracle.svm.hosted.FeatureImpl.BeforeAnalysisAccessImpl; +import com.oracle.svm.hosted.LinkAtBuildTimeSupport; import com.oracle.svm.hosted.annotation.AnnotationMemberValue; import com.oracle.svm.hosted.annotation.AnnotationValue; import com.oracle.svm.hosted.annotation.SubstrateAnnotationExtractor; @@ -195,7 +196,7 @@ public void registerAllClassesQuery(ConfigurationCondition condition, Class c registerClass(innerClass, false, !MissingRegistrationUtils.throwMissingRegistrationErrors()); } } catch (LinkageError e) { - classLookupExceptions.put(clazz, e); + registerLinkageError(clazz, e, classLookupExceptions); } } @@ -209,7 +210,7 @@ public void registerAllDeclaredClassesQuery(ConfigurationCondition condition, Cl registerClass(innerClass, false, !MissingRegistrationUtils.throwMissingRegistrationErrors()); } } catch (LinkageError e) { - classLookupExceptions.put(clazz, e); + registerLinkageError(clazz, e, classLookupExceptions); } } @@ -332,7 +333,7 @@ public void registerAllMethodsQuery(ConfigurationCondition condition, boolean qu try { register(condition, queriedOnly, clazz.getMethods()); } catch (LinkageError e) { - methodLookupExceptions.put(clazz, e); + registerLinkageError(clazz, e, methodLookupExceptions); } } @@ -343,7 +344,7 @@ public void registerAllDeclaredMethodsQuery(ConfigurationCondition condition, bo try { register(condition, queriedOnly, clazz.getDeclaredMethods()); } catch (LinkageError e) { - methodLookupExceptions.put(clazz, e); + registerLinkageError(clazz, e, methodLookupExceptions); } } @@ -357,7 +358,7 @@ public void registerAllConstructorsQuery(ConfigurationCondition condition, boole try { register(condition, queriedOnly, clazz.getConstructors()); } catch (LinkageError e) { - constructorLookupExceptions.put(clazz, e); + registerLinkageError(clazz, e, constructorLookupExceptions); } } @@ -368,7 +369,7 @@ public void registerAllDeclaredConstructorsQuery(ConfigurationCondition conditio try { register(condition, queriedOnly, clazz.getDeclaredConstructors()); } catch (LinkageError e) { - constructorLookupExceptions.put(clazz, e); + registerLinkageError(clazz, e, constructorLookupExceptions); } } @@ -465,7 +466,7 @@ public void registerAllFieldsQuery(ConfigurationCondition condition, Class cl try { registerInternal(condition, clazz.getFields()); } catch (LinkageError e) { - fieldLookupExceptions.put(clazz, e); + registerLinkageError(clazz, e, fieldLookupExceptions); } } @@ -476,7 +477,7 @@ public void registerAllDeclaredFieldsQuery(ConfigurationCondition condition, Cla try { registerInternal(condition, clazz.getDeclaredFields()); } catch (LinkageError e) { - fieldLookupExceptions.put(clazz, e); + registerLinkageError(clazz, e, fieldLookupExceptions); } } @@ -939,6 +940,14 @@ private void maybeRegisterRecordComponents(Class clazz) { } } + private void registerLinkageError(Class clazz, LinkageError error, Map, Throwable> errorMap) { + if (LinkAtBuildTimeSupport.singleton().linkAtBuildTime(clazz)) { + throw error; + } else { + errorMap.put(clazz, error); + } + } + private static void reportLinkingErrors(Class clazz, List errors) { if (errors.isEmpty()) { return; From 82f32aa3fc97e17501321a93c9d12a978509edbf Mon Sep 17 00:00:00 2001 From: Boris Spasojevic Date: Thu, 14 Dec 2023 11:09:25 +0100 Subject: [PATCH 207/593] Don't add stats to statsList unless flag is set. --- .../oracle/svm/core/sampler/SafepointProfilingSampler.java | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/sampler/SafepointProfilingSampler.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/sampler/SafepointProfilingSampler.java index 883e51519f0c..de3e75ea6cf2 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/sampler/SafepointProfilingSampler.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/sampler/SafepointProfilingSampler.java @@ -29,6 +29,7 @@ import java.nio.file.Files; import java.nio.file.Path; import java.util.ArrayList; +import java.util.Collections; import java.util.List; import java.util.LongSummaryStatistics; import java.util.concurrent.TimeUnit; @@ -58,7 +59,7 @@ static class Options { private final SamplingStackVisitor samplingStackVisitor = new SamplingStackVisitor(); private final LockFreePrefixTree prefixTree = new LockFreePrefixTree(new LockFreePrefixTree.ObjectPoolingAllocator()); - private final List statsList = new ArrayList<>(); + private final List statsList = Collections.synchronizedList(new ArrayList<>()); @Platforms(Platform.HOSTED_ONLY.class) public SafepointProfilingSampler() { @@ -88,7 +89,9 @@ public SafepointProfilingSampler() { public void beforeThreadRun() { SamplingStackVisitor.StackTrace stackTrace = new SamplingStackVisitor.StackTrace(DEFAULT_STACK_SIZE); SamplerStats samplerStats = new SamplerStats(); - statsList.add(samplerStats); + if (Options.SafepointSamplerStats.hasBeenSet()) { + statsList.add(samplerStats); + } Threading.registerRecurringCallback(10, TimeUnit.MILLISECONDS, access -> sampleThreadStack(stackTrace, samplerStats)); } From 1bce1dd26246480b1612938ce4508494af9396ef Mon Sep 17 00:00:00 2001 From: ol-automation_ww Date: Thu, 14 Dec 2023 10:37:25 +0000 Subject: [PATCH 208/593] [GR-23997] Periodic update of the graal import (2023-12-08). PullRequest: js/3004 --- vm/mx.vm/suite.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/vm/mx.vm/suite.py b/vm/mx.vm/suite.py index 4a31dacf5fdb..d0afebacff39 100644 --- a/vm/mx.vm/suite.py +++ b/vm/mx.vm/suite.py @@ -33,7 +33,7 @@ "name": "graal-nodejs", "subdir": True, "dynamic": True, - "version": "0cc93fec5a8962911a7a314f7a9a47505dac570e", + "version": "861b6828eccc81abaee684a04c6899d64d39cba6", "urls" : [ {"url" : "https://github.com/graalvm/graaljs.git", "kind" : "git"}, ] @@ -42,7 +42,7 @@ "name": "graal-js", "subdir": True, "dynamic": True, - "version": "0cc93fec5a8962911a7a314f7a9a47505dac570e", + "version": "861b6828eccc81abaee684a04c6899d64d39cba6", "urls": [ {"url": "https://github.com/graalvm/graaljs.git", "kind" : "git"}, ] From a1decd7695ebbca5b6b3fe51adf6afb5428e258d Mon Sep 17 00:00:00 2001 From: Josef Eisl Date: Thu, 14 Dec 2023 13:24:51 +0100 Subject: [PATCH 209/593] svm: handle JNI_VERSION_23 --- .../src/com/oracle/svm/core/jni/functions/JNIFunctions.java | 1 + .../oracle/svm/core/jni/headers/JNIVersionJDK22OrLater.java | 6 +++++- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jni/functions/JNIFunctions.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jni/functions/JNIFunctions.java index e6ef80ee0f37..cbfe7dc30e2d 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jni/functions/JNIFunctions.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jni/functions/JNIFunctions.java @@ -162,6 +162,7 @@ static int GetVersion(JNIEnvironment env) { case 21: return JNIVersion.JNI_VERSION_21(); case 22: + case 23: return JNIVersionJDK22OrLater.JNI_VERSION_22(); default: throw VMError.shouldNotReachHere("Unsupported Java version " + JavaVersionUtil.JAVA_SPEC); diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jni/headers/JNIVersionJDK22OrLater.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jni/headers/JNIVersionJDK22OrLater.java index 29f28a4c28ba..e6aebc8f91bf 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jni/headers/JNIVersionJDK22OrLater.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jni/headers/JNIVersionJDK22OrLater.java @@ -24,10 +24,11 @@ */ package com.oracle.svm.core.jni.headers; -import jdk.graal.compiler.serviceprovider.JavaVersionUtil; import org.graalvm.nativeimage.c.CContext; import org.graalvm.nativeimage.c.constant.CConstant; +import jdk.graal.compiler.serviceprovider.JavaVersionUtil; + final class JNIHeaderDirectivesJDK22OrLater extends JNIHeaderDirectives { @Override public boolean isInConfiguration() { @@ -43,6 +44,9 @@ public final class JNIVersionJDK22OrLater { /* * GR-48572: there is not yet a JNI_VERSION_22 constant defined. As soon as it gets available, * the "value" property of the CConstant annotation below must be removed. + * + * GR-50948: there is not yet a JNI_VERSION_23 constant defined. As soon as it gets available, + * the "value" property of the CConstant annotation below must be removed. */ @CConstant(value = "JNI_VERSION_21") public static native int JNI_VERSION_22(); From 468811f4a4a80ad426f9627e08625e4cb8cfbe97 Mon Sep 17 00:00:00 2001 From: Josef Eisl Date: Thu, 14 Dec 2023 13:25:21 +0100 Subject: [PATCH 210/593] compiler: accept JDK 23 classfile version --- .../jdk/graal/compiler/replacements/classfile/Classfile.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/replacements/classfile/Classfile.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/replacements/classfile/Classfile.java index 3d19e9a580ee..3799fd5a7ac6 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/replacements/classfile/Classfile.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/replacements/classfile/Classfile.java @@ -49,7 +49,7 @@ public class Classfile { private final List codeAttributes; private static final int MAJOR_VERSION_JAVA_MIN = 51; // JDK7 - private static final int MAJOR_VERSION_JAVA_MAX = 66; // JDK22 + private static final int MAJOR_VERSION_JAVA_MAX = 67; // JDK23 private static final int MAGIC = 0xCAFEBABE; /** From ad3843ebd2d61068fb8542cf94038f41efb8e7d9 Mon Sep 17 00:00:00 2001 From: Loic Ottet Date: Thu, 7 Dec 2023 16:29:54 +0100 Subject: [PATCH 211/593] Fix failure when no resource bundle nullary constructor is present --- .../jdk/localization/LocalizationSupport.java | 29 +++++++++++++------ 1 file changed, 20 insertions(+), 9 deletions(-) diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/localization/LocalizationSupport.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/localization/LocalizationSupport.java index 8fa7d1ad7779..fe2cb8dd2720 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/localization/LocalizationSupport.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/localization/LocalizationSupport.java @@ -115,13 +115,7 @@ public void prepareBundle(String bundleName, ResourceBundle bundle, Function nullaryConstructor = bundle.getClass().getDeclaredConstructor(); - RuntimeReflection.register(nullaryConstructor); - } catch (NoSuchMethodException e) { - RuntimeReflection.registerConstructorLookup(bundle.getClass()); - } + registerNullaryConstructor(bundle.getClass()); } /* Property-based bundle lookup happens only if class-based lookup fails */ @@ -258,8 +252,25 @@ public static Locale parseLocaleFromTag(String tag) { } public void prepareClassResourceBundle(@SuppressWarnings("unused") String basename, Class bundleClass) { - RuntimeReflection.register(bundleClass); - RuntimeReflection.registerForReflectiveInstantiation(bundleClass); + registerNullaryConstructor(bundleClass); onClassBundlePrepared(bundleClass); } + + /** + * Bundle lookup code tries to reflectively access the default constructor of candidate bundle + * classes, and then tries to invoke them if they exist. We therefore need to register the + * default constructor as invoked if it exists, and as queried if it doesn't, which we know will + * result in a negative query. + */ + private void registerNullaryConstructor(Class bundleClass) { + RuntimeReflection.register(bundleClass); + Constructor nullaryConstructor; + try { + nullaryConstructor = bundleClass.getDeclaredConstructor(); + } catch (NoSuchMethodException e) { + RuntimeReflection.registerConstructorLookup(bundleClass); + return; + } + RuntimeReflection.register(nullaryConstructor); + } } From 01cc90725363a5fdebc7b88100b49e05ec9b55a3 Mon Sep 17 00:00:00 2001 From: Carlo Refice Date: Thu, 14 Dec 2023 14:23:49 +0100 Subject: [PATCH 212/593] Increase thread stack size for renaissance benchmarks on all configurations --- .../mx.java-benchmarks/mx_java_benchmarks.py | 20 ++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/java-benchmarks/mx.java-benchmarks/mx_java_benchmarks.py b/java-benchmarks/mx.java-benchmarks/mx_java_benchmarks.py index e2ef50afe467..40b18f2b3c73 100644 --- a/java-benchmarks/mx.java-benchmarks/mx_java_benchmarks.py +++ b/java-benchmarks/mx.java-benchmarks/mx_java_benchmarks.py @@ -2012,8 +2012,26 @@ def createCommandLineArgs(self, benchmarks, bmSuiteArgs): mx.abort("Must specify at least one benchmark.") else: benchArg = ",".join(benchmarks) + + vmArgs = self.vmArgs(bmSuiteArgs) + sparkBenchmarks = set([ + "als", + "chi-square", + "dec-tree", + "gauss-mix", + "log-regression", + "movie-lens", + "naive-bayes", + "page-rank", + ]) + + if any(benchmark in sparkBenchmarks for benchmark in benchmarks): + # Spark benchmarks require a higher stack size than default in some configurations. + # [JDK-8303076] [GR-44499] [GR-50671] + vmArgs.append("-Xss1090k") + runArgs = self.postprocessRunArgs(benchmarks[0], self.runArgs(bmSuiteArgs)) - return (self.vmArgs(bmSuiteArgs) + ["-jar", self.renaissancePath()] + runArgs + [benchArg]) + return (vmArgs + ["-jar", self.renaissancePath()] + runArgs + [benchArg]) def benchmarkList(self, bmSuiteArgs): return [b for b, it in self.renaissanceIterations().items() if it != -1] From f4bc6466441242cfc468745c806f56a3568bf327 Mon Sep 17 00:00:00 2001 From: Danilo Ansaloni Date: Thu, 14 Dec 2023 18:56:46 +0100 Subject: [PATCH 213/593] Fix exclusion of files from standalone dependencies. --- wasm/mx.wasm/mx_wasm.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/wasm/mx.wasm/mx_wasm.py b/wasm/mx.wasm/mx_wasm.py index 5ad66fba05eb..0f2b1d06abd4 100644 --- a/wasm/mx.wasm/mx_wasm.py +++ b/wasm/mx.wasm/mx_wasm.py @@ -535,7 +535,7 @@ def clean(self, forBuild=False): }, standalone_dependencies_enterprise={ 'gwal': ('', []), # GraalWasm license files - 'GraalVM enterprise license files': ('LICENSE.txt', ['GRAALVM-README.md']), + 'GraalVM enterprise license files': ('', ['LICENSE.txt', 'GRAALVM-README.md']), }, license_files=[], third_party_license_files=[], From e1fded1fcb2c5975c0cbd09a6dc4883b4458852d Mon Sep 17 00:00:00 2001 From: Danilo Ansaloni Date: Thu, 14 Dec 2023 18:59:57 +0100 Subject: [PATCH 214/593] Add a command that prints the type of GraalVM artifacts. Snapshot or release. --- sdk/mx.sdk/mx_sdk_vm_impl.py | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/sdk/mx.sdk/mx_sdk_vm_impl.py b/sdk/mx.sdk/mx_sdk_vm_impl.py index 0b89c498f84d..7089d22044dc 100644 --- a/sdk/mx.sdk/mx_sdk_vm_impl.py +++ b/sdk/mx.sdk/mx_sdk_vm_impl.py @@ -4106,6 +4106,12 @@ def print_standalone_home(args): print(standalone_home(args.comp_dir_name, is_jvm=(args.type == 'jvm'))) +def print_graalvm_type(args): + """print the GraalVM artifact type""" + # Required by the CI jsonnet files that trigger structure checks + print('release' if _suite.is_release() else 'snapshot') + + def _infer_env(graalvm_dist): dynamicImports = set() components = [] @@ -4917,6 +4923,7 @@ def mx_post_parse_cmd_line(args): 'graalvm-dist-name': [print_graalvm_dist_name, ''], 'graalvm-version': [print_graalvm_version, ''], 'graalvm-home': [print_graalvm_home, ''], + 'graalvm-type': [print_graalvm_type, ''], 'graalvm-enter': [graalvm_enter, ''], 'graalvm-show': [graalvm_show, ''], 'graalvm-vm-name': [print_graalvm_vm_name, ''], From d31fb93d6c25a0844b678ff80d75280371d925ff Mon Sep 17 00:00:00 2001 From: Christian Wimmer Date: Thu, 14 Dec 2023 13:46:15 -0800 Subject: [PATCH 215/593] Introduce ReflectionSubstitutionSupport.singleton() --- .../src/com/oracle/svm/core/jdk/VarHandleFeature.java | 2 +- .../core/reflect/target/ExecutableAccessorComputer.java | 3 +-- .../svm/core/reflect/target/FieldOffsetComputer.java | 4 +--- .../core/reflect/target/ReflectionSubstitutionSupport.java | 7 +++++++ .../reflect/target/Target_java_lang_reflect_Field.java | 2 +- .../src/com/oracle/svm/truffle/TruffleBaseFeature.java | 6 +++--- 6 files changed, 14 insertions(+), 10 deletions(-) diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/VarHandleFeature.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/VarHandleFeature.java index 92191bebe238..9e74855377c7 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/VarHandleFeature.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/VarHandleFeature.java @@ -251,7 +251,7 @@ public ValueAvailability valueAvailability() { @Override public Object transform(Object receiver, Object originalValue) { Field field = ImageSingletons.lookup(VarHandleFeature.class).findVarHandleField(receiver); - int offset = ImageSingletons.lookup(ReflectionSubstitutionSupport.class).getFieldOffset(field, true); + int offset = ReflectionSubstitutionSupport.singleton().getFieldOffset(field, true); if (offset <= 0) { throw VMError.shouldNotReachHere("Field is not marked as unsafe accessed: " + field); } diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/reflect/target/ExecutableAccessorComputer.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/reflect/target/ExecutableAccessorComputer.java index c4093cf3ec9e..782f967a9819 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/reflect/target/ExecutableAccessorComputer.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/reflect/target/ExecutableAccessorComputer.java @@ -26,7 +26,6 @@ import java.lang.reflect.Executable; -import org.graalvm.nativeimage.ImageSingletons; import org.graalvm.nativeimage.hosted.FieldValueTransformer; import com.oracle.svm.core.annotate.RecomputeFieldValue; @@ -40,6 +39,6 @@ public final class ExecutableAccessorComputer implements FieldValueTransformer { @Override public Object transform(Object receiver, Object originalValue) { - return ImageSingletons.lookup(ReflectionSubstitutionSupport.class).getOrCreateAccessor((Executable) receiver); + return ReflectionSubstitutionSupport.singleton().getOrCreateAccessor((Executable) receiver); } } diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/reflect/target/FieldOffsetComputer.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/reflect/target/FieldOffsetComputer.java index 25a921c6d472..cffd02e1b145 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/reflect/target/FieldOffsetComputer.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/reflect/target/FieldOffsetComputer.java @@ -26,8 +26,6 @@ import java.lang.reflect.Field; -import org.graalvm.nativeimage.ImageSingletons; - import com.oracle.svm.core.fieldvaluetransformer.FieldValueTransformerWithAvailability; public class FieldOffsetComputer implements FieldValueTransformerWithAvailability { @@ -39,6 +37,6 @@ public ValueAvailability valueAvailability() { @Override public Object transform(Object receiver, Object originalValue) { - return ImageSingletons.lookup(ReflectionSubstitutionSupport.class).getFieldOffset((Field) receiver, true); + return ReflectionSubstitutionSupport.singleton().getFieldOffset((Field) receiver, true); } } diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/reflect/target/ReflectionSubstitutionSupport.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/reflect/target/ReflectionSubstitutionSupport.java index ca9719de5884..75833e9f31ad 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/reflect/target/ReflectionSubstitutionSupport.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/reflect/target/ReflectionSubstitutionSupport.java @@ -27,10 +27,17 @@ import java.lang.reflect.Executable; import java.lang.reflect.Field; +import org.graalvm.nativeimage.ImageSingletons; + import com.oracle.svm.core.annotate.Delete; import com.oracle.svm.core.reflect.SubstrateAccessor; public interface ReflectionSubstitutionSupport { + + static ReflectionSubstitutionSupport singleton() { + return ImageSingletons.lookup(ReflectionSubstitutionSupport.class); + } + SubstrateAccessor getOrCreateAccessor(Executable member); /** Offset of the field or -1 if the field was not registered for unsafe access. */ diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/reflect/target/Target_java_lang_reflect_Field.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/reflect/target/Target_java_lang_reflect_Field.java index 05385d4c63ab..859d73ad5d42 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/reflect/target/Target_java_lang_reflect_Field.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/reflect/target/Target_java_lang_reflect_Field.java @@ -133,7 +133,7 @@ public ValueAvailability valueAvailability() { @Override public Object transform(Object receiver, Object originalValue) { - return ImageSingletons.lookup(ReflectionSubstitutionSupport.class).getDeletionReason((Field) receiver); + return ReflectionSubstitutionSupport.singleton().getDeletionReason((Field) receiver); } } diff --git a/substratevm/src/com.oracle.svm.truffle/src/com/oracle/svm/truffle/TruffleBaseFeature.java b/substratevm/src/com.oracle.svm.truffle/src/com/oracle/svm/truffle/TruffleBaseFeature.java index a91e7eef28d0..c9ee3819b84b 100644 --- a/substratevm/src/com.oracle.svm.truffle/src/com/oracle/svm/truffle/TruffleBaseFeature.java +++ b/substratevm/src/com.oracle.svm.truffle/src/com/oracle/svm/truffle/TruffleBaseFeature.java @@ -1412,7 +1412,7 @@ public ValueAvailability valueAvailability() { public Object transform(Object receiver, Object originalValue) { Class generatedStorageClass = ReflectionUtil.readField(SHAPE_GENERATOR, "generatedStorageClass", receiver); Field field = ReflectionUtil.lookupField(generatedStorageClass, storageClassFieldName); - int offset = ImageSingletons.lookup(ReflectionSubstitutionSupport.class).getFieldOffset(field, false); + int offset = ReflectionSubstitutionSupport.singleton().getFieldOffset(field, false); if (offset <= 0) { throw VMError.shouldNotReachHere("Field is not marked as accessed: " + field); } @@ -1537,7 +1537,7 @@ public Object transform(Object receiver, Object originalValue) { Class declaringClass = ReflectionUtil.readField(receiver.getClass(), "declaringClass", receiver); String name = ReflectionUtil.readField(receiver.getClass(), "name", receiver); Field field = ReflectionUtil.lookupField(declaringClass, name); - int offset = ImageSingletons.lookup(ReflectionSubstitutionSupport.class).getFieldOffset(field, false); + int offset = ReflectionSubstitutionSupport.singleton().getFieldOffset(field, false); if (offset <= 0) { throw VMError.shouldNotReachHere("Field is not marked as accessed: " + field); } @@ -1569,7 +1569,7 @@ public Object transform(Object receiver, Object originalValue) { Class declaringClass = ReflectionUtil.readField(InlinableField.class.getSuperclass(), "declaringClass", receiver); String name = ReflectionUtil.readField(InlinableField.class.getSuperclass(), "name", receiver); Field field = ReflectionUtil.lookupField(declaringClass, name); - int offset = ImageSingletons.lookup(ReflectionSubstitutionSupport.class).getFieldOffset(field, false); + int offset = ReflectionSubstitutionSupport.singleton().getFieldOffset(field, false); if (offset == -1) { throw VMError.shouldNotReachHere("Field is not marked as accessed: " + field); } From 74ec4f9d3136107745ca05b36c6f8fd3f04509ba Mon Sep 17 00:00:00 2001 From: Christian Wimmer Date: Wed, 11 Oct 2023 16:28:03 -0700 Subject: [PATCH 216/593] Remove ReadableJavaField.isValueAvailableBeforeAnalysis --- .../svm/hosted/ameta/ReadableJavaField.java | 16 +--------------- .../hosted/analysis/CustomTypeFieldHandler.java | 2 +- .../svm/hosted/substitute/AnnotatedField.java | 7 ++++--- .../hosted/substitute/ComputedValueField.java | 7 +------ .../svm/hosted/substitute/SubstitutionField.java | 2 +- 5 files changed, 8 insertions(+), 26 deletions(-) diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/ameta/ReadableJavaField.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/ameta/ReadableJavaField.java index 8d8588e0151c..4897acd7e99d 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/ameta/ReadableJavaField.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/ameta/ReadableJavaField.java @@ -26,8 +26,6 @@ import com.oracle.graal.pointsto.meta.AnalysisField; import com.oracle.graal.pointsto.util.GraalAccess; -import com.oracle.svm.core.BuildPhaseProvider; -import com.oracle.svm.core.fieldvaluetransformer.FieldValueTransformerWithAvailability.ValueAvailability; import com.oracle.svm.core.util.VMError; import com.oracle.svm.hosted.classinitialization.ClassInitializationSupport; import com.oracle.svm.hosted.meta.HostedField; @@ -95,19 +93,7 @@ static JavaConstant readFieldValue(ClassInitializationSupport classInitializatio JavaConstant readValue(ClassInitializationSupport classInitializationSupport, JavaConstant receiver); - /** - * When this method returns true, image heap snapshotting can access the value before analysis. - * If the field is final, then the value can also be constant folded before analysis. - * - * The introduction of this method pre-dates {@link ValueAvailability}, i.e., we could combine - * this method and {@link #isValueAvailable} into a single method that returns the - * {@link ValueAvailability} of the field. - */ - boolean isValueAvailableBeforeAnalysis(); - - default boolean isValueAvailable() { - return isValueAvailableBeforeAnalysis() || BuildPhaseProvider.isAnalysisFinished(); - } + boolean isValueAvailable(); boolean injectFinalForRuntimeCompilation(); diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/analysis/CustomTypeFieldHandler.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/analysis/CustomTypeFieldHandler.java index ec793d8018a0..faf8f040ce6e 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/analysis/CustomTypeFieldHandler.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/analysis/CustomTypeFieldHandler.java @@ -58,7 +58,7 @@ public void handleField(AnalysisField field) { */ assert field.isAccessed(); if (field.wrapped instanceof ComputedValueField computedField) { - if (!computedField.isValueAvailableBeforeAnalysis() && field.getStorageKind().isObject()) { + if (!computedField.isValueAvailable() && field.getJavaKind().isObject()) { injectFieldTypes(field, field.getType()); } else if (bb.trackPrimitiveValues() && field.getStorageKind().isPrimitive() && field instanceof PointsToAnalysisField ptaField) { ptaField.saturatePrimitiveField(); diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/substitute/AnnotatedField.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/substitute/AnnotatedField.java index ef199ce0def2..eb2f8aa22486 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/substitute/AnnotatedField.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/substitute/AnnotatedField.java @@ -29,6 +29,7 @@ import java.lang.reflect.Field; import com.oracle.graal.pointsto.infrastructure.OriginalFieldProvider; +import com.oracle.svm.core.BuildPhaseProvider; import com.oracle.svm.hosted.ameta.ReadableJavaField; import com.oracle.svm.hosted.annotation.AnnotationValue; import com.oracle.svm.hosted.annotation.AnnotationWrapper; @@ -66,12 +67,12 @@ public JavaConstant readValue(ClassInitializationSupport classInitializationSupp } @Override - public boolean isValueAvailableBeforeAnalysis() { + public boolean isValueAvailable() { /* * We assume that fields for which this class is used always have altered behavior for which - * constant folding is not valid. + * constant folding before or during analysis is not valid. */ - return false; + return BuildPhaseProvider.isAnalysisFinished(); } @Override diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/substitute/ComputedValueField.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/substitute/ComputedValueField.java index 353413539823..f16c2d1fa401 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/substitute/ComputedValueField.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/substitute/ComputedValueField.java @@ -182,11 +182,6 @@ public static boolean isOffsetRecomputation(RecomputeFieldValue.Kind kind) { return offsetComputationKinds.contains(kind); } - @Override - public boolean isValueAvailableBeforeAnalysis() { - return isValueAvailableBeforeAnalysis; - } - @Override public boolean isValueAvailable() { /* @@ -196,7 +191,7 @@ public boolean isValueAvailable() { * value available when strengthening graphs after analysis, i.e., when applying analysis * results back into the IR. */ - return constantValue != null || isValueAvailableBeforeAnalysis() || + return constantValue != null || isValueAvailableBeforeAnalysis || (isValueAvailableOnlyAfterAnalysis && BuildPhaseProvider.isHostedUniverseBuilt()) || (isValueAvailableOnlyAfterCompilation && BuildPhaseProvider.isCompilationFinished()); } diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/substitute/SubstitutionField.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/substitute/SubstitutionField.java index 0c12e1b87c37..5df2f1454341 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/substitute/SubstitutionField.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/substitute/SubstitutionField.java @@ -55,7 +55,7 @@ public SubstitutionField(ResolvedJavaField original, ResolvedJavaField annotated } @Override - public boolean isValueAvailableBeforeAnalysis() { + public boolean isValueAvailable() { return true; } From 8716e0ee64e52a823c0ef3d6f7dfc60231ea4b7d Mon Sep 17 00:00:00 2001 From: Christian Wimmer Date: Fri, 8 Dec 2023 15:21:27 -0800 Subject: [PATCH 217/593] Do not mark AnalysisType reachable when creating AnalysisField --- .../pointsto/standalone/StandaloneHost.java | 14 +- .../com/oracle/graal/pointsto/api/HostVM.java | 8 +- .../graal/pointsto/heap/ImageHeapScanner.java | 2 +- .../heap/value/LazyValueSupplier.java | 3 +- .../pointsto/heap/value/ValueSupplier.java | 3 +- .../infrastructure/OriginalClassProvider.java | 9 +- .../infrastructure/OriginalFieldProvider.java | 19 +- .../graal/pointsto/meta/AnalysisField.java | 63 ++- .../graal/pointsto/meta/AnalysisType.java | 11 +- .../graal/pointsto/meta/AnalysisUniverse.java | 40 +- .../com/oracle/svm/core/ParsingReason.java | 2 +- .../ArrayBaseOffsetFieldValueTransformer.java | 45 ++ .../ArrayIndexScaleFieldValueTransformer.java | 45 ++ .../ArrayIndexShiftFieldValueTransformer.java | 45 ++ .../BoxingTransformer.java} | 29 +- .../FieldOffsetFieldValueTransformer.java | 53 +++ .../StaticFieldBaseFieldValueTransformer.java | 47 ++ .../svm/core/hub/DynamicHubSupport.java | 3 +- .../com/oracle/svm/hosted/FeatureImpl.java | 3 +- .../svm/hosted/HostedConfiguration.java | 7 +- .../svm/hosted/NativeImageGenerator.java | 27 +- .../src/com/oracle/svm/hosted/SVMHost.java | 107 +---- .../ameta/AnalysisConstantFieldProvider.java | 3 - .../AnalysisConstantReflectionProvider.java | 9 +- .../CustomTypeFieldHandler.java | 20 +- .../ameta/FieldValueInterceptionSupport.java | 298 ++++++++++++ .../svm/hosted/ameta/ReadableJavaField.java | 7 - .../hosted/analysis/FieldValueComputer.java | 52 +++ .../analysis/NativeImagePointsToAnalysis.java | 1 + ...NativeImageReachabilityAnalysisEngine.java | 1 + .../PointsToCustomTypeFieldHandler.java | 1 + .../flow/SVMMethodTypeFlowBuilder.java | 27 +- .../StaticFinalFieldFoldingNodePlugin.java | 12 +- .../svm/hosted/heap/HeapDumpHostedUtils.java | 12 +- .../svm/hosted/heap/SVMImageHeapScanner.java | 6 +- .../oracle/svm/hosted/meta/HostedField.java | 11 +- .../meta/SharedConstantFieldProvider.java | 31 +- .../svm/hosted/meta/UniverseBuilder.java | 5 +- .../phases/SharedGraphBuilderPhase.java | 4 +- .../hosted/snippets/ReflectionPlugins.java | 2 +- .../SubstrateGraphBuilderPlugins.java | 2 +- .../svm/hosted/substitute/AnnotatedField.java | 5 +- .../AnnotationSubstitutionProcessor.java | 28 +- ...AutomaticUnsafeTransformationSupport.java} | 426 ++++++++---------- .../hosted/substitute/ComputedValueField.java | 199 ++------ .../substitute/FieldValueTransformation.java | 156 +++++++ .../hosted/substitute/SubstitutionField.java | 5 +- 47 files changed, 1187 insertions(+), 721 deletions(-) create mode 100644 substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/fieldvaluetransformer/ArrayBaseOffsetFieldValueTransformer.java create mode 100644 substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/fieldvaluetransformer/ArrayIndexScaleFieldValueTransformer.java create mode 100644 substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/fieldvaluetransformer/ArrayIndexShiftFieldValueTransformer.java rename substratevm/src/{com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/meta/FieldValueComputer.java => com.oracle.svm.core/src/com/oracle/svm/core/fieldvaluetransformer/BoxingTransformer.java} (66%) create mode 100644 substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/fieldvaluetransformer/FieldOffsetFieldValueTransformer.java create mode 100644 substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/fieldvaluetransformer/StaticFieldBaseFieldValueTransformer.java rename substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/{analysis => ameta}/CustomTypeFieldHandler.java (87%) create mode 100644 substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/ameta/FieldValueInterceptionSupport.java create mode 100644 substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/analysis/FieldValueComputer.java rename substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/substitute/{UnsafeAutomaticSubstitutionProcessor.java => AutomaticUnsafeTransformationSupport.java} (73%) create mode 100644 substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/substitute/FieldValueTransformation.java diff --git a/substratevm/src/com.oracle.graal.pointsto.standalone/src/com/oracle/graal/pointsto/standalone/StandaloneHost.java b/substratevm/src/com.oracle.graal.pointsto.standalone/src/com/oracle/graal/pointsto/standalone/StandaloneHost.java index 26ac64d8a6a1..cf0e0990c0dd 100644 --- a/substratevm/src/com.oracle.graal.pointsto.standalone/src/com/oracle/graal/pointsto/standalone/StandaloneHost.java +++ b/substratevm/src/com.oracle.graal.pointsto.standalone/src/com/oracle/graal/pointsto/standalone/StandaloneHost.java @@ -29,18 +29,18 @@ import java.util.Comparator; import java.util.concurrent.ConcurrentHashMap; -import jdk.graal.compiler.java.GraphBuilderPhase; -import jdk.graal.compiler.nodes.graphbuilderconf.GraphBuilderConfiguration; -import jdk.graal.compiler.nodes.graphbuilderconf.IntrinsicContext; -import jdk.graal.compiler.options.OptionValues; -import jdk.graal.compiler.phases.OptimisticOptimizations; - +import com.oracle.graal.pointsto.BigBang; import com.oracle.graal.pointsto.api.HostVM; import com.oracle.graal.pointsto.meta.AnalysisType; import com.oracle.graal.pointsto.meta.HostedProviders; import com.oracle.graal.pointsto.standalone.plugins.StandaloneGraphBuilderPhase; import com.oracle.graal.pointsto.util.AnalysisError; +import jdk.graal.compiler.java.GraphBuilderPhase; +import jdk.graal.compiler.nodes.graphbuilderconf.GraphBuilderConfiguration; +import jdk.graal.compiler.nodes.graphbuilderconf.IntrinsicContext; +import jdk.graal.compiler.options.OptionValues; +import jdk.graal.compiler.phases.OptimisticOptimizations; import jdk.vm.ci.meta.ResolvedJavaType; public class StandaloneHost extends HostVM { @@ -72,7 +72,7 @@ public boolean isInitialized(AnalysisType type) { } @Override - public void onTypeReachable(AnalysisType type) { + public void onTypeReachable(BigBang bb, AnalysisType type) { if (!type.isReachable()) { AnalysisError.shouldNotReachHere("Registering and initializing a type that was not yet marked as reachable: " + type); } diff --git a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/api/HostVM.java b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/api/HostVM.java index 4ed6438b42bc..9ec95cd96b31 100644 --- a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/api/HostVM.java +++ b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/api/HostVM.java @@ -41,11 +41,9 @@ import com.oracle.graal.pointsto.BigBang; import com.oracle.graal.pointsto.PointsToAnalysis; import com.oracle.graal.pointsto.flow.InvokeTypeFlow; -import com.oracle.graal.pointsto.meta.AnalysisField; import com.oracle.graal.pointsto.meta.AnalysisMethod; import com.oracle.graal.pointsto.meta.AnalysisType; import com.oracle.graal.pointsto.meta.AnalysisUniverse; -import com.oracle.graal.pointsto.meta.FieldValueComputer; import com.oracle.graal.pointsto.meta.HostedProviders; import com.oracle.graal.pointsto.phases.InlineBeforeAnalysisGraphDecoder; import com.oracle.graal.pointsto.phases.InlineBeforeAnalysisPolicy; @@ -155,7 +153,7 @@ public void checkType(ResolvedJavaType type, AnalysisUniverse universe) { * * @param newValue the type to initialize */ - public abstract void onTypeReachable(AnalysisType newValue); + public abstract void onTypeReachable(BigBang bb, AnalysisType newValue); /** * Check if an {@link AnalysisType} is initialized. @@ -420,8 +418,4 @@ public boolean allowConstantFolding(AnalysisMethod method) { */ return method.isOriginalMethod(); } - - public FieldValueComputer createFieldValueComputer(@SuppressWarnings("unused") AnalysisField field) { - return null; - } } diff --git a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/heap/ImageHeapScanner.java b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/heap/ImageHeapScanner.java index 5ed293358b20..fa757545e9ac 100644 --- a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/heap/ImageHeapScanner.java +++ b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/heap/ImageHeapScanner.java @@ -545,7 +545,7 @@ private void updateInstanceField(AnalysisField field, ImageHeapInstance imageHea } public boolean isValueAvailable(AnalysisField field) { - return field.isValueAvailable(); + return true; } protected String formatReason(String message, ScanReason reason) { diff --git a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/heap/value/LazyValueSupplier.java b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/heap/value/LazyValueSupplier.java index b39cea55ef7b..2c7bb89e498d 100644 --- a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/heap/value/LazyValueSupplier.java +++ b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/heap/value/LazyValueSupplier.java @@ -24,6 +24,7 @@ */ package com.oracle.graal.pointsto.heap.value; +import java.util.Objects; import java.util.function.BooleanSupplier; import java.util.function.Supplier; @@ -47,6 +48,6 @@ public boolean isAvailable() { @Override public V get() { AnalysisError.guarantee(isAvailable(), "Value is not yet available."); - return valueSupplier.get(); + return Objects.requireNonNull(valueSupplier.get()); } } diff --git a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/heap/value/ValueSupplier.java b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/heap/value/ValueSupplier.java index febb337f8be7..181b9e691b74 100644 --- a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/heap/value/ValueSupplier.java +++ b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/heap/value/ValueSupplier.java @@ -24,6 +24,7 @@ */ package com.oracle.graal.pointsto.heap.value; +import java.util.Objects; import java.util.function.BooleanSupplier; import java.util.function.Supplier; @@ -42,7 +43,7 @@ public interface ValueSupplier { static ValueSupplier eagerValue(V value) { - return new EagerValueSupplier<>(value); + return new EagerValueSupplier<>(Objects.requireNonNull(value)); } static ValueSupplier lazyValue(Supplier valueSupplier, BooleanSupplier isAvailable) { diff --git a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/infrastructure/OriginalClassProvider.java b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/infrastructure/OriginalClassProvider.java index b8caed018e82..950061247e93 100644 --- a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/infrastructure/OriginalClassProvider.java +++ b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/infrastructure/OriginalClassProvider.java @@ -28,16 +28,21 @@ import com.oracle.graal.pointsto.util.GraalAccess; +import jdk.vm.ci.meta.JavaType; import jdk.vm.ci.meta.ResolvedJavaType; public interface OriginalClassProvider { - static Class getJavaClass(ResolvedJavaType javaType) { + static Class getJavaClass(JavaType javaType) { Class result; if (javaType instanceof OriginalClassProvider) { result = ((OriginalClassProvider) javaType).getJavaClass(); } else { - result = GraalAccess.getOriginalSnippetReflection().originalClass(javaType); + /* + * The static analysis and the image generator never use unresolved types. The JavaType + * in the method signature is just to avoid casts in the callers. + */ + result = GraalAccess.getOriginalSnippetReflection().originalClass((ResolvedJavaType) javaType); } /* diff --git a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/infrastructure/OriginalFieldProvider.java b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/infrastructure/OriginalFieldProvider.java index 646843e5f87e..e88434b5c340 100644 --- a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/infrastructure/OriginalFieldProvider.java +++ b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/infrastructure/OriginalFieldProvider.java @@ -41,21 +41,28 @@ */ public interface OriginalFieldProvider { + static ResolvedJavaField getOriginalField(ResolvedJavaField field) { + ResolvedJavaField cur = field; + while (cur instanceof OriginalFieldProvider originalFieldProvider) { + cur = originalFieldProvider.unwrapTowardsOriginalField(); + } + return cur; + } + static Field getJavaField(ResolvedJavaField field) { - if (field instanceof OriginalFieldProvider) { - return ((OriginalFieldProvider) field).getJavaField(); - } else { + ResolvedJavaField originalField = getOriginalField(field); + if (originalField != null) { try { - return GraalAccess.getOriginalSnippetReflection().originalField(field); + return GraalAccess.getOriginalSnippetReflection().originalField(originalField); } catch (LinkageError ignored) { /* * Ignore any linking problems and incompatible class change errors. Looking up a * reflective representation of a JVMCI field is always a best effort operation. */ - return null; } } + return null; } - Field getJavaField(); + ResolvedJavaField unwrapTowardsOriginalField(); } diff --git a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/meta/AnalysisField.java b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/meta/AnalysisField.java index b78da63d0585..453fd6234529 100644 --- a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/meta/AnalysisField.java +++ b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/meta/AnalysisField.java @@ -24,16 +24,14 @@ */ package com.oracle.graal.pointsto.meta; -import java.lang.reflect.Field; import java.lang.reflect.Modifier; import java.util.ArrayList; +import java.util.List; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; import java.util.concurrent.atomic.AtomicIntegerFieldUpdater; import java.util.concurrent.atomic.AtomicReferenceFieldUpdater; -import jdk.graal.compiler.debug.GraalError; - import com.oracle.graal.pointsto.api.DefaultUnsafePartition; import com.oracle.graal.pointsto.api.HostVM; import com.oracle.graal.pointsto.api.PointstoOptions; @@ -42,10 +40,12 @@ import com.oracle.graal.pointsto.infrastructure.OriginalFieldProvider; import com.oracle.graal.pointsto.infrastructure.WrappedJavaField; import com.oracle.graal.pointsto.typestate.TypeState; +import com.oracle.graal.pointsto.util.AnalysisFuture; import com.oracle.graal.pointsto.util.AtomicUtils; import com.oracle.graal.pointsto.util.ConcurrentLightHashSet; import com.oracle.svm.util.UnsafePartitionKind; +import jdk.graal.compiler.debug.GraalError; import jdk.vm.ci.code.BytecodePosition; import jdk.vm.ci.meta.JavaConstant; import jdk.vm.ci.meta.JavaKind; @@ -123,9 +123,10 @@ public abstract class AnalysisField extends AnalysisElement implements WrappedJa /** * Marks a field whose value is computed during image building, in general derived from other - * values, and it cannot be constant-folded or otherwise optimized. + * values. The actual meaning of the field value is out of scope of the static analysis, but the + * value is stored here to allow fast access. */ - protected final FieldValueComputer fieldValueComputer; + protected Object fieldValueInterceptor; @SuppressWarnings("this-escape") public AnalysisField(AnalysisUniverse universe, ResolvedJavaField wrappedField) { @@ -152,8 +153,6 @@ public AnalysisField(AnalysisUniverse universe, ResolvedJavaField wrappedField) this.instanceFieldFlow = new ContextInsensitiveFieldTypeFlow(this, getType()); this.initialInstanceFieldFlow = new FieldTypeFlow(this, getType()); } - - fieldValueComputer = universe.hostVM().createFieldValueComputer(this); } @Override @@ -260,6 +259,8 @@ public void cleanupAfterAnalysis() { } public boolean registerAsAccessed(Object reason) { + getDeclaringClass().registerAsReachable(this); + assert isValidReason(reason) : "Registering a field as accessed needs to provide a valid reason."; boolean firstAttempt = AtomicUtils.atomicSet(this, reason, isAccessedUpdater); notifyUpdateAccessInfo(); @@ -275,6 +276,8 @@ public boolean registerAsAccessed(Object reason) { * @param reason the reason why this field is read, non-null */ public boolean registerAsRead(Object reason) { + getDeclaringClass().registerAsReachable(this); + assert isValidReason(reason) : "Registering a field as read needs to provide a valid reason."; boolean firstAttempt = AtomicUtils.atomicSet(this, reason, isReadUpdater); notifyUpdateAccessInfo(); @@ -295,6 +298,8 @@ public boolean registerAsRead(Object reason) { * @param reason the reason why this field is written, non-null */ public boolean registerAsWritten(Object reason) { + getDeclaringClass().registerAsReachable(this); + assert isValidReason(reason) : "Registering a field as written needs to provide a valid reason."; boolean firstAttempt = AtomicUtils.atomicSet(this, reason, isWrittenUpdater); notifyUpdateAccessInfo(); @@ -311,6 +316,8 @@ public boolean registerAsWritten(Object reason) { } public void registerAsFolded(Object reason) { + getDeclaringClass().registerAsReachable(this); + assert isValidReason(reason) : "Registering a field as folded needs to provide a valid reason."; if (AtomicUtils.atomicSet(this, reason, isFoldedUpdater)) { assert getDeclaringClass().isReachable() : this; @@ -442,23 +449,12 @@ public void onReachable() { notifyReachabilityCallbacks(declaringClass.getUniverse(), new ArrayList<>()); } - public boolean isValueAvailable() { - if (fieldValueComputer != null) { - return fieldValueComputer.isAvailable(); - } - return true; - } - - public boolean isComputedValue() { - return fieldValueComputer != null; - } - - public Class[] computedValueTypes() { - return fieldValueComputer.types(); + public Object getFieldValueInterceptor() { + return fieldValueInterceptor; } - public boolean computedValueCanBeNull() { - return fieldValueComputer.canBeNull(); + public void setFieldValueInterceptor(Object fieldValueInterceptor) { + this.fieldValueInterceptor = fieldValueInterceptor; } public void setCanBeNull(boolean canBeNull) { @@ -531,8 +527,8 @@ public String toString() { } @Override - public Field getJavaField() { - return OriginalFieldProvider.getJavaField(wrapped); + public ResolvedJavaField unwrapTowardsOriginalField() { + return wrapped; } @Override @@ -540,6 +536,25 @@ public JavaConstant getConstantValue() { return getUniverse().lookup(getWrapped().getConstantValue()); } + /** + * Ensure that all reachability handler that were present at the time the declaring type was + * marked as reachable are executed before accessing field values. This allows field value + * transformer to be installed reliably in reachability handler. + */ + public void beforeFieldValueAccess() { + declaringClass.registerAsReachable(this); + declaringClass.ensureOnTypeReachableTaskDone(); + + List> notifications = declaringClass.scheduledTypeReachableNotifications; + if (notifications != null) { + for (var notification : notifications) { + notification.ensureDone(); + } + /* Now we know all the handlers have been executed, no checks are necessary anymore. */ + declaringClass.scheduledTypeReachableNotifications = null; + } + } + public void addAnalysisFieldObserver(AnalysisFieldObserver observer) { ConcurrentLightHashSet.addElement(this, OBSERVERS_UPDATER, observer); } diff --git a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/meta/AnalysisType.java b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/meta/AnalysisType.java index d7f368549859..1a378ff0ca68 100644 --- a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/meta/AnalysisType.java +++ b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/meta/AnalysisType.java @@ -681,13 +681,18 @@ private static void forAllSuperTypes(AnalysisType elementType, int arrayDimensio if (elementType == null) { return; } - if (processType) { - superTypeConsumer.accept(elementType.getArrayClass(arrayDimension)); - } for (AnalysisType interf : elementType.getInterfaces()) { forAllSuperTypes(interf, arrayDimension, true, superTypeConsumer); } forAllSuperTypes(elementType.getSuperclass(), arrayDimension, true, superTypeConsumer); + /* + * Process the type itself only after visiting all supertypes. This ensures that, e.g., a + * type is never seen as reachable by another thread before all of its supertypes are + * already marked as reachable too. + */ + if (processType) { + superTypeConsumer.accept(elementType.getArrayClass(arrayDimension)); + } } protected synchronized void addAssignableType(BigBang bb, TypeState typeState) { diff --git a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/meta/AnalysisUniverse.java b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/meta/AnalysisUniverse.java index 4623d41da59a..285b97891da2 100644 --- a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/meta/AnalysisUniverse.java +++ b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/meta/AnalysisUniverse.java @@ -57,7 +57,6 @@ import com.oracle.graal.pointsto.infrastructure.WrappedJavaType; import com.oracle.graal.pointsto.meta.AnalysisType.UsageKind; import com.oracle.graal.pointsto.util.AnalysisError; -import com.oracle.graal.pointsto.util.AnalysisFuture; import com.oracle.graal.pointsto.util.GraalAccess; import jdk.graal.compiler.api.replacements.SnippetReflectionProvider; @@ -357,43 +356,6 @@ public JavaField lookupAllowUnresolved(JavaField rawField) { ResolvedJavaField field = (ResolvedJavaField) rawField; - if (!sealed) { - /* - * Trigger computation of automatic substitutions. There might be an automatic - * substitution for the current field and we want to register it before the analysis - * field is created. This also ensures that the class is initialized (if the class is - * registered for initialization at build time) before any constant folding of static - * fields is attempted. Calling ensureInitialized() here at field lookup avoids calling - * it during constant folding. - */ - AnalysisType declaringType = lookup(field.getDeclaringClass()); - declaringType.registerAsReachable(field); - declaringType.ensureOnTypeReachableTaskDone(); - - /* - * Ensure that all reachability handler that were present at the time the type was - * marked as reachable are executed before creating the field. This allows field value - * transformer to be installed reliably in reachability handler. - * - * This is necessary because field value transformer are currently implemented via - * ComputedValueField that are injected into the substitution universe. A - * ComputedValueField added after the AnalysisField is created would be ignored. In the - * future, we want a better implementation of field value transformer that do not rely - * on the substitution universe, then this code can be removed. - */ - List> notifications = declaringType.scheduledTypeReachableNotifications; - if (notifications != null) { - for (var notification : notifications) { - notification.ensureDone(); - } - /* - * Now we know all the handlers have been executed, so subsequent field lookups do - * not need to check anymore. - */ - declaringType.scheduledTypeReachableNotifications = null; - } - } - field = substitutions.lookup(field); AnalysisField result = fields.get(field); if (result == null) { @@ -732,7 +694,7 @@ public void onTypeInstantiated(AnalysisType type, UsageKind usage) { } public void onTypeReachable(AnalysisType type) { - hostVM.onTypeReachable(type); + hostVM.onTypeReachable(bb, type); if (bb != null) { bb.onTypeReachable(type); } diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/ParsingReason.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/ParsingReason.java index 0d01c3d11de8..5a77ab3f3205 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/ParsingReason.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/ParsingReason.java @@ -30,7 +30,7 @@ public enum ParsingReason { AOTCompilation, JITCompilation, EarlyClassInitializerAnalysis, - UnsafeSubstitutionAnalysis; + AutomaticUnsafeTransformation; public boolean isForHosted() { return this != JITCompilation; diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/fieldvaluetransformer/ArrayBaseOffsetFieldValueTransformer.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/fieldvaluetransformer/ArrayBaseOffsetFieldValueTransformer.java new file mode 100644 index 000000000000..6438f1436e0a --- /dev/null +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/fieldvaluetransformer/ArrayBaseOffsetFieldValueTransformer.java @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2023, 2023, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.svm.core.fieldvaluetransformer; + +import org.graalvm.nativeimage.hosted.FieldValueTransformer; + +import com.oracle.svm.core.config.ConfigurationValues; + +import jdk.vm.ci.meta.JavaKind; + +public final class ArrayBaseOffsetFieldValueTransformer extends BoxingTransformer implements FieldValueTransformer { + private final Class targetClass; + + public ArrayBaseOffsetFieldValueTransformer(Class targetClass, Class returnType) { + super(returnType); + this.targetClass = targetClass; + } + + @Override + public Object transform(Object receiver, Object originalValue) { + return box(ConfigurationValues.getObjectLayout().getArrayBaseOffset(JavaKind.fromJavaClass(targetClass.getComponentType()))); + } +} diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/fieldvaluetransformer/ArrayIndexScaleFieldValueTransformer.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/fieldvaluetransformer/ArrayIndexScaleFieldValueTransformer.java new file mode 100644 index 000000000000..265a1cc62f65 --- /dev/null +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/fieldvaluetransformer/ArrayIndexScaleFieldValueTransformer.java @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2023, 2023, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.svm.core.fieldvaluetransformer; + +import org.graalvm.nativeimage.hosted.FieldValueTransformer; + +import com.oracle.svm.core.config.ConfigurationValues; + +import jdk.vm.ci.meta.JavaKind; + +public final class ArrayIndexScaleFieldValueTransformer extends BoxingTransformer implements FieldValueTransformer { + private final Class targetClass; + + public ArrayIndexScaleFieldValueTransformer(Class targetClass, Class returnType) { + super(returnType); + this.targetClass = targetClass; + } + + @Override + public Object transform(Object receiver, Object originalValue) { + return box(ConfigurationValues.getObjectLayout().getArrayIndexScale(JavaKind.fromJavaClass(targetClass.getComponentType()))); + } +} diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/fieldvaluetransformer/ArrayIndexShiftFieldValueTransformer.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/fieldvaluetransformer/ArrayIndexShiftFieldValueTransformer.java new file mode 100644 index 000000000000..78b9da2d9bcd --- /dev/null +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/fieldvaluetransformer/ArrayIndexShiftFieldValueTransformer.java @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2023, 2023, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.svm.core.fieldvaluetransformer; + +import org.graalvm.nativeimage.hosted.FieldValueTransformer; + +import com.oracle.svm.core.config.ConfigurationValues; + +import jdk.vm.ci.meta.JavaKind; + +public final class ArrayIndexShiftFieldValueTransformer extends BoxingTransformer implements FieldValueTransformer { + private final Class targetClass; + + public ArrayIndexShiftFieldValueTransformer(Class targetClass, Class returnType) { + super(returnType); + this.targetClass = targetClass; + } + + @Override + public Object transform(Object receiver, Object originalValue) { + return box(ConfigurationValues.getObjectLayout().getArrayIndexShift(JavaKind.fromJavaClass(targetClass.getComponentType()))); + } +} diff --git a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/meta/FieldValueComputer.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/fieldvaluetransformer/BoxingTransformer.java similarity index 66% rename from substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/meta/FieldValueComputer.java rename to substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/fieldvaluetransformer/BoxingTransformer.java index 39be8a4041ad..c64177c8f903 100644 --- a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/meta/FieldValueComputer.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/fieldvaluetransformer/BoxingTransformer.java @@ -22,25 +22,24 @@ * or visit www.oracle.com if you need additional information or have any * questions. */ -package com.oracle.graal.pointsto.meta; +package com.oracle.svm.core.fieldvaluetransformer; -import org.graalvm.nativeimage.Platform; -import org.graalvm.nativeimage.Platforms; +import com.oracle.svm.core.util.VMError; -@Platforms(Platform.HOSTED_ONLY.class) -public interface FieldValueComputer { +abstract class BoxingTransformer { + private final Class returnType; - Class[] EMPTY_TYPES = new Class[0]; - - default boolean isAvailable() { - return true; - } - - default Class[] types() { - return EMPTY_TYPES; + BoxingTransformer(Class returnType) { + this.returnType = returnType; } - default boolean canBeNull() { - return false; + Object box(int value) { + if (returnType == int.class || returnType == Integer.class) { + return Integer.valueOf(value); + } else if (returnType == long.class || returnType == Long.class) { + return Long.valueOf(value); + } else { + throw VMError.shouldNotReachHere("Unexpected type: " + returnType); + } } } diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/fieldvaluetransformer/FieldOffsetFieldValueTransformer.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/fieldvaluetransformer/FieldOffsetFieldValueTransformer.java new file mode 100644 index 000000000000..bb53ef42e85c --- /dev/null +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/fieldvaluetransformer/FieldOffsetFieldValueTransformer.java @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2023, 2023, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.svm.core.fieldvaluetransformer; + +import java.lang.reflect.Field; + +import com.oracle.svm.core.reflect.target.ReflectionSubstitutionSupport; +import com.oracle.svm.core.util.VMError; + +public final class FieldOffsetFieldValueTransformer extends BoxingTransformer implements FieldValueTransformerWithAvailability { + private final Field targetField; + + public FieldOffsetFieldValueTransformer(Field targetField, Class returnType) { + super(returnType); + this.targetField = targetField; + } + + @Override + public ValueAvailability valueAvailability() { + return ValueAvailability.AfterAnalysis; + } + + @Override + public Object transform(Object receiver, Object originalValue) { + int offset = ReflectionSubstitutionSupport.singleton().getFieldOffset(targetField, true); + if (offset <= 0) { + throw VMError.shouldNotReachHere("Field is not marked as unsafe accessed: " + targetField); + } + return box(offset); + } +} diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/fieldvaluetransformer/StaticFieldBaseFieldValueTransformer.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/fieldvaluetransformer/StaticFieldBaseFieldValueTransformer.java new file mode 100644 index 000000000000..515a3b50db13 --- /dev/null +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/fieldvaluetransformer/StaticFieldBaseFieldValueTransformer.java @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2023, 2023, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.svm.core.fieldvaluetransformer; + +import java.lang.reflect.Field; + +import com.oracle.svm.core.StaticFieldsSupport; + +public final class StaticFieldBaseFieldValueTransformer implements FieldValueTransformerWithAvailability { + private final Field targetField; + + public StaticFieldBaseFieldValueTransformer(Field targetField) { + this.targetField = targetField; + } + + @Override + public ValueAvailability valueAvailability() { + return ValueAvailability.AfterAnalysis; + } + + @Override + public Object transform(Object receiver, Object originalValue) { + return targetField.getType().isPrimitive() ? StaticFieldsSupport.getStaticPrimitiveFields() : StaticFieldsSupport.getStaticObjectFields(); + } +} diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/hub/DynamicHubSupport.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/hub/DynamicHubSupport.java index 71befa3164c8..8261e019ec48 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/hub/DynamicHubSupport.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/hub/DynamicHubSupport.java @@ -34,11 +34,12 @@ import com.oracle.svm.core.c.NonmovableArrays; import com.oracle.svm.core.feature.AutomaticallyRegisteredImageSingleton; import com.oracle.svm.core.heap.UnknownObjectField; +import com.oracle.svm.core.heap.UnknownPrimitiveField; @AutomaticallyRegisteredImageSingleton public final class DynamicHubSupport { - @UnknownObjectField(availability = AfterHostedUniverse.class) private int maxTypeId; + @UnknownPrimitiveField(availability = AfterHostedUniverse.class) private int maxTypeId; @UnknownObjectField(availability = AfterHostedUniverse.class) private byte[] referenceMapEncoding; @Platforms(Platform.HOSTED_ONLY.class) diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/FeatureImpl.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/FeatureImpl.java index b9f0c0238583..8daa17a3dc08 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/FeatureImpl.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/FeatureImpl.java @@ -72,6 +72,7 @@ import com.oracle.svm.core.meta.SharedType; import com.oracle.svm.core.option.SubstrateOptionsParser; import com.oracle.svm.core.util.VMError; +import com.oracle.svm.hosted.ameta.FieldValueInterceptionSupport; import com.oracle.svm.hosted.analysis.Inflation; import com.oracle.svm.hosted.c.NativeLibraries; import com.oracle.svm.hosted.code.CEntryPointData; @@ -452,7 +453,7 @@ public boolean concurrentReachabilityHandlers() { @Override public void registerFieldValueTransformer(Field field, FieldValueTransformer transformer) { - bb.getAnnotationSubstitutionProcessor().registerFieldValueTransformer(field, transformer); + FieldValueInterceptionSupport.singleton().registerFieldValueTransformer(field, transformer); } /** diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/HostedConfiguration.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/HostedConfiguration.java index ca531229c685..25eb7f0b7c0e 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/HostedConfiguration.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/HostedConfiguration.java @@ -67,7 +67,7 @@ import com.oracle.svm.hosted.meta.HostedInstanceClass; import com.oracle.svm.hosted.meta.HostedMetaAccess; import com.oracle.svm.hosted.meta.HostedUniverse; -import com.oracle.svm.hosted.substitute.UnsafeAutomaticSubstitutionProcessor; +import com.oracle.svm.hosted.substitute.AnnotationSubstitutionProcessor; import jdk.graal.compiler.api.replacements.SnippetReflectionProvider; import jdk.graal.compiler.core.common.CompressEncoding; @@ -162,9 +162,8 @@ public static ObjectLayout createObjectLayout(JavaKind referenceKind, IdentityHa return new ObjectLayout(target, referenceSize, objectAlignment, hubOffset, firstFieldOffset, arrayLengthOffset, arrayBaseOffset, headerIdentityHashOffset, identityHashMode); } - public SVMHost createHostVM(OptionValues options, ClassLoader classLoader, ClassInitializationSupport classInitializationSupport, - UnsafeAutomaticSubstitutionProcessor automaticSubstitutions, Platform platform) { - return new SVMHost(options, classLoader, classInitializationSupport, automaticSubstitutions, platform); + public SVMHost createHostVM(OptionValues options, ImageClassLoader loader, ClassInitializationSupport classInitializationSupport, AnnotationSubstitutionProcessor annotationSubstitutions) { + return new SVMHost(options, loader, classInitializationSupport, annotationSubstitutions); } public CompileQueue createCompileQueue(DebugContext debug, FeatureHandler featureHandler, HostedUniverse hostedUniverse, RuntimeConfiguration runtimeConfiguration, boolean deoptimizeAll, diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/NativeImageGenerator.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/NativeImageGenerator.java index 577a0139c5df..5d0b797abe61 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/NativeImageGenerator.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/NativeImageGenerator.java @@ -253,7 +253,6 @@ import com.oracle.svm.hosted.snippets.SubstrateGraphBuilderPlugins; import com.oracle.svm.hosted.substitute.AnnotationSubstitutionProcessor; import com.oracle.svm.hosted.substitute.DeletedFieldsPlugin; -import com.oracle.svm.hosted.substitute.UnsafeAutomaticSubstitutionProcessor; import com.oracle.svm.hosted.util.CPUTypeAArch64; import com.oracle.svm.hosted.util.CPUTypeAMD64; import com.oracle.svm.hosted.util.CPUTypeRISCV64; @@ -564,11 +563,10 @@ protected void doRun(Map entryPoints, JavaMainSupport j List hostedEntryPoints = new ArrayList<>(); OptionValues options = HostedOptionValues.singleton(); - SnippetReflectionProvider originalSnippetReflection = GraalAccess.getOriginalSnippetReflection(); - try (DebugContext debug = new Builder(options, new GraalDebugHandlersFactory(originalSnippetReflection)).build(); + try (DebugContext debug = new Builder(options, new GraalDebugHandlersFactory(GraalAccess.getOriginalSnippetReflection())).build(); DebugCloseable featureCleanup = () -> featureHandler.forEachFeature(Feature::cleanup)) { - setupNativeImage(options, entryPoints, javaMainSupport, harnessSubstitutions, originalSnippetReflection, debug); + setupNativeImage(options, entryPoints, javaMainSupport, harnessSubstitutions, debug); boolean returnAfterAnalysis = runPointsToAnalysis(imageName, options, debug); if (returnAfterAnalysis) { @@ -863,7 +861,7 @@ protected boolean verifyAssignableTypes() { @SuppressWarnings("try") protected void setupNativeImage(OptionValues options, Map entryPoints, JavaMainSupport javaMainSupport, - SubstitutionProcessor harnessSubstitutions, SnippetReflectionProvider originalSnippetReflection, DebugContext debug) { + SubstitutionProcessor harnessSubstitutions, DebugContext debug) { try (Indent ignored = debug.logAndIndent("setup native-image builder")) { try (StopTimer ignored1 = TimerCollection.createTimerAndStart(TimerCollection.Registry.SETUP)) { SubstrateTargetDescription target = createTarget(); @@ -917,7 +915,7 @@ protected void setupNativeImage(OptionValues options, Map additionalSubstitutions) { - UnsafeAutomaticSubstitutionProcessor automaticSubstitutions = createAutomaticUnsafeSubstitutions(options, originalSnippetReflection, annotationSubstitutions); - SubstitutionProcessor aSubstitutions = createAnalysisSubstitutionProcessor(cEnumProcessor, automaticSubstitutions, annotationSubstitutions, additionalSubstitutions); + SubstitutionProcessor aSubstitutions = createAnalysisSubstitutionProcessor(cEnumProcessor, annotationSubstitutions, additionalSubstitutions); - SVMHost hostVM = HostedConfiguration.instance().createHostVM(options, loader.getClassLoader(), classInitializationSupport, automaticSubstitutions, loader.platform); + SVMHost hostVM = HostedConfiguration.instance().createHostVM(options, loader, classInitializationSupport, annotationSubstitutions); - automaticSubstitutions.init(loader, originalMetaAccess); AnalysisPolicy analysisPolicy = PointstoOptions.AllocationSiteSensitiveHeap.getValue(options) ? new BytecodeSensitiveAnalysisPolicy(options) : new DefaultAnalysisPolicy(options); AnalysisFactory analysisFactory; @@ -1054,17 +1050,12 @@ public static AnnotationSubstitutionProcessor createAnnotationSubstitutionProces return annotationSubstitutions; } - public static UnsafeAutomaticSubstitutionProcessor createAutomaticUnsafeSubstitutions(OptionValues options, SnippetReflectionProvider originalSnippetReflection, - AnnotationSubstitutionProcessor annotationSubstitutions) { - return new UnsafeAutomaticSubstitutionProcessor(options, annotationSubstitutions, originalSnippetReflection); - } - public static SubstitutionProcessor createAnalysisSubstitutionProcessor( - SubstitutionProcessor cEnumProcessor, SubstitutionProcessor automaticSubstitutions, SubstitutionProcessor annotationSubstitutions, + SubstitutionProcessor cEnumProcessor, SubstitutionProcessor annotationSubstitutions, List additionalSubstitutionProcessors) { List allProcessors = new ArrayList<>(); SubstitutionProcessor cFunctionSubstitutions = new CFunctionSubstitutionProcessor(); - allProcessors.addAll(Arrays.asList(annotationSubstitutions, cFunctionSubstitutions, automaticSubstitutions, cEnumProcessor)); + allProcessors.addAll(Arrays.asList(annotationSubstitutions, cFunctionSubstitutions, cEnumProcessor)); allProcessors.addAll(additionalSubstitutionProcessors); return SubstitutionProcessor.chainUpInOrder(allProcessors.toArray(new SubstitutionProcessor[0])); } diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/SVMHost.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/SVMHost.java index e1d1f4750401..ce07a00c936c 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/SVMHost.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/SVMHost.java @@ -24,8 +24,6 @@ */ package com.oracle.svm.hosted; -import static com.oracle.graal.pointsto.util.AnalysisError.shouldNotReachHere; - import java.lang.ref.PhantomReference; import java.lang.ref.Reference; import java.lang.ref.SoftReference; @@ -33,8 +31,6 @@ import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.lang.reflect.Modifier; -import java.util.ArrayList; -import java.util.Arrays; import java.util.Collections; import java.util.Comparator; import java.util.EnumSet; @@ -48,7 +44,6 @@ import java.util.concurrent.ConcurrentMap; import java.util.concurrent.CopyOnWriteArrayList; import java.util.function.BiPredicate; -import java.util.function.BooleanSupplier; import java.util.function.Function; import org.graalvm.nativeimage.AnnotationAccess; @@ -67,7 +62,6 @@ import com.oracle.graal.pointsto.meta.AnalysisMethod; import com.oracle.graal.pointsto.meta.AnalysisType; import com.oracle.graal.pointsto.meta.AnalysisUniverse; -import com.oracle.graal.pointsto.meta.FieldValueComputer; import com.oracle.graal.pointsto.meta.HostedProviders; import com.oracle.graal.pointsto.phases.InlineBeforeAnalysisGraphDecoder; import com.oracle.graal.pointsto.phases.InlineBeforeAnalysisPolicy; @@ -87,8 +81,6 @@ import com.oracle.svm.core.heap.StoredContinuation; import com.oracle.svm.core.heap.Target_java_lang_ref_Reference; import com.oracle.svm.core.heap.UnknownClass; -import com.oracle.svm.core.heap.UnknownObjectField; -import com.oracle.svm.core.heap.UnknownPrimitiveField; import com.oracle.svm.core.hub.DynamicHub; import com.oracle.svm.core.hub.HubType; import com.oracle.svm.core.hub.ReferenceType; @@ -99,7 +91,7 @@ import com.oracle.svm.core.thread.ContinuationSupport; import com.oracle.svm.core.util.HostedStringDeduplication; import com.oracle.svm.core.util.VMError; -import com.oracle.svm.hosted.analysis.CustomTypeFieldHandler; +import com.oracle.svm.hosted.ameta.FieldValueInterceptionSupport; import com.oracle.svm.hosted.analysis.SVMParsingSupport; import com.oracle.svm.hosted.classinitialization.ClassInitializationOptions; import com.oracle.svm.hosted.classinitialization.ClassInitializationSupport; @@ -117,7 +109,8 @@ import com.oracle.svm.hosted.phases.InlineBeforeAnalysisGraphDecoderImpl; import com.oracle.svm.hosted.phases.InlineBeforeAnalysisPolicyImpl; import com.oracle.svm.hosted.phases.InlineBeforeAnalysisPolicyUtils; -import com.oracle.svm.hosted.substitute.UnsafeAutomaticSubstitutionProcessor; +import com.oracle.svm.hosted.substitute.AnnotationSubstitutionProcessor; +import com.oracle.svm.hosted.substitute.AutomaticUnsafeTransformationSupport; import com.oracle.svm.util.LogUtils; import com.oracle.svm.util.ReflectionUtil; @@ -157,7 +150,7 @@ public class SVMHost extends HostVM { private final ClassInitializationSupport classInitializationSupport; private final LinkAtBuildTimeSupport linkAtBuildTimeSupport; private final HostedStringDeduplication stringTable; - private final UnsafeAutomaticSubstitutionProcessor automaticSubstitutions; + private final AutomaticUnsafeTransformationSupport automaticUnsafeTransformations; /** * Optionally keep the Graal graphs alive during analysis. This increases the memory footprint @@ -179,15 +172,16 @@ public class SVMHost extends HostVM { private final SVMParsingSupport parsingSupport; private final InlineBeforeAnalysisPolicy inlineBeforeAnalysisPolicy; + private final FieldValueInterceptionSupport fieldValueInterceptionSupport; + @SuppressWarnings("this-escape") - public SVMHost(OptionValues options, ClassLoader classLoader, ClassInitializationSupport classInitializationSupport, - UnsafeAutomaticSubstitutionProcessor automaticSubstitutions, Platform platform) { - super(options, classLoader); + public SVMHost(OptionValues options, ImageClassLoader loader, ClassInitializationSupport classInitializationSupport, AnnotationSubstitutionProcessor annotationSubstitutions) { + super(options, loader.getClassLoader()); this.classInitializationSupport = classInitializationSupport; this.stringTable = HostedStringDeduplication.singleton(); this.forbiddenTypes = setupForbiddenTypes(options); - this.automaticSubstitutions = automaticSubstitutions; - this.platform = platform; + this.automaticUnsafeTransformations = new AutomaticUnsafeTransformationSupport(options, annotationSubstitutions, loader); + this.platform = loader.platform; this.linkAtBuildTimeSupport = LinkAtBuildTimeSupport.singleton(); if (ImageSingletons.contains(MultiMethodAnalysisPolicy.class)) { multiMethodAnalysisPolicy = ImageSingletons.lookup(MultiMethodAnalysisPolicy.class); @@ -204,6 +198,8 @@ public SVMHost(OptionValues options, ClassLoader classLoader, ClassInitializatio } else { parsingSupport = null; } + fieldValueInterceptionSupport = new FieldValueInterceptionSupport(annotationSubstitutions); + ImageSingletons.add(FieldValueInterceptionSupport.class, fieldValueInterceptionSupport); } protected InlineBeforeAnalysisPolicyUtils getInlineBeforeAnalysisPolicyUtils() { @@ -303,7 +299,7 @@ public void registerType(AnalysisType analysisType) { } @Override - public void onTypeReachable(AnalysisType analysisType) { + public void onTypeReachable(BigBang bb, AnalysisType analysisType) { if (!analysisType.isReachable()) { throw VMError.shouldNotReachHere("Registering and initializing a type that was not yet marked as reachable: " + analysisType); } @@ -315,7 +311,7 @@ public void onTypeReachable(AnalysisType analysisType) { classInitializationSupport.maybeInitializeAtBuildTime(analysisType); /* Compute the automatic substitutions. */ - automaticSubstitutions.computeSubstitutions(this, GraalAccess.getOriginalProviders().getMetaAccess().lookupJavaType(analysisType.getJavaClass())); + automaticUnsafeTransformations.computeTransformations(bb, this, GraalAccess.getOriginalProviders().getMetaAccess().lookupJavaType(analysisType.getJavaClass())); } @Override @@ -484,10 +480,6 @@ public ClassInitializationSupport getClassInitializationSupport() { return classInitializationSupport; } - public UnsafeAutomaticSubstitutionProcessor getAutomaticSubstitutionProcessor() { - return automaticSubstitutions; - } - private static int computeHubType(AnalysisType type) { if (type.isArray()) { if (type.getComponentType().isPrimitive() || type.getComponentType().isWordType()) { @@ -952,77 +944,6 @@ public boolean allowConstantFolding(AnalysisMethod method) { return method.isOriginalMethod() && !SubstrateCompilationDirectives.singleton().isRegisteredForDeoptTesting(method); } - @Override - public FieldValueComputer createFieldValueComputer(AnalysisField field) { - UnknownObjectField unknownObjectField = field.getAnnotation(UnknownObjectField.class); - if (unknownObjectField != null) { - return createObjectFieldValueComputer(field, unknownObjectField); - } - UnknownPrimitiveField unknownPrimitiveField = field.getAnnotation(UnknownPrimitiveField.class); - if (unknownPrimitiveField != null) { - return createPrimitiveFieldValueComputer(field, unknownPrimitiveField); - } - return null; - } - - private static FieldValueComputer createObjectFieldValueComputer(AnalysisField field, UnknownObjectField unknownValueField) { - return new FieldValueComputer() { - final BooleanSupplier availability = ReflectionUtil.newInstance(unknownValueField.availability()); - - @Override - public boolean isAvailable() { - return availability.getAsBoolean(); - } - - @Override - public Class[] types() { - return extractAnnotationTypes(field, unknownValueField.types(), unknownValueField.fullyQualifiedTypes()); - } - - @Override - public boolean canBeNull() { - return unknownValueField.canBeNull(); - } - }; - } - - private static FieldValueComputer createPrimitiveFieldValueComputer(AnalysisField field, UnknownPrimitiveField unknownValueField) { - return new FieldValueComputer() { - final BooleanSupplier availability = ReflectionUtil.newInstance(unknownValueField.availability()); - - @Override - public boolean isAvailable() { - return availability.getAsBoolean(); - } - - @Override - public Class[] types() { - return new Class[]{field.getType().getJavaClass()}; - } - }; - } - - private static Class[] extractAnnotationTypes(AnalysisField field, Class[] types, String[] fullyQualifiedTypes) { - List> annotationTypes = new ArrayList<>(Arrays.asList(types)); - for (String annotationTypeName : fullyQualifiedTypes) { - try { - Class annotationType = Class.forName(annotationTypeName); - annotationTypes.add(annotationType); - } catch (ClassNotFoundException e) { - throw shouldNotReachHere("Specified computed value type not found " + annotationTypeName); - } - } - - if (annotationTypes.isEmpty()) { - /* If no types are specified fallback to the field declared type. */ - AnalysisType fieldType = field.getType(); - VMError.guarantee(CustomTypeFieldHandler.isConcreteType(fieldType), "Illegal use of @UnknownObjectField annotation on field %s. " + - "The field type must be concrete or the annotation must declare a concrete type.", field); - annotationTypes.add(fieldType.getJavaClass()); - } - return annotationTypes.toArray(new Class[0]); - } - public SimulateClassInitializerSupport createSimulateClassInitializerSupport(AnalysisMetaAccess aMetaAccess) { return new SimulateClassInitializerSupport(aMetaAccess, this); } diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/ameta/AnalysisConstantFieldProvider.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/ameta/AnalysisConstantFieldProvider.java index 5b61e6ea32e4..103075939797 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/ameta/AnalysisConstantFieldProvider.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/ameta/AnalysisConstantFieldProvider.java @@ -45,9 +45,6 @@ public AnalysisConstantFieldProvider(MetaAccessProvider metaAccess, SVMHost host @Override public T readConstantField(ResolvedJavaField f, ConstantFieldTool analysisTool) { AnalysisField field = (AnalysisField) f; - if (!ReadableJavaField.isValueAvailable(field)) { - return null; - } T foldedValue = super.readConstantField(field, analysisTool); diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/ameta/AnalysisConstantReflectionProvider.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/ameta/AnalysisConstantReflectionProvider.java index 5df7adc0a78f..9ba901df5171 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/ameta/AnalysisConstantReflectionProvider.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/ameta/AnalysisConstantReflectionProvider.java @@ -76,6 +76,7 @@ public class AnalysisConstantReflectionProvider extends SharedConstantReflection private final ClassInitializationSupport classInitializationSupport; private final AnalysisMethodHandleAccessProvider methodHandleAccess; private SimulateClassInitializerSupport simulateClassInitializerSupport; + private final FieldValueInterceptionSupport fieldValueInterceptionSupport = FieldValueInterceptionSupport.singleton(); public AnalysisConstantReflectionProvider(AnalysisUniverse universe, UniverseMetaAccess metaAccess, ClassInitializationSupport classInitializationSupport) { this.universe = universe; @@ -227,7 +228,7 @@ public JavaConstant readValue(UniverseMetaAccess suppliedMetaAccess, AnalysisFie } if (value == null && receiver instanceof ImageHeapConstant heapConstant) { heapConstant.ensureReaderInstalled(); - AnalysisError.guarantee(ReadableJavaField.isValueAvailable(field), "Value not yet available for %s", field); + AnalysisError.guarantee(fieldValueInterceptionSupport.isValueAvailable(field), "Value not yet available for %s", field); ImageHeapInstance heapObject = (ImageHeapInstance) receiver; value = heapObject.readFieldValue(field); } @@ -245,7 +246,7 @@ public JavaConstant readValue(UniverseMetaAccess suppliedMetaAccess, AnalysisFie * heap is a snapshot of the hosted state; simulated values are a level above the shadow heap. */ public ValueSupplier readHostedFieldValue(AnalysisField field, JavaConstant receiver) { - if (ReadableJavaField.isValueAvailable(field)) { + if (fieldValueInterceptionSupport.isValueAvailable(field)) { /* Materialize and return the value. */ return ValueSupplier.eagerValue(doReadValue(field, receiver)); } @@ -258,7 +259,7 @@ public ValueSupplier readHostedFieldValue(AnalysisField field, Jav * during analysis or in a later phase. Attempts to materialize the value before it becomes * available will result in an error. */ - return ValueSupplier.lazyValue(() -> doReadValue(field, receiver), () -> ReadableJavaField.isValueAvailable(field)); + return ValueSupplier.lazyValue(() -> doReadValue(field, receiver), () -> fieldValueInterceptionSupport.isValueAvailable(field)); } /** Returns the hosted field value. The receiver must be a hosted constant. */ @@ -268,7 +269,7 @@ public JavaConstant readHostedFieldValue(UniverseMetaAccess access, AnalysisFiel } private JavaConstant doReadValue(AnalysisField field, JavaConstant receiver) { - return universe.fromHosted(ReadableJavaField.readFieldValue(classInitializationSupport, field.wrapped, receiver)); + return universe.fromHosted(fieldValueInterceptionSupport.readFieldValue(classInitializationSupport, field, receiver)); } /** diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/analysis/CustomTypeFieldHandler.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/ameta/CustomTypeFieldHandler.java similarity index 87% rename from substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/analysis/CustomTypeFieldHandler.java rename to substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/ameta/CustomTypeFieldHandler.java index faf8f040ce6e..fbaad53baafe 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/analysis/CustomTypeFieldHandler.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/ameta/CustomTypeFieldHandler.java @@ -22,7 +22,7 @@ * or visit www.oracle.com if you need additional information or have any * questions. */ -package com.oracle.svm.hosted.analysis; +package com.oracle.svm.hosted.ameta; import java.util.ArrayList; import java.util.List; @@ -36,11 +36,12 @@ import com.oracle.graal.pointsto.meta.AnalysisMetaAccess; import com.oracle.graal.pointsto.meta.AnalysisType; import com.oracle.graal.pointsto.meta.PointsToAnalysisField; -import com.oracle.svm.hosted.substitute.ComputedValueField; +import com.oracle.svm.hosted.analysis.FieldValueComputer; public abstract class CustomTypeFieldHandler { protected final BigBang bb; private final AnalysisMetaAccess metaAccess; + private final FieldValueInterceptionSupport fieldValueInterceptionSupport = FieldValueInterceptionSupport.singleton(); private Set processedFields = ConcurrentHashMap.newKeySet(); public CustomTypeFieldHandler(BigBang bb, AnalysisMetaAccess metaAccess) { @@ -49,7 +50,7 @@ public CustomTypeFieldHandler(BigBang bb, AnalysisMetaAccess metaAccess) { } public void handleField(AnalysisField field) { - if (processedFields.contains(field)) { + if (!processedFields.add(field)) { return; } /* @@ -57,21 +58,20 @@ public void handleField(AnalysisField field) { * types as allocated when the field is not yet accessed. */ assert field.isAccessed(); - if (field.wrapped instanceof ComputedValueField computedField) { - if (!computedField.isValueAvailable() && field.getJavaKind().isObject()) { + if (fieldValueInterceptionSupport.hasFieldValueTransformer(field)) { + if (field.getJavaKind().isObject() && !fieldValueInterceptionSupport.isValueAvailable(field)) { injectFieldTypes(field, field.getType()); } else if (bb.trackPrimitiveValues() && field.getStorageKind().isPrimitive() && field instanceof PointsToAnalysisField ptaField) { ptaField.saturatePrimitiveField(); } - } else if (field.isComputedValue()) { + } else if (fieldValueInterceptionSupport.lookupFieldValueInterceptor(field) instanceof FieldValueComputer fieldValueComputer) { if (field.getStorageKind().isObject()) { - field.setCanBeNull(field.computedValueCanBeNull()); - injectFieldTypes(field, transformTypes(field, field.computedValueTypes())); + field.setCanBeNull(fieldValueComputer.canBeNull()); + injectFieldTypes(field, transformTypes(field, fieldValueComputer.types())); } else if (bb.trackPrimitiveValues() && field.getStorageKind().isPrimitive() && field instanceof PointsToAnalysisField ptaField) { ptaField.saturatePrimitiveField(); } } - processedFields.add(field); } private void injectFieldTypes(AnalysisField field, List customTypes) { @@ -87,7 +87,7 @@ private void injectFieldTypes(AnalysisField field, List customType protected abstract void injectFieldTypes(AnalysisField aField, AnalysisType... customTypes); - private List transformTypes(AnalysisField field, Class[] types) { + private List transformTypes(AnalysisField field, List> types) { List customTypes = new ArrayList<>(); AnalysisType declaredType = field.getType(); diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/ameta/FieldValueInterceptionSupport.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/ameta/FieldValueInterceptionSupport.java new file mode 100644 index 000000000000..4975cb5eb161 --- /dev/null +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/ameta/FieldValueInterceptionSupport.java @@ -0,0 +1,298 @@ +/* + * Copyright (c) 2023, 2023, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.svm.hosted.ameta; + +import java.lang.reflect.Field; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.concurrent.ConcurrentHashMap; + +import org.graalvm.nativeimage.ImageSingletons; +import org.graalvm.nativeimage.hosted.Feature.BeforeAnalysisAccess; +import org.graalvm.nativeimage.hosted.FieldValueTransformer; + +import com.oracle.graal.pointsto.infrastructure.OriginalClassProvider; +import com.oracle.graal.pointsto.infrastructure.OriginalFieldProvider; +import com.oracle.graal.pointsto.meta.AnalysisField; +import com.oracle.graal.pointsto.meta.AnalysisType; +import com.oracle.graal.pointsto.util.GraalAccess; +import com.oracle.svm.core.BuildPhaseProvider; +import com.oracle.svm.core.annotate.RecomputeFieldValue; +import com.oracle.svm.core.fieldvaluetransformer.FieldValueTransformerWithAvailability; +import com.oracle.svm.core.fieldvaluetransformer.FieldValueTransformerWithAvailability.ValueAvailability; +import com.oracle.svm.core.heap.UnknownObjectField; +import com.oracle.svm.core.heap.UnknownPrimitiveField; +import com.oracle.svm.core.util.UserError; +import com.oracle.svm.core.util.VMError; +import com.oracle.svm.hosted.analysis.FieldValueComputer; +import com.oracle.svm.hosted.classinitialization.ClassInitializationSupport; +import com.oracle.svm.hosted.substitute.AnnotationSubstitutionProcessor; +import com.oracle.svm.hosted.substitute.AutomaticUnsafeTransformationSupport; +import com.oracle.svm.hosted.substitute.ComputedValueField; +import com.oracle.svm.hosted.substitute.FieldValueTransformation; +import com.oracle.svm.util.ReflectionUtil; + +import jdk.vm.ci.hotspot.HotSpotResolvedJavaField; +import jdk.vm.ci.meta.JavaConstant; +import jdk.vm.ci.meta.ResolvedJavaField; + +/** + * This class centralizes access to the several ways we have to transform and intercept field + * values: + * + * {@link FieldValueTransformer} are part of the supported API, and the preferred way of + * transformation. The non-API {@link FieldValueTransformerWithAvailability} allows to provide field + * values only after static analysis. The API for registration transformers + * {@link BeforeAnalysisAccess#registerFieldValueTransformer}. Transformers are also registered + * automatically by the {@link AutomaticUnsafeTransformationSupport}. + * + * {@link ComputedValueField} registered via the {@link RecomputeFieldValue} annotation is the + * legacy way of registering a transformer. Eventually, we want to remove {@link ComputedValueField} + * and only use field value transformer, but for now that is a functionally equivalent way of + * transformation and we always need to check for both. + * + * {@link UnknownObjectField} and {@link UnknownPrimitiveField} are internal annotations for fields + * whose value is only available after static analysis. Once the value is available, it is read as + * usual from the hosted HotSpot field without any further transformation. + */ +public final class FieldValueInterceptionSupport { + private static final Object INTERCEPTOR_ACCESSED_MARKER = new Object(); + + private final AnnotationSubstitutionProcessor annotationSubstitutions; + private final Map fieldValueInterceptors = new ConcurrentHashMap<>(); + + public static FieldValueInterceptionSupport singleton() { + return ImageSingletons.lookup(FieldValueInterceptionSupport.class); + } + + public FieldValueInterceptionSupport(AnnotationSubstitutionProcessor annotationSubstitutions) { + this.annotationSubstitutions = annotationSubstitutions; + } + + /** + * Register a field value transformer for the provided field. There can only be one transformer + * per field, if there is already a transformation in place, a {@link UserError} is reported. + */ + public void registerFieldValueTransformer(Field reflectionField, FieldValueTransformer transformer) { + registerFieldValueTransformer(GraalAccess.getOriginalProviders().getMetaAccess().lookupJavaField(reflectionField), transformer); + } + + public void registerFieldValueTransformer(ResolvedJavaField oField, FieldValueTransformer transformer) { + assert oField instanceof HotSpotResolvedJavaField : oField; + if (annotationSubstitutions.isDeleted(oField)) { + throw UserError.abort("Cannot register a field value transformer for field %s: %s", oField.format("%H.%n"), + "The field is marked as deleted, i.e., the field is not available on this platform"); + } + + var substitution = annotationSubstitutions.findSubstitution(oField); + if (substitution.isPresent() && substitution.get() instanceof ComputedValueField computedValueField && computedValueField.getRecomputeValueKind() != RecomputeFieldValue.Kind.None) { + throw UserError.abort("Cannot register a field value transformer for field %s: %s", oField.format("%H.%n"), "The field value is already transformed via an @Alias annotation."); + } + + var transformation = new FieldValueTransformation(OriginalClassProvider.getJavaClass(oField.getType()), Objects.requireNonNull(transformer), false); + var existingInterceptor = fieldValueInterceptors.putIfAbsent(oField, transformation); + + if (existingInterceptor == INTERCEPTOR_ACCESSED_MARKER) { + throw UserError.abort("Cannot register a field value transformer for field %s: %s", oField.format("%H.%n"), + "The field was already accessed by the static analysis. The transformer must be registered earlier, before the static analysis sees a reference to the field for the first time."); + } else if (existingInterceptor != null) { + throw UserError.abort("Cannot register a field value transformer for field %s: %s", oField.format("%H.%n"), + "A field value transformer is already registered for this field."); + } + } + + Object lookupFieldValueInterceptor(AnalysisField field) { + var result = field.getFieldValueInterceptor(); + if (result == null) { + result = computeAndCacheFieldValueInterceptor(field); + } + return result == INTERCEPTOR_ACCESSED_MARKER ? null : result; + } + + private Object computeAndCacheFieldValueInterceptor(AnalysisField field) { + /* + * Trigger computation of automatic substitutions. There might be an automatic substitution + * for the current field, and we must register it before checking if a field value + * transformer exists. + */ + field.beforeFieldValueAccess(); + + ResolvedJavaField oField = OriginalFieldProvider.getOriginalField(field); + assert oField == null || oField instanceof HotSpotResolvedJavaField : oField; + + FieldValueComputer computer = createFieldValueComputer(field); + Object result; + if (computer != null) { + VMError.guarantee(oField != null, "Cannot have a @UnknownObjectField or @UnknownPrimitiveField annotation on synthetic field %s", field); + + var interceptor = fieldValueInterceptors.computeIfAbsent(oField, k -> computer); + /* + * There can be a race with another thread, so `interceptor` might not be the same + * object as `computer`. But that is not a problem because they are equivalent + * `FieldValueComputer`. We only need to check that there was no field value transformer + * registered beforehand. Unfortunately, we do not have a good stack trace for the user + * showing how the field value transformer was created. But we expect this to be a rare + * error, since the `@Unknown*Field` annotations are not public API. + */ + if (!(interceptor instanceof FieldValueComputer)) { + throw UserError.abort("Cannot register a field value transformer for field %s: %s", field.format("%H.%n"), + "The field is annotated with @UnknownObjectField or @UnknownPrimitiveField."); + } + result = interceptor; + + } else if (oField != null) { + /* + * If no field value transformer was registered beforehand, install our marker value so + * that later registration of a field value transformer is reported as an error. + */ + result = fieldValueInterceptors.computeIfAbsent(oField, k -> INTERCEPTOR_ACCESSED_MARKER); + } else { + /* + * This is a synthetic field, so it is not possible to install a field value transformer + * for it. + */ + result = INTERCEPTOR_ACCESSED_MARKER; + } + + Objects.requireNonNull(result, "Must have a non-null value now to avoid repeated invocation of this method"); + /* + * Cache the result for future fast lookups. No need to be atomic here again, that was + * already done via the operations on `fieldValueInterceptors`. Multiple threads might write + * the same value into the cache. + */ + field.setFieldValueInterceptor(result); + return result; + } + + /** + * Check if the value of the provided field is currently available. After this method has been + * called, it is not possible to install a transformer anymore. + */ + public boolean isValueAvailable(AnalysisField field) { + var interceptor = lookupFieldValueInterceptor(field); + if (interceptor instanceof FieldValueTransformation transformation) { + if (transformation.getFieldValueTransformer() instanceof FieldValueTransformerWithAvailability transformerWithAvailability) { + if (!isAvailable(transformerWithAvailability.valueAvailability())) { + return false; + } + } + } else if (interceptor instanceof FieldValueComputer computer) { + if (!computer.isAvailable()) { + return false; + } + } else if (field.wrapped instanceof ReadableJavaField readableField) { + if (!readableField.isValueAvailable()) { + return false; + } + } + return true; + } + + private static boolean isAvailable(ValueAvailability availability) { + /* + * Note that we use isHostedUniverseBuild on purpose to define "available after analysis": + * many field value transformers require field offsets to be available, i.e., the hosted + * universe to be built. This ensures that such field value transformers do not have their + * value available when strengthening graphs after analysis, i.e., when applying analysis + * results back into the IR. + */ + return switch (availability) { + case BeforeAnalysis -> true; + case AfterAnalysis -> BuildPhaseProvider.isHostedUniverseBuilt(); + case AfterCompilation -> BuildPhaseProvider.isCompilationFinished(); + }; + } + + /** + * Returns true if a field value transformer has been registered for this field. After this + * method has been called, it is not possible to install a transformer anymore. + */ + public boolean hasFieldValueTransformer(AnalysisField field) { + var interceptor = lookupFieldValueInterceptor(field); + if (interceptor instanceof FieldValueTransformation) { + return true; + } else if (field.wrapped instanceof ComputedValueField) { + return true; + } + return false; + } + + JavaConstant readFieldValue(ClassInitializationSupport classInitializationSupport, AnalysisField field, JavaConstant receiver) { + assert isValueAvailable(field) : field; + + var interceptor = lookupFieldValueInterceptor(field); + if (interceptor instanceof FieldValueTransformation transformation) { + return transformation.readValue(classInitializationSupport, field.wrapped, receiver); + } else { + /* + * If the wrapped field is ComputedValueField, the ReadableJavaField handling does the + * necessary field value transformations. + */ + return ReadableJavaField.readFieldValue(classInitializationSupport, field.wrapped, receiver); + } + } + + private static FieldValueComputer createFieldValueComputer(AnalysisField field) { + UnknownObjectField unknownObjectField = field.getAnnotation(UnknownObjectField.class); + if (unknownObjectField != null) { + return new FieldValueComputer( + ReflectionUtil.newInstance(unknownObjectField.availability()), + extractAnnotationTypes(field, unknownObjectField.types(), unknownObjectField.fullyQualifiedTypes()), + unknownObjectField.canBeNull()); + } + UnknownPrimitiveField unknownPrimitiveField = field.getAnnotation(UnknownPrimitiveField.class); + if (unknownPrimitiveField != null) { + return new FieldValueComputer( + ReflectionUtil.newInstance(unknownPrimitiveField.availability()), + List.of(field.getType().getJavaClass()), + false); + } + return null; + } + + private static List> extractAnnotationTypes(AnalysisField field, Class[] types, String[] fullyQualifiedTypes) { + List> annotationTypes = new ArrayList<>(Arrays.asList(types)); + for (String annotationTypeName : fullyQualifiedTypes) { + try { + Class annotationType = Class.forName(annotationTypeName); + annotationTypes.add(annotationType); + } catch (ClassNotFoundException e) { + throw UserError.abort("Specified computed value type not found: " + annotationTypeName); + } + } + + if (annotationTypes.isEmpty()) { + /* If no types are specified, fall back to the field declared type. */ + AnalysisType fieldType = field.getType(); + UserError.guarantee(CustomTypeFieldHandler.isConcreteType(fieldType), "Illegal use of @UnknownObjectField annotation on field %s. " + + "The field type must be concrete or the annotation must declare a concrete type.", field); + annotationTypes.add(fieldType.getJavaClass()); + } + return annotationTypes; + } +} diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/ameta/ReadableJavaField.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/ameta/ReadableJavaField.java index 4897acd7e99d..4e255fc49bfa 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/ameta/ReadableJavaField.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/ameta/ReadableJavaField.java @@ -35,13 +35,6 @@ public interface ReadableJavaField extends ResolvedJavaField { - static boolean isValueAvailable(AnalysisField field) { - if (field.wrapped instanceof ReadableJavaField readableField) { - return readableField.isValueAvailable(); - } - return field.isValueAvailable(); - } - static JavaConstant readFieldValue(ClassInitializationSupport classInitializationSupport, ResolvedJavaField field, JavaConstant receiver) { assert !(field instanceof AnalysisField) && !(field instanceof HostedField) : "must have been unwrapped"; diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/analysis/FieldValueComputer.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/analysis/FieldValueComputer.java new file mode 100644 index 000000000000..b27391fa23ce --- /dev/null +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/analysis/FieldValueComputer.java @@ -0,0 +1,52 @@ +/* + * Copyright (c) 2023, 2023, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.svm.hosted.analysis; + +import java.util.List; +import java.util.function.BooleanSupplier; + +public final class FieldValueComputer { + private final BooleanSupplier availability; + private final List> types; + private final boolean canBeNull; + + public FieldValueComputer(BooleanSupplier availability, List> types, boolean canBeNull) { + this.availability = availability; + this.types = types; + this.canBeNull = canBeNull; + } + + public boolean isAvailable() { + return availability.getAsBoolean(); + } + + public List> types() { + return types; + } + + public boolean canBeNull() { + return canBeNull; + } +} diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/analysis/NativeImagePointsToAnalysis.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/analysis/NativeImagePointsToAnalysis.java index f984e4946e65..f9eb3ae3524d 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/analysis/NativeImagePointsToAnalysis.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/analysis/NativeImagePointsToAnalysis.java @@ -41,6 +41,7 @@ import com.oracle.graal.pointsto.util.TimerCollection; import com.oracle.svm.hosted.HostedConfiguration; import com.oracle.svm.hosted.SVMHost; +import com.oracle.svm.hosted.ameta.CustomTypeFieldHandler; import com.oracle.svm.hosted.code.IncompatibleClassChangeFallbackMethod; import com.oracle.svm.hosted.meta.HostedType; import com.oracle.svm.hosted.substitute.AnnotationSubstitutionProcessor; diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/analysis/NativeImageReachabilityAnalysisEngine.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/analysis/NativeImageReachabilityAnalysisEngine.java index 788139e03492..be0373bf07b4 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/analysis/NativeImageReachabilityAnalysisEngine.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/analysis/NativeImageReachabilityAnalysisEngine.java @@ -32,6 +32,7 @@ import com.oracle.graal.reachability.ReachabilityAnalysisEngine; import com.oracle.graal.reachability.ReachabilityMethodProcessingHandler; import com.oracle.svm.hosted.SVMHost; +import com.oracle.svm.hosted.ameta.CustomTypeFieldHandler; import com.oracle.svm.hosted.substitute.AnnotationSubstitutionProcessor; import jdk.graal.compiler.api.replacements.SnippetReflectionProvider; diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/analysis/PointsToCustomTypeFieldHandler.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/analysis/PointsToCustomTypeFieldHandler.java index bc0179a8138b..724a35c005ac 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/analysis/PointsToCustomTypeFieldHandler.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/analysis/PointsToCustomTypeFieldHandler.java @@ -29,6 +29,7 @@ import com.oracle.graal.pointsto.meta.AnalysisField; import com.oracle.graal.pointsto.meta.AnalysisMetaAccess; import com.oracle.graal.pointsto.meta.AnalysisType; +import com.oracle.svm.hosted.ameta.CustomTypeFieldHandler; public class PointsToCustomTypeFieldHandler extends CustomTypeFieldHandler { public PointsToCustomTypeFieldHandler(BigBang bb, AnalysisMetaAccess metaAccess) { diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/analysis/flow/SVMMethodTypeFlowBuilder.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/analysis/flow/SVMMethodTypeFlowBuilder.java index 7b6da38e8e38..de83d64c6372 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/analysis/flow/SVMMethodTypeFlowBuilder.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/analysis/flow/SVMMethodTypeFlowBuilder.java @@ -25,18 +25,6 @@ package com.oracle.svm.hosted.analysis.flow; -import jdk.graal.compiler.core.common.type.ObjectStamp; -import jdk.graal.compiler.core.common.type.Stamp; -import jdk.graal.compiler.debug.GraalError; -import jdk.graal.compiler.graph.Node; -import jdk.graal.compiler.nodes.CallTargetNode.InvokeKind; -import jdk.graal.compiler.nodes.ConstantNode; -import jdk.graal.compiler.nodes.FixedNode; -import jdk.graal.compiler.nodes.NodeView; -import jdk.graal.compiler.nodes.StructuredGraph; -import jdk.graal.compiler.nodes.ValueNode; -import jdk.graal.compiler.nodes.java.LoadFieldNode; - import com.oracle.graal.pointsto.AbstractAnalysisEngine; import com.oracle.graal.pointsto.PointsToAnalysis; import com.oracle.graal.pointsto.flow.MethodFlowsGraph; @@ -53,9 +41,20 @@ import com.oracle.svm.core.util.UserError.UserException; import com.oracle.svm.hosted.NativeImageOptions; import com.oracle.svm.hosted.SVMHost; +import com.oracle.svm.hosted.ameta.FieldValueInterceptionSupport; import com.oracle.svm.hosted.code.SubstrateCompilationDirectives; -import com.oracle.svm.hosted.substitute.ComputedValueField; +import jdk.graal.compiler.core.common.type.ObjectStamp; +import jdk.graal.compiler.core.common.type.Stamp; +import jdk.graal.compiler.debug.GraalError; +import jdk.graal.compiler.graph.Node; +import jdk.graal.compiler.nodes.CallTargetNode.InvokeKind; +import jdk.graal.compiler.nodes.ConstantNode; +import jdk.graal.compiler.nodes.FixedNode; +import jdk.graal.compiler.nodes.NodeView; +import jdk.graal.compiler.nodes.StructuredGraph; +import jdk.graal.compiler.nodes.ValueNode; +import jdk.graal.compiler.nodes.java.LoadFieldNode; import jdk.vm.ci.code.BytecodePosition; import jdk.vm.ci.meta.JavaConstant; import jdk.vm.ci.meta.JavaKind; @@ -159,7 +158,7 @@ protected void checkUnsafeOffset(ValueNode base, ValueNode offsetNode) { if (field.isStatic() && getHostVM().getClassInitializationSupport().maybeInitializeAtBuildTime(field.getDeclaringClass()) && !field.getDeclaringClass().unsafeFieldsRecomputed() && - !(field.wrapped instanceof ComputedValueField) && + !FieldValueInterceptionSupport.singleton().hasFieldValueTransformer(field) && !(base.isConstant() && base.asConstant().isDefaultForKind())) { String message = String.format("Field %s is used as an offset in an unsafe operation, but no value recomputation found.%n Wrapped field: %s", field, field.wrapped); message += String.format("%n Location: %s", pos); diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/fieldfolding/StaticFinalFieldFoldingNodePlugin.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/fieldfolding/StaticFinalFieldFoldingNodePlugin.java index 8c57bf0f90e2..661230b89b56 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/fieldfolding/StaticFinalFieldFoldingNodePlugin.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/fieldfolding/StaticFinalFieldFoldingNodePlugin.java @@ -26,6 +26,10 @@ import java.util.Arrays; +import com.oracle.graal.pointsto.meta.AnalysisField; +import com.oracle.graal.pointsto.meta.AnalysisMethod; +import com.oracle.svm.hosted.ameta.FieldValueInterceptionSupport; + import jdk.graal.compiler.nodes.ConstantNode; import jdk.graal.compiler.nodes.EndNode; import jdk.graal.compiler.nodes.IfNode; @@ -39,11 +43,6 @@ import jdk.graal.compiler.nodes.graphbuilderconf.GraphBuilderContext; import jdk.graal.compiler.nodes.graphbuilderconf.NodePlugin; import jdk.graal.compiler.nodes.type.StampTool; - -import com.oracle.graal.pointsto.meta.AnalysisField; -import com.oracle.graal.pointsto.meta.AnalysisMethod; -import com.oracle.svm.hosted.ameta.ReadableJavaField; - import jdk.vm.ci.meta.JavaConstant; import jdk.vm.ci.meta.ResolvedJavaField; @@ -53,6 +52,7 @@ final class StaticFinalFieldFoldingNodePlugin implements NodePlugin { private final StaticFinalFieldFoldingFeature feature; + private final FieldValueInterceptionSupport fieldValueInterceptionSupport = FieldValueInterceptionSupport.singleton(); StaticFinalFieldFoldingNodePlugin(StaticFinalFieldFoldingFeature feature) { this.feature = feature; @@ -80,7 +80,7 @@ public boolean handleLoadStaticField(GraphBuilderContext b, ResolvedJavaField fi return false; } - if (!ReadableJavaField.isValueAvailable(aField)) { + if (!fieldValueInterceptionSupport.isValueAvailable(aField)) { /* * Cannot optimize static field whose value is recomputed and is not yet available, * i.e., it may depend on analysis/compilation derived data. diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/heap/HeapDumpHostedUtils.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/heap/HeapDumpHostedUtils.java index ceb2491d81ab..8fd3c0114683 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/heap/HeapDumpHostedUtils.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/heap/HeapDumpHostedUtils.java @@ -27,8 +27,6 @@ import java.io.UnsupportedEncodingException; import java.util.Collection; -import jdk.graal.compiler.core.common.util.TypeConversion; -import jdk.graal.compiler.core.common.util.UnsafeArrayTypeWriter; import org.graalvm.nativeimage.Platform; import org.graalvm.nativeimage.Platforms; @@ -37,6 +35,8 @@ import com.oracle.svm.core.util.ByteArrayReader; import com.oracle.svm.core.util.VMError; +import jdk.graal.compiler.core.common.util.TypeConversion; +import jdk.graal.compiler.core.common.util.UnsafeArrayTypeWriter; import jdk.vm.ci.meta.ResolvedJavaField; /** Legacy implementation, only used by other legacy code (see GR-44538). */ @@ -80,14 +80,14 @@ public static void writeFieldsInfo(UnsafeArrayTypeWriter writeBuffer, Collection for (ResolvedJavaField resolvedJavaField : inHotSpotFieldOrder(sfields)) { if (resolvedJavaField instanceof SharedField) { final SharedField field = (SharedField) resolvedJavaField; - if (!field.isWritten() && field.isValueAvailable()) { - /* I am only interested in fields that are not constants. */ - continue; - } if (!field.isAccessed()) { /* I am only interested in fields that are used. */ continue; } + if (!field.isWritten() && field.isValueAvailable()) { + /* I am only interested in fields that are not constants. */ + continue; + } writeField(field, writeBuffer); } } diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/heap/SVMImageHeapScanner.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/heap/SVMImageHeapScanner.java index 83970e32cd64..d75382b40d3a 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/heap/SVMImageHeapScanner.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/heap/SVMImageHeapScanner.java @@ -51,7 +51,7 @@ import com.oracle.svm.core.util.VMError; import com.oracle.svm.hosted.ImageClassLoader; import com.oracle.svm.hosted.ameta.AnalysisConstantReflectionProvider; -import com.oracle.svm.hosted.ameta.ReadableJavaField; +import com.oracle.svm.hosted.ameta.FieldValueInterceptionSupport; import com.oracle.svm.hosted.classinitialization.SimulateClassInitializerSupport; import com.oracle.svm.hosted.methodhandles.MethodHandleFeature; import com.oracle.svm.hosted.reflect.ReflectionHostedSupport; @@ -75,6 +75,7 @@ public class SVMImageHeapScanner extends ImageHeapScanner { private final MethodHandleFeature methodHandleSupport; private final Class directMethodHandleClass; private final VarHandleFeature varHandleSupport; + private final FieldValueInterceptionSupport fieldValueInterceptionSupport; @SuppressWarnings("this-escape") public SVMImageHeapScanner(BigBang bb, ImageHeap imageHeap, ImageClassLoader loader, AnalysisMetaAccess metaAccess, @@ -92,6 +93,7 @@ public SVMImageHeapScanner(BigBang bb, ImageHeap imageHeap, ImageClassLoader loa methodHandleSupport = ImageSingletons.lookup(MethodHandleFeature.class); directMethodHandleClass = getClass("java.lang.invoke.DirectMethodHandle"); varHandleSupport = ImageSingletons.lookup(VarHandleFeature.class); + fieldValueInterceptionSupport = FieldValueInterceptionSupport.singleton(); } public static ImageHeapScanner instance() { @@ -111,7 +113,7 @@ protected ImageHeapConstant getOrCreateImageHeapConstant(JavaConstant javaConsta @Override public boolean isValueAvailable(AnalysisField field) { - return ReadableJavaField.isValueAvailable(field); + return fieldValueInterceptionSupport.isValueAvailable(field); } /** diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/meta/HostedField.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/meta/HostedField.java index f397d729b7a2..f13a5ef104e3 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/meta/HostedField.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/meta/HostedField.java @@ -24,15 +24,14 @@ */ package com.oracle.svm.hosted.meta; -import java.lang.reflect.Field; - import com.oracle.graal.pointsto.infrastructure.OriginalFieldProvider; import com.oracle.graal.pointsto.infrastructure.WrappedJavaField; import com.oracle.graal.pointsto.meta.AnalysisField; import com.oracle.svm.core.meta.SharedField; -import com.oracle.svm.hosted.ameta.ReadableJavaField; +import com.oracle.svm.hosted.ameta.FieldValueInterceptionSupport; import jdk.vm.ci.meta.JavaKind; +import jdk.vm.ci.meta.ResolvedJavaField; /** * Store the compile-time information for a field in the Substrate VM, such as the field offset. @@ -112,7 +111,7 @@ public boolean isWritten() { @Override public boolean isValueAvailable() { - return ReadableJavaField.isValueAvailable(wrapped); + return FieldValueInterceptionSupport.singleton().isValueAvailable(wrapped); } @Override @@ -166,7 +165,7 @@ public JavaKind getStorageKind() { } @Override - public Field getJavaField() { - return wrapped.getJavaField(); + public ResolvedJavaField unwrapTowardsOriginalField() { + return wrapped; } } diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/meta/SharedConstantFieldProvider.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/meta/SharedConstantFieldProvider.java index af5e9b8b83c3..4f097d792e9f 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/meta/SharedConstantFieldProvider.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/meta/SharedConstantFieldProvider.java @@ -24,7 +24,6 @@ */ package com.oracle.svm.hosted.meta; -import jdk.graal.compiler.core.common.spi.JavaConstantFieldProvider; import org.graalvm.nativeimage.Platform; import org.graalvm.nativeimage.Platforms; @@ -32,8 +31,9 @@ import com.oracle.graal.pointsto.meta.AnalysisField; import com.oracle.svm.core.meta.MethodPointer; import com.oracle.svm.hosted.SVMHost; -import com.oracle.svm.hosted.ameta.ReadableJavaField; +import com.oracle.svm.hosted.ameta.FieldValueInterceptionSupport; +import jdk.graal.compiler.core.common.spi.JavaConstantFieldProvider; import jdk.vm.ci.meta.JavaConstant; import jdk.vm.ci.meta.JavaKind; import jdk.vm.ci.meta.MetaAccessProvider; @@ -44,6 +44,7 @@ public abstract class SharedConstantFieldProvider extends JavaConstantFieldProvi protected final UniverseMetaAccess metaAccess; protected final SVMHost hostVM; + protected final FieldValueInterceptionSupport fieldValueInterceptionSupport = FieldValueInterceptionSupport.singleton(); public SharedConstantFieldProvider(MetaAccessProvider metaAccess, SVMHost hostVM) { super(metaAccess); @@ -51,14 +52,6 @@ public SharedConstantFieldProvider(MetaAccessProvider metaAccess, SVMHost hostVM this.hostVM = hostVM; } - @Override - public T readConstantField(ResolvedJavaField field, ConstantFieldTool analysisTool) { - if (!ReadableJavaField.isValueAvailable(asAnalysisField(field))) { - return null; - } - return super.readConstantField(field, analysisTool); - } - protected abstract AnalysisField asAnalysisField(ResolvedJavaField field); @Override @@ -83,10 +76,24 @@ public boolean isStableField(ResolvedJavaField field, ConstantFieldTool tool) } private boolean allowConstantFolding(ResolvedJavaField field) { - if (field.isStatic() && !isClassInitialized(field) && !(asAnalysisField(field).getWrapped() instanceof ReadableJavaField)) { + var aField = asAnalysisField(field); + + /* + * This code should run as late as possible, because it has side effects. So we only do it + * after we have already checked that the field is `final` or `stable`. It marks the + * declaring class of the field as reachable, in order to trigger computation of automatic + * substitutions. It also ensures that the class is initialized (if the class is registered + * for initialization at build time) before any constant folding of static fields is + * attempted. + */ + if (!fieldValueInterceptionSupport.isValueAvailable(aField)) { + return false; + } + + if (field.isStatic() && !isClassInitialized(field) && !fieldValueInterceptionSupport.hasFieldValueTransformer(aField)) { /* * The class is not initialized at image build time, so we do not have a static field - * value to constant fold. Note that a ReadableJavaField is able to provide a field + * value to constant fold. Note that a FieldValueTransformer is able to provide a field * value also for non-initialized classes. */ return false; diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/meta/UniverseBuilder.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/meta/UniverseBuilder.java index 9aace5aa2b1a..1ceab52617d5 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/meta/UniverseBuilder.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/meta/UniverseBuilder.java @@ -91,7 +91,7 @@ import com.oracle.svm.hosted.FeatureImpl.BeforeAnalysisAccessImpl; import com.oracle.svm.hosted.HostedConfiguration; import com.oracle.svm.hosted.NativeImageOptions; -import com.oracle.svm.hosted.ameta.ReadableJavaField; +import com.oracle.svm.hosted.ameta.FieldValueInterceptionSupport; import com.oracle.svm.hosted.annotation.CustomSubstitutionMethod; import com.oracle.svm.hosted.config.HybridLayout; import com.oracle.svm.hosted.heap.PodSupport; @@ -1133,13 +1133,14 @@ private static boolean excludeFromReferenceMap(HostedField field) { } private void processFieldLocations() { + var fieldValueInterceptionSupport = FieldValueInterceptionSupport.singleton(); for (HostedField hField : hUniverse.fields.values()) { AnalysisField aField = hField.wrapped; if (aField.wrapped instanceof ComputedValueField) { ((ComputedValueField) aField.wrapped).processSubstrate(hMetaAccess); } - if (!hField.hasLocation() && Modifier.isStatic(hField.getModifiers()) && !aField.isWritten() && ReadableJavaField.isValueAvailable(aField)) { + if (hField.isReachable() && !hField.hasLocation() && Modifier.isStatic(hField.getModifiers()) && !aField.isWritten() && fieldValueInterceptionSupport.isValueAvailable(aField)) { hField.setUnmaterializedStaticConstant(); } } diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/phases/SharedGraphBuilderPhase.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/phases/SharedGraphBuilderPhase.java index 824f7feb9c50..aa017bdf5f4e 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/phases/SharedGraphBuilderPhase.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/phases/SharedGraphBuilderPhase.java @@ -541,7 +541,7 @@ private static Class findResolutionError Class[] searchSignature = signatureToClasses(searchMethod); Class searchReturnType = null; if (searchMethod.getSignature().getReturnType(null) instanceof ResolvedJavaType) { - searchReturnType = OriginalClassProvider.getJavaClass((ResolvedJavaType) searchMethod.getSignature().getReturnType(null)); + searchReturnType = OriginalClassProvider.getJavaClass(searchMethod.getSignature().getReturnType(null)); } Class declaringClass = OriginalClassProvider.getJavaClass(declaringType); @@ -585,7 +585,7 @@ private static Class[] signatureToClasses(JavaMethod method) { for (int i = 0; i < paramCount; i++) { JavaType parameterType = method.getSignature().getParameterType(i, null); if (parameterType instanceof ResolvedJavaType) { - result[i] = OriginalClassProvider.getJavaClass((ResolvedJavaType) parameterType); + result[i] = OriginalClassProvider.getJavaClass(parameterType); } } return result; diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/snippets/ReflectionPlugins.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/snippets/ReflectionPlugins.java index e048e06e2e86..3790e75bbe5d 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/snippets/ReflectionPlugins.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/snippets/ReflectionPlugins.java @@ -644,7 +644,7 @@ private Object unboxObjectConstant(GraphBuilderContext b, JavaConstant argConsta */ @SuppressWarnings("unchecked") private T getIntrinsic(GraphBuilderContext context, T element) { - if (reason == ParsingReason.UnsafeSubstitutionAnalysis || reason == ParsingReason.EarlyClassInitializerAnalysis) { + if (reason == ParsingReason.AutomaticUnsafeTransformation || reason == ParsingReason.EarlyClassInitializerAnalysis) { /* We are analyzing the static initializers and should always intrinsify. */ return element; } diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/snippets/SubstrateGraphBuilderPlugins.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/snippets/SubstrateGraphBuilderPlugins.java index 909a466dc167..a36c127bfb6f 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/snippets/SubstrateGraphBuilderPlugins.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/snippets/SubstrateGraphBuilderPlugins.java @@ -1320,7 +1320,7 @@ protected ValueNode getFieldOffset(GraphBuilderContext b, ResolvedJavaField fiel if (field instanceof AnalysisField) { ((AnalysisField) field).registerAsUnsafeAccessed(nonNullReason(b.getGraph().currentNodeSourcePosition())); } - return LazyConstantNode.create(StampFactory.forKind(JavaKind.Long), new FieldOffsetConstantProvider(((OriginalFieldProvider) field).getJavaField()), b); + return LazyConstantNode.create(StampFactory.forKind(JavaKind.Long), new FieldOffsetConstantProvider(OriginalFieldProvider.getJavaField(field)), b); } @Override diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/substitute/AnnotatedField.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/substitute/AnnotatedField.java index eb2f8aa22486..cab58f3f8fb0 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/substitute/AnnotatedField.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/substitute/AnnotatedField.java @@ -26,7 +26,6 @@ import java.lang.annotation.Annotation; import java.lang.reflect.AnnotatedElement; -import java.lang.reflect.Field; import com.oracle.graal.pointsto.infrastructure.OriginalFieldProvider; import com.oracle.svm.core.BuildPhaseProvider; @@ -123,8 +122,8 @@ public String toString() { } @Override - public Field getJavaField() { - return OriginalFieldProvider.getJavaField(original); + public ResolvedJavaField unwrapTowardsOriginalField() { + return original; } @Override diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/substitute/AnnotationSubstitutionProcessor.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/substitute/AnnotationSubstitutionProcessor.java index 8970ee6efc23..053b1b94d5ca 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/substitute/AnnotationSubstitutionProcessor.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/substitute/AnnotationSubstitutionProcessor.java @@ -50,7 +50,6 @@ import org.graalvm.nativeimage.ImageSingletons; import org.graalvm.nativeimage.Platform; import org.graalvm.nativeimage.Platforms; -import org.graalvm.nativeimage.hosted.FieldValueTransformer; import com.oracle.graal.pointsto.BigBang; import com.oracle.graal.pointsto.infrastructure.SubstitutionProcessor; @@ -107,7 +106,7 @@ public class AnnotationSubstitutionProcessor extends SubstitutionProcessor { private final Map methodSubstitutions; private final Map polymorphicMethodSubstitutions; private final Map fieldSubstitutions; - private ClassInitializationSupport classInitializationSupport; + private final ClassInitializationSupport classInitializationSupport; public AnnotationSubstitutionProcessor(ImageClassLoader imageClassLoader, MetaAccessProvider metaAccess, ClassInitializationSupport classInitializationSupport) { this.imageClassLoader = imageClassLoader; @@ -121,20 +120,6 @@ public AnnotationSubstitutionProcessor(ImageClassLoader imageClassLoader, MetaAc fieldSubstitutions = new ConcurrentHashMap<>(); } - public void registerFieldValueTransformer(Field reflectionField, FieldValueTransformer transformer) { - ResolvedJavaField field = metaAccess.lookupJavaField(reflectionField); - boolean isFinal = field.isFinal(); - ComputedValueField computedValueField = new ComputedValueField(field, field, Kind.Custom, reflectionField.getType(), transformer, null, null, isFinal, false); - ResolvedJavaField existingSubstitution = fieldSubstitutions.put(field, computedValueField); - - if (existingSubstitution != null) { - String reason = existingSubstitution.equals(field) - ? "The field was already accessed by the static analysis. The transformer must be registered earlier, before the static analysis sees a reference to the field for the first time." - : "A field value transformer is already registered for this field."; - throw UserError.abort("Cannot register a field value transformer for field %s: %s", field, reason); - } - } - @Override public ResolvedJavaType lookup(ResolvedJavaType type) { Delete deleteAnnotation = deleteAnnotations.get(type); @@ -200,12 +185,7 @@ public ResolvedJavaField lookup(ResolvedJavaField field) { throw new DeletedElementException(deleteErrorMessage(field, deleteAnnotation, true)); } - /* - * If there is no substitution registered yet, put in the field itself as a marker that the - * field was used in a lookup. Registering a substitution after a lookup was done is not - * allowed because that means the substitution was missed in the prior lookup. - */ - ResolvedJavaField existing = fieldSubstitutions.putIfAbsent(field, field); + ResolvedJavaField existing = fieldSubstitutions.get(field); return existing != null ? existing : field; } @@ -996,12 +976,12 @@ private ResolvedJavaField fieldValueRecomputation(Class originalClass, Resolv } Class transformedValueAllowedType = getTargetClass(annotatedField.getType()); - return new ComputedValueField(original, annotated, kind, transformedValueAllowedType, null, targetClass, targetName, isFinal, disableCaching); + return ComputedValueField.create(original, annotated, kind, transformedValueAllowedType, null, targetClass, targetName, isFinal, disableCaching); } protected void reinitializeField(Field annotatedField) { ResolvedJavaField annotated = metaAccess.lookupJavaField(annotatedField); - ComputedValueField alias = new ComputedValueField(annotated, annotated, Kind.Reset, annotatedField.getDeclaringClass(), "", false); + ComputedValueField alias = ComputedValueField.create(annotated, annotated, Kind.Reset, annotatedField.getDeclaringClass(), "", false); register(fieldSubstitutions, annotated, annotated, alias); } diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/substitute/UnsafeAutomaticSubstitutionProcessor.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/substitute/AutomaticUnsafeTransformationSupport.java similarity index 73% rename from substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/substitute/UnsafeAutomaticSubstitutionProcessor.java rename to substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/substitute/AutomaticUnsafeTransformationSupport.java index 83754b3fdf1a..088511b32352 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/substitute/UnsafeAutomaticSubstitutionProcessor.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/substitute/AutomaticUnsafeTransformationSupport.java @@ -37,12 +37,38 @@ import java.util.ArrayList; import java.util.HashSet; import java.util.List; -import java.util.Map; import java.util.Optional; -import java.util.concurrent.ConcurrentHashMap; import java.util.function.Supplier; import java.util.stream.Collectors; +import org.graalvm.nativeimage.ImageSingletons; +import org.graalvm.nativeimage.hosted.FieldValueTransformer; + +import com.oracle.graal.pointsto.BigBang; +import com.oracle.graal.pointsto.api.DefaultUnsafePartition; +import com.oracle.graal.pointsto.phases.NoClassInitializationPlugin; +import com.oracle.graal.pointsto.util.GraalAccess; +import com.oracle.svm.core.ParsingReason; +import com.oracle.svm.core.annotate.RecomputeFieldValue; +import com.oracle.svm.core.annotate.RecomputeFieldValue.Kind; +import com.oracle.svm.core.fieldvaluetransformer.ArrayBaseOffsetFieldValueTransformer; +import com.oracle.svm.core.fieldvaluetransformer.ArrayIndexScaleFieldValueTransformer; +import com.oracle.svm.core.fieldvaluetransformer.ArrayIndexShiftFieldValueTransformer; +import com.oracle.svm.core.fieldvaluetransformer.FieldOffsetFieldValueTransformer; +import com.oracle.svm.core.fieldvaluetransformer.StaticFieldBaseFieldValueTransformer; +import com.oracle.svm.core.option.HostedOptionKey; +import com.oracle.svm.core.option.SubstrateOptionsParser; +import com.oracle.svm.core.util.VMError; +import com.oracle.svm.hosted.FallbackFeature; +import com.oracle.svm.hosted.ImageClassLoader; +import com.oracle.svm.hosted.SVMHost; +import com.oracle.svm.hosted.ameta.FieldValueInterceptionSupport; +import com.oracle.svm.hosted.classinitialization.ClassInitializerGraphBuilderPhase; +import com.oracle.svm.hosted.phases.ConstantFoldLoadFieldPlugin; +import com.oracle.svm.hosted.snippets.ReflectionPlugins; +import com.oracle.svm.util.LogUtils; +import com.oracle.svm.util.ReflectionUtil; + import jdk.graal.compiler.api.replacements.SnippetReflectionProvider; import jdk.graal.compiler.debug.DebugContext; import jdk.graal.compiler.debug.DebugContext.Builder; @@ -72,29 +98,6 @@ import jdk.graal.compiler.phases.common.CanonicalizerPhase; import jdk.graal.compiler.phases.tiers.HighTierContext; import jdk.graal.compiler.phases.util.Providers; -import org.graalvm.nativeimage.ImageSingletons; - -import com.oracle.graal.pointsto.infrastructure.SubstitutionProcessor; -import com.oracle.graal.pointsto.meta.AnalysisType; -import com.oracle.graal.pointsto.phases.NoClassInitializationPlugin; -import com.oracle.graal.pointsto.util.GraalAccess; -import com.oracle.svm.core.ParsingReason; -import com.oracle.svm.core.annotate.RecomputeFieldValue; -import com.oracle.svm.core.annotate.RecomputeFieldValue.Kind; -import com.oracle.svm.core.feature.AutomaticallyRegisteredFeature; -import com.oracle.svm.core.feature.InternalFeature; -import com.oracle.svm.core.option.HostedOptionKey; -import com.oracle.svm.core.option.SubstrateOptionsParser; -import com.oracle.svm.core.util.VMError; -import com.oracle.svm.hosted.FallbackFeature; -import com.oracle.svm.hosted.FeatureImpl.DuringAnalysisAccessImpl; -import com.oracle.svm.hosted.ImageClassLoader; -import com.oracle.svm.hosted.SVMHost; -import com.oracle.svm.hosted.classinitialization.ClassInitializerGraphBuilderPhase; -import com.oracle.svm.hosted.phases.ConstantFoldLoadFieldPlugin; -import com.oracle.svm.hosted.snippets.ReflectionPlugins; -import com.oracle.svm.util.LogUtils; - import jdk.vm.ci.meta.JavaConstant; import jdk.vm.ci.meta.JavaKind; import jdk.vm.ci.meta.MetaAccessProvider; @@ -103,82 +106,56 @@ import jdk.vm.ci.meta.ResolvedJavaMethod; import jdk.vm.ci.meta.ResolvedJavaType; -@AutomaticallyRegisteredFeature -class AutomaticSubstitutionFeature implements InternalFeature { - - @Override - public void duringAnalysis(DuringAnalysisAccess access) { - DuringAnalysisAccessImpl accessImpl = (DuringAnalysisAccessImpl) access; - UnsafeAutomaticSubstitutionProcessor automaticSubstitutions = accessImpl.getHostVM().getAutomaticSubstitutionProcessor(); - automaticSubstitutions.processComputedValueFields(accessImpl); - } -} - /** - * This class tries to registered automatic substitutions for field offset, array base, array index + * This class tries to registered field value transformer for field offset, array base, array index * scale and array index shift unsafe computations. */ -public class UnsafeAutomaticSubstitutionProcessor extends SubstitutionProcessor { +public class AutomaticUnsafeTransformationSupport { private static final int BASIC_LEVEL = 1; private static final int INFO_LEVEL = 2; private static final int DEBUG_LEVEL = 3; static class Options { - - @Option(help = "Unsafe automatic substitutions logging level: Disabled=0, Basic=1, Info=2, Debug=3.)")// - static final HostedOptionKey UnsafeAutomaticSubstitutionsLogLevel = new HostedOptionKey<>(BASIC_LEVEL); + @Option(help = "Automatic unsafe field value transformation logging level: Disabled=0, Basic=1, Info=2, Debug=3.)") // + static final HostedOptionKey AutomaticUnsafeTransformationLogLevel = new HostedOptionKey<>(BASIC_LEVEL); } private final AnnotationSubstitutionProcessor annotationSubstitutions; - private final Map fieldSubstitutions; private final List suppressWarnings; - private static ResolvedJavaType resolvedUnsafeClass; - private static ResolvedJavaType resolvedSunMiscUnsafeClass; + private final ResolvedJavaType jdkInternalUnsafeType; + private final ResolvedJavaType sunMiscUnsafeType; - private ResolvedJavaMethod unsafeStaticFieldOffsetMethod; - private ResolvedJavaMethod unsafeStaticFieldBaseMethod; - private ResolvedJavaMethod unsafeObjectFieldOffsetFieldMethod; - private ResolvedJavaMethod sunMiscUnsafeObjectFieldOffsetMethod; - private ResolvedJavaMethod unsafeObjectFieldOffsetClassStringMethod; - private ResolvedJavaMethod unsafeArrayBaseOffsetMethod; - private ResolvedJavaMethod unsafeArrayIndexScaleMethod; - private ResolvedJavaMethod integerNumberOfLeadingZerosMethod; + private final ResolvedJavaMethod unsafeStaticFieldOffsetMethod; + private final ResolvedJavaMethod unsafeStaticFieldBaseMethod; + private final ResolvedJavaMethod unsafeObjectFieldOffsetFieldMethod; + private final ResolvedJavaMethod sunMiscUnsafeObjectFieldOffsetMethod; + private final ResolvedJavaMethod unsafeObjectFieldOffsetClassStringMethod; + private final ResolvedJavaMethod unsafeArrayBaseOffsetMethod; + private final ResolvedJavaMethod unsafeArrayIndexScaleMethod; + private final ResolvedJavaMethod integerNumberOfLeadingZerosMethod; - private HashSet neverInlineSet = new HashSet<>(); - private HashSet noCheckedExceptionsSet = new HashSet<>(); + private final HashSet neverInlineSet = new HashSet<>(); + private final HashSet noCheckedExceptionsSet = new HashSet<>(); - private Plugins plugins; + private final Plugins plugins; private final OptionValues options; - private final SnippetReflectionProvider snippetReflection; - public UnsafeAutomaticSubstitutionProcessor(OptionValues options, AnnotationSubstitutionProcessor annotationSubstitutions, SnippetReflectionProvider snippetReflection) { + public AutomaticUnsafeTransformationSupport(OptionValues options, AnnotationSubstitutionProcessor annotationSubstitutions, ImageClassLoader loader) { this.options = options; - this.snippetReflection = snippetReflection; this.annotationSubstitutions = annotationSubstitutions; - this.fieldSubstitutions = new ConcurrentHashMap<>(); - this.suppressWarnings = new ArrayList<>(); - } - - public void init(ImageClassLoader loader, MetaAccessProvider originalMetaAccess) { - ResolvedJavaMethod atomicIntegerFieldUpdaterNewUpdaterMethod; - ResolvedJavaMethod atomicLongFieldUpdaterNewUpdaterMethod; - ResolvedJavaMethod atomicReferenceFieldUpdaterNewUpdaterMethod; - - ResolvedJavaMethod fieldSetAccessibleMethod; - ResolvedJavaMethod fieldGetMethod; + MetaAccessProvider originalMetaAccess = GraalAccess.getOriginalProviders().getMetaAccess(); try { - Method fieldSetAccessible = Field.class.getMethod("setAccessible", boolean.class); - fieldSetAccessibleMethod = originalMetaAccess.lookupJavaMethod(fieldSetAccessible); + ResolvedJavaMethod fieldSetAccessibleMethod = originalMetaAccess.lookupJavaMethod(fieldSetAccessible); neverInlineSet.add(fieldSetAccessibleMethod); Method fieldGet = Field.class.getMethod("get", Object.class); - fieldGetMethod = originalMetaAccess.lookupJavaMethod(fieldGet); + ResolvedJavaMethod fieldGetMethod = originalMetaAccess.lookupJavaMethod(fieldGet); neverInlineSet.add(fieldGetMethod); /* @@ -186,39 +163,31 @@ public void init(ImageClassLoader loader, MetaAccessProvider originalMetaAccess) * There is no need to analyze these calls because VarHandle accesses are intrinsified * to simple array and field access nodes during inlining before analysis. */ - for (Method method : loader.findClassOrFail("java.lang.invoke.VarHandles").getDeclaredMethods()) { + for (Method method : ReflectionUtil.lookupClass(false, "java.lang.invoke.VarHandles").getDeclaredMethods()) { neverInlineSet.add(originalMetaAccess.lookupJavaMethod(method)); } - Class unsafeClass; - Class sunMiscUnsafeClass; - - try { - sunMiscUnsafeClass = Class.forName("sun.misc.Unsafe"); - unsafeClass = Class.forName("jdk.internal.misc.Unsafe"); - } catch (ClassNotFoundException cnfe) { - throw VMError.shouldNotReachHere(cnfe); - } - - resolvedUnsafeClass = originalMetaAccess.lookupJavaType(unsafeClass); - resolvedSunMiscUnsafeClass = originalMetaAccess.lookupJavaType(sunMiscUnsafeClass); + Class sunMiscUnsafeClass = ReflectionUtil.lookupClass(false, "sun.misc.Unsafe"); + sunMiscUnsafeType = originalMetaAccess.lookupJavaType(sunMiscUnsafeClass); + Class jdkInternalUnsafeClass = jdk.internal.misc.Unsafe.class; + jdkInternalUnsafeType = originalMetaAccess.lookupJavaType(jdkInternalUnsafeClass); - Method unsafeStaticFieldOffset = unsafeClass.getMethod("staticFieldOffset", Field.class); + Method unsafeStaticFieldOffset = jdkInternalUnsafeClass.getMethod("staticFieldOffset", Field.class); unsafeStaticFieldOffsetMethod = originalMetaAccess.lookupJavaMethod(unsafeStaticFieldOffset); noCheckedExceptionsSet.add(unsafeStaticFieldOffsetMethod); neverInlineSet.add(unsafeStaticFieldOffsetMethod); - Method unsafeStaticFieldBase = unsafeClass.getMethod("staticFieldBase", Field.class); + Method unsafeStaticFieldBase = jdkInternalUnsafeClass.getMethod("staticFieldBase", Field.class); unsafeStaticFieldBaseMethod = originalMetaAccess.lookupJavaMethod(unsafeStaticFieldBase); noCheckedExceptionsSet.add(unsafeStaticFieldBaseMethod); neverInlineSet.add(unsafeStaticFieldBaseMethod); - Method unsafeObjectFieldOffset = unsafeClass.getMethod("objectFieldOffset", java.lang.reflect.Field.class); + Method unsafeObjectFieldOffset = jdkInternalUnsafeClass.getMethod("objectFieldOffset", java.lang.reflect.Field.class); unsafeObjectFieldOffsetFieldMethod = originalMetaAccess.lookupJavaMethod(unsafeObjectFieldOffset); noCheckedExceptionsSet.add(unsafeObjectFieldOffsetFieldMethod); neverInlineSet.add(unsafeObjectFieldOffsetFieldMethod); - Method unsafeObjectClassStringOffset = unsafeClass.getMethod("objectFieldOffset", java.lang.Class.class, String.class); + Method unsafeObjectClassStringOffset = jdkInternalUnsafeClass.getMethod("objectFieldOffset", java.lang.Class.class, String.class); unsafeObjectFieldOffsetClassStringMethod = originalMetaAccess.lookupJavaMethod(unsafeObjectClassStringOffset); noCheckedExceptionsSet.add(unsafeObjectFieldOffsetClassStringMethod); neverInlineSet.add(unsafeObjectFieldOffsetClassStringMethod); @@ -233,12 +202,12 @@ public void init(ImageClassLoader loader, MetaAccessProvider originalMetaAccess) noCheckedExceptionsSet.add(sunMiscUnsafeObjectFieldOffsetMethod); neverInlineSet.add(sunMiscUnsafeObjectFieldOffsetMethod); - Method unsafeArrayBaseOffset = unsafeClass.getMethod("arrayBaseOffset", java.lang.Class.class); + Method unsafeArrayBaseOffset = jdkInternalUnsafeClass.getMethod("arrayBaseOffset", java.lang.Class.class); unsafeArrayBaseOffsetMethod = originalMetaAccess.lookupJavaMethod(unsafeArrayBaseOffset); noCheckedExceptionsSet.add(unsafeArrayBaseOffsetMethod); neverInlineSet.add(unsafeArrayBaseOffsetMethod); - Method unsafeArrayIndexScale = unsafeClass.getMethod("arrayIndexScale", java.lang.Class.class); + Method unsafeArrayIndexScale = jdkInternalUnsafeClass.getMethod("arrayIndexScale", java.lang.Class.class); unsafeArrayIndexScaleMethod = originalMetaAccess.lookupJavaMethod(unsafeArrayIndexScale); noCheckedExceptionsSet.add(unsafeArrayIndexScaleMethod); neverInlineSet.add(unsafeArrayIndexScaleMethod); @@ -248,15 +217,15 @@ public void init(ImageClassLoader loader, MetaAccessProvider originalMetaAccess) neverInlineSet.add(integerNumberOfLeadingZerosMethod); Method atomicIntegerFieldUpdaterNewUpdater = java.util.concurrent.atomic.AtomicIntegerFieldUpdater.class.getMethod("newUpdater", Class.class, String.class); - atomicIntegerFieldUpdaterNewUpdaterMethod = originalMetaAccess.lookupJavaMethod(atomicIntegerFieldUpdaterNewUpdater); + ResolvedJavaMethod atomicIntegerFieldUpdaterNewUpdaterMethod = originalMetaAccess.lookupJavaMethod(atomicIntegerFieldUpdaterNewUpdater); neverInlineSet.add(atomicIntegerFieldUpdaterNewUpdaterMethod); Method atomicLongFieldUpdaterNewUpdater = java.util.concurrent.atomic.AtomicLongFieldUpdater.class.getMethod("newUpdater", Class.class, String.class); - atomicLongFieldUpdaterNewUpdaterMethod = originalMetaAccess.lookupJavaMethod(atomicLongFieldUpdaterNewUpdater); + ResolvedJavaMethod atomicLongFieldUpdaterNewUpdaterMethod = originalMetaAccess.lookupJavaMethod(atomicLongFieldUpdaterNewUpdater); neverInlineSet.add(atomicLongFieldUpdaterNewUpdaterMethod); Method atomicReferenceFieldUpdaterNewUpdater = java.util.concurrent.atomic.AtomicReferenceFieldUpdater.class.getMethod("newUpdater", Class.class, Class.class, String.class); - atomicReferenceFieldUpdaterNewUpdaterMethod = originalMetaAccess.lookupJavaMethod(atomicReferenceFieldUpdaterNewUpdater); + ResolvedJavaMethod atomicReferenceFieldUpdaterNewUpdaterMethod = originalMetaAccess.lookupJavaMethod(atomicReferenceFieldUpdaterNewUpdater); neverInlineSet.add(atomicReferenceFieldUpdaterNewUpdaterMethod); } catch (NoSuchMethodException e) { @@ -284,8 +253,8 @@ public void init(ImageClassLoader loader, MetaAccessProvider originalMetaAccess) plugins.setClassInitializationPlugin(classInitializationPlugin); FallbackFeature fallbackFeature = ImageSingletons.contains(FallbackFeature.class) ? ImageSingletons.lookup(FallbackFeature.class) : null; - ReflectionPlugins.registerInvocationPlugins(loader, snippetReflection, annotationSubstitutions, classInitializationPlugin, plugins.getInvocationPlugins(), null, - ParsingReason.UnsafeSubstitutionAnalysis, fallbackFeature); + ReflectionPlugins.registerInvocationPlugins(loader, GraalAccess.getOriginalSnippetReflection(), annotationSubstitutions, classInitializationPlugin, plugins.getInvocationPlugins(), null, + ParsingReason.AutomaticUnsafeTransformation, fallbackFeature); /* * Note: ConstantFoldLoadFieldPlugin should not be installed because it will disrupt @@ -298,58 +267,37 @@ public void init(ImageClassLoader loader, MetaAccessProvider originalMetaAccess) * Analyzing certain classes leads to false errors. We disable reporting for those classes * by default. */ - try { - suppressWarnings.add(originalMetaAccess.lookupJavaType(Class.forName("sun.security.provider.ByteArrayAccess"))); - } catch (ClassNotFoundException e) { - throw VMError.shouldNotReachHere(e); - } + suppressWarnings = List.of(originalMetaAccess.lookupJavaType(ReflectionUtil.lookupClass(false, "sun.security.provider.ByteArrayAccess"))); } /** - * Post-process computed value fields during analysis, e.g, like registering the target field of - * field offset computation as unsafe accessed. Operations that lookup fields/methods/types in - * the analysis universe cannot be executed while the substitution is computed. The call to - * {@link #computeSubstitutions} is made from - * com.oracle.graal.pointsto.meta.AnalysisUniverse#createType(ResolvedJavaType), before the type - * is published. Thus if there is a circular dependency between the processed type and one of - * the fields/methods/types that it needs to access it might lead to a deadlock in - * {@link AnalysisType} creation. The automatic substitutions for an {@link AnalysisType} are - * computed just after the type is created but before it is published to other threads so that - * all threads see the substitutions. + * We use {@link ComputedValueField} to hold information about transformations, because it is a + * convenient holder class to check for equality for manually registered substitutions. But now + * we need to convert it to a {@link FieldValueTransformer}, because that is the only mechanism + * we can install late while the analysis is already running. */ - void processComputedValueFields(DuringAnalysisAccessImpl access) { - for (ResolvedJavaField field : fieldSubstitutions.values()) { - if (field instanceof ComputedValueField) { - ComputedValueField cvField = (ComputedValueField) field; - - switch (cvField.getRecomputeValueKind()) { - case FieldOffset: - Field targetField = cvField.getTargetField(); - if (access.registerAsUnsafeAccessed(access.getMetaAccess().lookupJavaField(targetField), cvField)) { - access.requireAnalysisIteration(); - } - break; - } - } - } + private void addTransformation(BigBang bb, ResolvedJavaField original, ComputedValueField transformation) { + Class returnType = original.getType().getJavaKind().toJavaClass(); + + FieldValueTransformer transformer = switch (transformation.getRecomputeValueKind()) { + case ArrayBaseOffset -> new ArrayBaseOffsetFieldValueTransformer(transformation.getTargetClass(), returnType); + case ArrayIndexScale -> new ArrayIndexScaleFieldValueTransformer(transformation.getTargetClass(), returnType); + case ArrayIndexShift -> new ArrayIndexShiftFieldValueTransformer(transformation.getTargetClass(), returnType); + case FieldOffset -> createFieldOffsetFieldValueTransformer(bb, original, transformation.getTargetField()); + case StaticFieldBase -> new StaticFieldBaseFieldValueTransformer(transformation.getTargetField()); + default -> throw VMError.shouldNotReachHere("Unexpected kind: " + transformation); + }; + + FieldValueInterceptionSupport.singleton().registerFieldValueTransformer(original, transformer); } - private void addSubstitutionField(ResolvedJavaField original, ComputedValueField substitution) { - assert substitution != null; - assert !fieldSubstitutions.containsKey(original); - fieldSubstitutions.put(original, substitution); - } - - @Override - public ResolvedJavaField lookup(ResolvedJavaField field) { - if (fieldSubstitutions.containsKey(field)) { - return fieldSubstitutions.get(field); - } - return field; + private static FieldOffsetFieldValueTransformer createFieldOffsetFieldValueTransformer(BigBang bb, ResolvedJavaField original, Field targetField) { + bb.postTask(debugContext -> bb.registerAsUnsafeAccessed(bb.getMetaAccess().lookupJavaField(targetField), DefaultUnsafePartition.get(), original)); + return new FieldOffsetFieldValueTransformer(targetField, original.getType().getJavaKind().toJavaClass()); } @SuppressWarnings("try") - public void computeSubstitutions(SVMHost hostVM, ResolvedJavaType hostType) { + public void computeTransformations(BigBang bb, SVMHost hostVM, ResolvedJavaType hostType) { if (hostType.isArray()) { return; } @@ -371,7 +319,7 @@ public void computeSubstitutions(SVMHost hostVM, ResolvedJavaType hostType) { if (annotationSubstitutions.findFullSubstitution(hostType).isPresent()) { /* If the class is substituted clinit will be eliminated, so bail early. */ - reportSkippedSubstitution(hostType); + reportSkippedTransformation(hostType); return; } @@ -390,16 +338,16 @@ public void computeSubstitutions(SVMHost hostVM, ResolvedJavaType hostType) { for (Invoke invoke : clinitGraph.getInvokes()) { if (invoke.callTarget() instanceof MethodCallTargetNode) { if (isInvokeTo(invoke, unsafeStaticFieldBaseMethod)) { - processUnsafeFieldComputation(hostType, invoke, StaticFieldBase); + processUnsafeFieldComputation(bb, hostType, invoke, StaticFieldBase); } else if (isInvokeTo(invoke, unsafeObjectFieldOffsetFieldMethod) || isInvokeTo(invoke, sunMiscUnsafeObjectFieldOffsetMethod) || isInvokeTo(invoke, unsafeStaticFieldOffsetMethod)) { - processUnsafeFieldComputation(hostType, invoke, FieldOffset); + processUnsafeFieldComputation(bb, hostType, invoke, FieldOffset); } else if (isInvokeTo(invoke, unsafeObjectFieldOffsetClassStringMethod)) { - processUnsafeObjectFieldOffsetClassStringInvoke(hostType, invoke); + processUnsafeObjectFieldOffsetClassStringInvoke(bb, hostType, invoke); } else if (isInvokeTo(invoke, unsafeArrayBaseOffsetMethod)) { - processUnsafeArrayBaseOffsetInvoke(hostType, invoke); + processUnsafeArrayBaseOffsetInvoke(bb, hostType, invoke); } else if (isInvokeTo(invoke, unsafeArrayIndexScaleMethod)) { - processUnsafeArrayIndexScaleInvoke(hostType, invoke, clinitGraph); + processUnsafeArrayIndexScaleInvoke(bb, hostType, invoke, clinitGraph); } } } @@ -422,7 +370,7 @@ public void computeSubstitutions(SVMHost hostVM, ResolvedJavaType hostType) { *

    * static final long fieldOffset = Unsafe.getUnsafe().staticFieldBase(X.class.getDeclaredField("f")); */ - private void processUnsafeFieldComputation(ResolvedJavaType type, Invoke invoke, Kind kind) { + private void processUnsafeFieldComputation(BigBang bb, ResolvedJavaType type, Invoke invoke, Kind kind) { List> unsuccessfulReasons = new ArrayList<>(); Class targetFieldHolder = null; @@ -432,7 +380,7 @@ private void processUnsafeFieldComputation(ResolvedJavaType type, Invoke invoke, ValueNode fieldArgumentNode = invoke.callTarget().arguments().get(1); JavaConstant fieldArgument = nodeAsConstant(fieldArgumentNode); if (fieldArgument != null) { - Field targetField = snippetReflection.asObject(Field.class, fieldArgument); + Field targetField = GraalAccess.getOriginalSnippetReflection().asObject(Field.class, fieldArgument); if (isValidField(invoke, targetField, unsuccessfulReasons, methodFormat)) { targetFieldHolder = targetField.getDeclaringClass(); targetFieldName = targetField.getName(); @@ -440,7 +388,7 @@ private void processUnsafeFieldComputation(ResolvedJavaType type, Invoke invoke, } else { unsuccessfulReasons.add(() -> "The argument of " + methodFormat + " is not a constant value or a field load that can be constant-folded."); } - processUnsafeFieldComputation(type, invoke, kind, unsuccessfulReasons, targetFieldHolder, targetFieldName); + processUnsafeFieldComputation(bb, type, invoke, kind, unsuccessfulReasons, targetFieldHolder, targetFieldName); } /** @@ -448,7 +396,7 @@ private void processUnsafeFieldComputation(ResolvedJavaType type, Invoke invoke, * {@link LoadFieldNode} it attempts to constant fold it. We manually constant fold just * specific nodes instead of globally installing {@link ConstantFoldLoadFieldPlugin} to avoid * folding load filed nodes that could disrupt other patterns that we try to match, e.g., like - * {@link #processArrayIndexShiftFromField(ResolvedJavaType, ResolvedJavaField, Class, StructuredGraph)}. + * {@link #processArrayIndexShiftFromField}. */ private JavaConstant nodeAsConstant(ValueNode node) { if (node.isConstant()) { @@ -500,7 +448,7 @@ private boolean isValidField(Invoke invoke, Field field, List> * * static final long fieldOffset = Unsafe.getUnsafe().objectFieldOffset(X.class, "f"); */ - private void processUnsafeObjectFieldOffsetClassStringInvoke(ResolvedJavaType type, Invoke unsafeObjectFieldOffsetInvoke) { + private void processUnsafeObjectFieldOffsetClassStringInvoke(BigBang bb, ResolvedJavaType type, Invoke unsafeObjectFieldOffsetInvoke) { List> unsuccessfulReasons = new ArrayList<>(); Class targetFieldHolder = null; @@ -508,7 +456,7 @@ private void processUnsafeObjectFieldOffsetClassStringInvoke(ResolvedJavaType ty ValueNode classArgument = unsafeObjectFieldOffsetInvoke.callTarget().arguments().get(1); if (classArgument.isConstant()) { - Class clazz = snippetReflection.asObject(Class.class, classArgument.asJavaConstant()); + Class clazz = GraalAccess.getOriginalSnippetReflection().asObject(Class.class, classArgument.asJavaConstant()); if (clazz == null) { unsuccessfulReasons.add(() -> "The Class argument of Unsafe.objectFieldOffset(Class, String) is a null constant."); } else { @@ -520,7 +468,7 @@ private void processUnsafeObjectFieldOffsetClassStringInvoke(ResolvedJavaType ty ValueNode nameArgument = unsafeObjectFieldOffsetInvoke.callTarget().arguments().get(2); if (nameArgument.isConstant()) { - String fieldName = snippetReflection.asObject(String.class, nameArgument.asJavaConstant()); + String fieldName = GraalAccess.getOriginalSnippetReflection().asObject(String.class, nameArgument.asJavaConstant()); if (fieldName == null) { unsuccessfulReasons.add(() -> "The String argument of Unsafe.objectFieldOffset(Class, String) is a null String."); } else { @@ -529,10 +477,11 @@ private void processUnsafeObjectFieldOffsetClassStringInvoke(ResolvedJavaType ty } else { unsuccessfulReasons.add(() -> "The name argument of Unsafe.objectFieldOffset(Class, String) is not a constant String."); } - processUnsafeFieldComputation(type, unsafeObjectFieldOffsetInvoke, FieldOffset, unsuccessfulReasons, targetFieldHolder, targetFieldName); + processUnsafeFieldComputation(bb, type, unsafeObjectFieldOffsetInvoke, FieldOffset, unsuccessfulReasons, targetFieldHolder, targetFieldName); } - private void processUnsafeFieldComputation(ResolvedJavaType type, Invoke invoke, Kind kind, List> unsuccessfulReasons, Class targetFieldHolder, String targetFieldName) { + private void processUnsafeFieldComputation(BigBang bb, ResolvedJavaType type, Invoke invoke, Kind kind, List> unsuccessfulReasons, Class targetFieldHolder, + String targetFieldName) { assert kind == FieldOffset || kind == StaticFieldBase; /* * If the value returned by the call to Unsafe.objectFieldOffset() is stored into a field @@ -548,11 +497,11 @@ private void processUnsafeFieldComputation(ResolvedJavaType type, Invoke invoke, ResolvedJavaField valueStoreField = result.valueStoreField; /* * If the target field holder and name, and the offset field were found try to register a - * substitution. + * transformation. */ if (targetFieldHolder != null && targetFieldName != null && valueStoreField != null) { - Supplier supplier = () -> new ComputedValueField(valueStoreField, null, kind, targetFieldHolder, targetFieldName, false); - if (tryAutomaticRecomputation(valueStoreField, kind, supplier)) { + Supplier supplier = () -> ComputedValueField.create(valueStoreField, null, kind, targetFieldHolder, targetFieldName, false); + if (tryAutomaticTransformation(bb, valueStoreField, kind, supplier)) { reportSuccessfulAutomaticRecomputation(kind, valueStoreField, targetFieldHolder.getName() + "." + targetFieldName); } } else { @@ -566,7 +515,7 @@ private void processUnsafeFieldComputation(ResolvedJavaType type, Invoke invoke, * * static final long arrayBaseOffsets = Unsafe.getUnsafe().arrayBaseOffset(byte[].class); */ - private void processUnsafeArrayBaseOffsetInvoke(ResolvedJavaType type, Invoke unsafeArrayBaseOffsetInvoke) { + private void processUnsafeArrayBaseOffsetInvoke(BigBang bb, ResolvedJavaType type, Invoke unsafeArrayBaseOffsetInvoke) { SnippetReflectionProvider snippetReflectionProvider = GraalAccess.getOriginalSnippetReflection(); List> unsuccessfulReasons = new ArrayList<>(); @@ -589,8 +538,8 @@ private void processUnsafeArrayBaseOffsetInvoke(ResolvedJavaType type, Invoke un ResolvedJavaField offsetField = result.valueStoreField; if (arrayClass != null && offsetField != null) { Class finalArrayClass = arrayClass; - Supplier supplier = () -> new ComputedValueField(offsetField, null, ArrayBaseOffset, finalArrayClass, null, true); - if (tryAutomaticRecomputation(offsetField, ArrayBaseOffset, supplier)) { + Supplier supplier = () -> ComputedValueField.create(offsetField, null, ArrayBaseOffset, finalArrayClass, null, true); + if (tryAutomaticTransformation(bb, offsetField, ArrayBaseOffset, supplier)) { reportSuccessfulAutomaticRecomputation(ArrayBaseOffset, offsetField, arrayClass.getCanonicalName()); } } else { @@ -607,7 +556,7 @@ private void processUnsafeArrayBaseOffsetInvoke(ResolvedJavaType type, Invoke un * * static final long byteArrayIndexScale = Unsafe.getUnsafe().arrayIndexScale(byte[].class); */ - private void processUnsafeArrayIndexScaleInvoke(ResolvedJavaType type, Invoke unsafeArrayIndexScale, StructuredGraph clinitGraph) { + private void processUnsafeArrayIndexScaleInvoke(BigBang bb, ResolvedJavaType type, Invoke unsafeArrayIndexScale, StructuredGraph clinitGraph) { SnippetReflectionProvider snippetReflectionProvider = GraalAccess.getOriginalSnippetReflection(); List> unsuccessfulReasons = new ArrayList<>(); @@ -634,19 +583,19 @@ private void processUnsafeArrayIndexScaleInvoke(ResolvedJavaType type, Invoke un if (arrayClass != null) { if (indexScaleField != null) { Class finalArrayClass = arrayClass; - Supplier supplier = () -> new ComputedValueField(indexScaleField, null, ArrayIndexScale, finalArrayClass, null, true); - if (tryAutomaticRecomputation(indexScaleField, ArrayIndexScale, supplier)) { + Supplier supplier = () -> ComputedValueField.create(indexScaleField, null, ArrayIndexScale, finalArrayClass, null, true); + if (tryAutomaticTransformation(bb, indexScaleField, ArrayIndexScale, supplier)) { reportSuccessfulAutomaticRecomputation(ArrayIndexScale, indexScaleField, arrayClass.getCanonicalName()); indexScaleComputed = true; - /* Try substitution for the array index shift computation if present. */ - indexShiftComputed = processArrayIndexShiftFromField(type, indexScaleField, arrayClass, clinitGraph); + /* Try transformation for the array index shift computation if present. */ + indexShiftComputed = processArrayIndexShiftFromField(bb, type, indexScaleField, arrayClass, clinitGraph); } } else { /* * The index scale is not stored into a field, it might be used to compute the index * shift. */ - indexShiftComputed = processArrayIndexShiftFromLocal(type, unsafeArrayIndexScale, arrayClass); + indexShiftComputed = processArrayIndexShiftFromLocal(bb, type, unsafeArrayIndexScale, arrayClass); } } if (!indexScaleComputed && !indexShiftComputed) { @@ -676,7 +625,7 @@ private void processUnsafeArrayIndexScaleInvoke(ResolvedJavaType type, Invoke un * It is important that constant folding is not enabled for the byteArrayIndexScale load because * it would break the link between the scale and shift computations. */ - private boolean processArrayIndexShiftFromField(ResolvedJavaType type, ResolvedJavaField indexScaleField, Class arrayClass, StructuredGraph clinitGraph) { + private boolean processArrayIndexShiftFromField(BigBang bb, ResolvedJavaType type, ResolvedJavaField indexScaleField, Class arrayClass, StructuredGraph clinitGraph) { for (LoadFieldNode load : clinitGraph.getNodes().filter(LoadFieldNode.class)) { if (load.field().equals(indexScaleField)) { /* @@ -684,7 +633,7 @@ private boolean processArrayIndexShiftFromField(ResolvedJavaType type, ResolvedJ * field was already found. The case where both scale and shift are computed is * uncommon. */ - if (processArrayIndexShift(type, arrayClass, load, true)) { + if (processArrayIndexShift(bb, type, arrayClass, load, true)) { /* * Return true as soon as an index shift computed from the index scale field is * found. It is very unlikely that there are multiple shift computations from @@ -713,13 +662,15 @@ private boolean processArrayIndexShiftFromField(ResolvedJavaType type, ResolvedJ * } * */ - private boolean processArrayIndexShiftFromLocal(ResolvedJavaType type, Invoke unsafeArrayIndexScale, Class arrayClass) { + private boolean processArrayIndexShiftFromLocal(BigBang bb, ResolvedJavaType type, Invoke unsafeArrayIndexScale, Class arrayClass) { /* Try to compute index shift. Report errors since the index scale field was not found. */ - return processArrayIndexShift(type, arrayClass, unsafeArrayIndexScale.asNode(), false); + return processArrayIndexShift(bb, type, arrayClass, unsafeArrayIndexScale.asNode(), false); } - /** Try to compute the arrayIndexShift. Return true if successful, false otherwise. */ - private boolean processArrayIndexShift(ResolvedJavaType type, Class arrayClass, ValueNode indexScaleValue, boolean silentFailure) { + /** + * Try to compute the arrayIndexShift. Return true if successful, false otherwise. + */ + private boolean processArrayIndexShift(BigBang bb, ResolvedJavaType type, Class arrayClass, ValueNode indexScaleValue, boolean silentFailure) { NodeIterable loadMethodCallTargetUsages = indexScaleValue.usages().filter(MethodCallTargetNode.class); for (MethodCallTargetNode methodCallTarget : loadMethodCallTargetUsages) { /* Iterate over all the calls that use the index scale value. */ @@ -753,8 +704,8 @@ private boolean processArrayIndexShift(ResolvedJavaType type, Class arrayClas if (indexShiftField != null) { ResolvedJavaField finalIndexShiftField = indexShiftField; - Supplier supplier = () -> new ComputedValueField(finalIndexShiftField, null, ArrayIndexShift, arrayClass, null, true); - if (tryAutomaticRecomputation(indexShiftField, ArrayIndexShift, supplier)) { + Supplier supplier = () -> ComputedValueField.create(finalIndexShiftField, null, ArrayIndexShift, arrayClass, null, true); + if (tryAutomaticTransformation(bb, indexShiftField, ArrayIndexShift, supplier)) { reportSuccessfulAutomaticRecomputation(ArrayIndexShift, indexShiftField, arrayClass.getCanonicalName()); return true; } @@ -807,7 +758,9 @@ private static boolean subNodeComputesLog2(SubNode subNode, Invoke numberOfLeadi * static final field where the unsafe value may be stored. */ static final class SearchResult { - /** The field where the value is stored, if found. */ + /** + * The field where the value is stored, if found. + */ final ResolvedJavaField valueStoreField; /** * Uses that can lead to the unsafe value having side effects that we didn't account for are @@ -838,7 +791,7 @@ static SearchResult didNotFindIllegalUse() { * returned. If the field is either not static or not final the method returns null and the * reason is recorded in the unsuccessfulReasons parameter. */ - private static SearchResult extractValueStoreField(ValueNode valueNode, Kind substitutionKind, List> unsuccessfulReasons) { + private SearchResult extractValueStoreField(ValueNode valueNode, Kind recomputeKind, List> unsuccessfulReasons) { ResolvedJavaField valueStoreField = null; boolean illegalUseFound = false; @@ -875,7 +828,7 @@ private static SearchResult extractValueStoreField(ValueNode valueNode, Kind sub return SearchResult.foundField(valueStoreField); } else { ResolvedJavaField valueStoreFieldFinal = valueStoreField; - Supplier message = () -> "The field " + valueStoreFieldFinal.format("%H.%n") + ", where the value produced by the " + kindAsString(substitutionKind) + + Supplier message = () -> "The field " + valueStoreFieldFinal.format("%H.%n") + ", where the value produced by the " + kindAsString(recomputeKind) + " computation is stored, is not" + (!valueStoreFieldFinal.isStatic() ? " static" : "") + (!valueStoreFieldFinal.isFinal() ? " final" : "") + "."; unsuccessfulReasons.add(message); /* Value is stored to a non static final field. */ @@ -898,7 +851,7 @@ private static SearchResult extractValueStoreField(ValueNode valueNode, Kind sub throw VMError.shouldNotReachHereUnexpectedInput(valueNode); // ExcludeFromJacocoGeneratedReport } Supplier message = () -> "Could not determine the field where the value produced by the " + producer + - " for the " + kindAsString(substitutionKind) + " computation is stored. The " + operation + + " for the " + kindAsString(recomputeKind) + " computation is stored. The " + operation + " is not directly followed by a field store or by a sign extend node followed directly by a field store. "; unsuccessfulReasons.add(message); return SearchResult.foundIllegalUse(); @@ -912,7 +865,7 @@ private static SearchResult extractValueStoreField(ValueNode valueNode, Kind sub * Determine if the valueNodeUsage parameter is an allowed usage of an offset, indexScale or * indexShift unsafe value. */ - private static boolean isAllowedUnsafeValueSink(Node valueNodeUsage) { + private boolean isAllowedUnsafeValueSink(Node valueNodeUsage) { if (valueNodeUsage instanceof FrameState) { /* * The frame state keeps track of the local variables and operand stack at a particular @@ -930,7 +883,7 @@ private static boolean isAllowedUnsafeValueSink(Node valueNodeUsage) { */ MethodCallTargetNode methodCallTarget = (MethodCallTargetNode) valueNodeUsage; ResolvedJavaType declaringClass = methodCallTarget.targetMethod().getDeclaringClass(); - if (declaringClass.equals(resolvedUnsafeClass) || declaringClass.equals(resolvedSunMiscUnsafeClass)) { + if (declaringClass.equals(jdkInternalUnsafeType) || declaringClass.equals(sunMiscUnsafeType)) { return true; } } @@ -938,19 +891,17 @@ private static boolean isAllowedUnsafeValueSink(Node valueNodeUsage) { } /** - * Try to register the automatic substitution for a field. Bail if the field was deleted or - * another substitution is detected. - * - * @param field stores the value of the recomputation, i.e., an offset, array idx scale or shift + * Try to register the automatic transformation for a field. Bail if the field was deleted or a + * conflicting substitution is detected. */ - private boolean tryAutomaticRecomputation(ResolvedJavaField field, Kind kind, Supplier substitutionSupplier) { + private boolean tryAutomaticTransformation(BigBang bb, ResolvedJavaField field, Kind kind, Supplier transformationSupplier) { if (annotationSubstitutions.isDeleted(field)) { String conflictingSubstitution = "The field " + field.format("%H.%n") + " is marked as deleted. "; reportConflictingSubstitution(field, kind, conflictingSubstitution); return false; } else { - ComputedValueField computedValueField = substitutionSupplier.get(); - Field targetField = computedValueField.getTargetField(); + ComputedValueField transformation = transformationSupplier.get(); + Field targetField = transformation.getTargetField(); if (targetField != null && annotationSubstitutions.isDeleted(targetField)) { String conflictingSubstitution = "The target field of " + field.format("%H.%n") + " is marked as deleted. "; reportSkippedSubstitution(field, kind, conflictingSubstitution); @@ -958,39 +909,30 @@ private boolean tryAutomaticRecomputation(ResolvedJavaField field, Kind kind, Su } Optional annotationSubstitution = annotationSubstitutions.findSubstitution(field); if (annotationSubstitution.isPresent()) { - /* An annotation substitutions detected. */ ResolvedJavaField substitutionField = annotationSubstitution.get(); - if (substitutionField instanceof ComputedValueField) { - ComputedValueField computedSubstitutionField = (ComputedValueField) substitutionField; - if (computedSubstitutionField.getRecomputeValueKind().equals(kind)) { - if (computedSubstitutionField.getTargetField().equals(computedValueField.getTargetField())) { + if (substitutionField instanceof ComputedValueField computedValueField) { + if (computedValueField.getRecomputeValueKind().equals(kind)) { + if (computedValueField.getTargetField().equals(transformation.getTargetField())) { /* * Skip the warning when the target field of the found manual * substitution differs from the target field of the discovered original * offset computation. This will avoid printing false positives for * substitutions like Target_java_lang_Class_Atomic.*Offset. */ - reportUnnecessarySubstitution(computedValueField, computedSubstitutionField); + reportUnnecessarySubstitution(transformation, computedValueField); } return false; - } else if (computedSubstitutionField.getRecomputeValueKind().equals(Kind.None)) { + } else if (computedValueField.getRecomputeValueKind().equals(Kind.None)) { /* * This is essentially an @Alias field. An @Alias for a field with an - * automatic recomputed value is allowed but the alias needs to be - * overwritten otherwise the value from the original field would be read. To - * do this a new recomputed value field is registered in the automatic - * substitution processor, which follows the annotation substitution - * processor in the substitutions chain. Thus, every time the substitutions - * chain is queried for the original field, e.g., in - * AnalysisUniverse.lookupAllowUnresolved(JavaField), the alias field is - * forwarded to the automatic substitution. + * automatic recomputed value is allowed. */ - addSubstitutionField(computedSubstitutionField, computedValueField); - reportOvewrittenSubstitution(substitutionField, kind, computedSubstitutionField.getAnnotated(), computedSubstitutionField.getRecomputeValueKind()); + addTransformation(bb, field, transformation); + reportOvewrittenSubstitution(substitutionField, kind, computedValueField.getAnnotated(), computedValueField.getRecomputeValueKind()); return true; } else { - String conflictingSubstitution = "Detected RecomputeFieldValue." + computedSubstitutionField.getRecomputeValueKind() + - " " + computedSubstitutionField.getAnnotated().format("%H.%n") + " substitution field. "; + String conflictingSubstitution = "Detected RecomputeFieldValue." + computedValueField.getRecomputeValueKind() + + " " + computedValueField.getAnnotated().format("%H.%n") + " substitution field. "; reportConflictingSubstitution(substitutionField, kind, conflictingSubstitution); return false; } @@ -1001,42 +943,42 @@ private boolean tryAutomaticRecomputation(ResolvedJavaField field, Kind kind, Su } } else { /* No other substitutions detected. */ - addSubstitutionField(field, computedValueField); + addTransformation(bb, field, transformation); return true; } } } - private static void reportSkippedSubstitution(ResolvedJavaType type) { - if (Options.UnsafeAutomaticSubstitutionsLogLevel.getValue() >= DEBUG_LEVEL) { - LogUtils.warning("Skipped automatic unsafe substitutions analysis for type " + type.getName() + + private static void reportSkippedTransformation(ResolvedJavaType type) { + if (Options.AutomaticUnsafeTransformationLogLevel.getValue() >= DEBUG_LEVEL) { + LogUtils.warning("Skipped automatic unsafe transformation analysis for type " + type.getName() + ". The entire type is substituted, therefore its class initializer is eliminated."); } } private static void reportUnnecessarySubstitution(ResolvedJavaField offsetField, ComputedValueField computedSubstitutionField) { - if (Options.UnsafeAutomaticSubstitutionsLogLevel.getValue() >= BASIC_LEVEL) { + if (Options.AutomaticUnsafeTransformationLogLevel.getValue() >= BASIC_LEVEL) { Kind kind = computedSubstitutionField.getRecomputeValueKind(); String kindStr = RecomputeFieldValue.class.getSimpleName() + "." + kind; String annotatedFieldStr = computedSubstitutionField.getAnnotated().format("%H.%n"); String offsetFieldStr = offsetField.format("%H.%n"); - String optionStr = SubstrateOptionsParser.commandArgument(Options.UnsafeAutomaticSubstitutionsLogLevel, "+"); - LogUtils.warning( - "Detected unnecessary %s %s substitution field for %s. The annotated field can be removed. This %s computation can be detected automatically. Use option -H:+%s=%s to print all automatically detected substitutions.", + String optionStr = SubstrateOptionsParser.commandArgument(Options.AutomaticUnsafeTransformationLogLevel, "+"); + LogUtils.warning("Detected unnecessary %s %s substitution field for %s. The annotated field can be removed. " + + "This %s computation can be detected automatically. Use option -H:+%s=%s to print all automatically detected substitutions.", kindStr, annotatedFieldStr, offsetFieldStr, kind, optionStr, INFO_LEVEL); } } - private static void reportSuccessfulAutomaticRecomputation(Kind substitutionKind, ResolvedJavaField substitutedField, String target) { - if (Options.UnsafeAutomaticSubstitutionsLogLevel.getValue() >= INFO_LEVEL) { - String substitutionKindStr = RecomputeFieldValue.class.getSimpleName() + "." + substitutionKind; + private static void reportSuccessfulAutomaticRecomputation(Kind recomputeKind, ResolvedJavaField substitutedField, String target) { + if (Options.AutomaticUnsafeTransformationLogLevel.getValue() >= INFO_LEVEL) { + String recomputeKindStr = RecomputeFieldValue.class.getSimpleName() + "." + recomputeKind; String substitutedFieldStr = substitutedField.format("%H.%n"); - LogUtils.info("%s substitution automatically registered for %s, target element %s.", substitutionKindStr, substitutedFieldStr, target); + LogUtils.info("%s substitution automatically registered for %s, target element %s.", recomputeKindStr, substitutedFieldStr, target); } } private static void reportOvewrittenSubstitution(ResolvedJavaField offsetField, Kind newKind, ResolvedJavaField overwrittenField, Kind overwrittenKind) { - if (Options.UnsafeAutomaticSubstitutionsLogLevel.getValue() >= INFO_LEVEL) { + if (Options.AutomaticUnsafeTransformationLogLevel.getValue() >= INFO_LEVEL) { String newKindStr = RecomputeFieldValue.class.getSimpleName() + "." + newKind; String overwrittenKindStr = RecomputeFieldValue.class.getSimpleName() + "." + overwrittenKind; String offsetFieldStr = offsetField.format("%H.%n"); @@ -1045,49 +987,49 @@ private static void reportOvewrittenSubstitution(ResolvedJavaField offsetField, } } - private static void reportConflictingSubstitution(ResolvedJavaField field, Kind substitutionKind, String conflictingSubstitution) { - if (Options.UnsafeAutomaticSubstitutionsLogLevel.getValue() >= BASIC_LEVEL) { + private static void reportConflictingSubstitution(ResolvedJavaField field, Kind recomputeKind, String conflictingSubstitution) { + if (Options.AutomaticUnsafeTransformationLogLevel.getValue() >= BASIC_LEVEL) { String fieldStr = field.format("%H.%n"); - String substitutionKindStr = RecomputeFieldValue.class.getSimpleName() + "." + substitutionKind; - LogUtils.warning( - "The %s substitution for %s could not be recomputed automatically because a conflicting substitution was detected. Conflicting substitution: %s. Add a %s manual substitution for %s.", - substitutionKindStr, fieldStr, conflictingSubstitution, substitutionKindStr, fieldStr); + String recomputeKindStr = RecomputeFieldValue.class.getSimpleName() + "." + recomputeKind; + LogUtils.warning("The %s substitution for %s could not be recomputed automatically because a conflicting substitution was detected. " + + "Conflicting substitution: %s. Add a %s manual substitution for %s.", + recomputeKindStr, fieldStr, conflictingSubstitution, recomputeKindStr, fieldStr); } } - private static void reportSkippedSubstitution(ResolvedJavaField field, Kind substitutionKind, String conflictingSubstitution) { - if (Options.UnsafeAutomaticSubstitutionsLogLevel.getValue() >= BASIC_LEVEL) { + private static void reportSkippedSubstitution(ResolvedJavaField field, Kind recomputeKind, String conflictingSubstitution) { + if (Options.AutomaticUnsafeTransformationLogLevel.getValue() >= BASIC_LEVEL) { String fieldStr = field.format("%H.%n"); - String substitutionKindStr = RecomputeFieldValue.class.getSimpleName() + "." + substitutionKind; + String recomputeKindStr = RecomputeFieldValue.class.getSimpleName() + "." + recomputeKind; LogUtils.warning("The %s substitution for %s could not be recomputed automatically because a conflicting substitution was detected. Conflicting substitution: %s.", - substitutionKindStr, fieldStr, conflictingSubstitution); + recomputeKindStr, fieldStr, conflictingSubstitution); } } - private void reportUnsuccessfulAutomaticRecomputation(ResolvedJavaType type, ResolvedJavaField computedField, Invoke invoke, Kind substitutionKind, List> reasons) { + private void reportUnsuccessfulAutomaticRecomputation(ResolvedJavaType type, ResolvedJavaField computedField, Invoke invoke, Kind recomputeKind, List> reasons) { String msg = ""; - if (Options.UnsafeAutomaticSubstitutionsLogLevel.getValue() >= BASIC_LEVEL) { - if (!suppressWarningsFor(type) || Options.UnsafeAutomaticSubstitutionsLogLevel.getValue() >= DEBUG_LEVEL) { - String substitutionKindStr = RecomputeFieldValue.class.getSimpleName() + "." + substitutionKind; + if (Options.AutomaticUnsafeTransformationLogLevel.getValue() >= BASIC_LEVEL) { + if (!suppressWarningsFor(type) || Options.AutomaticUnsafeTransformationLogLevel.getValue() >= DEBUG_LEVEL) { + String recomputeKindStr = RecomputeFieldValue.class.getSimpleName() + "." + recomputeKind; String invokeStr = invoke.callTarget().targetMethod().format("%H.%n(%p)"); - msg += substitutionKindStr + " automatic substitution failed. "; - msg += "The automatic substitution registration was attempted because "; - if (substitutionKind == ArrayIndexShift) { + msg += recomputeKindStr + " automatic field value transformation failed. "; + msg += "The automatic registration was attempted because "; + if (recomputeKind == ArrayIndexShift) { msg += "an " + ArrayIndexScale + " computation followed by a call to " + invokeStr + " "; } else { msg += "a call to " + invokeStr + " "; } - msg += "was detected in the static initializer of " + type.toJavaName() + ". "; + msg += "was detected in the class initializer of " + type.toJavaName() + ". "; if (computedField != null) { /* If the computed field is null then reasons will contain the details. */ - msg += "Add a " + substitutionKindStr + " manual substitution for " + computedField.format("%H.%n") + ". "; + msg += "Add a " + recomputeKindStr + " manual substitution for " + computedField.format("%H.%n") + ". "; } msg += "Detailed failure reason(s): " + reasons.stream().map(s -> s.get()).collect(Collectors.joining(", ")); } } - if (Options.UnsafeAutomaticSubstitutionsLogLevel.getValue() >= DEBUG_LEVEL) { + if (Options.AutomaticUnsafeTransformationLogLevel.getValue() >= DEBUG_LEVEL) { if (suppressWarningsFor(type)) { msg += "(This warning is suppressed by default because this type "; if (warningsAreWhiteListed(type)) { @@ -1107,8 +1049,8 @@ private void reportUnsuccessfulAutomaticRecomputation(ResolvedJavaType type, Res } } - private static String kindAsString(Kind substitutionKind) { - switch (substitutionKind) { + private static String kindAsString(Kind recomputeKind) { + switch (recomputeKind) { case FieldOffset: return "field offset"; case StaticFieldBase: @@ -1120,7 +1062,7 @@ private static String kindAsString(Kind substitutionKind) { case ArrayIndexShift: return "array index shift"; default: - throw VMError.shouldNotReachHere("Unexpected substitution kind: " + substitutionKind); + throw VMError.shouldNotReachHere("Unexpected kind: " + recomputeKind); } } diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/substitute/ComputedValueField.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/substitute/ComputedValueField.java index f16c2d1fa401..9062a321892b 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/substitute/ComputedValueField.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/substitute/ComputedValueField.java @@ -24,7 +24,6 @@ */ package com.oracle.svm.hosted.substitute; -import static com.oracle.svm.core.SubstrateUtil.toUnboxedClass; import static com.oracle.svm.core.annotate.RecomputeFieldValue.Kind.AtomicFieldUpdaterOffset; import static com.oracle.svm.core.annotate.RecomputeFieldValue.Kind.FieldOffset; import static com.oracle.svm.core.annotate.RecomputeFieldValue.Kind.StaticFieldBase; @@ -38,11 +37,7 @@ import java.lang.reflect.Modifier; import java.util.EnumSet; import java.util.Objects; -import java.util.concurrent.locks.ReentrantReadWriteLock; -import java.util.concurrent.locks.ReentrantReadWriteLock.ReadLock; -import java.util.concurrent.locks.ReentrantReadWriteLock.WriteLock; -import org.graalvm.collections.EconomicMap; import org.graalvm.nativeimage.ImageSingletons; import org.graalvm.nativeimage.hosted.FieldValueTransformer; @@ -81,7 +76,7 @@ * @see RecomputeFieldValue * @see NativeImageReinitialize */ -public class ComputedValueField implements ReadableJavaField, OriginalFieldProvider, AnnotationWrapper { +public final class ComputedValueField extends FieldValueTransformation implements ReadableJavaField, OriginalFieldProvider, AnnotationWrapper { private static final EnumSet offsetComputationKinds = EnumSet.of(FieldOffset, TranslateFieldOffset, AtomicFieldUpdaterOffset); private final ResolvedJavaField original; @@ -90,10 +85,7 @@ public class ComputedValueField implements ReadableJavaField, OriginalFieldProvi private final RecomputeFieldValue.Kind kind; private final Class targetClass; private final Field targetField; - private final Class transformedValueAllowedType; - private final FieldValueTransformer fieldValueTransformer; private final boolean isFinal; - private final boolean disableCaching; /** True if the value doesn't depend on any analysis results. */ private final boolean isValueAvailableBeforeAnalysis; /** True if the value depends on analysis results. */ @@ -103,47 +95,35 @@ public class ComputedValueField implements ReadableJavaField, OriginalFieldProvi private JavaConstant constantValue; - private final EconomicMap valueCache; - /** - * Economic map does not allow to store null keys. Therefore null key is stored in an extra - * field. - */ - private JavaConstant valueCacheNullKey; - private final ReentrantReadWriteLock valueCacheLock = new ReentrantReadWriteLock(); - - public ComputedValueField(ResolvedJavaField original, ResolvedJavaField annotated, RecomputeFieldValue.Kind kind, Class targetClass, String targetName, boolean isFinal) { - this(original, annotated, kind, null, null, targetClass, targetName, isFinal, false); + public static ComputedValueField create(ResolvedJavaField original, ResolvedJavaField annotated, RecomputeFieldValue.Kind kind, Class targetClass, String targetName, boolean isFinal) { + return create(original, annotated, kind, null, null, targetClass, targetName, isFinal, false); } - @SuppressWarnings("this-escape") - public ComputedValueField(ResolvedJavaField original, ResolvedJavaField annotated, RecomputeFieldValue.Kind kind, Class transformedValueAllowedType, FieldValueTransformer initialTransformer, - Class targetClass, String targetName, boolean isFinal, boolean disableCaching) { + public static ComputedValueField create(ResolvedJavaField original, ResolvedJavaField annotated, RecomputeFieldValue.Kind kind, Class transformedValueAllowedType, + FieldValueTransformer initialTransformer, Class targetClass, String targetName, boolean isFinal, boolean disableCaching) { assert original != null; assert initialTransformer != null || targetClass != null; - this.original = original; - this.annotated = annotated; - this.kind = kind; - this.transformedValueAllowedType = transformedValueAllowedType; - this.targetClass = targetClass; - this.isFinal = isFinal; - this.disableCaching = disableCaching; - boolean customValueAvailableBeforeAnalysis = true; boolean customValueAvailableOnlyAfterAnalysis = false; boolean customValueAvailableOnlyAfterCompilation = false; FieldValueTransformer transformer = null; Field f = null; + JavaConstant constantValue = null; switch (kind) { case Reset: - constantValue = JavaConstant.defaultForKind(getJavaKind()); + constantValue = JavaConstant.defaultForKind(original.getType().getJavaKind()); break; case FieldOffset: f = getField(annotated, targetClass, targetName); break; case StaticFieldBase: f = getField(annotated, targetClass, targetName); - UserError.guarantee(Modifier.isStatic(f.getModifiers()), "Target field must be static for %s computation of %s", StaticFieldBase, fieldFormat()); + Object[] args = new Object[]{}; + if (!Modifier.isStatic(f.getModifiers())) { + throw UserError.abort("Target field must be static for " + StaticFieldBase + " computation of field " + original.format("%H.%n") + + (annotated != null ? " specified by alias " + annotated.format("%H.%n") : "")); + } break; case Custom: if (initialTransformer != null) { @@ -162,12 +142,12 @@ public ComputedValueField(ResolvedJavaField original, ResolvedJavaField annotate boolean isOffsetField = isOffsetRecomputation(kind); boolean isStaticFieldBase = kind == StaticFieldBase; guarantee(!isFinal || !isOffsetField); - this.isValueAvailableBeforeAnalysis = customValueAvailableBeforeAnalysis && !isOffsetField && !isStaticFieldBase; - this.isValueAvailableOnlyAfterAnalysis = customValueAvailableOnlyAfterAnalysis || isOffsetField || isStaticFieldBase; - this.isValueAvailableOnlyAfterCompilation = customValueAvailableOnlyAfterCompilation; - this.targetField = f; - this.fieldValueTransformer = transformer; - this.valueCache = EconomicMap.create(); + boolean isValueAvailableBeforeAnalysis = customValueAvailableBeforeAnalysis && !isOffsetField && !isStaticFieldBase; + boolean isValueAvailableOnlyAfterAnalysis = customValueAvailableOnlyAfterAnalysis || isOffsetField || isStaticFieldBase; + boolean isValueAvailableOnlyAfterCompilation = customValueAvailableOnlyAfterCompilation; + + return new ComputedValueField(original, annotated, kind, transformedValueAllowedType, transformer, isFinal, disableCaching, targetClass, f, isValueAvailableBeforeAnalysis, + isValueAvailableOnlyAfterAnalysis, isValueAvailableOnlyAfterCompilation, constantValue); } private static Field getField(ResolvedJavaField annotated, Class targetClass, String targetName) { @@ -182,6 +162,22 @@ public static boolean isOffsetRecomputation(RecomputeFieldValue.Kind kind) { return offsetComputationKinds.contains(kind); } + private ComputedValueField(ResolvedJavaField original, ResolvedJavaField annotated, RecomputeFieldValue.Kind kind, + Class transformedValueAllowedType, FieldValueTransformer fieldValueTransformer, boolean isFinal, boolean disableCaching, Class targetClass, Field targetField, + boolean isValueAvailableBeforeAnalysis, boolean isValueAvailableOnlyAfterAnalysis, boolean isValueAvailableOnlyAfterCompilation, JavaConstant constantValue) { + super(transformedValueAllowedType, fieldValueTransformer, disableCaching); + this.original = original; + this.annotated = annotated; + this.kind = kind; + this.targetClass = targetClass; + this.targetField = targetField; + this.isFinal = isFinal; + this.isValueAvailableBeforeAnalysis = isValueAvailableBeforeAnalysis; + this.isValueAvailableOnlyAfterAnalysis = isValueAvailableOnlyAfterAnalysis; + this.isValueAvailableOnlyAfterCompilation = isValueAvailableOnlyAfterCompilation; + this.constantValue = constantValue; + } + @Override public boolean isValueAvailable() { /* @@ -200,6 +196,10 @@ public ResolvedJavaField getAnnotated() { return annotated; } + Class getTargetClass() { + return targetClass; + } + public Field getTargetField() { return targetField; } @@ -303,52 +303,19 @@ public JavaConstant readValue(ClassInitializationSupport classInitializationSupp return constantValue; } - ReadLock readLock = valueCacheLock.readLock(); - try { - readLock.lock(); - JavaConstant result = getCached(receiver); - if (result != null) { - return result; - } - } finally { - readLock.unlock(); - } - - WriteLock writeLock = valueCacheLock.writeLock(); - try { - writeLock.lock(); - /* - * Check the cache again, now that we are holding the write-lock, i.e., we know that no - * other thread is computing a value right now. - */ - JavaConstant result = getCached(receiver); - if (result != null) { - return result; - } - /* - * Note that the value computation must be inside the lock, because we want to guarantee - * that field-value computers are only executed once per unique receiver. - */ - result = computeValue(classInitializationSupport, receiver); - putCached(receiver, result); - return result; - } finally { - writeLock.unlock(); - } + return super.readValue(classInitializationSupport, original, receiver); } - private JavaConstant computeValue(ClassInitializationSupport classInitializationSupport, JavaConstant receiver) { + @Override + protected JavaConstant computeValue(ClassInitializationSupport classInitializationSupport, ResolvedJavaField field, JavaConstant receiver) { assert isValueAvailable() : "Field " + format("%H.%n") + " value not available for reading."; - SnippetReflectionProvider originalSnippetReflection = GraalAccess.getOriginalSnippetReflection(); JavaConstant result; - Object originalValue; switch (kind) { case NewInstanceWhenNotNull: - originalValue = fetchOriginalValue(classInitializationSupport, receiver, originalSnippetReflection); - result = originalValue == null ? originalSnippetReflection.forObject(null) : createNewInstance(originalSnippetReflection); + result = fetchOriginalValue(classInitializationSupport, field, receiver) == null ? JavaConstant.NULL_POINTER : createNewInstance(); break; case NewInstance: - result = createNewInstance(originalSnippetReflection); + result = createNewInstance(); break; case AtomicFieldUpdaterOffset: result = computeAtomicFieldUpdaterOffset(classInitializationSupport, receiver); @@ -357,91 +324,25 @@ private JavaConstant computeValue(ClassInitializationSupport classInitialization result = translateFieldOffset(classInitializationSupport, receiver, targetClass); break; case Custom: - Object receiverValue = receiver == null ? null : originalSnippetReflection.asObject(Object.class, receiver); - originalValue = fetchOriginalValue(classInitializationSupport, receiver, originalSnippetReflection); - Object newValue = fieldValueTransformer.transform(receiverValue, originalValue); - checkValue(newValue); - result = originalSnippetReflection.forBoxed(original.getJavaKind(), newValue); - - assert result.getJavaKind() == original.getJavaKind(); + result = super.computeValue(classInitializationSupport, field, receiver); break; default: - throw shouldNotReachHere("Field recomputation of kind " + kind + " for " + fieldFormat() + " not yet supported"); + throw shouldNotReachHere("Field recomputation of kind " + kind + " for field " + original.format("%H.%n") + + (annotated != null ? " specified by alias " + annotated.format("%H.%n") : "") + " not yet supported"); } return result; } - private void checkValue(Object newValue) { - boolean primitive = transformedValueAllowedType.isPrimitive(); - if (newValue == null) { - if (primitive) { - throw UserError.abort("Field value transformer returned null for primitive %s", fieldFormat()); - } else { - /* Null is always allowed for reference fields. */ - return; - } - } - /* - * The compute/transform methods autobox primitive values. We unbox them here, but only if - * the original field is primitive. - */ - Class actualType = primitive ? toUnboxedClass(newValue.getClass()) : newValue.getClass(); - if (!transformedValueAllowedType.isAssignableFrom(actualType)) { - throw UserError.abort("Field value transformer returned value of type `%s` that is not assignable to declared type `%s` of %s", - actualType.getTypeName(), transformedValueAllowedType.getTypeName(), fieldFormat()); - } - } - - private String fieldFormat() { - return "field " + original.format("%H.%n") + (annotated != null ? " specified by alias " + annotated.format("%H.%n") : ""); - } - - private JavaConstant createNewInstance(SnippetReflectionProvider originalSnippetReflection) { + private JavaConstant createNewInstance() { JavaConstant result; try { - result = originalSnippetReflection.forObject(ReflectionUtil.newInstance(targetClass)); + result = GraalAccess.getOriginalSnippetReflection().forObject(ReflectionUtil.newInstance(targetClass)); } catch (ReflectionUtilError ex) { throw VMError.shouldNotReachHere("Error performing field recomputation for alias " + annotated.format("%H.%n"), ex.getCause()); } return result; } - private Object fetchOriginalValue(ClassInitializationSupport classInitializationSupport, JavaConstant receiver, - SnippetReflectionProvider originalSnippetReflection) { - JavaConstant originalValueConstant = ReadableJavaField.readFieldValue(classInitializationSupport, original, receiver); - if (originalValueConstant == null) { - /* - * The class is still uninitialized, so static fields cannot be read. Or it is an - * instance field in a substitution class, i.e., a field that does not exist in the - * hosted object. - */ - return null; - } else if (originalValueConstant.getJavaKind().isPrimitive()) { - return originalValueConstant.asBoxedPrimitive(); - } else { - return originalSnippetReflection.asObject(Object.class, originalValueConstant); - } - } - - private void putCached(JavaConstant receiver, JavaConstant result) { - if (disableCaching) { - return; - } - if (receiver == null) { - valueCacheNullKey = result; - } else { - valueCache.put(receiver, result); - } - } - - private JavaConstant getCached(JavaConstant receiver) { - if (receiver == null) { - return valueCacheNullKey; - } else { - return valueCache.get(receiver); - } - } - @Override public boolean injectFinalForRuntimeCompilation() { if (original.isFinal()) { @@ -525,8 +426,8 @@ public String toString() { } @Override - public Field getJavaField() { - return OriginalFieldProvider.getJavaField(original); + public ResolvedJavaField unwrapTowardsOriginalField() { + return original; } @Override diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/substitute/FieldValueTransformation.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/substitute/FieldValueTransformation.java new file mode 100644 index 000000000000..20f8332ede05 --- /dev/null +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/substitute/FieldValueTransformation.java @@ -0,0 +1,156 @@ +/* + * Copyright (c) 2023, 2023, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.svm.hosted.substitute; + +import java.util.concurrent.locks.ReentrantReadWriteLock; +import java.util.concurrent.locks.ReentrantReadWriteLock.ReadLock; +import java.util.concurrent.locks.ReentrantReadWriteLock.WriteLock; + +import org.graalvm.collections.EconomicMap; +import org.graalvm.nativeimage.hosted.FieldValueTransformer; + +import com.oracle.graal.pointsto.util.GraalAccess; +import com.oracle.svm.core.SubstrateUtil; +import com.oracle.svm.core.util.UserError; +import com.oracle.svm.hosted.ameta.ReadableJavaField; +import com.oracle.svm.hosted.classinitialization.ClassInitializationSupport; + +import jdk.vm.ci.meta.JavaConstant; +import jdk.vm.ci.meta.ResolvedJavaField; + +public class FieldValueTransformation { + protected final FieldValueTransformer fieldValueTransformer; + protected final Class transformedValueAllowedType; + protected final boolean disableCaching; + + private final EconomicMap valueCache = EconomicMap.create(); + private final ReentrantReadWriteLock valueCacheLock = new ReentrantReadWriteLock(); + + public FieldValueTransformation(Class transformedValueAllowedType, FieldValueTransformer fieldValueTransformer, boolean disableCaching) { + this.fieldValueTransformer = fieldValueTransformer; + this.transformedValueAllowedType = transformedValueAllowedType; + this.disableCaching = disableCaching; + } + + public FieldValueTransformer getFieldValueTransformer() { + return fieldValueTransformer; + } + + public JavaConstant readValue(ClassInitializationSupport classInitializationSupport, ResolvedJavaField field, JavaConstant receiver) { + ReadLock readLock = valueCacheLock.readLock(); + try { + readLock.lock(); + JavaConstant result = getCached(receiver); + if (result != null) { + return result; + } + } finally { + readLock.unlock(); + } + + WriteLock writeLock = valueCacheLock.writeLock(); + try { + writeLock.lock(); + /* + * Check the cache again, now that we are holding the write-lock, i.e., we know that no + * other thread is computing a value right now. + */ + JavaConstant result = getCached(receiver); + if (result != null) { + return result; + } + /* + * Note that the value computation must be inside the lock, because we want to guarantee + * that field-value computers are only executed once per unique receiver. + */ + result = computeValue(classInitializationSupport, field, receiver); + putCached(receiver, result); + return result; + } finally { + writeLock.unlock(); + } + } + + protected JavaConstant computeValue(ClassInitializationSupport classInitializationSupport, ResolvedJavaField field, JavaConstant receiver) { + Object receiverValue = receiver == null ? null : GraalAccess.getOriginalSnippetReflection().asObject(Object.class, receiver); + Object originalValue = fetchOriginalValue(classInitializationSupport, field, receiver); + Object newValue = fieldValueTransformer.transform(receiverValue, originalValue); + checkValue(newValue, field); + JavaConstant result = GraalAccess.getOriginalSnippetReflection().forBoxed(field.getJavaKind(), newValue); + + assert result.getJavaKind() == field.getJavaKind(); + return result; + } + + private void checkValue(Object newValue, ResolvedJavaField field) { + boolean primitive = transformedValueAllowedType.isPrimitive(); + if (newValue == null) { + if (primitive) { + throw UserError.abort("Field value transformer returned null for primitive %s", field.format("%H.%n")); + } else { + /* Null is always allowed for reference fields. */ + return; + } + } + /* + * The compute/transform methods autobox primitive values. We unbox them here, but only if + * the original field is primitive. + */ + Class actualType = primitive ? SubstrateUtil.toUnboxedClass(newValue.getClass()) : newValue.getClass(); + if (!transformedValueAllowedType.isAssignableFrom(actualType)) { + throw UserError.abort("Field value transformer returned value of type `%s` that is not assignable to declared type `%s` of %s", + actualType.getTypeName(), transformedValueAllowedType.getTypeName(), field.format("%H.%n")); + } + } + + protected Object fetchOriginalValue(ClassInitializationSupport classInitializationSupport, ResolvedJavaField field, JavaConstant receiver) { + JavaConstant originalValueConstant = ReadableJavaField.readFieldValue(classInitializationSupport, field, receiver); + if (originalValueConstant == null) { + /* + * The class is still uninitialized, so static fields cannot be read. Or it is an + * instance field in a substitution class, i.e., a field that does not exist in the + * hosted object. + */ + return null; + } else if (originalValueConstant.getJavaKind().isPrimitive()) { + return originalValueConstant.asBoxedPrimitive(); + } else { + return GraalAccess.getOriginalSnippetReflection().asObject(Object.class, originalValueConstant); + } + } + + private void putCached(JavaConstant receiver, JavaConstant result) { + if (disableCaching) { + return; + } + JavaConstant key = receiver == null ? JavaConstant.NULL_POINTER : receiver; + valueCache.put(key, result); + } + + private JavaConstant getCached(JavaConstant receiver) { + JavaConstant key = receiver == null ? JavaConstant.NULL_POINTER : receiver; + return valueCache.get(key); + } +} diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/substitute/SubstitutionField.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/substitute/SubstitutionField.java index 5df2f1454341..e72df883588b 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/substitute/SubstitutionField.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/substitute/SubstitutionField.java @@ -25,7 +25,6 @@ package com.oracle.svm.hosted.substitute; import java.lang.reflect.AnnotatedElement; -import java.lang.reflect.Field; import com.oracle.graal.pointsto.infrastructure.OriginalFieldProvider; import com.oracle.svm.hosted.ameta.ReadableJavaField; @@ -131,8 +130,8 @@ public AnnotatedElement getAnnotationRoot() { } @Override - public Field getJavaField() { - return OriginalFieldProvider.getJavaField(original); + public ResolvedJavaField unwrapTowardsOriginalField() { + return original; } @Override From 145124e41092ffe438405415f532fb52cff72963 Mon Sep 17 00:00:00 2001 From: Francois Farquet Date: Fri, 15 Dec 2023 08:47:26 +0100 Subject: [PATCH 218/593] Inherit SVM dependencies for libgraal benchmarks --- compiler/ci/ci_common/compiler-common.libsonnet | 1 + 1 file changed, 1 insertion(+) diff --git a/compiler/ci/ci_common/compiler-common.libsonnet b/compiler/ci/ci_common/compiler-common.libsonnet index 0c06c55de24f..7f97e498a3d8 100644 --- a/compiler/ci/ci_common/compiler-common.libsonnet +++ b/compiler/ci/ci_common/compiler-common.libsonnet @@ -53,6 +53,7 @@ job_prefix:: "bench-compiler", tags+: ["bench-compiler"], python_version : "3", + packages+: common.deps.svm.packages, environment+: { BENCH_RESULTS_FILE_PATH : "bench-results.json" }, From b3f1660fd41406870b00dff510140de198bbc435 Mon Sep 17 00:00:00 2001 From: Tom Shull Date: Thu, 30 Nov 2023 11:43:08 +0100 Subject: [PATCH 219/593] cleanup (truffle) runtime compilation hierarchy --- .../graal/pointsto/flow/MethodTypeFlow.java | 4 +- .../hosted/ParseOnceDeoptTestFeature.java | 253 ---- .../hosted/RuntimeCompilationFeature.java | 730 ----------- .../runtimecompilation/CallTreeInfo.java | 337 +++++ .../GraalGraphObjectReplacer.java | 2 +- .../RuntimeCompilationCandidate.java | 63 + .../RuntimeCompilationFeature.java} | 1098 ++++++----------- .../RuntimeCompiledMethod.java | 80 ++ .../RuntimeCompiledMethodSupport.java | 570 +++++++++ .../SubstrateGraalCompilerSetup.java | 2 +- .../SubstrateProviders.java | 2 +- .../graal/isolated/IsolateAwareProviders.java | 2 +- .../substitutions/GraalSubstitutions.java | 2 +- .../svm/hosted/NativeImageGenerator.java | 16 +- ....java => RuntimeCompilationCallbacks.java} | 5 +- .../hosted/analysis/SVMParsingSupport.java | 7 +- .../svm/truffle/TruffleBaseFeature.java | 6 +- .../oracle/svm/truffle/TruffleFeature.java | 69 +- .../oracle/svm/truffle/TruffleSupport.java | 18 +- 19 files changed, 1532 insertions(+), 1734 deletions(-) delete mode 100644 substratevm/src/com.oracle.svm.graal/src/com/oracle/svm/graal/hosted/ParseOnceDeoptTestFeature.java delete mode 100644 substratevm/src/com.oracle.svm.graal/src/com/oracle/svm/graal/hosted/RuntimeCompilationFeature.java create mode 100644 substratevm/src/com.oracle.svm.graal/src/com/oracle/svm/graal/hosted/runtimecompilation/CallTreeInfo.java rename substratevm/src/com.oracle.svm.graal/src/com/oracle/svm/graal/hosted/{ => runtimecompilation}/GraalGraphObjectReplacer.java (99%) create mode 100644 substratevm/src/com.oracle.svm.graal/src/com/oracle/svm/graal/hosted/runtimecompilation/RuntimeCompilationCandidate.java rename substratevm/src/com.oracle.svm.graal/src/com/oracle/svm/graal/hosted/{ParseOnceRuntimeCompilationFeature.java => runtimecompilation/RuntimeCompilationFeature.java} (52%) create mode 100644 substratevm/src/com.oracle.svm.graal/src/com/oracle/svm/graal/hosted/runtimecompilation/RuntimeCompiledMethod.java create mode 100644 substratevm/src/com.oracle.svm.graal/src/com/oracle/svm/graal/hosted/runtimecompilation/RuntimeCompiledMethodSupport.java rename substratevm/src/com.oracle.svm.graal/src/com/oracle/svm/graal/hosted/{ => runtimecompilation}/SubstrateGraalCompilerSetup.java (98%) rename substratevm/src/com.oracle.svm.graal/src/com/oracle/svm/graal/hosted/{ => runtimecompilation}/SubstrateProviders.java (98%) rename substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/{RuntimeCompilationSupport.java => RuntimeCompilationCallbacks.java} (89%) diff --git a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/flow/MethodTypeFlow.java b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/flow/MethodTypeFlow.java index be8af5a17052..e840e5e016ce 100644 --- a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/flow/MethodTypeFlow.java +++ b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/flow/MethodTypeFlow.java @@ -180,7 +180,7 @@ private synchronized void createFlowsGraph(PointsToAnalysis bb, InvokeTypeFlow r initFlowsGraph(bb, builder.postInitFlows); } catch (Throwable t) { - /* Wrap all other errors as parsing errors. */ + /* Wrap all errors as parsing errors. */ throw AnalysisError.parsingError(method, t); } } @@ -342,7 +342,7 @@ public synchronized boolean updateFlowsGraph(PointsToAnalysis bb, MethodFlowsGra } } } catch (Throwable t) { - /* Wrap all other errors as parsing errors. */ + /* Wrap all errors as parsing errors. */ throw AnalysisError.parsingError(method, t); } return true; diff --git a/substratevm/src/com.oracle.svm.graal/src/com/oracle/svm/graal/hosted/ParseOnceDeoptTestFeature.java b/substratevm/src/com.oracle.svm.graal/src/com/oracle/svm/graal/hosted/ParseOnceDeoptTestFeature.java deleted file mode 100644 index aa9d43fe94f8..000000000000 --- a/substratevm/src/com.oracle.svm.graal/src/com/oracle/svm/graal/hosted/ParseOnceDeoptTestFeature.java +++ /dev/null @@ -1,253 +0,0 @@ -/* - * Copyright (c) 2023, 2023, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.oracle.svm.graal.hosted; - -import static com.oracle.svm.common.meta.MultiMethod.DEOPT_TARGET_METHOD; -import static com.oracle.svm.common.meta.MultiMethod.ORIGINAL_METHOD; - -import java.util.Collection; -import java.util.List; -import java.util.function.Function; -import java.util.function.Supplier; - -import jdk.graal.compiler.debug.DebugContext; -import jdk.graal.compiler.nodes.StructuredGraph; -import jdk.graal.compiler.nodes.graphbuilderconf.GraphBuilderConfiguration; -import org.graalvm.nativeimage.ImageSingletons; -import org.graalvm.nativeimage.hosted.Feature; - -import com.oracle.graal.pointsto.BigBang; -import com.oracle.graal.pointsto.PointsToAnalysis; -import com.oracle.graal.pointsto.api.HostVM; -import com.oracle.graal.pointsto.flow.InvokeTypeFlow; -import com.oracle.graal.pointsto.meta.AnalysisMethod; -import com.oracle.graal.pointsto.meta.AnalysisType; -import com.oracle.graal.pointsto.meta.HostedProviders; -import com.oracle.graal.pointsto.meta.PointsToAnalysisMethod; -import com.oracle.graal.pointsto.phases.InlineBeforeAnalysisPolicy; -import com.oracle.svm.common.meta.MultiMethod; -import com.oracle.svm.core.feature.InternalFeature; -import com.oracle.svm.core.graal.snippets.DeoptTester; -import com.oracle.svm.core.util.VMError; -import com.oracle.svm.hosted.SVMHost; -import com.oracle.svm.hosted.analysis.SVMParsingSupport; -import com.oracle.svm.hosted.code.DeoptimizationUtils; -import com.oracle.svm.hosted.phases.InlineBeforeAnalysisPolicyUtils; - -import jdk.vm.ci.meta.ResolvedJavaType; - -/** - * For Deoptimization Testing we create two versions of candidate methods: - *

      - *
    1. The "original" method which can deoptimize
    2. - *
    3. A deoptimization target method to deoptimize to
    4. - *
    - * - * This is different than our runtime compilation support, as in that environment also a runtime - * compilation version for methods are created. In addition, in that environment "original" methods - * are not allowed to deoptimize. - */ -public class ParseOnceDeoptTestFeature implements InternalFeature { - @Override - public List> getRequiredFeatures() { - return List.of(DeoptimizationFeature.class); - } - - @Override - public void afterRegistration(AfterRegistrationAccess access) { - ImageSingletons.add(SVMParsingSupport.class, new DeoptTestingParsingSupport()); - ImageSingletons.add(HostVM.MultiMethodAnalysisPolicy.class, new DeoptTestingAnalysisPolicy()); - } - - private class DeoptTestingParsingSupport implements SVMParsingSupport { - - @Override - public Object parseGraph(BigBang bb, DebugContext debug, AnalysisMethod method) { - /* Regular parsing is always used. */ - return HostVM.PARSING_UNHANDLED; - } - - @Override - public GraphBuilderConfiguration updateGraphBuilderConfiguration(GraphBuilderConfiguration config, AnalysisMethod method) { - if (method.isDeoptTarget()) { - /* - * Local variables are never retained to help ensure the state of the deoptimization - * source will always be a superset of the deoptimization target. - */ - return config.withRetainLocalVariables(false); - } - return config; - } - - @Override - public boolean validateGraph(PointsToAnalysis bb, StructuredGraph graph) { - PointsToAnalysisMethod aMethod = (PointsToAnalysisMethod) graph.method(); - Supplier graphInvalidator = DeoptimizationUtils.createGraphInvalidator(graph); - if (aMethod.isDeoptTarget()) { - return !graphInvalidator.get(); - } else { - boolean canDeoptForTesting = aMethod.isOriginalMethod() && - DeoptimizationUtils.canDeoptForTesting(aMethod, DeoptTester.enabled(), graphInvalidator); - if (canDeoptForTesting) { - DeoptimizationUtils.registerDeoptEntriesForDeoptTesting(bb, graph, aMethod); - } - } - - return true; - } - - @Override - public boolean allowAssumptions(AnalysisMethod method) { - /* Assumptions are not allowed it AOT compiled methods */ - return false; - } - - @Override - public boolean recordInlinedMethods(AnalysisMethod method) { - return false; - } - - @Override - public HostedProviders getHostedProviders(MultiMethod.MultiMethodKey key) { - /* The buildtime providers are always used. */ - return null; - } - - @Override - public void initializeInlineBeforeAnalysisPolicy(SVMHost svmHost, InlineBeforeAnalysisPolicyUtils inliningUtils) { - /* We do not use a custom analysis policy for deopt testing. */ - } - - /** - * Currently we do not support inlining before analysis during deopt testing. More work is - * needed to support this. - */ - @Override - public InlineBeforeAnalysisPolicy inlineBeforeAnalysisPolicy(MultiMethod.MultiMethodKey multiMethodKey, InlineBeforeAnalysisPolicy defaultPolicy) { - if (multiMethodKey == ORIGINAL_METHOD) { - /* - * Since we can deopt from original methods, we do not inline here. Doing so would - * require us to track the flows into these inlined methods. - */ - return InlineBeforeAnalysisPolicy.NO_INLINING; - } else if (multiMethodKey == DEOPT_TARGET_METHOD) { - return InlineBeforeAnalysisPolicy.NO_INLINING; - } else { - throw VMError.shouldNotReachHere("Unexpected method key: %s", multiMethodKey); - } - } - - @Override - public Function getStrengthenGraphsToTargetFunction(MultiMethod.MultiMethodKey key) { - /* No customization is needed to deopt testing. */ - return null; - } - } - - private static class DeoptTestingAnalysisPolicy implements HostVM.MultiMethodAnalysisPolicy { - - @Override - public Collection determineCallees(BigBang bb, T implementation, T target, MultiMethod.MultiMethodKey callerMultiMethodKey, InvokeTypeFlow invokeFlow) { - if (callerMultiMethodKey == ORIGINAL_METHOD) { - if (DeoptimizationUtils.canDeoptForTesting(implementation, DeoptTester.enabled(), () -> false)) { - /* - * If the target is registered for deoptimization, then we must also make a - * deoptimized version. - */ - return List.of(implementation, getDeoptVersion(implementation)); - } else { - return List.of(implementation); - } - } else { - assert callerMultiMethodKey == DEOPT_TARGET_METHOD; - /* - * A deoptimization target will always call the original method. However, the return - * can also be from a deoptimized version when a deoptimization is triggered in an - * inlined callee. - */ - return List.of(implementation, getDeoptVersion(implementation)); - } - } - - @SuppressWarnings("unchecked") - protected T getDeoptVersion(T implementation) { - /* - * Flows for deopt versions are only created once a frame state for the method is seen - * within a runtime compiled method. - */ - return (T) implementation.getOrCreateMultiMethod(DEOPT_TARGET_METHOD, (newMethod) -> ((PointsToAnalysisMethod) newMethod).getTypeFlow().setAsStubFlow()); - } - - @Override - public boolean performParameterLinking(MultiMethod.MultiMethodKey callerMultiMethodKey, MultiMethod.MultiMethodKey calleeMultiMethodKey) { - if (callerMultiMethodKey == DEOPT_TARGET_METHOD) { - /* A deopt method can call the original version only. */ - return calleeMultiMethodKey == ORIGINAL_METHOD; - } else { - assert callerMultiMethodKey == ORIGINAL_METHOD; - /* An original method can call the deopt target as well. */ - return true; - } - } - - @Override - public boolean performReturnLinking(MultiMethod.MultiMethodKey callerMultiMethodKey, MultiMethod.MultiMethodKey calleeMultiMethodKey) { - if (callerMultiMethodKey == DEOPT_TARGET_METHOD) { - /* A deopt method can be returned to from the deopt target or an original method. */ - return true; - } else { - assert callerMultiMethodKey == ORIGINAL_METHOD; - /* - * An original method can be returned to from the deopt target or an original - * method. - */ - return true; - } - } - - @Override - public boolean canComputeReturnedParameterIndex(MultiMethod.MultiMethodKey multiMethodKey) { - /* - * Since Deopt Target Methods may have their flow created multiple times, this - * optimization is not allowed. - */ - return multiMethodKey != DEOPT_TARGET_METHOD; - } - - @Override - public boolean insertPlaceholderParamAndReturnFlows(MultiMethod.MultiMethodKey multiMethodKey) { - /* - * Since Deopt Target Methods may have their flow created multiple times, placeholder - * flows are needed. - */ - return multiMethodKey == DEOPT_TARGET_METHOD; - } - - @Override - public boolean unknownReturnValue(BigBang bb, MultiMethod.MultiMethodKey callerMultiMethodKey, AnalysisMethod implementation) { - return false; - } - } -} diff --git a/substratevm/src/com.oracle.svm.graal/src/com/oracle/svm/graal/hosted/RuntimeCompilationFeature.java b/substratevm/src/com.oracle.svm.graal/src/com/oracle/svm/graal/hosted/RuntimeCompilationFeature.java deleted file mode 100644 index 25829a88652a..000000000000 --- a/substratevm/src/com.oracle.svm.graal/src/com/oracle/svm/graal/hosted/RuntimeCompilationFeature.java +++ /dev/null @@ -1,730 +0,0 @@ -/* - * Copyright (c) 2013, 2022, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.oracle.svm.graal.hosted; - -import static com.oracle.svm.core.util.VMError.guarantee; - -import java.lang.reflect.Executable; -import java.util.ArrayList; -import java.util.Collection; -import java.util.Comparator; -import java.util.LinkedHashSet; -import java.util.List; -import java.util.Map; -import java.util.Objects; -import java.util.Set; -import java.util.concurrent.ConcurrentHashMap; -import java.util.function.BooleanSupplier; -import java.util.function.Function; -import java.util.function.Predicate; -import java.util.stream.Collectors; - -import org.graalvm.nativeimage.ImageSingletons; -import org.graalvm.nativeimage.hosted.Feature; -import org.graalvm.nativeimage.hosted.Feature.AfterCompilationAccess; -import org.graalvm.nativeimage.hosted.Feature.AfterHeapLayoutAccess; -import org.graalvm.nativeimage.hosted.Feature.BeforeAnalysisAccess; -import org.graalvm.nativeimage.hosted.Feature.BeforeHeapLayoutAccess; -import org.graalvm.nativeimage.hosted.Feature.DuringSetupAccess; -import org.graalvm.word.LocationIdentity; - -import com.oracle.graal.pointsto.BigBang; -import com.oracle.graal.pointsto.heap.ImageHeapConstant; -import com.oracle.graal.pointsto.heap.ImageHeapScanner; -import com.oracle.graal.pointsto.meta.AnalysisMetaAccess; -import com.oracle.graal.pointsto.meta.AnalysisMethod; -import com.oracle.graal.pointsto.meta.AnalysisType; -import com.oracle.graal.pointsto.meta.HostedProviders; -import com.oracle.graal.pointsto.util.GraalAccess; -import com.oracle.svm.core.FrameAccess; -import com.oracle.svm.core.ParsingReason; -import com.oracle.svm.core.SubstrateOptions; -import com.oracle.svm.core.config.ConfigurationValues; -import com.oracle.svm.core.graal.RuntimeCompilationCanaryFeature; -import com.oracle.svm.core.graal.code.SubstrateBackend; -import com.oracle.svm.core.graal.code.SubstrateMetaAccessExtensionProvider; -import com.oracle.svm.core.graal.code.SubstratePlatformConfigurationProvider; -import com.oracle.svm.core.graal.meta.RuntimeConfiguration; -import com.oracle.svm.core.graal.meta.SubstrateReplacements; -import com.oracle.svm.core.graal.nodes.ThrowBytecodeExceptionNode; -import com.oracle.svm.core.graal.word.SubstrateWordTypes; -import com.oracle.svm.core.heap.BarrierSetProvider; -import com.oracle.svm.core.jdk.RuntimeSupport; -import com.oracle.svm.core.meta.SharedType; -import com.oracle.svm.core.option.HostedOptionKey; -import com.oracle.svm.core.option.LocatableMultiOptionValue; -import com.oracle.svm.core.option.RuntimeOptionValues; -import com.oracle.svm.core.util.UserError; -import com.oracle.svm.core.util.VMError; -import com.oracle.svm.graal.GraalSupport; -import com.oracle.svm.graal.SubstrateGraalRuntime; -import com.oracle.svm.graal.TruffleRuntimeCompilationSupport; -import com.oracle.svm.graal.meta.SubstrateField; -import com.oracle.svm.graal.meta.SubstrateMethod; -import com.oracle.svm.graal.meta.SubstrateType; -import com.oracle.svm.graal.meta.SubstrateUniverseFactory; -import com.oracle.svm.hosted.FeatureHandler; -import com.oracle.svm.hosted.FeatureImpl; -import com.oracle.svm.hosted.FeatureImpl.AfterHeapLayoutAccessImpl; -import com.oracle.svm.hosted.FeatureImpl.BeforeAnalysisAccessImpl; -import com.oracle.svm.hosted.FeatureImpl.CompilationAccessImpl; -import com.oracle.svm.hosted.FeatureImpl.DuringSetupAccessImpl; -import com.oracle.svm.hosted.NativeImageGenerator; -import com.oracle.svm.hosted.ProgressReporter; -import com.oracle.svm.hosted.analysis.Inflation; -import com.oracle.svm.hosted.classinitialization.ClassInitializationSupport; -import com.oracle.svm.hosted.meta.HostedMetaAccess; -import com.oracle.svm.hosted.meta.HostedUniverse; -import com.oracle.svm.hosted.phases.SubstrateClassInitializationPlugin; - -import jdk.graal.compiler.api.runtime.GraalRuntime; -import jdk.graal.compiler.core.common.spi.ConstantFieldProvider; -import jdk.graal.compiler.core.common.spi.MetaAccessExtensionProvider; -import jdk.graal.compiler.debug.DebugContext; -import jdk.graal.compiler.graph.NodeClass; -import jdk.graal.compiler.lir.phases.LIRSuites; -import jdk.graal.compiler.nodes.GraphDecoder; -import jdk.graal.compiler.nodes.GraphEncoder; -import jdk.graal.compiler.nodes.StructuredGraph; -import jdk.graal.compiler.nodes.extended.BytecodeExceptionNode; -import jdk.graal.compiler.nodes.graphbuilderconf.GraphBuilderConfiguration; -import jdk.graal.compiler.nodes.graphbuilderconf.GraphBuilderConfiguration.BytecodeExceptionMode; -import jdk.graal.compiler.nodes.graphbuilderconf.GraphBuilderContext; -import jdk.graal.compiler.options.Option; -import jdk.graal.compiler.options.OptionStability; -import jdk.graal.compiler.phases.OptimisticOptimizations; -import jdk.graal.compiler.phases.tiers.Suites; -import jdk.graal.compiler.phases.util.Providers; -import jdk.graal.compiler.truffle.nodes.ObjectLocationIdentity; -import jdk.vm.ci.code.Architecture; -import jdk.vm.ci.meta.JavaConstant; -import jdk.vm.ci.meta.JavaKind; -import jdk.vm.ci.meta.JavaType; -import jdk.vm.ci.meta.ResolvedJavaMethod; -import jdk.vm.ci.meta.ResolvedJavaType; - -/** - * The main handler for running the Graal compiler in the Substrate VM at run time. This feature - * (and features it depends on like {@link FieldsOffsetsFeature}) encodes Graal graphs for runtime - * compilation, ensures that all required {@link SubstrateType}, {@link SubstrateMethod}, - * {@link SubstrateField} objects are created by {@link GraalGraphObjectReplacer} and added to the - * image. Data that is prepared during image generation and used at run time is stored in - * {@link TruffleRuntimeCompilationSupport}. - */ -public abstract class RuntimeCompilationFeature { - - public static class Options { - @Option(help = "Print methods available for runtime compilation")// - public static final HostedOptionKey PrintRuntimeCompileMethods = new HostedOptionKey<>(false); - - @Option(help = "Print call tree of methods reachable for runtime compilation")// - public static final HostedOptionKey PrintRuntimeCompilationCallTree = new HostedOptionKey<>(false); - - @Option(help = "Maximum number of methods allowed for runtime compilation.", stability = OptionStability.STABLE)// - public static final HostedOptionKey MaxRuntimeCompileMethods = new HostedOptionKey<>(LocatableMultiOptionValue.Strings.build()); - - @Option(help = "Enforce checking of maximum number of methods allowed for runtime compilation. Useful for checking in the gate that the number of methods does not go up without a good reason.")// - public static final HostedOptionKey EnforceMaxRuntimeCompileMethods = new HostedOptionKey<>(false); - } - - public static final class IsEnabled implements BooleanSupplier { - @Override - public boolean getAsBoolean() { - return ImageSingletons.contains(RuntimeCompilationFeature.class); - } - } - - public static RuntimeCompilationFeature singleton() { - return ImageSingletons.lookup(RuntimeCompilationFeature.class); - } - - public static Class getRuntimeCompilationFeature() { - return ParseOnceRuntimeCompilationFeature.class; - } - - public interface RuntimeCompilationCandidatePredicate { - boolean allowRuntimeCompilation(ResolvedJavaMethod method); - } - - public interface AllowInliningPredicate { - enum InlineDecision { - INLINE, - INLINING_DISALLOWED, - NO_DECISION - } - - InlineDecision allowInlining(GraphBuilderContext builder, ResolvedJavaMethod target); - } - - public abstract static class AbstractCallTreeNode implements Comparable { - private final AnalysisMethod implementationMethod; - private final AnalysisMethod targetMethod; - private final AbstractCallTreeNode parent; - private final int level; - private Set children; - - protected AbstractCallTreeNode(AbstractCallTreeNode parent, AnalysisMethod targetMethod, AnalysisMethod implementationMethod) { - this.implementationMethod = implementationMethod; - this.targetMethod = targetMethod; - this.parent = parent; - this.children = null; - if (parent != null) { - level = parent.level + 1; - } else { - level = 0; - } - } - - public AnalysisMethod getImplementationMethod() { - return implementationMethod; - } - - public AnalysisMethod getTargetMethod() { - return targetMethod; - } - - protected AbstractCallTreeNode getParent() { - return parent; - } - - /** - * Helper method to create parent->child link when this node becomes part of the call tree. - */ - protected void linkAsChild() { - if (parent != null) { - if (parent.children == null) { - parent.children = new LinkedHashSet<>(); - } - boolean added = parent.children.add(this); - assert added : "child linked to parent multiple times."; - } - } - - private Collection getChildren() { - return children == null ? List.of() : children; - } - - protected int getLevel() { - return level; - } - - public abstract String getPosition(); - - public abstract int getNodeCount(); - - @Override - public int compareTo(AbstractCallTreeNode o) { - int result = implementationMethod.getQualifiedName().compareTo(o.implementationMethod.getQualifiedName()); - if (result != 0) { - return result; - } - result = targetMethod.getQualifiedName().compareTo(o.targetMethod.getQualifiedName()); - if (result != 0) { - return result; - } - - result = Integer.compare(level, o.level); - if (result != 0) { - return result; - } - - if (parent != null && o.parent != null) { - return parent.compareTo(o.parent); - } - - // this must be true otherwise the level check should return different value - assert parent == null && o.parent == null; - return 0; - } - - /** - * For equality purposes we only care whether it is an equivalent call site (i.e., the - * target and implementation match). - */ - @Override - public boolean equals(Object o) { - if (this == o) { - return true; - } - if (o == null || getClass() != o.getClass()) { - return false; - } - AbstractCallTreeNode that = (AbstractCallTreeNode) o; - - return implementationMethod.equals(that.implementationMethod) && targetMethod.equals(that.targetMethod); - } - - @Override - public int hashCode() { - return Objects.hash(implementationMethod, targetMethod); - } - } - - protected abstract AbstractCallTreeNode getCallTreeNode(RuntimeCompilationCandidate candidate); - - protected abstract AbstractCallTreeNode getCallTreeNode(RuntimeCompiledMethod method); - - protected abstract AbstractCallTreeNode getCallTreeNode(ResolvedJavaMethod method); - - public interface RuntimeCompiledMethod { - AnalysisMethod getMethod(); - - Collection getInlinedMethods(); - - Collection getInvokeTargets(); - } - - public abstract Collection getRuntimeCompiledMethods(); - - public interface RuntimeCompilationCandidate { - AnalysisMethod getImplementationMethod(); - - AnalysisMethod getTargetMethod(); - } - - public abstract Collection getAllRuntimeCompilationCandidates(); - - public final Comparator getRuntimeCompilationComparator() { - return (o1, o2) -> getCallTreeNode(o1).compareTo(getCallTreeNode(o2)); - } - - public final List getCallTrace(ResolvedJavaMethod method) { - return getCallTraceHelper(getCallTreeNode(method)); - } - - public final List getCallTrace(RuntimeCompilationCandidate candidate) { - return getCallTraceHelper(getCallTreeNode(candidate)); - } - - private static List getCallTraceHelper(AbstractCallTreeNode node) { - List trace = new ArrayList<>(); - for (AbstractCallTreeNode cur = node; cur != null; cur = cur.getParent()) { - trace.add(cur.getPosition()); - } - return trace; - } - - protected GraalGraphObjectReplacer objectReplacer; - protected HostedProviders hostedProviders; - protected GraphEncoder graphEncoder; - - private boolean initialized; - protected GraphBuilderConfiguration graphBuilderConfig; - protected OptimisticOptimizations optimisticOpts; - protected RuntimeCompilationCandidatePredicate runtimeCompilationCandidatePredicate; - private boolean runtimeCompilationCandidatePredicateUpdated = false; - protected Predicate deoptimizeOnExceptionPredicate; - - private SubstrateUniverseFactory universeFactory = new SubstrateUniverseFactory(); - - public HostedProviders getHostedProviders() { - return hostedProviders; - } - - public GraalGraphObjectReplacer getObjectReplacer() { - return objectReplacer; - } - - protected static List> getRequiredFeaturesHelper() { - return List.of(RuntimeCompilationCanaryFeature.class, DeoptimizationFeature.class, GraalCompilerFeature.class); - } - - public void setUniverseFactory(SubstrateUniverseFactory universeFactory) { - this.universeFactory = universeFactory; - } - - protected final void duringSetupHelper(DuringSetupAccess c) { - if (SubstrateOptions.useLLVMBackend()) { - throw UserError.abort("Runtime compilation is currently unimplemented on the LLVM backend (GR-43073)."); - } - ImageSingletons.add(TruffleRuntimeCompilationSupport.class, new TruffleRuntimeCompilationSupport()); - if (!ImageSingletons.contains(SubstrateGraalCompilerSetup.class)) { - ImageSingletons.add(SubstrateGraalCompilerSetup.class, new SubstrateGraalCompilerSetup()); - } - - DuringSetupAccessImpl config = (DuringSetupAccessImpl) c; - AnalysisMetaAccess aMetaAccess = config.getMetaAccess(); - SubstrateWordTypes wordTypes = new SubstrateWordTypes(aMetaAccess, FrameAccess.getWordKind()); - SubstrateProviders substrateProviders = ImageSingletons.lookup(SubstrateGraalCompilerSetup.class).getSubstrateProviders(aMetaAccess, wordTypes); - objectReplacer = new GraalGraphObjectReplacer(config.getUniverse(), substrateProviders, universeFactory); - config.registerObjectReplacer(objectReplacer); - } - - private void installRuntimeConfig(BeforeAnalysisAccessImpl config) { - Function backendProvider = TruffleRuntimeCompilationSupport.getRuntimeBackendProvider(); - ClassInitializationSupport classInitializationSupport = config.getHostVM().getClassInitializationSupport(); - Providers originalProviders = GraalAccess.getOriginalProviders(); - SubstratePlatformConfigurationProvider platformConfig = new SubstratePlatformConfigurationProvider(ImageSingletons.lookup(BarrierSetProvider.class).createBarrierSet(config.getMetaAccess())); - RuntimeConfiguration runtimeConfig = ImageSingletons.lookup(SubstrateGraalCompilerSetup.class) - .createRuntimeConfigurationBuilder(RuntimeOptionValues.singleton(), config.getHostVM(), config.getUniverse(), config.getMetaAccess(), - backendProvider, classInitializationSupport, originalProviders.getLoopsDataProvider(), platformConfig, config.getBigBang().getSnippetReflectionProvider()) - .build(); - - Providers runtimeProviders = runtimeConfig.getProviders(); - hostedProviders = new HostedProviders(runtimeProviders.getMetaAccess(), runtimeProviders.getCodeCache(), runtimeProviders.getConstantReflection(), runtimeProviders.getConstantFieldProvider(), - runtimeProviders.getForeignCalls(), runtimeProviders.getLowerer(), runtimeProviders.getReplacements(), runtimeProviders.getStampProvider(), - runtimeConfig.getSnippetReflection(), runtimeProviders.getWordTypes(), runtimeProviders.getPlatformConfigurationProvider(), new GraphPrepareMetaAccessExtensionProvider(), - runtimeProviders.getLoopsDataProvider()); - - FeatureHandler featureHandler = config.getFeatureHandler(); - final boolean supportsStubBasedPlugins = !SubstrateOptions.useLLVMBackend(); - - NativeImageGenerator.registerGraphBuilderPlugins(featureHandler, runtimeConfig, hostedProviders, config.getMetaAccess(), config.getUniverse(), null, config.getNativeLibraries(), - config.getImageClassLoader(), ParsingReason.JITCompilation, ((Inflation) config.getBigBang()).getAnnotationSubstitutionProcessor(), - new SubstrateClassInitializationPlugin(config.getHostVM()), ConfigurationValues.getTarget(), supportsStubBasedPlugins); - - NativeImageGenerator.registerReplacements(DebugContext.forCurrentThread(), featureHandler, runtimeConfig, runtimeConfig.getProviders(), false, true, - new RuntimeCompilationGraphEncoder(ConfigurationValues.getTarget().arch, config.getUniverse().getHeapScanner())); - - featureHandler.forEachGraalFeature(feature -> feature.registerCodeObserver(runtimeConfig)); - Suites suites = NativeImageGenerator.createSuites(featureHandler, runtimeConfig, runtimeConfig.getSnippetReflection(), false); - LIRSuites lirSuites = NativeImageGenerator.createLIRSuites(featureHandler, runtimeConfig.getProviders(), false); - Suites firstTierSuites = NativeImageGenerator.createFirstTierSuites(featureHandler, runtimeConfig, runtimeConfig.getSnippetReflection(), false); - LIRSuites firstTierLirSuites = NativeImageGenerator.createFirstTierLIRSuites(featureHandler, runtimeConfig.getProviders(), false); - - TruffleRuntimeCompilationSupport.setRuntimeConfig(runtimeConfig, suites, lirSuites, firstTierSuites, firstTierLirSuites); - } - - /** - * A graph encoder that unwraps the {@link ImageHeapConstant} objects. This is used both after - * analysis and after compilation. The corresponding graph decoder used during AOT compilation, - * {@link RuntimeCompilationGraphDecoder}, looks-up the constant in the shadow heap and re-wraps - * it. - *

    - * The reason why we need to unwrap the {@link ImageHeapConstant}s after analysis, and not only - * when we finally encode the graphs for run time compilation, is because the values in - * {@link GraphEncoder#objectsArray} are captured in GraalSupport#graphObjects and - * SubstrateReplacements#snippetObjects which are then scanned. - */ - public static class RuntimeCompilationGraphEncoder extends GraphEncoder { - - private final ImageHeapScanner heapScanner; - /** - * Cache already converted location identity objects to avoid creating multiple new - * instances for the same underlying location identity. - */ - private final Map locationIdentityCache; - - public RuntimeCompilationGraphEncoder(Architecture architecture, ImageHeapScanner heapScanner) { - super(architecture); - this.heapScanner = heapScanner; - this.locationIdentityCache = new ConcurrentHashMap<>(); - } - - @Override - protected void addObject(Object object) { - super.addObject(unwrap(object)); - } - - @Override - protected void writeObjectId(Object object) { - super.writeObjectId(unwrap(object)); - } - - @Override - protected GraphDecoder graphDecoderForVerification(StructuredGraph decodedGraph) { - return new RuntimeCompilationGraphDecoder(architecture, decodedGraph, heapScanner); - } - - private Object unwrap(Object object) { - if (object instanceof ImageHeapConstant ihc) { - VMError.guarantee(ihc.getHostedObject() != null); - return ihc.getHostedObject(); - } else if (object instanceof ObjectLocationIdentity oli && oli.getObject() instanceof ImageHeapConstant heapConstant) { - return locationIdentityCache.computeIfAbsent(heapConstant, (hc) -> ObjectLocationIdentity.create(hc.getHostedObject())); - } - return object; - } - } - - static class RuntimeCompilationGraphDecoder extends GraphDecoder { - - private final ImageHeapScanner heapScanner; - /** - * Cache already converted location identity objects to avoid creating multiple new - * instances for the same underlying location identity. - */ - private final Map locationIdentityCache; - - RuntimeCompilationGraphDecoder(Architecture architecture, StructuredGraph graph, ImageHeapScanner heapScanner) { - super(architecture, graph); - this.heapScanner = heapScanner; - this.locationIdentityCache = new ConcurrentHashMap<>(); - } - - @Override - protected Object readObject(MethodScope methodScope) { - Object object = super.readObject(methodScope); - if (object instanceof JavaConstant constant) { - return heapScanner.getImageHeapConstant(constant); - } else if (object instanceof ObjectLocationIdentity oli) { - return locationIdentityCache.computeIfAbsent(oli.getObject(), (obj) -> ObjectLocationIdentity.create(heapScanner.getImageHeapConstant(obj))); - } - return object; - } - } - - protected final void beforeAnalysisHelper(BeforeAnalysisAccess c) { - - BeforeAnalysisAccessImpl config = (BeforeAnalysisAccessImpl) c; - installRuntimeConfig(config); - - SubstrateGraalRuntime graalRuntime = new SubstrateGraalRuntime(); - objectReplacer.setGraalRuntime(graalRuntime); - objectReplacer.setAnalysisAccess(config); - ImageSingletons.add(GraalRuntime.class, graalRuntime); - RuntimeSupport.getRuntimeSupport().addShutdownHook(new GraalSupport.GraalShutdownHook()); - - /* Initialize configuration with reasonable default values. */ - graphBuilderConfig = GraphBuilderConfiguration.getDefault(hostedProviders.getGraphBuilderPlugins()).withBytecodeExceptionMode(BytecodeExceptionMode.ExplicitOnly); - runtimeCompilationCandidatePredicate = RuntimeCompilationFeature::defaultAllowRuntimeCompilation; - optimisticOpts = OptimisticOptimizations.ALL.remove(OptimisticOptimizations.Optimization.UseLoopLimitChecks); - graphEncoder = new RuntimeCompilationGraphEncoder(ConfigurationValues.getTarget().arch, config.getUniverse().getHeapScanner()); - - /* - * Ensure all snippet types are registered as used. - */ - SubstrateReplacements replacements = (SubstrateReplacements) TruffleRuntimeCompilationSupport.getRuntimeConfig().getProviders().getReplacements(); - for (NodeClass nodeClass : replacements.getSnippetNodeClasses()) { - config.getMetaAccess().lookupJavaType(nodeClass.getClazz()).registerAsAllocated("All " + NodeClass.class.getName() + " classes are marked as instantiated eagerly."); - } - /* - * Ensure runtime snippet graphs are analyzed. - */ - NativeImageGenerator.performSnippetGraphAnalysis(config.getBigBang(), replacements, config.getBigBang().getOptions()); - - /* - * Ensure that all snippet methods have their SubstrateMethod object created by the object - * replacer, to avoid corner cases later when writing the native image. - */ - for (ResolvedJavaMethod method : replacements.getSnippetMethods()) { - objectReplacer.apply(method); - } - } - - @SuppressWarnings("unused") - private static boolean defaultAllowRuntimeCompilation(ResolvedJavaMethod method) { - return false; - } - - public void initializeRuntimeCompilationForTesting(FeatureImpl.BeforeAnalysisAccessImpl config, RuntimeCompilationCandidatePredicate newRuntimeCompilationCandidatePredicate) { - initializeRuntimeCompilationConfiguration(hostedProviders, graphBuilderConfig, newRuntimeCompilationCandidatePredicate, deoptimizeOnExceptionPredicate); - initializeRuntimeCompilationForTesting(config); - } - - public void initializeRuntimeCompilationForTesting(BeforeAnalysisAccessImpl config) { - initializeAnalysisProviders(config.getBigBang(), provider -> provider); - } - - public void initializeRuntimeCompilationConfiguration(HostedProviders newHostedProviders, GraphBuilderConfiguration newGraphBuilderConfig, - RuntimeCompilationCandidatePredicate newRuntimeCompilationCandidatePredicate, - Predicate newDeoptimizeOnExceptionPredicate) { - guarantee(initialized == false, "runtime compilation configuration already initialized"); - initialized = true; - - hostedProviders = newHostedProviders; - graphBuilderConfig = newGraphBuilderConfig.withNodeSourcePosition(true); - assert !runtimeCompilationCandidatePredicateUpdated : "Updated compilation predicate multiple times"; - runtimeCompilationCandidatePredicate = newRuntimeCompilationCandidatePredicate; - runtimeCompilationCandidatePredicateUpdated = true; - deoptimizeOnExceptionPredicate = newDeoptimizeOnExceptionPredicate; - } - - public SubstrateMethod requireFrameInformationForMethod(ResolvedJavaMethod method, BeforeAnalysisAccessImpl config, boolean registerAsRoot) { - AnalysisMethod aMethod = (AnalysisMethod) method; - SubstrateMethod sMethod = objectReplacer.createMethod(aMethod); - - requireFrameInformationForMethodHelper(aMethod, config, registerAsRoot); - - return sMethod; - } - - protected abstract void requireFrameInformationForMethodHelper(AnalysisMethod aMethod, BeforeAnalysisAccessImpl config, boolean registerAsRoot); - - public SubstrateMethod prepareMethodForRuntimeCompilation(Executable method, BeforeAnalysisAccessImpl config) { - return prepareMethodForRuntimeCompilation(config.getMetaAccess().lookupJavaMethod(method), config); - } - - public abstract void initializeAnalysisProviders(BigBang bb, Function generator); - - public abstract void registerAllowInliningPredicate(AllowInliningPredicate predicate); - - public abstract SubstrateMethod prepareMethodForRuntimeCompilation(ResolvedJavaMethod method, BeforeAnalysisAccessImpl config); - - protected final void afterAnalysisHelper() { - ProgressReporter.singleton().setNumRuntimeCompiledMethods(getRuntimeCompiledMethods().size()); - } - - /** - * Checks if any illegal nodes are present within the graph. Runtime Compiled methods should - * never have explicit BytecodeExceptions; instead they should have deoptimizations. - */ - protected static boolean verifyNodes(StructuredGraph graph) { - for (var node : graph.getNodes()) { - boolean invalidNodeKind = node instanceof BytecodeExceptionNode || node instanceof ThrowBytecodeExceptionNode; - assert !invalidNodeKind : "illegal node in graph: " + node + " method: " + graph.method(); - } - return true; - } - - protected final void beforeCompilationHelper() { - if (Options.PrintRuntimeCompileMethods.getValue()) { - System.out.println("****Start Print Runtime Compile Methods***"); - getRuntimeCompiledMethods().stream().map(m -> m.getMethod().format("%H.%n(%p)")).sorted().collect(Collectors.toList()).forEach(System.out::println); - System.out.println("****End Print Runtime Compile Methods***"); - } - - if (Options.PrintRuntimeCompilationCallTree.getValue()) { - System.out.println("****Start Print Runtime Compile Call Tree***"); - printCallTree(); - System.out.println("****End Print Runtime Compile Call Tree***"); - } - - int maxMethods = 0; - for (String value : Options.MaxRuntimeCompileMethods.getValue().values()) { - String numberStr = null; - try { - /* Strip optional comment string from MaxRuntimeCompileMethods value */ - numberStr = value.split("#")[0]; - maxMethods += Integer.parseInt(numberStr); - } catch (NumberFormatException ex) { - throw UserError.abort("Invalid value for option 'MaxRuntimeCompileMethods': '%s' is not a valid number", numberStr); - } - } - if (Options.EnforceMaxRuntimeCompileMethods.getValue() && maxMethods != 0 && getRuntimeCompiledMethods().size() > maxMethods) { - printDeepestLevelPath(); - throw VMError.shouldNotReachHere("Number of methods for runtime compilation exceeds the allowed limit: " + getRuntimeCompiledMethods().size() + " > " + maxMethods); - } - } - - private void printDeepestLevelPath() { - AbstractCallTreeNode maxLevelCallTreeNode = null; - for (var method : getRuntimeCompiledMethods()) { - var callTreeNode = getCallTreeNode(method); - if (maxLevelCallTreeNode == null || maxLevelCallTreeNode.getLevel() < callTreeNode.getLevel()) { - maxLevelCallTreeNode = callTreeNode; - } - } - - System.out.println(String.format("Deepest level call tree path (%d calls):", maxLevelCallTreeNode.getLevel())); - AbstractCallTreeNode node = maxLevelCallTreeNode; - while (node != null) { - AnalysisMethod implementationMethod = node.getImplementationMethod(); - AnalysisMethod targetMethod = node.getTargetMethod(); - - System.out.format("%5d ; %s ; %s", node.getNodeCount(), node.getPosition(), implementationMethod == null ? "" - : implementationMethod.format("%H.%n(%p)")); - if (targetMethod != null && !targetMethod.equals(implementationMethod)) { - System.out.print(" ; " + targetMethod.format("%H.%n(%p)")); - } - System.out.println(); - node = node.getParent(); - } - } - - private void printCallTree() { - System.out.println("depth;method;Graal nodes;invoked from source;full method name;full name of invoked virtual method"); - for (var method : getRuntimeCompiledMethods()) { - var node = getCallTreeNode(method); - if (node.getLevel() == 0) { - printCallTreeNode(node); - } - } - } - - private void printCallTreeNode(AbstractCallTreeNode node) { - AnalysisMethod implementationMethod = node.getImplementationMethod(); - AnalysisMethod targetMethod = node.getTargetMethod(); - - StringBuilder indent = new StringBuilder(); - for (int i = 0; i < node.getLevel(); i++) { - indent.append(" "); - } - if (implementationMethod != null) { - indent.append(implementationMethod.format("%h.%n")); - } - - System.out.format("%4d ; %-80s ;%5d ; %s ; %s", node.getLevel(), indent, node.getNodeCount(), node.getPosition(), - implementationMethod == null ? "" : implementationMethod.format("%H.%n(%p)")); - if (targetMethod != null && !targetMethod.equals(implementationMethod)) { - System.out.print(" ; " + targetMethod.format("%H.%n(%p)")); - } - System.out.println(); - - for (AbstractCallTreeNode child : node.getChildren()) { - printCallTreeNode(child); - } - } - - protected final void afterCompilationHelper(AfterCompilationAccess a) { - CompilationAccessImpl config = (CompilationAccessImpl) a; - - HostedMetaAccess hMetaAccess = config.getMetaAccess(); - HostedUniverse hUniverse = hMetaAccess.getUniverse(); - objectReplacer.updateSubstrateDataAfterCompilation(hUniverse, config.getProviders()); - } - - protected final void beforeHeapLayoutHelper(BeforeHeapLayoutAccess a) { - objectReplacer.registerImmutableObjects(a); - TruffleRuntimeCompilationSupport.registerImmutableObjects(a); - ((SubstrateReplacements) TruffleRuntimeCompilationSupport.getRuntimeConfig().getProviders().getReplacements()).registerImmutableObjects(a); - } - - protected final void afterHeapLayoutHelper(AfterHeapLayoutAccess a) { - AfterHeapLayoutAccessImpl config = (AfterHeapLayoutAccessImpl) a; - HostedMetaAccess hMetaAccess = config.getMetaAccess(); - HostedUniverse hUniverse = hMetaAccess.getUniverse(); - objectReplacer.updateSubstrateDataAfterHeapLayout(hUniverse); - } -} - -/** - * Same behavior as {@link SubstrateMetaAccessExtensionProvider}, but operating on - * {@link AnalysisType} instead of {@link SharedType} since parsing of graphs for runtime - * compilation happens in the Analysis universe. - */ -class GraphPrepareMetaAccessExtensionProvider implements MetaAccessExtensionProvider { - - @Override - public JavaKind getStorageKind(JavaType type) { - return ((AnalysisType) type).getStorageKind(); - } - - @Override - public boolean canConstantFoldDynamicAllocation(ResolvedJavaType type) { - assert type instanceof AnalysisType : "AnalysisType is required; AnalysisType lazily creates array types of any depth, so type cannot be null"; - return ((AnalysisType) type).isInstantiated(); - } - - @Override - public boolean isGuaranteedSafepoint(ResolvedJavaMethod method, boolean isDirect) { - throw VMError.shouldNotReachHereAtRuntime(); // ExcludeFromJacocoGeneratedReport - } - - @Override - public boolean canVirtualize(ResolvedJavaType instanceType) { - return true; - } -} diff --git a/substratevm/src/com.oracle.svm.graal/src/com/oracle/svm/graal/hosted/runtimecompilation/CallTreeInfo.java b/substratevm/src/com.oracle.svm.graal/src/com/oracle/svm/graal/hosted/runtimecompilation/CallTreeInfo.java new file mode 100644 index 000000000000..0ed531bea9bb --- /dev/null +++ b/substratevm/src/com.oracle.svm.graal/src/com/oracle/svm/graal/hosted/runtimecompilation/CallTreeInfo.java @@ -0,0 +1,337 @@ +/* + * Copyright (c) 2023, 2023, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.svm.graal.hosted.runtimecompilation; + +import static com.oracle.svm.common.meta.MultiMethod.ORIGINAL_METHOD; +import static com.oracle.svm.hosted.code.SubstrateCompilationDirectives.RUNTIME_COMPILED_METHOD; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.Comparator; +import java.util.HashMap; +import java.util.HashSet; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; +import java.util.Optional; +import java.util.Queue; +import java.util.Set; +import java.util.stream.Collectors; + +import com.oracle.graal.pointsto.meta.AnalysisMethod; +import com.oracle.graal.pointsto.meta.AnalysisUniverse; +import com.oracle.graal.pointsto.meta.InvokeInfo; +import com.oracle.svm.core.util.VMError; +import com.oracle.svm.hosted.code.SubstrateCompilationDirectives; + +import jdk.vm.ci.code.BytecodeFrame; +import jdk.vm.ci.code.BytecodePosition; + +public final class CallTreeInfo { + private final Map runtimeCompilations; + private Map runtimeCandidateMap; + private Map analysisMethodMap; + private boolean callTreeInitialized = false; + private boolean callTraceInitialized = false; + + private CallTreeInfo(Map runtimeCompilations) { + this.runtimeCompilations = runtimeCompilations; + } + + public Collection runtimeCompilations() { + return runtimeCompilations.values(); + } + + public static CallTreeInfo create(AnalysisUniverse aUniverse, Map invalidForRuntimeCompilation) { + Map runtimeCompilations = new HashMap<>(); + for (var method : aUniverse.getMethods()) { + var rMethod = method.getMultiMethod(RUNTIME_COMPILED_METHOD); + if (rMethod != null && rMethod.isReachable() && !invalidForRuntimeCompilation.containsKey(rMethod)) { + var origInlinedMethods = rMethod.getAnalyzedGraph().getInlinedMethods().stream().map(inlinedMethod -> { + AnalysisMethod orig = ((AnalysisMethod) inlinedMethod).getMultiMethod(ORIGINAL_METHOD); + assert orig != null; + return orig; + }).collect(Collectors.toUnmodifiableSet()); + var previous = runtimeCompilations.put(rMethod, new RuntimeCompiledMethod(rMethod, origInlinedMethods)); + assert previous == null : previous; + } + } + + return new CallTreeInfo(runtimeCompilations); + } + + private void initializeCallTraceInfo() { + if (callTraceInitialized) { + return; + } + + callTraceInitialized = true; + analysisMethodMap = new HashMap<>(); + runtimeCandidateMap = new HashMap<>(); + + for (var runtimeCompilation : runtimeCompilations()) { + AnalysisMethod method = runtimeCompilation.runtimeMethod; + MethodNode callerMethodNode = analysisMethodMap.computeIfAbsent(method, MethodNode::new); + + for (InvokeInfo invokeInfo : method.getInvokes()) { + AnalysisMethod invokeTarget = invokeInfo.getTargetMethod(); + boolean deoptInvokeTypeFlow = invokeInfo.isDeoptInvokeTypeFlow(); + if (deoptInvokeTypeFlow) { + assert SubstrateCompilationDirectives.isRuntimeCompiledMethod(invokeTarget); + invokeTarget = invokeTarget.getMultiMethod(ORIGINAL_METHOD); + } + assert invokeTarget.isOriginalMethod(); + for (AnalysisMethod callee : invokeInfo.getAllCallees()) { + /* + * Special handling is needed for deoptInvokeTypeFlows because they only have + * the deopt method variant as a callee. + */ + if (deoptInvokeTypeFlow || SubstrateCompilationDirectives.isRuntimeCompiledMethod(callee)) { + MethodNode calleeMethodNode = analysisMethodMap.computeIfAbsent(callee, MethodNode::new); + InvokeNode invoke = new InvokeNode(callerMethodNode, invokeInfo.getPosition()); + calleeMethodNode.addCaller(invoke); + + var origCallee = callee.getMultiMethod(ORIGINAL_METHOD); + assert origCallee != null; + runtimeCandidateMap.putIfAbsent(new RuntimeCompilationCandidate(origCallee, invokeTarget), invoke); + } else if (callee.isOriginalMethod() && callee.getMultiMethod(RUNTIME_COMPILED_METHOD) == null) { + /* + * Recording that this call was reachable, but not converted to a runtime + * compiled method. + */ + runtimeCandidateMap.computeIfAbsent(new RuntimeCompilationCandidate(callee, invokeTarget), + (candidate) -> { + return new InvokeNode(callerMethodNode, invokeInfo.getPosition()); + }); + } + } + } + } + } + + public void initializeCallTreeInfo(Set registeredRoots) { + if (callTreeInitialized) { + return; + } + + initializeCallTraceInfo(); + callTreeInitialized = true; + + // ensure invokeInfo calculated + + Queue worklist = new LinkedList<>(); + /* + * First initialize all nodes with no callers. + */ + for (var methodNode : analysisMethodMap.values()) { + if (methodNode.getCallers().isEmpty() || registeredRoots.contains(methodNode.method.getMultiMethod(ORIGINAL_METHOD))) { + worklist.add(methodNode); + methodNode.trace = new TraceInfo(0, new BytecodePosition(null, methodNode.method, BytecodeFrame.UNKNOWN_BCI), null); + } + } + + /* Walk through to find a reachable path for all nodes */ + while (!worklist.isEmpty()) { + MethodNode callerMethodNode = worklist.remove(); + TraceInfo callerTrace = callerMethodNode.trace; + VMError.guarantee(callerTrace != null); + + for (InvokeInfo invokeInfo : callerMethodNode.method.getInvokes()) { + boolean deoptInvokeTypeFlow = invokeInfo.isDeoptInvokeTypeFlow(); + if (deoptInvokeTypeFlow) { + // we do not need to trace deoptInvokes + continue; + } + InvokeNode callerInvokeNode = null; + for (AnalysisMethod callee : invokeInfo.getAllCallees()) { + if (SubstrateCompilationDirectives.isRuntimeCompiledMethod(callee)) { + MethodNode calleeMethodNode = analysisMethodMap.get(callee); + if (calleeMethodNode.trace == null) { + /* + * If this was the first time this node was reached, then add to + * worklist. + */ + if (callerInvokeNode == null) { + callerInvokeNode = new InvokeNode(callerMethodNode, invokeInfo.getPosition()); + } + worklist.add(calleeMethodNode); + calleeMethodNode.trace = new TraceInfo(callerTrace.level + 1, invokeInfo.getPosition(), callerInvokeNode); + callerTrace.addTraceTarget(calleeMethodNode); + } + } + } + } + } + } + + private static final String[] UNKNOWN_TRACE = new String[]{"Unknown"}; + private static final String[] EMPTY_STRING = new String[0]; + + public static String[] getCallTrace(CallTreeInfo callTreeInfo, AnalysisMethod method) { + callTreeInfo.initializeCallTraceInfo(); + MethodNode methodNode = callTreeInfo.analysisMethodMap.get(method); + if (methodNode == null) { + return UNKNOWN_TRACE; + } + + ArrayList trace = new ArrayList<>(); + findCallTraceHelper(trace, methodNode); + return trace.toArray(EMPTY_STRING); + } + + public static String[] getCallTrace(CallTreeInfo callTreeInfo, RuntimeCompilationCandidate candidate) { + callTreeInfo.initializeCallTraceInfo(); + InvokeNode invokeNode = callTreeInfo.runtimeCandidateMap.get(candidate); + if (invokeNode == null) { + return UNKNOWN_TRACE; + } + + ArrayList trace = new ArrayList<>(); + findCallTraceHelper(trace, invokeNode.method); + return trace.toArray(EMPTY_STRING); + } + + private static void findCallTraceHelper(ArrayList trace, MethodNode first) { + Set covered = new HashSet<>(); + MethodNode current = first; + covered.add(current); + + while (current != null) { + // find parent + MethodNode parent = null; + for (InvokeNode caller : current.getCallers()) { + if (covered.add(caller.method)) { + parent = caller.method; + trace.add(caller.position.toString()); + break; + } + } + current = parent; + } + } + + public static void printCallTree(CallTreeInfo info, Set registeredRuntimeCompilations) { + info.initializeCallTreeInfo(registeredRuntimeCompilations); + + System.out.println("depth;method;invoke position"); + for (MethodNode methodNode : info.analysisMethodMap.values()) { + if (methodNode.trace != null && methodNode.trace.level == 0) { + printCallTreeNode(methodNode); + } + } + } + + private static void printCallTreeNode(MethodNode node) { + TraceInfo trace = node.trace; + StringBuilder indent = new StringBuilder(); + indent.append(" ".repeat(Math.max(0, trace.level))); + indent.append(node.method.format("%H.%n")); + System.out.format("%4d ; %-80s ; %s%n", trace.level, indent, trace.position); + for (MethodNode child : trace.getTraceTargets()) { + printCallTreeNode(child); + } + } + + public static void printDeepestPath(CallTreeInfo info, Set registeredRuntimeCompilations) { + info.initializeCallTreeInfo(registeredRuntimeCompilations); + + Optional deepestNode = info.analysisMethodMap.values().stream().max(Comparator.comparingInt(t -> t.trace == null ? -1 : t.trace.level)); + + if (deepestNode.isEmpty() || deepestNode.get().trace == null) { + System.out.println("Could not find a trace"); + return; + } + + MethodNode node = deepestNode.get(); + System.out.printf("Deepest level call tree path (%s calls):%n", node.trace.level); + System.out.println("depth;method;invoke position"); + do { + TraceInfo trace = node.trace; + StringBuilder indent = new StringBuilder(); + indent.append(" ".repeat(Math.max(0, trace.level))); + indent.append(node.method.format("%H.%n")); + System.out.format("%4d ; %-80s ; %s%n", trace.level, indent, trace.position); + InvokeNode call = trace.invokeParent; + node = call == null ? null : call.method; + } while (node != null); + } +} + +class MethodNode { + public AnalysisMethod method; + public List callers; + public TraceInfo trace; + + MethodNode(AnalysisMethod method) { + this.method = method; + this.callers = null; + + } + + List getCallers() { + return callers == null ? List.of() : callers; + } + + void addCaller(InvokeNode invoke) { + if (callers == null) { + callers = new ArrayList<>(); + } + callers.add(invoke); + } +} + +class InvokeNode { + final MethodNode method; + final BytecodePosition position; + + InvokeNode(MethodNode method, BytecodePosition position) { + this.method = method; + this.position = position; + } +} + +class TraceInfo { + final int level; + final BytecodePosition position; + final InvokeNode invokeParent; + List traceTargets; + + TraceInfo(int level, BytecodePosition position, InvokeNode invokeParent) { + this.level = level; + this.position = position; + this.invokeParent = invokeParent; + } + + List getTraceTargets() { + return traceTargets == null ? List.of() : traceTargets; + } + + void addTraceTarget(MethodNode node) { + if (traceTargets == null) { + traceTargets = new ArrayList<>(); + } + traceTargets.add(node); + } +} diff --git a/substratevm/src/com.oracle.svm.graal/src/com/oracle/svm/graal/hosted/GraalGraphObjectReplacer.java b/substratevm/src/com.oracle.svm.graal/src/com/oracle/svm/graal/hosted/runtimecompilation/GraalGraphObjectReplacer.java similarity index 99% rename from substratevm/src/com.oracle.svm.graal/src/com/oracle/svm/graal/hosted/GraalGraphObjectReplacer.java rename to substratevm/src/com.oracle.svm.graal/src/com/oracle/svm/graal/hosted/runtimecompilation/GraalGraphObjectReplacer.java index cc3ed6852370..de2e922f1857 100644 --- a/substratevm/src/com.oracle.svm.graal/src/com/oracle/svm/graal/hosted/GraalGraphObjectReplacer.java +++ b/substratevm/src/com.oracle.svm.graal/src/com/oracle/svm/graal/hosted/runtimecompilation/GraalGraphObjectReplacer.java @@ -22,7 +22,7 @@ * or visit www.oracle.com if you need additional information or have any * questions. */ -package com.oracle.svm.graal.hosted; +package com.oracle.svm.graal.hosted.runtimecompilation; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; diff --git a/substratevm/src/com.oracle.svm.graal/src/com/oracle/svm/graal/hosted/runtimecompilation/RuntimeCompilationCandidate.java b/substratevm/src/com.oracle.svm.graal/src/com/oracle/svm/graal/hosted/runtimecompilation/RuntimeCompilationCandidate.java new file mode 100644 index 000000000000..361cd8532c46 --- /dev/null +++ b/substratevm/src/com.oracle.svm.graal/src/com/oracle/svm/graal/hosted/runtimecompilation/RuntimeCompilationCandidate.java @@ -0,0 +1,63 @@ +/* + * Copyright (c) 2023, 2023, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.svm.graal.hosted.runtimecompilation; + +import java.util.Objects; + +import com.oracle.graal.pointsto.meta.AnalysisMethod; + +public final class RuntimeCompilationCandidate { + AnalysisMethod implementationMethod; + AnalysisMethod targetMethod; + + RuntimeCompilationCandidate(AnalysisMethod implementationMethod, AnalysisMethod targetMethod) { + this.implementationMethod = implementationMethod; + this.targetMethod = targetMethod; + } + + public AnalysisMethod getImplementationMethod() { + return implementationMethod; + } + + public AnalysisMethod getTargetMethod() { + return targetMethod; + } + + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + RuntimeCompilationCandidate that = (RuntimeCompilationCandidate) o; + return implementationMethod.equals(that.implementationMethod) && targetMethod.equals(that.targetMethod); + } + + @Override + public int hashCode() { + return Objects.hash(implementationMethod, targetMethod); + } +} diff --git a/substratevm/src/com.oracle.svm.graal/src/com/oracle/svm/graal/hosted/ParseOnceRuntimeCompilationFeature.java b/substratevm/src/com.oracle.svm.graal/src/com/oracle/svm/graal/hosted/runtimecompilation/RuntimeCompilationFeature.java similarity index 52% rename from substratevm/src/com.oracle.svm.graal/src/com/oracle/svm/graal/hosted/ParseOnceRuntimeCompilationFeature.java rename to substratevm/src/com.oracle.svm.graal/src/com/oracle/svm/graal/hosted/runtimecompilation/RuntimeCompilationFeature.java index a77c64d41a88..2ed14e40d39d 100644 --- a/substratevm/src/com.oracle.svm.graal/src/com/oracle/svm/graal/hosted/ParseOnceRuntimeCompilationFeature.java +++ b/substratevm/src/com.oracle.svm.graal/src/com/oracle/svm/graal/hosted/runtimecompilation/RuntimeCompilationFeature.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 2022, 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,31 +22,29 @@ * or visit www.oracle.com if you need additional information or have any * questions. */ -package com.oracle.svm.graal.hosted; +package com.oracle.svm.graal.hosted.runtimecompilation; import static com.oracle.svm.common.meta.MultiMethod.DEOPT_TARGET_METHOD; import static com.oracle.svm.common.meta.MultiMethod.ORIGINAL_METHOD; +import static com.oracle.svm.core.util.VMError.guarantee; import static com.oracle.svm.hosted.code.SubstrateCompilationDirectives.RUNTIME_COMPILED_METHOD; import static com.oracle.svm.hosted.phases.InlineBeforeAnalysisPolicyUtils.Options.InlineBeforeAnalysisAllowedDepth; import static jdk.graal.compiler.java.BytecodeParserOptions.InlineDuringParsingMaxDepth; -import java.util.ArrayList; +import java.lang.reflect.Executable; +import java.util.Arrays; import java.util.Collection; -import java.util.HashMap; -import java.util.HashSet; -import java.util.LinkedList; import java.util.List; import java.util.Map; -import java.util.Objects; -import java.util.Queue; import java.util.Set; import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.atomic.AtomicLong; +import java.util.function.BooleanSupplier; +import java.util.function.Consumer; import java.util.function.Function; +import java.util.function.Predicate; import java.util.function.Supplier; -import java.util.stream.Collectors; +import java.util.stream.Stream; -import org.graalvm.collections.EconomicMap; import org.graalvm.nativeimage.ImageSingletons; import org.graalvm.nativeimage.hosted.Feature; @@ -55,330 +53,395 @@ import com.oracle.graal.pointsto.api.HostVM; import com.oracle.graal.pointsto.flow.InvokeTypeFlow; import com.oracle.graal.pointsto.flow.MethodFlowsGraph; -import com.oracle.graal.pointsto.heap.ImageHeapScanner; import com.oracle.graal.pointsto.infrastructure.GraphProvider; -import com.oracle.graal.pointsto.meta.AnalysisField; import com.oracle.graal.pointsto.meta.AnalysisMetaAccess; import com.oracle.graal.pointsto.meta.AnalysisMethod; import com.oracle.graal.pointsto.meta.AnalysisType; +import com.oracle.graal.pointsto.meta.AnalysisUniverse; import com.oracle.graal.pointsto.meta.HostedProviders; -import com.oracle.graal.pointsto.meta.InvokeInfo; import com.oracle.graal.pointsto.meta.PointsToAnalysisMethod; import com.oracle.graal.pointsto.phases.InlineBeforeAnalysisPolicy; -import com.oracle.graal.pointsto.util.CompletionExecutor; +import com.oracle.graal.pointsto.util.AnalysisError; +import com.oracle.graal.pointsto.util.GraalAccess; +import com.oracle.graal.pointsto.util.ParallelExecutionException; import com.oracle.svm.common.meta.MultiMethod; +import com.oracle.svm.core.FrameAccess; import com.oracle.svm.core.ParsingReason; +import com.oracle.svm.core.SubstrateOptions; import com.oracle.svm.core.config.ConfigurationValues; -import com.oracle.svm.core.graal.nodes.DeoptEntryNode; -import com.oracle.svm.core.graal.nodes.DeoptEntrySupport; -import com.oracle.svm.core.graal.nodes.DeoptProxyAnchorNode; +import com.oracle.svm.core.graal.RuntimeCompilationCanaryFeature; +import com.oracle.svm.core.graal.code.SubstrateBackend; +import com.oracle.svm.core.graal.code.SubstrateMetaAccessExtensionProvider; +import com.oracle.svm.core.graal.code.SubstratePlatformConfigurationProvider; +import com.oracle.svm.core.graal.meta.RuntimeConfiguration; +import com.oracle.svm.core.graal.meta.SubstrateReplacements; import com.oracle.svm.core.graal.nodes.InlinedInvokeArgumentsNode; +import com.oracle.svm.core.graal.word.SubstrateWordTypes; +import com.oracle.svm.core.heap.BarrierSetProvider; +import com.oracle.svm.core.jdk.RuntimeSupport; +import com.oracle.svm.core.meta.SharedType; import com.oracle.svm.core.option.HostedOptionKey; import com.oracle.svm.core.option.HostedOptionValues; +import com.oracle.svm.core.option.LocatableMultiOptionValue; +import com.oracle.svm.core.option.RuntimeOptionValues; +import com.oracle.svm.core.util.UserError; import com.oracle.svm.core.util.VMError; +import com.oracle.svm.graal.GraalSupport; +import com.oracle.svm.graal.SubstrateGraalRuntime; import com.oracle.svm.graal.TruffleRuntimeCompilationSupport; +import com.oracle.svm.graal.hosted.DeoptimizationFeature; +import com.oracle.svm.graal.hosted.FieldsOffsetsFeature; +import com.oracle.svm.graal.hosted.GraalCompilerFeature; +import com.oracle.svm.graal.meta.SubstrateField; import com.oracle.svm.graal.meta.SubstrateMethod; +import com.oracle.svm.graal.meta.SubstrateType; +import com.oracle.svm.graal.meta.SubstrateUniverseFactory; +import com.oracle.svm.hosted.FeatureHandler; import com.oracle.svm.hosted.FeatureImpl; -import com.oracle.svm.hosted.HeapBreakdownProvider; -import com.oracle.svm.hosted.RuntimeCompilationSupport; +import com.oracle.svm.hosted.FeatureImpl.AfterHeapLayoutAccessImpl; +import com.oracle.svm.hosted.FeatureImpl.BeforeAnalysisAccessImpl; +import com.oracle.svm.hosted.FeatureImpl.CompilationAccessImpl; +import com.oracle.svm.hosted.FeatureImpl.DuringSetupAccessImpl; +import com.oracle.svm.hosted.NativeImageGenerator; +import com.oracle.svm.hosted.ProgressReporter; +import com.oracle.svm.hosted.RuntimeCompilationCallbacks; import com.oracle.svm.hosted.SVMHost; -import com.oracle.svm.hosted.ameta.AnalysisConstantFieldProvider; -import com.oracle.svm.hosted.ameta.AnalysisConstantReflectionProvider; +import com.oracle.svm.hosted.analysis.Inflation; import com.oracle.svm.hosted.analysis.SVMParsingSupport; import com.oracle.svm.hosted.classinitialization.ClassInitializationSupport; import com.oracle.svm.hosted.code.CompileQueue; import com.oracle.svm.hosted.code.DeoptimizationUtils; import com.oracle.svm.hosted.code.SubstrateCompilationDirectives; -import com.oracle.svm.hosted.meta.HostedConstantFieldProvider; -import com.oracle.svm.hosted.meta.HostedField; +import com.oracle.svm.hosted.meta.HostedMetaAccess; import com.oracle.svm.hosted.meta.HostedMethod; import com.oracle.svm.hosted.meta.HostedUniverse; -import com.oracle.svm.hosted.nodes.DeoptProxyNode; -import com.oracle.svm.hosted.phases.AnalysisGraphBuilderPhase; import com.oracle.svm.hosted.phases.ConstantFoldLoadFieldPlugin; import com.oracle.svm.hosted.phases.InlineBeforeAnalysisPolicyUtils; -import com.oracle.svm.hosted.phases.InlineBeforeAnalysisPolicyUtils.AccumulativeInlineScope; -import com.oracle.svm.hosted.phases.InlineBeforeAnalysisPolicyUtils.AlwaysInlineScope; +import com.oracle.svm.hosted.phases.SubstrateClassInitializationPlugin; +import jdk.graal.compiler.api.runtime.GraalRuntime; import jdk.graal.compiler.core.common.PermanentBailoutException; import jdk.graal.compiler.core.common.spi.ConstantFieldProvider; +import jdk.graal.compiler.core.common.spi.MetaAccessExtensionProvider; import jdk.graal.compiler.debug.DebugContext; -import jdk.graal.compiler.debug.DebugHandlersFactory; import jdk.graal.compiler.debug.Indent; import jdk.graal.compiler.graph.NodeClass; import jdk.graal.compiler.graph.NodeSourcePosition; -import jdk.graal.compiler.java.BytecodeParser; -import jdk.graal.compiler.java.GraphBuilderPhase; +import jdk.graal.compiler.lir.phases.LIRSuites; import jdk.graal.compiler.loop.phases.ConvertDeoptimizeToGuardPhase; -import jdk.graal.compiler.nodes.CallTargetNode; import jdk.graal.compiler.nodes.FixedWithNextNode; -import jdk.graal.compiler.nodes.FrameState; -import jdk.graal.compiler.nodes.StateSplit; +import jdk.graal.compiler.nodes.GraphEncoder; import jdk.graal.compiler.nodes.StructuredGraph; import jdk.graal.compiler.nodes.ValueNode; import jdk.graal.compiler.nodes.graphbuilderconf.GraphBuilderConfiguration; +import jdk.graal.compiler.nodes.graphbuilderconf.GraphBuilderConfiguration.BytecodeExceptionMode; import jdk.graal.compiler.nodes.graphbuilderconf.GraphBuilderContext; import jdk.graal.compiler.nodes.graphbuilderconf.InlineInvokePlugin; -import jdk.graal.compiler.nodes.graphbuilderconf.IntrinsicContext; import jdk.graal.compiler.nodes.graphbuilderconf.NodePlugin; -import jdk.graal.compiler.nodes.java.ExceptionObjectNode; import jdk.graal.compiler.options.Option; -import jdk.graal.compiler.options.OptionValues; +import jdk.graal.compiler.options.OptionStability; import jdk.graal.compiler.phases.OptimisticOptimizations; -import jdk.graal.compiler.phases.Phase; -import jdk.graal.compiler.phases.PhaseSuite; import jdk.graal.compiler.phases.common.CanonicalizerPhase; -import jdk.graal.compiler.phases.common.DominatorBasedGlobalValueNumberingPhase; -import jdk.graal.compiler.phases.common.IterativeConditionalEliminationPhase; -import jdk.graal.compiler.phases.tiers.HighTierContext; +import jdk.graal.compiler.phases.tiers.Suites; import jdk.graal.compiler.phases.util.Providers; -import jdk.graal.compiler.printer.GraalDebugHandlersFactory; import jdk.graal.compiler.truffle.phases.DeoptimizeOnExceptionPhase; -import jdk.vm.ci.code.BytecodeFrame; -import jdk.vm.ci.code.BytecodePosition; -import jdk.vm.ci.meta.JavaConstant; import jdk.vm.ci.meta.JavaKind; -import jdk.vm.ci.meta.MetaAccessProvider; -import jdk.vm.ci.meta.ResolvedJavaField; +import jdk.vm.ci.meta.JavaType; import jdk.vm.ci.meta.ResolvedJavaMethod; import jdk.vm.ci.meta.ResolvedJavaType; -public class ParseOnceRuntimeCompilationFeature extends RuntimeCompilationFeature implements Feature, RuntimeCompilationSupport { +/** + * The main handler for running the Graal compiler in the Substrate VM at run time. This feature + * (and features it depends on like {@link FieldsOffsetsFeature}) encodes Graal graphs for runtime + * compilation, ensures that all required {@link SubstrateType}, {@link SubstrateMethod}, + * {@link SubstrateField} objects are created by {@link GraalGraphObjectReplacer} and added to the + * image. Data that is prepared during image generation and used at run time is stored in + * {@link TruffleRuntimeCompilationSupport}. + */ +public final class RuntimeCompilationFeature implements Feature, RuntimeCompilationCallbacks { public static class Options { - @Option(help = "Remove Deopt(Entries,Anchors,Proxies) determined to be unneeded after the runtime compiled graphs have been finalized.")// - public static final HostedOptionKey RemoveUnneededDeoptSupport = new HostedOptionKey<>(true); + @Option(help = "Print methods available for runtime compilation")// + public static final HostedOptionKey PrintRuntimeCompileMethods = new HostedOptionKey<>(false); + + @Option(help = "Print call tree of methods reachable for runtime compilation")// + public static final HostedOptionKey PrintRuntimeCompilationCallTree = new HostedOptionKey<>(false); + + @Option(help = "Maximum number of methods allowed for runtime compilation.", stability = OptionStability.STABLE)// + public static final HostedOptionKey MaxRuntimeCompileMethods = new HostedOptionKey<>(LocatableMultiOptionValue.Strings.build()); + + @Option(help = "Enforce checking of maximum number of methods allowed for runtime compilation. Useful for checking in the gate that the number of methods does not go up without a good reason.")// + public static final HostedOptionKey EnforceMaxRuntimeCompileMethods = new HostedOptionKey<>(false); @Option(help = "Perform InlineBeforeAnalysis on runtime compiled methods")// public static final HostedOptionKey RuntimeCompilationInlineBeforeAnalysis = new HostedOptionKey<>(true); } - public static final class CallTreeNode extends AbstractCallTreeNode { - final BytecodePosition position; - final boolean inlined; - - CallTreeNode(AnalysisMethod implementationMethod, AnalysisMethod targetMethod, CallTreeNode parent, BytecodePosition position, boolean inlined) { - super(parent, targetMethod, implementationMethod); - this.position = position; - this.inlined = inlined; + public static final class IsEnabled implements BooleanSupplier { + @Override + public boolean getAsBoolean() { + return ImageSingletons.contains(RuntimeCompilationFeature.class); } + } - @Override - public String getPosition() { - String message = ""; - if (inlined) { - message += "(inlined: some parent frames may be missing) "; + public static RuntimeCompilationFeature singleton() { + return ImageSingletons.lookup(RuntimeCompilationFeature.class); + } - } - if (getParent() == null) { - message += "[root] "; - } - return message + position; - } + public interface RuntimeCompilationCandidatePredicate { + boolean allowRuntimeCompilation(ResolvedJavaMethod method); + } - /** - * It is not worthwhile to decode the graph to get the node count. - */ - @Override - public int getNodeCount() { - return -1; + public interface AllowInliningPredicate { + enum InlineDecision { + INLINE, + INLINING_DISALLOWED, + NO_DECISION } + InlineDecision allowInlining(GraphBuilderContext builder, ResolvedJavaMethod target); } - static class RuntimeCompilationCandidateImpl implements RuntimeCompilationCandidate { - AnalysisMethod implementationMethod; - AnalysisMethod targetMethod; + private GraalGraphObjectReplacer objectReplacer; + private HostedProviders hostedProviders; + private GraphEncoder graphEncoder; - RuntimeCompilationCandidateImpl(AnalysisMethod implementationMethod, AnalysisMethod targetMethod) { - this.implementationMethod = implementationMethod; - this.targetMethod = targetMethod; - } + private boolean initialized; + private GraphBuilderConfiguration graphBuilderConfig; + private OptimisticOptimizations optimisticOpts; + private RuntimeCompilationCandidatePredicate runtimeCompilationCandidatePredicate; + private boolean runtimeCompilationCandidatePredicateUpdated = false; + private Predicate deoptimizeOnExceptionPredicate; - @Override - public AnalysisMethod getImplementationMethod() { - return implementationMethod; - } + private SubstrateUniverseFactory universeFactory = new SubstrateUniverseFactory(); - @Override - public AnalysisMethod getTargetMethod() { - return targetMethod; - } + private final Set registeredRuntimeCompilations = ConcurrentHashMap.newKeySet(); + private final Set substrateAnalysisMethods = ConcurrentHashMap.newKeySet(); + private final Map invalidForRuntimeCompilation = new ConcurrentHashMap<>(); + private final Set runtimeCompilationCandidates = ConcurrentHashMap.newKeySet(); + private CallTreeInfo callTreeMetadata = null; + private HostedProviders analysisProviders = null; + private AllowInliningPredicate allowInliningPredicate = (builder, target) -> AllowInliningPredicate.InlineDecision.INLINING_DISALLOWED; + private boolean allowInliningPredicateUpdated = false; + private Function constantFieldProviderWrapper = Function.identity(); + private Consumer blocklistChecker = (ignore) -> { + }; - @Override - public boolean equals(Object o) { - if (this == o) { - return true; - } - if (o == null || getClass() != o.getClass()) { - return false; - } - RuntimeCompilationCandidateImpl that = (RuntimeCompilationCandidateImpl) o; - return implementationMethod.equals(that.implementationMethod) && targetMethod.equals(that.targetMethod); - } + public HostedProviders getHostedProviders() { + return hostedProviders; + } - @Override - public int hashCode() { - return Objects.hash(implementationMethod, targetMethod); - } + public GraalGraphObjectReplacer getObjectReplacer() { + return objectReplacer; } - static final class RuntimeCompiledMethodImpl implements RuntimeCompiledMethod { - final AnalysisMethod method; - final Collection inlinedMethods; + public void setUniverseFactory(SubstrateUniverseFactory universeFactory) { + this.universeFactory = universeFactory; + } - private RuntimeCompiledMethodImpl(AnalysisMethod method, Collection inlinedMethods) { - this.method = method; - this.inlinedMethods = inlinedMethods; - } + @SuppressWarnings("unused") + private static boolean defaultAllowRuntimeCompilation(ResolvedJavaMethod method) { + return false; + } - @Override - public AnalysisMethod getMethod() { - return method; - } + public void initializeRuntimeCompilationForTesting(FeatureImpl.BeforeAnalysisAccessImpl config, RuntimeCompilationCandidatePredicate newRuntimeCompilationCandidatePredicate) { + initializeRuntimeCompilationConfiguration(hostedProviders, graphBuilderConfig, newRuntimeCompilationCandidatePredicate, deoptimizeOnExceptionPredicate, blocklistChecker); + initializeRuntimeCompilationForTesting(config); + } - @Override - public Collection getInlinedMethods() { - return inlinedMethods; - } + public void initializeRuntimeCompilationForTesting(BeforeAnalysisAccessImpl config) { + initializeAnalysisProviders(config.getBigBang(), provider -> provider); + } - @Override - public Collection getInvokeTargets() { - List targets = new ArrayList<>(); - for (var invoke : method.getInvokes()) { - targets.add(invoke.getTargetMethod()); - } - return targets; - } + public void initializeRuntimeCompilationConfiguration(HostedProviders newHostedProviders, GraphBuilderConfiguration newGraphBuilderConfig, + RuntimeCompilationCandidatePredicate newRuntimeCompilationCandidatePredicate, + Predicate newDeoptimizeOnExceptionPredicate, Consumer newBlocklistChecker) { + guarantee(initialized == false, "runtime compilation configuration already initialized"); + initialized = true; + + hostedProviders = newHostedProviders; + graphBuilderConfig = newGraphBuilderConfig.withNodeSourcePosition(true); + assert !runtimeCompilationCandidatePredicateUpdated : "Updated compilation predicate multiple times"; + runtimeCompilationCandidatePredicate = newRuntimeCompilationCandidatePredicate; + runtimeCompilationCandidatePredicateUpdated = true; + deoptimizeOnExceptionPredicate = newDeoptimizeOnExceptionPredicate; + blocklistChecker = newBlocklistChecker; + } - @Override - public boolean equals(Object o) { - if (this == o) { - return true; - } - if (o == null || getClass() != o.getClass()) { - return false; - } - RuntimeCompiledMethodImpl that = (RuntimeCompiledMethodImpl) o; - return method.equals(that.method); - } + public SubstrateMethod requireFrameInformationForMethod(ResolvedJavaMethod method, BeforeAnalysisAccessImpl config, boolean registerAsRoot) { + AnalysisMethod aMethod = (AnalysisMethod) method; + SubstrateMethod sMethod = objectReplacer.createMethod(aMethod); - @Override - public int hashCode() { - return Objects.hash(method); + assert aMethod.isOriginalMethod(); + AnalysisMethod deoptTarget = aMethod.getOrCreateMultiMethod(DEOPT_TARGET_METHOD); + SubstrateCompilationDirectives.singleton().registerFrameInformationRequired(aMethod, deoptTarget); + if (registerAsRoot) { + config.registerAsRoot(aMethod, true, "Frame information required, registered in " + RuntimeCompilationFeature.class, DEOPT_TARGET_METHOD); } - } - private static final class RuntimeGraphBuilderPhase extends AnalysisGraphBuilderPhase { + return sMethod; + } - private RuntimeGraphBuilderPhase(Providers providers, - GraphBuilderConfiguration graphBuilderConfig, OptimisticOptimizations optimisticOpts, IntrinsicContext initialIntrinsicContext, SVMHost hostVM) { - super(providers, graphBuilderConfig, optimisticOpts, initialIntrinsicContext, hostVM); - } + public SubstrateMethod prepareMethodForRuntimeCompilation(Executable method, BeforeAnalysisAccessImpl config) { + return prepareMethodForRuntimeCompilation(config.getMetaAccess().lookupJavaMethod(method), config); + } - static RuntimeGraphBuilderPhase createRuntimeGraphBuilderPhase(BigBang bb, Providers providers, - GraphBuilderConfiguration graphBuilderConfig, OptimisticOptimizations optimisticOpts) { + public void registerAllowInliningPredicate(AllowInliningPredicate predicate) { + assert !allowInliningPredicateUpdated; + allowInliningPredicate = predicate; + allowInliningPredicateUpdated = true; + } - // Adjust graphbuilderconfig to match analysis phase - var newGraphBuilderConfig = graphBuilderConfig - .withEagerResolving(true) - .withUnresolvedIsError(false); - return new RuntimeGraphBuilderPhase(providers, newGraphBuilderConfig, optimisticOpts, null, (SVMHost) bb.getHostVM()); - } + public void initializeAnalysisProviders(BigBang bb, Function generator) { + HostedProviders defaultProviders = bb.getProviders(ORIGINAL_METHOD); + HostedProviders customHostedProviders = defaultProviders.copyWith(generator.apply(defaultProviders.getConstantFieldProvider())); + constantFieldProviderWrapper = generator; + customHostedProviders.setGraphBuilderPlugins(hostedProviders.getGraphBuilderPlugins()); + analysisProviders = customHostedProviders; + } - @Override - protected BytecodeParser createBytecodeParser(StructuredGraph graph, BytecodeParser parent, ResolvedJavaMethod method, int entryBCI, IntrinsicContext intrinsicContext) { - return new RuntimeBytecodeParser(this, graph, parent, method, entryBCI, intrinsicContext, hostVM); - } + public CallTreeInfo getCallTreeInfo() { + VMError.guarantee(callTreeMetadata != null); + return callTreeMetadata; } - private static final class RuntimeBytecodeParser extends AnalysisGraphBuilderPhase.AnalysisBytecodeParser { + public Collection getAllRuntimeCompilationCandidates() { + return runtimeCompilationCandidates; + } - RuntimeBytecodeParser(GraphBuilderPhase.Instance graphBuilderInstance, StructuredGraph graph, BytecodeParser parent, ResolvedJavaMethod method, int entryBCI, - IntrinsicContext intrinsicContext, SVMHost svmHost) { - super(graphBuilderInstance, graph, parent, method, entryBCI, intrinsicContext, svmHost, false); - } + public SubstrateMethod prepareMethodForRuntimeCompilation(ResolvedJavaMethod method, FeatureImpl.BeforeAnalysisAccessImpl config) { + AnalysisMethod aMethod = (AnalysisMethod) method; + assert aMethod.isOriginalMethod(); - @Override - protected boolean tryInvocationPlugin(CallTargetNode.InvokeKind invokeKind, ValueNode[] args, ResolvedJavaMethod targetMethod, JavaKind resultType) { - boolean result = super.tryInvocationPlugin(invokeKind, args, targetMethod, resultType); - if (result) { - SubstrateCompilationDirectives.singleton().registerAsDeoptInlininingExclude(targetMethod); - } - return result; - } + SubstrateMethod sMethod = objectReplacer.createMethod(aMethod); + substrateAnalysisMethods.add(sMethod); - @Override - protected boolean shouldVerifyFrameStates() { + if (registeredRuntimeCompilations.add(aMethod)) { + aMethod.getOrCreateMultiMethod(RUNTIME_COMPILED_METHOD); /* - * (GR-46115) Ideally we should verify frame states in methods registered for runtime - * compilations, as well as any other methods that can deoptimize. Because runtime - * compiled methods can pull in almost arbitrary code, this means most frame states - * should be verified. We currently use illegal states as placeholders in many places, - * so this cannot be enabled at the moment. + * For static methods it is important to also register the deopt targets to ensure the + * method will be linked appropriately. However, we do not need to make the entire flow + * until we see what FrameStates exist. */ - return false; + var deoptMethod = aMethod.getOrCreateMultiMethod(DEOPT_TARGET_METHOD, (newMethod) -> ((PointsToAnalysisMethod) newMethod).getTypeFlow().setAsStubFlow()); + SubstrateCompilationDirectives.singleton().registerDeoptTarget(deoptMethod); + config.registerAsRoot(aMethod, true, "Runtime compilation, registered in " + RuntimeCompilationFeature.class, RUNTIME_COMPILED_METHOD, DEOPT_TARGET_METHOD); } - } - private final Set registeredRuntimeCompilations = ConcurrentHashMap.newKeySet(); - private final Set substrateAnalysisMethods = ConcurrentHashMap.newKeySet(); - private final Map invalidForRuntimeCompilation = new ConcurrentHashMap<>(); - private final Set runtimeCompilationCandidates = ConcurrentHashMap.newKeySet(); - private Set runtimeCompilations = null; - private Map runtimeCandidateCallTree = null; - private Map runtimeCompiledMethodCallTree = null; - private HostedProviders analysisProviders = null; - private ImageHeapScanner heapScanner; - private HostedProviders runtimeCompilationProviders = null; - private AllowInliningPredicate allowInliningPredicate = (builder, target) -> AllowInliningPredicate.InlineDecision.INLINING_DISALLOWED; - private boolean allowInliningPredicateUpdated = false; - private Function constantFieldProviderWrapper = Function.identity(); + return sMethod; + } @Override public List> getRequiredFeatures() { - return RuntimeCompilationFeature.getRequiredFeaturesHelper(); + return List.of(RuntimeCompilationCanaryFeature.class, DeoptimizationFeature.class, GraalCompilerFeature.class); } @Override - public void afterRegistration(AfterRegistrationAccess access) { + public void afterRegistration(Feature.AfterRegistrationAccess access) { ImageSingletons.add(SVMParsingSupport.class, new RuntimeCompilationParsingSupport()); ImageSingletons.add(HostVM.MultiMethodAnalysisPolicy.class, new RuntimeCompilationAnalysisPolicy()); - ImageSingletons.add(RuntimeCompilationFeature.class, this); - ImageSingletons.add(RuntimeCompilationSupport.class, this); + ImageSingletons.add(RuntimeCompilationCallbacks.class, this); } @Override public void duringSetup(DuringSetupAccess c) { - duringSetupHelper(c); - } + if (SubstrateOptions.useLLVMBackend()) { + throw UserError.abort("Runtime compilation is currently unimplemented on the LLVM backend (GR-43073)."); + } + ImageSingletons.add(TruffleRuntimeCompilationSupport.class, new TruffleRuntimeCompilationSupport()); + if (!ImageSingletons.contains(SubstrateGraalCompilerSetup.class)) { + ImageSingletons.add(SubstrateGraalCompilerSetup.class, new SubstrateGraalCompilerSetup()); + } - @Override - public void beforeAnalysis(BeforeAnalysisAccess c) { - beforeAnalysisHelper(c); + DuringSetupAccessImpl config = (DuringSetupAccessImpl) c; + AnalysisMetaAccess aMetaAccess = config.getMetaAccess(); + SubstrateWordTypes wordTypes = new SubstrateWordTypes(aMetaAccess, FrameAccess.getWordKind()); + SubstrateProviders substrateProviders = ImageSingletons.lookup(SubstrateGraalCompilerSetup.class).getSubstrateProviders(aMetaAccess, wordTypes); + objectReplacer = new GraalGraphObjectReplacer(config.getUniverse(), substrateProviders, universeFactory); + config.registerObjectReplacer(objectReplacer); } - @Override - public void registerAllowInliningPredicate(AllowInliningPredicate predicate) { - assert !allowInliningPredicateUpdated; - allowInliningPredicate = predicate; - allowInliningPredicateUpdated = true; + private void installRuntimeConfig(BeforeAnalysisAccessImpl config) { + Function backendProvider = TruffleRuntimeCompilationSupport.getRuntimeBackendProvider(); + ClassInitializationSupport classInitializationSupport = config.getHostVM().getClassInitializationSupport(); + Providers originalProviders = GraalAccess.getOriginalProviders(); + SubstratePlatformConfigurationProvider platformConfig = new SubstratePlatformConfigurationProvider( + ImageSingletons.lookup(BarrierSetProvider.class).createBarrierSet(config.getMetaAccess())); + RuntimeConfiguration runtimeConfig = ImageSingletons.lookup(SubstrateGraalCompilerSetup.class) + .createRuntimeConfigurationBuilder(RuntimeOptionValues.singleton(), config.getHostVM(), config.getUniverse(), config.getMetaAccess(), + backendProvider, classInitializationSupport, originalProviders.getLoopsDataProvider(), platformConfig, + config.getBigBang().getSnippetReflectionProvider()) + .build(); + + Providers runtimeProviders = runtimeConfig.getProviders(); + hostedProviders = new HostedProviders(runtimeProviders.getMetaAccess(), runtimeProviders.getCodeCache(), runtimeProviders.getConstantReflection(), + runtimeProviders.getConstantFieldProvider(), + runtimeProviders.getForeignCalls(), runtimeProviders.getLowerer(), runtimeProviders.getReplacements(), runtimeProviders.getStampProvider(), + runtimeConfig.getSnippetReflection(), runtimeProviders.getWordTypes(), runtimeProviders.getPlatformConfigurationProvider(), new GraphPrepareMetaAccessExtensionProvider(), + runtimeProviders.getLoopsDataProvider()); + + FeatureHandler featureHandler = config.getFeatureHandler(); + final boolean supportsStubBasedPlugins = !SubstrateOptions.useLLVMBackend(); + + NativeImageGenerator.registerGraphBuilderPlugins(featureHandler, runtimeConfig, hostedProviders, config.getMetaAccess(), config.getUniverse(), null, config.getNativeLibraries(), + config.getImageClassLoader(), ParsingReason.JITCompilation, ((Inflation) config.getBigBang()).getAnnotationSubstitutionProcessor(), + new SubstrateClassInitializationPlugin(config.getHostVM()), ConfigurationValues.getTarget(), supportsStubBasedPlugins); + + NativeImageGenerator.registerReplacements(DebugContext.forCurrentThread(), featureHandler, runtimeConfig, runtimeConfig.getProviders(), false, true, + new RuntimeCompiledMethodSupport.RuntimeCompilationGraphEncoder(ConfigurationValues.getTarget().arch, config.getUniverse().getHeapScanner())); + + featureHandler.forEachGraalFeature(feature -> feature.registerCodeObserver(runtimeConfig)); + Suites suites = NativeImageGenerator.createSuites(featureHandler, runtimeConfig, runtimeConfig.getSnippetReflection(), false); + LIRSuites lirSuites = NativeImageGenerator.createLIRSuites(featureHandler, runtimeConfig.getProviders(), false); + Suites firstTierSuites = NativeImageGenerator.createFirstTierSuites(featureHandler, runtimeConfig, runtimeConfig.getSnippetReflection(), false); + LIRSuites firstTierLirSuites = NativeImageGenerator.createFirstTierLIRSuites(featureHandler, runtimeConfig.getProviders(), false); + + TruffleRuntimeCompilationSupport.setRuntimeConfig(runtimeConfig, suites, lirSuites, firstTierSuites, firstTierLirSuites); } @Override - public void initializeAnalysisProviders(BigBang bb, Function generator) { - HostedProviders defaultProviders = bb.getProviders(ORIGINAL_METHOD); - HostedProviders customHostedProviders = defaultProviders.copyWith(generator.apply(defaultProviders.getConstantFieldProvider())); - constantFieldProviderWrapper = generator; - customHostedProviders.setGraphBuilderPlugins(hostedProviders.getGraphBuilderPlugins()); - analysisProviders = customHostedProviders; - heapScanner = bb.getUniverse().getHeapScanner(); + public void beforeAnalysis(BeforeAnalysisAccess c) { + + BeforeAnalysisAccessImpl config = (BeforeAnalysisAccessImpl) c; + installRuntimeConfig(config); + + SubstrateGraalRuntime graalRuntime = new SubstrateGraalRuntime(); + objectReplacer.setGraalRuntime(graalRuntime); + objectReplacer.setAnalysisAccess(config); + ImageSingletons.add(GraalRuntime.class, graalRuntime); + RuntimeSupport.getRuntimeSupport().addShutdownHook(new GraalSupport.GraalShutdownHook()); + + /* Initialize configuration with reasonable default values. */ + graphBuilderConfig = GraphBuilderConfiguration.getDefault(hostedProviders.getGraphBuilderPlugins()).withBytecodeExceptionMode(BytecodeExceptionMode.ExplicitOnly); + runtimeCompilationCandidatePredicate = RuntimeCompilationFeature::defaultAllowRuntimeCompilation; + optimisticOpts = OptimisticOptimizations.ALL.remove(OptimisticOptimizations.Optimization.UseLoopLimitChecks); + graphEncoder = new RuntimeCompiledMethodSupport.RuntimeCompilationGraphEncoder(ConfigurationValues.getTarget().arch, config.getUniverse().getHeapScanner()); + + /* + * Ensure all snippet types are registered as used. + */ + SubstrateReplacements replacements = (SubstrateReplacements) TruffleRuntimeCompilationSupport.getRuntimeConfig().getProviders().getReplacements(); + for (NodeClass nodeClass : replacements.getSnippetNodeClasses()) { + config.getMetaAccess().lookupJavaType(nodeClass.getClazz()).registerAsAllocated("All " + NodeClass.class.getName() + " classes are marked as instantiated eagerly."); + } + /* + * Ensure runtime snippet graphs are analyzed. + */ + NativeImageGenerator.performSnippetGraphAnalysis(config.getBigBang(), replacements, config.getBigBang().getOptions()); + + /* + * Ensure that all snippet methods have their SubstrateMethod object created by the object + * replacer, to avoid corner cases later when writing the native image. + */ + for (ResolvedJavaMethod method : replacements.getSnippetMethods()) { + objectReplacer.apply(method); + } } boolean newRuntimeMethodsSeen = false; @Override - public void duringAnalysis(DuringAnalysisAccess c) { + public void duringAnalysis(Feature.DuringAnalysisAccess c) { /* * Note this will be removed once graphEncoder and the graal graph object replacer are * thread friendly. @@ -403,375 +466,129 @@ public void duringAnalysis(DuringAnalysisAccess c) { } } - @Override - public void afterAnalysis(AfterAnalysisAccess access) { - /* - * At this point need to determine which methods are actually valid for runtime compilation - * and calculate their reachability info. - */ - buildCallTrees(); - - runtimeCompilations = new HashSet<>(); - FeatureImpl.AfterAnalysisAccessImpl impl = (FeatureImpl.AfterAnalysisAccessImpl) access; - for (var method : impl.getUniverse().getMethods()) { - var rMethod = method.getMultiMethod(RUNTIME_COMPILED_METHOD); - if (rMethod != null && rMethod.isReachable() && !invalidForRuntimeCompilation.containsKey(rMethod)) { - var runtimeInlinedMethods = rMethod.getAnalyzedGraph().getInlinedMethods(); - var inlinedMethods = runtimeInlinedMethods.stream().map(inlinedMethod -> { - ResolvedJavaMethod orig = ((AnalysisMethod) inlinedMethod).getMultiMethod(ORIGINAL_METHOD); - assert orig != null; - return orig; - }).collect(Collectors.toUnmodifiableSet()); - boolean added = runtimeCompilations.add(new RuntimeCompiledMethodImpl(method, inlinedMethods)); - assert added; - assert runtimeCompiledMethodCallTree.containsKey(method); + private void checkMaxRuntimeCompiledMethods(CallTreeInfo callTreeInfo) { + int maxMethods = 0; + for (String value : Options.MaxRuntimeCompileMethods.getValue().values()) { + String numberStr = null; + try { + /* Strip optional comment string from MaxRuntimeCompileMethods value */ + numberStr = value.split("#")[0]; + maxMethods += Integer.parseInt(numberStr); + } catch (NumberFormatException ex) { + throw UserError.abort("Invalid value for option 'MaxRuntimeCompileMethods': '%s' is not a valid number", numberStr); } } - // call super after - afterAnalysisHelper(); - - // after analysis has completed we must ensure no new SubstrateTypes are introduced - objectReplacer.forbidNewTypes(); - } - - @Override - protected AbstractCallTreeNode getCallTreeNode(RuntimeCompilationCandidate candidate) { - var result = runtimeCandidateCallTree.get(candidate); - assert result != null; - return result; - } - - @Override - protected AbstractCallTreeNode getCallTreeNode(RuntimeCompiledMethod method) { - return getCallTreeNode(method.getMethod()); - } - - @Override - protected AbstractCallTreeNode getCallTreeNode(ResolvedJavaMethod method) { - ResolvedJavaMethod origMethod = method instanceof MultiMethod m ? (ResolvedJavaMethod) m.getMultiMethod(ORIGINAL_METHOD) : method; - var result = runtimeCompiledMethodCallTree.get(origMethod); - assert result != null; - return result; - } - - @Override - public Collection getRuntimeCompiledMethods() { - return runtimeCompilations; - } - - @Override - public Collection getAllRuntimeCompilationCandidates() { - return runtimeCompilationCandidates; - } - - private void buildCallTrees() { - /* - * While it is possible to dynamically calculate call traces by enabling - * PointstoOptions#TraceAccessChain, creating call trees post-analysis for runtime compiled - * methods allows use to not have this overhead during analysis and also to determine the - * access chains for multiple call sites with the same destination. - * - * This is useful to create more stringent blocklist checks. - */ - assert runtimeCandidateCallTree == null && runtimeCompiledMethodCallTree == null; - runtimeCandidateCallTree = new HashMap<>(); - runtimeCompiledMethodCallTree = new HashMap<>(); - - Queue worklist = new LinkedList<>(); - - /* First initialize with registered runtime compilations */ - for (AnalysisMethod root : registeredRuntimeCompilations) { - var runtimeRoot = root.getMultiMethod(RUNTIME_COMPILED_METHOD); - if (runtimeRoot != null) { - runtimeCandidateCallTree.computeIfAbsent(new RuntimeCompilationCandidateImpl(root, root), (candidate) -> { - var result = new CallTreeNode(root, root, null, new BytecodePosition(null, root, BytecodeFrame.UNKNOWN_BCI), false); - worklist.add(result); - return result; - }); - } - } - - /* - * Find all runtime compiled methods reachable from registered runtime compilations. - * - * Note within the maps we store the original methods, not the runtime methods. - */ - while (!worklist.isEmpty()) { - CallTreeNode caller = worklist.remove(); - caller.linkAsChild(); - - /* - * We only need to record one trace for methods - */ - var method = caller.getImplementationMethod(); - if (runtimeCompiledMethodCallTree.containsKey(method)) { - // This method has already been processed - continue; - } else { - runtimeCompiledMethodCallTree.put(method, caller); - } - AnalysisMethod runtimeMethod = method.getMultiMethod(RUNTIME_COMPILED_METHOD); - assert runtimeMethod != null; - - for (InvokeInfo invokeInfo : runtimeMethod.getInvokes()) { - AnalysisMethod invokeTarget = invokeInfo.getTargetMethod(); - boolean deoptInvokeTypeFlow = invokeInfo.isDeoptInvokeTypeFlow(); - if (deoptInvokeTypeFlow) { - assert SubstrateCompilationDirectives.isRuntimeCompiledMethod(invokeTarget); - invokeTarget = invokeTarget.getMultiMethod(ORIGINAL_METHOD); - } - AnalysisMethod target = invokeTarget; - assert target.isOriginalMethod(); - for (AnalysisMethod implementation : invokeInfo.getAllCallees()) { - if (deoptInvokeTypeFlow || SubstrateCompilationDirectives.isRuntimeCompiledMethod(implementation)) { - var origImpl = implementation.getMultiMethod(ORIGINAL_METHOD); - assert origImpl != null; - runtimeCandidateCallTree.computeIfAbsent(new RuntimeCompilationCandidateImpl(origImpl, target), (candidate) -> { - var result = new CallTreeNode(origImpl, target, caller, invokeInfo.getPosition(), deoptInvokeTypeFlow); - worklist.add(result); - return result; - }); - } else if (implementation.isOriginalMethod() && implementation.getMultiMethod(RUNTIME_COMPILED_METHOD) == null) { - /* - * Recording that this call was reachable, but not converted to a runtime - * compiled method. - */ - runtimeCandidateCallTree.computeIfAbsent(new RuntimeCompilationCandidateImpl(implementation, target), - (candidate) -> { - var result = new CallTreeNode(implementation, target, caller, invokeInfo.getPosition(), false); - result.linkAsChild(); - return result; - }); - } - } - } - } - } - - public Set parsedRuntimeMethods = ConcurrentHashMap.newKeySet(); - public AtomicLong totalParsedRuntimeMethods = new AtomicLong(); - public Set parsedDeoptMethods = ConcurrentHashMap.newKeySet(); - public AtomicLong totalParsedDeoptMethods = new AtomicLong(); - - private class RuntimeCompileTask implements CompletionExecutor.DebugContextRunnable { - final HostedMethod method; - - RuntimeCompileTask(HostedMethod method) { - this.method = method; - } - - @Override - public DebugContext getDebug(OptionValues options, List factories) { - return new DebugContext.Builder(options, factories).description(getDescription()).build(); - } - - @Override - public void run(DebugContext debug) { - compileRuntimeCompiledMethod(debug, method); + if (Options.EnforceMaxRuntimeCompileMethods.getValue() && maxMethods != 0 && callTreeInfo.runtimeCompilations().size() > maxMethods) { + CallTreeInfo.printDeepestPath(callTreeInfo, registeredRuntimeCompilations); + throw VMError.shouldNotReachHere("Number of methods for runtime compilation exceeds the allowed limit: " + callTreeInfo.runtimeCompilations().size() + " > " + maxMethods); } } - private final Map runtimeGraphs = new ConcurrentHashMap<>(); - - @SuppressWarnings("try") - private void compileRuntimeCompiledMethod(DebugContext debug, HostedMethod method) { - assert method.getMultiMethodKey() == RUNTIME_COMPILED_METHOD; - - AnalysisMethod aMethod = method.getWrapped(); - StructuredGraph graph = aMethod.decodeAnalyzedGraph(debug, null, false, - (arch, analyzedGraph) -> new RuntimeCompilationGraphDecoder(arch, analyzedGraph, heapScanner)); - if (graph == null) { - throw VMError.shouldNotReachHere("Method not parsed during static analysis: " + aMethod.format("%r %H.%n(%p)")); - } - /* - * The graph in the analysis universe is no longer necessary once it is transplanted into - * the hosted universe. - */ - aMethod.setAnalyzedGraph(null); - - try (DebugContext.Scope s = debug.scope("RuntimeOptimize", graph, method, this)) { - CanonicalizerPhase canonicalizer = CanonicalizerPhase.create(); - canonicalizer.apply(graph, runtimeCompilationProviders); - - new DominatorBasedGlobalValueNumberingPhase(canonicalizer).apply(graph, runtimeCompilationProviders); - - new IterativeConditionalEliminationPhase(canonicalizer, true).apply(graph, runtimeCompilationProviders); - - /* - * ConvertDeoptimizeToGuardPhase was already executed after parsing, but optimizations - * applied in between can provide new potential. - */ - new ConvertDeoptimizeToGuardPhase(canonicalizer).apply(graph, runtimeCompilationProviders); + @Override + public void afterAnalysis(Feature.AfterAnalysisAccess access) { + VMError.guarantee(callTreeMetadata == null); + callTreeMetadata = CallTreeInfo.create(((FeatureImpl.AfterAnalysisAccessImpl) access).getUniverse(), invalidForRuntimeCompilation); - /* - * More optimizations can be added here. - */ - } catch (Throwable e) { - throw debug.handle(e); - } + ProgressReporter.singleton().setNumRuntimeCompiledMethods(callTreeMetadata.runtimeCompilations().size()); + // after analysis has completed we must ensure no new SubstrateTypes are introduced + objectReplacer.forbidNewTypes(); - /* - * Registering all deopt entries seen within the optimized graph. This should be strictly a - * subset of the deopt entrypoints seen during evaluation. - */ - AnalysisMethod origMethod = method.getMultiMethod(ORIGINAL_METHOD).getWrapped(); - DeoptimizationUtils.registerDeoptEntries(graph, registeredRuntimeCompilations.contains(origMethod), - (deoptEntryMethod -> { - PointsToAnalysisMethod deoptMethod = (PointsToAnalysisMethod) ((PointsToAnalysisMethod) deoptEntryMethod).getMultiMethod(DEOPT_TARGET_METHOD); - VMError.guarantee(deoptMethod != null, "New deopt target method seen: %s", deoptEntryMethod); - return deoptMethod; - })); - - assert RuntimeCompilationFeature.verifyNodes(graph); - var previous = runtimeGraphs.put(method, graph); - assert previous == null; - - // graph encoder is not currently threadsafe - synchronized (this) { - graphEncoder.prepare(graph); + VMError.guarantee(callTreeMetadata != null); + if (Options.PrintRuntimeCompileMethods.getValue()) { + System.out.println("****Start Print Runtime Compile Methods***"); + callTreeMetadata.runtimeCompilations().stream().map(m -> m.getRuntimeMethod().format("%H.%n(%p)")).sorted().toList().forEach(System.out::println); + System.out.println("****End Print Runtime Compile Methods***"); } - } - @SuppressWarnings("try") - private void encodeRuntimeCompiledMethods() { - graphEncoder.finishPrepare(); - - // at this point no new deoptimization entrypoints can be registered. - SubstrateCompilationDirectives.singleton().sealDeoptimizationInfo(); - - for (var runtimeInfo : runtimeGraphs.entrySet()) { - var graph = runtimeInfo.getValue(); - var method = runtimeInfo.getKey(); - DebugContext debug = new DebugContext.Builder(graph.getOptions(), new GraalDebugHandlersFactory(runtimeCompilationProviders.getSnippetReflection())).build(); - graph.resetDebug(debug); - try (DebugContext.Scope s = debug.scope("Graph Encoding", graph); - DebugContext.Activation a = debug.activate()) { - long startOffset = graphEncoder.encode(graph); - objectReplacer.createMethod(method).setEncodedGraphStartOffset(startOffset); - } catch (Throwable ex) { - debug.handle(ex); - } + if (Options.PrintRuntimeCompilationCallTree.getValue()) { + System.out.println("****Start Print Runtime Compile Call Tree***"); + CallTreeInfo.printCallTree(callTreeMetadata, registeredRuntimeCompilations); + System.out.println("****End Print Runtime Compile Call Tree***"); } - HeapBreakdownProvider.singleton().setGraphEncodingByteLength(graphEncoder.getEncoding().length); - TruffleRuntimeCompilationSupport.setGraphEncoding(null, graphEncoder.getEncoding(), graphEncoder.getObjects(), graphEncoder.getNodeClasses()); - - objectReplacer.setMethodsImplementations(); - - /* All the temporary data structures used during encoding are no longer necessary. */ - graphEncoder = null; - } - - @Override - public void beforeCompilation(BeforeCompilationAccess c) { - beforeCompilationHelper(); + checkMaxRuntimeCompiledMethods(callTreeMetadata); } @Override public void onCompileQueueCreation(BigBang bb, HostedUniverse hUniverse, CompileQueue compileQueue) { - /* - * Start fresh with a new GraphEncoder, since we are going to optimize all graphs now that - * the static analysis results are available. - */ - graphEncoder = new RuntimeCompilationGraphEncoder(ConfigurationValues.getTarget().arch, bb.getUniverse().getHeapScanner()); - assert runtimeCompilationProviders == null; - runtimeCompilationProviders = hostedProviders - .copyWith(constantFieldProviderWrapper.apply(new RuntimeCompilationFieldProvider(hostedProviders.getMetaAccess(), hUniverse))) - .copyWith(new RuntimeCompilationReflectionProvider(bb, hUniverse.hostVM().getClassInitializationSupport())); - - SubstrateCompilationDirectives.singleton().resetDeoptEntries(); - /* - * Customize runtime compile methods for compiling them into substrate graphs. - */ - CompletionExecutor executor = compileQueue.getExecutor(); - try { - compileQueue.runOnExecutor(() -> { - hUniverse.getMethods().stream().map(method -> method.getMultiMethod(RUNTIME_COMPILED_METHOD)).filter(method -> { - if (method != null) { - AnalysisMethod aMethod = method.getWrapped(); - return aMethod.isImplementationInvoked() && !invalidForRuntimeCompilation.containsKey(aMethod); - } - return false; - }).forEach(method -> { - executor.execute(new RuntimeCompileTask(method)); - }); - }); - } catch (InterruptedException exception) { - VMError.shouldNotReachHere(exception); - } - encodeRuntimeCompiledMethods(); - - /* - * For Deoptimization Targets add a custom phase which removes all deoptimization - * entrypoints which are deemed no longer necessary. - */ - CompileQueue.ParseHooks deoptParseHooks = new CompileQueue.ParseHooks(compileQueue) { - @Override - protected PhaseSuite getAfterParseSuite() { - PhaseSuite suite = super.getAfterParseSuite(); - if (Options.RemoveUnneededDeoptSupport.getValue()) { - suite.prependPhase(new RemoveUnneededDeoptSupport()); - } - - return suite; - } - }; - - hUniverse.getMethods().stream().map(method -> method.getMultiMethod(DEOPT_TARGET_METHOD)).filter(method -> { + graphEncoder = null; + Stream methodsToCompile = hUniverse.getMethods().stream().map(method -> method.getMultiMethod(RUNTIME_COMPILED_METHOD)).filter(method -> { if (method != null) { - return compileQueue.isRegisteredDeoptTarget(method); + AnalysisMethod aMethod = method.getWrapped(); + return aMethod.isImplementationInvoked() && !invalidForRuntimeCompilation.containsKey(aMethod); } return false; - }).forEach(method -> method.compilationInfo.setCustomParseHooks(deoptParseHooks)); - + }); + RuntimeCompiledMethodSupport.onCompileQueueCreation(bb, hUniverse, compileQueue, hostedProviders, constantFieldProviderWrapper, objectReplacer, + registeredRuntimeCompilations, methodsToCompile); } @Override public void afterCompilation(AfterCompilationAccess a) { - super.afterCompilationHelper(a); + CompilationAccessImpl config = (CompilationAccessImpl) a; + + HostedMetaAccess hMetaAccess = config.getMetaAccess(); + HostedUniverse hUniverse = hMetaAccess.getUniverse(); + objectReplacer.updateSubstrateDataAfterCompilation(hUniverse, config.getProviders()); } @Override public void beforeHeapLayout(BeforeHeapLayoutAccess a) { - super.beforeHeapLayoutHelper(a); + objectReplacer.registerImmutableObjects(a); + TruffleRuntimeCompilationSupport.registerImmutableObjects(a); + ((SubstrateReplacements) TruffleRuntimeCompilationSupport.getRuntimeConfig().getProviders().getReplacements()).registerImmutableObjects(a); } @Override public void afterHeapLayout(AfterHeapLayoutAccess a) { - afterHeapLayoutHelper(a); + AfterHeapLayoutAccessImpl config = (AfterHeapLayoutAccessImpl) a; + HostedMetaAccess hMetaAccess = config.getMetaAccess(); + HostedUniverse hUniverse = hMetaAccess.getUniverse(); + objectReplacer.updateSubstrateDataAfterHeapLayout(hUniverse); } + /** + * When a failure occurs during parsing, it is likely due to a missing truffle boundary. Check + * to see if anything on the blocklist has been reached and/or the number of runtime compiled + * methods exceeds the maximum allowed. + */ @Override - public SubstrateMethod prepareMethodForRuntimeCompilation(ResolvedJavaMethod method, FeatureImpl.BeforeAnalysisAccessImpl config) { - AnalysisMethod aMethod = (AnalysisMethod) method; - assert aMethod.isOriginalMethod(); - - SubstrateMethod sMethod = objectReplacer.createMethod(aMethod); - substrateAnalysisMethods.add(sMethod); - - if (registeredRuntimeCompilations.add(aMethod)) { - aMethod.getOrCreateMultiMethod(RUNTIME_COMPILED_METHOD); - /* - * For static methods it is important to also register the deopt targets to ensure the - * method will be linked appropriately. However, we do not need to make the entire flow - * until we see what FrameStates exist. - */ - var deoptMethod = aMethod.getOrCreateMultiMethod(DEOPT_TARGET_METHOD, (newMethod) -> ((PointsToAnalysisMethod) newMethod).getTypeFlow().setAsStubFlow()); - SubstrateCompilationDirectives.singleton().registerDeoptTarget(deoptMethod); - config.registerAsRoot(aMethod, true, "Runtime compilation, registered in " + ParseOnceRuntimeCompilationFeature.class, RUNTIME_COMPILED_METHOD, DEOPT_TARGET_METHOD); + public void reportAnalysisError(AnalysisUniverse aUniverse, Throwable t) { + var treeInfo = CallTreeInfo.create(aUniverse, invalidForRuntimeCompilation); + + blocklistChecker.accept(treeInfo); + + checkMaxRuntimeCompiledMethods(treeInfo); + + boolean foundError = false; + if (t instanceof ParallelExecutionException exception) { + for (var e : exception.getExceptions()) { + if (e instanceof AnalysisError.ParsingError parsingError) { + AnalysisMethod errorMethod = parsingError.getMethod(); + if (errorMethod.isDeoptTarget() || SubstrateCompilationDirectives.isRuntimeCompiledMethod(errorMethod)) { + foundError = true; + AnalysisMethod failingRuntimeMethod = null; + if (SubstrateCompilationDirectives.isRuntimeCompiledMethod(errorMethod)) { + failingRuntimeMethod = errorMethod; + } else if (errorMethod.isDeoptTarget()) { + failingRuntimeMethod = errorMethod.getMultiMethod(RUNTIME_COMPILED_METHOD); + } + System.out.println("Parsing failed on a special method version: " + errorMethod.format("%H.%n")); + System.out.println("Method reachability trace"); + if (failingRuntimeMethod != null) { + Arrays.stream(CallTreeInfo.getCallTrace(treeInfo, failingRuntimeMethod)).forEach(System.out::println); + } else { + System.out.println("trace unavailable"); + } + System.out.println("error: " + e.getMessage()); + } + } + } } - return sMethod; - } - - @Override - protected void requireFrameInformationForMethodHelper(AnalysisMethod aMethod, FeatureImpl.BeforeAnalysisAccessImpl config, boolean registerAsRoot) { - assert aMethod.isOriginalMethod(); - AnalysisMethod deoptTarget = aMethod.getOrCreateMultiMethod(DEOPT_TARGET_METHOD); - SubstrateCompilationDirectives.singleton().registerFrameInformationRequired(aMethod, deoptTarget); - if (registerAsRoot) { - config.registerAsRoot(aMethod, true, "Frame information required, registered in " + ParseOnceRuntimeCompilationFeature.class, DEOPT_TARGET_METHOD); + if (foundError) { + throw VMError.shouldNotReachHere("Analysis failed while parsing deopt and/or runtime methods"); } } @@ -845,7 +662,7 @@ private Object parseRuntimeCompiledMethod(BigBang bb, DebugContext debug, Analys if (parsed) { // enable this logging to get log output in compilation passes try (Indent indent2 = debug.logAndIndent("parse graph phases")) { - RuntimeGraphBuilderPhase.createRuntimeGraphBuilderPhase(bb, analysisProviders, graphBuilderConfig, optimisticOpts).apply(graph); + RuntimeCompiledMethodSupport.RuntimeGraphBuilderPhase.createRuntimeGraphBuilderPhase(bb, analysisProviders, graphBuilderConfig, optimisticOpts).apply(graph); } catch (PermanentBailoutException ex) { bb.getUnsupportedFeatures().addMessage(method.format("%H.%n(%p)"), method, ex.getLocalizedMessage(), null, ex); recordFailed(method); @@ -893,8 +710,6 @@ public boolean validateGraph(PointsToAnalysis bb, StructuredGraph graph) { } } if (multiMethodKey == RUNTIME_COMPILED_METHOD) { - parsedRuntimeMethods.add(aMethod); - totalParsedRuntimeMethods.incrementAndGet(); /* * Register all FrameStates as DeoptEntries. */ @@ -924,10 +739,7 @@ public boolean validateGraph(PointsToAnalysis bb, StructuredGraph graph) { substrateAnalysisMethods.add(sMethod); graphEncoder.prepare(graph); } - assert RuntimeCompilationFeature.verifyNodes(graph); - } else if (multiMethodKey == DEOPT_TARGET_METHOD) { - parsedDeoptMethods.add(aMethod); - totalParsedDeoptMethods.incrementAndGet(); + assert RuntimeCompiledMethodSupport.verifyNodes(graph); } return true; @@ -935,7 +747,7 @@ public boolean validateGraph(PointsToAnalysis bb, StructuredGraph graph) { @Override public void initializeInlineBeforeAnalysisPolicy(SVMHost svmHost, InlineBeforeAnalysisPolicyUtils inliningUtils) { - if (Options.RuntimeCompilationInlineBeforeAnalysis.getValue()) { + if (RuntimeCompilationFeature.Options.RuntimeCompilationInlineBeforeAnalysis.getValue()) { assert runtimeInlineBeforeAnalysisPolicy == null; runtimeInlineBeforeAnalysisPolicy = new RuntimeCompilationInlineBeforeAnalysisPolicy(svmHost, inliningUtils); } @@ -948,7 +760,7 @@ public InlineBeforeAnalysisPolicy inlineBeforeAnalysisPolicy(MultiMethod.MultiMe } else if (multiMethodKey == DEOPT_TARGET_METHOD) { return InlineBeforeAnalysisPolicy.NO_INLINING; } else if (multiMethodKey == RUNTIME_COMPILED_METHOD) { - if (Options.RuntimeCompilationInlineBeforeAnalysis.getValue()) { + if (RuntimeCompilationFeature.Options.RuntimeCompilationInlineBeforeAnalysis.getValue()) { assert runtimeInlineBeforeAnalysisPolicy != null; return runtimeInlineBeforeAnalysisPolicy; } @@ -1061,7 +873,7 @@ protected AbstractPolicyScope createRootScope() { @Override protected AbstractPolicyScope openCalleeScope(AbstractPolicyScope outer, AnalysisMetaAccess metaAccess, AnalysisMethod method, boolean[] constArgsWithReceiver, boolean intrinsifiedMethodHandle) { - if (outer instanceof AccumulativeInlineScope accOuter) { + if (outer instanceof InlineBeforeAnalysisPolicyUtils.AccumulativeInlineScope accOuter) { /* * once the accumulative policy is activated, then we cannot return to the trivial * policy @@ -1069,13 +881,13 @@ protected AbstractPolicyScope openCalleeScope(AbstractPolicyScope outer, Analysi return inliningUtils.createAccumulativeInlineScope(accOuter, metaAccess, method, constArgsWithReceiver, intrinsifiedMethodHandle); } - assert outer == null || outer instanceof AlwaysInlineScope : "unexpected outer scope: " + outer; + assert outer == null || outer instanceof InlineBeforeAnalysisPolicyUtils.AlwaysInlineScope : "unexpected outer scope: " + outer; // check if trivial is possible boolean trivialInlineAllowed = hostVM.isAnalysisTrivialMethod(method); int inliningDepth = outer == null ? 1 : outer.inliningDepth + 1; if (trivialInlineAllowed && inliningDepth <= trivialAllowingInliningDepth) { - return new AlwaysInlineScope(inliningDepth); + return new InlineBeforeAnalysisPolicyUtils.AlwaysInlineScope(inliningDepth); } else { // start with a new accumulative inline scope return inliningUtils.createAccumulativeInlineScope(null, metaAccess, method, constArgsWithReceiver, intrinsifiedMethodHandle); @@ -1096,7 +908,7 @@ public Collection determineCallees(BigBang bb, T i assert SubstrateCompilationDirectives.isRuntimeCompiledMethod(implementation); var originalTarget = implementation.getMultiMethod(ORIGINAL_METHOD); assert originalTarget != null; - runtimeCompilationCandidates.add(new RuntimeCompilationCandidateImpl(originalTarget, originalTarget)); + runtimeCompilationCandidates.add(new RuntimeCompilationCandidate(originalTarget, originalTarget)); return List.of(getStubDeoptVersion(implementation)); } assert implementation.isOriginalMethod() && target.isOriginalMethod(); @@ -1129,7 +941,7 @@ public Collection determineCallees(BigBang bb, T i if (callerMultiMethodKey == RUNTIME_COMPILED_METHOD) { // recording compilation candidate - runtimeCompilationCandidates.add(new RuntimeCompilationCandidateImpl(implementation, target)); + runtimeCompilationCandidates.add(new RuntimeCompilationCandidate(implementation, target)); /* * The runtime method can call all three types: original (if it is not partial * evaluated), runtime (if it is partial evaluated), and deoptimized (if the @@ -1224,7 +1036,9 @@ public boolean performParameterLinking(MultiMethod.MultiMethodKey callerMultiMet @Override public boolean performReturnLinking(MultiMethod.MultiMethodKey callerMultiMethodKey, MultiMethod.MultiMethodKey calleeMultiMethodKey) { if (callerMultiMethodKey == RUNTIME_COMPILED_METHOD) { - /* A runtime method can be returned to from either a runtime or original method. */ + /* + * A runtime method can be returned to from either a runtime or original method. + */ return calleeMultiMethodKey == RUNTIME_COMPILED_METHOD || calleeMultiMethodKey == ORIGINAL_METHOD; } else if (callerMultiMethodKey == DEOPT_TARGET_METHOD) { /* A deopt method can be returned to from all three. */ @@ -1266,143 +1080,33 @@ public boolean unknownReturnValue(BigBang bb, MultiMethod.MultiMethodKey callerM return false; } } +} - /** - * Since we perform runtime compilation after universe creation, we can leverage components of - * the hosted universe provider for identifying final fields. - */ - private static class RuntimeCompilationFieldProvider extends AnalysisConstantFieldProvider { - final HostedUniverse hUniverse; - - RuntimeCompilationFieldProvider(MetaAccessProvider metaAccess, HostedUniverse hUniverse) { - super(metaAccess, hUniverse.hostVM()); - this.hUniverse = hUniverse; - } +/** + * Same behavior as {@link SubstrateMetaAccessExtensionProvider}, but operating on + * {@link AnalysisType} instead of {@link SharedType} since parsing of graphs for runtime + * compilation happens in the Analysis universe. + */ +class GraphPrepareMetaAccessExtensionProvider implements MetaAccessExtensionProvider { - @Override - public boolean isFinalField(ResolvedJavaField f, ConstantFieldTool tool) { - HostedField hField = hUniverse.lookup(f); - if (HostedConstantFieldProvider.isFinalField(hField)) { - return true; - } - return super.isFinalField(f, tool); - } + @Override + public JavaKind getStorageKind(JavaType type) { + return ((AnalysisType) type).getStorageKind(); } - private static class RuntimeCompilationReflectionProvider extends AnalysisConstantReflectionProvider { - - RuntimeCompilationReflectionProvider(BigBang bb, ClassInitializationSupport classInitializationSupport) { - super(bb.getUniverse(), bb.getMetaAccess(), classInitializationSupport); - } - - @Override - public JavaConstant readFieldValue(ResolvedJavaField field, JavaConstant receiver) { - /* - * We cannot fold simulated values during initial before-analysis graph creation; - * however, this runs after analysis has completed. - */ - return readValue(metaAccess, (AnalysisField) field, receiver, true); - } + @Override + public boolean canConstantFoldDynamicAllocation(ResolvedJavaType type) { + assert type instanceof AnalysisType : "AnalysisType is required; AnalysisType lazily creates array types of any depth, so type cannot be null"; + return ((AnalysisType) type).isInstantiated(); } - /** - * Removes {@link DeoptEntryNode}s, {@link DeoptProxyAnchorNode}s, and {@link DeoptProxyNode}s - * which are determined to be unnecessary after the runtime compilation methods are optimized. - */ - static class RemoveUnneededDeoptSupport extends Phase { - enum RemovalDecision { - KEEP, - PROXIFY, - REMOVE - } - - @Override - protected void run(StructuredGraph graph) { - EconomicMap decisionCache = EconomicMap.create(); - - // First go through and delete all unneeded proxies - for (DeoptProxyNode proxyNode : graph.getNodes(DeoptProxyNode.TYPE).snapshot()) { - ValueNode proxyPoint = proxyNode.getProxyPoint(); - if (proxyPoint instanceof StateSplit) { - if (getDecision((StateSplit) proxyPoint, decisionCache) == RemovalDecision.REMOVE) { - proxyNode.replaceAtAllUsages(proxyNode.getOriginalNode(), true); - proxyNode.safeDelete(); - } - } - } - - // Next, remove all unneeded DeoptEntryNodes - for (DeoptEntryNode deoptEntry : graph.getNodes().filter(DeoptEntryNode.class).snapshot()) { - switch (getDecision(deoptEntry, decisionCache)) { - case REMOVE -> { - deoptEntry.killExceptionEdge(); - graph.removeSplit(deoptEntry, deoptEntry.getPrimarySuccessor()); - } - case PROXIFY -> { - deoptEntry.killExceptionEdge(); - DeoptProxyAnchorNode newAnchor = graph.add(new DeoptProxyAnchorNode(deoptEntry.getProxifiedInvokeBci())); - newAnchor.setStateAfter(deoptEntry.stateAfter()); - graph.replaceSplitWithFixed(deoptEntry, newAnchor, deoptEntry.getPrimarySuccessor()); - } - } - } - - // Finally, remove all unneeded DeoptProxyAnchorNodes - for (DeoptProxyAnchorNode proxyAnchor : graph.getNodes().filter(DeoptProxyAnchorNode.class).snapshot()) { - if (getDecision(proxyAnchor, decisionCache) == RemovalDecision.REMOVE) { - graph.removeFixed(proxyAnchor); - } - } - } - - RemovalDecision getDecision(StateSplit node, EconomicMap decisionCache) { - RemovalDecision cached = decisionCache.get(node); - if (cached != null) { - return cached; - } - - DeoptEntrySupport proxyNode; - if (node instanceof ExceptionObjectNode exceptionObject) { - /* - * For the exception edge of a DeoptEntryNode, we insert the proxies on the - * exception object. - */ - proxyNode = (DeoptEntrySupport) exceptionObject.predecessor(); - } else { - proxyNode = (DeoptEntrySupport) node; - } - - RemovalDecision decision = RemovalDecision.REMOVE; - var directive = SubstrateCompilationDirectives.singleton(); - FrameState state = proxyNode.stateAfter(); - HostedMethod method = (HostedMethod) state.getMethod(); - if (proxyNode instanceof DeoptEntryNode) { - if (directive.isDeoptEntry(method, state.bci, state.getStackState())) { - // must keep all deopt entries which are still guarding nodes - decision = RemovalDecision.KEEP; - } - } - - if (decision == RemovalDecision.REMOVE) { - // now check for any implicit deopt entry being protected against - int proxifiedInvokeBci = proxyNode.getProxifiedInvokeBci(); - if (proxifiedInvokeBci != BytecodeFrame.UNKNOWN_BCI && directive.isDeoptEntry(method, proxifiedInvokeBci, FrameState.StackState.AfterPop)) { - // must keep still keep a proxy for nodes which are "proxifying" an invoke - decision = proxyNode instanceof DeoptEntryNode ? RemovalDecision.PROXIFY : RemovalDecision.KEEP; - } - } - - // cache the decision - decisionCache.put(node, decision); - if (proxyNode != node) { - decisionCache.put(proxyNode, decision); - } - return decision; - } + @Override + public boolean isGuaranteedSafepoint(ResolvedJavaMethod method, boolean isDirect) { + throw VMError.shouldNotReachHereAtRuntime(); // ExcludeFromJacocoGeneratedReport + } - @Override - public CharSequence getName() { - return "RemoveUnneededDeoptSupport"; - } + @Override + public boolean canVirtualize(ResolvedJavaType instanceType) { + return true; } } diff --git a/substratevm/src/com.oracle.svm.graal/src/com/oracle/svm/graal/hosted/runtimecompilation/RuntimeCompiledMethod.java b/substratevm/src/com.oracle.svm.graal/src/com/oracle/svm/graal/hosted/runtimecompilation/RuntimeCompiledMethod.java new file mode 100644 index 000000000000..427c9641640c --- /dev/null +++ b/substratevm/src/com.oracle.svm.graal/src/com/oracle/svm/graal/hosted/runtimecompilation/RuntimeCompiledMethod.java @@ -0,0 +1,80 @@ +/* + * Copyright (c) 2023, 2023, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.svm.graal.hosted.runtimecompilation; + +import static com.oracle.svm.common.meta.MultiMethod.ORIGINAL_METHOD; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; + +import com.oracle.graal.pointsto.meta.AnalysisMethod; +import com.oracle.svm.common.meta.MultiMethod; +import com.oracle.svm.hosted.code.SubstrateCompilationDirectives; + +import jdk.vm.ci.meta.ResolvedJavaMethod; + +public class RuntimeCompiledMethod { + final AnalysisMethod runtimeMethod; + final AnalysisMethod originalMethod; + + /** + * Collection of all methods inlined into this method. All methods contained here are of the + * {@link MultiMethod#ORIGINAL_METHOD} type. + */ + final Collection inlinedMethods; + + RuntimeCompiledMethod(AnalysisMethod runtimeMethod, Collection inlinedMethods) { + this.runtimeMethod = runtimeMethod; + assert SubstrateCompilationDirectives.isRuntimeCompiledMethod(runtimeMethod) : runtimeMethod; + this.originalMethod = runtimeMethod.getMultiMethod(ORIGINAL_METHOD); + assert originalMethod != null; + this.inlinedMethods = inlinedMethods; + } + + public AnalysisMethod getRuntimeMethod() { + return runtimeMethod; + } + + public AnalysisMethod getOriginalMethod() { + return originalMethod; + } + + public Collection getInlinedMethods() { + return inlinedMethods; + } + + public Collection getInvokeTargets() { + List targets = new ArrayList<>(); + for (var invoke : runtimeMethod.getInvokes()) { + if (invoke.isDeoptInvokeTypeFlow()) { + // deopt invoke type flows are not real targets + continue; + } + targets.add(invoke.getTargetMethod()); + } + return targets; + } +} diff --git a/substratevm/src/com.oracle.svm.graal/src/com/oracle/svm/graal/hosted/runtimecompilation/RuntimeCompiledMethodSupport.java b/substratevm/src/com.oracle.svm.graal/src/com/oracle/svm/graal/hosted/runtimecompilation/RuntimeCompiledMethodSupport.java new file mode 100644 index 000000000000..954cdc5616b8 --- /dev/null +++ b/substratevm/src/com.oracle.svm.graal/src/com/oracle/svm/graal/hosted/runtimecompilation/RuntimeCompiledMethodSupport.java @@ -0,0 +1,570 @@ +/* + * Copyright (c) 2023, 2023, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.svm.graal.hosted.runtimecompilation; + +import static com.oracle.svm.common.meta.MultiMethod.DEOPT_TARGET_METHOD; +import static com.oracle.svm.common.meta.MultiMethod.ORIGINAL_METHOD; +import static com.oracle.svm.hosted.code.SubstrateCompilationDirectives.RUNTIME_COMPILED_METHOD; + +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.concurrent.ConcurrentHashMap; +import java.util.function.Function; +import java.util.stream.Stream; + +import org.graalvm.collections.EconomicMap; +import org.graalvm.word.LocationIdentity; + +import com.oracle.graal.pointsto.BigBang; +import com.oracle.graal.pointsto.heap.ImageHeapConstant; +import com.oracle.graal.pointsto.heap.ImageHeapScanner; +import com.oracle.graal.pointsto.meta.AnalysisField; +import com.oracle.graal.pointsto.meta.AnalysisMethod; +import com.oracle.graal.pointsto.meta.HostedProviders; +import com.oracle.graal.pointsto.meta.PointsToAnalysisMethod; +import com.oracle.graal.pointsto.util.CompletionExecutor; +import com.oracle.svm.core.config.ConfigurationValues; +import com.oracle.svm.core.graal.nodes.DeoptEntryNode; +import com.oracle.svm.core.graal.nodes.DeoptEntrySupport; +import com.oracle.svm.core.graal.nodes.DeoptProxyAnchorNode; +import com.oracle.svm.core.graal.nodes.ThrowBytecodeExceptionNode; +import com.oracle.svm.core.option.HostedOptionKey; +import com.oracle.svm.core.util.VMError; +import com.oracle.svm.hosted.HeapBreakdownProvider; +import com.oracle.svm.hosted.SVMHost; +import com.oracle.svm.hosted.ameta.AnalysisConstantFieldProvider; +import com.oracle.svm.hosted.ameta.AnalysisConstantReflectionProvider; +import com.oracle.svm.hosted.classinitialization.ClassInitializationSupport; +import com.oracle.svm.hosted.code.CompileQueue; +import com.oracle.svm.hosted.code.DeoptimizationUtils; +import com.oracle.svm.hosted.code.SubstrateCompilationDirectives; +import com.oracle.svm.hosted.meta.HostedConstantFieldProvider; +import com.oracle.svm.hosted.meta.HostedField; +import com.oracle.svm.hosted.meta.HostedMethod; +import com.oracle.svm.hosted.meta.HostedUniverse; +import com.oracle.svm.hosted.nodes.DeoptProxyNode; +import com.oracle.svm.hosted.phases.AnalysisGraphBuilderPhase; + +import jdk.graal.compiler.core.common.spi.ConstantFieldProvider; +import jdk.graal.compiler.debug.DebugContext; +import jdk.graal.compiler.debug.DebugHandlersFactory; +import jdk.graal.compiler.java.BytecodeParser; +import jdk.graal.compiler.java.GraphBuilderPhase; +import jdk.graal.compiler.loop.phases.ConvertDeoptimizeToGuardPhase; +import jdk.graal.compiler.nodes.CallTargetNode; +import jdk.graal.compiler.nodes.FrameState; +import jdk.graal.compiler.nodes.GraphDecoder; +import jdk.graal.compiler.nodes.GraphEncoder; +import jdk.graal.compiler.nodes.StateSplit; +import jdk.graal.compiler.nodes.StructuredGraph; +import jdk.graal.compiler.nodes.ValueNode; +import jdk.graal.compiler.nodes.extended.BytecodeExceptionNode; +import jdk.graal.compiler.nodes.graphbuilderconf.GraphBuilderConfiguration; +import jdk.graal.compiler.nodes.graphbuilderconf.IntrinsicContext; +import jdk.graal.compiler.nodes.java.ExceptionObjectNode; +import jdk.graal.compiler.options.Option; +import jdk.graal.compiler.options.OptionValues; +import jdk.graal.compiler.phases.OptimisticOptimizations; +import jdk.graal.compiler.phases.Phase; +import jdk.graal.compiler.phases.PhaseSuite; +import jdk.graal.compiler.phases.common.CanonicalizerPhase; +import jdk.graal.compiler.phases.common.DominatorBasedGlobalValueNumberingPhase; +import jdk.graal.compiler.phases.common.IterativeConditionalEliminationPhase; +import jdk.graal.compiler.phases.tiers.HighTierContext; +import jdk.graal.compiler.phases.util.Providers; +import jdk.graal.compiler.printer.GraalDebugHandlersFactory; +import jdk.graal.compiler.truffle.nodes.ObjectLocationIdentity; +import jdk.vm.ci.code.Architecture; +import jdk.vm.ci.code.BytecodeFrame; +import jdk.vm.ci.meta.JavaConstant; +import jdk.vm.ci.meta.JavaKind; +import jdk.vm.ci.meta.MetaAccessProvider; +import jdk.vm.ci.meta.ResolvedJavaField; +import jdk.vm.ci.meta.ResolvedJavaMethod; + +/** + * This class infrastructure needed for creating the RuntimeCompiledMethods variants. + */ +public class RuntimeCompiledMethodSupport { + + public static class Options { + @Option(help = "Remove Deopt(Entries,Anchors,Proxies) determined to be unneeded after the runtime compiled graphs have been finalized.")// + public static final HostedOptionKey RemoveUnneededDeoptSupport = new HostedOptionKey<>(true); + } + + private record CompilationState( + GraalGraphObjectReplacer objectReplacer, + GraphEncoder graphEncoder, + HostedProviders runtimeCompilationProviders, + ImageHeapScanner heapScanner, + Map runtimeGraphs, + Set registeredRuntimeCompilations) { + } + + public static void onCompileQueueCreation(BigBang bb, HostedUniverse hUniverse, CompileQueue compileQueue, HostedProviders hostedProviders, + Function constantFieldProviderWrapper, + GraalGraphObjectReplacer objectReplacer, Set registeredRuntimeCompilations, Stream methodsToCompile) { + + ImageHeapScanner imageScanner = bb.getUniverse().getHeapScanner(); + + GraphEncoder graphEncoder = new RuntimeCompiledMethodSupport.RuntimeCompilationGraphEncoder(ConfigurationValues.getTarget().arch, imageScanner); + HostedProviders runtimeCompilationProviders = hostedProviders + .copyWith(constantFieldProviderWrapper.apply(new RuntimeCompilationFieldProvider(hostedProviders.getMetaAccess(), hUniverse))) + .copyWith(new RuntimeCompilationReflectionProvider(bb, hUniverse.hostVM().getClassInitializationSupport())); + + SubstrateCompilationDirectives.singleton().resetDeoptEntries(); + + CompilationState compilationState = new CompilationState(objectReplacer, graphEncoder, runtimeCompilationProviders, imageScanner, new ConcurrentHashMap<>(), + registeredRuntimeCompilations); + + /* + * Customize runtime compile methods for compiling them into substrate graphs. + */ + CompletionExecutor executor = compileQueue.getExecutor(); + try { + compileQueue.runOnExecutor(() -> { + methodsToCompile.forEach(method -> { + executor.execute(new RuntimeCompileTask(method, compilationState)); + }); + }); + } catch (InterruptedException exception) { + VMError.shouldNotReachHere(exception); + } + + encodeRuntimeCompiledMethods(compilationState); + + /* + * For Deoptimization Targets add a custom phase which removes all deoptimization + * entrypoints which are deemed no longer necessary. + */ + CompileQueue.ParseHooks deoptParseHooks = new CompileQueue.ParseHooks(compileQueue) { + @Override + protected PhaseSuite getAfterParseSuite() { + PhaseSuite suite = super.getAfterParseSuite(); + if (Options.RemoveUnneededDeoptSupport.getValue()) { + suite.prependPhase(new RemoveUnneededDeoptSupport()); + } + + return suite; + } + }; + + hUniverse.getMethods().stream().map(method -> method.getMultiMethod(DEOPT_TARGET_METHOD)).filter(method -> { + if (method != null) { + return compileQueue.isRegisteredDeoptTarget(method); + } + return false; + }).forEach(method -> method.compilationInfo.setCustomParseHooks(deoptParseHooks)); + + } + + private static class RuntimeCompileTask implements CompletionExecutor.DebugContextRunnable { + final HostedMethod method; + final CompilationState compilationState; + + RuntimeCompileTask(HostedMethod method, CompilationState compilationState) { + this.method = method; + this.compilationState = compilationState; + } + + @Override + public DebugContext getDebug(OptionValues options, List factories) { + return new DebugContext.Builder(options, factories).description(getDescription()).build(); + } + + @Override + public void run(DebugContext debug) { + compileRuntimeCompiledMethod(debug, method); + } + + @SuppressWarnings("try") + private void compileRuntimeCompiledMethod(DebugContext debug, HostedMethod method) { + assert method.getMultiMethodKey() == RUNTIME_COMPILED_METHOD; + + AnalysisMethod aMethod = method.getWrapped(); + StructuredGraph graph = aMethod.decodeAnalyzedGraph(debug, null, false, + (arch, analyzedGraph) -> new RuntimeCompilationGraphDecoder(arch, analyzedGraph, compilationState.heapScanner)); + if (graph == null) { + throw VMError.shouldNotReachHere("Method not parsed during static analysis: " + aMethod.format("%r %H.%n(%p)")); + } + /* + * The graph in the analysis universe is no longer necessary once it is transplanted + * into the hosted universe. + */ + aMethod.setAnalyzedGraph(null); + + try (DebugContext.Scope s = debug.scope("RuntimeOptimize", graph, method, this)) { + CanonicalizerPhase canonicalizer = CanonicalizerPhase.create(); + canonicalizer.apply(graph, compilationState.runtimeCompilationProviders); + + new DominatorBasedGlobalValueNumberingPhase(canonicalizer).apply(graph, compilationState.runtimeCompilationProviders); + + new IterativeConditionalEliminationPhase(canonicalizer, true).apply(graph, compilationState.runtimeCompilationProviders); + + /* + * ConvertDeoptimizeToGuardPhase was already executed after parsing, but + * optimizations applied in between can provide new potential. + */ + new ConvertDeoptimizeToGuardPhase(canonicalizer).apply(graph, compilationState.runtimeCompilationProviders); + + /* + * More optimizations can be added here. + */ + } catch (Throwable e) { + throw debug.handle(e); + } + + /* + * Registering all deopt entries seen within the optimized graph. This should be + * strictly a subset of the deopt entrypoints seen during evaluation. + */ + AnalysisMethod origMethod = method.getMultiMethod(ORIGINAL_METHOD).getWrapped(); + DeoptimizationUtils.registerDeoptEntries(graph, compilationState.registeredRuntimeCompilations.contains(origMethod), + (deoptEntryMethod -> { + PointsToAnalysisMethod deoptMethod = (PointsToAnalysisMethod) ((PointsToAnalysisMethod) deoptEntryMethod).getMultiMethod(DEOPT_TARGET_METHOD); + VMError.guarantee(deoptMethod != null, "New deopt target method seen: %s", deoptEntryMethod); + return deoptMethod; + })); + + assert verifyNodes(graph); + var previous = compilationState.runtimeGraphs.put(method, graph); + assert previous == null; + + // graph encoder is not currently threadsafe + synchronized (compilationState.graphEncoder) { + compilationState.graphEncoder.prepare(graph); + } + } + } + + /** + * Checks if any illegal nodes are present within the graph. Runtime Compiled methods should + * never have explicit BytecodeExceptions; instead they should have deoptimizations. + */ + static boolean verifyNodes(StructuredGraph graph) { + for (var node : graph.getNodes()) { + boolean invalidNodeKind = node instanceof BytecodeExceptionNode || node instanceof ThrowBytecodeExceptionNode; + assert !invalidNodeKind : "illegal node in graph: " + node + " method: " + graph.method(); + } + return true; + } + + @SuppressWarnings("try") + private static void encodeRuntimeCompiledMethods(CompilationState compilationState) { + compilationState.graphEncoder.finishPrepare(); + + // at this point no new deoptimization entrypoints can be registered. + SubstrateCompilationDirectives.singleton().sealDeoptimizationInfo(); + + for (var runtimeInfo : compilationState.runtimeGraphs.entrySet()) { + var graph = runtimeInfo.getValue(); + var method = runtimeInfo.getKey(); + DebugContext debug = new DebugContext.Builder(graph.getOptions(), new GraalDebugHandlersFactory(compilationState.runtimeCompilationProviders.getSnippetReflection())).build(); + graph.resetDebug(debug); + try (DebugContext.Scope s = debug.scope("Graph Encoding", graph); + DebugContext.Activation a = debug.activate()) { + long startOffset = compilationState.graphEncoder.encode(graph); + compilationState.objectReplacer.createMethod(method).setEncodedGraphStartOffset(startOffset); + } catch (Throwable ex) { + debug.handle(ex); + } + } + + HeapBreakdownProvider.singleton().setGraphEncodingByteLength(compilationState.graphEncoder.getEncoding().length); + com.oracle.svm.graal.TruffleRuntimeCompilationSupport.setGraphEncoding(null, compilationState.graphEncoder.getEncoding(), compilationState.graphEncoder.getObjects(), + compilationState.graphEncoder.getNodeClasses()); + + compilationState.objectReplacer.setMethodsImplementations(); + } + + /** + * Since we perform runtime compilation after universe creation, we can leverage components of + * the hosted universe provider for identifying final fields. + */ + static class RuntimeCompilationFieldProvider extends AnalysisConstantFieldProvider { + final HostedUniverse hUniverse; + + RuntimeCompilationFieldProvider(MetaAccessProvider metaAccess, HostedUniverse hUniverse) { + super(metaAccess, hUniverse.hostVM()); + this.hUniverse = hUniverse; + } + + @Override + public boolean isFinalField(ResolvedJavaField f, ConstantFieldTool tool) { + HostedField hField = hUniverse.lookup(f); + if (HostedConstantFieldProvider.isFinalField(hField)) { + return true; + } + return super.isFinalField(f, tool); + } + } + + static class RuntimeCompilationReflectionProvider extends AnalysisConstantReflectionProvider { + + RuntimeCompilationReflectionProvider(BigBang bb, ClassInitializationSupport classInitializationSupport) { + super(bb.getUniverse(), bb.getMetaAccess(), classInitializationSupport); + } + + @Override + public JavaConstant readFieldValue(ResolvedJavaField field, JavaConstant receiver) { + /* + * We cannot fold simulated values during initial before-analysis graph creation; + * however, this runs after analysis has completed. + */ + return readValue(metaAccess, (AnalysisField) field, receiver, true); + } + } + + /** + * A graph encoder that unwraps the {@link ImageHeapConstant} objects. This is used both after + * analysis and after compilation. The corresponding graph decoder used during AOT compilation, + * {@link RuntimeCompilationGraphDecoder}, looks-up the constant in the shadow heap and re-wraps + * it. + *

    + * The reason why we need to unwrap the {@link ImageHeapConstant}s after analysis, and not only + * when we finally encode the graphs for run time compilation, is because the values in + * {@link GraphEncoder#objectsArray} are captured in GraalSupport#graphObjects and + * SubstrateReplacements#snippetObjects which are then scanned. + */ + public static class RuntimeCompilationGraphEncoder extends GraphEncoder { + + private final ImageHeapScanner heapScanner; + /** + * Cache already converted location identity objects to avoid creating multiple new + * instances for the same underlying location identity. + */ + private final Map locationIdentityCache; + + public RuntimeCompilationGraphEncoder(Architecture architecture, ImageHeapScanner heapScanner) { + super(architecture); + this.heapScanner = heapScanner; + this.locationIdentityCache = new ConcurrentHashMap<>(); + } + + @Override + protected void addObject(Object object) { + super.addObject(unwrap(object)); + } + + @Override + protected void writeObjectId(Object object) { + super.writeObjectId(unwrap(object)); + } + + @Override + protected GraphDecoder graphDecoderForVerification(StructuredGraph decodedGraph) { + return new RuntimeCompilationGraphDecoder(architecture, decodedGraph, heapScanner); + } + + private Object unwrap(Object object) { + if (object instanceof ImageHeapConstant ihc) { + VMError.guarantee(ihc.getHostedObject() != null); + return ihc.getHostedObject(); + } else if (object instanceof ObjectLocationIdentity oli && oli.getObject() instanceof ImageHeapConstant heapConstant) { + return locationIdentityCache.computeIfAbsent(heapConstant, (hc) -> ObjectLocationIdentity.create(hc.getHostedObject())); + } + return object; + } + } + + static class RuntimeCompilationGraphDecoder extends GraphDecoder { + + private final ImageHeapScanner heapScanner; + /** + * Cache already converted location identity objects to avoid creating multiple new + * instances for the same underlying location identity. + */ + private final Map locationIdentityCache; + + RuntimeCompilationGraphDecoder(Architecture architecture, StructuredGraph graph, ImageHeapScanner heapScanner) { + super(architecture, graph); + this.heapScanner = heapScanner; + this.locationIdentityCache = new ConcurrentHashMap<>(); + } + + @Override + protected Object readObject(MethodScope methodScope) { + Object object = super.readObject(methodScope); + if (object instanceof JavaConstant constant) { + return heapScanner.getImageHeapConstant(constant); + } else if (object instanceof ObjectLocationIdentity oli) { + return locationIdentityCache.computeIfAbsent(oli.getObject(), (obj) -> ObjectLocationIdentity.create(heapScanner.getImageHeapConstant(obj))); + } + return object; + } + } + + static final class RuntimeGraphBuilderPhase extends AnalysisGraphBuilderPhase { + + private RuntimeGraphBuilderPhase(Providers providers, + GraphBuilderConfiguration graphBuilderConfig, OptimisticOptimizations optimisticOpts, IntrinsicContext initialIntrinsicContext, SVMHost hostVM) { + super(providers, graphBuilderConfig, optimisticOpts, initialIntrinsicContext, hostVM); + } + + static RuntimeGraphBuilderPhase createRuntimeGraphBuilderPhase(BigBang bb, Providers providers, + GraphBuilderConfiguration graphBuilderConfig, OptimisticOptimizations optimisticOpts) { + + // Adjust graphbuilderconfig to match analysis phase + var newGraphBuilderConfig = graphBuilderConfig.withEagerResolving(true).withUnresolvedIsError(false); + return new RuntimeGraphBuilderPhase(providers, newGraphBuilderConfig, optimisticOpts, null, (SVMHost) bb.getHostVM()); + } + + @Override + protected BytecodeParser createBytecodeParser(StructuredGraph graph, BytecodeParser parent, ResolvedJavaMethod method, int entryBCI, IntrinsicContext intrinsicContext) { + return new RuntimeBytecodeParser(this, graph, parent, method, entryBCI, intrinsicContext, hostVM); + } + } + + private static final class RuntimeBytecodeParser extends AnalysisGraphBuilderPhase.AnalysisBytecodeParser { + + RuntimeBytecodeParser(GraphBuilderPhase.Instance graphBuilderInstance, StructuredGraph graph, BytecodeParser parent, ResolvedJavaMethod method, int entryBCI, + IntrinsicContext intrinsicContext, SVMHost svmHost) { + super(graphBuilderInstance, graph, parent, method, entryBCI, intrinsicContext, svmHost, false); + } + + @Override + protected boolean tryInvocationPlugin(CallTargetNode.InvokeKind invokeKind, ValueNode[] args, ResolvedJavaMethod targetMethod, JavaKind resultType) { + boolean result = super.tryInvocationPlugin(invokeKind, args, targetMethod, resultType); + if (result) { + SubstrateCompilationDirectives.singleton().registerAsDeoptInlininingExclude(targetMethod); + } + return result; + } + + @Override + protected boolean shouldVerifyFrameStates() { + /* + * (GR-46115) Ideally we should verify frame states in methods registered for runtime + * compilations, as well as any other methods that can deoptimize. Because runtime + * compiled methods can pull in almost arbitrary code, this means most frame states + * should be verified. We currently use illegal states as placeholders in many places, + * so this cannot be enabled at the moment. + */ + return false; + } + } + + /** + * Removes {@link DeoptEntryNode}s, {@link DeoptProxyAnchorNode}s, and {@link DeoptProxyNode}s + * which are determined to be unnecessary after the runtime compilation methods are optimized. + */ + private static class RemoveUnneededDeoptSupport extends Phase { + enum RemovalDecision { + KEEP, + PROXIFY, + REMOVE + } + + @Override + protected void run(StructuredGraph graph) { + EconomicMap decisionCache = EconomicMap.create(); + + // First go through and delete all unneeded proxies + for (DeoptProxyNode proxyNode : graph.getNodes(DeoptProxyNode.TYPE).snapshot()) { + ValueNode proxyPoint = proxyNode.getProxyPoint(); + if (proxyPoint instanceof StateSplit) { + if (getDecision((StateSplit) proxyPoint, decisionCache) == RemovalDecision.REMOVE) { + proxyNode.replaceAtAllUsages(proxyNode.getOriginalNode(), true); + proxyNode.safeDelete(); + } + } + } + + // Next, remove all unneeded DeoptEntryNodes + for (DeoptEntryNode deoptEntry : graph.getNodes().filter(DeoptEntryNode.class).snapshot()) { + switch (getDecision(deoptEntry, decisionCache)) { + case REMOVE -> { + deoptEntry.killExceptionEdge(); + graph.removeSplit(deoptEntry, deoptEntry.getPrimarySuccessor()); + } + case PROXIFY -> { + deoptEntry.killExceptionEdge(); + DeoptProxyAnchorNode newAnchor = graph.add(new DeoptProxyAnchorNode(deoptEntry.getProxifiedInvokeBci())); + newAnchor.setStateAfter(deoptEntry.stateAfter()); + graph.replaceSplitWithFixed(deoptEntry, newAnchor, deoptEntry.getPrimarySuccessor()); + } + } + } + + // Finally, remove all unneeded DeoptProxyAnchorNodes + for (DeoptProxyAnchorNode proxyAnchor : graph.getNodes().filter(DeoptProxyAnchorNode.class).snapshot()) { + if (getDecision(proxyAnchor, decisionCache) == RemovalDecision.REMOVE) { + graph.removeFixed(proxyAnchor); + } + } + } + + RemovalDecision getDecision(StateSplit node, EconomicMap decisionCache) { + RemovalDecision cached = decisionCache.get(node); + if (cached != null) { + return cached; + } + + DeoptEntrySupport proxyNode; + if (node instanceof ExceptionObjectNode exceptionObject) { + /* + * For the exception edge of a DeoptEntryNode, we insert the proxies on the + * exception object. + */ + proxyNode = (DeoptEntrySupport) exceptionObject.predecessor(); + } else { + proxyNode = (DeoptEntrySupport) node; + } + + RemovalDecision decision = RemovalDecision.REMOVE; + var directive = SubstrateCompilationDirectives.singleton(); + FrameState state = proxyNode.stateAfter(); + HostedMethod method = (HostedMethod) state.getMethod(); + if (proxyNode instanceof DeoptEntryNode) { + if (directive.isDeoptEntry(method, state.bci, state.getStackState())) { + // must keep all deopt entries which are still guarding nodes + decision = RemovalDecision.KEEP; + } + } + + if (decision == RemovalDecision.REMOVE) { + // now check for any implicit deopt entry being protected against + int proxifiedInvokeBci = proxyNode.getProxifiedInvokeBci(); + if (proxifiedInvokeBci != BytecodeFrame.UNKNOWN_BCI && directive.isDeoptEntry(method, proxifiedInvokeBci, FrameState.StackState.AfterPop)) { + // must keep still keep a proxy for nodes which are "proxifying" an invoke + decision = proxyNode instanceof DeoptEntryNode ? RemovalDecision.PROXIFY : RemovalDecision.KEEP; + } + } + + // cache the decision + decisionCache.put(node, decision); + if (proxyNode != node) { + decisionCache.put(proxyNode, decision); + } + return decision; + } + + @Override + public CharSequence getName() { + return "RemoveUnneededDeoptSupport"; + } + } +} diff --git a/substratevm/src/com.oracle.svm.graal/src/com/oracle/svm/graal/hosted/SubstrateGraalCompilerSetup.java b/substratevm/src/com.oracle.svm.graal/src/com/oracle/svm/graal/hosted/runtimecompilation/SubstrateGraalCompilerSetup.java similarity index 98% rename from substratevm/src/com.oracle.svm.graal/src/com/oracle/svm/graal/hosted/SubstrateGraalCompilerSetup.java rename to substratevm/src/com.oracle.svm.graal/src/com/oracle/svm/graal/hosted/runtimecompilation/SubstrateGraalCompilerSetup.java index 43b70d36c3d8..8124c7ddc8da 100644 --- a/substratevm/src/com.oracle.svm.graal/src/com/oracle/svm/graal/hosted/SubstrateGraalCompilerSetup.java +++ b/substratevm/src/com.oracle.svm.graal/src/com/oracle/svm/graal/hosted/runtimecompilation/SubstrateGraalCompilerSetup.java @@ -22,7 +22,7 @@ * or visit www.oracle.com if you need additional information or have any * questions. */ -package com.oracle.svm.graal.hosted; +package com.oracle.svm.graal.hosted.runtimecompilation; import java.util.function.Function; diff --git a/substratevm/src/com.oracle.svm.graal/src/com/oracle/svm/graal/hosted/SubstrateProviders.java b/substratevm/src/com.oracle.svm.graal/src/com/oracle/svm/graal/hosted/runtimecompilation/SubstrateProviders.java similarity index 98% rename from substratevm/src/com.oracle.svm.graal/src/com/oracle/svm/graal/hosted/SubstrateProviders.java rename to substratevm/src/com.oracle.svm.graal/src/com/oracle/svm/graal/hosted/runtimecompilation/SubstrateProviders.java index c05496a5cd8a..cd135cee5ec0 100644 --- a/substratevm/src/com.oracle.svm.graal/src/com/oracle/svm/graal/hosted/SubstrateProviders.java +++ b/substratevm/src/com.oracle.svm.graal/src/com/oracle/svm/graal/hosted/runtimecompilation/SubstrateProviders.java @@ -22,7 +22,7 @@ * or visit www.oracle.com if you need additional information or have any * questions. */ -package com.oracle.svm.graal.hosted; +package com.oracle.svm.graal.hosted.runtimecompilation; import com.oracle.graal.pointsto.meta.AnalysisMetaAccess; import com.oracle.svm.core.graal.meta.SubstrateSnippetReflectionProvider; diff --git a/substratevm/src/com.oracle.svm.graal/src/com/oracle/svm/graal/isolated/IsolateAwareProviders.java b/substratevm/src/com.oracle.svm.graal/src/com/oracle/svm/graal/isolated/IsolateAwareProviders.java index c0d50ef2ffea..88c434d54775 100644 --- a/substratevm/src/com.oracle.svm.graal/src/com/oracle/svm/graal/isolated/IsolateAwareProviders.java +++ b/substratevm/src/com.oracle.svm.graal/src/com/oracle/svm/graal/isolated/IsolateAwareProviders.java @@ -25,7 +25,7 @@ package com.oracle.svm.graal.isolated; import com.oracle.graal.pointsto.meta.AnalysisMetaAccess; -import com.oracle.svm.graal.hosted.SubstrateProviders; +import com.oracle.svm.graal.hosted.runtimecompilation.SubstrateProviders; import com.oracle.svm.graal.meta.SubstrateConstantFieldProvider; public final class IsolateAwareProviders extends SubstrateProviders { diff --git a/substratevm/src/com.oracle.svm.graal/src/com/oracle/svm/graal/substitutions/GraalSubstitutions.java b/substratevm/src/com.oracle.svm.graal/src/com/oracle/svm/graal/substitutions/GraalSubstitutions.java index b6fb0a8b5d25..4c43000bf0dc 100644 --- a/substratevm/src/com.oracle.svm.graal/src/com/oracle/svm/graal/substitutions/GraalSubstitutions.java +++ b/substratevm/src/com.oracle.svm.graal/src/com/oracle/svm/graal/substitutions/GraalSubstitutions.java @@ -63,7 +63,7 @@ import com.oracle.svm.graal.TruffleRuntimeCompilationSupport; import com.oracle.svm.graal.hosted.FieldsOffsetsFeature; import com.oracle.svm.graal.hosted.GraalCompilerFeature; -import com.oracle.svm.graal.hosted.RuntimeCompilationFeature; +import com.oracle.svm.graal.hosted.runtimecompilation.RuntimeCompilationFeature; import com.oracle.svm.graal.meta.SubstrateMethod; import com.oracle.svm.util.ReflectionUtil; diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/NativeImageGenerator.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/NativeImageGenerator.java index fbce62ddb497..4b2b2f91a1af 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/NativeImageGenerator.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/NativeImageGenerator.java @@ -648,8 +648,8 @@ protected void doRun(Map entryPoints, JavaMainSupport j CompileQueue compileQueue; try (StopTimer t = TimerCollection.createTimerAndStart(TimerCollection.Registry.COMPILE_TOTAL)) { compileQueue = HostedConfiguration.instance().createCompileQueue(debug, featureHandler, hUniverse, runtimeConfiguration, DeoptTester.enabled(), bb.getSnippetReflectionProvider()); - if (ImageSingletons.contains(RuntimeCompilationSupport.class)) { - ImageSingletons.lookup(RuntimeCompilationSupport.class).onCompileQueueCreation(bb, hUniverse, compileQueue); + if (ImageSingletons.contains(RuntimeCompilationCallbacks.class)) { + ImageSingletons.lookup(RuntimeCompilationCallbacks.class).onCompileQueueCreation(bb, hUniverse, compileQueue); } compileQueue.finish(debug); BuildPhaseProvider.markCompileQueueFinished(); @@ -799,8 +799,16 @@ protected boolean runPointsToAnalysis(String imageName, OptionValues options, De } return !config.getAndResetRequireAnalysisIteration(); }); - } catch (AnalysisError e) { - throw UserError.abort(e, "Analysis step failed. Reason: %s.", e.getMessage()); + } catch (Throwable t) { + if (ImageSingletons.contains(RuntimeCompilationCallbacks.class)) { + ImageSingletons.lookup(RuntimeCompilationCallbacks.class).reportAnalysisError(aUniverse, t); + } + + if (t instanceof AnalysisError e) { + throw UserError.abort(e, "Analysis step failed. Reason: %s.", e.getMessage()); + } else { + throw t; + } } assert verifyAssignableTypes(); diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/RuntimeCompilationSupport.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/RuntimeCompilationCallbacks.java similarity index 89% rename from substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/RuntimeCompilationSupport.java rename to substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/RuntimeCompilationCallbacks.java index a6530ef70880..d1a6414c64fc 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/RuntimeCompilationSupport.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/RuntimeCompilationCallbacks.java @@ -25,9 +25,12 @@ package com.oracle.svm.hosted; import com.oracle.graal.pointsto.BigBang; +import com.oracle.graal.pointsto.meta.AnalysisUniverse; import com.oracle.svm.hosted.code.CompileQueue; import com.oracle.svm.hosted.meta.HostedUniverse; -public interface RuntimeCompilationSupport { +public interface RuntimeCompilationCallbacks { void onCompileQueueCreation(BigBang bb, HostedUniverse hUniverse, CompileQueue compileQueue); + + void reportAnalysisError(AnalysisUniverse aUniverse, Throwable error); } diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/analysis/SVMParsingSupport.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/analysis/SVMParsingSupport.java index ae0911f99a81..ee2b1cc5d8dc 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/analysis/SVMParsingSupport.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/analysis/SVMParsingSupport.java @@ -26,10 +26,6 @@ import java.util.function.Function; -import jdk.graal.compiler.debug.DebugContext; -import jdk.graal.compiler.nodes.StructuredGraph; -import jdk.graal.compiler.nodes.graphbuilderconf.GraphBuilderConfiguration; - import com.oracle.graal.pointsto.BigBang; import com.oracle.graal.pointsto.PointsToAnalysis; import com.oracle.graal.pointsto.meta.AnalysisMethod; @@ -40,6 +36,9 @@ import com.oracle.svm.hosted.SVMHost; import com.oracle.svm.hosted.phases.InlineBeforeAnalysisPolicyUtils; +import jdk.graal.compiler.debug.DebugContext; +import jdk.graal.compiler.nodes.StructuredGraph; +import jdk.graal.compiler.nodes.graphbuilderconf.GraphBuilderConfiguration; import jdk.vm.ci.meta.ResolvedJavaType; /** diff --git a/substratevm/src/com.oracle.svm.truffle/src/com/oracle/svm/truffle/TruffleBaseFeature.java b/substratevm/src/com.oracle.svm.truffle/src/com/oracle/svm/truffle/TruffleBaseFeature.java index a91e7eef28d0..1c430527e219 100644 --- a/substratevm/src/com.oracle.svm.truffle/src/com/oracle/svm/truffle/TruffleBaseFeature.java +++ b/substratevm/src/com.oracle.svm.truffle/src/com/oracle/svm/truffle/TruffleBaseFeature.java @@ -102,9 +102,9 @@ import com.oracle.svm.core.reflect.target.ReflectionSubstitutionSupport; import com.oracle.svm.core.util.UserError; import com.oracle.svm.core.util.VMError; -import com.oracle.svm.graal.hosted.GraalGraphObjectReplacer; -import com.oracle.svm.graal.hosted.SubstrateGraalCompilerSetup; -import com.oracle.svm.graal.hosted.SubstrateProviders; +import com.oracle.svm.graal.hosted.runtimecompilation.GraalGraphObjectReplacer; +import com.oracle.svm.graal.hosted.runtimecompilation.SubstrateGraalCompilerSetup; +import com.oracle.svm.graal.hosted.runtimecompilation.SubstrateProviders; import com.oracle.svm.graal.meta.SubstrateUniverseFactory; import com.oracle.svm.hosted.FeatureImpl; import com.oracle.svm.hosted.FeatureImpl.BeforeAnalysisAccessImpl; diff --git a/substratevm/src/com.oracle.svm.truffle/src/com/oracle/svm/truffle/TruffleFeature.java b/substratevm/src/com.oracle.svm.truffle/src/com/oracle/svm/truffle/TruffleFeature.java index e3b26b3e93c3..27f42f9680c7 100644 --- a/substratevm/src/com.oracle.svm.truffle/src/com/oracle/svm/truffle/TruffleFeature.java +++ b/substratevm/src/com.oracle.svm.truffle/src/com/oracle/svm/truffle/TruffleFeature.java @@ -25,9 +25,9 @@ package com.oracle.svm.truffle; -import static com.oracle.svm.graal.hosted.RuntimeCompilationFeature.AllowInliningPredicate.InlineDecision.INLINE; -import static com.oracle.svm.graal.hosted.RuntimeCompilationFeature.AllowInliningPredicate.InlineDecision.INLINING_DISALLOWED; -import static com.oracle.svm.graal.hosted.RuntimeCompilationFeature.AllowInliningPredicate.InlineDecision.NO_DECISION; +import static com.oracle.svm.graal.hosted.runtimecompilation.RuntimeCompilationFeature.AllowInliningPredicate.InlineDecision.INLINE; +import static com.oracle.svm.graal.hosted.runtimecompilation.RuntimeCompilationFeature.AllowInliningPredicate.InlineDecision.INLINING_DISALLOWED; +import static com.oracle.svm.graal.hosted.runtimecompilation.RuntimeCompilationFeature.AllowInliningPredicate.InlineDecision.NO_DECISION; import java.lang.reflect.Executable; import java.lang.reflect.Field; @@ -124,9 +124,10 @@ import com.oracle.svm.core.stack.JavaStackWalker; import com.oracle.svm.core.util.UserError; import com.oracle.svm.core.util.VMError; -import com.oracle.svm.graal.hosted.RuntimeCompilationFeature; -import com.oracle.svm.graal.hosted.RuntimeCompilationFeature.RuntimeCompilationCandidate; -import com.oracle.svm.graal.hosted.RuntimeCompilationFeature.RuntimeCompiledMethod; +import com.oracle.svm.graal.hosted.runtimecompilation.CallTreeInfo; +import com.oracle.svm.graal.hosted.runtimecompilation.RuntimeCompilationCandidate; +import com.oracle.svm.graal.hosted.runtimecompilation.RuntimeCompilationFeature; +import com.oracle.svm.graal.hosted.runtimecompilation.RuntimeCompiledMethod; import com.oracle.svm.hosted.FeatureImpl; import com.oracle.svm.hosted.FeatureImpl.AfterAnalysisAccessImpl; import com.oracle.svm.hosted.FeatureImpl.BeforeAnalysisAccessImpl; @@ -248,7 +249,7 @@ public void registerLowerings(RuntimeConfiguration runtimeConfig, OptionValues o @Override public List> getRequiredFeatures() { - return List.of(RuntimeCompilationFeature.getRuntimeCompilationFeature(), TruffleBaseFeature.class); + return List.of(RuntimeCompilationFeature.class, TruffleBaseFeature.class); } /* @@ -389,7 +390,7 @@ public void beforeAnalysis(BeforeAnalysisAccess access) { runtimeCompilationFeature.getHostedProviders().getLoopsDataProvider()); newHostedProviders.setGraphBuilderPlugins(graphBuilderConfig.getPlugins()); - runtimeCompilationFeature.initializeRuntimeCompilationConfiguration(newHostedProviders, graphBuilderConfig, this::allowRuntimeCompilation, this::deoptimizeOnException); + runtimeCompilationFeature.initializeRuntimeCompilationConfiguration(newHostedProviders, graphBuilderConfig, this::allowRuntimeCompilation, this::deoptimizeOnException, this::checkBlockList); for (ResolvedJavaMethod method : partialEvaluator.getCompilationRootMethods()) { runtimeCompilationFeature.prepareMethodForRuntimeCompilation(method, config); } @@ -780,10 +781,11 @@ private void warnAllMethods(MetaAccessProvider metaAccess, Class clazz) { } } - @Override - public void beforeCompilation(BeforeCompilationAccess config) { - FeatureImpl.BeforeCompilationAccessImpl access = (FeatureImpl.BeforeCompilationAccessImpl) config; + private record BlocklistViolationInfo(RuntimeCompilationCandidate candidate, String[] callTrace) { + }; + private void checkBlockList(CallTreeInfo treeInfo) { + RuntimeCompilationFeature runtimeCompilation = RuntimeCompilationFeature.singleton(); boolean failBlockListViolations; if (Options.TruffleCheckBlackListedMethods.hasBeenSet()) { failBlockListViolations = Options.TruffleCheckBlackListedMethods.getValue(); @@ -792,8 +794,8 @@ public void beforeCompilation(BeforeCompilationAccess config) { } boolean printBlockListViolations = RuntimeCompilationFeature.Options.PrintRuntimeCompileMethods.getValue() || failBlockListViolations; if (printBlockListViolations) { - Set blocklistViolations = new TreeSet<>(RuntimeCompilationFeature.singleton().getRuntimeCompilationComparator()); - for (RuntimeCompilationCandidate candidate : RuntimeCompilationFeature.singleton().getAllRuntimeCompilationCandidates()) { + Set blocklistViolations = new TreeSet<>((o1, o2) -> Arrays.compare(o1.callTrace(), o2.callTrace())); + for (RuntimeCompilationCandidate candidate : runtimeCompilation.getAllRuntimeCompilationCandidates()) { // Determine blocklist violations if (!runtimeCompilationForbidden(candidate.getImplementationMethod())) { @@ -802,7 +804,8 @@ public void beforeCompilation(BeforeCompilationAccess config) { tempTargetAllowlistMethods.contains(candidate.getTargetMethod()) && !isBlocklisted(candidate.getImplementationMethod()); if (!tempAllow) { - blocklistViolations.add(candidate); + BlocklistViolationInfo violation = new BlocklistViolationInfo(candidate, CallTreeInfo.getCallTrace(treeInfo, candidate)); + blocklistViolations.add(violation); } } } @@ -811,11 +814,13 @@ public void beforeCompilation(BeforeCompilationAccess config) { System.out.println(); System.out.println("=== Found " + blocklistViolations.size() + " compilation blocklist violations ==="); System.out.println(); - for (RuntimeCompilationCandidate violation : blocklistViolations) { + for (BlocklistViolationInfo violation : blocklistViolations) { System.out.println("Blocklisted method"); - System.out.format(" %s (target: %s)%n", violation.getImplementationMethod().format("%H.%n(%p)"), violation.getTargetMethod().format("%H.%n(%p)")); + System.out.format(" %s (target: %s)%n", violation.candidate.getImplementationMethod().format("%H.%n(%p)"), violation.candidate.getTargetMethod().format("%H.%n(%p)")); System.out.println("trace:"); - RuntimeCompilationFeature.singleton().getCallTrace(violation).forEach(item -> System.out.println(" " + item)); + for (String item : violation.callTrace()) { + System.out.println(" " + item); + } } if (failBlockListViolations) { throw VMError.shouldNotReachHere("Blocklisted methods are reachable for runtime compilation"); @@ -824,7 +829,7 @@ public void beforeCompilation(BeforeCompilationAccess config) { } Set warnViolations = new HashSet<>(); - for (RuntimeCompilationCandidate node : RuntimeCompilationFeature.singleton().getAllRuntimeCompilationCandidates()) { + for (RuntimeCompilationCandidate node : runtimeCompilation.getAllRuntimeCompilationCandidates()) { var method = node.getImplementationMethod(); if (warnMethods.contains(method)) { warnViolations.add(node); @@ -841,7 +846,9 @@ public void beforeCompilation(BeforeCompilationAccess config) { for (RuntimeCompilationCandidate violation : warnViolations) { System.out.println("Suspicious method: " + violation.getImplementationMethod().format("%H.%n(%p)")); System.out.println("trace:"); - RuntimeCompilationFeature.singleton().getCallTrace(violation).forEach(item -> System.out.println(" " + item)); + for (String item : CallTreeInfo.getCallTrace(treeInfo, violation)) { + System.out.println(" " + item); + } } } @@ -850,10 +857,16 @@ public void beforeCompilation(BeforeCompilationAccess config) { for (Pair violation : neverPartOfCompilationViolations) { System.out.println("called from"); System.out.println("(inlined call path): " + violation.getRight()); - RuntimeCompilationFeature.singleton().getCallTrace(violation.getLeft()).forEach(item -> System.out.println(" " + item)); + for (String item : CallTreeInfo.getCallTrace(treeInfo, (AnalysisMethod) violation.getLeft())) { + System.out.println(" " + item); + } } throw VMError.shouldNotReachHere("CompilerAsserts.neverPartOfCompilation reachable for runtime compilation"); } + } + + @Override + public void beforeCompilation(BeforeCompilationAccess config) { if (Options.TruffleCheckFrameImplementation.getValue()) { /* @@ -865,7 +878,7 @@ public void beforeCompilation(BeforeCompilationAccess config) { * DefaultMaterializedFrame, ReadOnlyFrame) to detect wrong usages of the Frame API, so * we can only check when running with compilation enabled. */ - Optional optionalFrameType = access.getMetaAccess().optionalLookupJavaType(Frame.class); + Optional optionalFrameType = ((FeatureImpl.BeforeCompilationAccessImpl) config).getMetaAccess().optionalLookupJavaType(Frame.class); if (optionalFrameType.isPresent()) { HostedType frameType = (HostedType) optionalFrameType.get(); Set implementations = new HashSet<>(); @@ -919,8 +932,12 @@ private static void collectImplementations(HostedType type, Set impl @Override public void afterAnalysis(AfterAnalysisAccess access) { + CallTreeInfo treeInfo = RuntimeCompilationFeature.singleton().getCallTreeInfo(); + + checkBlockList(treeInfo); + if (Options.PrintStaticTruffleBoundaries.getValue()) { - printStaticTruffleBoundaries(); + printStaticTruffleBoundaries(treeInfo); } SubstrateTruffleRuntime truffleRuntime = (SubstrateTruffleRuntime) Truffle.getRuntime(); @@ -931,9 +948,9 @@ public void afterAnalysis(AfterAnalysisAccess access) { runtimeCompiledMethods.addAll(Arrays.asList(config.getMetaAccess().lookupJavaType(CompilerDirectives.class).getDeclaredMethods(false))); runtimeCompiledMethods.addAll(Arrays.asList(config.getMetaAccess().lookupJavaType(CompilerAsserts.class).getDeclaredMethods(false))); - for (RuntimeCompiledMethod runtimeCompiledMethod : RuntimeCompilationFeature.singleton().getRuntimeCompiledMethods()) { + for (RuntimeCompiledMethod runtimeCompiledMethod : treeInfo.runtimeCompilations()) { - runtimeCompiledMethods.add(runtimeCompiledMethod.getMethod()); + runtimeCompiledMethods.add(runtimeCompiledMethod.getOriginalMethod()); /* * The list of runtime compiled methods is not containing all methods that are always @@ -955,11 +972,11 @@ public void afterAnalysis(AfterAnalysisAccess access) { } } - private static void printStaticTruffleBoundaries() { + private static void printStaticTruffleBoundaries(CallTreeInfo treeInfo) { HashSet foundBoundaries = new HashSet<>(); int callSiteCount = 0; int calleeCount = 0; - for (RuntimeCompiledMethod runtimeCompiledMethod : RuntimeCompilationFeature.singleton().getRuntimeCompiledMethods()) { + for (RuntimeCompiledMethod runtimeCompiledMethod : treeInfo.runtimeCompilations()) { for (ResolvedJavaMethod targetMethod : runtimeCompiledMethod.getInvokeTargets()) { TruffleBoundary truffleBoundary = targetMethod.getAnnotation(TruffleBoundary.class); if (truffleBoundary != null) { diff --git a/substratevm/src/com.oracle.svm.truffle/src/com/oracle/svm/truffle/TruffleSupport.java b/substratevm/src/com.oracle.svm.truffle/src/com/oracle/svm/truffle/TruffleSupport.java index 3f37a934c36f..71542b803ef0 100644 --- a/substratevm/src/com.oracle.svm.truffle/src/com/oracle/svm/truffle/TruffleSupport.java +++ b/substratevm/src/com.oracle.svm.truffle/src/com/oracle/svm/truffle/TruffleSupport.java @@ -28,14 +28,6 @@ import java.util.function.Consumer; import java.util.function.Supplier; -import jdk.graal.compiler.api.replacements.SnippetReflectionProvider; -import jdk.graal.compiler.nodes.graphbuilderconf.GraphBuilderConfiguration; -import jdk.graal.compiler.phases.util.Providers; -import jdk.graal.compiler.truffle.EconomyPartialEvaluatorConfiguration; -import jdk.graal.compiler.truffle.PartialEvaluatorConfiguration; -import jdk.graal.compiler.truffle.TruffleCompilerConfiguration; -import jdk.graal.compiler.truffle.TruffleCompilerImpl; -import jdk.graal.compiler.truffle.TruffleTierConfiguration; import org.graalvm.nativeimage.ImageSingletons; import com.oracle.svm.core.SubstrateOptions; @@ -43,7 +35,7 @@ import com.oracle.svm.core.graal.code.SubstrateBackend; import com.oracle.svm.core.meta.SubstrateObjectConstant; import com.oracle.svm.graal.TruffleRuntimeCompilationSupport; -import com.oracle.svm.graal.hosted.RuntimeCompilationFeature; +import com.oracle.svm.graal.hosted.runtimecompilation.RuntimeCompilationFeature; import com.oracle.svm.truffle.api.SubstrateKnownTruffleTypes; import com.oracle.svm.truffle.api.SubstrateOptimizedCallTarget; import com.oracle.svm.truffle.api.SubstrateOptimizedCallTargetInstalledCode; @@ -64,6 +56,14 @@ import com.oracle.truffle.runtime.OptimizedCallTarget; import com.oracle.truffle.runtime.OptimizedDirectCallNode; +import jdk.graal.compiler.api.replacements.SnippetReflectionProvider; +import jdk.graal.compiler.nodes.graphbuilderconf.GraphBuilderConfiguration; +import jdk.graal.compiler.phases.util.Providers; +import jdk.graal.compiler.truffle.EconomyPartialEvaluatorConfiguration; +import jdk.graal.compiler.truffle.PartialEvaluatorConfiguration; +import jdk.graal.compiler.truffle.TruffleCompilerConfiguration; +import jdk.graal.compiler.truffle.TruffleCompilerImpl; +import jdk.graal.compiler.truffle.TruffleTierConfiguration; import jdk.vm.ci.meta.JavaConstant; public class TruffleSupport { From 80332b8fc2c977e8cec093d142a2d94abc61b919 Mon Sep 17 00:00:00 2001 From: Christian Haeubl Date: Fri, 15 Dec 2023 10:49:47 +0100 Subject: [PATCH 220/593] Add crash log output to exception handling. --- .../core/graal/snippets/CEntryPointSnippets.java | 6 +++--- .../oracle/svm/core/snippets/ExceptionUnwind.java | 14 +++++++------- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/graal/snippets/CEntryPointSnippets.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/graal/snippets/CEntryPointSnippets.java index 5ce47bc3f5e0..83129a008571 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/graal/snippets/CEntryPointSnippets.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/graal/snippets/CEntryPointSnippets.java @@ -38,7 +38,6 @@ import org.graalvm.nativeimage.ImageSingletons; import org.graalvm.nativeimage.Isolate; import org.graalvm.nativeimage.IsolateThread; -import org.graalvm.nativeimage.LogHandler; import org.graalvm.nativeimage.StackValue; import org.graalvm.nativeimage.c.type.CCharPointer; import org.graalvm.nativeimage.c.type.CLongPointer; @@ -716,13 +715,14 @@ private static int reportException(Throwable exception) { private static void reportExceptionInterruptibly(Throwable exception) { logException(exception); - ImageSingletons.lookup(LogHandler.class).fatalError(); + VMError.shouldNotReachHere("Unhandled exception"); } @RestrictHeapAccess(access = NO_ALLOCATION, reason = "Must not allocate in fatal error handling.") private static void logException(Throwable exception) { try { - Log.log().exception(exception).newline(); + Log.log().string("Unhandled exception: "); + Log.log().exception(exception).newline().newline(); } catch (Throwable ex) { /* Logging failed, so there is nothing we can do anymore to log. */ } diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/snippets/ExceptionUnwind.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/snippets/ExceptionUnwind.java index 12ae6a1f6678..7dc1b43ec35b 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/snippets/ExceptionUnwind.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/snippets/ExceptionUnwind.java @@ -28,7 +28,6 @@ import org.graalvm.nativeimage.CurrentIsolate; import org.graalvm.nativeimage.ImageSingletons; -import org.graalvm.nativeimage.LogHandler; import org.graalvm.nativeimage.StackValue; import org.graalvm.nativeimage.c.function.CodePointer; import org.graalvm.nativeimage.hosted.Feature; @@ -57,6 +56,7 @@ import com.oracle.svm.core.thread.VMThreads; import com.oracle.svm.core.threadlocal.FastThreadLocalFactory; import com.oracle.svm.core.threadlocal.FastThreadLocalObject; +import com.oracle.svm.core.util.VMError; public abstract class ExceptionUnwind { @@ -145,8 +145,8 @@ private static void unwindExceptionInterruptible(Throwable exception, Pointer ca */ private static void reportRecursiveUnwind(Throwable exception) { Log.log().string("Fatal error: recursion in exception handling: ").string(exception.getClass().getName()); - Log.log().string(" thrown while unwinding ").string(currentException.get().getClass().getName()).newline(); - ImageSingletons.lookup(LogHandler.class).fatalError(); + Log.log().string(" thrown while unwinding ").string(currentException.get().getClass().getName()).newline().newline(); + VMError.shouldNotReachHere("Recursion in exception handling"); } /** @@ -159,8 +159,8 @@ private static void reportRecursiveUnwind(Throwable exception) { */ private static void reportFatalUnwind(Throwable exception) { Log.log().string("Fatal error: exception unwind while thread is not in Java state: "); - Log.log().exception(exception).newline(); - ImageSingletons.lookup(LogHandler.class).fatalError(); + Log.log().exception(exception).newline().newline(); + VMError.shouldNotReachHere("Exception unwind while thread is not in Java state"); } /** @@ -171,8 +171,8 @@ private static void reportFatalUnwind(Throwable exception) { */ private static void reportUnhandledException(Throwable exception) { Log.log().string("Fatal error: unhandled exception in isolate ").hex(CurrentIsolate.getIsolate()).string(": "); - Log.log().exception(exception).newline(); - ImageSingletons.lookup(LogHandler.class).fatalError(); + Log.log().exception(exception).newline().newline(); + VMError.shouldNotReachHere("Unhandled exception"); } /** Hook to allow a {@link Feature} to install custom exception unwind code. */ From 9e4e7dfd11681597ef2a4b084afedc98a0fea746 Mon Sep 17 00:00:00 2001 From: Christian Haeubl Date: Fri, 15 Dec 2023 11:31:40 +0100 Subject: [PATCH 221/593] Catch exceptions that happen while a thread starts. --- .../com/oracle/svm/core/thread/PlatformThreads.java | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/thread/PlatformThreads.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/thread/PlatformThreads.java index 9d715dbbd980..6407d06ac432 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/thread/PlatformThreads.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/thread/PlatformThreads.java @@ -765,13 +765,14 @@ void startThread(Thread thread, long stackSize) { @SuppressFBWarnings(value = "Ru", justification = "We really want to call Thread.run and not Thread.start because we are in the low-level thread start routine") protected static void threadStartRoutine(ObjectHandle threadHandle) { Thread thread = ObjectHandles.getGlobal().get(threadHandle); - assignCurrent(thread, false); - ObjectHandles.getGlobal().destroy(threadHandle); - - singleton().unattachedStartedThreads.decrementAndGet(); - singleton().beforeThreadRun(thread); try { + assignCurrent(thread, false); + ObjectHandles.getGlobal().destroy(threadHandle); + + singleton().unattachedStartedThreads.decrementAndGet(); + singleton().beforeThreadRun(thread); + if (VMThreads.isTearingDown()) { /* * As a newly started thread, we might not have been interrupted like the Java From b0821d5c3b2c8027beae1a0431cd51f595d44710 Mon Sep 17 00:00:00 2001 From: Josef Eisl Date: Fri, 15 Dec 2023 12:46:11 +0100 Subject: [PATCH 222/593] compiler: strip optional java version part in JVMCIVersionCheck --- .../compiler/hotspot/JVMCIVersionCheck.java | 27 ++++++++++++++++++- 1 file changed, 26 insertions(+), 1 deletion(-) diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/JVMCIVersionCheck.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/JVMCIVersionCheck.java index 096962ee1485..c9dd587ac702 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/JVMCIVersionCheck.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/JVMCIVersionCheck.java @@ -113,13 +113,38 @@ private Version(String jdkVersionString, int jvmciMajor, int jvmciMinor, int jvm } private Version(Runtime.Version jdkVersion, int jvmciMajor, int jvmciMinor, int jvmciBuild, boolean legacy) { - this.jdkVersion = jdkVersion; + this.jdkVersion = stripOptional(jdkVersion); this.jvmciMajor = jvmciMajor; this.jvmciMinor = jvmciMinor; this.jvmciBuild = jvmciBuild; this.legacy = legacy; } + /** + * Gets rid of the {@link Runtime.Version#optional()} part of a version string. See + * {@link Runtime.Version} for details about the version string format. + */ + private static Runtime.Version stripOptional(Runtime.Version jdkVersion) { + if (!jdkVersion.optional().isPresent()) { + return jdkVersion; + } + String jdkVersionStr = jdkVersion.toString(); + final int optionalLength; + if (!jdkVersion.pre().isPresent() && !jdkVersion.build().isPresent()) { + // if we have no $PRE and no $BUILD, then the optional is delimited by "+-" + optionalLength = "+-".length() + jdkVersion.optional().get().length(); + } else { + // else it is only delimited by "-" + optionalLength = "-".length() + jdkVersion.optional().get().length(); + } + Runtime.Version strippedVersion = Runtime.Version.parse(jdkVersionStr.substring(0, jdkVersionStr.length() - optionalLength)); + if (!strippedVersion.equalsIgnoreOptional(jdkVersion)) { + throw new RuntimeException(String.format("%s failed to strip the $OPTIONAL part from the Java Runtime Version string: %s vs %s", JVMCIVersionCheck.class.getSimpleName(), jdkVersion, + strippedVersion)); + } + return strippedVersion; + } + boolean isGreaterThan(Version other) { if (!isLessThan(other)) { return !equals(other); From 8115ac207d2bbdfd407d79406f8cf21ede6ed0f5 Mon Sep 17 00:00:00 2001 From: Christian Haeubl Date: Thu, 7 Dec 2023 15:49:00 +0100 Subject: [PATCH 223/593] Make segfault handler more robust. --- .../aarch64/SubstrateAArch64Backend.java | 86 ++++++------- .../graal/amd64/SubstrateAMD64Backend.java | 4 +- .../svm/core/graal/llvm/NodeLLVMBuilder.java | 73 ++++++----- .../posix/PosixSubstrateSegfaultHandler.java | 4 + .../WindowsSubstrateSegfaultHandler.java | 9 +- .../svm/core/SubstrateSegfaultHandler.java | 116 ++++++++++++++---- .../meta/SubstrateBasicLoweringProvider.java | 46 +++---- .../oracle/svm/core/heap/ObjectHeader.java | 5 - .../oracle/svm/core/heap/ReferenceAccess.java | 12 +- .../svm/core/heap/ReferenceAccessImpl.java | 17 ++- 10 files changed, 230 insertions(+), 142 deletions(-) diff --git a/substratevm/src/com.oracle.svm.core.graal.aarch64/src/com/oracle/svm/core/graal/aarch64/SubstrateAArch64Backend.java b/substratevm/src/com.oracle.svm.core.graal.aarch64/src/com/oracle/svm/core/graal/aarch64/SubstrateAArch64Backend.java index 1963fe393cd2..d237fb640257 100755 --- a/substratevm/src/com.oracle.svm.core.graal.aarch64/src/com/oracle/svm/core/graal/aarch64/SubstrateAArch64Backend.java +++ b/substratevm/src/com.oracle.svm.core.graal.aarch64/src/com/oracle/svm/core/graal/aarch64/SubstrateAArch64Backend.java @@ -28,16 +28,53 @@ import static com.oracle.svm.core.graal.code.SubstrateBackend.SubstrateMarkId.PROLOGUE_DECD_RSP; import static com.oracle.svm.core.graal.code.SubstrateBackend.SubstrateMarkId.PROLOGUE_END; import static com.oracle.svm.core.util.VMError.shouldNotReachHere; -import static jdk.vm.ci.aarch64.AArch64.lr; -import static jdk.vm.ci.aarch64.AArch64.sp; -import static jdk.vm.ci.code.ValueUtil.asRegister; import static jdk.graal.compiler.core.common.GraalOptions.ZapStackOnMethodEntry; import static jdk.graal.compiler.lir.LIRInstruction.OperandFlag.REG; import static jdk.graal.compiler.lir.LIRValueUtil.asConstantValue; import static jdk.graal.compiler.lir.LIRValueUtil.differentRegisters; +import static jdk.vm.ci.aarch64.AArch64.lr; +import static jdk.vm.ci.aarch64.AArch64.sp; +import static jdk.vm.ci.code.ValueUtil.asRegister; import java.util.function.BiConsumer; +import org.graalvm.nativeimage.ImageSingletons; + +import com.oracle.svm.core.FrameAccess; +import com.oracle.svm.core.ReservedRegisters; +import com.oracle.svm.core.SubstrateOptions; +import com.oracle.svm.core.SubstrateUtil; +import com.oracle.svm.core.code.CodeInfoTable; +import com.oracle.svm.core.config.ConfigurationValues; +import com.oracle.svm.core.deopt.Deoptimizer; +import com.oracle.svm.core.graal.code.PatchConsumerFactory; +import com.oracle.svm.core.graal.code.SubstrateBackend; +import com.oracle.svm.core.graal.code.SubstrateCallingConvention; +import com.oracle.svm.core.graal.code.SubstrateCallingConventionKind; +import com.oracle.svm.core.graal.code.SubstrateCallingConventionType; +import com.oracle.svm.core.graal.code.SubstrateCompiledCode; +import com.oracle.svm.core.graal.code.SubstrateDataBuilder; +import com.oracle.svm.core.graal.code.SubstrateDebugInfoBuilder; +import com.oracle.svm.core.graal.code.SubstrateLIRGenerator; +import com.oracle.svm.core.graal.code.SubstrateNodeLIRBuilder; +import com.oracle.svm.core.graal.lir.VerificationMarkerOp; +import com.oracle.svm.core.graal.meta.KnownOffsets; +import com.oracle.svm.core.graal.meta.SharedConstantReflectionProvider; +import com.oracle.svm.core.graal.meta.SubstrateForeignCallLinkage; +import com.oracle.svm.core.graal.meta.SubstrateRegisterConfig; +import com.oracle.svm.core.graal.nodes.CGlobalDataLoadAddressNode; +import com.oracle.svm.core.graal.nodes.ComputedIndirectCallTargetNode; +import com.oracle.svm.core.heap.ReferenceAccess; +import com.oracle.svm.core.heap.SubstrateReferenceMapBuilder; +import com.oracle.svm.core.meta.CompressedNullConstant; +import com.oracle.svm.core.meta.SharedField; +import com.oracle.svm.core.meta.SharedMethod; +import com.oracle.svm.core.meta.SubstrateMethodPointerConstant; +import com.oracle.svm.core.meta.SubstrateObjectConstant; +import com.oracle.svm.core.nodes.SafepointCheckNode; +import com.oracle.svm.core.thread.VMThreads.StatusSupport; +import com.oracle.svm.core.util.VMError; + import jdk.graal.compiler.asm.BranchTargetOutOfBoundsException; import jdk.graal.compiler.asm.Label; import jdk.graal.compiler.asm.aarch64.AArch64Address; @@ -119,43 +156,6 @@ import jdk.graal.compiler.phases.BasePhase; import jdk.graal.compiler.phases.common.AddressLoweringByUsePhase; import jdk.graal.compiler.phases.util.Providers; -import org.graalvm.nativeimage.ImageSingletons; - -import com.oracle.svm.core.FrameAccess; -import com.oracle.svm.core.ReservedRegisters; -import com.oracle.svm.core.SubstrateOptions; -import com.oracle.svm.core.SubstrateUtil; -import com.oracle.svm.core.code.CodeInfoTable; -import com.oracle.svm.core.config.ConfigurationValues; -import com.oracle.svm.core.deopt.Deoptimizer; -import com.oracle.svm.core.graal.code.PatchConsumerFactory; -import com.oracle.svm.core.graal.code.SubstrateBackend; -import com.oracle.svm.core.graal.code.SubstrateCallingConvention; -import com.oracle.svm.core.graal.code.SubstrateCallingConventionKind; -import com.oracle.svm.core.graal.code.SubstrateCallingConventionType; -import com.oracle.svm.core.graal.code.SubstrateCompiledCode; -import com.oracle.svm.core.graal.code.SubstrateDataBuilder; -import com.oracle.svm.core.graal.code.SubstrateDebugInfoBuilder; -import com.oracle.svm.core.graal.code.SubstrateLIRGenerator; -import com.oracle.svm.core.graal.code.SubstrateNodeLIRBuilder; -import com.oracle.svm.core.graal.lir.VerificationMarkerOp; -import com.oracle.svm.core.graal.meta.KnownOffsets; -import com.oracle.svm.core.graal.meta.SharedConstantReflectionProvider; -import com.oracle.svm.core.graal.meta.SubstrateForeignCallLinkage; -import com.oracle.svm.core.graal.meta.SubstrateRegisterConfig; -import com.oracle.svm.core.graal.nodes.CGlobalDataLoadAddressNode; -import com.oracle.svm.core.graal.nodes.ComputedIndirectCallTargetNode; -import com.oracle.svm.core.heap.ReferenceAccess; -import com.oracle.svm.core.heap.SubstrateReferenceMapBuilder; -import com.oracle.svm.core.meta.CompressedNullConstant; -import com.oracle.svm.core.meta.SharedField; -import com.oracle.svm.core.meta.SharedMethod; -import com.oracle.svm.core.meta.SubstrateMethodPointerConstant; -import com.oracle.svm.core.meta.SubstrateObjectConstant; -import com.oracle.svm.core.nodes.SafepointCheckNode; -import com.oracle.svm.core.thread.VMThreads.StatusSupport; -import com.oracle.svm.core.util.VMError; - import jdk.vm.ci.aarch64.AArch64; import jdk.vm.ci.aarch64.AArch64Kind; import jdk.vm.ci.code.CallingConvention; @@ -300,7 +300,7 @@ public void emitCode(CompilationResultBuilder crb, AArch64MacroAssembler masm) { Register immediateScratch = sc1.getRegister(); Register addressScratch = sc2.getRegister(); - CompressEncoding compressEncoding = ReferenceAccess.singleton().getCompressEncoding(); + int compressionShift = ReferenceAccess.singleton().getCompressionShift(); Register computeRegister = asRegister(addressBase); int addressBitSize = addressBase.getPlatformKind().getSizeInBytes() * Byte.SIZE; boolean nextMemoryAccessNeedsDecompress = false; @@ -324,7 +324,7 @@ public void emitCode(CompilationResultBuilder crb, AArch64MacroAssembler masm) { * currently in use: references are relative to the heap base register, * with an optional shift. */ - masm.add(64, addressScratch, ReservedRegisters.singleton().getHeapBaseRegister(), computeRegister, ShiftType.LSL, compressEncoding.getShift()); + masm.add(64, addressScratch, ReservedRegisters.singleton().getHeapBaseRegister(), computeRegister, ShiftType.LSL, compressionShift); memoryAddress = masm.makeAddress(addressBitSize, addressScratch, field.getOffset(), immediateScratch); } else { memoryAddress = masm.makeAddress(addressBitSize, computeRegister, field.getOffset(), immediateScratch); @@ -353,7 +353,7 @@ public void emitCode(CompilationResultBuilder crb, AArch64MacroAssembler masm) { } else { masm.mov(addressScratch, 0xDEADDEADDEADDEADL, true); } - masm.add(64, addressScratch, ReservedRegisters.singleton().getHeapBaseRegister(), addressScratch, ShiftType.LSL, compressEncoding.getShift()); + masm.add(64, addressScratch, ReservedRegisters.singleton().getHeapBaseRegister(), addressScratch, ShiftType.LSL, compressionShift); memoryAddress = masm.makeAddress(addressBitSize, addressScratch, field.getOffset(), immediateScratch); } else { memoryAddress = masm.makeAddress(addressBitSize, ReservedRegisters.singleton().getHeapBaseRegister(), field.getOffset() + constantReflection.getImageHeapOffset(object), diff --git a/substratevm/src/com.oracle.svm.core.graal.amd64/src/com/oracle/svm/core/graal/amd64/SubstrateAMD64Backend.java b/substratevm/src/com.oracle.svm.core.graal.amd64/src/com/oracle/svm/core/graal/amd64/SubstrateAMD64Backend.java index e022cfec80c2..b9969cbb5cc0 100644 --- a/substratevm/src/com.oracle.svm.core.graal.amd64/src/com/oracle/svm/core/graal/amd64/SubstrateAMD64Backend.java +++ b/substratevm/src/com.oracle.svm.core.graal.amd64/src/com/oracle/svm/core/graal/amd64/SubstrateAMD64Backend.java @@ -363,7 +363,7 @@ public SubstrateAMD64ComputedIndirectCallOp(ResolvedJavaMethod callTarget, Value public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) { VMError.guarantee(SubstrateOptions.SpawnIsolates.getValue(), "Memory access without isolates is not implemented"); - CompressEncoding compressEncoding = ReferenceAccess.singleton().getCompressEncoding(); + int compressionShift = ReferenceAccess.singleton().getCompressionShift(); Register computeRegister = asRegister(addressBase); AMD64BaseAssembler.OperandSize lastOperandSize = AMD64BaseAssembler.OperandSize.get(addressBase.getPlatformKind()); boolean nextMemoryAccessNeedsDecompress = false; @@ -387,7 +387,7 @@ public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) { * an optional shift that is known to be a valid addressing mode. */ memoryAddress = new AMD64Address(ReservedRegisters.singleton().getHeapBaseRegister(), - computeRegister, Stride.fromLog2(compressEncoding.getShift()), + computeRegister, Stride.fromLog2(compressionShift), field.getOffset()); } else { memoryAddress = new AMD64Address(computeRegister, field.getOffset()); diff --git a/substratevm/src/com.oracle.svm.core.graal.llvm/src/com/oracle/svm/core/graal/llvm/NodeLLVMBuilder.java b/substratevm/src/com.oracle.svm.core.graal.llvm/src/com/oracle/svm/core/graal/llvm/NodeLLVMBuilder.java index e91c8b8ccd03..de34ca87f7af 100644 --- a/substratevm/src/com.oracle.svm.core.graal.llvm/src/com/oracle/svm/core/graal/llvm/NodeLLVMBuilder.java +++ b/substratevm/src/com.oracle.svm.core.graal.llvm/src/com/oracle/svm/core/graal/llvm/NodeLLVMBuilder.java @@ -38,8 +38,41 @@ import java.util.Set; import org.graalvm.collections.Pair; + +import com.oracle.svm.core.ReservedRegisters; +import com.oracle.svm.core.SubstrateOptions; +import com.oracle.svm.core.graal.code.CGlobalDataInfo; +import com.oracle.svm.core.graal.code.CGlobalDataReference; +import com.oracle.svm.core.graal.code.SubstrateBackend; +import com.oracle.svm.core.graal.code.SubstrateCallingConventionKind; +import com.oracle.svm.core.graal.code.SubstrateCallingConventionType; +import com.oracle.svm.core.graal.code.SubstrateDebugInfoBuilder; +import com.oracle.svm.core.graal.code.SubstrateNodeLIRBuilder; +import com.oracle.svm.core.graal.llvm.lowering.LLVMAddressLowering.LLVMAddressValue; +import com.oracle.svm.core.graal.llvm.runtime.LLVMExceptionUnwind; +import com.oracle.svm.core.graal.llvm.util.LLVMIRBuilder; +import com.oracle.svm.core.graal.llvm.util.LLVMUtils; +import com.oracle.svm.core.graal.llvm.util.LLVMUtils.LLVMKind; +import com.oracle.svm.core.graal.llvm.util.LLVMUtils.LLVMPendingSpecialRegisterRead; +import com.oracle.svm.core.graal.llvm.util.LLVMUtils.LLVMValueWrapper; +import com.oracle.svm.core.graal.llvm.util.LLVMUtils.LLVMVariable; +import com.oracle.svm.core.graal.meta.KnownOffsets; +import com.oracle.svm.core.graal.nodes.CGlobalDataLoadAddressNode; +import com.oracle.svm.core.graal.nodes.ComputedIndirectCallTargetNode; +import com.oracle.svm.core.graal.nodes.ForeignCallWithExceptionNode; +import com.oracle.svm.core.heap.ReferenceAccess; +import com.oracle.svm.core.meta.SharedField; +import com.oracle.svm.core.meta.SubstrateObjectConstant; +import com.oracle.svm.core.nodes.SafepointCheckNode; +import com.oracle.svm.core.thread.Safepoint; +import com.oracle.svm.core.thread.ThreadingSupportImpl; +import com.oracle.svm.core.thread.VMThreads; +import com.oracle.svm.core.util.VMError; +import com.oracle.svm.shadowed.org.bytedeco.llvm.LLVM.LLVMBasicBlockRef; +import com.oracle.svm.shadowed.org.bytedeco.llvm.LLVM.LLVMTypeRef; +import com.oracle.svm.shadowed.org.bytedeco.llvm.LLVM.LLVMValueRef; + import jdk.graal.compiler.code.CompilationResult; -import jdk.graal.compiler.core.common.CompressEncoding; import jdk.graal.compiler.core.common.NumUtil; import jdk.graal.compiler.core.common.calc.Condition; import jdk.graal.compiler.core.common.cfg.BasicBlock; @@ -89,40 +122,6 @@ import jdk.graal.compiler.nodes.java.TypeSwitchNode; import jdk.graal.compiler.nodes.spi.LIRLowerable; import jdk.graal.compiler.nodes.spi.NodeLIRBuilderTool; - -import com.oracle.svm.core.ReservedRegisters; -import com.oracle.svm.core.SubstrateOptions; -import com.oracle.svm.core.graal.code.CGlobalDataInfo; -import com.oracle.svm.core.graal.code.CGlobalDataReference; -import com.oracle.svm.core.graal.code.SubstrateBackend; -import com.oracle.svm.core.graal.code.SubstrateCallingConventionKind; -import com.oracle.svm.core.graal.code.SubstrateCallingConventionType; -import com.oracle.svm.core.graal.code.SubstrateDebugInfoBuilder; -import com.oracle.svm.core.graal.code.SubstrateNodeLIRBuilder; -import com.oracle.svm.core.graal.llvm.lowering.LLVMAddressLowering.LLVMAddressValue; -import com.oracle.svm.core.graal.llvm.runtime.LLVMExceptionUnwind; -import com.oracle.svm.core.graal.llvm.util.LLVMIRBuilder; -import com.oracle.svm.core.graal.llvm.util.LLVMUtils; -import com.oracle.svm.core.graal.llvm.util.LLVMUtils.LLVMKind; -import com.oracle.svm.core.graal.llvm.util.LLVMUtils.LLVMPendingSpecialRegisterRead; -import com.oracle.svm.core.graal.llvm.util.LLVMUtils.LLVMValueWrapper; -import com.oracle.svm.core.graal.llvm.util.LLVMUtils.LLVMVariable; -import com.oracle.svm.core.graal.meta.KnownOffsets; -import com.oracle.svm.core.graal.nodes.CGlobalDataLoadAddressNode; -import com.oracle.svm.core.graal.nodes.ComputedIndirectCallTargetNode; -import com.oracle.svm.core.graal.nodes.ForeignCallWithExceptionNode; -import com.oracle.svm.core.heap.ReferenceAccess; -import com.oracle.svm.core.meta.SharedField; -import com.oracle.svm.core.meta.SubstrateObjectConstant; -import com.oracle.svm.core.nodes.SafepointCheckNode; -import com.oracle.svm.core.thread.Safepoint; -import com.oracle.svm.core.thread.ThreadingSupportImpl; -import com.oracle.svm.core.thread.VMThreads; -import com.oracle.svm.core.util.VMError; -import com.oracle.svm.shadowed.org.bytedeco.llvm.LLVM.LLVMBasicBlockRef; -import com.oracle.svm.shadowed.org.bytedeco.llvm.LLVM.LLVMTypeRef; -import com.oracle.svm.shadowed.org.bytedeco.llvm.LLVM.LLVMValueRef; - import jdk.vm.ci.code.DebugInfo; import jdk.vm.ci.code.Register; import jdk.vm.ci.code.RegisterValue; @@ -499,7 +498,7 @@ public void emitInvoke(Invoke i) { ComputedIndirectCallTargetNode computedIndirectCallTargetNode = (ComputedIndirectCallTargetNode) callTarget; LLVMValueRef computedAddress = llvmOperand(computedIndirectCallTargetNode.getAddressBase()); - CompressEncoding compressEncoding = ReferenceAccess.singleton().getCompressEncoding(); + int compressionShift = ReferenceAccess.singleton().getCompressionShift(); boolean nextMemoryAccessNeedsDecompress = false; for (var computation : computedIndirectCallTargetNode.getAddressComputation()) { @@ -510,7 +509,7 @@ public void emitInvoke(Invoke i) { if (nextMemoryAccessNeedsDecompress) { computedAddress = builder.buildAddrSpaceCast(computedAddress, builder.objectType(true)); LLVMValueRef heapBase = ((LLVMVariable) gen.emitReadRegister(ReservedRegisters.singleton().getHeapBaseRegister(), null)).get(); - computedAddress = builder.buildUncompress(computedAddress, heapBase, true, compressEncoding.getShift()); + computedAddress = builder.buildUncompress(computedAddress, heapBase, true, compressionShift); } computedAddress = builder.buildGEP(computedAddress, builder.constantInt(field.getOffset())); diff --git a/substratevm/src/com.oracle.svm.core.posix/src/com/oracle/svm/core/posix/PosixSubstrateSegfaultHandler.java b/substratevm/src/com.oracle.svm.core.posix/src/com/oracle/svm/core/posix/PosixSubstrateSegfaultHandler.java index 7f34cb65847d..a35b7911ddb4 100644 --- a/substratevm/src/com.oracle.svm.core.posix/src/com/oracle/svm/core/posix/PosixSubstrateSegfaultHandler.java +++ b/substratevm/src/com.oracle.svm.core.posix/src/com/oracle/svm/core/posix/PosixSubstrateSegfaultHandler.java @@ -36,6 +36,7 @@ import com.oracle.svm.core.c.function.CEntryPointOptions.NoEpilogue; import com.oracle.svm.core.c.function.CEntryPointOptions.NoPrologue; import com.oracle.svm.core.feature.AutomaticallyRegisteredImageSingleton; +import com.oracle.svm.core.headers.LibC; import com.oracle.svm.core.heap.RestrictHeapAccess; import com.oracle.svm.core.log.Log; import com.oracle.svm.core.os.MemoryProtectionProvider; @@ -60,6 +61,9 @@ private static void dispatch(@SuppressWarnings("unused") int signalNumber, @Supp dump(sigInfo, uContext); throw VMError.shouldNotReachHereAtRuntime(); } + + /* Attach failed - kill the process because the segfault handler must not return. */ + LibC.abort(); } @Override diff --git a/substratevm/src/com.oracle.svm.core.windows/src/com/oracle/svm/core/windows/WindowsSubstrateSegfaultHandler.java b/substratevm/src/com.oracle.svm.core.windows/src/com/oracle/svm/core/windows/WindowsSubstrateSegfaultHandler.java index 34eaf74042ee..9b71605eea47 100644 --- a/substratevm/src/com.oracle.svm.core.windows/src/com/oracle/svm/core/windows/WindowsSubstrateSegfaultHandler.java +++ b/substratevm/src/com.oracle.svm.core.windows/src/com/oracle/svm/core/windows/WindowsSubstrateSegfaultHandler.java @@ -75,8 +75,7 @@ protected void installInternal() { } } - private static final CEntryPointLiteral HANDLER_LITERAL = CEntryPointLiteral.create(WindowsSubstrateSegfaultHandler.class, - "handler", ErrHandlingAPI.EXCEPTION_POINTERS.class); + private static final CEntryPointLiteral HANDLER_LITERAL = CEntryPointLiteral.create(WindowsSubstrateSegfaultHandler.class, "handler", ErrHandlingAPI.EXCEPTION_POINTERS.class); @CEntryPoint(include = CEntryPoint.NotIncludedAutomatically.class, publishAs = Publish.NotPublished) @CEntryPointOptions(prologue = NoPrologue.class, epilogue = NoEpilogue.class) @@ -94,7 +93,11 @@ private static int handler(ErrHandlingAPI.EXCEPTION_POINTERS exceptionInfo) { dump(exceptionInfo, context); throw shouldNotReachHere(); } - /* Nothing we can do. */ + + /* + * Attach failed - nothing we need to do. If there is no other OS-level exception handler + * installed, then Windows will abort the process. + */ return ErrHandlingAPI.EXCEPTION_CONTINUE_SEARCH(); } diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/SubstrateSegfaultHandler.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/SubstrateSegfaultHandler.java index bad0da5167a9..e84606ddf7ae 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/SubstrateSegfaultHandler.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/SubstrateSegfaultHandler.java @@ -26,6 +26,7 @@ import static com.oracle.svm.core.heap.RestrictHeapAccess.Access.NO_ALLOCATION; +import java.lang.reflect.Field; import java.util.Collections; import java.util.List; @@ -39,8 +40,10 @@ import org.graalvm.word.LocationIdentity; import org.graalvm.word.Pointer; import org.graalvm.word.PointerBase; +import org.graalvm.word.UnsignedWord; import org.graalvm.word.WordFactory; +import com.oracle.svm.core.BuildPhaseProvider.ReadyForCompilation; import com.oracle.svm.core.IsolateListenerSupport.IsolateListener; import com.oracle.svm.core.SubstrateSegfaultHandler.SingleIsolateSegfaultSetup; import com.oracle.svm.core.c.CGlobalData; @@ -51,15 +54,17 @@ import com.oracle.svm.core.graal.nodes.WriteCurrentVMThreadNode; import com.oracle.svm.core.graal.snippets.CEntryPointSnippets; import com.oracle.svm.core.graal.stackvalue.UnsafeLateStackValue; +import com.oracle.svm.core.heap.ReferenceAccess; import com.oracle.svm.core.heap.RestrictHeapAccess; +import com.oracle.svm.core.heap.UnknownPrimitiveField; import com.oracle.svm.core.jdk.RuntimeSupport; import com.oracle.svm.core.log.Log; import com.oracle.svm.core.option.RuntimeOptionKey; -import com.oracle.svm.core.snippets.KnownIntrinsics; import com.oracle.svm.core.stack.StackOverflowCheck; import com.oracle.svm.core.thread.VMThreads; import com.oracle.svm.core.thread.VMThreads.SafepointBehavior; import com.oracle.svm.core.threadlocal.VMThreadLocalMTSupport; +import com.oracle.svm.util.ReflectionUtil; import jdk.graal.compiler.api.replacements.Fold; import jdk.graal.compiler.options.Option; @@ -74,15 +79,31 @@ public List> getRequiredFeatures() { @Override public void beforeAnalysis(BeforeAnalysisAccess access) { if (!ImageSingletons.contains(SubstrateSegfaultHandler.class)) { - return; /* No segfault handler. */ + return; } + /* Register the marker as accessed so that we have a field with a well-known value. */ + access.registerAsUnsafeAccessed(getStaticFieldWithWellKnownValue()); + SingleIsolateSegfaultSetup singleIsolateSegfaultSetup = new SingleIsolateSegfaultSetup(); ImageSingletons.add(SingleIsolateSegfaultSetup.class, singleIsolateSegfaultSetup); IsolateListenerSupport.singleton().register(singleIsolateSegfaultSetup); RuntimeSupport.getRuntimeSupport().addStartupHook(new SubstrateSegfaultHandlerStartupHook()); } + + @Override + public void beforeCompilation(BeforeCompilationAccess access) { + if (!ImageSingletons.contains(SubstrateSegfaultHandler.class)) { + return; + } + + SubstrateSegfaultHandler.offsetOfStaticFieldWithWellKnownValue = access.objectFieldOffset(getStaticFieldWithWellKnownValue()); + } + + private static Field getStaticFieldWithWellKnownValue() { + return ReflectionUtil.lookupField(SubstrateSegfaultHandler.class, "staticFieldWithWellKnownValue"); + } } final class SubstrateSegfaultHandlerStartupHook implements RuntimeSupport.Hook { @@ -103,6 +124,11 @@ public static class Options { static final RuntimeOptionKey InstallSegfaultHandler = new RuntimeOptionKey<>(null); } + private static final long MARKER_VALUE = 0x0123456789ABCDEFL; + @UnknownPrimitiveField(availability = ReadyForCompilation.class) // + static long offsetOfStaticFieldWithWellKnownValue; + private static long staticFieldWithWellKnownValue = MARKER_VALUE; + private boolean installed; @Fold @@ -124,38 +150,86 @@ public void install() { protected abstract void printSignalInfo(Log log, PointerBase signalInfo); - /** Called from the platform dependent segfault handler to enter the isolate. */ + /** + * Called from the platform dependent segfault handler to enter the isolate. Note that this code + * may trigger a new segfault, which can lead to recursion. In the worst case, the recursion is + * only stopped once we trigger a native stack overflow. + */ @Uninterruptible(reason = "Thread state not set up yet.") protected static boolean tryEnterIsolate(RegisterDumper.Context context) { - // Check if we have sufficient information to enter the correct isolate. + /* If there is only a single isolate, we can just enter that isolate. */ Isolate isolate = SingleIsolateSegfaultSetup.singleton().getIsolate(); if (isolate.rawValue() != -1) { - // There is only a single isolate, so lets attach to that isolate. int error = CEntryPointSnippets.enterAttachFromCrashHandler(isolate); return error == CEntryPointErrors.NO_ERROR; - } else if (!SubstrateOptions.useLLVMBackend()) { - // Try to determine the isolate via the register information. This very likely fails if - // the crash happened in native code that was linked into Native Image. - if (SubstrateOptions.SpawnIsolates.getValue()) { - PointerBase heapBase = RegisterDumper.singleton().getHeapBase(context); - CEntryPointSnippets.setHeapBase(heapBase); - } - if (SubstrateOptions.MultiThreaded.getValue()) { - PointerBase threadPointer = RegisterDumper.singleton().getThreadPointer(context); - WriteCurrentVMThreadNode.writeCurrentVMThread((IsolateThread) threadPointer); + } + + /* The LLVM backend doesn't support the register-based approach. */ + if (SubstrateOptions.useLLVMBackend()) { + return false; + } + + /* Try to determine the isolate via the thread register. */ + if (SubstrateOptions.MultiThreaded.getValue()) { + /* + * Set the thread register to null so that we don't execute this code more than once if + * we trigger a recursive segfault. + */ + WriteCurrentVMThreadNode.writeCurrentVMThread(WordFactory.nullPointer()); + + IsolateThread isolateThread = (IsolateThread) RegisterDumper.singleton().getThreadPointer(context); + if (isolateThread.isNonNull()) { + isolate = VMThreads.IsolateTL.get(isolateThread); + if (isValid(isolate)) { + if (SubstrateOptions.SpawnIsolates.getValue()) { + CEntryPointSnippets.setHeapBase(isolate); + } + + WriteCurrentVMThreadNode.writeCurrentVMThread(isolateThread); + return true; + } } + } + /* Try to determine the isolate via the heap base register. */ + if (SubstrateOptions.SpawnIsolates.getValue()) { /* - * The following probing is subject to implicit recursion as it may trigger a new - * segfault. However, this is fine, as it will eventually result in native stack - * overflow. + * Set the heap base register to null so that we don't execute this code more than once + * if we trigger a recursive segfault. */ - isolate = VMThreads.IsolateTL.get(); - return Isolates.checkIsolate(isolate) == CEntryPointErrors.NO_ERROR && (!SubstrateOptions.SpawnIsolates.getValue() || isolate.equal(KnownIntrinsics.heapBase())); + CEntryPointSnippets.setHeapBase(WordFactory.nullPointer()); + + isolate = (Isolate) RegisterDumper.singleton().getHeapBase(context); + if (isValid(isolate)) { + int error = CEntryPointSnippets.enterAttachFromCrashHandler(isolate); + return error == CEntryPointErrors.NO_ERROR; + } } + return false; } + @Uninterruptible(reason = "Thread state not set up yet.") + private static boolean isValid(Isolate isolate) { + if (Isolates.checkIsolate(isolate) != CEntryPointErrors.NO_ERROR) { + return false; + } + + /* + * Read a static field in the image heap and compare its value with a well-known marker + * value as an extra sanity check. Note that the heap base register still contains an + * invalid value when we execute this code, which makes things a bit more complex. + */ + if (SubstrateOptions.SpawnIsolates.getValue()) { + UnsignedWord staticFieldsOffsets = ReferenceAccess.singleton().getCompressedRepresentation(StaticFieldsSupport.getStaticPrimitiveFields()); + UnsignedWord wellKnownFieldOffset = staticFieldsOffsets.shiftLeft(ReferenceAccess.singleton().getCompressionShift()).add(WordFactory.unsigned(offsetOfStaticFieldWithWellKnownValue)); + Pointer wellKnownField = ((Pointer) isolate).add(wellKnownFieldOffset); + return wellKnownField.readLong(0) == MARKER_VALUE; + } + + return true; + } + /** * Enter the isolate in an async-signal safe way. Being async-signal-safe significantly limits * what we can do (e.g., for unattached threads, we need to allocate the IsolateThread on the @@ -223,7 +297,7 @@ protected static void printSegfaultAddressInfo(Log log, long addr) { } } - static class SingleIsolateSegfaultSetup implements IsolateListener { + public static class SingleIsolateSegfaultSetup implements IsolateListener { /** * Stores the address of the first isolate created. This is meant to attempt to detect the diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/graal/meta/SubstrateBasicLoweringProvider.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/graal/meta/SubstrateBasicLoweringProvider.java index c8c41c3c2274..87039cac7749 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/graal/meta/SubstrateBasicLoweringProvider.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/graal/meta/SubstrateBasicLoweringProvider.java @@ -27,6 +27,28 @@ import java.util.HashMap; import java.util.Map; +import org.graalvm.nativeimage.Platform; +import org.graalvm.nativeimage.Platforms; + +import com.oracle.svm.core.StaticFieldsSupport; +import com.oracle.svm.core.config.ConfigurationValues; +import com.oracle.svm.core.config.ObjectLayout; +import com.oracle.svm.core.graal.code.SubstrateBackend; +import com.oracle.svm.core.graal.nodes.FloatingWordCastNode; +import com.oracle.svm.core.graal.nodes.LoweredDeadEndNode; +import com.oracle.svm.core.graal.nodes.SubstrateCompressionNode; +import com.oracle.svm.core.graal.nodes.SubstrateFieldLocationIdentity; +import com.oracle.svm.core.graal.nodes.SubstrateNarrowOopStamp; +import com.oracle.svm.core.graal.snippets.NodeLoweringProvider; +import com.oracle.svm.core.heap.Heap; +import com.oracle.svm.core.heap.ReferenceAccess; +import com.oracle.svm.core.hub.DynamicHub; +import com.oracle.svm.core.identityhashcode.IdentityHashCodeSupport; +import com.oracle.svm.core.meta.SharedField; +import com.oracle.svm.core.meta.SharedMethod; +import com.oracle.svm.core.meta.SubstrateMethodPointerStamp; +import com.oracle.svm.core.snippets.SubstrateIsArraySnippets; + import jdk.graal.compiler.core.common.memory.BarrierType; import jdk.graal.compiler.core.common.memory.MemoryOrderMode; import jdk.graal.compiler.core.common.spi.ForeignCallsProvider; @@ -65,28 +87,6 @@ import jdk.graal.compiler.replacements.IsArraySnippets; import jdk.graal.compiler.replacements.SnippetCounter.Group; import jdk.graal.compiler.replacements.nodes.AssertionNode; -import org.graalvm.nativeimage.Platform; -import org.graalvm.nativeimage.Platforms; - -import com.oracle.svm.core.StaticFieldsSupport; -import com.oracle.svm.core.config.ConfigurationValues; -import com.oracle.svm.core.config.ObjectLayout; -import com.oracle.svm.core.graal.code.SubstrateBackend; -import com.oracle.svm.core.graal.nodes.FloatingWordCastNode; -import com.oracle.svm.core.graal.nodes.LoweredDeadEndNode; -import com.oracle.svm.core.graal.nodes.SubstrateCompressionNode; -import com.oracle.svm.core.graal.nodes.SubstrateFieldLocationIdentity; -import com.oracle.svm.core.graal.nodes.SubstrateNarrowOopStamp; -import com.oracle.svm.core.graal.snippets.NodeLoweringProvider; -import com.oracle.svm.core.heap.Heap; -import com.oracle.svm.core.heap.ReferenceAccess; -import com.oracle.svm.core.hub.DynamicHub; -import com.oracle.svm.core.identityhashcode.IdentityHashCodeSupport; -import com.oracle.svm.core.meta.SharedField; -import com.oracle.svm.core.meta.SharedMethod; -import com.oracle.svm.core.meta.SubstrateMethodPointerStamp; -import com.oracle.svm.core.snippets.SubstrateIsArraySnippets; - import jdk.vm.ci.code.CodeUtil; import jdk.vm.ci.code.TargetDescription; import jdk.vm.ci.meta.JavaKind; @@ -228,7 +228,7 @@ protected ValueNode createReadHub(StructuredGraph graph, ValueNode object, Lower // get rid of the reserved header bits and extract the actual pointer to the hub assert CodeUtil.isPowerOf2(reservedBitsMask + 1) : "only the lowest bits may be set"; int numReservedBits = CodeUtil.log2(reservedBitsMask + 1); - int compressionShift = ReferenceAccess.singleton().getCompressEncoding().getShift(); + int compressionShift = ReferenceAccess.singleton().getCompressionShift(); int numAlignmentBits = CodeUtil.log2(objectLayout.getAlignment()); assert compressionShift <= numAlignmentBits : "compression discards bits"; if (numReservedBits == numAlignmentBits && compressionShift == 0) { diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/heap/ObjectHeader.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/heap/ObjectHeader.java index 3f634de041d5..9a106c94a078 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/heap/ObjectHeader.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/heap/ObjectHeader.java @@ -145,11 +145,6 @@ protected static int getReferenceSize() { return ConfigurationValues.getObjectLayout().getReferenceSize(); } - @Fold - protected static int getCompressionShift() { - return ReferenceAccess.singleton().getCompressEncoding().getShift(); - } - @Fold protected static int getHubOffset() { return ConfigurationValues.getObjectLayout().getHubOffset(); diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/heap/ReferenceAccess.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/heap/ReferenceAccess.java index ac81a094d3d3..ffc867aeca32 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/heap/ReferenceAccess.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/heap/ReferenceAccess.java @@ -25,15 +25,16 @@ package com.oracle.svm.core.heap; -import jdk.graal.compiler.api.replacements.Fold; -import jdk.graal.compiler.core.common.CompressEncoding; -import jdk.graal.compiler.word.Word; import org.graalvm.nativeimage.ImageSingletons; import org.graalvm.word.Pointer; import org.graalvm.word.UnsignedWord; import com.oracle.svm.core.config.ObjectLayout; +import jdk.graal.compiler.api.replacements.Fold; +import jdk.graal.compiler.core.common.CompressEncoding; +import jdk.graal.compiler.word.Word; + /** * Means for accessing object references, explicitly distinguishing between compressed and * uncompressed references. @@ -118,6 +119,11 @@ static ReferenceAccess singleton() { */ CompressEncoding getCompressEncoding(); + /** + * Returns a compile-time constant for {@link CompressEncoding#getShift()}. + */ + int getCompressionShift(); + /** * Returns the size of the address space, based on the reference size. */ diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/heap/ReferenceAccessImpl.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/heap/ReferenceAccessImpl.java index 1658ff894237..a6c93312b645 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/heap/ReferenceAccessImpl.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/heap/ReferenceAccessImpl.java @@ -24,11 +24,6 @@ */ package com.oracle.svm.core.heap; -import jdk.graal.compiler.api.replacements.Fold; -import jdk.graal.compiler.core.common.CompressEncoding; -import jdk.graal.compiler.word.BarrieredAccess; -import jdk.graal.compiler.word.ObjectAccess; -import jdk.graal.compiler.word.Word; import org.graalvm.nativeimage.ImageSingletons; import org.graalvm.word.Pointer; import org.graalvm.word.UnsignedWord; @@ -40,6 +35,12 @@ import com.oracle.svm.core.config.ConfigurationValues; import com.oracle.svm.core.feature.AutomaticallyRegisteredImageSingleton; +import jdk.graal.compiler.api.replacements.Fold; +import jdk.graal.compiler.core.common.CompressEncoding; +import jdk.graal.compiler.word.BarrieredAccess; +import jdk.graal.compiler.word.ObjectAccess; +import jdk.graal.compiler.word.Word; + @AutomaticallyRegisteredImageSingleton(ReferenceAccess.class) public final class ReferenceAccessImpl implements ReferenceAccess { @@ -117,4 +118,10 @@ public UnsignedWord getAddressSpaceSize() { // Assume that 48 bit is the maximum address space that can be used. return WordFactory.unsigned((1L << 48) - 1); } + + @Fold + @Override + public int getCompressionShift() { + return getCompressEncoding().getShift(); + } } From a6c046d5cbd780efbd97157b032770f6e12c922d Mon Sep 17 00:00:00 2001 From: Josef Haider Date: Thu, 7 Dec 2023 15:56:44 +0100 Subject: [PATCH 224/593] Add test for return value of StringUTF16.compress intrinsic --- .../test/StringCompressInflateTest.java | 33 ++++++++++++++++--- 1 file changed, 28 insertions(+), 5 deletions(-) diff --git a/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/replacements/test/StringCompressInflateTest.java b/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/replacements/test/StringCompressInflateTest.java index d5c5d2d9239c..701def7c3c96 100644 --- a/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/replacements/test/StringCompressInflateTest.java +++ b/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/replacements/test/StringCompressInflateTest.java @@ -27,20 +27,22 @@ import static org.junit.Assume.assumeTrue; import java.io.UnsupportedEncodingException; +import java.util.Arrays; + +import org.junit.Assert; +import org.junit.Assume; +import org.junit.Before; +import org.junit.Test; import jdk.graal.compiler.core.common.CompilationIdentifier; -import jdk.graal.compiler.replacements.amd64.AMD64GraphBuilderPlugins; import jdk.graal.compiler.hotspot.test.HotSpotGraalCompilerTest; import jdk.graal.compiler.nodes.Invoke; import jdk.graal.compiler.nodes.StructuredGraph; import jdk.graal.compiler.nodes.StructuredGraph.AllowAssumptions; import jdk.graal.compiler.replacements.StringLatin1InflateNode; import jdk.graal.compiler.replacements.StringUTF16CompressNode; +import jdk.graal.compiler.replacements.amd64.AMD64GraphBuilderPlugins; import jdk.graal.compiler.test.AddExports; -import org.junit.Assume; -import org.junit.Before; -import org.junit.Test; - import jdk.vm.ci.code.InstalledCode; import jdk.vm.ci.code.InvalidInstalledCodeException; import jdk.vm.ci.meta.JavaConstant; @@ -296,6 +298,27 @@ public void testStringUTF16CompressCharByte() throws ClassNotFoundException { } } } + + // Exhaustively check compress returning the correct index of the non-latin1 char. + final int SIZE = 48; + final byte FILL_BYTE = 'R'; + char[] chars = new char[SIZE]; + final byte[] bytes = new byte[chars.length]; + Arrays.fill(bytes, FILL_BYTE); + for (int i = 0; i < SIZE; i++) { // Every starting index + for (int j = i; j < SIZE; j++) { // Every location of non-latin1 + Arrays.fill(chars, 'A'); + chars[j] = 0xFF21; + byte[] dst = Arrays.copyOf(bytes, bytes.length); + byte[] dst2 = Arrays.copyOf(bytes, bytes.length); + int result = (int) invokeSafe(caller, null, chars, i, dst, 0, chars.length - i); + int result2 = (int) executeVarargsSafe(code, chars, i, dst2, 0, chars.length - i); + Assert.assertEquals(result, result2); + Assert.assertArrayEquals(dst, dst2); + Assert.assertEquals("compress found wrong index", j - i, result); + Assert.assertEquals("extra character stored", FILL_BYTE, bytes[j]); + } + } } public static void getCharsSnippet(String s, int srcBegin, int srcEnd, char[] dst, int dstBegin) { From d0955462079927ea5d9edb5d9eef3314bcdf11b7 Mon Sep 17 00:00:00 2001 From: Josef Haider Date: Thu, 7 Dec 2023 17:33:05 +0100 Subject: [PATCH 225/593] Sync StringUTF16.compress intrinsic to new HotSpot implementation --- .../lir/amd64/AMD64StringUTF16CompressOp.java | 229 +++++++++++++++++- 1 file changed, 228 insertions(+), 1 deletion(-) diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/amd64/AMD64StringUTF16CompressOp.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/amd64/AMD64StringUTF16CompressOp.java index bf12726c0495..1a7feaa1ece0 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/amd64/AMD64StringUTF16CompressOp.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/amd64/AMD64StringUTF16CompressOp.java @@ -48,6 +48,7 @@ import jdk.graal.compiler.lir.Opcode; import jdk.graal.compiler.lir.asm.CompilationResultBuilder; import jdk.graal.compiler.lir.gen.LIRGeneratorTool; +import jdk.graal.compiler.serviceprovider.JavaVersionUtil; import jdk.vm.ci.amd64.AMD64; import jdk.vm.ci.amd64.AMD64.CPUFeature; import jdk.vm.ci.amd64.AMD64Kind; @@ -127,7 +128,11 @@ public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) { Register tmp4 = asRegister(vtmp4); Register tmp5 = asRegister(rtmp5); - charArrayCompress(masm, src, dst, len, tmp1, tmp2, tmp3, tmp4, tmp5, res); + if (JavaVersionUtil.JAVA_SPEC >= 22) { + charArrayCompress(masm, src, dst, len, tmp1, tmp2, tmp3, tmp4, tmp5, res); + } else { + charArrayCompressLegacy(masm, src, dst, len, tmp1, tmp2, tmp3, tmp4, tmp5, res); + } } private boolean canUseAVX512Variant() { @@ -156,6 +161,228 @@ private void charArrayCompress(AMD64MacroAssembler masm, Register src, Register assert tmp3Reg.getRegisterCategory().equals(AMD64.XMM); assert tmp4Reg.getRegisterCategory().equals(AMD64.XMM); + Label labelCopyCharsLoop = new Label(); + Label labelResetSp = new Label(); + Label labelDone = new Label(); + Label labelCopyTail = new Label(); + + assert len.number != result.number : Assertions.errorMessageContext("len", len, "result", result); + + // Save length for return. + masm.movl(result, len); + + if (canUseAVX512Variant()) { + Label labelCopy32Loop = new Label(); + Label labelCopyLoopTail = new Label(); + Label labelBelowThreshold = new Label(); + Label labelPostAlignment = new Label(); + Label labelResetForCopyTail = new Label(); + + // If the length of the string is less than 32, we chose not to use the + // AVX512 instructions. + masm.testlAndJcc(len, -32, ConditionFlag.Zero, labelBelowThreshold, false); + + // First check whether a character is compressible (<= 0xff). + // Create mask to test for Unicode chars inside (zmm) vector. + masm.movl(tmp5, 0x00ff); + masm.evpbroadcastw(tmp2Reg, tmp5); + + masm.testlAndJcc(len, -64, ConditionFlag.Zero, labelPostAlignment, true); + + masm.movl(tmp5, dst); + masm.andl(tmp5, (32 - 1)); + masm.negl(tmp5); + masm.andl(tmp5, (32 - 1)); + + // bail out when there is nothing to be done + masm.testlAndJcc(tmp5, tmp5, ConditionFlag.Zero, labelPostAlignment, true); + + // Compute (1 << N) - 1 = ~(~0 << N), where N is the remaining number + // of characters to process. + masm.movl(len, 0xFFFFFFFF); + masm.shlxl(len, len, tmp5); + masm.notl(len); + masm.kmovd(k3, len); + masm.movl(len, result); + + masm.evmovdqu16(tmp1Reg, k3, new AMD64Address(src)); + masm.evpcmpuw(k2, k3, tmp1Reg, tmp2Reg, EVEXComparisonPredicate.LE); + masm.ktestd(k2, k3); + masm.jcc(ConditionFlag.CarryClear, labelCopyTail); + + masm.evpmovwb(new AMD64Address(dst), k3, tmp1Reg); + + masm.addq(src, tmp5); + masm.addq(src, tmp5); + masm.addq(dst, tmp5); + masm.subl(len, tmp5); + + masm.bind(labelPostAlignment); + // end of alignment + + masm.movl(tmp5, len); + masm.andl(tmp5, 32 - 1); // The tail count (in chars). + // The vector count (in chars). + masm.andlAndJcc(len, ~(32 - 1), ConditionFlag.Zero, labelCopyLoopTail, true); + + masm.leaq(src, new AMD64Address(src, len, Stride.S2)); + masm.leaq(dst, new AMD64Address(dst, len, Stride.S1)); + masm.negq(len); + + // Test and compress 32 chars per iteration, reading 512-bit vectors and + // writing 256-bit compressed ditto. + masm.bind(labelCopy32Loop); + masm.evmovdqu16(tmp1Reg, new AMD64Address(src, len, Stride.S2)); + masm.evpcmpuw(k2, tmp1Reg, tmp2Reg, EVEXComparisonPredicate.LE); + masm.kortestd(k2, k2); + masm.jcc(ConditionFlag.CarryClear, labelResetForCopyTail); + + // All 32 chars in the current vector (chunk) are valid for compression, + // write truncated byte elements to memory. + masm.evpmovwb(new AMD64Address(dst, len, Stride.S1), tmp1Reg); + masm.addqAndJcc(len, 32, ConditionFlag.NotZero, labelCopy32Loop, true); + + masm.bind(labelCopyLoopTail); + // All done if the tail count is zero. + masm.testlAndJcc(tmp5, tmp5, ConditionFlag.Zero, labelDone, false); + + masm.movl(len, tmp5); + + // Compute (1 << N) - 1 = ~(~0 << N), where N is the remaining number + // of characters to process. + masm.movl(tmp5, -1); + masm.shlxl(tmp5, tmp5, len); + masm.notl(tmp5); + + masm.kmovd(k3, tmp5); + + masm.evmovdqu16(tmp1Reg, k3, new AMD64Address(src)); + masm.evpcmpuw(k2, k3, tmp1Reg, tmp2Reg, EVEXComparisonPredicate.LE); + masm.ktestd(k2, k3); + masm.jcc(ConditionFlag.CarryClear, labelCopyTail); + + masm.evpmovwb(new AMD64Address(dst), k3, tmp1Reg); + masm.jmp(labelDone); + + masm.bind(labelResetForCopyTail); + masm.leaq(src, new AMD64Address(src, tmp5, Stride.S2)); + masm.leaq(dst, new AMD64Address(dst, tmp5, Stride.S1)); + masm.subq(len, tmp5); + masm.jmp(labelCopyCharsLoop); + + masm.bind(labelBelowThreshold); + } + + if (masm.supports(CPUFeature.SSE4_2)) { + Label labelCopy32Loop = new Label(); + Label labelCopy16 = new Label(); + Label labelCopyTailSSE = new Label(); + Label labelResetForCopyTail = new Label(); + + // vectored compression + masm.testlAndJcc(len, 0xfffffff8, ConditionFlag.Zero, labelCopyTail, false); + + masm.movl(tmp5, 0xff00ff00); // Create mask to test for Unicode chars in vectors. + masm.movdl(tmp1Reg, tmp5); + masm.pshufd(tmp1Reg, tmp1Reg, 0); // Store Unicode mask in 'vtmp1'. + + masm.andlAndJcc(len, 0xfffffff0, ConditionFlag.Zero, labelCopy16, true); + + // Compress 16 chars per iteration. + masm.pxor(tmp4Reg, tmp4Reg); + + masm.leaq(src, new AMD64Address(src, len, Stride.S2)); + masm.leaq(dst, new AMD64Address(dst, len, Stride.S1)); + masm.negq(len); + + // Test and compress 16 chars per iteration, reading 128-bit vectors and + // writing 64-bit compressed ditto. + masm.bind(labelCopy32Loop); + // load 1st 8 characters + masm.movdqu(tmp2Reg, new AMD64Address(src, len, Stride.S2)); + masm.por(tmp4Reg, tmp2Reg); + // load next 8 characters + masm.movdqu(tmp3Reg, new AMD64Address(src, len, Stride.S2, 16)); + masm.por(tmp4Reg, tmp3Reg); + masm.ptest(tmp4Reg, tmp1Reg); // Check for Unicode chars in vector. + masm.jccb(ConditionFlag.NotZero, labelResetForCopyTail); + masm.packuswb(tmp2Reg, tmp3Reg); // Only ASCII chars; compress each to a byte. + masm.movdqu(new AMD64Address(dst, len, Stride.S1), tmp2Reg); + masm.addqAndJcc(len, 16, ConditionFlag.NotZero, labelCopy32Loop, true); + + // Test and compress another 8 chars before final tail copy. + masm.bind(labelCopy16); + // len = 0 + masm.testlAndJcc(result, 0x00000008, ConditionFlag.Zero, labelCopyTailSSE, true); + + masm.pxor(tmp3Reg, tmp3Reg); + + masm.movdqu(tmp2Reg, new AMD64Address(src)); + masm.ptest(tmp2Reg, tmp1Reg); // Check for Unicode chars in vector. + masm.jccb(ConditionFlag.NotZero, labelResetForCopyTail); + masm.packuswb(tmp2Reg, tmp3Reg); // Only ASCII chars; compress each to a byte. + masm.movq(new AMD64Address(dst), tmp2Reg); + masm.addq(src, 16); + masm.addq(dst, 8); + masm.jmpb(labelCopyTailSSE); + + masm.bind(labelResetForCopyTail); + masm.movl(tmp5, result); + masm.andl(tmp5, 0x0000000f); + masm.leaq(src, new AMD64Address(src, tmp5, Stride.S2)); + masm.leaq(dst, new AMD64Address(dst, tmp5, Stride.S1)); + masm.subq(len, tmp5); + masm.jmpb(labelCopyCharsLoop); + + masm.bind(labelCopyTailSSE); + masm.movl(len, result); + masm.andl(len, 0x00000007); // tail count (in chars) + } + masm.bind(labelCopyTail); + // Compress any remaining characters using a vanilla implementation. + masm.testlAndJcc(len, len, ConditionFlag.Zero, labelDone, true); + masm.leaq(src, new AMD64Address(src, len, Stride.S2)); + masm.leaq(dst, new AMD64Address(dst, len, Stride.S1)); + masm.negq(len); + + // Compress a single character per iteration. + masm.bind(labelCopyCharsLoop); + masm.movzwl(tmp5, new AMD64Address(src, len, Stride.S2)); + // Check if Unicode character. + masm.testlAndJcc(tmp5, 0xff00, ConditionFlag.NotZero, labelResetSp, true); + // An ASCII character; compress to a byte. + masm.movb(new AMD64Address(dst, len, Stride.S1), tmp5); + masm.incqAndJcc(len, ConditionFlag.NotZero, labelCopyCharsLoop, true); + + // add len then return (len will be zero if compress succeeded, otherwise negative) + masm.bind(labelResetSp); + masm.addl(result, len); + + masm.bind(labelDone); + } + + /** + * Compress a UTF16 string which de facto is a Latin1 string into a byte array representation + * (buffer). + * + * @param masm the assembler + * @param src (rsi) the start address of source char[] to be compressed + * @param dst (rdi) the start address of destination byte[] vector + * @param len (rdx) the length + * @param tmp1Reg (xmm) temporary xmm register + * @param tmp2Reg (xmm) temporary xmm register + * @param tmp3Reg (xmm) temporary xmm register + * @param tmp4Reg (xmm) temporary xmm register + * @param tmp5 (gpr) temporary gpr register + * @param result (rax) the result code (length on success, zero otherwise) + */ + private void charArrayCompressLegacy(AMD64MacroAssembler masm, Register src, Register dst, Register len, Register tmp1Reg, + Register tmp2Reg, Register tmp3Reg, Register tmp4Reg, Register tmp5, Register result) { + assert tmp1Reg.getRegisterCategory().equals(AMD64.XMM); + assert tmp2Reg.getRegisterCategory().equals(AMD64.XMM); + assert tmp3Reg.getRegisterCategory().equals(AMD64.XMM); + assert tmp4Reg.getRegisterCategory().equals(AMD64.XMM); + Label labelCopyCharsLoop = new Label(); Label labelReturnLength = new Label(); Label labelReturnZero = new Label(); From 39f58b45ded1b0a7481cd55988ef0091bc03cd80 Mon Sep 17 00:00:00 2001 From: Josef Haider Date: Mon, 11 Dec 2023 13:59:15 +0100 Subject: [PATCH 226/593] Add file update command generation in SyncPortProcessor --- .../lir/processor/SyncPortProcessor.java | 30 ++++++++++++++----- 1 file changed, 23 insertions(+), 7 deletions(-) diff --git a/compiler/src/jdk.graal.compiler.processor/src/jdk/graal/compiler/lir/processor/SyncPortProcessor.java b/compiler/src/jdk.graal.compiler.processor/src/jdk/graal/compiler/lir/processor/SyncPortProcessor.java index a7f2a542c4a7..f09b680fdd9a 100644 --- a/compiler/src/jdk.graal.compiler.processor/src/jdk/graal/compiler/lir/processor/SyncPortProcessor.java +++ b/compiler/src/jdk.graal.compiler.processor/src/jdk/graal/compiler/lir/processor/SyncPortProcessor.java @@ -31,6 +31,7 @@ import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; +import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; @@ -70,6 +71,10 @@ public class SyncPortProcessor extends AbstractProcessor { // Allows comparing against local files. E.g., // HOTSPOT_PORT_SYNC_CHECK=true HOTSPOT_PORT_SYNC_OVERWRITE="file:///PATH/TO/JDK" mx build static final String SYNC_OVERWRITE_ENV_VAR = "HOTSPOT_PORT_SYNC_OVERWRITE"; + // Allows generating a file of bash commands to update changed line numbers. E.g.: + // HOTSPOT_PORT_SYNC_CHECK=true HOTSPOT_PORT_SYNC_SHIFT_UPDATE_CMD_FILE="update.sh" mx build && + // bash update.sh + static final String SYNC_SHIFT_UPDATE_COMMAND_DUMP_FILE_ENV_VAR = "HOTSPOT_PORT_SYNC_SHIFT_UPDATE_CMD_FILE"; static final String JDK_LATEST = "https://raw.githubusercontent.com/openjdk/jdk/master/"; static final String JDK_LATEST_HUMAN = "https://github.com/openjdk/jdk/blob/master/"; @@ -104,7 +109,14 @@ private void compareDigest(MessageDigest md, AnnotationMirror annotationMirror, int lineStart = Integer.parseInt(matcher.group("lineStart")); int lineEnd = Integer.parseInt(matcher.group("lineEnd")); - try { + String dumpUpdateCommandsEnvVar = System.getenv(SYNC_SHIFT_UPDATE_COMMAND_DUMP_FILE_ENV_VAR); + PrintWriter dumpUpdateCommands; + if (dumpUpdateCommandsEnvVar != null) { + dumpUpdateCommands = new PrintWriter(new FileOutputStream(dumpUpdateCommandsEnvVar, true)); + } else { + dumpUpdateCommands = null; + } + try (dumpUpdateCommands) { String overwriteURL = System.getenv(SYNC_OVERWRITE_ENV_VAR); boolean isURLOverwritten = overwriteURL != null && !"".equals(overwriteURL); @@ -120,23 +132,27 @@ private void compareDigest(MessageDigest md, AnnotationMirror annotationMirror, if (!isURLOverwritten) { String urlOld = String.format("https://raw.githubusercontent.com/openjdk/jdk/%s/%s", commit, path); String sha1Old = digest(proxy, md, urlOld, lineStart - 1, lineEnd); - if (sha1.equals(sha1Old)) { String latestCommit = getLatestCommit(proxy); int idx = find(proxy, urlOld, url, lineStart - 1, lineEnd, SEARCH_RANGE); if (idx != -1) { int idxInclusive = idx + 1; kind = NOTE; + String urlFormat = "https://github.com/openjdk/jdk/blob/%s/%s#L%d-L%d"; + String newUrl = String.format(urlFormat, latestCommit, path, idxInclusive, idxInclusive + (lineEnd - lineStart)); extraMessage = String.format(""" The original code snippet is shifted. Update with: - @SyncPort(from = "https://github.com/openjdk/jdk/blob/%s/%s#L%d-L%d", + @SyncPort(from = "%s", sha1 = "%s") """, - latestCommit, - path, - idxInclusive, - idxInclusive + (lineEnd - lineStart), + newUrl, sha1); + if (dumpUpdateCommands != null) { + String oldUrl = String.format(urlFormat, commit, path, lineStart, lineEnd); + assert !oldUrl.contains("+"); + assert !newUrl.contains("+"); + dumpUpdateCommands.printf("sed -i s+%s+%s+g $(git grep --files-with-matches %s)%n", oldUrl, newUrl, sha1); + } } else { extraMessage = String.format(""" See also: From b30a94c40c7eb5ea03701518f5c9acd2f2467ad3 Mon Sep 17 00:00:00 2001 From: Josef Haider Date: Mon, 11 Dec 2023 14:01:37 +0100 Subject: [PATCH 227/593] Update line numbers in SyncPort annotations --- .../compiler/hotspot/meta/HotSpotGraphBuilderPlugins.java | 2 +- .../hotspot/replacements/HotSpotHashCodeSnippets.java | 2 +- .../compiler/hotspot/replacements/MonitorSnippets.java | 4 ++-- .../replacements/VirtualThreadUpdateJFRSnippets.java | 2 +- .../jdk/graal/compiler/lir/aarch64/AArch64AESDecryptOp.java | 2 +- .../jdk/graal/compiler/lir/aarch64/AArch64AESEncryptOp.java | 2 +- .../compiler/lir/aarch64/AArch64BigIntegerMulAddOp.java | 2 +- .../lir/aarch64/AArch64BigIntegerMultiplyToLenOp.java | 2 +- .../lir/aarch64/AArch64BigIntegerSquareToLenOp.java | 2 +- .../lir/aarch64/AArch64CipherBlockChainingAESDecryptOp.java | 2 +- .../lir/aarch64/AArch64CipherBlockChainingAESEncryptOp.java | 2 +- .../graal/compiler/lir/aarch64/AArch64CountPositivesOp.java | 4 ++-- .../compiler/lir/aarch64/AArch64CounterModeAESCryptOp.java | 2 +- .../compiler/lir/aarch64/AArch64GHASHProcessBlocksOp.java | 2 +- .../src/jdk/graal/compiler/lir/aarch64/AArch64MD5Op.java | 2 +- .../compiler/lir/aarch64/AArch64RoundFloatToIntegerOp.java | 2 +- .../src/jdk/graal/compiler/lir/aarch64/AArch64SHA1Op.java | 2 +- .../src/jdk/graal/compiler/lir/aarch64/AArch64SHA256Op.java | 2 +- .../src/jdk/graal/compiler/lir/aarch64/AArch64SHA3Op.java | 2 +- .../src/jdk/graal/compiler/lir/aarch64/AArch64SHA512Op.java | 2 +- .../src/jdk/graal/compiler/lir/amd64/AMD64AESDecryptOp.java | 2 +- .../src/jdk/graal/compiler/lir/amd64/AMD64AESEncryptOp.java | 2 +- .../graal/compiler/lir/amd64/AMD64BigIntegerMulAddOp.java | 6 +++--- .../compiler/lir/amd64/AMD64BigIntegerMultiplyToLenOp.java | 4 ++-- .../compiler/lir/amd64/AMD64BigIntegerSquareToLenOp.java | 4 ++-- .../src/jdk/graal/compiler/lir/amd64/AMD64BitSwapOp.java | 2 +- .../lir/amd64/AMD64CipherBlockChainingAESDecryptOp.java | 2 +- .../lir/amd64/AMD64CipherBlockChainingAESEncryptOp.java | 2 +- .../compiler/lir/amd64/AMD64CounterModeAESCryptOp.java | 2 +- .../jdk/graal/compiler/lir/amd64/AMD64EncodeArrayOp.java | 2 +- .../src/jdk/graal/compiler/lir/amd64/AMD64MD5Op.java | 2 +- .../compiler/lir/amd64/AMD64RoundFloatToIntegerOp.java | 4 ++-- .../src/jdk/graal/compiler/lir/amd64/AMD64SHA1Op.java | 2 +- .../src/jdk/graal/compiler/lir/amd64/AMD64SHA256Op.java | 2 +- .../src/jdk/graal/compiler/lir/amd64/AMD64SHA512Op.java | 2 +- .../graal/compiler/lir/amd64/AMD64VectorizedHashCodeOp.java | 6 +++--- .../graal/compiler/lir/amd64/AMD64VectorizedMismatchOp.java | 2 +- 37 files changed, 46 insertions(+), 46 deletions(-) diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/meta/HotSpotGraphBuilderPlugins.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/meta/HotSpotGraphBuilderPlugins.java index 9a7bf0e2279e..f383c4fe8ac8 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/meta/HotSpotGraphBuilderPlugins.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/meta/HotSpotGraphBuilderPlugins.java @@ -670,7 +670,7 @@ public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Rec } // @formatter:off - @SyncPort(from = "https://github.com/openjdk/jdk/blob/0d4de8a71f063e44618f43ddd862a91aed647f48/src/hotspot/share/opto/library_call.cpp#L2868-L2923", + @SyncPort(from = "https://github.com/openjdk/jdk/blob/ce8399fd6071766114f5f201b6e44a7abdba9f5a/src/hotspot/share/opto/library_call.cpp#L2873-L2928", sha1 = "5c117a305e90a48f0a6fe86ace2c15942393c0ab") // @formatter:on private static void inlineNativeNotifyJvmtiFunctions(GraalHotSpotVMConfig config, GraphBuilderContext b, ResolvedJavaMethod targetMethod, ForeignCallDescriptor descriptor, diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/replacements/HotSpotHashCodeSnippets.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/replacements/HotSpotHashCodeSnippets.java index 1e690fc940df..a3e3871ecdd2 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/replacements/HotSpotHashCodeSnippets.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/replacements/HotSpotHashCodeSnippets.java @@ -42,7 +42,7 @@ import org.graalvm.word.WordFactory; // @formatter:off -@SyncPort(from = "https://github.com/openjdk/jdk/blob/d4c904d81970bbe5b0afe1029eae705366779839/src/hotspot/share/opto/library_call.cpp#L4480-L4604", +@SyncPort(from = "https://github.com/openjdk/jdk/blob/ce8399fd6071766114f5f201b6e44a7abdba9f5a/src/hotspot/share/opto/library_call.cpp#L4485-L4609", sha1 = "34281fb78c4f0657a704dbda3e3cc85ed56dd2ad") // @formatter:on public class HotSpotHashCodeSnippets extends IdentityHashCodeSnippets { diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/replacements/MonitorSnippets.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/replacements/MonitorSnippets.java index 2cb4ad879e44..47b0ae46618b 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/replacements/MonitorSnippets.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/replacements/MonitorSnippets.java @@ -329,7 +329,7 @@ private static boolean tryStackLocking(Object object, Word lock, Word mark, Word } // @formatter:off - @SyncPort(from = "https://github.com/openjdk/jdk/blob/0d4de8a71f063e44618f43ddd862a91aed647f48/src/hotspot/cpu/x86/macroAssembler_x86.cpp#L9792-L9826", + @SyncPort(from = "https://github.com/openjdk/jdk/blob/ce8399fd6071766114f5f201b6e44a7abdba9f5a/src/hotspot/cpu/x86/macroAssembler_x86.cpp#L9963-L9997", sha1 = "7a02d52b6b621959389e574984ca20b52100fe5e") // @formatter:on private static boolean tryLightweightLocking(Object object, Word lock, Word mark, Word thread, boolean trace, Counters counters, Register stackPointerRegister) { @@ -431,7 +431,7 @@ private static boolean tryStackUnlocking(Object object, Word displacedMark, Word } // @formatter:off - @SyncPort(from = "https://github.com/openjdk/jdk/blob/0d4de8a71f063e44618f43ddd862a91aed647f48/src/hotspot/cpu/x86/macroAssembler_x86.cpp#L9828-L9857", + @SyncPort(from = "https://github.com/openjdk/jdk/blob/ce8399fd6071766114f5f201b6e44a7abdba9f5a/src/hotspot/cpu/x86/macroAssembler_x86.cpp#L9999-L10028", sha1 = "666343ea6d941f68ed863a396d9496cb3ce1b69b") // @formatter:on private static boolean tryLightweightUnlocking(Object object, Word thread, boolean trace, Counters counters) { diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/replacements/VirtualThreadUpdateJFRSnippets.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/replacements/VirtualThreadUpdateJFRSnippets.java index 5aa2a619894f..c44a41c86ca8 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/replacements/VirtualThreadUpdateJFRSnippets.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/replacements/VirtualThreadUpdateJFRSnippets.java @@ -64,7 +64,7 @@ * Snippet for updating JFR thread local data on {@code Thread#setCurrentThread} events. */ // @formatter:off -@SyncPort(from = "https://github.com/openjdk/jdk/blob/0a3a925ad88921d387aa851157f54ac0054d347b/src/hotspot/share/opto/library_call.cpp#L3453-L3579", +@SyncPort(from = "https://github.com/openjdk/jdk/blob/ce8399fd6071766114f5f201b6e44a7abdba9f5a/src/hotspot/share/opto/library_call.cpp#L3458-L3584", sha1 = "1f980401f5d7d9a363577635fd57fc1e24505d91") // @formatter:on public class VirtualThreadUpdateJFRSnippets implements Snippets { diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/aarch64/AArch64AESDecryptOp.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/aarch64/AArch64AESDecryptOp.java index a6797dc6e6dd..11f67582eb2f 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/aarch64/AArch64AESDecryptOp.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/aarch64/AArch64AESDecryptOp.java @@ -56,7 +56,7 @@ import jdk.vm.ci.meta.Value; // @formatter:off -@SyncPort(from = "https://github.com/openjdk/jdk/blob/0a3a925ad88921d387aa851157f54ac0054d347b/src/hotspot/cpu/aarch64/stubGenerator_aarch64.cpp#L2703-L2734", +@SyncPort(from = "https://github.com/openjdk/jdk/blob/ce8399fd6071766114f5f201b6e44a7abdba9f5a/src/hotspot/cpu/aarch64/stubGenerator_aarch64.cpp#L2719-L2750", sha1 = "69b7e01dbc601afd660d5dcef88917a43613e00c") @SyncPort(from = "https://github.com/openjdk/jdk/blob/12358e6c94bc96e618efc3ec5299a2cfe1b4669d/src/hotspot/cpu/aarch64/macroAssembler_aarch64_aes.cpp#L34-L110", sha1 = "4916141cba98c26e4d98edb457161f88a8c66ffa") diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/aarch64/AArch64AESEncryptOp.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/aarch64/AArch64AESEncryptOp.java index bd1ecc57b7ff..076224283aed 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/aarch64/AArch64AESEncryptOp.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/aarch64/AArch64AESEncryptOp.java @@ -66,7 +66,7 @@ import jdk.vm.ci.meta.Value; // @formatter:off -@SyncPort(from = "https://github.com/openjdk/jdk/blob/0a3a925ad88921d387aa851157f54ac0054d347b/src/hotspot/cpu/aarch64/stubGenerator_aarch64.cpp#L2671-L2701", +@SyncPort(from = "https://github.com/openjdk/jdk/blob/ce8399fd6071766114f5f201b6e44a7abdba9f5a/src/hotspot/cpu/aarch64/stubGenerator_aarch64.cpp#L2687-L2717", sha1 = "e1333c6ab2d693fa9231a7365c568d81db63fae7") @SyncPort(from = "https://github.com/openjdk/jdk/blob/12358e6c94bc96e618efc3ec5299a2cfe1b4669d/src/hotspot/cpu/aarch64/macroAssembler_aarch64_aes.cpp#L112-L283", sha1 = "41ef4f49f68c0e08ff4d698c8cc962e392cc16ec") diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/aarch64/AArch64BigIntegerMulAddOp.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/aarch64/AArch64BigIntegerMulAddOp.java index 1436b28e8741..338eddf433e0 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/aarch64/AArch64BigIntegerMulAddOp.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/aarch64/AArch64BigIntegerMulAddOp.java @@ -48,7 +48,7 @@ // @formatter:off -@SyncPort(from = "https://github.com/openjdk/jdk/blob/0a3a925ad88921d387aa851157f54ac0054d347b/src/hotspot/cpu/aarch64/stubGenerator_aarch64.cpp#L4702-L4721", +@SyncPort(from = "https://github.com/openjdk/jdk/blob/ce8399fd6071766114f5f201b6e44a7abdba9f5a/src/hotspot/cpu/aarch64/stubGenerator_aarch64.cpp#L4718-L4737", sha1 = "57f40186d75104a5e607d6fc047bbd50ef246590") @SyncPort(from = "https://github.com/openjdk/jdk/blob/0a3a925ad88921d387aa851157f54ac0054d347b/src/hotspot/cpu/aarch64/macroAssembler_aarch64.cpp#L3622-L3658", sha1 = "33649be9177daf5f0b4817d807458a5ff8c00365") diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/aarch64/AArch64BigIntegerMultiplyToLenOp.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/aarch64/AArch64BigIntegerMultiplyToLenOp.java index 4bbb88284f5f..a40868cd4fe3 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/aarch64/AArch64BigIntegerMultiplyToLenOp.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/aarch64/AArch64BigIntegerMultiplyToLenOp.java @@ -57,7 +57,7 @@ import jdk.vm.ci.meta.Value; // @formatter:off -@SyncPort(from = "https://github.com/openjdk/jdk/blob/0a3a925ad88921d387aa851157f54ac0054d347b/src/hotspot/cpu/aarch64/stubGenerator_aarch64.cpp#L4626-L4664", +@SyncPort(from = "https://github.com/openjdk/jdk/blob/ce8399fd6071766114f5f201b6e44a7abdba9f5a/src/hotspot/cpu/aarch64/stubGenerator_aarch64.cpp#L4642-L4680", sha1 = "9c106817eae54d0e6783c1442b26fee08bc7a07a") @SyncPort(from = "https://github.com/openjdk/jdk/blob/0a3a925ad88921d387aa851157f54ac0054d347b/src/hotspot/cpu/aarch64/macroAssembler_aarch64.cpp#L3113-L3122", sha1 = "376de6fbb2caccaac53c4aa934ce96f8f0dc7f18") diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/aarch64/AArch64BigIntegerSquareToLenOp.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/aarch64/AArch64BigIntegerSquareToLenOp.java index 69c171e44eb8..ebefe7ffce47 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/aarch64/AArch64BigIntegerSquareToLenOp.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/aarch64/AArch64BigIntegerSquareToLenOp.java @@ -53,7 +53,7 @@ import jdk.vm.ci.meta.Value; // @formatter:off -@SyncPort(from = "https://github.com/openjdk/jdk/blob/0a3a925ad88921d387aa851157f54ac0054d347b/src/hotspot/cpu/aarch64/stubGenerator_aarch64.cpp#L4666-L4700", +@SyncPort(from = "https://github.com/openjdk/jdk/blob/ce8399fd6071766114f5f201b6e44a7abdba9f5a/src/hotspot/cpu/aarch64/stubGenerator_aarch64.cpp#L4682-L4716", sha1 = "0ad03e74934e230a64b9eb107a413248daa5be88") // @formatter:on public final class AArch64BigIntegerSquareToLenOp extends AArch64LIRInstruction { diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/aarch64/AArch64CipherBlockChainingAESDecryptOp.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/aarch64/AArch64CipherBlockChainingAESDecryptOp.java index be4a6ba45934..11b73165e7a3 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/aarch64/AArch64CipherBlockChainingAESDecryptOp.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/aarch64/AArch64CipherBlockChainingAESDecryptOp.java @@ -67,7 +67,7 @@ import jdk.vm.ci.meta.Value; // @formatter:off -@SyncPort(from = "https://github.com/openjdk/jdk/blob/0a3a925ad88921d387aa851157f54ac0054d347b/src/hotspot/cpu/aarch64/stubGenerator_aarch64.cpp#L2840-L2946", +@SyncPort(from = "https://github.com/openjdk/jdk/blob/ce8399fd6071766114f5f201b6e44a7abdba9f5a/src/hotspot/cpu/aarch64/stubGenerator_aarch64.cpp#L2856-L2962", sha1 = "59698d0ec90b5f69709188321f8b5df625e1a027") // @formatter:on public final class AArch64CipherBlockChainingAESDecryptOp extends AArch64LIRInstruction { diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/aarch64/AArch64CipherBlockChainingAESEncryptOp.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/aarch64/AArch64CipherBlockChainingAESEncryptOp.java index 39c0c5e5034d..87f53a3f9876 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/aarch64/AArch64CipherBlockChainingAESEncryptOp.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/aarch64/AArch64CipherBlockChainingAESEncryptOp.java @@ -66,7 +66,7 @@ import jdk.vm.ci.meta.Value; // @formatter:off -@SyncPort(from = "https://github.com/openjdk/jdk/blob/0a3a925ad88921d387aa851157f54ac0054d347b/src/hotspot/cpu/aarch64/stubGenerator_aarch64.cpp#L2736-L2838", +@SyncPort(from = "https://github.com/openjdk/jdk/blob/ce8399fd6071766114f5f201b6e44a7abdba9f5a/src/hotspot/cpu/aarch64/stubGenerator_aarch64.cpp#L2752-L2854", sha1 = "b64bab8291f14f42af2e45fcb499d20631195072") // @formatter:on public final class AArch64CipherBlockChainingAESEncryptOp extends AArch64LIRInstruction { diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/aarch64/AArch64CountPositivesOp.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/aarch64/AArch64CountPositivesOp.java index 29c22c2f4e42..86330f04b778 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/aarch64/AArch64CountPositivesOp.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/aarch64/AArch64CountPositivesOp.java @@ -69,9 +69,9 @@ * Returns the number of positive bytes. */ // @formatter:off -@SyncPort(from = "https://github.com/openjdk/jdk/blob/0a3a925ad88921d387aa851157f54ac0054d347b/src/hotspot/cpu/aarch64/macroAssembler_aarch64.cpp#L5045-L5114", +@SyncPort(from = "https://github.com/openjdk/jdk/blob/ce8399fd6071766114f5f201b6e44a7abdba9f5a/src/hotspot/cpu/aarch64/macroAssembler_aarch64.cpp#L5062-L5131", sha1 = "ce54a7cf2fcfe7ccb8f6604c038887fc1c4ebce1") -@SyncPort(from = "https://github.com/openjdk/jdk/blob/0a3a925ad88921d387aa851157f54ac0054d347b/src/hotspot/cpu/aarch64/stubGenerator_aarch64.cpp#L4955-L5121", +@SyncPort(from = "https://github.com/openjdk/jdk/blob/ce8399fd6071766114f5f201b6e44a7abdba9f5a/src/hotspot/cpu/aarch64/stubGenerator_aarch64.cpp#L4971-L5137", sha1 = "3b4e6edb4372e8babb009763c2d05961348dd723") // @formatter:on @Opcode("AARCH64_COUNT_POSITIVES") diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/aarch64/AArch64CounterModeAESCryptOp.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/aarch64/AArch64CounterModeAESCryptOp.java index 2c8f8e08d683..555a9a10c790 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/aarch64/AArch64CounterModeAESCryptOp.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/aarch64/AArch64CounterModeAESCryptOp.java @@ -74,7 +74,7 @@ import jdk.vm.ci.meta.Value; // @formatter:off -@SyncPort(from = "https://github.com/openjdk/jdk/blob/0a3a925ad88921d387aa851157f54ac0054d347b/src/hotspot/cpu/aarch64/stubGenerator_aarch64.cpp#L2948-L3228", +@SyncPort(from = "https://github.com/openjdk/jdk/blob/ce8399fd6071766114f5f201b6e44a7abdba9f5a/src/hotspot/cpu/aarch64/stubGenerator_aarch64.cpp#L2964-L3244", sha1 = "75a3a4dabdc42e5e23bbec0cb448d09fb0d7b129") // @formatter:on public final class AArch64CounterModeAESCryptOp extends AArch64LIRInstruction { diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/aarch64/AArch64GHASHProcessBlocksOp.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/aarch64/AArch64GHASHProcessBlocksOp.java index 1588f978f7b2..4ae5a26e14a3 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/aarch64/AArch64GHASHProcessBlocksOp.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/aarch64/AArch64GHASHProcessBlocksOp.java @@ -65,7 +65,7 @@ import jdk.vm.ci.meta.Value; // @formatter:off -@SyncPort(from = "https://github.com/openjdk/jdk/blob/0a3a925ad88921d387aa851157f54ac0054d347b/src/hotspot/cpu/aarch64/stubGenerator_aarch64.cpp#L6152-L6286", +@SyncPort(from = "https://github.com/openjdk/jdk/blob/ce8399fd6071766114f5f201b6e44a7abdba9f5a/src/hotspot/cpu/aarch64/stubGenerator_aarch64.cpp#L6168-L6302", sha1 = "84b96e679b2ff5dc836da5c28fbbc779b5320a2b") @SyncPort(from = "https://github.com/openjdk/jdk/blob/12358e6c94bc96e618efc3ec5299a2cfe1b4669d/src/hotspot/cpu/aarch64/macroAssembler_aarch64_aes.cpp#L285-L691", sha1 = "1cd41d8f202ebe127aa31053ab3c6851f3900034") diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/aarch64/AArch64MD5Op.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/aarch64/AArch64MD5Op.java index 312213bf51c3..5c09898f75a0 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/aarch64/AArch64MD5Op.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/aarch64/AArch64MD5Op.java @@ -63,7 +63,7 @@ import jdk.vm.ci.meta.Value; // @formatter:off -@SyncPort(from = "https://github.com/openjdk/jdk/blob/0a3a925ad88921d387aa851157f54ac0054d347b/src/hotspot/cpu/aarch64/stubGenerator_aarch64.cpp#L3356-L3590", +@SyncPort(from = "https://github.com/openjdk/jdk/blob/ce8399fd6071766114f5f201b6e44a7abdba9f5a/src/hotspot/cpu/aarch64/stubGenerator_aarch64.cpp#L3372-L3606", sha1 = "cfd2b9fcbbb67a138b8e28e7362ba1fff6a99aec") // @formatter:on public final class AArch64MD5Op extends AArch64LIRInstruction { diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/aarch64/AArch64RoundFloatToIntegerOp.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/aarch64/AArch64RoundFloatToIntegerOp.java index 33b012d023af..a65ab4f3fb60 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/aarch64/AArch64RoundFloatToIntegerOp.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/aarch64/AArch64RoundFloatToIntegerOp.java @@ -45,7 +45,7 @@ * {@link Math#round} algorithm for details. */ // @formatter:off -@SyncPort(from = "https://github.com/openjdk/jdk/blob/0a3a925ad88921d387aa851157f54ac0054d347b/src/hotspot/cpu/aarch64/macroAssembler_aarch64.cpp#L5882-L5930", +@SyncPort(from = "https://github.com/openjdk/jdk/blob/ce8399fd6071766114f5f201b6e44a7abdba9f5a/src/hotspot/cpu/aarch64/macroAssembler_aarch64.cpp#L5899-L5947", sha1 = "76d47473bf8d1408bf6e7bf6b8a3d93c19dab9c6") // @formatter:on @Opcode("AARCH64_ROUND_FLOAT_TO_INTEGER") diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/aarch64/AArch64SHA1Op.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/aarch64/AArch64SHA1Op.java index 281c2eebde1d..436d6994762b 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/aarch64/AArch64SHA1Op.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/aarch64/AArch64SHA1Op.java @@ -66,7 +66,7 @@ import jdk.vm.ci.meta.Value; // @formatter:off -@SyncPort(from = "https://github.com/openjdk/jdk/blob/0a3a925ad88921d387aa851157f54ac0054d347b/src/hotspot/cpu/aarch64/stubGenerator_aarch64.cpp#L3592-L3681", +@SyncPort(from = "https://github.com/openjdk/jdk/blob/ce8399fd6071766114f5f201b6e44a7abdba9f5a/src/hotspot/cpu/aarch64/stubGenerator_aarch64.cpp#L3608-L3697", sha1 = "64b4f4aa44a5201f87d28ee048721dcd3c3231ed") // @formatter:on public final class AArch64SHA1Op extends AArch64LIRInstruction { diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/aarch64/AArch64SHA256Op.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/aarch64/AArch64SHA256Op.java index 39e6aaac6006..987b251d40d9 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/aarch64/AArch64SHA256Op.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/aarch64/AArch64SHA256Op.java @@ -76,7 +76,7 @@ import jdk.vm.ci.meta.Value; // @formatter:off -@SyncPort(from = "https://github.com/openjdk/jdk/blob/0a3a925ad88921d387aa851157f54ac0054d347b/src/hotspot/cpu/aarch64/stubGenerator_aarch64.cpp#L3684-L3796", +@SyncPort(from = "https://github.com/openjdk/jdk/blob/ce8399fd6071766114f5f201b6e44a7abdba9f5a/src/hotspot/cpu/aarch64/stubGenerator_aarch64.cpp#L3700-L3812", sha1 = "f226b109da456148c11f83d1bcd78d14aac862cf") // @formatter:on public final class AArch64SHA256Op extends AArch64LIRInstruction { diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/aarch64/AArch64SHA3Op.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/aarch64/AArch64SHA3Op.java index f1ccc89d5237..d4826ddd0889 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/aarch64/AArch64SHA3Op.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/aarch64/AArch64SHA3Op.java @@ -87,7 +87,7 @@ import jdk.vm.ci.meta.Value; // @formatter:off -@SyncPort(from = "https://github.com/openjdk/jdk/blob/0a3a925ad88921d387aa851157f54ac0054d347b/src/hotspot/cpu/aarch64/stubGenerator_aarch64.cpp#L3973-L4195", +@SyncPort(from = "https://github.com/openjdk/jdk/blob/ce8399fd6071766114f5f201b6e44a7abdba9f5a/src/hotspot/cpu/aarch64/stubGenerator_aarch64.cpp#L3989-L4211", sha1 = "c17848fadbacb526e5da3c4e7c2a300c8160e092") // @formatter:on public final class AArch64SHA3Op extends AArch64LIRInstruction { diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/aarch64/AArch64SHA512Op.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/aarch64/AArch64SHA512Op.java index e97ca72d5272..aadf076b2b56 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/aarch64/AArch64SHA512Op.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/aarch64/AArch64SHA512Op.java @@ -81,7 +81,7 @@ import jdk.vm.ci.meta.Value; // @formatter:off -@SyncPort(from = "https://github.com/openjdk/jdk/blob/0a3a925ad88921d387aa851157f54ac0054d347b/src/hotspot/cpu/aarch64/stubGenerator_aarch64.cpp#L3798-L3971", +@SyncPort(from = "https://github.com/openjdk/jdk/blob/ce8399fd6071766114f5f201b6e44a7abdba9f5a/src/hotspot/cpu/aarch64/stubGenerator_aarch64.cpp#L3814-L3987", sha1 = "9a27893e95da304e616ebd2105529e39d9634483") // @formatter:on public final class AArch64SHA512Op extends AArch64LIRInstruction { diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/amd64/AMD64AESDecryptOp.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/amd64/AMD64AESDecryptOp.java index 5e42667e74c9..1d5713daa29f 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/amd64/AMD64AESDecryptOp.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/amd64/AMD64AESDecryptOp.java @@ -43,7 +43,7 @@ import jdk.vm.ci.meta.Value; // @formatter:off -@SyncPort(from = "https://github.com/openjdk/jdk/blob/d7b941640638b35f9ac1ef11cd6bf6ccb795c29a/src/hotspot/cpu/x86/stubGenerator_x86_64_aes.cpp#L1011-L1104", +@SyncPort(from = "https://github.com/openjdk/jdk/blob/ce8399fd6071766114f5f201b6e44a7abdba9f5a/src/hotspot/cpu/x86/stubGenerator_x86_64_aes.cpp#L1119-L1212", sha1 = "e87f6c5b4d86975678f423126a4c79c1e31b6833") // @formatter:on public final class AMD64AESDecryptOp extends AMD64LIRInstruction { diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/amd64/AMD64AESEncryptOp.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/amd64/AMD64AESEncryptOp.java index 601bcb024d40..8ec257668d3e 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/amd64/AMD64AESEncryptOp.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/amd64/AMD64AESEncryptOp.java @@ -48,7 +48,7 @@ import jdk.vm.ci.meta.Value; // @formatter:off -@SyncPort(from = "https://github.com/openjdk/jdk/blob/d7b941640638b35f9ac1ef11cd6bf6ccb795c29a/src/hotspot/cpu/x86/stubGenerator_x86_64_aes.cpp#L917-L1009", +@SyncPort(from = "https://github.com/openjdk/jdk/blob/ce8399fd6071766114f5f201b6e44a7abdba9f5a/src/hotspot/cpu/x86/stubGenerator_x86_64_aes.cpp#L1025-L1117", sha1 = "beab5f4817b620d98201e17dc1e07f680177b147") // @formatter:on public final class AMD64AESEncryptOp extends AMD64LIRInstruction { diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/amd64/AMD64BigIntegerMulAddOp.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/amd64/AMD64BigIntegerMulAddOp.java index f239ca20ea88..dc890ce120d6 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/amd64/AMD64BigIntegerMulAddOp.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/amd64/AMD64BigIntegerMulAddOp.java @@ -57,11 +57,11 @@ import jdk.vm.ci.meta.Value; // @formatter:off -@SyncPort(from = "https://github.com/openjdk/jdk/blob/0a3a925ad88921d387aa851157f54ac0054d347b/src/hotspot/cpu/x86/stubGenerator_x86_64.cpp#L3185-L3237", +@SyncPort(from = "https://github.com/openjdk/jdk/blob/ce8399fd6071766114f5f201b6e44a7abdba9f5a/src/hotspot/cpu/x86/stubGenerator_x86_64.cpp#L3186-L3238", sha1 = "2f3b577fa7f0ced9cc2514af80d2c2833ab7caf2") -@SyncPort(from = "https://github.com/openjdk/jdk/blob/0a3a925ad88921d387aa851157f54ac0054d347b/src/hotspot/cpu/x86/macroAssembler_x86.cpp#L6989-L7023", +@SyncPort(from = "https://github.com/openjdk/jdk/blob/ce8399fd6071766114f5f201b6e44a7abdba9f5a/src/hotspot/cpu/x86/macroAssembler_x86.cpp#L7138-L7172", sha1 = "e68b8c7bdb37d4bd1350c7e1219fdcb419d2618a") -@SyncPort(from = "https://github.com/openjdk/jdk/blob/0a3a925ad88921d387aa851157f54ac0054d347b/src/hotspot/cpu/x86/macroAssembler_x86.cpp#L7241-L7418", +@SyncPort(from = "https://github.com/openjdk/jdk/blob/ce8399fd6071766114f5f201b6e44a7abdba9f5a/src/hotspot/cpu/x86/macroAssembler_x86.cpp#L7390-L7567", sha1 = "d89ad721deb560178359f86e8c6c96ffc6530878") // @formatter:on public final class AMD64BigIntegerMulAddOp extends AMD64LIRInstruction { diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/amd64/AMD64BigIntegerMultiplyToLenOp.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/amd64/AMD64BigIntegerMultiplyToLenOp.java index f0f33e45b12d..28a44acb64f5 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/amd64/AMD64BigIntegerMultiplyToLenOp.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/amd64/AMD64BigIntegerMultiplyToLenOp.java @@ -57,9 +57,9 @@ import jdk.vm.ci.meta.Value; // @formatter:off -@SyncPort(from = "https://github.com/openjdk/jdk/blob/0a3a925ad88921d387aa851157f54ac0054d347b/src/hotspot/cpu/x86/stubGenerator_x86_64.cpp#L2948-L3009", +@SyncPort(from = "https://github.com/openjdk/jdk/blob/ce8399fd6071766114f5f201b6e44a7abdba9f5a/src/hotspot/cpu/x86/stubGenerator_x86_64.cpp#L2949-L3010", sha1 = "a4f29fea55385633aac2f71f50d57f9b378516d9") -@SyncPort(from = "https://github.com/openjdk/jdk/blob/0a3a925ad88921d387aa851157f54ac0054d347b/src/hotspot/cpu/x86/macroAssembler_x86.cpp#L6245-L6702", +@SyncPort(from = "https://github.com/openjdk/jdk/blob/ce8399fd6071766114f5f201b6e44a7abdba9f5a/src/hotspot/cpu/x86/macroAssembler_x86.cpp#L6394-L6851", sha1 = "6aac8a818c14df53d6201ac3df0bc35d3aaac9e4") // @formatter:on public final class AMD64BigIntegerMultiplyToLenOp extends AMD64LIRInstruction { diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/amd64/AMD64BigIntegerSquareToLenOp.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/amd64/AMD64BigIntegerSquareToLenOp.java index 5a05adf51587..37057795d21c 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/amd64/AMD64BigIntegerSquareToLenOp.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/amd64/AMD64BigIntegerSquareToLenOp.java @@ -56,9 +56,9 @@ import jdk.vm.ci.meta.Value; // @formatter:off -@SyncPort(from = "https://github.com/openjdk/jdk/blob/0a3a925ad88921d387aa851157f54ac0054d347b/src/hotspot/cpu/x86/stubGenerator_x86_64.cpp#L3063-L3107", +@SyncPort(from = "https://github.com/openjdk/jdk/blob/ce8399fd6071766114f5f201b6e44a7abdba9f5a/src/hotspot/cpu/x86/stubGenerator_x86_64.cpp#L3064-L3108", sha1 = "ab70559cefe0dc177a290d417047955fba3ad1fc") -@SyncPort(from = "https://github.com/openjdk/jdk/blob/0a3a925ad88921d387aa851157f54ac0054d347b/src/hotspot/cpu/x86/macroAssembler_x86.cpp#L6926-L7239", +@SyncPort(from = "https://github.com/openjdk/jdk/blob/ce8399fd6071766114f5f201b6e44a7abdba9f5a/src/hotspot/cpu/x86/macroAssembler_x86.cpp#L7075-L7388", sha1 = "2e4ea1436904cbd5a933eb8c687296d9bbefe4f0") // @formatter:on public final class AMD64BigIntegerSquareToLenOp extends AMD64LIRInstruction { diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/amd64/AMD64BitSwapOp.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/amd64/AMD64BitSwapOp.java index a5f47c9e036b..3d8d01cfc6cd 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/amd64/AMD64BitSwapOp.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/amd64/AMD64BitSwapOp.java @@ -43,7 +43,7 @@ import jdk.vm.ci.meta.Value; // @formatter:off -@SyncPort(from = "https://github.com/openjdk/jdk/blob/0a3a925ad88921d387aa851157f54ac0054d347b/src/hotspot/cpu/x86/c2_MacroAssembler_x86.cpp#L5744-L5826", +@SyncPort(from = "https://github.com/openjdk/jdk/blob/ce8399fd6071766114f5f201b6e44a7abdba9f5a/src/hotspot/cpu/x86/c2_MacroAssembler_x86.cpp#L5798-L5880", sha1 = "cb807f6ece0a42ba5abae88477e8899436d09a4e") // @formatter:on public final class AMD64BitSwapOp extends AMD64LIRInstruction { diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/amd64/AMD64CipherBlockChainingAESDecryptOp.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/amd64/AMD64CipherBlockChainingAESDecryptOp.java index 16606d1f7251..830f659f188b 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/amd64/AMD64CipherBlockChainingAESDecryptOp.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/amd64/AMD64CipherBlockChainingAESDecryptOp.java @@ -69,7 +69,7 @@ import jdk.vm.ci.meta.Value; // @formatter:off -@SyncPort(from = "https://github.com/openjdk/jdk/blob/d7b941640638b35f9ac1ef11cd6bf6ccb795c29a/src/hotspot/cpu/x86/stubGenerator_x86_64_aes.cpp#L1255-L1511", +@SyncPort(from = "https://github.com/openjdk/jdk/blob/ce8399fd6071766114f5f201b6e44a7abdba9f5a/src/hotspot/cpu/x86/stubGenerator_x86_64_aes.cpp#L1363-L1619", sha1 = "e3481678a0bdb4d66c9b3641ba44a3559979aff5") // @formatter:on public final class AMD64CipherBlockChainingAESDecryptOp extends AMD64LIRInstruction { diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/amd64/AMD64CipherBlockChainingAESEncryptOp.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/amd64/AMD64CipherBlockChainingAESEncryptOp.java index 98524cefa356..d6be7bead88b 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/amd64/AMD64CipherBlockChainingAESEncryptOp.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/amd64/AMD64CipherBlockChainingAESEncryptOp.java @@ -64,7 +64,7 @@ import jdk.vm.ci.meta.Value; // @formatter:off -@SyncPort(from = "https://github.com/openjdk/jdk/blob/d7b941640638b35f9ac1ef11cd6bf6ccb795c29a/src/hotspot/cpu/x86/stubGenerator_x86_64_aes.cpp#L1107-L1253", +@SyncPort(from = "https://github.com/openjdk/jdk/blob/ce8399fd6071766114f5f201b6e44a7abdba9f5a/src/hotspot/cpu/x86/stubGenerator_x86_64_aes.cpp#L1215-L1361", sha1 = "644bffae25607c21475e4b5f51476fa6117f4ca2") // @formatter:on public final class AMD64CipherBlockChainingAESEncryptOp extends AMD64LIRInstruction { diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/amd64/AMD64CounterModeAESCryptOp.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/amd64/AMD64CounterModeAESCryptOp.java index 0469f3851314..f1009149f97d 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/amd64/AMD64CounterModeAESCryptOp.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/amd64/AMD64CounterModeAESCryptOp.java @@ -69,7 +69,7 @@ import jdk.vm.ci.meta.Value; // @formatter:off -@SyncPort(from = "https://github.com/openjdk/jdk/blob/d7b941640638b35f9ac1ef11cd6bf6ccb795c29a/src/hotspot/cpu/x86/stubGenerator_x86_64_aes.cpp#L333-L640", +@SyncPort(from = "https://github.com/openjdk/jdk/blob/ce8399fd6071766114f5f201b6e44a7abdba9f5a/src/hotspot/cpu/x86/stubGenerator_x86_64_aes.cpp#L441-L748", sha1 = "f73999add65bf7ccd9ee310df5412213fac98192") // @formatter:on public final class AMD64CounterModeAESCryptOp extends AMD64LIRInstruction { diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/amd64/AMD64EncodeArrayOp.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/amd64/AMD64EncodeArrayOp.java index c23726d51ba5..7aefa3260b4b 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/amd64/AMD64EncodeArrayOp.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/amd64/AMD64EncodeArrayOp.java @@ -54,7 +54,7 @@ import jdk.vm.ci.meta.Value; // @formatter:off -@SyncPort(from = "https://github.com/openjdk/jdk/blob/0a3a925ad88921d387aa851157f54ac0054d347b/src/hotspot/cpu/x86/macroAssembler_x86.cpp#L6084-L6242", +@SyncPort(from = "https://github.com/openjdk/jdk/blob/ce8399fd6071766114f5f201b6e44a7abdba9f5a/src/hotspot/cpu/x86/macroAssembler_x86.cpp#L6233-L6391", sha1 = "90e15d79705bc87ffbefbcaa4bdfa55123c12aba") // @formatter:on @Opcode("AMD64_ENCODE_ARRAY") diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/amd64/AMD64MD5Op.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/amd64/AMD64MD5Op.java index 98eacf2b148c..06cf7f6429ff 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/amd64/AMD64MD5Op.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/amd64/AMD64MD5Op.java @@ -48,7 +48,7 @@ import jdk.vm.ci.meta.Value; // @formatter:off -@SyncPort(from = "https://github.com/openjdk/jdk/blob/0a3a925ad88921d387aa851157f54ac0054d347b/src/hotspot/cpu/x86/stubGenerator_x86_64.cpp#L1287-L1323", +@SyncPort(from = "https://github.com/openjdk/jdk/blob/ce8399fd6071766114f5f201b6e44a7abdba9f5a/src/hotspot/cpu/x86/stubGenerator_x86_64.cpp#L1288-L1324", sha1 = "acf2eea69d799b0a1a38edaff048ff30f5257016") @SyncPort(from = "https://github.com/openjdk/jdk/blob/0487aa61c67de695d008af4fe75c2a3072261a6f/src/hotspot/cpu/x86/macroAssembler_x86_md5.cpp#L52-L209", sha1 = "5cb0a6acf3329957f7f5868a32d4d228f98595ab") diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/amd64/AMD64RoundFloatToIntegerOp.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/amd64/AMD64RoundFloatToIntegerOp.java index 5d68f6b6fa00..594e423f4fb2 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/amd64/AMD64RoundFloatToIntegerOp.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/amd64/AMD64RoundFloatToIntegerOp.java @@ -46,9 +46,9 @@ * {@link Math#round} algorithm for details. */ // @formatter:off -@SyncPort(from = "https://github.com/openjdk/jdk/blob/0a3a925ad88921d387aa851157f54ac0054d347b/src/hotspot/cpu/x86/macroAssembler_x86.cpp#L9562-L9658", +@SyncPort(from = "https://github.com/openjdk/jdk/blob/ce8399fd6071766114f5f201b6e44a7abdba9f5a/src/hotspot/cpu/x86/macroAssembler_x86.cpp#L9733-L9829", sha1 = "9e13c7375bbb35809ad79ebd6a9cc19e66f57aa1") -@SyncPort(from = "https://github.com/openjdk/jdk/blob/0a3a925ad88921d387aa851157f54ac0054d347b/src/hotspot/cpu/x86/stubGenerator_x86_64.cpp#L597-L764", +@SyncPort(from = "https://github.com/openjdk/jdk/blob/ce8399fd6071766114f5f201b6e44a7abdba9f5a/src/hotspot/cpu/x86/stubGenerator_x86_64.cpp#L598-L765", sha1 = "312f16a0551887f78cc567638477bbbcbc3765c5") // @formatter:on @Opcode("AMD64_ROUND_FLOAT_TO_INTEGER") diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/amd64/AMD64SHA1Op.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/amd64/AMD64SHA1Op.java index 093cbea2f21c..7b085d93887e 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/amd64/AMD64SHA1Op.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/amd64/AMD64SHA1Op.java @@ -55,7 +55,7 @@ import jdk.vm.ci.meta.Value; // @formatter:off -@SyncPort(from = "https://github.com/openjdk/jdk/blob/0a3a925ad88921d387aa851157f54ac0054d347b/src/hotspot/cpu/x86/stubGenerator_x86_64.cpp#L1347-L1382", +@SyncPort(from = "https://github.com/openjdk/jdk/blob/ce8399fd6071766114f5f201b6e44a7abdba9f5a/src/hotspot/cpu/x86/stubGenerator_x86_64.cpp#L1348-L1383", sha1 = "12a9844b6c686f0185bb738d9c0758a66b54ba7a") @SyncPort(from = "https://github.com/openjdk/jdk/blob/b3f34039fedd3c49404783ec880e1885dceb296b/src/hotspot/cpu/x86/macroAssembler_x86_sha.cpp#L32-L233", sha1 = "983fb75958945f5fb6b89327bd807f98b4e8c99c") diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/amd64/AMD64SHA256Op.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/amd64/AMD64SHA256Op.java index e7968927d9ba..f9acd30e1cbb 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/amd64/AMD64SHA256Op.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/amd64/AMD64SHA256Op.java @@ -56,7 +56,7 @@ import jdk.vm.ci.meta.Value; // @formatter:off -@SyncPort(from = "https://github.com/openjdk/jdk/blob/0a3a925ad88921d387aa851157f54ac0054d347b/src/hotspot/cpu/x86/stubGenerator_x86_64.cpp#L1430-L1472", +@SyncPort(from = "https://github.com/openjdk/jdk/blob/ce8399fd6071766114f5f201b6e44a7abdba9f5a/src/hotspot/cpu/x86/stubGenerator_x86_64.cpp#L1431-L1473", sha1 = "593a45db708f1b6a74086cf170612c1102fe56c2") @SyncPort(from = "https://github.com/openjdk/jdk/blob/8c9d091f19760deece8daf3e57add85482b9f2a7/src/hotspot/cpu/x86/macroAssembler_x86_sha.cpp#L235-L493", sha1 = "722bdd7519a7d7b9d9cec900af38137f1849ac4e") diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/amd64/AMD64SHA512Op.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/amd64/AMD64SHA512Op.java index 23b91d7ccc10..689134c0dab8 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/amd64/AMD64SHA512Op.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/amd64/AMD64SHA512Op.java @@ -73,7 +73,7 @@ import jdk.vm.ci.meta.Value; // @formatter:off -@SyncPort(from = "https://github.com/openjdk/jdk/blob/0a3a925ad88921d387aa851157f54ac0054d347b/src/hotspot/cpu/x86/stubGenerator_x86_64.cpp#L1474-L1507", +@SyncPort(from = "https://github.com/openjdk/jdk/blob/ce8399fd6071766114f5f201b6e44a7abdba9f5a/src/hotspot/cpu/x86/stubGenerator_x86_64.cpp#L1475-L1508", sha1 = "0bdbfb85ba18320b87b5dd9ae87e1fd9d55b5882") @SyncPort(from = "https://github.com/openjdk/jdk/blob/8cd43bff3cd18d6e83cbf07b78a809ad002993c5/src/hotspot/cpu/x86/macroAssembler_x86_sha.cpp#L1037-L1520", sha1 = "0c248f818f86a13bd0fa92be499928737723f395") diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/amd64/AMD64VectorizedHashCodeOp.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/amd64/AMD64VectorizedHashCodeOp.java index 182acde59ba7..4e331cdadf86 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/amd64/AMD64VectorizedHashCodeOp.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/amd64/AMD64VectorizedHashCodeOp.java @@ -75,11 +75,11 @@ import jdk.vm.ci.meta.Value; // @formatter:off -@SyncPort(from = "https://github.com/openjdk/jdk/blob/0a3a925ad88921d387aa851157f54ac0054d347b/src/hotspot/cpu/x86/c2_MacroAssembler_x86.cpp#L1698-L1797", +@SyncPort(from = "https://github.com/openjdk/jdk/blob/ce8399fd6071766114f5f201b6e44a7abdba9f5a/src/hotspot/cpu/x86/c2_MacroAssembler_x86.cpp#L1744-L1843", sha1 = "a93850c44f7e34fcec05226bae95fd695b2ea2f7") -@SyncPort(from = "https://github.com/openjdk/jdk/blob/0a3a925ad88921d387aa851157f54ac0054d347b/src/hotspot/cpu/x86/c2_MacroAssembler_x86.cpp#L1919-L1965", +@SyncPort(from = "https://github.com/openjdk/jdk/blob/ce8399fd6071766114f5f201b6e44a7abdba9f5a/src/hotspot/cpu/x86/c2_MacroAssembler_x86.cpp#L1965-L2011", sha1 = "9cbba8bd6c4037427fa46f067abb722b15aca90c") -@SyncPort(from = "https://github.com/openjdk/jdk/blob/0a3a925ad88921d387aa851157f54ac0054d347b/src/hotspot/cpu/x86/c2_MacroAssembler_x86.cpp#L3237-L3424", +@SyncPort(from = "https://github.com/openjdk/jdk/blob/ce8399fd6071766114f5f201b6e44a7abdba9f5a/src/hotspot/cpu/x86/c2_MacroAssembler_x86.cpp#L3283-L3470", sha1 = "2457cf3f9d3ff89c1515fa5d95cc7c8437a5318b") // @formatter:on @Opcode("VECTORIZED_HASHCODE") diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/amd64/AMD64VectorizedMismatchOp.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/amd64/AMD64VectorizedMismatchOp.java index 47b8777d8e0e..1733a56696db 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/amd64/AMD64VectorizedMismatchOp.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/amd64/AMD64VectorizedMismatchOp.java @@ -61,7 +61,7 @@ * instructions where possible. */ // @formatter:off -@SyncPort(from = "https://github.com/openjdk/jdk/blob/0a3a925ad88921d387aa851157f54ac0054d347b/src/hotspot/cpu/x86/macroAssembler_x86.cpp#L6704-L6922", +@SyncPort(from = "https://github.com/openjdk/jdk/blob/ce8399fd6071766114f5f201b6e44a7abdba9f5a/src/hotspot/cpu/x86/macroAssembler_x86.cpp#L6853-L7071", sha1 = "72f9b7a60b75ecabf09fc10cb01a9504be97957a") // @formatter:on @Opcode("VECTORIZED_MISMATCH") From 13309ccfa3576832ba3fe4d42fee17014790ef90 Mon Sep 17 00:00:00 2001 From: Josef Haider Date: Mon, 11 Dec 2023 14:08:05 +0100 Subject: [PATCH 228/593] Add SyncPort annotation to AMD64StringUTF16CompressOp --- .../graal/compiler/lir/amd64/AMD64StringUTF16CompressOp.java | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/amd64/AMD64StringUTF16CompressOp.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/amd64/AMD64StringUTF16CompressOp.java index 1a7feaa1ece0..7db93a43c2b3 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/amd64/AMD64StringUTF16CompressOp.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/amd64/AMD64StringUTF16CompressOp.java @@ -46,6 +46,7 @@ import jdk.graal.compiler.debug.Assertions; import jdk.graal.compiler.lir.LIRInstructionClass; import jdk.graal.compiler.lir.Opcode; +import jdk.graal.compiler.lir.SyncPort; import jdk.graal.compiler.lir.asm.CompilationResultBuilder; import jdk.graal.compiler.lir.gen.LIRGeneratorTool; import jdk.graal.compiler.serviceprovider.JavaVersionUtil; @@ -57,6 +58,10 @@ import jdk.vm.ci.meta.JavaKind; import jdk.vm.ci.meta.Value; +// @formatter:off +@SyncPort(from = "https://github.com/openjdk/jdk/blob/ce8399fd6071766114f5f201b6e44a7abdba9f5a/src/hotspot/cpu/x86/macroAssembler_x86.cpp#L8647-L8855", + sha1 = "3e365037f473204b3f742ab364bd9ad514e72161") +// @formatter:on @Opcode("AMD64_STRING_COMPRESS") public final class AMD64StringUTF16CompressOp extends AMD64ComplexVectorOp { public static final LIRInstructionClass TYPE = LIRInstructionClass.create(AMD64StringUTF16CompressOp.class); From cdab6fd79c4f7fd427be4abef79ef857feefa23b Mon Sep 17 00:00:00 2001 From: Josef Haider Date: Mon, 11 Dec 2023 16:47:16 +0100 Subject: [PATCH 229/593] Update line numbers in SyncPort annotations --- .../compiler/lir/amd64/AMD64NormalizedUnsignedCompareOp.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/amd64/AMD64NormalizedUnsignedCompareOp.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/amd64/AMD64NormalizedUnsignedCompareOp.java index 3765776b6971..b07e7849b1d4 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/amd64/AMD64NormalizedUnsignedCompareOp.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/amd64/AMD64NormalizedUnsignedCompareOp.java @@ -41,9 +41,9 @@ * Returns -1, 0, or 1 if either x < y, x == y, or x > y. */ // @formatter:off -@SyncPort(from = "https://github.com/openjdk/jdk/blob/0a3a925ad88921d387aa851157f54ac0054d347b/src/hotspot/cpu/x86/x86_64.ad#L12905-L12929", +@SyncPort(from = "https://github.com/openjdk/jdk/blob/486594d4273e9d5a8db43de861e3ca3ce823f0da/src/hotspot/cpu/x86/x86_64.ad#L11894-L11918", sha1 = "90dcf08952d34fa4381e43cbe988ce01a0fd2f26") -@SyncPort(from = "https://github.com/openjdk/jdk/blob/0a3a925ad88921d387aa851157f54ac0054d347b/src/hotspot/cpu/x86/x86_64.ad#L12957-L12981", +@SyncPort(from = "https://github.com/openjdk/jdk/blob/486594d4273e9d5a8db43de861e3ca3ce823f0da/src/hotspot/cpu/x86/x86_64.ad#L11946-L11970", sha1 = "541cc1716b2aa630e52634a3f1595159f274aa8f") // @formatter:on public class AMD64NormalizedUnsignedCompareOp extends AMD64LIRInstruction { From 95f87136217b71c9dd602ab9e20aa407fd695775 Mon Sep 17 00:00:00 2001 From: Josef Haider Date: Mon, 11 Dec 2023 16:48:37 +0100 Subject: [PATCH 230/593] Update SyncPort annotation of AArch64EncodeArrayOp. Hash changed due to changed comment. --- .../jdk/graal/compiler/lir/aarch64/AArch64EncodeArrayOp.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/aarch64/AArch64EncodeArrayOp.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/aarch64/AArch64EncodeArrayOp.java index 02f5f5c385d9..20ab52266961 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/aarch64/AArch64EncodeArrayOp.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/aarch64/AArch64EncodeArrayOp.java @@ -51,8 +51,8 @@ import jdk.vm.ci.meta.Value; // @formatter:off -@SyncPort(from = "https://github.com/openjdk/jdk/blob/0a3a925ad88921d387aa851157f54ac0054d347b/src/hotspot/cpu/aarch64/macroAssembler_aarch64.cpp#L5649-L5761", - sha1 = "95adbb3a56ad94eca2698b6fd6d8359a15069de7") +@SyncPort(from = "https://github.com/openjdk/jdk/blob/486594d4273e9d5a8db43de861e3ca3ce823f0da/src/hotspot/cpu/aarch64/macroAssembler_aarch64.cpp#L5666-L5779", + sha1 = "80e6323172af5e8a33625b4eb14629cdad500a0f") // @formatter:on @Opcode("AArch64_ENCODE_ARRAY") public final class AArch64EncodeArrayOp extends AArch64ComplexVectorOp { From 76fa638995fd3eb443deb4e4ee32ece8106bb223 Mon Sep 17 00:00:00 2001 From: Josef Haider Date: Mon, 11 Dec 2023 16:49:10 +0100 Subject: [PATCH 231/593] Sync upstream changes of AMD64CountPositivesOp --- .../lir/amd64/AMD64CountPositivesOp.java | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/amd64/AMD64CountPositivesOp.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/amd64/AMD64CountPositivesOp.java index 762d38f88bee..d4fa8acfda21 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/amd64/AMD64CountPositivesOp.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/amd64/AMD64CountPositivesOp.java @@ -55,8 +55,8 @@ import jdk.vm.ci.meta.Value; // @formatter:off -@SyncPort(from = "https://github.com/openjdk/jdk/blob/0a3a925ad88921d387aa851157f54ac0054d347b/src/hotspot/cpu/x86/c2_MacroAssembler_x86.cpp#L3822-L4084", - sha1 = "3b48e8dac29e4f52f708d9e667eb596fca146c9a") +@SyncPort(from = "https://github.com/openjdk/jdk/blob/486594d4273e9d5a8db43de861e3ca3ce823f0da/src/hotspot/cpu/x86/c2_MacroAssembler_x86.cpp#L3868-L4138", + sha1 = "684b5353c58bbf92e4403aa985113a78a1f38930") // @formatter:on @Opcode("AMD64_COUNT_POSITIVES") public final class AMD64CountPositivesOp extends AMD64ComplexVectorOp { @@ -146,9 +146,9 @@ public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) { masm.movl(tmp1, len); masm.emit(VPXOR, vec2, vec2, vec2, ZMM); // tail count (in chars) 0x3 - masm.andl(tmp1, 64 - 1); + masm.andl(tmp1, 0x0000003f); // vector count (in chars) - masm.andlAndJcc(len, ~(64 - 1), ConditionFlag.Zero, labelTestTail, true); + masm.andlAndJcc(len, 0xffffffc0, ConditionFlag.Zero, labelTestTail, true); masm.leaq(ary1, new AMD64Address(ary1, len, Stride.S1)); masm.negq(len); @@ -165,6 +165,7 @@ public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) { // bail out when there is nothing to be done masm.testlAndJcc(tmp1, -1, ConditionFlag.Zero, labelDone, false); + // check the tail for absence of negatives // ~(~0 << len) applied up to two times (for 32-bit scenario) masm.movq(tmp3Aliased, 0xFFFFFFFF_FFFFFFFFL); masm.emit(SHLX, tmp3Aliased, tmp3Aliased, tmp1, QWORD); @@ -176,8 +177,14 @@ public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) { masm.ktestq(mask1, mask2); masm.jcc(ConditionFlag.Zero, labelDone); + // do a full check for negative registers in the tail + // tmp1 holds low 6-bit from original len + masm.movl(len, tmp1); + // ary1 already pointing to the right place + masm.jmpb(labelTailStart); + masm.bind(labelBreakLoop); - // At least one byte in the last 64 bytes is negative. + // At least one byte in the last 64 byte block was negative. // Set up to look at the last 64 bytes as if they were a tail masm.leaq(ary1, new AMD64Address(ary1, len, Stride.S1)); masm.addq(result, len); From af703de350d9a3efc98ab6e2719f286b5795a35c Mon Sep 17 00:00:00 2001 From: Josef Haider Date: Tue, 12 Dec 2023 12:31:24 +0100 Subject: [PATCH 232/593] Replace custom AArch64StringUTF16CompressOp with AArch64EncodeArrayOp. --- .../lir/aarch64/AArch64EncodeArrayOp.java | 51 +++-- .../aarch64/AArch64StringUTF16CompressOp.java | 216 ++++-------------- 2 files changed, 73 insertions(+), 194 deletions(-) diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/aarch64/AArch64EncodeArrayOp.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/aarch64/AArch64EncodeArrayOp.java index 20ab52266961..af97eec88221 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/aarch64/AArch64EncodeArrayOp.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/aarch64/AArch64EncodeArrayOp.java @@ -24,11 +24,11 @@ */ package jdk.graal.compiler.lir.aarch64; -import static jdk.vm.ci.code.ValueUtil.asRegister; import static jdk.graal.compiler.asm.aarch64.AArch64ASIMDAssembler.ASIMDSize.FullReg; import static jdk.graal.compiler.asm.aarch64.AArch64Address.createBaseRegisterOnlyAddress; import static jdk.graal.compiler.asm.aarch64.AArch64Address.createImmediateAddress; import static jdk.graal.compiler.lir.LIRInstruction.OperandFlag.REG; +import static jdk.vm.ci.code.ValueUtil.asRegister; import jdk.graal.compiler.asm.Label; import jdk.graal.compiler.asm.aarch64.AArch64ASIMDAssembler.ASIMDInstruction; @@ -38,13 +38,13 @@ import jdk.graal.compiler.asm.aarch64.AArch64Assembler.ConditionFlag; import jdk.graal.compiler.asm.aarch64.AArch64Assembler.PrefetchMode; import jdk.graal.compiler.asm.aarch64.AArch64MacroAssembler; -import jdk.graal.compiler.lir.asm.CompilationResultBuilder; +import jdk.graal.compiler.debug.GraalError; import jdk.graal.compiler.lir.LIRInstructionClass; import jdk.graal.compiler.lir.Opcode; import jdk.graal.compiler.lir.SyncPort; +import jdk.graal.compiler.lir.asm.CompilationResultBuilder; import jdk.graal.compiler.lir.gen.LIRGeneratorTool; import jdk.graal.compiler.lir.gen.LIRGeneratorTool.CharsetName; - import jdk.vm.ci.aarch64.AArch64Kind; import jdk.vm.ci.code.Register; import jdk.vm.ci.meta.AllocatableValue; @@ -81,31 +81,46 @@ public AArch64EncodeArrayOp(LIRGeneratorTool tool, Value result, Value src, Valu this.srcValue = tool.newVariable(src.getValueKind()); this.dstValue = tool.newVariable(dst.getValueKind()); - this.vectorTempValue = allocateConsecutiveVectorRegisters(tool, charset == CharsetName.ASCII ? 7 : 6); - + this.vectorTempValue = allocateVectorRegisters(tool, charset); this.charset = charset; - assert charset == CharsetName.ASCII || charset == CharsetName.ISO_8859_1 : charset; + } + + public static Value[] allocateVectorRegisters(LIRGeneratorTool tool, CharsetName charset) { + switch (charset) { + case ASCII -> { + return allocateConsecutiveVectorRegisters(tool, 7); + } + case ISO_8859_1 -> { + return allocateConsecutiveVectorRegisters(tool, 6); + } + default -> throw GraalError.shouldNotReachHereUnexpectedValue(charset); // ExcludeFromJacocoGeneratedReport + } } @Override protected void emitCode(CompilationResultBuilder crb, AArch64MacroAssembler masm) { - AArch64Move.move(AArch64Kind.QWORD, crb, masm, srcValue, originSrcValue); - AArch64Move.move(AArch64Kind.QWORD, crb, masm, dstValue, originDstValue); - - boolean ascii = charset == CharsetName.ASCII; - Register src = asRegister(srcValue); Register dst = asRegister(dstValue); Register len = asRegister(lenValue); Register res = asRegister(resultValue); - Register vtmp0 = asRegister(vectorTempValue[0]); - Register vtmp1 = asRegister(vectorTempValue[1]); - Register vtmp2 = asRegister(vectorTempValue[2]); - Register vtmp3 = asRegister(vectorTempValue[3]); - Register vlo0 = asRegister(vectorTempValue[4]); - Register vlo1 = asRegister(vectorTempValue[5]); - Register vmask = ascii ? asRegister(vectorTempValue[6]) : null; + AArch64Move.move(AArch64Kind.QWORD, crb, masm, srcValue, originSrcValue); + AArch64Move.move(AArch64Kind.QWORD, crb, masm, dstValue, originDstValue); + + emitEncodeArrayOp(masm, res, src, dst, len, vectorTempValue, charset); + } + + public static void emitEncodeArrayOp(AArch64MacroAssembler masm, Register res, Register src, Register dst, Register len, Value[] vectorRegisters, CharsetName charset) { + GraalError.guarantee(charset == CharsetName.ASCII || charset == CharsetName.ISO_8859_1, charset.toString()); + boolean ascii = charset == CharsetName.ASCII; + + Register vtmp0 = asRegister(vectorRegisters[0]); + Register vtmp1 = asRegister(vectorRegisters[1]); + Register vtmp2 = asRegister(vectorRegisters[2]); + Register vtmp3 = asRegister(vectorRegisters[3]); + Register vlo0 = asRegister(vectorRegisters[4]); + Register vlo1 = asRegister(vectorRegisters[5]); + Register vmask = ascii ? asRegister(vectorRegisters[6]) : null; Register cnt = res; diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/aarch64/AArch64StringUTF16CompressOp.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/aarch64/AArch64StringUTF16CompressOp.java index 876054ad9251..682534f63ffb 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/aarch64/AArch64StringUTF16CompressOp.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/aarch64/AArch64StringUTF16CompressOp.java @@ -25,206 +25,70 @@ */ package jdk.graal.compiler.lir.aarch64; -import static jdk.vm.ci.aarch64.AArch64.SIMD; +import static jdk.graal.compiler.lir.LIRInstruction.OperandFlag.REG; import static jdk.vm.ci.aarch64.AArch64.zr; import static jdk.vm.ci.code.ValueUtil.asRegister; -import static jdk.graal.compiler.lir.LIRInstruction.OperandFlag.REG; -import jdk.graal.compiler.asm.Label; -import jdk.graal.compiler.asm.aarch64.AArch64ASIMDAssembler; -import jdk.graal.compiler.asm.aarch64.AArch64ASIMDAssembler.ElementSize; -import jdk.graal.compiler.asm.aarch64.AArch64Address; -import jdk.graal.compiler.asm.aarch64.AArch64Address.AddressingMode; import jdk.graal.compiler.asm.aarch64.AArch64Assembler; -import jdk.graal.compiler.asm.aarch64.AArch64Assembler.ConditionFlag; import jdk.graal.compiler.asm.aarch64.AArch64MacroAssembler; -import jdk.graal.compiler.asm.aarch64.AArch64MacroAssembler.ScratchRegister; -import jdk.graal.compiler.core.common.LIRKind; -import jdk.graal.compiler.lir.asm.CompilationResultBuilder; +import jdk.graal.compiler.debug.GraalError; import jdk.graal.compiler.lir.LIRInstructionClass; import jdk.graal.compiler.lir.Opcode; +import jdk.graal.compiler.lir.SyncPort; +import jdk.graal.compiler.lir.asm.CompilationResultBuilder; import jdk.graal.compiler.lir.gen.LIRGeneratorTool; - +import jdk.graal.compiler.serviceprovider.JavaVersionUtil; import jdk.vm.ci.aarch64.AArch64Kind; import jdk.vm.ci.code.Register; import jdk.vm.ci.meta.AllocatableValue; +import jdk.vm.ci.meta.Value; +// @formatter:off +@SyncPort(from = "https://github.com/openjdk/jdk/blob/c51685267c7bd5a7cee27ebc2bf0d9899cda9d4c/src/hotspot/cpu/aarch64/macroAssembler_aarch64.cpp#L5887-L5897", + sha1 = "857dc6f9a492da6c8e20afb2139ae393efd228ac") +// @formatter:on @Opcode("AArch64_STRING_COMPRESS") -public final class AArch64StringUTF16CompressOp extends AArch64LIRInstruction { +public final class AArch64StringUTF16CompressOp extends AArch64ComplexVectorOp { public static final LIRInstructionClass TYPE = LIRInstructionClass.create(AArch64StringUTF16CompressOp.class); - private static final int CHUNK_ELEMENT_COUNT = 16; - @Def({REG}) protected AllocatableValue resultValue; - @Use({REG}) protected AllocatableValue len; - @Alive({REG}) protected AllocatableValue src; - @Alive({REG}) protected AllocatableValue dst; - @Temp({REG}) protected AllocatableValue temp1; - @Temp({REG}) protected AllocatableValue temp2; - @Temp({REG}) protected AllocatableValue temp3; - @Temp({REG}) protected AllocatableValue vectorTemp1; - @Temp({REG}) protected AllocatableValue vectorTemp2; - @Temp({REG}) protected AllocatableValue vectorTemp3; + @Alive({REG}) protected AllocatableValue lenValue; + @Alive({REG}) protected AllocatableValue srcValue; + @Alive({REG}) protected AllocatableValue dstValue; + @Temp({REG}) protected AllocatableValue[] temp; + @Temp({REG}) protected Value[] vectorTemp; public AArch64StringUTF16CompressOp(LIRGeneratorTool tool, AllocatableValue src, AllocatableValue dst, AllocatableValue len, AllocatableValue result) { super(TYPE); - assert result.getPlatformKind().equals(AArch64Kind.DWORD) : result; - assert len.getPlatformKind().equals(AArch64Kind.DWORD) : len; - assert src.getPlatformKind().equals(AArch64Kind.QWORD) : src; - assert dst.getPlatformKind().equals(AArch64Kind.QWORD) : dst; - - this.len = len; - this.src = src; - this.dst = dst; + GraalError.guarantee(result.getPlatformKind().equals(AArch64Kind.DWORD), "int value expected"); + GraalError.guarantee(len.getPlatformKind().equals(AArch64Kind.DWORD), "int value expected"); + GraalError.guarantee(src.getPlatformKind().equals(AArch64Kind.QWORD), "pointer value expected"); + GraalError.guarantee(dst.getPlatformKind().equals(AArch64Kind.QWORD), "pointer value expected"); + + this.lenValue = len; + this.srcValue = src; + this.dstValue = dst; resultValue = result; - LIRKind archWordKind = LIRKind.value(AArch64Kind.QWORD); - temp1 = tool.newVariable(archWordKind); - temp2 = tool.newVariable(archWordKind); - temp3 = tool.newVariable(archWordKind); - LIRKind vectorKind = LIRKind.value(tool.target().arch.getLargestStorableKind(SIMD)); - vectorTemp1 = tool.newVariable(vectorKind); - vectorTemp2 = tool.newVariable(vectorKind); - vectorTemp3 = tool.newVariable(vectorKind); + temp = allocateTempRegisters(tool, 3); + vectorTemp = AArch64EncodeArrayOp.allocateVectorRegisters(tool, LIRGeneratorTool.CharsetName.ISO_8859_1); } @Override public void emitCode(CompilationResultBuilder crb, AArch64MacroAssembler masm) { - Label simdImpl = new Label(); - Label scalarImpl = new Label(); - Label done = new Label(); - - /* - * Initialise result for successful return (a sign-extended length). Note length is - * guaranteed to be a non-negative value, so this is equivalent to zero-extending length. - */ - Register result = asRegister(resultValue); - masm.sxt(64, 32, result, asRegister(len)); - - // return immediately if length is zero - masm.cbz(32, result, done); - - Register srcAddress = asRegister(temp1); - Register destAddress = asRegister(temp2); - masm.mov(64, srcAddress, asRegister(src)); - masm.mov(64, destAddress, asRegister(dst)); - - masm.compare(64, result, CHUNK_ELEMENT_COUNT); - masm.branchConditionally(ConditionFlag.GE, simdImpl); - - masm.bind(scalarImpl); - emitScalar(masm, done, srcAddress, destAddress, result); - masm.jmp(done); - - masm.bind(simdImpl); - emitSIMD(masm, scalarImpl, done, srcAddress, destAddress, result); - - masm.bind(done); - } - - private static void emitScalar(AArch64MacroAssembler masm, Label done, Register srcAddress, Register destAddress, Register result) { - Label failToCompress = new Label(); - Label scalarLoop = new Label(); - - try (ScratchRegister scratchReg1 = masm.getScratchRegister(); ScratchRegister scratchReg2 = masm.getScratchRegister()) { - Register val = scratchReg1.getRegister(); - Register count = scratchReg2.getRegister(); - - masm.mov(64, count, result); - - masm.align(AArch64MacroAssembler.PREFERRED_LOOP_ALIGNMENT); - masm.bind(scalarLoop); - masm.ldr(16, val, AArch64Address.createImmediateAddress(16, AddressingMode.IMMEDIATE_POST_INDEXED, srcAddress, 2)); - /* - * If the current char is greater than 0xFF, stop compressing and return zero as result. - */ - masm.compare(64, val, 0xFF); - masm.branchConditionally(ConditionFlag.GT, failToCompress); - - masm.str(8, val, AArch64Address.createImmediateAddress(8, AddressingMode.IMMEDIATE_POST_INDEXED, destAddress, 1)); - masm.subs(64, count, count, 1); - masm.branchConditionally(ConditionFlag.GT, scalarLoop); - masm.jmp(done); - - masm.bind(failToCompress); - masm.mov(64, result, zr); - } - } - - private void emitSIMD(AArch64MacroAssembler masm, Label scalarImpl, Label done, Register srcChunkAddress, Register destChunkAddress, Register result) { - Register chunkPart1RegV = asRegister(vectorTemp1); - Register chunkPart2RegV = asRegister(vectorTemp2); - Register tmpRegV1 = asRegister(vectorTemp3); - Register tmp = asRegister(temp3); - - Label simdLoop = new Label(); - Label failToCompress = new Label(); - Label redoEntireChunk = new Label(); - - try (ScratchRegister scratchRegister1 = masm.getScratchRegister(); ScratchRegister scratchRegister2 = masm.getScratchRegister()) { - Register lastChunkAddress = scratchRegister1.getRegister(); - Register endOfSrcAddress = scratchRegister2.getRegister(); - masm.add(64, endOfSrcAddress, srcChunkAddress, result, AArch64Assembler.ShiftType.LSL, 1); - masm.sub(64, lastChunkAddress, endOfSrcAddress, CHUNK_ELEMENT_COUNT * 2); - - masm.align(AArch64MacroAssembler.PREFERRED_LOOP_ALIGNMENT); - masm.bind(simdLoop); - masm.fldp(128, chunkPart1RegV, chunkPart2RegV, AArch64Address.createImmediateAddress(128, AddressingMode.IMMEDIATE_PAIR_POST_INDEXED, srcChunkAddress, CHUNK_ELEMENT_COUNT * 2)); - /* - * If an element in the chunk is greater than 0xFF, stop compressing and retry with - * scalar code. - * - * To do so, we check for any top bytes which are not zero. - */ - masm.neon.orrVVV(AArch64ASIMDAssembler.ASIMDSize.FullReg, tmpRegV1, chunkPart1RegV, chunkPart2RegV); - masm.neon.uzp2VVV(AArch64ASIMDAssembler.ASIMDSize.FullReg, ElementSize.Byte, tmpRegV1, tmpRegV1, tmpRegV1); - masm.neon.umovGX(ElementSize.DoubleWord, tmp, tmpRegV1, 0); - masm.cbnz(64, tmp, failToCompress); - - // compress elements - masm.neon.xtnVV(ElementSize.Byte, tmpRegV1, chunkPart1RegV); - masm.neon.xtn2VV(ElementSize.Byte, tmpRegV1, chunkPart2RegV); - masm.fstr(128, tmpRegV1, AArch64Address.createImmediateAddress(128, AddressingMode.IMMEDIATE_POST_INDEXED, destChunkAddress, CHUNK_ELEMENT_COUNT)); - masm.cmp(64, srcChunkAddress, lastChunkAddress); - masm.branchConditionally(ConditionFlag.LO, simdLoop); - - /* - * Process the last chunk. Move the source position back to the last chunk, 16 bytes - * before the end of the input array. Move the destination position back twice the - * movement of source position. - */ - masm.cmp(64, srcChunkAddress, endOfSrcAddress); - masm.branchConditionally(ConditionFlag.HS, done); - masm.sub(64, srcChunkAddress, srcChunkAddress, lastChunkAddress); - // srcChunkAddress will be a value in the range (1, 31), so LSR and ASR are equivalent - masm.sub(64, destChunkAddress, destChunkAddress, srcChunkAddress, AArch64Assembler.ShiftType.LSR, 1); - masm.mov(64, srcChunkAddress, lastChunkAddress); - masm.jmp(simdLoop); + Register src = asRegister(temp[0]); + Register dst = asRegister(temp[1]); + Register len = asRegister(temp[2]); + Register res = asRegister(resultValue); + + masm.mov(64, src, asRegister(srcValue)); + masm.mov(64, dst, asRegister(dstValue)); + masm.mov(32, len, asRegister(lenValue)); + + AArch64EncodeArrayOp.emitEncodeArrayOp(masm, res, src, dst, len, vectorTemp, LIRGeneratorTool.CharsetName.ISO_8859_1); + if (JavaVersionUtil.JAVA_SPEC < 22) { + // legacy behavior: if (result != length) { result = 0; } + masm.cmp(32, res, asRegister(lenValue)); + masm.csel(32, res, res, zr, AArch64Assembler.ConditionFlag.EQ); } - - masm.bind(failToCompress); - /* - * Determine whether the first un-compressible element was in the first chunk. Compress and - * copy the first 16 bytes if the first un-compressible chars is in the second chunk. - * Afterwards, jump to the scalar loop to process the failed chunk element-by-element. - * - * Because we start immediately at the failing chunk part, we know at most 8 elements need - * to be checked to find the mismatch. - */ - masm.mov(result, 8); - masm.neon.uzp2VVV(AArch64ASIMDAssembler.ASIMDSize.FullReg, ElementSize.Byte, tmpRegV1, chunkPart1RegV, chunkPart1RegV); - masm.neon.umovGX(ElementSize.DoubleWord, tmp, tmpRegV1, 0); - masm.cbnz(64, tmp, redoEntireChunk); - - // fall-through: store chunkPart1 and start search at chunkPart2 - // note this is really CHUNK_ELEMENT_SIZE * 2 / 2 - masm.sub(64, srcChunkAddress, srcChunkAddress, CHUNK_ELEMENT_COUNT); - masm.neon.xtnVV(ElementSize.Byte, tmpRegV1, chunkPart1RegV); - masm.fstr(64, tmpRegV1, AArch64Address.createImmediateAddress(64, AddressingMode.IMMEDIATE_POST_INDEXED, destChunkAddress, CHUNK_ELEMENT_COUNT / 2)); - masm.jmp(scalarImpl); - - // start at chunkPart1 - masm.bind(redoEntireChunk); - masm.sub(64, srcChunkAddress, srcChunkAddress, CHUNK_ELEMENT_COUNT * 2); - masm.jmp(scalarImpl); } } From a4ac17a5bf11e15bcd1124386b7c99f516473216 Mon Sep 17 00:00:00 2001 From: Josef Haider Date: Tue, 12 Dec 2023 14:34:34 +0100 Subject: [PATCH 233/593] Optimization in AArch64ArrayRegionCompareToOp --- .../lir/aarch64/AArch64ArrayRegionCompareToOp.java | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/aarch64/AArch64ArrayRegionCompareToOp.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/aarch64/AArch64ArrayRegionCompareToOp.java index 7f2e083cc67c..3b9752623204 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/aarch64/AArch64ArrayRegionCompareToOp.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/aarch64/AArch64ArrayRegionCompareToOp.java @@ -291,11 +291,9 @@ private static void loadAndExtend(AArch64MacroAssembler asm, Stride strideDst, S private static void calcReturnValue(AArch64MacroAssembler asm, Register ret, Register vecArrayA, Register vecArrayB, Register vecTmp, Register vecIndex, Register vecMask, Stride strideMax) { // set all equal bytes to 0xff, others to 0x00 asm.neon.cmeqVVV(FullReg, fromStride(strideMax), vecTmp, vecArrayA, vecArrayB); - // BIC with the ascending index mask, this will replace all non-equal bytes with their - // corresponding byte index - asm.neon.bicVVV(FullReg, vecIndex, vecMask, vecTmp); - // OR with the result of CMEQ, replacing all equal bytes with 0xff again - asm.neon.orrVVV(FullReg, vecIndex, vecIndex, vecTmp); + // OR with the ascending index mask, this will replace all non-equal bytes with their + // corresponding byte index, and all equal bytes with 0xff + asm.neon.orrVVV(FullReg, vecIndex, vecMask, vecTmp); // Get the unsigned minimum. This will yield the index of the first non-equal bytes, since // all equal ones are filled with 0xff asm.neon.uminvSV(FullReg, fromStride(strideMax), vecIndex, vecIndex); From 97d2a126c4517a2201b0d0b0d5e4bd3843169d6e Mon Sep 17 00:00:00 2001 From: Martin Entlicher Date: Fri, 8 Dec 2023 19:25:16 +0100 Subject: [PATCH 234/593] Add an embedding example to the Insight documentation. (GR-50848) --- docs/tools/insight/Insight-Embedding.md | 49 ++++++++++++++++++- .../org/graalvm/tools/insight/Insight.java | 17 ++++--- 2 files changed, 58 insertions(+), 8 deletions(-) diff --git a/docs/tools/insight/Insight-Embedding.md b/docs/tools/insight/Insight-Embedding.md index 7b2bb3ff2bae..3570545d4550 100644 --- a/docs/tools/insight/Insight-Embedding.md +++ b/docs/tools/insight/Insight-Embedding.md @@ -10,8 +10,7 @@ permalink: /tools/graalvm-insight/embedding/ ## Embedding Insight into Java GraalVM languages (languages implemented with the Truffle framework, i.e., JavaScript, Python, Ruby, R) can be embedded into custom Java applications via [Polyglot Context API](https://www.graalvm.org/sdk/javadoc/org/graalvm/polyglot/Context.html). -GraalVM Insight can also be controlled via the same API. -For example: +GraalVM Insight can also be controlled via the same API. Like: ```java final Engine engine = context.getEngine(); @@ -21,8 +20,54 @@ AutoCloseable handle = access.apply(agentSrc); ``` Obtain `Engine` for `Context` and ask for the `insight` instrument. +

    Then create `Source` with the GraalVM Insight script and apply it while obtaining its instrumentation handle. Use `handle.close()` to disable all the script's instrumentations when when no longer needed. +For Example: + +```java +Source instrument = Source.create("js", """ + insight.on('return', function(ctx, frame) { + console.log(`Instrumented where = ${frame.where}`); + }, { + roots: true, + rootNameFilter: 'end', + }); + """); +Source script = Source.create("js", """ + function end() { + var where = 'end'; + console.log(where + ' invoked') + } + end(); + """); +try (Context context = Context.newBuilder().build()) { + @SuppressWarnings("unchecked") + Function insight = context.getEngine().getInstruments().get("insight").lookup(Function.class); + + // run without instrumentation + context.eval(script); + + // run with instrumentation + try (AutoCloseable handle = insight.apply(instrument)) { + context.eval(script); + } + + // run without instrumentation + context.eval(script); +} +``` + +See [Embedding Dependency Setup](../../reference-manual/embedding/embed-languages.md#dependency-setup). Add a dependency on `insight`: +``` + + org.graalvm.polyglot + + insight + 23.1.1 + pom + +``` ### Ignoring Internal Scripts diff --git a/tools/src/org.graalvm.tools.insight/src/org/graalvm/tools/insight/Insight.java b/tools/src/org.graalvm.tools.insight/src/org/graalvm/tools/insight/Insight.java index 2a6b9ad7b43b..cdc21017109a 100644 --- a/tools/src/org.graalvm.tools.insight/src/org/graalvm/tools/insight/Insight.java +++ b/tools/src/org.graalvm.tools.insight/src/org/graalvm/tools/insight/Insight.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2023, 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 @@ -36,8 +36,13 @@ * {@codesnippet Embedding#apply} * * and then {@link Function#apply(java.lang.Object) evaluate} {@link org.graalvm.polyglot.Source} - * scripts written in any language accessing the {@code agent} variable exposed to them. Use - * {@link #VERSION following API} when dealing with the {@code insight} variable: + * scripts written in any language accessing the {@code agent} variable exposed to them. + *

    + * See an example at Embedding + * Insight into Java. + * + * Use {@link #VERSION following API} when dealing with the {@code insight} variable: *

    * {@codesnippet InsightAPI} * @@ -79,16 +84,16 @@ private Insight() { * every {@link #ID Insight script} when properly registered into the virtual machine. A typical * way is to register your custom instrument is to use property * {@code truffle.class.path.append} when launching the virtual machine: - * + * *

          * graalvm/bin/java -Dtruffle.class.path.append=meaningOfWorld.jar -jar app.jar
          * 
    - * + * * Take care when writing your {@link TruffleInstrument instruments} as they can alter many * aspects of program execution and aren't subject to any security sandbox. See * {@link TruffleInstrument} for more information about developing, using and registering * instruments. - * + * * @since 21.0 */ public interface SymbolProvider { From b6ac3638617c3c23e954ff3d7c320f2ff91adc30 Mon Sep 17 00:00:00 2001 From: Josef Haider Date: Fri, 15 Dec 2023 15:04:40 +0100 Subject: [PATCH 235/593] Style fixes --- .../test/StringCompressInflateTest.java | 14 +++++++------- .../compiler/lir/aarch64/AArch64EncodeArrayOp.java | 2 +- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/replacements/test/StringCompressInflateTest.java b/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/replacements/test/StringCompressInflateTest.java index 701def7c3c96..6d33c868f500 100644 --- a/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/replacements/test/StringCompressInflateTest.java +++ b/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/replacements/test/StringCompressInflateTest.java @@ -300,13 +300,13 @@ public void testStringUTF16CompressCharByte() throws ClassNotFoundException { } // Exhaustively check compress returning the correct index of the non-latin1 char. - final int SIZE = 48; - final byte FILL_BYTE = 'R'; - char[] chars = new char[SIZE]; + final int size = 48; + final byte fillByte = 'R'; + char[] chars = new char[size]; final byte[] bytes = new byte[chars.length]; - Arrays.fill(bytes, FILL_BYTE); - for (int i = 0; i < SIZE; i++) { // Every starting index - for (int j = i; j < SIZE; j++) { // Every location of non-latin1 + Arrays.fill(bytes, fillByte); + for (int i = 0; i < size; i++) { // Every starting index + for (int j = i; j < size; j++) { // Every location of non-latin1 Arrays.fill(chars, 'A'); chars[j] = 0xFF21; byte[] dst = Arrays.copyOf(bytes, bytes.length); @@ -316,7 +316,7 @@ public void testStringUTF16CompressCharByte() throws ClassNotFoundException { Assert.assertEquals(result, result2); Assert.assertArrayEquals(dst, dst2); Assert.assertEquals("compress found wrong index", j - i, result); - Assert.assertEquals("extra character stored", FILL_BYTE, bytes[j]); + Assert.assertEquals("extra character stored", fillByte, bytes[j]); } } } diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/aarch64/AArch64EncodeArrayOp.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/aarch64/AArch64EncodeArrayOp.java index af97eec88221..7f4249508992 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/aarch64/AArch64EncodeArrayOp.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/aarch64/AArch64EncodeArrayOp.java @@ -111,7 +111,7 @@ protected void emitCode(CompilationResultBuilder crb, AArch64MacroAssembler masm } public static void emitEncodeArrayOp(AArch64MacroAssembler masm, Register res, Register src, Register dst, Register len, Value[] vectorRegisters, CharsetName charset) { - GraalError.guarantee(charset == CharsetName.ASCII || charset == CharsetName.ISO_8859_1, charset.toString()); + GraalError.guarantee(charset == CharsetName.ASCII || charset == CharsetName.ISO_8859_1, "unsupported charset: %s", charset); boolean ascii = charset == CharsetName.ASCII; Register vtmp0 = asRegister(vectorRegisters[0]); From 708e42489b0a88b1dd6889f45b78105777dac4a0 Mon Sep 17 00:00:00 2001 From: Robert Toyonaga Date: Fri, 15 Dec 2023 13:09:33 -0500 Subject: [PATCH 236/593] clean up --- .../com/oracle/svm/core/jfr/JfrFeature.java | 2 - .../core/jfr/Target_jdk_jfr_internal_JVM.java | 10 +++- .../svm/hosted/jfr/JfrEventFeature.java | 8 --- .../svm/hosted/jfr/JfrEventSubstitution.java | 50 ------------------- 4 files changed, 9 insertions(+), 61 deletions(-) diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jfr/JfrFeature.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jfr/JfrFeature.java index 67e977e6aca8..182b3ed513f5 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jfr/JfrFeature.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jfr/JfrFeature.java @@ -149,8 +149,6 @@ public List> getRequiredFeatures() { @Override public void afterRegistration(AfterRegistrationAccess access) { - ModuleSupport.accessPackagesToClass(ModuleSupport.Access.OPEN, null, false, "jdk.jfr"); - ModuleSupport.accessPackagesToClass(ModuleSupport.Access.OPEN, null, false, "java.base"); // Initialize some parts of JFR/JFC at image build time. List knownConfigurations = JFC.getConfigurations(); diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jfr/Target_jdk_jfr_internal_JVM.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jfr/Target_jdk_jfr_internal_JVM.java index 103ff7276ce0..4f4330b8a4af 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jfr/Target_jdk_jfr_internal_JVM.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jfr/Target_jdk_jfr_internal_JVM.java @@ -27,6 +27,7 @@ import java.util.List; import java.util.function.BooleanSupplier; +import jdk.jfr.internal.LogLevel; import org.graalvm.nativeimage.Platform; import org.graalvm.nativeimage.Platforms; import org.graalvm.nativeimage.ProcessProperties; @@ -46,6 +47,7 @@ import jdk.graal.compiler.api.replacements.Fold; import jdk.jfr.internal.JVM; import jdk.jfr.internal.LogTag; +import jdk.jfr.internal.Logger; @SuppressWarnings({"static-method", "unused"}) @TargetClass(value = jdk.jfr.internal.JVM.class, onlyWith = HasJfrSupport.class) @@ -168,10 +170,16 @@ public static void unregisterStackFilter(long stackFilterId) { throw VMError.unimplemented("JFR StackFilters are not yet supported."); } + /** + * As of 22+27, This method is both used to set cutoff tick values for leak profiling and + * for @Deprecated events. + */ @Substitute @TargetElement(onlyWith = JDK22OrLater.class) public static void setMiscellaneous(long eventTypeId, long value) { - throw VMError.unimplemented("@Deprecated JFR events are not yet supported."); + // Add logging here since JDK code obfuscates root exception message. + Logger.log(LogTag.JFR_SETTING, LogLevel.WARN, "@Deprecated JFR events, and leak profiling are not yet supported."); + throw VMError.unimplemented("@Deprecated JFR events, and leak profiling are not yet supported."); } /** See {@link JVM#getThreadId}. */ diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/jfr/JfrEventFeature.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/jfr/JfrEventFeature.java index d3c5453b4f34..e3a3dfbe3600 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/jfr/JfrEventFeature.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/jfr/JfrEventFeature.java @@ -67,14 +67,6 @@ public List> getRequiredFeatures() { return Collections.singletonList(JfrFeature.class); } - @Override - public void afterRegistration(AfterRegistrationAccess access) { - ModuleSupport.accessPackagesToClass(ModuleSupport.Access.OPEN, JfrEventFeature.class, false, "jdk.jfr", "jdk.jfr.events"); - ModuleSupport.accessPackagesToClass(ModuleSupport.Access.OPEN, JfrFeature.class, false, "jdk.jfr", "jdk.jfr.events"); - ModuleSupport.accessPackagesToClass(ModuleSupport.Access.OPEN, JfrEventSubstitution.class, false, "jdk.internal.vm.ci", "jdk.vm.ci.hotspot"); - ModuleSupport.accessPackagesToClass(ModuleSupport.Access.OPEN, JfrEventFeature.class, false, "java.base", "jdk.internal.event"); - } - @Override public void duringSetup(DuringSetupAccess c) { FeatureImpl.DuringSetupAccessImpl config = (FeatureImpl.DuringSetupAccessImpl) c; diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/jfr/JfrEventSubstitution.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/jfr/JfrEventSubstitution.java index 9d6e27c95553..73c61c26ba97 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/jfr/JfrEventSubstitution.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/jfr/JfrEventSubstitution.java @@ -44,7 +44,6 @@ import com.oracle.svm.util.ReflectionUtil; import jdk.graal.compiler.serviceprovider.JavaVersionUtil; -import jdk.internal.misc.Unsafe; import jdk.jfr.internal.JVM; import jdk.jfr.internal.SecuritySupport; import jdk.jfr.internal.event.EventWriter; @@ -72,7 +71,6 @@ public class JfrEventSubstitution extends SubstitutionProcessor { JfrEventSubstitution(MetaAccessProvider metaAccess) { baseEventType = metaAccess.lookupJavaType(jdk.internal.event.Event.class); ResolvedJavaType jdkJfrEventWriter = metaAccess.lookupJavaType(EventWriter.class); - changeWriterResetMethod(jdkJfrEventWriter); typeSubstitution = new ConcurrentHashMap<>(); methodSubstitutions = new ConcurrentHashMap<>(); fieldSubstitutions = new ConcurrentHashMap<>(); @@ -186,54 +184,6 @@ private boolean needsClassRedefinition(ResolvedJavaType type) { return !type.isAbstract() && baseEventType.isAssignableFrom(type) && !baseEventType.equals(type); } - /** - * The method EventWriter.reset() is private but it is called by the EventHandler classes, which - * are generated automatically. To prevent bytecode parsing issues, we patch the visibility of - * that method using the hacky way below. - */ - private static void changeWriterResetMethod(ResolvedJavaType eventWriterType) { - for (ResolvedJavaMethod m : eventWriterType.getDeclaredMethods(false)) { - if (m.getName().equals("reset")) { - setPublicModifier(m); - } - } - } - - private static void setPublicModifier(ResolvedJavaMethod m) { - try { - Class hotspotMethodClass = m.getClass(); - Method metaspaceMethodM = getMethodToFetchMetaspaceMethod(hotspotMethodClass); - metaspaceMethodM.setAccessible(true); - long metaspaceMethod = (Long) metaspaceMethodM.invoke(m); - VMError.guarantee(metaspaceMethod != 0); - Class hotSpotVMConfigC = Class.forName("jdk.vm.ci.hotspot.HotSpotVMConfig"); - Method configM = hotSpotVMConfigC.getDeclaredMethod("config"); - configM.setAccessible(true); - Field methodAccessFlagsOffsetF = hotSpotVMConfigC.getDeclaredField("methodAccessFlagsOffset"); - methodAccessFlagsOffsetF.setAccessible(true); - Object hotSpotVMConfig = configM.invoke(null); - int methodAccessFlagsOffset = methodAccessFlagsOffsetF.getInt(hotSpotVMConfig); - int modifiers = Unsafe.getUnsafe().getInt(metaspaceMethod + methodAccessFlagsOffset); - int newModifiers = modifiers & ~Modifier.PRIVATE | Modifier.PUBLIC; - Unsafe.getUnsafe().putInt(metaspaceMethod + methodAccessFlagsOffset, newModifiers); - } catch (Exception ex) { - throw VMError.shouldNotReachHere(ex); - } - } - - private static Method getMethodToFetchMetaspaceMethod(Class method) throws NoSuchMethodException { - // The exact method depends on the JVMCI version. - try { - return method.getDeclaredMethod("getMethodPointer"); - } catch (NoSuchMethodException e) { - try { - return method.getDeclaredMethod("getMetaspaceMethod"); - } catch (NoSuchMethodException e2) { - return method.getDeclaredMethod("getMetaspacePointer"); - } - } - } - /* * Mirror events contain the JFR-specific annotations. The mirrored event does not have any * dependency on JFR-specific classes. If the mirrored event is used, we must ensure that the From d77207f8aac693f7d9f13d644e5c343c56ec944d Mon Sep 17 00:00:00 2001 From: Robert Toyonaga Date: Fri, 15 Dec 2023 13:24:34 -0500 Subject: [PATCH 237/593] style fixes style 2 --- .../src/com/oracle/svm/core/jfr/JfrFeature.java | 1 - .../src/com/oracle/svm/hosted/jfr/JfrEventFeature.java | 1 - .../src/com/oracle/svm/hosted/jfr/JfrEventSubstitution.java | 2 -- 3 files changed, 4 deletions(-) diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jfr/JfrFeature.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jfr/JfrFeature.java index 182b3ed513f5..055b4bf3ddc5 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jfr/JfrFeature.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jfr/JfrFeature.java @@ -47,7 +47,6 @@ import com.oracle.svm.core.util.UserError; import com.oracle.svm.core.util.VMError; import com.oracle.svm.util.LogUtils; -import com.oracle.svm.util.ModuleSupport; import com.oracle.svm.util.ReflectionUtil; import com.sun.management.HotSpotDiagnosticMXBean; import com.sun.management.internal.PlatformMBeanProviderImpl; diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/jfr/JfrEventFeature.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/jfr/JfrEventFeature.java index e3a3dfbe3600..0d3c2273a6fc 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/jfr/JfrEventFeature.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/jfr/JfrEventFeature.java @@ -45,7 +45,6 @@ import com.oracle.svm.core.meta.SharedType; import com.oracle.svm.core.util.VMError; import com.oracle.svm.hosted.FeatureImpl; -import com.oracle.svm.util.ModuleSupport; import jdk.internal.event.Event; import jdk.jfr.internal.JVM; diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/jfr/JfrEventSubstitution.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/jfr/JfrEventSubstitution.java index 73c61c26ba97..02ee0fcb91ef 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/jfr/JfrEventSubstitution.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/jfr/JfrEventSubstitution.java @@ -25,9 +25,7 @@ package com.oracle.svm.hosted.jfr; import java.lang.annotation.Annotation; -import java.lang.reflect.Field; import java.lang.reflect.Method; -import java.lang.reflect.Modifier; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; From 94ec1bcc3a79823182e69d60937eb37f63208ab7 Mon Sep 17 00:00:00 2001 From: Christian Wimmer Date: Fri, 15 Dec 2023 11:18:25 -0800 Subject: [PATCH 238/593] Fix clinit simulation for arraycopy with null values --- .../SimulateClassInitializerGraphDecoder.java | 9 ++++++--- .../oracle/svm/test/clinit/TestClassInitialization.java | 6 +++--- 2 files changed, 9 insertions(+), 6 deletions(-) diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/classinitialization/SimulateClassInitializerGraphDecoder.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/classinitialization/SimulateClassInitializerGraphDecoder.java index 02d2eb09cf05..d757991a844c 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/classinitialization/SimulateClassInitializerGraphDecoder.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/classinitialization/SimulateClassInitializerGraphDecoder.java @@ -346,9 +346,12 @@ protected boolean handleArrayCopy(ImageHeapArray source, int sourcePos, ImageHea } if (destComponentType.getJavaKind() == JavaKind.Object && !destComponentType.isJavaLangObject() && !sourceComponentType.equals(destComponentType)) { for (int i = 0; i < length; i++) { - var elementValueType = ((TypedConstant) source.getElement(sourcePos + i)).getType(metaAccess); - if (!destComponentType.isAssignableFrom(elementValueType)) { - return false; + var elementValue = (JavaConstant) source.getElement(sourcePos + i); + if (elementValue.isNonNull()) { + var elementValueType = ((TypedConstant) elementValue).getType(metaAccess); + if (!destComponentType.isAssignableFrom(elementValueType)) { + return false; + } } } } diff --git a/substratevm/src/com.oracle.svm.test/src/com/oracle/svm/test/clinit/TestClassInitialization.java b/substratevm/src/com.oracle.svm.test/src/com/oracle/svm/test/clinit/TestClassInitialization.java index ffa6fad54a78..983a46edc6e9 100644 --- a/substratevm/src/com.oracle.svm.test/src/com/oracle/svm/test/clinit/TestClassInitialization.java +++ b/substratevm/src/com.oracle.svm.test/src/com/oracle/svm/test/clinit/TestClassInitialization.java @@ -612,7 +612,7 @@ public static Object defaultValue(Class clazz) { System.arraycopy(shorts, 1, S1, 2, 5); System.arraycopy(S1, 3, S1, 5, 5); - Object[] objects = {"42", "43", "44", "45", "46", "47", "48"}; + Object[] objects = {"42", null, "44", "45", null, "47", "48"}; O1 = Arrays.copyOf(objects, 3); O2 = Arrays.copyOfRange(objects, 3, 6, String[].class); } @@ -943,8 +943,8 @@ public static void main(String[] args) { assertSame(Short.class, BoxingMustBeSimulated.defaultValue(short.class).getClass()); assertSame(Float.class, BoxingMustBeSimulated.defaultValue(float.class).getClass()); assertTrue(Arrays.equals((short[]) BoxingMustBeSimulated.S1, new short[]{0, 0, 43, 44, 45, 44, 45, 46, 47, 0, 0, 0})); - assertTrue(Arrays.equals((Object[]) BoxingMustBeSimulated.O1, new Object[]{"42", "43", "44"})); - assertTrue(Arrays.equals((Object[]) BoxingMustBeSimulated.O2, new String[]{"45", "46", "47"})); + assertTrue(Arrays.equals((Object[]) BoxingMustBeSimulated.O1, new Object[]{"42", null, "44"})); + assertTrue(Arrays.equals((Object[]) BoxingMustBeSimulated.O2, new String[]{"45", null, "47"})); /* * The unsafe field offset lookup is constant folded at image build time, which also From 410a192e2882b90151e0e853c376d3333106441c Mon Sep 17 00:00:00 2001 From: Christian Wimmer Date: Fri, 15 Dec 2023 12:48:39 -0800 Subject: [PATCH 239/593] Constant fold reflection lookups in sun.nio.ch.Reflect --- .../oracle/svm/hosted/snippets/ReflectionPlugins.java | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/snippets/ReflectionPlugins.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/snippets/ReflectionPlugins.java index e048e06e2e86..859c6e53683c 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/snippets/ReflectionPlugins.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/snippets/ReflectionPlugins.java @@ -290,6 +290,15 @@ private void registerClassPlugins(InvocationPlugins plugins) { "getField", "getMethod", "getConstructor", "getDeclaredField", "getDeclaredMethod", "getDeclaredConstructor"); + /* + * The class sun.nio.ch.Reflect contains various reflection lookup methods that then pass + * parameters through to the actual methods in java.lang.Class. But they do additional + * things like calling setAccessible(true), so method inlining before analysis cannot + * constant-fold them automatically. So we register them manually here for folding too. + */ + registerFoldInvocationPlugins(plugins, ReflectionUtil.lookupClass(false, "sun.nio.ch.Reflect"), + "lookupConstructor", "lookupMethod", "lookupField"); + if (MissingRegistrationUtils.throwMissingRegistrationErrors() && reason.duringAnalysis() && reason != ParsingReason.JITCompilation) { registerBulkInvocationPlugin(plugins, Class.class, "getClasses", RuntimeReflection::registerAllClasses); registerBulkInvocationPlugin(plugins, Class.class, "getDeclaredClasses", RuntimeReflection::registerAllDeclaredClasses); From 86d5ec09eb39d4a182314268e631c4f53243e991 Mon Sep 17 00:00:00 2001 From: ol-automation_ww Date: Sun, 17 Dec 2023 12:00:23 +0000 Subject: [PATCH 240/593] [GR-23997] Periodic update of the graal import (2023-12-15). PullRequest: js/3006 --- vm/mx.vm/suite.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/vm/mx.vm/suite.py b/vm/mx.vm/suite.py index 2e961525c0af..6ee5e0ce9198 100644 --- a/vm/mx.vm/suite.py +++ b/vm/mx.vm/suite.py @@ -33,7 +33,7 @@ "name": "graal-nodejs", "subdir": True, "dynamic": True, - "version": "861b6828eccc81abaee684a04c6899d64d39cba6", + "version": "9bde3a5564b1bf1968e0f38be51dad2df7b2a33d", "urls" : [ {"url" : "https://github.com/graalvm/graaljs.git", "kind" : "git"}, ] @@ -42,7 +42,7 @@ "name": "graal-js", "subdir": True, "dynamic": True, - "version": "861b6828eccc81abaee684a04c6899d64d39cba6", + "version": "9bde3a5564b1bf1968e0f38be51dad2df7b2a33d", "urls": [ {"url": "https://github.com/graalvm/graaljs.git", "kind" : "git"}, ] From d2c73c0771c910a1da314da6f9fb57155a96616c Mon Sep 17 00:00:00 2001 From: Codrut Stancu Date: Fri, 15 Dec 2023 23:01:35 +0100 Subject: [PATCH 241/593] Add object reachability hooks. --- .../graal/pointsto/heap/ImageHeapScanner.java | 4 ++ .../graal/pointsto/meta/AnalysisType.java | 29 ++++++++++++ .../svm/core/reflect/SubstrateAccessor.java | 22 ++++++++- .../reflect/SubstrateConstructorAccessor.java | 5 +- .../core/reflect/SubstrateMethodAccessor.java | 11 +++-- .../com/oracle/svm/hosted/FeatureImpl.java | 14 +++++- .../svm/hosted/reflect/ReflectionFeature.java | 47 ++++++++++++++----- 7 files changed, 109 insertions(+), 23 deletions(-) diff --git a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/heap/ImageHeapScanner.java b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/heap/ImageHeapScanner.java index fa757545e9ac..b71030577aa5 100644 --- a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/heap/ImageHeapScanner.java +++ b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/heap/ImageHeapScanner.java @@ -515,6 +515,10 @@ protected void onObjectReachable(ImageHeapConstant imageHeapConstant, ScanReason AnalysisType objectType = metaAccess.lookupJavaType(imageHeapConstant); imageHeap.addReachableObject(objectType, imageHeapConstant); + AnalysisType type = imageHeapConstant.getType(metaAccess); + Object object = bb.getSnippetReflectionProvider().asObject(Object.class, imageHeapConstant); + type.notifyObjectReachable(universe.getConcurrentAnalysisAccess(), object); + markTypeInstantiated(objectType, reason); if (imageHeapConstant instanceof ImageHeapObjectArray imageHeapArray) { AnalysisType arrayType = imageHeapArray.getType(metaAccess); diff --git a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/meta/AnalysisType.java b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/meta/AnalysisType.java index 1a378ff0ca68..e87a907f9d3f 100644 --- a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/meta/AnalysisType.java +++ b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/meta/AnalysisType.java @@ -37,6 +37,7 @@ import java.util.concurrent.ConcurrentMap; import java.util.concurrent.atomic.AtomicIntegerFieldUpdater; import java.util.concurrent.atomic.AtomicReferenceFieldUpdater; +import java.util.function.BiConsumer; import java.util.function.Consumer; import java.util.function.Function; @@ -96,6 +97,9 @@ public abstract class AnalysisType extends AnalysisElement implements WrappedJav private static final AtomicReferenceFieldUpdater instantiatedNotificationsUpdater = AtomicReferenceFieldUpdater .newUpdater(AnalysisType.class, Object.class, "typeInstantiatedNotifications"); + private static final AtomicReferenceFieldUpdater objectReachableCallbacksUpdater = AtomicReferenceFieldUpdater + .newUpdater(AnalysisType.class, Object.class, "objectReachableCallbacks"); + private static final AtomicReferenceFieldUpdater isAllocatedUpdater = AtomicReferenceFieldUpdater .newUpdater(AnalysisType.class, Object.class, "isAllocated"); @@ -219,6 +223,11 @@ public enum UsageKind { */ @SuppressWarnings("unused") private volatile Object typeInstantiatedNotifications; + /** + * Contains callbacks that are executed when an object of this type is marked as reachable. + */ + @SuppressWarnings("unused") private volatile Object objectReachableCallbacks; + @SuppressWarnings("this-escape") public AnalysisType(AnalysisUniverse universe, ResolvedJavaType javaType, JavaKind storageKind, AnalysisType objectType, AnalysisType cloneableType) { this.universe = universe; @@ -614,6 +623,21 @@ public Set getOverrideReachabilityNotificat return ConcurrentLightHashMap.getOrDefault(this, overrideReachableNotificationsUpdater, method, Collections.emptySet()); } + public void registerObjectReachableCallback(BiConsumer callback) { + ConcurrentLightHashSet.addElement(this, objectReachableCallbacksUpdater, callback); + /* Register the callback with already discovered subtypes too. */ + for (AnalysisType subType : subTypes) { + /* Subtypes include this type itself. */ + if (!subType.equals(this)) { + subType.registerObjectReachableCallback(callback); + } + } + } + + public void notifyObjectReachable(DuringAnalysisAccess access, T object) { + ConcurrentLightHashSet.forEach(this, objectReachableCallbacksUpdater, (BiConsumer c) -> c.accept(access, object)); + } + public void registerInstantiatedCallback(Consumer callback) { if (this.isInstantiated()) { /* If the type is already instantiated just trigger the callback. */ @@ -1013,6 +1037,11 @@ public Set getSubTypes() { private void addSubType(AnalysisType subType) { boolean result = this.subTypes.add(subType); + /* Register the object reachability callbacks with the newly discovered subtype. */ + if (!subType.equals(this)) { + /* Subtypes include this type itself. */ + ConcurrentLightHashSet.forEach(this, objectReachableCallbacksUpdater, (BiConsumer callback) -> subType.registerObjectReachableCallback(callback)); + } assert result : "Tried to add a " + subType + " which is already registered"; } diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/reflect/SubstrateAccessor.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/reflect/SubstrateAccessor.java index 241e3605e4bd..18f775676588 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/reflect/SubstrateAccessor.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/reflect/SubstrateAccessor.java @@ -33,6 +33,8 @@ import com.oracle.svm.core.hub.DynamicHub; import com.oracle.svm.core.jdk.InternalVMMethod; +import jdk.vm.ci.meta.ResolvedJavaMethod; + @InternalVMMethod public abstract class SubstrateAccessor { /** @@ -43,6 +45,14 @@ public abstract class SubstrateAccessor { @Platforms(Platform.HOSTED_ONLY.class) // final Executable member; + /** + * The actual target method. For @{@link SubstrateConstructorAccessor} this is a factory method. + * For {@link SubstrateMethodAccessor} it can be the member itself or an adapter for caller + * sensitive methods. + */ + @Platforms(Platform.HOSTED_ONLY.class) // + final ResolvedJavaMethod targetMethod; + /** * The first-level function that is invoked. It expands the boxed Object[] signature to the * expanded real signature. @@ -62,14 +72,24 @@ public abstract class SubstrateAccessor { final DynamicHub initializeBeforeInvoke; @Platforms(Platform.HOSTED_ONLY.class) - SubstrateAccessor(Executable member, CFunctionPointer expandSignature, CFunctionPointer directTarget, DynamicHub initializeBeforeInvoke) { + SubstrateAccessor(Executable member, CFunctionPointer expandSignature, CFunctionPointer directTarget, ResolvedJavaMethod targetMethod, DynamicHub initializeBeforeInvoke) { this.member = member; this.expandSignature = expandSignature; this.directTarget = directTarget; this.initializeBeforeInvoke = initializeBeforeInvoke; + this.targetMethod = targetMethod; } public Executable getMember() { return member; } + + public CFunctionPointer getExpandSignature() { + return expandSignature; + } + + @Platforms(Platform.HOSTED_ONLY.class) + public ResolvedJavaMethod getTargetMethod() { + return targetMethod; + } } diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/reflect/SubstrateConstructorAccessor.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/reflect/SubstrateConstructorAccessor.java index 9c3c96273844..d181594bafc2 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/reflect/SubstrateConstructorAccessor.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/reflect/SubstrateConstructorAccessor.java @@ -34,12 +34,13 @@ import com.oracle.svm.core.reflect.ReflectionAccessorHolder.MethodInvokeFunctionPointer; import jdk.internal.reflect.ConstructorAccessor; +import jdk.vm.ci.meta.ResolvedJavaMethod; @InternalVMMethod public final class SubstrateConstructorAccessor extends SubstrateAccessor implements ConstructorAccessor { - public SubstrateConstructorAccessor(Executable member, CFunctionPointer expandSignature, CFunctionPointer directTarget, DynamicHub initializeBeforeInvoke) { - super(member, expandSignature, directTarget, initializeBeforeInvoke); + public SubstrateConstructorAccessor(Executable member, CFunctionPointer expandSignature, CFunctionPointer directTarget, ResolvedJavaMethod targetMethod, DynamicHub initializeBeforeInvoke) { + super(member, expandSignature, directTarget, targetMethod, initializeBeforeInvoke); } @Override diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/reflect/SubstrateMethodAccessor.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/reflect/SubstrateMethodAccessor.java index 1f522fe4400a..90a03acca074 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/reflect/SubstrateMethodAccessor.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/reflect/SubstrateMethodAccessor.java @@ -26,8 +26,6 @@ import java.lang.reflect.Executable; -import jdk.graal.compiler.nodes.NamedLocationIdentity; -import jdk.graal.compiler.word.BarrieredAccess; import org.graalvm.nativeimage.Platform; import org.graalvm.nativeimage.Platforms; import org.graalvm.nativeimage.c.function.CFunctionPointer; @@ -39,7 +37,10 @@ import com.oracle.svm.core.reflect.ReflectionAccessorHolder.MethodInvokeFunctionPointerForCallerSensitiveAdapter; import com.oracle.svm.core.util.VMError; +import jdk.graal.compiler.nodes.NamedLocationIdentity; +import jdk.graal.compiler.word.BarrieredAccess; import jdk.internal.reflect.MethodAccessor; +import jdk.vm.ci.meta.ResolvedJavaMethod; interface MethodAccessorJDK19 { Object invoke(Object obj, Object[] args, Class caller); @@ -61,9 +62,9 @@ public final class SubstrateMethodAccessor extends SubstrateAccessor implements private final boolean callerSensitiveAdapter; @Platforms(Platform.HOSTED_ONLY.class) - public SubstrateMethodAccessor(Executable member, Class receiverType, CFunctionPointer expandSignature, CFunctionPointer directTarget, int vtableOffset, DynamicHub initializeBeforeInvoke, - boolean callerSensitiveAdapter) { - super(member, expandSignature, directTarget, initializeBeforeInvoke); + public SubstrateMethodAccessor(Executable member, Class receiverType, CFunctionPointer expandSignature, CFunctionPointer directTarget, ResolvedJavaMethod targetMethod, int vtableOffset, + DynamicHub initializeBeforeInvoke, boolean callerSensitiveAdapter) { + super(member, expandSignature, directTarget, targetMethod, initializeBeforeInvoke); this.receiverType = receiverType; this.vtableOffset = vtableOffset; this.callerSensitiveAdapter = callerSensitiveAdapter; diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/FeatureImpl.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/FeatureImpl.java index 8daa17a3dc08..102d0b5fec39 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/FeatureImpl.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/FeatureImpl.java @@ -46,8 +46,6 @@ import java.util.stream.Collectors; import org.graalvm.collections.Pair; -import jdk.graal.compiler.debug.DebugContext; -import jdk.graal.compiler.phases.util.Providers; import org.graalvm.nativeimage.AnnotationAccess; import org.graalvm.nativeimage.hosted.Feature; import org.graalvm.nativeimage.hosted.Feature.DuringAnalysisAccess; @@ -89,6 +87,8 @@ import com.oracle.svm.util.ReflectionUtil; import com.oracle.svm.util.UnsafePartitionKind; +import jdk.graal.compiler.debug.DebugContext; +import jdk.graal.compiler.phases.util.Providers; import jdk.vm.ci.meta.MetaAccessProvider; @SuppressWarnings("deprecation") @@ -290,6 +290,16 @@ public void registerObjectReplacer(Function replacer) { getUniverse().registerObjectReplacer(replacer); } + /** + * Register a callback that is executed when an object of the specified type or any of its + * subtypes is marked as reachable. + * + * @since 24.0 + */ + public void registerObjectReachableCallback(Class clazz, BiConsumer callback) { + getMetaAccess().lookupJavaType(clazz).registerObjectReachableCallback(callback); + } + public void registerSubstitutionProcessor(SubstitutionProcessor substitution) { getUniverse().registerFeatureSubstitution(substitution); } diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/reflect/ReflectionFeature.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/reflect/ReflectionFeature.java index dbfc7ff67bd0..2277fd9418c1 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/reflect/ReflectionFeature.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/reflect/ReflectionFeature.java @@ -70,6 +70,7 @@ import com.oracle.svm.hosted.FallbackFeature; import com.oracle.svm.hosted.FeatureImpl; import com.oracle.svm.hosted.FeatureImpl.BeforeCompilationAccessImpl; +import com.oracle.svm.hosted.FeatureImpl.DuringAnalysisAccessImpl; import com.oracle.svm.hosted.FeatureImpl.DuringSetupAccessImpl; import com.oracle.svm.hosted.ImageClassLoader; import com.oracle.svm.hosted.analysis.Inflation; @@ -163,6 +164,7 @@ public SubstrateAccessor getOrCreateAccessor(Executable member) { private SubstrateAccessor createAccessor(Executable member) { MethodPointer expandSignature; MethodPointer directTarget = null; + AnalysisMethod targetMethod = null; DynamicHub initializeBeforeInvoke = null; if (member instanceof Method) { int vtableOffset = SubstrateMethodAccessor.STATICALLY_BOUND; @@ -171,7 +173,7 @@ private SubstrateAccessor createAccessor(Executable member) { if (member.getDeclaringClass() == MethodHandle.class && (member.getName().equals("invoke") || member.getName().equals("invokeExact"))) { /* Method handles must not be invoked via reflection. */ - expandSignature = register(analysisAccess.getMetaAccess().lookupJavaMethod(methodHandleInvokeErrorMethod), "Registered in " + ReflectionFeature.class); + expandSignature = asMethodPointer(analysisAccess.getMetaAccess().lookupJavaMethod(methodHandleInvokeErrorMethod)); } else { Method target = (Method) member; try { @@ -184,18 +186,17 @@ private SubstrateAccessor createAccessor(Executable member) { throw VMError.shouldNotReachHere(ex); } expandSignature = createExpandSignatureMethod(target, callerSensitiveAdapter); - AnalysisMethod targetMethod = analysisAccess.getMetaAccess().lookupJavaMethod(target); + targetMethod = analysisAccess.getMetaAccess().lookupJavaMethod(target); /* * The SubstrateMethodAccessor is also used for the implementation of MethodHandle * that are created to do an invokespecial. So non-abstract instance methods have * both a directTarget and a vtableOffset. */ if (!targetMethod.isAbstract()) { - directTarget = register(targetMethod, "Reflection target, registered in " + ReflectionFeature.class); + directTarget = asMethodPointer(targetMethod); } if (!targetMethod.canBeStaticallyBound()) { vtableOffset = SubstrateMethodAccessor.OFFSET_NOT_YET_COMPUTED; - analysisAccess.registerAsRoot(targetMethod, false, "Accessor method for reflection, registered in " + ReflectionFeature.class); } VMError.guarantee(directTarget != null || vtableOffset != SubstrateMethodAccessor.STATICALLY_BOUND, "Must have either a directTarget or a vtableOffset"); if (!targetMethod.isStatic()) { @@ -205,7 +206,7 @@ private SubstrateAccessor createAccessor(Executable member) { initializeBeforeInvoke = analysisAccess.getHostVM().dynamicHub(targetMethod.getDeclaringClass()); } } - return new SubstrateMethodAccessor(member, receiverType, expandSignature, directTarget, vtableOffset, initializeBeforeInvoke, callerSensitiveAdapter); + return new SubstrateMethodAccessor(member, receiverType, expandSignature, directTarget, targetMethod, vtableOffset, initializeBeforeInvoke, callerSensitiveAdapter); } else { Class holder = member.getDeclaringClass(); @@ -216,31 +217,30 @@ private SubstrateAccessor createAccessor(Executable member) { * an interface, array, or primitive type, but we are defensive and throw the * exception in that case too. */ - expandSignature = register(analysisAccess.getMetaAccess().lookupJavaMethod(newInstanceErrorMethod), "Registered in " + ReflectionFeature.class); + expandSignature = asMethodPointer(analysisAccess.getMetaAccess().lookupJavaMethod(newInstanceErrorMethod)); } else { expandSignature = createExpandSignatureMethod(member, false); AnalysisMethod constructor = analysisAccess.getMetaAccess().lookupJavaMethod(member); - AnalysisMethod factoryMethod = FactoryMethodSupport.singleton().lookup(analysisAccess.getMetaAccess(), constructor, false); - directTarget = register(factoryMethod, "Factory method, registered in " + ReflectionFeature.class); + targetMethod = FactoryMethodSupport.singleton().lookup(analysisAccess.getMetaAccess(), constructor, false); + directTarget = asMethodPointer(targetMethod); if (!constructor.getDeclaringClass().isInitialized()) { initializeBeforeInvoke = analysisAccess.getHostVM().dynamicHub(constructor.getDeclaringClass()); } } - return new SubstrateConstructorAccessor(member, expandSignature, directTarget, initializeBeforeInvoke); + return new SubstrateConstructorAccessor(member, expandSignature, directTarget, targetMethod, initializeBeforeInvoke); } } private MethodPointer createExpandSignatureMethod(Executable member, boolean callerSensitiveAdapter) { return expandSignatureMethods.computeIfAbsent(new SignatureKey(member, callerSensitiveAdapter), signatureKey -> { ResolvedJavaMethod prototype = analysisAccess.getMetaAccess().lookupJavaMethod(callerSensitiveAdapter ? invokePrototypeForCallerSensitiveAdapter : invokePrototype).getWrapped(); - return register(new ReflectionExpandSignatureMethod("invoke_" + signatureKey.uniqueShortName(), prototype, signatureKey.isStatic, signatureKey.argTypes, signatureKey.returnKind, - signatureKey.callerSensitiveAdapter), "Registered in " + ReflectionFeature.class); + return asMethodPointer(new ReflectionExpandSignatureMethod("invoke_" + signatureKey.uniqueShortName(), prototype, signatureKey.isStatic, signatureKey.argTypes, signatureKey.returnKind, + signatureKey.callerSensitiveAdapter)); }); } - private MethodPointer register(ResolvedJavaMethod method, String reason) { + private MethodPointer asMethodPointer(ResolvedJavaMethod method) { AnalysisMethod aMethod = method instanceof AnalysisMethod ? (AnalysisMethod) method : analysisAccess.getUniverse().lookup(method); - analysisAccess.registerAsRoot(aMethod, true, reason); return new MethodPointer(aMethod); } @@ -273,6 +273,27 @@ public void duringSetup(DuringSetupAccess a) { for (Class primitiveClass : PRIMITIVE_CLASSES) { ClassForNameSupport.registerNegativeQuery(primitiveClass.getName()); } + + access.registerObjectReachableCallback(SubstrateAccessor.class, ReflectionFeature::onAccessorReachable); + } + + private static void onAccessorReachable(DuringAnalysisAccess a, SubstrateAccessor accessor) { + DuringAnalysisAccessImpl access = (DuringAnalysisAccessImpl) a; + + String reason = "Registered in " + ReflectionFeature.class; + ResolvedJavaMethod expandSignatureMethod = ((MethodPointer) accessor.getExpandSignature()).getMethod(); + access.registerAsRoot((AnalysisMethod) expandSignatureMethod, true, reason); + + ResolvedJavaMethod targetMethod = accessor.getTargetMethod(); + if (targetMethod != null) { + if (!targetMethod.isAbstract()) { + access.registerAsRoot((AnalysisMethod) targetMethod, true, reason); + } + /* If the accessor can be used for a virtual call, register virtual root method. */ + if (accessor instanceof SubstrateMethodAccessor mAccessor && mAccessor.getVTableOffset() != SubstrateMethodAccessor.STATICALLY_BOUND) { + access.registerAsRoot((AnalysisMethod) targetMethod, false, reason); + } + } } @Override From ba32dfebd2aeb962ce8af273d2eed6c2aeebfb8b Mon Sep 17 00:00:00 2001 From: Codrut Stancu Date: Sat, 16 Dec 2023 12:38:08 +0100 Subject: [PATCH 242/593] Guarantee field position is known before accessing it. --- .../src/com/oracle/graal/pointsto/meta/AnalysisField.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/meta/AnalysisField.java b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/meta/AnalysisField.java index 453fd6234529..e8ed9ab33b56 100644 --- a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/meta/AnalysisField.java +++ b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/meta/AnalysisField.java @@ -40,6 +40,7 @@ import com.oracle.graal.pointsto.infrastructure.OriginalFieldProvider; import com.oracle.graal.pointsto.infrastructure.WrappedJavaField; import com.oracle.graal.pointsto.typestate.TypeState; +import com.oracle.graal.pointsto.util.AnalysisError; import com.oracle.graal.pointsto.util.AnalysisFuture; import com.oracle.graal.pointsto.util.AtomicUtils; import com.oracle.graal.pointsto.util.ConcurrentLightHashSet; @@ -476,7 +477,7 @@ public void setPosition(int newPosition) { } public int getPosition() { - assert position != -1 : this; + AnalysisError.guarantee(position != -1, "Unknown position for field %s", this); return position; } From b9612dcca3b04d07bd0f790585f3efba6bd00cd7 Mon Sep 17 00:00:00 2001 From: Josef Eisl Date: Mon, 18 Dec 2023 09:17:36 +0100 Subject: [PATCH 243/593] svm: rename JNIVersionJDK22OrLater to JNIVersionJDKLatest --- .../svm/core/jni/functions/JNIFunctions.java | 14 +++++--------- .../oracle/svm/core/jni/headers/JNIVersion.java | 5 +++-- ...nJDK22OrLater.java => JNIVersionJDKLatest.java} | 13 +++++-------- 3 files changed, 13 insertions(+), 19 deletions(-) rename substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jni/headers/{JNIVersionJDK22OrLater.java => JNIVersionJDKLatest.java} (78%) diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jni/functions/JNIFunctions.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jni/functions/JNIFunctions.java index cbfe7dc30e2d..b564d50b0e30 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jni/functions/JNIFunctions.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jni/functions/JNIFunctions.java @@ -102,7 +102,7 @@ import com.oracle.svm.core.jni.headers.JNIObjectRefType; import com.oracle.svm.core.jni.headers.JNIValue; import com.oracle.svm.core.jni.headers.JNIVersion; -import com.oracle.svm.core.jni.headers.JNIVersionJDK22OrLater; +import com.oracle.svm.core.jni.headers.JNIVersionJDKLatest; import com.oracle.svm.core.log.Log; import com.oracle.svm.core.monitor.MonitorInflationCause; import com.oracle.svm.core.monitor.MonitorSupport; @@ -158,14 +158,10 @@ public final class JNIFunctions { @CEntryPointOptions(prologue = CEntryPointOptions.NoPrologue.class, epilogue = CEntryPointOptions.NoEpilogue.class) @Uninterruptible(reason = "No need to enter the isolate and also no way to report errors if unable to.") static int GetVersion(JNIEnvironment env) { - switch (JavaVersionUtil.JAVA_SPEC) { - case 21: - return JNIVersion.JNI_VERSION_21(); - case 22: - case 23: - return JNIVersionJDK22OrLater.JNI_VERSION_22(); - default: - throw VMError.shouldNotReachHere("Unsupported Java version " + JavaVersionUtil.JAVA_SPEC); + if (JavaVersionUtil.JAVA_SPEC == 21) { + return JNIVersion.JNI_VERSION_21(); + } else { + return JNIVersionJDKLatest.JNI_VERSION_LATEST(); } } diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jni/headers/JNIVersion.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jni/headers/JNIVersion.java index d5f5ac0d95c6..356a74c4beb2 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jni/headers/JNIVersion.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jni/headers/JNIVersion.java @@ -24,17 +24,18 @@ */ package com.oracle.svm.core.jni.headers; -import jdk.graal.compiler.serviceprovider.JavaVersionUtil; import org.graalvm.nativeimage.c.CContext; import org.graalvm.nativeimage.c.constant.CConstant; import com.oracle.svm.core.Uninterruptible; +import jdk.graal.compiler.serviceprovider.JavaVersionUtil; + @CContext(JNIHeaderDirectives.class) public final class JNIVersion { @Uninterruptible(reason = "Called from uninterruptible code.", mayBeInlined = true) public static boolean isSupported(int version) { - return (JavaVersionUtil.JAVA_SPEC >= 22 && version == JNIVersionJDK22OrLater.JNI_VERSION_22()) || + return (JavaVersionUtil.JAVA_SPEC >= 22 && version == JNIVersionJDKLatest.JNI_VERSION_LATEST()) || version == JNI_VERSION_21() || version == JNI_VERSION_20() || version == JNI_VERSION_19() || diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jni/headers/JNIVersionJDK22OrLater.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jni/headers/JNIVersionJDKLatest.java similarity index 78% rename from substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jni/headers/JNIVersionJDK22OrLater.java rename to substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jni/headers/JNIVersionJDKLatest.java index e6aebc8f91bf..fa03c24a386c 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jni/headers/JNIVersionJDK22OrLater.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jni/headers/JNIVersionJDKLatest.java @@ -37,22 +37,19 @@ public boolean isInConfiguration() { } @CContext(JNIHeaderDirectivesJDK22OrLater.class) -public final class JNIVersionJDK22OrLater { +public final class JNIVersionJDKLatest { // Checkstyle: stop /* - * GR-48572: there is not yet a JNI_VERSION_22 constant defined. As soon as it gets available, - * the "value" property of the CConstant annotation below must be removed. - * - * GR-50948: there is not yet a JNI_VERSION_23 constant defined. As soon as it gets available, - * the "value" property of the CConstant annotation below must be removed. + * GR-50948: there is not yet a JNI_VERSION_XX constant defined for JDK latest. As soon as it + * gets available, the "value" property of the CConstant annotation below must be removed. */ @CConstant(value = "JNI_VERSION_21") - public static native int JNI_VERSION_22(); + public static native int JNI_VERSION_LATEST(); // Checkstyle: resume - private JNIVersionJDK22OrLater() { + private JNIVersionJDKLatest() { } } From 50a8e84704d9f94d355c58a1e339b9412f41f29d Mon Sep 17 00:00:00 2001 From: Eugene Sytnik Date: Mon, 18 Dec 2023 11:34:04 +0300 Subject: [PATCH 244/593] fix debug section alignment which can lead to corrupt debug info --- .../oracle/objectfile/elf/ELFObjectFile.java | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/ELFObjectFile.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/ELFObjectFile.java index c5a4fc36f731..e0af88f3fd07 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/ELFObjectFile.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/ELFObjectFile.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 2023, 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 @@ -1184,14 +1184,14 @@ public void installDebugInfo(DebugInfoProvider debugInfoProvider) { DwarfRangesSectionImpl elfRangesSectionImpl = dwarfSections.getRangesSectionImpl(); DwarfLineSectionImpl elfLineSectionImpl = dwarfSections.getLineSectionImpl(); /* Now we can create the section elements with empty content. */ - newUserDefinedSection(elfStrSectionImpl.getSectionName(), elfStrSectionImpl); - newUserDefinedSection(elfAbbrevSectionImpl.getSectionName(), elfAbbrevSectionImpl); - newUserDefinedSection(frameSectionImpl.getSectionName(), frameSectionImpl); - newUserDefinedSection(elfLocSectionImpl.getSectionName(), elfLocSectionImpl); - newUserDefinedSection(elfInfoSectionImpl.getSectionName(), elfInfoSectionImpl); - newUserDefinedSection(elfARangesSectionImpl.getSectionName(), elfARangesSectionImpl); - newUserDefinedSection(elfRangesSectionImpl.getSectionName(), elfRangesSectionImpl); - newUserDefinedSection(elfLineSectionImpl.getSectionName(), elfLineSectionImpl); + newDebugSection(elfStrSectionImpl.getSectionName(), elfStrSectionImpl); + newDebugSection(elfAbbrevSectionImpl.getSectionName(), elfAbbrevSectionImpl); + newDebugSection(frameSectionImpl.getSectionName(), frameSectionImpl); + newDebugSection(elfLocSectionImpl.getSectionName(), elfLocSectionImpl); + newDebugSection(elfInfoSectionImpl.getSectionName(), elfInfoSectionImpl); + newDebugSection(elfARangesSectionImpl.getSectionName(), elfARangesSectionImpl); + newDebugSection(elfRangesSectionImpl.getSectionName(), elfRangesSectionImpl); + newDebugSection(elfLineSectionImpl.getSectionName(), elfLineSectionImpl); /* * Add symbols for the base of all DWARF sections whose content may need to be referenced * using a section global offset. These need to be written using a base relative reloc so From 6da46f7679179291f3fc3e7ab64d326cf8993734 Mon Sep 17 00:00:00 2001 From: Josef Eisl Date: Mon, 18 Dec 2023 10:09:40 +0100 Subject: [PATCH 245/593] Revert "compiler: strip optional java version part in JVMCIVersionCheck" This reverts commit b0821d5c3b2c8027beae1a0431cd51f595d44710. --- .../compiler/hotspot/JVMCIVersionCheck.java | 27 +------------------ 1 file changed, 1 insertion(+), 26 deletions(-) diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/JVMCIVersionCheck.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/JVMCIVersionCheck.java index c9dd587ac702..096962ee1485 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/JVMCIVersionCheck.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/JVMCIVersionCheck.java @@ -113,38 +113,13 @@ private Version(String jdkVersionString, int jvmciMajor, int jvmciMinor, int jvm } private Version(Runtime.Version jdkVersion, int jvmciMajor, int jvmciMinor, int jvmciBuild, boolean legacy) { - this.jdkVersion = stripOptional(jdkVersion); + this.jdkVersion = jdkVersion; this.jvmciMajor = jvmciMajor; this.jvmciMinor = jvmciMinor; this.jvmciBuild = jvmciBuild; this.legacy = legacy; } - /** - * Gets rid of the {@link Runtime.Version#optional()} part of a version string. See - * {@link Runtime.Version} for details about the version string format. - */ - private static Runtime.Version stripOptional(Runtime.Version jdkVersion) { - if (!jdkVersion.optional().isPresent()) { - return jdkVersion; - } - String jdkVersionStr = jdkVersion.toString(); - final int optionalLength; - if (!jdkVersion.pre().isPresent() && !jdkVersion.build().isPresent()) { - // if we have no $PRE and no $BUILD, then the optional is delimited by "+-" - optionalLength = "+-".length() + jdkVersion.optional().get().length(); - } else { - // else it is only delimited by "-" - optionalLength = "-".length() + jdkVersion.optional().get().length(); - } - Runtime.Version strippedVersion = Runtime.Version.parse(jdkVersionStr.substring(0, jdkVersionStr.length() - optionalLength)); - if (!strippedVersion.equalsIgnoreOptional(jdkVersion)) { - throw new RuntimeException(String.format("%s failed to strip the $OPTIONAL part from the Java Runtime Version string: %s vs %s", JVMCIVersionCheck.class.getSimpleName(), jdkVersion, - strippedVersion)); - } - return strippedVersion; - } - boolean isGreaterThan(Version other) { if (!isLessThan(other)) { return !equals(other); From c6065f103a41ac37e242ed0f5f18c9b19a1608b4 Mon Sep 17 00:00:00 2001 From: Carlo Refice Date: Mon, 18 Dec 2023 10:40:42 +0100 Subject: [PATCH 246/593] Remove redundant stack size flags from renaissance ci config --- compiler/ci/ci_common/benchmark-suites.libsonnet | 5 +---- java-benchmarks/mx.java-benchmarks/mx_java_benchmarks.py | 2 +- 2 files changed, 2 insertions(+), 5 deletions(-) diff --git a/compiler/ci/ci_common/benchmark-suites.libsonnet b/compiler/ci/ci_common/benchmark-suites.libsonnet index 2ea20d4f134a..3482f880443d 100644 --- a/compiler/ci/ci_common/benchmark-suites.libsonnet +++ b/compiler/ci/ci_common/benchmark-suites.libsonnet @@ -131,10 +131,7 @@ max_jdk_version:: max_jdk_version }, - renaissance: self.renaissance_template() + { - # [JDK-8303076] [GR-44499] requires extra stack size for C1 - extra_vm_args+:: if self.platform == "c1" then ["-Xss1090K"] else [] - }, + renaissance: self.renaissance_template(), specjbb2015: cc.compiler_benchmark + c.heap.large_with_large_young_gen + { suite:: "specjbb2015", diff --git a/java-benchmarks/mx.java-benchmarks/mx_java_benchmarks.py b/java-benchmarks/mx.java-benchmarks/mx_java_benchmarks.py index 40b18f2b3c73..036a65a59936 100644 --- a/java-benchmarks/mx.java-benchmarks/mx_java_benchmarks.py +++ b/java-benchmarks/mx.java-benchmarks/mx_java_benchmarks.py @@ -2028,7 +2028,7 @@ def createCommandLineArgs(self, benchmarks, bmSuiteArgs): if any(benchmark in sparkBenchmarks for benchmark in benchmarks): # Spark benchmarks require a higher stack size than default in some configurations. # [JDK-8303076] [GR-44499] [GR-50671] - vmArgs.append("-Xss1090k") + vmArgs.append("-Xss1090K") runArgs = self.postprocessRunArgs(benchmarks[0], self.runArgs(bmSuiteArgs)) return (vmArgs + ["-jar", self.renaissancePath()] + runArgs + [benchArg]) From dea2e1c940affd627f0d89c8436fc5803014dc14 Mon Sep 17 00:00:00 2001 From: Fabio Niephaus Date: Mon, 18 Dec 2023 11:39:49 +0100 Subject: [PATCH 247/593] Re-enable threaddump support for Truffle languages. --- sdk/mx.sdk/mx_sdk_vm_impl.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sdk/mx.sdk/mx_sdk_vm_impl.py b/sdk/mx.sdk/mx_sdk_vm_impl.py index 0b89c498f84d..ce468df9e313 100644 --- a/sdk/mx.sdk/mx_sdk_vm_impl.py +++ b/sdk/mx.sdk/mx_sdk_vm_impl.py @@ -1448,7 +1448,7 @@ def contents(self): if isinstance(image_config, mx_sdk.LauncherConfig) or (isinstance(image_config, mx_sdk.LanguageLibraryConfig) and image_config.launchers): build_args += [ '--install-exit-handlers', - '--enable-monitoring=jvmstat,heapdump,jfr', + '--enable-monitoring=jvmstat,heapdump,jfr,threaddump', ] + svm_experimental_options([ '-H:+DumpRuntimeCompilationOnSignal', '-H:+ReportExceptionStackTraces', From fb2bc1922ab0ec25db1b4bf5e9a7df2ccbf6c8ac Mon Sep 17 00:00:00 2001 From: Fabio Niephaus Date: Mon, 18 Dec 2023 11:40:17 +0100 Subject: [PATCH 248/593] Add missing threaddump option to docs. --- docs/reference-manual/native-image/BuildOptions.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/reference-manual/native-image/BuildOptions.md b/docs/reference-manual/native-image/BuildOptions.md index 579acdc72a48..50c5c67b9bf1 100644 --- a/docs/reference-manual/native-image/BuildOptions.md +++ b/docs/reference-manual/native-image/BuildOptions.md @@ -28,7 +28,7 @@ Depending on the GraalVM version, the options to the `native-image` builder may * `--enable-all-security-services`: add all security service classes to the generated native executable * `--enable-http`: enable HTTP support in a native executable * `--enable-https`: enable HTTPS support in a native executable -* `--enable-monitoring`: enable monitoring features that allow the VM to be inspected at run time. A comma-separated list can contain `heapdump`, `jfr`, `jvmstat`, `jmxserver` (experimental), `jmxclient` (experimental), or `all` (deprecated behavior: defaults to `all` if no argument is provided). For example: `--enable-monitoring=heapdump,jfr`. +* `--enable-monitoring`: enable monitoring features that allow the VM to be inspected at run time. A comma-separated list can contain `heapdump`, `jfr`, `jvmstat`, `jmxserver` (experimental), `jmxclient` (experimental), `threaddump`, or `all` (deprecated behavior: defaults to `all` if no argument is provided). For example: `--enable-monitoring=heapdump,jfr`. * `--enable-sbom`: embed a Software Bill of Materials (SBOM) in the executable or shared library for passive inspection. A comma-separated list can contain `cyclonedx`, `strict` (defaults to `cyclonedx` if no argument is provided), or `export` to save the SBOM to the native executable's output directory. The optional `strict` flag aborts the build if any class cannot be matched to a library in the SBOM. For example: `--enable-sbom=cyclonedx,strict`. (Not available in GraalVM Community Edition.) * `--enable-url-protocols`: list comma-separated URL protocols to enable * `--features`: a comma-separated list of fully qualified [Feature implementation classes](https://www.graalvm.org/sdk/javadoc/index.html?org/graalvm/nativeimage/hosted/Feature.html) From 416e07eca14b2f76d2dc754a31d1a8fc3e21b86f Mon Sep 17 00:00:00 2001 From: Fabio Niephaus Date: Mon, 18 Dec 2023 13:29:47 +0100 Subject: [PATCH 249/593] Add note on how to overwrite memory default behavior. --- docs/reference-manual/native-image/BuildOutput.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/reference-manual/native-image/BuildOutput.md b/docs/reference-manual/native-image/BuildOutput.md index 00c299639f62..c3cdbfadf68a 100644 --- a/docs/reference-manual/native-image/BuildOutput.md +++ b/docs/reference-manual/native-image/BuildOutput.md @@ -142,6 +142,7 @@ Please check the [peak RSS](#glossary-peak-rss) reported at the end of the build By default, the build process tries to only use free memory (to avoid memory pressure on the build machine), and never more than 32GB of memory. If less than 8GB of memory are free, the build process falls back to use 85% of total memory. Therefore, consider freeing up memory if your machine is slow during a build, for example, by closing applications that you do not need. +It is possible to overwrite the default behavior, for example with `-J-XX:MaxRAMPercentage=60.0` or `-J-Xmx16g`. By default, the build process uses all available processors to maximize speed, but not more than 32 threads. Use the `--parallelism` option to set the number of threads explicitly (for example, `--parallelism=4`). From ba953f7dfca13177fe47d263c44bac1912b3895b Mon Sep 17 00:00:00 2001 From: Olya Gupalo Date: Mon, 4 Dec 2023 15:07:24 +0100 Subject: [PATCH 250/593] Groovy syntax highlighting is not supported by the website --- .../guides/img/H2Example-json-configs.png | Bin 150307 -> 0 bytes .../include-reachability-metadata-gradle.md | 15 ++++++--------- 2 files changed, 6 insertions(+), 9 deletions(-) delete mode 100644 docs/reference-manual/native-image/guides/img/H2Example-json-configs.png diff --git a/docs/reference-manual/native-image/guides/img/H2Example-json-configs.png b/docs/reference-manual/native-image/guides/img/H2Example-json-configs.png deleted file mode 100644 index 5913a5396b17f9622d2cdd084469160a3a319a5e..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 150307 zcmeFZXIN9)+69VK=_mq9S5y=PRHRp>iAWQH(3|vLLJLJe?0^kWsRGgxI-w+VP?V04 z(3?mN1O!4acV?e`_Rc=vcYoYJ_dfUD!}CBE$trWrHRt<|G2SurOixFHk&cs&jEsy? z^S0_eGBOGT85w2dacb~Rg{;j>GBO4?XB8DaO%)Y>Js(d8XE%E?vfIz%jcFhT-`P{m z?rAz5qs)3VPWhTs`Oa~XhZ`OO=OZ4Sw7aEOlBh;CAesT`H9SGpPWO}tU3zJ=4x*=z zRkLu*t)ZozM-_#vgiMU?&2@Y@dMEc5#!P0)7kJNEF`rR6B1~Ug=rPDt%j=hW6o0u76e0XWaI3?cvDEX);Lzty)hm7Bjzw6|;9V!++8ZxWa z#5THP{6Ykyw{)NH$kW>@oMB-38Gk1^vq|oqv{p3p*2wt_Ui@_oWFNjxfA=Blsi7fs zoC{<6)w|D70$1fvAWN5E_(@jxRPZ6>%wBP1B<&sZVnRC1?iRE+4ji>1ICf7>Z zOjY)8UeUwwki8SSr+OZ~q|aKHOo5|e;P+=+y_LZ)86kc54IgU(*3te&a}`VTSfma+ zhtFGn$wz?^db}TVD~8S|y-MGV#yYl3yCDy`b+IeP3%H1LVjl`-!v#+IVD{fTlw7*Z zW-HW!Rr~qw^izqm{;%gQsOPz>v%iqOMj?4!E%JJp>r>W8Z&t0@l#Jeq&}-?9B(i^_ zS^FaStY!4H#JKULJJ0nnG;&|&2(8S%jiU4ymVO=M{Uk3E%+C>V_5A&KxlQv+nmYH_ zLte2{3+7^f-ggd59_Fn)HTy)EkiY`__TnVQ_4m75RWgSAffeOfMK#$3EtA_{yfpX{ zB}Uczkm42@>!rzW)?0t)`n(90d<5rjrJD80$>zZI zDZQ>E*ulfiq{oaBy)H4f4FU$P4R220VK}SK()^UE>KgCEy{X<+PRb`-T}`3XYugUG zfp?q)TuC#8!rHdASRFwnm(dc1#%UhmIad>U_;h)Hoj7Xd z(_J<&(X4ijam~RwV$45z`FvWN^uBmI=UaH4i%5 z5Kb!+_~YfnGsWbaSNWtSsrHpwj#ItnXFng|ca_P=gmSBz;VyY!gPR_CTf@C#Is_G0 zBYQE$67`-kg*1cCL-EOTRSbnuXs<25hl%N2H59eSBVVz|HYvYk@ok~@zBS6ie)8d? zbG^68-^4yRC-an2pTF-__3bmI+$JyF)bn50e!KaL(udbs#Y2GkwazcbHQFzFocT{a zW>n03y^AjGy>x??=f!L~Yp<;zFY0uGGQ7vaNgrc*8vPQBtCN^BiI^lEt?ePnbe3~Sijx{+4CdeLNd8(RmtT%R^vD;Sm zTB3A()zhj}h=#n5n}FiQ%~!Y23%p_do_0#>=W9C63t19b7Fl*#!dXl|XiBMvl9$w( z1RP&o_$BkpXH92Ke~oQT+(%3;$yVj}=azev?=HW)@UGz9#kLD~Xg(+As~|IX4c_Kf z_Yd{cxrh*M5O@g%j~_q&{5Vd%<}t)BK|T5_Z;US|vxMRgKj+vROzsTYH_h&j=*a1y zwP9L0eeMf4HyDD?hF+`v820Ay;o;4}@o9L0dnENbKGxGcWw;~rsE-GX@WKU(^ z>yyY9)JAtObVPRebQ*o+k-*(>d{6WKMW^vcKJoCze#g=eI~{bhmmMmjpQ$~HZn7;? zgR2#NPO&eY;cl00-!r-|oM2dixdV5Ad${`I^s#*iSH#Moo*P8+ToOjo(S3Ymcqn_g ztJ1wV)WgxK6)9W+FF`x%Rx+2TIa%3Z~D=6d=YhN4)4N5@RL-@B9 zS`)=neB~+WX_+rGIx}JzwV5oqcKJK5UlBxHM97Vbhq!G2K7LE}eoN`oBy$7NG_%g- z*p1j^-XNjp?D40Ol8gG~cI8)4&ZlIBeEOg3Z`r!pp1;Oe!k@r}KDQZ`Y%$tWrSiLF zyK1{_JBL=_WcGz*?FZ*$bw@vJi(Zy?*8DN{VDEvNkMDD%w)gKA-)-fc&1*Lp>3f`` zt&4u|ku0j?*}-q0^}wxt{tS<7FlIjXTB_ZhucN13rTo_h*QZ~$&cw-Gw{(^F+&{c~ z%fV%~tE0OHV#!t{_#z1@3Qy{uDw?f7MM-N!CmVg(G}GibbU4&rmNvINhxoQ|it2fr znuTp_V8J%jLlysZbStPNXk>kN&0rlz_l@cU70m_I8~N{fv<|Enb)DYIYHDRIvxW*5 zejF5e@y7kFz*@=L*INqP`V$$&#`{@;kW+g1O*U-qwPhW=g}T;$ ztL&c!I|fNPCU=t*mZ$tSH#)^%oiP#r=xExRELCP_w2j~?%PU)VIFf9IcCE>TcWS4M z-01cjM+C)%(;ekytCp!6`S{jN?8nfrQvIYVpdaHXG}%Vp*9-pCfkf0St)Dy0pjV39 zuKqb!_hsmXSz@5bQ1QE}`=uLSOB?Lv5^z_Wjnj#vN)3+(r_Y-z+c7o%B!6-z+Q~cP{nSWHimpT^N;c z7?>G5i{^4oag`c4(;vTl40Z};xzsrdv$N{2n>|1rAnS+sQFyXxWoLzZN}ub{H~V|W z-;WRaUtP2IeQVVhp(6UEg0Di_JV^EE+ndb(%=Oq!9$`hSuX%6{PPOY%YVe9+L%5Y=Xg9|HK zF^Qp~QpgxLx!?<{ZO`Cmjl0dKEzyArv%w=Vzql$rVylP3w7hUT%ljimE2qX5YUOae zQ4-cX{t0;8$T5Xyd)tPtG!%@m^3w?Y%$Ro?+d2+s(6{`XentNj%)>V03wB zs;juGT}-`xKJaqr(1_vMlP*4-ZfD zc%JVe3eC)f{8lzLcHjKQU=9oK2B9`ufy_Tp<5&1I-;?Lt#(JJK4HdPd2FXs=GYD#2wI&=k^dy2W@RKA+UX%jPe*K z85P(%27VQfas9Qee(Vw%#UJmJlaW1fCZqgwA06;Y{CNd_iO2lwmEz4~G8*vTN$?w( zPX6z`DG=!t|K6sI1fP-JG*Hph1g{2mKKAw=zD}NgJCm_j!5g$*w@rM>$k;Cse~)S2 zJHHCfKj3^H;s?>bD{JTJE^70@)7D-z(A|r89y0krS+MDD?`Ojw=D;ubA?vFiW z!8Y-2v2*-??BeIDa1Nra$FJh)W6v)sdR6r5IYl~tetvnM2M)6LRMr1H9Q>zn&dJZu zOIA!QARs_AKwQ+*$5HH>jEs!f)$3x{uZw^^M0|rh{A>b6JbVTIb&`LdN7dff&d1ry z&)L(1pLkvyTTiH;!nt$A3;p%;uXfr8I{$qo58pp;3*4X>@e{FYqF2TKIyX2}p7^e; zo^znRn~AEkJLofT4aIBMByPz6alrrh=4$$FC@)65b&{_5S3m#pF6d}QI(f0b9-1PZkEu3sG;%wu>fQ&hV3ZMm z$Zvu_m;Ut%wvX|bT(-;wV?vosQ}yQkz++2eG&QF%V_$zOUAm)j^VP%Sm!3-;7h*@G zXFRJ_Tj1w;ZK?J}ot5(D0#A#o-HX##E(5Wx zQv$_bGi?;fkMlny`|FSLO*$3`{k=3h0g^Yt$1QC9#a}<$9Q$j>KMwhSbnm>gUZdWv zLz;pq^E#Vvbrq2qxN*+cXTAv}H}v3~vUMkAZaRCKZ*{v~#G*$?E6-Sz!El*loWjvAhL4-QW=pUsg3vBjU+!6dfVFzJ3SIkkxx#&<;t{U+sw+7q79mr@{?|ZK zUZe#h&N=0RcyTP>(bI)-L$+wl;lUnktH9>4jviFJri*u;?OaxRYVxB(`AWfs;KW z4OW9Mv|}7}#M6V-i#y<)zqouU{~F#Aktg_z*N2a z$IuftW|ba{<4*+pQL^sC{npr)XK$AZD#z)@UC&iU7~b?6t@8F?ZKSC_D738o`k0xI z*PG#}GcPCAwlX;VVrMSP^ zY|S@COI4p4E8Et|DTO~V_aj@|6>g9d8!u$o);WQ6trW4W8Dzf#VQ~xYRpS^Esoej5 zitJ!I^ypw~vsZ)f14^+~sJGR$#5Q_>agQ3kzt%pM+kU7FK?kgCb|emgr;8`|tqHZa ze>ZvZ!ks~Fsj&w!TvpuP4AHAa^@qbe)0uIKvC!kQXGwa5pIl9{SZIIVTg-JJ?6u=6 zO3JVEqeO+h)`P9#WNv~y!r zbb$uo$E097UdgSzNlxtvBJ|^~w~pydnOMXdhVB2>@O(5~cp{Ty!mF9lznO7>rl8g1 zOYYI78Ze_;ErVv_b1yi&y{LTy>6S0Q-cgnvk#{Fv=!1CT2SFSFV`zT^T_&r>k*MDYsi09d;drSG!)E zAZ*+PyQ>vGa9|)}T+LVz!zod^x$NnCY_4`|+;_@#WjwSx|3@SfVv$KcXf2DsBX?%I z5RLEh(hfQSLH3ysqHo@vRod=DM4{qq}&QO_oE7kNZM3GzWXU|XeXDXTaOvs0$s6ncNiv4`CY8G z_cZ}wiX4O|hpcIim*5$?0{XH&Yp#y9imV^8hFvYkFN9>n?_a(bDnk`uh}V#Hx=(6Nw=yGi->6oPE!nxS|6-uJ5u{A zh${0RQ9XZP%~r-cl+o+$+Mhc`o%-F`$xvz%JcTN+wYcyr0b`dj7|F^D+z@0D1Ps7{ zmtI=Key-p1e0NjIea^+{-eTb zLsT~GezT1q$W_=(jc#im?Ocg_0-Spy8GYH>>v#i;6D6_ZxzR=Bt02aX5Ng2$4(w<({BuGU2&R@8+jbg4um3TuJ< zTH!V%WQ$adK-zwJ?g0yrViQ(;9u&8Ft(AK^XoBzbVi`A{3Gdl0{8x}CBj35K_kaTa z3iEuhK3qv|cRthilxept?h39yFOyBoa&(Lyghs#i7sdI$^fcZNhb_r1` zqUKdST(9OD_*ELoJ^Q3e~P-Wmzx2tQ3fqZW6i2F#-~?r$4Ts617Da zO$V2$)qoHR_N)(nWT>@2#UrO0b}`0WHAdUV4)Yt~O}}e`e50%@oqDw-13VrCSQQ{{ zzB+aO;73i+i>KY{+Yq`>i{u3?Jn&p9ztzdc#*7mJ>Z+7$su2?V0?LSDuBHB@d29hZ zC15=~@LC^9uK$Hre$9mVVML!mZVF;v8Jj5>kn<>4Aw>R*nT-YU>*b|0 z*^=}^#g8dsyOb=At&fI%PC_s)`Pe>)8ij&$zjZzGMop~xtYN@p@+qXOtMUbfD6E(Z zfuYj;iOPeFJ?Z8FdAGrZBhixL#>7D&eAw{UgJD%2`DbCJ} zc-BKjK0ZrT;AHZQQ`~(|zhWZOs){oQ(HL8^6S3Zd;dco^|a()X;f$Rm)#5_n)s zC54uRs7O;ayLiye`qE5RWq4-HL2*eNt1h=wyv`{|qL>vvdV}JoEVk~3PZ6pFKCie? zV#h51@shrE=teK?iA-jV01GBQ;a!bLFvY5G!kchcV@Pf<44~VioC5s^djy;-Dp9Og z`EE{H7z);vbE^lyId?2#D2UexdS{0RB383{Yru9XeES9p&l9lmbVM6tCB{9zCRFS) z!MU1uE1K@mrba(y&%P?{24r5_iNAn`FQh@pxR5(F#S2wTi4{x>X@e;)mC<%fjNaoM z`z)((opQ|%MUSTq;C1}On>o!a&F0AFKmxR1-3OrSsqrVnIJ7>_9MO}%C+k^Xo8(&3 z=Ts1!>X^X}?dN1*lmx2?uoc@E>}2qTbj67XsKJr)Hxai9{TFq-CXn*H^{!r zWEzi*T~zyIcGO3h4})l@g&*!TiqdIWW0?6sI%Mh+#;R7KOVwG!=0Ei|x;!IymELau zwcc%4NxdfrH$~y8{q1x%oX3)cLwpkhZGGqW{mli7K!7rIRGk!- z%Y!W;wPOlDKu*6ft}M6yhMm}zY!E`#TNu7t@HjkJ(s5IQ&+CelyVk6o5_zP#i_v zqsv!B5GA}N(^g5Agb)*j;a0J?g1X+_c7zGg=33ZRsd%@1UqRcq`nuCae}|4dKw4r9 z4Co2~`YQ*wMeUkv?|QgTAy7|E|K{rJrG|WsR{8za)9YzN`9SVBRG7OVcR`E-POY`r zo2lUy7;_#WiU>XxgF47}8!rF8yRpE9$fSi@6c{ZBc#J=16Rw$i8T%B1ucu9Nv9zH@ z$Z{}_69(;ACC=#gYn#RG=H1VGlT_qU8_eVy$d6EsAUtB#SvBohVcOj35O)a;6AI)@ zm0m9Ii_|y{uuR`$CWTc<>T2*^(vfThpfKeRI!y)G=2a-O5vUo_r`|619~Y&20uD*yr5WU9w(7(gs_+ISuB@=X&HEe zbz5qz!VfS9%AY)%WMfnHaU493-(I1U)0E==i9;VYn6fOINIP7oaNXWXH<6CFjxVYk zo>ZWRDz93yPBn0r@V}LsYVE(_F*+#g=fvlBEp*qfueNC_Ls`Q6r`^qmBc=8)&}kT} zoPXg@yCe6Gfw{Es@xtoakJct&{BYjBL!q%#kkm-~_~NN^8gaaKoM)v`57;5dIyVpW zaz%q!FyA4J#}Tlc@iNPaEyv%_NkVc2k^a3@{2ieY%k8YeXVF~nZondP{d#d%l9ZH9 z&+~wIPI=8w2KM+-nVZIwfD5AV-%BdcJF`hkC|n^ud*=u70n6ZphTKMDbMNZ0koC?p z>Zgsg3aH!e9cQwFyNgj)D2gwinF%Fl0cu_09IC(e&}xXzj8AFx}5e~4TJvHd5sJ(aWn zMg7ZvboU+5-Fj=>QqJTkJ|hA7L=m$tfKgMHBeLH3+kWEFpfQS3EyyTr2f?TYgD~kE zdji*wlQ8wMWFJeifE#JU&8we}fLY}#fZyqCw<{4N;S@dsK+K5Y9Xa<(B_c3F;tASL zoaECV_Z~KUOu)3MvH63@Y*Tc$i}~;2eDyf!WEBxFCN&+(IHniaY&aR#;4OK+yi~=$QnwrM;ECxvab$f*|d`f56W8PG$m)L%B>q;In%21^Zcn3J-&}3r( zwTApsakJZxtY`QGAYVBE=+2yAACLhsu%zAB4ePT1ftkt3qs_q7%i7H|E=q;2grVKX zYlhTco<7qX`94eK>zKO@Jpz+&Sa!`$on~$iBqs>ms32;K68kWc_OGTNqkImgkAx=1 zs?0$fH&LG!f7#$GkSXVH;eb;0#;?2uE#eko=qP93_CVOGu14-Rv*LDxdK@pSIc0=I zx-~gTFPsxmw$`>K2$yf-1_s&^L~u~X!(nw0T}LY1b$_0)TR~l=HiFXB{d#lJGGHNX z32>Na(%$5*lr)}y>%%OUN_;l+Je@>dMo65Hi;#HD z)J}ScEI1@27e~~fs2TK}L>#Tcc0R{&5?(D2mI(00)*P{Xpu*Cz2?dJOkBnYI?fBoL zWqQ}wAT*I87ce|t3yZ21pTDQvNJ$bZE(?O7mm>tXtVPimpges6BNQzcGM~|S25@C= zVv=Xw_c4upeVE~m?cVyM1J5KGU!&32F@kqbui)D;0=7i01gLK@L9{@m+%$cwQDqPE zafzq}N*y5;xXMpd$daT0_3WGf682rk+8w|P^yaXu_NS40CY}|drumFju-fAKonoO}^ZwQlm@zg$Hj!QUB*6_~ z`^h9bpFWw7$e-*U1JhqHpsatof9stM#G^ceDTfpV*A?tWRmhRCI)=P*k zifLGEUnNb|Qyf55Rpz-|p8uJ!+RR*ubR9tTpkQ10tQ1Y@;$51ZALvB?#eQee8?NI( zQFLD(nQ&<32}rJgK0sH~Ma^6%9$56Oi3NfiC|cn?^DFKBtvnQ)Yq<@TkHVe#wf3ap z7^(63qLVczAr$}f=E(Ci1mX}sqp=Z2B|oPs96C9-xPLr|#?Ck7A4~Al&1@;CxX0!2*_-NjS#C7)J0MgA!QZ;W5`CBHVZ^RIxva^ zj(lPV_h?OUvOWi8E(Ab0baP0E>zeHmzgke}o!$tfMqFw|(E9BAC;AXWCj!mYV1Njh zi^4-?A(iPAaJ)r|Qn;m8m{y`FQuFOanmG=IYrz{T*~g0ZZ&?#A1d?b&>8r#9SQT4X zyU8ilR)9kK1C{TxBP$aE?Y~^%zdU?FzH4Kl&%DyKpxkFhaI=AenG(n0XI)@Ymd&yB zgk~;tZuoHG=)h`KF*pN?GqT*8Y>yiH&!|FI3z9M!JlA{rMS*>LLLqW>CHx4ju=C46 zQzpsF`d|^xXleZG7;T(*$ab;y#uy`)WZ>2dUPyg9g)5lw1t6p~?o>MWVK+`E1%9?^ z7Oy41s9w+_j#06arv6}%osJpmOC#zwerRn1;&{Q?@gx&srT(Z+VSjb-Q7dXX7VqCB zGgk$zJJ>XnGA*vZc@vZ*67n(k)wU)poO*vKA>S7T{VLhPSVh#_(VHy zOW&l*>yyIaHn~*6(fk=Cpxb^cnUw_~)BxExv=JpMm10+OQsLg!2#M5F>m;oDQV4Mx zBi?#JLYI*PwT>UV+7mOMP{7HpM=F+oj>ORFx#|=zo=N1zsdt@j={?dQJwmc|~rc zM`a8K%I?HO$(~v@^_Z(>E`5B`LG6i7XNR*jro^%HGB%YTvo)gw}oO5b5H@KpeJU9rb><95LnRa;X>s?0rE z_LSIS7E;mdlm{3{iv7A^AOV0c3ENB#p@*Ytz#I=Ms@?q9`Tm;tPkE2(8FuvSM>ujY z9;EXw6cjxcjlCq`#E9pU>q$4wQiAT>?jXf4kk&tOCet z8dr{H60Me=2_Cw&CyG^q#Mm$Lf>6^B5Rn<+$fIlX`jO4uIx%ei2Na8gV<;#RNYai~ zOi)K&rLai%!Q#ffPu8eCRi%V4Z2N5Q#WM-*`B zc~`goS{f=FF)G||@n0Hzz0_P9PVyL7ZkH0DLj#-8{bEqj9I6Z5dlPudpG0E>xg;wG z?4y8-hu>cL&eplcaN?T)hLyHampP=NL(x1+*y` zD42a^meoR}jZ)^H0o3iXRkZovnT)vgDiws24TNza-QTekY~2n5{nloDmgDbA9dYZw z&HjIDZ_h4MaR<+T!j>=C1Fyg}pxD4`*Sq9`U}T$*|1lyS=z}4smYa<5U;8dNG+^af z&KJIaO)!b$n`HQQGatgfogF_YyV8|{KJ_igOYa|JjL31im4POSfNhPqgDR7xZOiRF zpohKj%c>c352G?d{$dA}oRob~uUgwYH^@Z-Z*Z|cD zNTR5P3&^=$2j9zRNN?e`Ffm@h%K$F0)N&06P7eezxX>45y6tT?ahcL0G!K=F|CT?% zg})J}d;5JEtKYeqv8Bf-PMNk30pEmkrniPBe`JJmx{S;$Ctn z@G6`b2-qBQG--|H8I$L+8p(A+kD&w5&IdULIbCNWot~Y%F#0=I=`awk_bHOcuji)6 zfd$$hMqzd^kRSpZVHY(&y%a^tPg!n<5_2>5Q&WnmDO(k`zyOfJ9f@0o)Y6<1E?J;Z zE`(>pU6T~6-FS1bpd0RkYk?s;8Kp+8rAEC%S)}cj_0IZjF3D`R2^Uem5JN9rcO9wF zUR4}d1$0<|9Os;q;y_f3sqm^ZpjKQ~V%K`XG}`_jU3Tjal7j%^({Mus#oaOQ`t6_e zFi^kHWG)B}=>TxKwis1!h^hYt^6@ZmC2*dg#C$O-_#jk5jyvO+Yy;rHX26ssk}u{V zLir5OQ$d~N2cETr1hXQW=Es(}g+q3ug1O3Kmp#yuDrkRarCH?&QEkB2Vw0}f1s4}O z?21%7e5t{XT|dzdp0vmGSB0MyGfMwxj0ve=a2|st4_YnFBbq$GTeSH3kM@^AbbNp9>dHlJcw*F)jZVZPW=ILm6Yf z-D8b1-%CKLw{e%WRR2(Uk?8Wu#mCB*KIbr{368*dnUy)j#PBLy{HfSgBVPa*&Tu0Q z-;#eGd;cHR=e)qdVwwWLN*X_90-D3cBjw@NlOf|id}Bos!`8TasQUI|OaZ`Dc=sBz z510no2j5b%9~PCm4P6gND}b@?#!;7jl!e~8nxmCic!v5d9s6~XvLhM!WuR?}H00-- zSC`^=&GYVE*jp+y1Oeu$yi$^ZuEG~;W?t^4fR?AP&rqwZapY^QfM*@)#l-_TAY6xG zd>wPNlQ8jyf=tM+;``L4$}A>O=g$ltSqhU2$? z)8GYScvUs`y5Qg~Ux~HS&AG~R-5(|7Y>NeX;vz`{Zyr!FL>gpWN4ITVhe|)=Z1=Y6 zkH$b@BM;mkuL8ap0P~S$VCjf zalXd)`7^oSFQI5QfJWwz9xt|uBCII!PuT!5--Rf|jmnmg!|@!Uz>Rcw>_eHU4=aT2 z&feCFBLKJUi&HhN3mp}SR*I|ADOWtdJtrOZdbz}si5?HQ%G^6q$g1j(u3K^Gy_rt; z!5pCJd#L*CPT>7 zZ3mA^+^1f!AhB(Asu^KaVCoS+-w?d;IT6T?G`wflm&&?_4RjAA0$X0zPrSLHHHKQ>Iz56IjkJ@cFGD8MdaU(1Z``r(PE`PPFSBs{7S|0scPE>e$tgyX%z9avD3ImT zKfzqkN*Dyzk?ZAmFHYb0W1ipNS&wXdR(Es=!(o><-?xH%`c|sAH@eYTl?Hpw?rY$f zZ}?n75u~K)F>~C(>D1NR&89L&);udQ=awdD_5d*&DYj{joZe-1=`@5F-pM$Y3GlH! zvCLBcVF1;Bsqq*!DICu#2Dy??NQ~QPB4k~Ag|}Vi8iie{&P*ZtaaAw$;GhWd`!!&R zLO+Lcd&feN9)8v_c+1futMENQSN6wH`Y@tSE9K*LwJ+%@8w7|4ibQqJjA&FWNmYOi z1x$o;jCY6(1c!aNZl7QK`zzO>+14<~ljyZJVS(A+CeFr2QqFYG2n>y1#IE_QHL+%T zHhHoiFAo9MK3I>5xruYH?5ll^f;N$8?%F*aAfnI0t|&{Ez- z)X@y{@0Wm-qt4xIbLa@dxK8QQ;K zLD57(%&4e0x`9)qi4;-XGav$(V9+KY#|*tZBfhQxNL5a26T|5qrQ?~0`>QyRw_L)H z_RgVq7vZBzV8(n{9;vLnsLlCAs{QK0{(AQa@QSf^#IZpD6?6p^<+dA>i@c*CJ6x1s zA>angKHrHqzdCSp;Uss@Kg=C>fa3J_ekh$Ok=8|G#(0> zt$HHRDl5IGzXruUkr^w}FX}Ycm3oaMLI&*s{dH7gLdME}BLkZa9~USfFm~ zdevx<(4&Y`tU$ZZYwG_=RAu+TUAhA$k&4%-IWe#GOMjj(g2#Vwssf5*U*R@R!V7eI zTsF*q#}mHq4NST+X0^dcAiK+;(Ox)L>s+EC=+3)KQ>kol$Lg;_rYrphpzIzo25@nn zz2T?$f5hfL_?K<1QLbJi0Fe%$sH^o;e^7#Civ5>J{a>N2w-*4*-TenSO7irH5T9QHq^Ud;&*cB;`c06f%ZqG9Sx9*R%WZ9dMqRL6j{iZu zf!-;x41Z7mx0RV_dH-Y9eI$G}`Dbm?nJ9GZ3C)s|NN|99_k)UMwnMEqmNdUTR2~M? zr?2jLwK6HE`2SV2%?i7B)1#P5?|r^A1pKBof7V17!TDflRxfh@hHxe;u*aP*1b+3O7^IUg!tFXI=JD!qxQX@ZfGiqFrlj82|>nkoV1bW}dZ}!n)o3 zM`kO7B|tFe@~{HAp(PmbhvKp>+4fE|51YQ`XU(Ljq> zvU`H@)pN5#<-EWTU#@$U`P##o+%LZPQHrU11sUN7xW2=m zS85+qz)`HgmUX73iCK+J^T6hyUECM5_#M&!rAG3e)mUCKg;w&U6T3{0XV{f<3!9*ZQFIo0|6R>wpicpg>3_QcbeC=48X0YY9@?`V1{m> z??$@QFmf(M244NA#-Ys51+tBs^~?hdyU528uma%Z2~&y5p7fhhHI9|Mc=aJ*-Ud3! z%!93=@$9gJUH_T*@bY0~TnPw?4ugjvwER{V;&mbd;NmOr2t%$%W)MN$R9k?Z9E$n= zIbtK0fGejgGrk#`B!R|=0!4(w6o}YCf2cm-d_>`ZOCk7fT{LFCZ=lQ)C@UueJf<`{ z5CBLs@+rzg6yzeHhx3S`%bt)lG2ek4EW-rwhkZhR%T+2>&@2k4bxyz zGK>U{b&_H<2-l}0Bs!HSQQ?~vBg0h2)&DA-QwZ$1+yrHr+M8+WCJR44j|Br&q=Hu= zn0n-a;2+BqE^2=~?MIJ&Xds~evYbtrsXR5mebpj>v4m)~Y&|W%t>d|x2mN2d%ZY7< zjug4p{)~l0Fs-Zi90|u$fb=)2BmK#P61~jItfLnLjyP61A8w3~IFwjhi0_ z!MZ8;F%*XDb5+)WeN~3@Df@b-hdJZ5(@G;4tAF_QST31@0eDVtf@p~bmXuB=#qG&Q z#&B#8aK~IlHa*tzr+`n=63u#W2@X3k#3~1;NpMuuIU^$8k^)frxWT z%J+Sg^7H@%=zB3F?zc%@NOb@ouAia({XfK;sJnJdQIBG)A`#L@}{98Pl25zP=Kmkc9<0)YyrH8-JVCRYNGS*>q z!~o%HA##Gd^iQM6qyni#!mk$yk~COGBwZ%YG7m}^5>7o0%b&m&D?;vVU@(=gGkO@y#%3O%$^AoHt~( zvBGtr@DUA25-*p>YezQmV@Y1Mf%M1&u%;+^1N(yr>Vfp|abvm#tusqPl=S+EZC+wc z?->BX32Y|b*bPYHK|cO;fgnm%;7%ru@BjzLAE?}a9SE%>R)=d@(51m%9hsR2a==bE z8UjTh0I0q+^`sSLo&SNTWrE@bkX=fj|51CWB?^4TR-w+*t-4potT>ClWw{QB`tSd4 zHH)TWi(CflEteV7H>}JmmfX#%ylgr;i-@pnF&{o!8oqBwtousX)&egA>R=%mteHRu zyqsPFEvW=f+9Y!L^91MgY*0`b0tP~Xin)J0>GQe()XI;ztyDuwY_aG7F*!oN!7|^` z_7jf6>>1f|A;jj&M7IkT;Y_To5SQc*DHg3#{{`^DfQWb1H#{9zk*)e7{iZJaH(wMe%SpoPeR` zx@xW5BBU!{!XKz)+j6|poWKI#2V_bz051;%x}~j%125^5|5XB>eB4c6H2Q0dSVe+} z*~eQ39xARN?G=DkX_l@wA_G5U96FjSf(eV}DYnwZLJd1pI%6QdS6* zF$`B^YKTFa3`}?T#Ugcp-HHglPPG0*n>_xDNXJ*SeQR4^h@!rkR(i}dL3C8$O{u&K zJ{{Lut0q4eqkzTIJk3nH*u|0V6%eyZK5HeSLUC1@8cGk?gpFQGC!kiwgXU5;!LsG5 z9Y8eJn`R&exkmadV3G9aq|KwgJOhol(N?paNuI#$?bF&X&oiA0!&e9y=2sb>dJjyG zb47T|GFAvO0(E)9w_Bkxh*+i!-l%Hklyp12v;|J=H^ALN>Y+SF`35Y)(57?62Lw+= zb3lOm!RM4I8z*?2(|9gJ;i>uFO!wtsF`w{zruu{djmIDV_jdtQ_vITEEV7H4RdgKg&(&|ksf+09 zz?vA^@qmRN7~-1a$xwhMOv9n6CHS0_8_u>~ad=_@l7fbbF7_Wz$>ZlWz)0pEkRST@ zGShY=ClQmrd4P-3zAZE5Zjl-`x zMKKg5b+sRNm~o|E=tiQD;g13(qC3)BkLZpx6#kv1`Sw6tz!LK_bY~_J9pn;?Q8qY5 z3OjBWf@fY`S3M2`BKT;-O_cElKm!s~rGc3=!Uzy{Mq>QXcCAbX5R3Y-(8BJsHBnyH z+NV@8A`p>WAiwBf!V+*BaN8gZ~ah-A}ufw-%Wl}S&0dH>Sb-1XcOHFQH%R<*;v%uTH$vK ztF}d!uI$2j4m|?G*kqeRF?uU0sbRR`ine!hjZ(ZL~z--|66}r~3>DyRR?7_W|Tn`E%B2#=Y%Lza5M@@>9w)O+WZg zry@TAblqj6CyuE>*--rGcgFi!8skpyM!|P33`JJ~C4*=rxVy+UV{DCC*UiyQV>fRH z1lfIQ(7O=rdv!gW^^eL4?qiZ@V|lT9`x@`xN?t@H_+klmM0jj0sPyER0XaRg7mE2Q z4Xgzt<<17Nn~5ngYr@5cpcc20+CDs*VwwR{&*XDep?CFnc?%`c?JkWH(XNG(cX#2< zC~9DA(ir$D9lY^AgcdIQVV@2WoZS66(eh_uIGDrZ2j~($fxdi0Vf4@E2XRTgZRN$X z*AGd3pr(ME^<{9bubcyyUz91`nh3Y@vI)Kt%Nxfk3M7m&;i8)B^6kWO%p_?(xlA-) zFD$knz3nb)$QK6W!(%nXuy&#rR#{+y#%|P@C`=pvZ*>8pwt|8h^E;-dMIiqr4-LHU zHY11umPs%I6;Y|}ceA}01{0@9*SGZ(T|!|zvp6=tm2ri@mmNT7a+~jg+3|+|S+MmO z`qL@+)!Y-%e#^ltxCCdO0xr=-&e2LwK42yfQT4(Icvu2tQAEGWodjYG3q(-+qZ=@> zGWz%ad&$)yyhxJxwGol_A0gly6|C#QN*cwTUvJ&My*leL0yuFJzT`8h;HT^ZhRt_^ z{YubzqJl+Ct4lp9%t#TlijSs7Y^In0MtwkFuLDnSqrj|?;qS2lwr)EES?7*1pI{tm zHT8H_5ePA%xCCL9e`v_}OhF(1z_flR0WU;@6{wJDPoQSnNaF!8SOKSRwjaTJjkFyP zm3N5-t4fdR>!dMFng26!4p@XH%ai8c|2F&oYrQS9VeH>?lV*rf%G?ty@+z&}{`q1P zh{YVczB*rN*@cZdh@P2B9B?`iT^Vn^-@h9I)>;XoO9vk^P-Nu^Ru^b~@a^tqEdUmb zlmJVCzB$MBS&>aVdS!NQivAZQM3U~2!U&B5DDfli#J72%r6$Z>l=fFuDz+M_|1}o> z5TYXoLO7g&v}WP`Wv0;^wlP0d7f2)i{F^F}%?dz(z`KMW5R74mJ996-#XHvAjV=O} z!!9$u4w3!6i6al-B5$iY=esoQT2!J03^_VKfitztW6VR>l}(W=&!86Qo25kgK4o>V z#O}pX-0M68yX4DYcM`?0&E9vAivpch{AY2Y=m3Evx`Z`{kc?)~+Q<9pNC z`={g+u9)1rFRIWCecZe^URyux+s!t%ntDvoMO~jB5h9tPNEW><5`knfX38NN(X!IP zyrmKrvC!H1v*umhz5`a@Awu_^PTgZJI41H+;M+8!?TISTJL(_ zIiH$ffUKzuhgC2N%8jVsLmy(XF#->uFdKn1q4?N|uX`mDEcw4jq~jtueYl-hLpV{= z|EFTGL17g)@kwHQVAHP=)i##>aK{iV9`^A#SNjviJhOC9Zn}Ds%IttUIkapry9ULm zAQX^*N1HfDmLY%xHQX5GAd6E+EG#T1NRd1E>$=SZY*aatPJ(LP7T~9j!mhxp$9w?o ztb@t02!v2A+vcz?7f=cKpM-+FxLsc(K{+QET_q zHQd>cvHZW*bck5GnDHo5!1-i*dA(gY>c#fKQ@RR-n`Tbym&Uy3_Xn!;;Tc{oRNs z@@BY1F=2AUfiI@qeUB9Q5x1t_%e;7k_O)ZRi?t|20jvaxY{y1iUbhH*zAh;2&9SnX zj(aP?_5cFnkMglR6T8weYo7q#tgz~Jfk+=y@KobwJcqY zh*J`}bK#!eX^chpy)c)TV>avK`|g5WTQhXyPHJb7eOqUhQ^?NI5*sVVc(;f48~kjZ z+i{#`;mA3vHjw=*xD0CIPFR>^&f<0)qqTX`FUd3S4x>ww$a}zBaq;uj(%SJtZlL+0Gp)Z#r9cbtY;H;_ObPw zn+|oznv)G)A<8>?7Tt+H2e+0NiJ9%8h2TyiRYinp9Nj#mCnR8@ z=DtuV9@4xUa)LHFoohZa6`ya5lOo+gRgjA~PnHOsje9(P#D}#0agY{k`yE4i z;dxXZP}@$g?YiDpD~Fh@bx>3~hPH%xG$E_s*~IZXS9yMP+}V4fUFBB5qLEKM+$=$& zYf?J?n~|g&SsOLweO~RFLp3u0Q`vW~fvCqhr|WsCt?oKd`?!*)s-B3!FhC;)^}LQg zZY>h@p^$#A$XqG!*3;Uo(RVl~f-+XfBmBgJxZwHZpE~6_9~2ic>g6@*)#qm-g{N(9 zrsT)J`#?ksYB5qChNXu2sWqmX zq!Z$V%C?BDUR1qs_m>4D;>0Y#AKbDme#ac61;&B?45KrEN3X?uyl$!5V2ppTwV*@4%=#>75A4d^sY`Z6Nn zPRsVx`K#D2AU^VC`+er#lZWL1yk}_q`s9)e6$sN@gsleKr=LMbWj|FJ!YdP|k=^AEN|td!B(gh#pY-xQo!v)2Ki^Negy-3bGCpP} zdvl@^62L2fzGEc6Y?p8rw>o9z1Ok)f3`W0Skgb3ay1EupHk3j|e-+ps_khVV8quBEo&G5sNWUqRhv3AK zhu=K-C#JEfk7|U6lB`8p`m={D{O&CYQw`H>2@f2ec4wxug+dI|wHlm`IDsKz7Wbd} z+_UhW6YmF#oYr@QUhAA;%RQ5{R8n!(bPnFt9w@qZ+*VWTRi*ApqjspGgvi!n;b5Mz zzoDm|!rXTIrLb0w!<-}nLgCz0c`42uGuZ-Ws4n-DrXjiPCTY{B-qA^wsTFU97sa2c zf1f{7<6?XxsYc+FS6M~(SH*0@LP>}V68Pm5P1N}3AK3VsyxT-ck_?M z6cQ={9+LWOQH?wp%fz;h4tfT*4&LJM09m~?Iwgbk)#B6R14+crXzql~Orw-sSAq!J z;duJ9v!9F!IG+MV7#+7n^g%sszfqIH^R~Wp$_r7kdA#{7IXCsp^+7IDy&Ly`Pe^+(Dy8^zlw8nn$0E8y(WE7 z`CWlm_uF^+{g&$@`XdS7ys5tT9R+mByFic9*4->ju2CF*zS+N-ONAU6sy*0BX>hu? zSBF6b(G66e7Tco{370jM zg&`I$@tLyzvx>(<#~@CZqMmz49HQa>pv#r8J`+Z*|~1{-Ccjl;@d!>am0kTmk4q<1;Lu( z*~EkD6-GonAL z&p!BUHixYl6!ax1hvz^)mM27Dm9zHEtONANtR^_lT2odqCYUuNblmEXI*(A{^MI`V~O!h04;61&Q$bEi3EcCsyNwq9-O4>6@&;+F#pO=ylxaBH?LXM(yd2& zw?PB({-E@CC$+up=x&&6wP%s#lVpSz_U?hij9R_=kRu56JthzWS8cV-`qKmdSf?2L z-rvc$6oKMs=giyU98dSV`b4^R;kn-seH53&#BU_UD*x_C>R$&KN&^)$R9Vx#3r_E1 z$9XP5s{z#M#lB8b$+obwBoaSY@6#|2uWwEN8!}#=L*K7#52(D#XsgO&ZF^G-4o(M= z`XHL07=L+bLHI%*2{LA)OVWwt{7>Q;-U%e08CSSY z*m3t)cSZ;jjt~l4_Wzhh$1Co2T^s)C6tVH)ZloXkaSNH9`zBt0ai{*$cv9n8t!xFG zhOV`-PzmHA_)HpCdu_669yC~0+XF0%#07hFErOdskMVdX>q+*YRt^o_TP^%z6NYQ3J5s06OYO8dT^8Q#GNA9%*@XP}J|9M02nzY&rmdsuRfMR_7U{LY`2 zQUX{Gt;?%A`h+(a`f*tpL5_k+s$p`@HnTI1%z9D(=}x|>^Ep-s)*CO2p5$lZrBz!b z-!$~!>^95jC#viQd{_Q<$uH;dqwj%wcXiw3PVHaOOuAy=cDYudRB9 zeuL-$k_frVL|mYe)^j^&pQIT-g}$NeNh0s@?};?|v9gPt$5O%VXjV>EnhiuU`S!3) zi!nbfb7rk)xJ67qDrE|>Y?q{}h?$T#XU_8pHlA)KNFP2Y+(ds5?OEH&z5OlT?G4#l z&PC*Bculzn3Lj@vDfv=}%bURYQmgJo;vLWq^ohj!cAYjZQ)+#`iji~NAVwt-qcE|5 zABes9+4eS`^qA?0NQwtODrLt$F9*qSb?!mOcuc|7eaJ)8sDDBxd7hrCP1RpPp}X6T zfLtj2pn(OE(-gU~+=1TlN>>wXYd7y1O0)_W}^Qo)4cPT&%NQ0fNhzrq3`y`LN zhzCaJ)lJORV^1jErhN=V{&H)lZrAQK!UB z_L~0H;A0M|9M7U$Eimmm(1ENKFvAD^4-3Ni8x!=TJ^?& z3Phr*GZn}+_;4Q!k8Pbb9?&2*6?cEMYN;pqUBRZr;|V=;VAB~|oq3zyR-zR!z`sU< zTeAzd;n0pn$zWiL9_jh?#oj>kq=V_zF$u+GVfDSVCp~!XmV9Y{?bAZ2=a>0BEIqS3 zQ%y#wm!`0LGT*fvn)3z^LkZ!%mu(jaNJ#c1=?b9d zyJG9FdqpKcIY6~GydkRtc_JpAWuva%9-2-|5h_hgjQx-lrt^qz>QMsBbi?uGq7;Sd1eoBknz3?7dz24e-OXN|Y$>h2sQq4v@QRveK~Ein`(9|L6pPPs zLd|%F#KXR`Ie{X*?7GZ%!Z!p}8xG_Gw2h1=jE7mBy5h!$Pa>|~dD=E}Hn-`Nld`I{ zQhEsMbM<8i$<);2Q*e;9kZ=7ENjoRKhDXF8XbG;V@Y*|zR%K+_TE+uRh^Va^!YhMY z)s_WUEw>MrYBN2G9=?98rmZpHzK$1CWII7(%Vp~Ay{*?sCmo33nmnGtj~uJZB=#sC zKaog~^`vydE7IE&nTT-PC_kx8wyIvPiy=Ar@fe~N8gpQpsl1X;emLvSY&4T{3yxo6)HC?_ z=#aD68Bsc!^0vg%rTuB9ip6GuW?;oeT?M*GAyt~uhJW;*GT<&s@P5S9K5}IlyR_zs zM4(#OLlAU$J6$rrGhGEzRz3ky;*!VLHBef^ON+!$LHoSz*$WbMbF0TH zVB~vFIN7*(Od#gR+RU8kT^xQy&+DUlDQe~U3<+)nr^{N|XWgI9aunM1M_LDqe zRRGD{)+x9nXEW=Jt+(im9dAzh^$_KF+aa7Fi~iUp17Uay!ek&ZxGos#1WHj`{5!5m ze5Z=L<_%}IyLP;T>D5}o;6vH$;XCnQSl$ecZ_Mh_b%MnBwrX$vobk1WetM0Fp%=5k zjLC|;Zh2CYe}X+c!fdmZ!jVwHzdjEa+Ie%9E3#nM@}Jb8`+%z7*9>Wq3s9R#Nk3`o z@6BYJ0_f7&Q1t+V;e-GUA~@aVb;C%r%w>F~ev90vh9-VZ+fm4m3lM1*0HXE31 z@2U{?h63@9d6b$tA=2c^;1@5LkR>$uqxKqY=y}hQR7CdnX4GKqCPYLrEfe6|Q777O zzD6ab?)qtG6Q0c^vKQxPsve_YFaBq|iW6r8$SJn<(Fx-1(@9kJuB$aY-TATqU$N`A zQE^{&cdm@D zTMTW~8H*L=qG@Gsj8>Q__#qDUzZ+l4%Dzl+{<0w_I_4W&VT2%ua9OK-k{Vt4YI*Ps z9O>@8GK}ssp6Aa+!P;%;ep^Z{#MfVozwv;{68{UxzWA4WGnO1&HoZL9EemR=#xJWC zA7}09)Ayuk_FJY6a@K-=c*lrp)K2YE)}ZQvJF2iK^gv2wnDB(ystGgx#L5PM*8GDd z?)&*D@fBRI+F!Qp#{J0) z7M7ms)rSXV$07{=2SnFgk6z$qb<(&~)1O!E8YjfRTc5g`L{(4$0qg*-!1_GdFD(~a zD@yiCtvEkJN3k&Gm|Ezk^W0Ys6Hk`A%fevoY zO(6~a+(~Z{DK^Nu{p4(xSTv8 z={P?-sI}!UJiqg5rAGUFd?ERhS#im+gud5i1%j2$erVflgv_pL#`AtWDWw0a`3BYc zWbXwLQ;6vFyYGQ49{m8@GP?8UIc+RFL=YsSpCEs??dc)R1{*5Fzj~Yl0!cxxxTE5v z6V|fo+B#6R^YNoO3(wy} z=zDC}Ypqgb?n(v2l{oPAOX=tV&tGj8wvRN^Wd{yPaUxSYDj3s>JNM>Gf_{F> zVx_EZunRWCnlR^EJ}Q=Gz88pIA2OVDAQ=(Yy?4l>riqz7vz0q&gzFUCC>%CV%9mPv^eElX9{FZb4p1#lugm3r_* zRB$N9{AE=$tj{+h9_+-!x<(mtAkcwoyw&bIV zbyw!C=YPDj9Ql6WU~zejSnLwEm>W=>dzpua<2TdR&!iaB0Kw&nLw&c7@lIO&OKWN^C>1rHO;LI zEx!aA8-Q=P$KylkG-=5NUbpu`bHYc0%;+=q;6zcBYhKrwAfR5UhTWlQ6AJry-85mL?YslWt7J*Vm>T%bv z6t7*;vabMcw^E&Vn`jy};N+HF-?EfQL7YO^&HJ=Q9ChIl!Mqw_K_V9ga5nGDp~)o( z(=~h<4R3sodbk$|h6V7c4JQPS`RKGU0~xoT;slqpG7i#xVs;I=?*SW3ao!;NL|Bt3 zF@ga+WNFjo4}x%B4_q2GxK#z=lKuEK`G-9X2ALiWn9ueS_w5VguZ!c}CiMHIf{Br6 zt|Df=UhHOjYguuZxrsZ)X-+M}F@Q4t6IW^NxtEPjc#SAwv%?LJR~AMZvFpJh`8GP^ z{F0R|$9i&AbzDw;X&t83`Wix~zhxyTy^e_IJ$?$3d96#He_-*bil4sw%-68NCNKCv zHu9H8zJe$Wb!4m2xOH$@i3vgYAxc)`86ozlts76P3I1R-Xh?XIHeV&4Hf|Ujp*K<0 zTD&!=nlnriqd^mYg@J#O_QGXpjU)1TGBl0Q;1TDbspFiNSsF1|Es3|Z3dm)~FZ0L` zV7I&YF4Qe*+pJ=t-}Umn$kuUp`G@}4EN;}m%0)XG$dbq!8#dekO}#5yeE}j5R9IlO6o>Fcu@nNDSXxZbC@0aTPam7+g?ffgEDn`CU0~>+&C}8poJQt`daV zKGAffVi*UZ#{Eb-$B5SUN7OgEBo~XBcC1WlBZ)MJ;*VHNaDy)pP@{<_Cen&FXg%@B zeKj;jNe*&Y9S?R2wL0zV)yM4e(1J8D(8@gp5ha&cK*m>DBD&4t*>p%OFl`IV|2;i_HLYDt!Kk5^nhnIFA zOnRt$sDzD^anHQjVW%ls5EDQNrwXI!zud2Xw63m?RLs%X&Nx1tQ#5jvRINE(ai?m3 zB;TQ)qxBW0i@aB1X06_RTBwU(QbG`s0@-pyds;TD5QO>b$u~Kf8=XyeC8!6wBp)+J zHAe$UHORRVc(5b><=3TJ`6e=Ws7>++O<+HkKmz!fsI3=%w5ItT;PnIuA)zqB&dZX8Q>OqHlsZ=KkM z@DFJy8CN;c+QV=!&@P3uOH^&Q#IAxQO~%Z@=LHqWpE5y&l_?%PYuWilY5>Rtv^kD{ z|DhhJ7skUlkFk3(1#3NTL!c;?UyF+9W5oG*Qp@RgO`EY|=AL^G`+WS#A$EhI6TI&^ zU}7gBow`;9tZP36My0x}AFEeyHDIqo#Ad!9T_;p77<&*2sU8QS!A!SpBg>>3XB!Uwh=AKk119+%=Yb-6+=^A_sM}nF}=Z z13nJss(zNGnt3*!Ti@g@JEpv^NXQ)42pyh7i{B4yzHw(813S#PQNbp@wN2 zv13!|#NVL6apCbm-V}0GpNexCq>xIuH@l~JH}hk?&yl5>+NF9L*IzgLyqcIglFMDfJ{@}IA>-UlR*Aq1%gnJy_Pj*WqYVLq7dqd<@y4V{-EVOi#I!BlH{IjFH zRRtzb*51>r<@0jL1G*L7e`TP z+?9WAVu{o=a7?^)XO2K<$qA^FKKWj>ec{V$vLU75{I{^Xx_vPU4Oq|TJT`6C>$ji| z%>+I^0}e~`otgDj2<=n@$1l4T0evqF3n}7pPSlA>k=1~UX$;y*4Au8W%7Y1m=FaDX zIdN)b4CYMS9M5;O68#MU*aIS?Z9D;}vf=O5Z-9qdRQc1-7_@7k}knY_P9AY8B?G zD)oW?aq|YYo8m`n+R?-5#{PlPto(#J5BsbzgmTG(JpA4-e1+A{S+I1=26KfGL${qf zxQEPJ`EaZ9!4aRXnpLx#%Ndt%WW$PaFqp$fbWN|B=)qmBqI8;ro}$;N0NLa9(s>5f z=|ilAX01(e4CZ{k!)d<(aMi6=3iDkIB7FS*m+<3sG=2gGGl(UlMG)F@?hU;z;ZRhlrI8P*f&Qx+7TF9y4K}oIu|os)3TN3m&r`=!?24OB5}Ka=+$Q ztTH{vMp%G;GA`8Q3q(t-!c<2t(s^2mYg`Uu90dby;GG))wH?~nSf0MVGuX90bHNkf z*e2yl&r=XSGBI8Zd9^;~nm(lGA#XRv(c08l3)0MVNVQV-$@YCEMur3&B@0*^6>x%2 zhMFZ@P{&ucK<@-oPtwpUwOzq8TB^5G5HFkwn^dy`r2{3ip%AzQua7<-)HKUL9!$;A zkU78lc>r-=65CdN^^BN(K^*Krr@<4b&H0aOb0qJmS3s)EoU@~To>v}x( zIb?msj8P}spP2~YJ{r?5GS3A=ikY-Peqf>R{xA6xD1kP2eORS|+KkHcZN@(B-Zixn56bc$(t)}mS5R2y@ zS$IXSLnH@%ROX|=aDp*JsxRt^8B1otqZt2i$><_2);FP&4|kO%Jswl8TD*oaR=F^G za#7+Uro~Wh4nK&Usy)0Ism-7UR6<1uh=SU+L#_TE)tEr;#6>2nO9&ujI_Il#Uy{f7RZfsVYGGA`=5Fi&B|0 zje#B}mK`z0qs$IVLErOrv1i4A{m2Dl7wJqtI%%;iYx!+j+#f4||Jlk3+l0}MqDH&v zXy*?5-*6CJrO{Zzepju~5pWh*?eJ_$Y5b8U2xY^&^=8jNUyusigpabKbwkMMdR2iP zD>;eG(fd0=r;>Ep)E1CI_ujglVEt0K*8&dtgC|yj>f%ii3$&z$@@Wx?1Obm2F;*wi zmFDW0M#d1L+UJlM^0~|$G5<4?*8a*hxG#M(>{M*T1g|}Vk}SUcYx|>C#dw>ahV}E_ zuO*K4+ZoL?e4~}(F*n!@*Yj74B*=;bBJ&|vGm#-P|t*kUIh4QA^Eg@ zW44v56ArBudS^t83Qxh@$T5VPOgmXx98NM=Y9|taG?WnC7Zq zx~3`sc@}v_LtI`>KU_PWA$?#FVbtVTX96g*9@aB42whGZvghSkI{o*)sDi>;u&x*0 zi&$;OQ{#S2{>46PmOdNrv`7XymB4pt-XD7a)21Qhr6{Y>jo4|Fz8UA2u{`tk+VA^` z2Yu2N{;FK>-b-~8q<#XqWKZXJ-ZyVaS_x?kQuV!`VxPYXHgq&1YB6zq?4J+Q8}1viEW;B|H0_!!TztAZN2pd#wf+DkeB9n= zr#d~;May8~cAwt`VGZYKJ7jYXGzCa$<6}gTFaEkS-2&RL^yxCp@6HGw`JhG(`wu@UO_?TcebPs=R%(@K}PpuKNAhDgA``aKUMEDfGN zT{tZbrXJP%rZ5py)qs&DggH(4pc3bcv99^g_k4pG5Y|)vXDkW*?r82eS&c_TT0VxJ zD%Ho{9cOhxl&M!Fr+#P|49R>}m0MncjaM+NC}#yvzDe|-y5to`)2j=ZRyfq_HcA`) z9^WRlP80oODcB4tws%a6t);>(%o_q${f{Ix4BfGbbO=P04KQUt23-Njtj-6etp`JM zUd?d~t62!iV!S~d^I+w}>4lpyb8fda8%T2^4AgLzWWSe`g8G}Fs}V*rXUXSna;m<5 zU1K{TWZGF!bZPXZT+ACv&DE2h z$*Z)i$|ad>QkG`;7~Jt9mB$f2g}n-YVQ=mO(|&sWA4>ok@^_iDV*@;XtW zmD{&*d_&AGn+(|2rqUVSxb1fPPtAp@RiFC6T3~w8{#}siy6}^|2ZF7^kBidk_a2Aq z4-4Jbw$}OPHF)CoaFoj3pC8%@4>ZqCQoBPvWKwCUjN0#*d_9Ne8}1_grh3J2)Mjo} zmxehA&P_NeK)F!h`4dEdLTCh`C2Rf4ZMUSP_K$VHRS-mZF?=m~&CP~s)%GdJ(PoZF zNz>CXwxWVzK+OLJsf<58ZGpkYB3W2|T5`l1catsE=*@C1^ZpyD*B3W56v?vWVtH7c z@WwTE3_w(AF>T0o|*zq=9>iK_&yMexZ)hI{U|G* zwP7?}=@ClAz?i&-vRe$vT%)ZwDS;v7dPoPn@bD+z)|$Ti*3iH8RQwuzz&aupb4r`- zhmN=H{4juDEb*wYBb4fe$rpD}6hBAXJEv|4!6^CU3I;hXtC|tnrTFW2pQ>y+yT7`R zt_S0pU4*%M!U)|dBsG)=q|#s6EZ#G%Uy9cr*=brU6~48SAF-(G(*UdA>_sWlz zd^@lRaQ=7VJ;U$w-3_+<|LH`eNue@HrD^ZP(OR{!VP$!GFW+Ixl4w#-nDIy<>(iBs7xtRwpV;rS_pNNuszg zK@w@!?}V>5KT>;+)bqSd^cGtruNq?$2E%58`!6`eIeA!s$h1FK2d2$T?z2Rj5WZP= z&hJoo3nPesuAZHocuCxL{5uQaMg5j94qGd&q5lAnzSm-O`6}q;KbYJVc}*~=vPZz= zIpw+D4@n4St9W*`kPVhSeX$J2kS@kg9nZmRy9}AgeSG@|yS}BCg6O%Tl@WVI_%W9& zm$zd6dl#<4T`=ixn=N9r$T9cMp}>95twqK=8zsLgl|!=^`Tpd_)9ND4ZGz*Qx4kVN zUfG#Z`FttmO%-)E$~i>JVUoY}kz}kFlBbnyCdsn{3da&G8?fYQOS11OC70bbg(gjs z+5HDi;AaH2lxT_i5V)b9qD&3BX|A@Bq~?9&)sj21jmHp1wkqQ%tS2-PNy?p>1x8Ab zQZjDKwRM(|SorI0`^+%i&i1gvW^TX9Ps@yW5;hku&?#8@ASxJrjJ!;<(8JNj%EWHd zZ>dVm@3nNi?6{3hx?#r^0=xfKUNWeH;j-IEe9`8NRHkD99)|VezPD>eYsp!r+FALd zoS~QjZ?20%a(0G}ofjokI{dCFN$ijCva_J+4aN*uXf?(#$?zJY@)JmfUw&Q^BW5U~ z&H~`#O*v);LpGS0RigCVgYW9^8wOx9a^=#p)t-jj@B3gyZo@JQ841u0hprhszZQ0D z|M^Gm+=otUK|JMcZQR-Eeh6uq)c`M2K1YAvj0=U60HMg{^T9K&+_cT6P||%iD<%s= z*^vXVk_q1FvBKOkmvxvq{~V<7S^dzE-TomE4|7{gz58^95k-v{R+-1rOujY#jkhsM zbl$Ir_?BQ;_NTw&;jA5P3XFD(WO%1d8hrr?IRfrjF>VBw8doqW|A9(;{;sUJBIt@; zoTdrBs`lJzBI*bX{i^G3Ut2qP*i4H!JCk)Dn)HE_;bUrKKBQ;p5Tz=`kI)6-{9qbn zX`#!wosB9ZP2+^BW|Q7E^4xoiLYkoaoBEQH3-TKE;U(oJy;uyEdxB(suR>q#;!+Aq z*WXjQ9m$oQP9ztNk`4E;_LFq^n13d~OKSwcnEp+E^7^vX_N!3G3YYb?!CYM{v!nyw zu>RSHvbZ+I81d0yfn{<#lAwej10|S95`Q_?_@<#e#9jGNrw^xL_?kT&B}pZ4?#OJ7 zNJxZhw(e~c5l}2A`Hic2>dDhCVx{XMvRW{IYY0Qn^3AS7@-b zBK+FPQx5}dw*eQ)glK^mrMeBIvXs&|>!z@6RlQ8y^S^8Vjut%zVwQ6_FKf|KznpEt zoYYIPe-B|J9n~ya`8V)N<_RwPj6mGBZwc;V3M$D^%KWwh1A$tsy&>*4blNZo<|}Ow z(<+4tA?$YVI-AiCQppXpE1YiOd0<-grph$ANS3@NbnrTL@Qar=4^&o!vPe5n{6re- zQgkaPjrffNu~g8`=baYSVw85gb_mPy013pog_JTn)92Q?Wh~6BP>j6)K6exNv*oW= zSKnT@X~ui%`r(HrQM7gBOzKLKK2H{&i?t$8md;9_jD}5DK{?j7@&eNit%36AW^Auz zHL73TVcht1ci3_sTsk}%q9$N`%#x4fm6&$~rG%C8u-arb3@CquYWsEkoB%7+M@@Iu zEA#Mu3B2@tbgSum8TNJs2;-bq>_WvGAf&}4bVR)LryV)nB)4X{k0BM8JRnz z6vZyah3P^t%l%K4^A-on;Gc=5Bwqv4ip%%O$wOb*F?sE3lK|bLs3Gpxph|BG2#vX3!h2WcPA?w>c*hnojud3dMW^6oJajj=nEBHB z2~3_hZSHLZX8oSM9?Y*|IPdG& zmwc!(!Qy}VdtT^YMMhHyR7=^?_v0I428m;eUh^6K_QT9lnVL8Yj5!@sTy>>t<@B;} zW3wZutLXUtEJFQc73pNyLT)26QkA2tV8Lqmk>4oH9MYk29nLl??FOK$os*@G%;5ZS zGw3`ikkYcfP(4pC#|ybP^!fYc5&(?0+Y8pkS+uy+qjX)O%dg1O5B|C;<8?p~9~N?> zi`^7vMcMGgsJ>Oh`sZnjUhWNs%jECr=&dSP=qPS}oQ{om&vM@Y*OH+m>xJjZ=BnyC z?#)qEECT7PKGY2{a`8uT#2(EL{V;vfh)5Ox{gZ;~C;=QgFsLtlKyW9Qo3)jMDf_X- z^WLXgC+_(*lgV*q*8TI>y{9burc~T7h8McOiGPM+LS&euvLdHiY^gf;Q?uQA=I2ey zu)F_4OQ_L2P!zM@l`iPjei&T-9+2Pgj$m+d6s=Fon#I4k@%q2+Ilhk&APF1wzGmye*;EIsgc3YTG%$pV9?NTlWN z@_nrMNbKY{lVu*ahg8%+O`2YHB0tM2L87?aR_gMJn zQ%r!;WALrz#Q(=_c68^cjq7}eu$n!R|C;U^=QKS9+Dd9u77@FbFLI2~k-v8Gg;T;T& z>&$9$6wll5r)2{ErVM8V;i;Nh_FAbfe9@{UYvpuG662b>VYitz-ttRmdWN|ILovi`JU$KCJfcWX7NYHzt+!N)DG9@$NU_% zSzN+L*(h-?K2!xGE@v^2UsGC;q^+n60m*v9-x6}4K>XNluCY*tR&j{sXi)|Uh5u^J z$*9NB1BbQ{44iV5_(KK8Fv;VTetBz>BzDufGW7`|pmMra@Ai44{==HZU;c_hmgMC3 z4>*q^ZgKLEjFdKdpRDsbL)|n`dwxb%EZl9W5X03II+U(tT!W5u*@{t>2IKA`b}6Rp4LlJGZ7{j!OMSU-|5U&Lc+e zWwZdS#3O%EC=UC%c)~OI*IS;; z0R5~H@ZyI86m;d&f|N$VU=PnGu3VKsBIK&9jz4FX5)YNsxc@m&(~9XU(48uPt;l`q zwuk&1f!sC2tAd`#T=X#(GH?^&HJ`$L_R+Qp$jy(H?7&z@ggr>dmsu^0Pl30@Z8Js_gMzuLcCs%RjHnzZ~kIL z&Cka$*-!=c40#@n$`I~su~{h%f>Q7EGyaJsv7c2ZTW>;&ZN8s9MZ=;sgbhl&A9f9k zm;`@)y3Z5_2-T^<49+5q}r@D@v^GBY^7xEX=loB*z9p> z3b)FSQx%3?5DW;C+SGY4D{-!x^j#9D>Ut7r63@1Bsb8ul@AGc*pW}{D42}qbeyk@k z%z4?Fliufk{vuws%G=v0;vgr-eFDd2e9J922@@E?IGNwTz`@*QcdLldJ(Y!DOMk{{ z;0T`<=}=2h($0aJ|k>ksVS%ZCI zhOdt)l8V)f->i^*c{jZGDp1pn&l8bT`m*rV(ekT{e3#Zh3m_pTKytfI8>0zo!5s9( zOSH)fUmn!s)8hyNLzx3&Ai_D(Wk?L+xPARy(zEC2*jpUfcJYB=W|k^?+Y06N0Fa0o z@ZYp#f(d0smTyDugS_!>0oh69<};JPsm#0ehW!{ITuI33S z(^Z>8*v7;s-MMM9s)r|x5d-j${1FHT_$n- z#d`u9kNe0q(BZa8aa#{RQO(v+qIh9)cc-S_4)^jp#8LJVF>s#7Y)mwI6iS3H!cZ*7 z#W=>=As}1Lzlo9Ux=*|I14KXF+=@9njYO*#Q0Sc=bn7!Q<>ZEBCJ_#(L`2EfI zuqDPmuVRDgnAV-!dHS^{k4pXP`FqrI9OJq1;T6_CtZ9UJr`##Sz!#hP2EI$X03R!( zkPLObOogq^s+F`@IhUc=y2`aORa1h>x^ZebYt zUESNOJmC;BbWJP|TtI`0{OKVst46-)_X8m`=9hF^6CZZn0#U<`EWv}DmTf-8S>?U` zGS2JRV$$`JbF+ur@$O2?Bfgqw7~@)#(FhxIR=npv-_-H+NyvWPJ#ri3`h#ZxF~Nbe z;-o^KxCLFjs2o&FEti$+-#7uO^4ZyT%DYwpH6q)oj#3s|?8lZ^C7|$cB#oE5lgh8+ z7tGT+u)?e~=gsPz4tif1LxXr;a`qZLN#Z{vpSbBgD(|! z0Q@P5Q*&D`{BT$?j$buT={GOkl@Y7aqF`R>_f8wzK;I|GJ^ij&<`x~VjwPHcu7(Bd1)odQD<)pM?xfT&-^r6A4t{JqFsNW#^>cC z&rst%jy*?PTpiJyE*@d3d966$UABb5Y-PrvH6n}rb}VSAywKVfH2%)dH$JUg zHnn=(h-}#Sq;IQN^`|<(fa1VcoS3q}!2=4Xb}0tUUaapSxB8fK%NnQyM$S-SJ$L)9 z8&*yI@kp;GQfG5KsZS(ox$L(B)Y790cO+$tu;+LNTaYi`XA{^PtB5nZ< zD!WA5eT3WTw~Ff6LS2-njpM*vaWzTN1HO@_?gwbMzTO>A0;(>8%R`eA& z`>R_w<@_Y4$^rcdeRtQ)X)4Dr>>F{#};VHg|f=TjiGcZ(M4sI=V- z*d9xZ(PhK$*b5T=a!t$_uOK11w3xwmZMb03EAzbhk;Z+E*NZuj&#cFtD8Jf&S1M&` zqMtEZRAbJQ!KT6TJl7%oz$obp1~l5>)U#71wZ&6Sri22 zgGN*_j69mt!e?sQA9GHAf4>rUW#Qn>PST^m7uu2m1Zw7P%><;qyuDV*eobD)206ds zGToGB#&Jl+w724Y%BIk35AxzzCwD+(Flq6dvN4r}y=W@0?piHpf%#i6pM|%nk;i-M zV_l6J8)BC{f6_<&_{xWd{vp6@vIXsh@k8|aDdNv}{||d_9TjD_|NYY?-6b6=9TL(F z5+*RD3?Lyb(t^a$(n=~V3Jx%I*ARk$^Z-L6h;%3&K6~zSpYJ*6dw%Qp_w&cI7Prf_ zZh?L6>$>*r{rSA!?{}DJQwmeMv%1Ch*>V8aWDtyQ$QOXhTU&!Zgn>eQGu~E$LHp0IfW-a2duIZLRem8I9)?OO0TvWLzDs~U>G$hmCO|x`Vb@?!DFY!o^?t;H)%)B{8(G>A2&z<`0! zgLHic9R{ezl>-A2eKjw~NbMBbboR^Q)7g5DjqeG^z9sn4cp0=FlZ3#drXu3^HBF9` zsc#ww?O30nodhJ80-=WmWj7_N1$cGYT=Uz_$+{Q|O;*6kV_dx{)tq^3kt5}v$mmXr zQ`u?4tp{9R%wHUCh#da7*gL`43HzkiOX8GcGEAU16|6R5H6 zqpq5~wag%iyz}%cZ35mj&rln|4H?B%^3ZY8<>0F&oOwM<1IactI`2&bQm?eDs zD6-!#ElsEXV>Ob3zOBu@H!Q_z4^(rFoJ6Wpd*3|YJ5Q%j_7d*urKfWV7l0xjF;7|U9@lA2Z ztqbfxZ{oG$9vwX#`#2;zW2%#B8^2F!^adA6T6uG~*6A>4$akS0hwS!1<7!jn0!xq& z*G?DH87mEys`I{Zq|`KDA;e%bR|U6ERpIPs0s8S72E72KX{mnI6+XT~HUJ&C=?s8| zj+)QJYi~M`d_r6f#^ z2cyh5PF}+b`w487cKAvcoXDne=U=-q;+i4aUOD)%h>LccL1IUbDxY*6=} z>#TF-7qm{g;tcZ}2$55Dqt3~kk92fnD!m5{FZ|~&3Ei#q<%^BWc3ibL4koi9<>O-0 z;LJz&6gkfBgbcsmgvV=%WOkB!hMKj(rcC8avLEHU&9PMWV_bNshb-keq?5gTO5J_A zOQ)eWznko^CZZSR5|&Lnm$A0sZ}sDvQY7ieO$H2`(=d#0 zUck34s=cwxEfB;%lhxz||4Db)Dg0O%=UpviXwDyD(fGoMqm?o-NU&)yOH@;)_g3mk zR6T4WNU46sbhLM*w#-AwmxnyzuYwCGRT{Cx2`YWbC1>AT_J7aSyspVzia9e*ntR4^ zeij{zn_!hNVsruhRg3iRoTQp62OL3Rj!nSfd5N;P*r%WEF`C^$J(%wR7?F(I=~lR4 zxlt4bN0tU2lFSA!CyP61W#IIT>6oQmJpLP674k5{3c(Oe`od0bH3P8vsaJG zn-89iZ(R_5&cV&kskUJ;Tco0GrEa)@$MP4cb7J+DmTz zh&ZGO+p_L{E?VKbcBdO_?(nV?O*!N?JXs7y)*1G>7gP?)Y9eR`p9ayO)U$Q65RG`| z=o?yXYxj})*GG=iyTUXd3aak4zS0Ol)$$s`CTi~foNdtUVm<{uHe-?1`XSnF0|PXT z`baC&&N;)k!Y%=kUSn|17(5d4X1V;fw0;RXCkLU+obYtY?ygS)Qv2iq3{Si!-frwP zc~*adq{Zlb_QgvTXE>B2Y!+T}LB$scregRv8-h@=no`_jnB)gu(WJoGX+bgR|9=J}D;KuOWMnG9D* z-_4`T7drXZCwE!tv8RqHLW8Oavx4?Lh7u6VioLShckrB=obA;_t7syX80Br|*sE#5 z=bgjL+*6$oJo!+3yEv9LxS4tm`p3*e>2!Q+q~_U+p4S zC%m`QtB2c&1r%G-aoy&dHA+?k@G>gXSWYz2ffAS(5S~7;KG$^5it6b60iVHaujuzS z;G+^c#bA7qy^E3%-fEPXj(H-j!wlgYk%j+zEi-N zeEcBB&edwmCP(aj*9aIq@`oGd5 zpV4@hhdeO2AmUH1$DPb|z8K}#h2+WN`q5}fx~GS?a9?8(b`BbPn5OBkU)#hcV>+EI zm1M&;RHzS`>tm}Uhr;OE@FA$E^^aMoU1l1mbgQZle!l{Kr`n}unIZHXODEgTqg#Hr zPbA)bdG52Ci9cf`I7Qt*|Lto~q>g0;+tP3HLb_xj7@YwTu=m_?lq!HOS-Uv>u&~}q zOS}A5MJzDCa8x%U;xgQlYtM5-5%ZoPd_X<3(dVdXzmVt`B&`~pan-UY=d4f_%3<~D zyKmEkD+q-~>`ay(YgF5Dj1J4dh-*J#k4zWWnRHnC2F1JN%Blqb23TgQsFw79 z8ETIb7H;w7svjgH_|EjuZIiY{n+T}d;JGC_{+K!Hn&4gcE_S}3!mTG<(bj@0qdJfW zi7u+Q>^h{9UQC*Ck?Dm)#RaLiFS!@6yK=yh!Cn@Z|BgS=Wt*qOMVAH&( z@QhaPi zLZB&sI_vX9&I`oLERE}t#9u#mhtWkXD59sXu`b+*a@x0Y{n4RxUYDSg_U%3Q@nzg< z;5(8OD+n>D*o{;(+I3HXn&s$QjD6(H-JaXTwS(ni#VoaxHJj6O08n&e(3M57-~LMu zlXwek)*gl1Vh<8Z45xp1t8zo}CCBI8mO4SeJb_saW10NrRwD2$fJt-yXp!EM8vnCH z7n4(us5^a!H%>m4GFz`M&j2pmC1N$1yD;HtFwD312xk(c5IuYnct~duh!3O6th8vl zy8X>VRQbjAq5&evm!DZs9BG%7XFdn*B61Fsi%E2$UQxiR^*A9bMx%fO07!~6GXV<$k_H;;eMpNIm61xR+oog+dYRQ zG!t238qnIpA|`6mI}X?{cFa4PC^kFAEGa#RKVQ1QG#f#&ocirw z;wj}(Oiz>y+A*})%boDMnNW>p|LVNK-f?W?t1r>#7GV-E;;fGFW0h%0(D{*4bKqL; z16NR=GiXVWqMI*PYVT}m(bztM7W_WnU9h2k=0wHfNb$+~d5mOG*t6Nl9(r>BF3C|h zgabt)wCo57ptu}iR!YY3do-1ANTC`%N5Pa~>Rb9mTpJ|KrO3^asJMYbc^x z*EzJYO;|NJ&p!qVD#>X1iK}X|DjXi)-wiyT8(O)x zo82yed9<|`fSbm)--&Gson)f880bD%FZyo&<_K5-&%MK7qEH1)}x<%3V>D0@m8wOnMbdwEFXeK;iScv9R4$ zYuFFS{?F@zccoI_)#H@j5T)O3ac#rCm;QC;iW7lin0dXFh2J4fbbb-D8uMle>}DAt zd$Z-ol~-W?c>KGlg2Znbe-qmV1z$t-xXe_6ySl0+SY!~Bn2&-<@4zc*c{XGW+F;m; zAdi?b=@9ljjvJ+_$|7JH>>_kSFGuW};L6a@yKA_4z#GK(+Y9qClQd;jZZdt|uT&k2 zx%NZZY#kkelr{U``L$_1yQHX9e;^_lzU2W&nU!u8NRDF51lZN@%;}~g8ZD*77CYNj z3HWai!CIcQwXzxPp!sGzd6zq5MUK)nSk%dZsHbXv>$SvlNsoGw&2e|~^5Qt3fDhd@ z3qj%SXF%GxNAM`fMawh^ke1IVS|&4ef6svan_7#G?j6f&v zw_RsXqR#Q75ojlz%U&P#PWZI|3y{c4F>-$Aqw1E5ZzYWG&?CpE*v1mbBeF3Il+OX# zE=PtWwV*O}#bLD2*vogq9Uin%5tzgC1aL^=N}CsBLq1E3TYxubU4Bi&SyU$3^`oNv z2ppExFHjYBRX)4(R5ZGKFXP0M>9W#K1J$f6e09Qg5G_(nK{%qt4)+w7&qKBstvI=s zpFup>A;AB7JPR+e-kpfh{;4%z{Q1dzpKXXPd-^2Dz6NEqdsg zn;hg(z+=aC3Nb>-oxV?h^EpT8>w5O5vt7AlVbW%a6xBH0v1!A2zeINn;$+e%de9Gj z)VwLBD5a^!8CEEnbefn;x#d*t4SXdl^5rI_H_d21-?HBkSi-LG~%)TH7AkSa(&to@tm^<8~ z>bliZwh-eDn-&f{TnUF4Hg7S-hI$&lb~5H?q+8C>kqEB$3cc08JcgiUa=v?%$KGX5 zX1FnTB1#i#&#}%IR6Chtr)+O!(hH?t@EDX33j`^-PZ79e2?16(#gEVBb&5x$t(hSf zuAbnMPlOJyOm^o8of0x?fqp>Or6Yi0m)t>XX_kbV0_rumoy4Y2IA1?^%!>s1Z%fzt zOx0#PJ>&aY!Tx{K$6n{xRrSLAd-D6R=`vD}l(%}E@S|3=1C8huzzR>vm*!p*E3x2q z?Q_HH6MQs*34mv}Ryt9uzVBqmG)>p;%uf{YzEyaY_crs`6OgeMebUMW2fNtTb6IYo zzdoZlz)dBgmj5A(1NQQdDbEMNQ!MklGsgGCw-aw*K9%6O|IN(;`}qJrwnz^V?F+jd zURO`2Si*)iAH37hup5;6N)?kI&%z6?_ouybK;>}Bn;>K4MGF+I+Oh6=Mh66iR#ucI zZT8W5sQ40+vpO6c=sGQc`uqD4wkF(R(9lu_^4`(0h#AK%&v6@|QI4ZWweDsc7eDMC z)3l++nOCrR3*>CoIK$*oR&j!oL}gvNkh$L~fG(E1VF`!Pozyvw_4F4Rm(Sa=TkmT2 z>VVGFVD@Wj{P}8V=zDl!CL&*vu~}`*mSX-_41({M9#C0Xzvn`&&TRXf6Ay_C%65fz z5AiTMI+s^^vq^QtfxAyJlgCzOWAZ0zjRM8Lv%);uL_H{*&7y?%0?Q+%H~hmFDHoMc zAO86T<88~JrA)k;by1TUPzZd#AVxJrqP^Pe=Q#n+sBU`jP9lMWPHL)|@6{F&f$=() zC%Ek}!oOyok_;S09Eil^U5Km#aMF2H^Ie>5jB&D`<-PC9?Y<6M!X?wE)mw1>Wh$pI z3i2r)zj`bZpZ-CMwJ@^C4F#WmK)9&=YSO|dbNZ#+t9NRfcq07}GZ=+uqE&*rZvbpP zTka&Zh|VqvA_wqspG?7A{fN_2p`+F`sAcH3z zxdqa?>BO9b_r+xVL4#!ikP$p}&#z;0M&1SGiMYfGa^3J{Iucn$c z*IG5@IhZX@olX@+tIS7C3f9&63(;Ca<&#V$*j< z2CvC#ccNPYqH$^LGb7?E`9gs&#!ZgO7_F1q}1Xy&dEOlcwlz>EuB+aei`_-i60&I z8si$`$XdH}_b~gF$0XVoHP0r~1uugZDw-3-JV^L8DVx_oyU*#{+$+#36Laahx81jxpAbxMSMpaq5KsOd)a(F4%tY@d(Cn2pRF}brms3i$Z+ju}#>$N#kr*!3ac5S>QK9bTdDENfGh|`14BAl#if8j@x_%S8MJ33IAHl74Gi zyQT2GRHo`#FM7)b{OH*k|7NS&$)TGj5Z%R;JfB^~o`OJ#e8gYi-$M+%dTYei5?tzv zEY6g`9>`!pTkN!<3s&V@*nEt$C&Tcmu~mYH3OPD#RFrc8Ku%&X9-1}jUmde&3$Lld9lA;>=i3XN|8q@h>@> z`MAtgCrWC0$!D(d5TFf4n}Oa+Bj2!$BS81&Qx8HM49S)bG$u?Y-aC_G=JH?EBW7YT zRO?`NtF7*Tqn0M&;Hr$g_*vBci>BZ??t-}}GW z&;R#r|AoW;=aeWHaoz_hiH5aX`$eX1Er+$B?~o&28pHG?2ULDd-v_upeKZ7|+>5~) z{h{R>#!mux{iogm@|tmI} zI7C73)3C5Nq(~9;1r32gu|dyxY3}2~zh(ACjqES?LV(Akuj%LcYDXFXj!#61V+8P^ zdFQ-?5rStT<~PE9fcgr=xPEIA?&bH3^OA>PlC3t9wAiF{t}c(CfXmzVO_mVGyq6pT zm{&2zb)ZdCIc2obOP~e>!`uej*uxpOw$&$3A z76Cv}KrSyDDR>DWunnL~z4b|-xbzsCkTo|qFeDgan+y)*3oL#*`QVeU)U|#o!u)M5 z@g~^!)S#N-3~PWSF9C;^(Z2>6?bR%kgy@N7{Eh+t;xKQeP5BRK7RC{30t9v9KN26P z4Fev`jkhVB+Vib7azQ;3BWZBWFDTFD?9=Svxtk{ZUVlva>*jcIR@~s@f1+1tf~r9# z2|HUoIUPvKZcH=J0~)^9#=Ljmh`#N?qmXO_rOB7l^JubMRakzq-80^&v)V~JNWrIx-A=N;Ju0jWdPFV!6$|Fdz9p_Sg=&W?a zI6)~Nq<=aMp0tR45O7FxMrIE30a+|2A*E(|vHtb?Eo#(C6IZ!5tsu4CQ1%CR7{~_J z0Wy?g7?8kA||pwbHl95jDx69;DLA|w|JA5l5a)L!uRy+ zn+IepQjY;OdMA%ObTNa1|Tv(Z0 z*KZ$$Wst@F;GK7L%~JsO$ZNVqqC^;-V(1uWuT!~@q}^-A7iqT)zshhWi^68M)!X#b z6T`H+W9)y5qd8;5p6*V3t^?#>c8U2Z>#wcgsP<|L)OJSH8T%RHZ{pDIKm{Fn7z7lL z_ubkq_D0S zdC+FIcW^FCKZ3aa^nyH6Q3{=QK#}2seFCkZ-_$@G_BTf!gruH{TCUU zG6Yn>tA~X0l{jW*Ae}KE!!(jBT_A`q00m`#IO{o7jIo%B-wCiR8K)}o_}-Cr?ptz3v(Wlye0~lkOR( zY`s-+3#X|n--NTCtcGJ_ z6W|1yy{ZPFW6JV1J@Kv1sKy*%*cCLL9x%0gFds1E%N88c_nK)8_q%R8u;a02cF?^* z*Z@9l{MD7G7lc;L2=s#TP~}f{yK#+<=V#DOJyw1vdsOo^?*Iy95hAG)Yyo5%w;#+F z^66*(BunNg3+Te@0C~cLE=}^3tc$NE42?B-I+ROwQdqSlh}zlS{-j~T(@?J!1~gES z=4(dBxoCOt1~z$_$kI?HaR!tPOF0u)0kUZK2e8Mr>CN}yUM#e1IirHryjbTxlu+o+ zYA4n%vV0X-q4o1}dA!t23&ZCIsm!+kdsY_Jw0IX6L<=FoULsgA%`v=0rVQK8+wE+t z%KS$kzqN*KX|ccmuE8$t+T6I7Z3iv{xP7#J0KmL-iYWDtPgi@Z)1)ia$;`fJ9x6{Q zAYls)eSQT{@vP`1hut*WGrC>;>YIAQ^d8^5(T*S2kL^TguG7#0d?!}>+3_GS&Tu&* z@1{=TAf74Vr>P)+rX_exbJ@bZ3%G|{^SV>N70KX{HR8)Ors&x2?Z~9 zZ9OeAKi*~;MtoO*T?StAjJQRvgs&Bu)s>M9JxjMzMZEfht>gHr^T3`F>;a0kz|(S= zF0K`aRV}hN9+M!XXh5MTBe`8zWB56BBUx8Cx}6=5f?a3e2puMo7y{VkAL8sVSqVKM z3soFdT>U5qwfjT_F3-26PmmlqU32trVpXcs>!zUql^yu7R7or_O0wTA+xr+0e|3Y? zNR0zi5a7tHq^K1e)j=p9tUAoc^jcfNoqY}PLXW`lv+L=@W$DFs4*RulZO8pa8oRk{&v}VqkG-ED5$K_cd|B&(ZL}Ps==~-6;^As0=5K3_vDkR=pywYyyo%k zc!vZ%z-CRfZp1!?|K7nFmh=bq>iq^O7GTALN$q74%3ZmsaK*4%cC`D;{y86N!ABU?Fax_0IpPjw$2pPd3Al1OBsK1m zFAC^uZ#-zRsaznpg%R`05YVWY09o!hia}$bEA_I;3>e+kGX4~L;D?dPbYeD0d*ruz zCpsg^VPsC&e*is{5ke95!0b={q{@&W zfsi9q%vp5{L0=r6cfl}u3@E+~ecE?=)63*H9wcDggm}nsgMpinpqva zeofE4tH^i*xfCq~7{GH7Li7mycPJ@?;Q%{K2}tMWCP9 z>-7)*y^mSBdH83hBi7}zc_NNyo`)sa^qPJZ#3r>;k%%+b?hdD%Lw`Tn){NBo2 zTXb#!8A{IHc=6cl;$lk0J_hxQ7%4(Jl~;gcZ|9a2{TN0-Qpgl)-vaH_q@H8FC%a0E zKc+)Py2W=d+j$@={6ZO*P#2rilH)fJ8Km;ei=l4AIW7TY5yHph6`8??S2ThFKYQ`A zbB?yJOt7 zQO5wsyy5V`1%Tr_xPO3s%q@p6E~62mY4CD@GG>EiGL?~o)rhy9lKEcJ`k4KvG|R6U z4v7Jxoi&^Il@Y#BFD=vK%g})0pT;XRo6IP{I2?3)!lFfgClDR^gS}?zar{)ZV@d^4 zk~^yel~YsD{=1LM$85lcWVvM=1F2HKDt2TJB0OGLcoH%k-Olma^&+z7znk1X~3k3t!_;A1YtTFQb%6k6+5|4FUi*!uSh?BBV^{MMS`^{dh}& z4`l6)bocVnvk74G~Q2)$+B4SqSSumR=k@bG21l+{s6G5N8wcc3;KQLU>; zbdMhz?#O;NK^BP{pG=2y}Ec?W55877V6>Z-K(!OG_VIG=2*i6&w zM3)6LuN9xPXmP`feMO)aZRu|3`a8LEkRKjE>A*-NI&x#iVae~k_|ro z1BaH3Nq!S!ZW*P}Vt!O+sd>ZQtgdY_g|C}EXo;3Gwd*sibYTzDg&Ityipv$E+7*11 zLGp~6ypZ#7uIWLg{YNFRMZZ+p7E!TlDTG72Ifn0f-bw-%o$HS6qF5dN>Sm(=QfLw~ zRdFcG>o}rGWC~c&nprVip7GLXsz{~7wcu18PK8>n@<&snKp*l$mmr$Wy)%RE-BXqO zK2|Ul8W8;cK~n-M{PIdg7h>cj#o_+x5OhE@Jx>{~L2D-8oh9M+UDGn_Uw-E0GRUEA zv5D#kI6-zm!0Emj{ulEP7a`BY3j0wHS|OGSd-D~%XEWjSIn@@=iH2Dn}yQoOYSlCXuCg7JT)gGVq>J>qin(|yWlMZo9PND znHWJjSrZDEXFP!YDU-eLLt(zky=_b}G4VR);I5@)_fo*M<&fSBD7ctQVcT7NA_DOl zR+K1={naBuRPB7A4^26V=o7jWMTeP1IIrFob}*nlu^GmCfoej3NckS|0Eyk$@Qy0N zl_*n<%B*wanKMs3>(b%lYPov~hj0AP*6n$ESzV|ZC3CwLiL#xb%S`$hN6SOt;-2BK zV;L`MTs@iH=r=8K28=(-P(KuCsqn*EJifE-6Fl(dKuv_06X*acvxrkzF8})V5L-<^-s9lr6w_amQw`(|;psvX7XJ(pPKU*k{>RFwmY`GVYItTB9jG zIHcb$OBwA|56F;eyLCHH0kr2b`TUaaHNGB72iB!PI_lr&5+O~0rfKf~<9*8?Re^+| z+zR9wxb=dx+3mSd(XBL(4g>C`A~XX;^6qW*nVJ_UiK-A#Y?bk1BP}Wx)`-r5k}8gW z9y0G%eCFMbgl>#0ESMyoAJ3Z=0dc0*@`g8Kd9*S%#sU?~+f?QA!CQZpIFKow8N#g? zy8N5(`t}VVHQsMEZFv5)>QV#jbjbWD2j5u~=|Z*>gi(`GeJSsI6eCmEM}ix0?*`<) zmOSw#h_;aSnJWOV4AD=3^xc=D+H?b8?j9{u9G*75<*Q3Cm#aG?=8fw}bS$2Cmc^KJ z-@=dznVxiB4asN;rwbQsqT6C)(FZpD3q(D+*79Jh;LCRB4!fol0&a|z59(4vBzfX+ zFQ57v)N9f<@-Wuyl>-*^ilm}%&bCE}7G+IHd{A-wCm@TVenGSkPm!l%1iI(s4Qe7pUeuD%J!iB!*B$f8kwFz1i89?$Gx z7{(`aMFcEpr?Ib4X|5@T4l;;8c8z%PPZuAnNM?H-pgHkTYji7gPueVg3Eoo3rhl=UI!QJyS?bvNp!kkCq$?fSA1C|1Z%tpvT0eb}TFq*=F3lfU<%P7=t@`8$gtqPjhnGwjmqlmYt{$D8ZvWrs-tE8Hesom+ zMh;$s`F6()4U87%@+!G9TVm>nf539|;}yHD3z>5zNmZ|`=f$LC5e}Bj!%&ly(z)Q9 zG?MCj)+EmxU1oMQH*eXs34_&m9RtMOnF-VMQFf$=kanBTx6hC!l&aEB%13v6#qMEc zJWq~6Q4<48HzX6jUXcrH*sb`$hZ^VM+pyg0RM-vVG;pVgQwgFoAmdVaX#Wv=B-8|< zfQ=o;BQF=>$OqPQpsaq@+;R81*j|SO9vNQzNoVj5_&i9y;lFGRy8JEFGfv0NcpmS% zR3RbkM`{tdt;3^{#P9Ax?>9VhQ^SkAA6j)O4|W=S)^3ot3uo13Y9shi^Y2mJi{#Zt zFybmIgU`-nPJ*EM{Bp9Yc&N%F7i3%3vKFFnW9>t-cZJ;&;buL*3;w z7LuE)*BunWC7Q!Xo*g<@o@Gk0ch%CY(+-dt17eOAdwZfcso=E{Qs`IXX4zqFvWI@? zQbw(6IBVK5>V}-&5x(3Cy<6cEaz@B! za!E)l78=qdUIGm&qkT8nPMc5U@SAdJ|Q+am)tn>Gmy2oLHjf!x=0; zm9<^n2|tRmqL!h5Lc3RtwTlEuzdq~-N-Fx^mpZkLn_A5&WlcMG^sUOH(y`)dn^i_J zhE&Q|7~7LSfr(zX5q-DJCqW*!#I{TIb&l{15;UJZ0Oj7V2WssaM|ac;q{$!H3pWkE#2Lqh z&#Xse+DcxeCd(k)r}GX-(W$AsNs=|-URP6b8!q}F>=#!DQ4x}eg4*Ghs5Y$DsxO&0 zTT^v;26nrbD!C;*YV*|iAbQoo>9-X*Y1JY}g@OmSK_d`rczv1Lr8T`vHCgon4x5-0 zC&Be1o%&8^7Qh&HqAEZ>pfP)_TXIHsYEKOvREK|{SXL5uZTHQ%Mi&VpMjP()oL z(rWBR73yV5-n34TzRAKaP`}IYi^I4xCV{cq;V4rHt`e3NBo+swc>^5RiZKG!%G+8# z%6`XlaW%g_e%50|C&W!vM0~r4Fb*n;q#O(hevv9`DoKOgQDHz+#{VY*lnpQ_q8 zz^zUg0JZfsViWwz+J@^W&1IXIgnXi2Dpo{0>~7Zt5I3Oe$N|{KtxJ6jtON}AWCV+{ z>nX-;I1P7#saHep6D=v5C(_7NRD95k+bHor+?W@VNeYR8@Vtc`Vnm6iUuSroB&uFB z{dgSRBt#;w3OaC{)_Y;4gt?A)zQ2}ewyww~{wAUB?5UNg1{c9w!eYWnqSG@jzq)(4 zQ4{%E$G^Se}9!P``5)&+0M}S&4%CbA?D%wU9ssm)#6s zO%=$BNw=pta2hdhA3SlM!M$+N;fHF-3ik|acbZJfuD#nf#5EIye&#i^=7nqH+MBg&(Q~M=9jt@5n}QL!%P^~@p9gicJpL_k(8q&}IkV+L zeKO|ypF2y8ehIRLL7E9Ol2?Gk-53Y^tn&pfy5g@3`s+whr4WC`_R9lBf z2^k}LT)?-#&0THHQQ>}sx6g9F(Mwg{femnQHr34--p&1P2m;ie)g3|}>Oce@f6A4H z?Z!Xz#X-Upju-uo!RF&=hu>cuaLX-|D;`vROK%*u(YuGrS5^ffbjb!4ohli6-vqRii{lr&puG+B*^&(9Y?by+s-eC@;Xg6ckd`4Zb3hC*_Hd3t#T7tvl=pR zF7uE2eL-@wfo}Wf9jSMGMHbD-Hd!yC@md&o-eGWW@oS)YH?Wa_W5SXJU*^UmBUdEw zyUD1Hgi*7Xa;UrqCF+$7k?@S}W!$;HLA$UgiC;m61@kYx^ednnAIG(;sGXe3ZG;A6 z>9h0}2myo2-pSjy-&9^iy@i2#7Xfoo@p81R;5Il9RZD%S!Wb?^N8FACi`?EGK?s|? zuXdT>)?o+ZR@iH+U|ZcPyTR9CWan((z&-|QH}AnF0_|qDhkvis0ml*iO*v@9EoS{m zkWse}2i+@a>pj~wXbxeiz6Ps|WXBz?037AfM!VrD{tD1~$^#|13r(w@jXD>6be#XW zEHe4I2h6McbnVF^nLF4)0*~yzbjMhusj{$l1qzs|`5xsK5Ixa3_HT3uM=22*N)l(< zDmP*jlXK7e2lGsnal<>L=G7?EIJB1^|8^>(GO8A$sh}VDuE2L5knq>;Bs5wus>YX= z!ihUuW3q7(c}-+^w(GtleVyb}m-DWGClFneicRAzot z=ih6;Uw>~b*+d^^o+!7A4Rl4P9K3_08EXJ{nLgGK260gBiNF4NvW)dZordGHWaVFx zLJ#watE)~DZF)?qjkL#%v$O$&@r{RKrf3}|Q)DWU?tQ$MLj^?&0&8p* z7xuqMKJ^iB%PxlF!3}40>y;YOp@Y7Cj^Pc;nh$OzRQCq5iappHe{@e^tKTWM#h!2A zCX|GfEL#9P&G{Mc63>Gy!=Use4;TGERuc=<-U{&(=Rq?Y-MnU7sup?lb#4b6w*puc z-AeBWyMGNDxRT^SGE;s+tk+R7Z>aZ*m;3++`_;uh{{UX>?6F*^vvLZ>F3S5=Be)OH zZ-iP#9Jo8dTs7|Kl5Eb?E~a0 z(V8lw`HZO}ERWr)NXGBLwu;~G^g!0KKa5CVlxLudnEa^ECtB_%nUd>rpY1#dn{K(9tqX@V36Xe-W8UL~Nto|MomK1_91@N3`@ZAd~6UlzZPev2bR{4&lxx zbf71&u(%8V=@}?Af*m$PSB5=O3ks{Wt}(6OVkZ?LF~dQWPDhMiA(rJJmZ$_bticYd zplRQcMijStd#-XgN%bS}>WKZ?Ep$JtaqVm-f}_l6`_5ArH7(NA3GMzv`Om9w+`~W1 zekGC4Q@lZVeGsf2CuH8?&qsEAr9o~^nQ)lYh$mNszeTeEhAH^YKEiYf+Jj*vbNBnn z-wf53&EykZw|yxe8vLatSJC&&^4oT^1ts+Loe2l&Z6V4HuMs*eN6OrG z2?U@bne4nr@z66auDtk9F{J4!G~c;1w1e@Mwc2y6;uh#k#EBEJ{`yijrOCC@-=tqW zq=~`m`NWwXZICX!5-Xy}kR|=9OkH;N0hOb1(*`GdPYsu?5)E;p@=Nf$d(uR7`LU@v zz*mSmk8($5R4MY#2PSOw`fkWwm#1V#RIg{$-k8-Nh$UeWcco$BJH0%ueDT-6$EMa+ z$DxHsPu+q)%A{7VMyrG+w79)L^0`7~Q`4%mL7t@?;f|sV@T?vxPF*&-=rNJPvaP+gT9^uQW zrmprc&=dVcf>~4k>npJWjNfkSXmt(@?e9tWdny`v!IijX#nb(LY5%xD%r(B&2g9+c z6WNXbdpQ3X6!>#g2t42~W?sN${_}@n5!*V0%VcT_^z-@qH~-`JgFh2pF}H7~$fjH8 zuWS3CAEwP=1MbG))OLRp_y7FzfBYrng)SJvoYZvzgMVJhKYt!m7MR~2*C+GW|Mw6I z&A<@WYu6zje@{K;hW+)`JB4=xBH?|0u=B59{*SS6%u#~}qE7!y40wJ2bAEdG!2DFq zr1@z5?;)(Gf*~}z+%bChzvo9>3e3;zxz=X6|2+ilIxvJWm$8cF|C*owdv1|#R?J#o ziUzGfs^Q8|j>Z<+%aT>jyU$G{aW_VwGP*NTBnFpIIHt<}&t6s<;s2h?cJM%LP%qWq z!&&|MlwmNFj&`DCRq_kJ{v960%iq=0-p0&Q10vwWo9q1~x$&qV!65pBZbGzLq;R8& z4NwDmyF35@OU2WEhGk&dMg8i6Dj>u>R~dVx*-s)#A%MK%<>~W%z+`n5?quX800UqTrk{^B{ znsRUADcET{8ZlU=|LYElOMrVfFnh*1AFzZp>7J_S)@Xfc()^7`3$Z~1@NAI?(o+lb zdP*}flL~7MvF9seXX4hN+OS+&mzuQ=DSgc(VfseE*nrOG>cVfN#BdWr_dc(`0l4LX zR@_`SFhu;}m9vdj;4{ckEIk^^I9MU zEyA}&hMfNWy}i&04t<-TdLO6Ml#cdrb4}vZ;C&;Hl*=6BDXgA!|Z$qA{6K^*f$H{e|!Mj6h+=`jgj)HM8xHakkCN(4Znpxn*{e*_#eyOX%J ze)FaM`y*Yf4&L0i${*MIN!iRFKQ7JOBANX-6jb4s^D1v+ezWEH$6NXmRlDODI{vPF z4Xr_ML8BOYp<9-|&}1qNAUZRN+0d`Jf&TnD=<+NE#Qv28x?_UXswO>L3weft0I_e& z-wVqX4fq@yOh1J-SgZSZ;gy?to&A9CgZ5SCbzqW5IV3Ofp!8#RPGKR>`c=^T#^1oD zNgX&cj^#5q^Zn~ZxAg~0M#dEt5xLbs`tq{KtG+UE>kG%@o%7Hf+tpy*{Wmvx2eK)Y zpALpMkx;+1l{G6xK*gi&|VjgMej??PJsT%F^jDi^im73pON#?ao( z7gqsx8CP$HXhh3^ym2F@Kr0~{xQw3-q-4qgO3gb-&c`*xyT{jz@84F7ka2#n?wk#b z&C$7B+uUt?^2QahM2s?T5T@~5OBFwEu^S{7bF*|7f)}}$@vw&AU;7aY3j4+WgYRS? z!7ZAEmo|Dy{{5lh;RDZgmvb7d#PH9RM%R-+nYt6}7pF?V7$*Q(@?<36FM^F2bH3*u%GI-6A&Z6npQ zFr|M)=O=mX6p|tp*w}9)aqT2ap^zUedIrdOm=J7>bU?3BRLO%{o0MA-^5mgk-qU-j zd{O3mz893tZBn0-7LZeOJ#e50b~f&VO0rct1wbTl?EIleb)Ccy>|aUT(0TfS&mF#= zv5x*jK*Lj!xcB(YYYVn*;6|vX@oBDsR?jY8ZM{RZH7%nZ)j}5d#fQ#vFf-#2g91r& z8#HHUVyHDBfo*B-!;il5B{%pGLix^XbkaUo|yo0SgVQbX7`L(%wD)?l4=|CW|ML zJ@d`|Gb^_r@R`LTIixJ~`wEd5Z|q)^{Lgk%Kt@z21DF^lXhMok;-K~$;5ZoNy6)2%MGpIgpRW7Zbs7x7I}QbjQ%=9!uKnA z-9+P!MHXO2ZP%UtjiqYLb2uZDQY7n)91qES)55J&BuE(D#$?o<6fo z=`zTY(xoNog-hw})s)v2lV-bK-@t*EJq! zxXPN_mv~&6_!9uxt(aSN4adUNjw?aV+49SzSAPo zIb3SNYL(gU0fIB+fIorLx#GqRKA?mBh#s=P+V`&D?RB z;BB8zrv{Fi;N_jIYdQDjL9Yq_f1cnm9h(Q|E!Yn~VoUQwB& z-yHx$p>$*JWo95(Ddw8}mhfd=rW!$1_d6Nv_!f|&idI}Xr9$3JaGbJ*tRd#QhF#+Q z+|+k>{yAu>+MD%c`@*NbDv<^A7m0#59KvOKTlwdsKkoo)>})}g6qmZTN9|*0TccVt zZo?`Q+SY)_EO2>@-C&)R8Doya1X-LzNDe9Dqbh?9g&2Mz?&r~UKyJbZQGCx17wN~K zBug~s+4Af&9*DO1fdt+e9_2#?BVT)+wma@^Cr>+KX@!&*y03oR!%Nu(T*NR?o)oYL z!iaWaF;Z^iTG#DpYlZRu8iLAOU zlaczqJmhz9Kigq+*|GR_*TJBijZJL+qPHPk*!h`3WS=7awy#}A7kRs)Fw`ArNS-e? z%d;zXycd-4Vd}5J*#076^3Vk8-Wo=b7*7}P`hkq-7JgFyWgz*7&$6#703AhJ*(9d6)1_$vuRIAhXQ`b2K z0!C1<$*LJ6DHK6cL>lhhKqgxOa*s`w@4(!ooLtDEkf2f+-xlsOZtPTZb^s-}AI$nn zP*BT&Ujb_dHHqncqV7}A`No?|m>005?hPe4XcI4i5!dB`{3e&E9hw*CfS~vUCboN=r*g3wgxC+`>-P ziMTGnSdD+uzvl8|h|6jlSq@dCa61hvGmb#0J)H8Vt3Bol=06T8a>OBJ8z-0FS8mOm zecH>&W6o^Qbo(Asdjf&nO+LAK&z)+FI>FAy*ufIp@*4d<|B`1q^OhAjsRljj+%~t) zeZt}*^DN^KF4>3sflUrasDy>Ehn24eWomLh5?vS4$?St8^lJMh@kCUyhA>3s$Hd7TlK(~r~Xwn{{4qwHN{)DiiRgjms~1~G>*%9y3t_ z`|fpd&f-f1yQ??#rJr}-5l@yWwmIFZvE;iS%h&u2edYv?#(uB&wbAEKQP$iL0<#>A zFQFru3YM~F_^U#+D&h6mnko7U#DC#5_A@sKON;mKxgZwR<4TwBKCT`PfI@DRj(7dWYC z{=U6YNj=*fHoV?-4Ajzx)*Lbn&;P#lJly!gtrIZ*W}*_N3FDBvmi>E&#=+6Slm>A#k8nrE?phz}3oysWlF2JdeCxKU`C}cyz8ydP_n6wM` z7BIFZJ$o;ts?i*CTMrUi2XoYpgsm}klS!-o(}7Te^D$~H%enef$9+zwt+Ag4if=jj zjG!&gE{89L&*&fyMLQI!)bF?|)%99ZVq%s?v>`tpm_inrw zax|eJ-}DY<9=bSQw}O3p^km~lZCH?o!3ccTturoDk!w?cPB#>rf&s)LWP64Kok-VN zigjh_yH`*W_gWC+vEn9|UTQb2a@hN8m& zw;%~Y#SyUjEU}p34_uwo-#kvn#wh;x1kX|%oPiV-Ru*2S5dSN_tp%j6N}(JW6d&?Z`cu0F5Ts9xH+5d zPS@-Ix{ayJhiaQnhfJ{1{Q_SBR(rfAQw}gYb-E?qZ@+`<9^GyNBf#_V3`+DR%Htb` z+V85J=U4kpJvF*&k)S>FqLIx2XkjEUS>E2Ud4^R$hU@U3?rz$9T6=A%n zi#s7<6#PrqVR7PI&2!#j|Asp|Z%Jl4bF zcoy^`axy4+Tvodims0BP$&f%tRfr3D2ps-Bg0*~z_*O;o%T7{OJuk?g$N2g0TP&A|)cMxQ@3(J?$1%+9kjr3az|nam-@Sl? zd*X!FBQ6yMi!=g2c^?gc9PEjT1(c@F&E_kBIW@6Ig^HVMjlu+aLod5I zl~&88X*XsilL7CU5HVW^@jYB^hd`i<-dh)8ZAX{u$DC^QnGNn_NF(kA<5)V`eBg5V z#e+Q}RVpyUc^v1V)J|)7f0*W1@#1CJJ062_VR`*C+%Wm{!1KM?GkWv>mMz-|T0in! zqna|891vR(O|7-dje1WXa{7itw~)=}JizD&3BZAz#%}@5`F$!c*SA~3nL06#ozF8N zrzyH(`+(og6e_=T+}{NAOg#mi{Wt0V?Eg4vC;=F3!%&}%Y|(9K_9UTvO?_VW3P%s- zFzfRK#jsg;!i&k!vSxUyb=l{T=Q|jTc28kye0N<}B`JC|W82&fY4j6e&yNTL@|9=t z4N9OG>4@^hsj4sU#v9j{@E{}Am~I#=B07?RZ9N1UZRY!@l_pS}nV?<%%u5KEuC{^> zz4%e!#VQ#IvJ&lah1{K-qgBpM{#>$FKxr$O@$p|huEK*>DSr^?-ojk;Ias(mIVYCb zQ`zKN{plZ5*?Zu$?j7jnukDa|Q`WtaTa!J?Q-JM~Adgxg!hY{E?cC5OPjgakb7=Bw zbv4_pDsKei)0H$~XGNF`IE35Y&lS&Fm`9?z3g{8W`~a~f>|eAz1x}%y4;c0@70)1M zkgo(On56wqL&IvZaSl5fKeU0bY&yA!i?(pi1K$6X)p62M;F4}fXNr6#hJ-GlT{743 zLYdLX1VoMMOzDK_#b5;|n|!ow_igU3wH{_U1nRGFkh_`7{ye{{vmP{}M8I2KXnelX zK9!p6x_lD1QuE6bcW2;(lb8E*>L=MSs`(|||27EpZX+jx-9ygY07(~`(KJzqRuCgf zqE`b8k4cz?M{EG6#WcD^-YHLg$i8ZpWnFf6Es=zD%B11G-k@&-u2aZ=)=~lFy8|c& z^Mwgh2C^O8XW_?P!N9yGGnvCew4NBLU@&cs0CSw|l%uu=0VuIbn(*K(jT6;iD44Zc z97z{491H`fuvhXQ+YDfyJm3M1to|%$3;xj=uU3$!PpA3FVTL@E6V@rm5VRQx!j&Y0 z*%|<;g%G@j5AS~E^Y2aKHpLXOabi0K(~4R*b_Whd{!ekic^;ADrlu@_phnuA*Zc44 z2p~WBtl&U!M(TO~?_2!e;6oOpG@Oz~DnsS(V(M?8=>PxF-z)O}SMOiN>%SHvRU`6e z0&66jE>}V4C#lGZitTz~kDYh(hVqS^#hom;w2f@I)YWW#88aFgU=Mi zs;hPi9@G8F^llYc4$AM%)Br{BH)Rr95Gugb_S#Jq#7wpRI$W0TOY5TLbXvN;z-k34 zciI%dXCw)!HqAgP@V5TdXnuu(+J4~CN*Ci=?+1H_FZ$otUPut=K8f;DlrBdwtDn^$ zG_T0zl5WR^qf1AD3*XqtW75jRa~2%<;65H+0u2x`2(J4y{XlPBBVB z3;liG7`V2Cz8auwD(_x>m;T`&@EW`VhLN3Q2K+WkQbgSqF-s#br=jiu3+yh-a?A!Z zp*Dc|d=nbpefJl#oq>ti3Ot|)iIXW@8Zv-AvcFV24E%i_`0Wvx*nd}0q_nKm^0iuQ zMnNJqPp@^`Jb1Kxcb?1@2{6J{4tox@K4ca z+Va0pc0NpQvea{L{WZKdd;Uhpw3=A$gJyHu@nUF>CE6Nna!v6UvZfNuV|z?xq}V?- z-;D3P2KXuD^=*Q`%)3CEMnH&S`{b4UoNPThC@Az1@n$4=!J>Y@v?O`oIDY~C35jXI z#n)f^fxovOsM+k*gX(-WE@B3$Nr&9A=P$ZM9D*f4ROe5a@sIbPx zm}RYx+iK71=SQOFbK(XNoH%q{@M*vc_9US20NE1}jz`@i&I6tLHm?O%%W=AN?T{5_ z2KS5SHhkos2{ghS`;os)6ZQT@N3cV*WrmSYotkd0$Or;&YnH+5 z&WbO^5^KB6s>5m^+QK}M!2U&)KJ?cBPhosg=nn=&S0e0l@@jzh*y)YzK>Vx1Xc!V* zCbgJ614QE-ih`A2+oHq!{vj|#q9Piw?9EG#609Mw{u}IN&OcHq&QK?$$WkMi9;rGSf z(Vy4r)g*`$sUbSO!);0W*r!{vW2$DiQ8*!<=B zYBv$0O9fLQZTQ0h_~u+gr~x9fp1MT)Co&FHy(RDn0D?reWA)3&L*(;-_3G%p6Zre; z6S=5cN|evE;*685iU^uLzaZ)MuR|gLJH?o+e~~?k4ZM~G=1Ini)Z4iqoJ3?rB1yRk z5vazvNaLg8hBE_^wW??~jjY!gxJZwye9s;Dy^n}1uytUhJVp@EMHmD){VLE?XW~Pc zwY2r{_A3!k=Yc{VDOfXZK;!%VJsC`l^M__X5?+X=htfK*-Ln%^?~uG$(Yk9JnLbll zvz6bS1wz5Iz*6TEh1Ta1Aqh&H&m3>v-#wl^g_Jh#H~M6OP-n%??JGG}3OkS$SIk4T z&jznfZjYwwSzmKtH#?%712n{Vi?;KKpQ%!M{RKUDrZX{hqj+!ErGDpSn9>+i+J~7v zAWx3MBLI#X2ksc(_klO8wpIc$ugOfk+N* zFKD4VKV(1X6r{}YfIxDlN{5>%y;F;_62-)Vk@p;4dlgoiRV^U2ZS}N~qe$}39Xgd~ za*wr>k^RpID(XPTx|QA+&lu`$qK-R9t4#GBr1mtOMxPn)%w9R4rbb|G;MqVrd_(d+ z#qm8VcbpHfp$P<`D&I0bfc@DGtRgUr(C&Ll-^PgNNJUOZxVADde_kK(`ba{4eFtYLH6m`u$o&r9gIUG(`S0FQRL~2LvTP6^bS* z=P$^fyR~W_ZnCuJA#CuQOYe4(%%sBz!g|ZD=lAZKUV%&(OVKxLK^4#%88jS9J5l{h z{BPD9lix$9TB}u*DMAkQJVc$BUhn*3!5SlEF2)BaT0D(#Eb~;KZ3&}UJm=cZa;)T( z=Jm~fM&J8}c@xuWr+7l)OM}~Q6^BBzuZ>AX#X&^V@ki1e;Dd^U^bkTR?iKb6G>6)i zXS=iyqC9plb>wj?`m3g2fbgpT#>ge=5e$Mb5KV1QWBHb^}OFWc<@$+v~-FzZOG}gtp{8Jx8W@r>pdk zSkxbTogGTbDqJW6m1{h0wH+9ca@=C#_>!IWez^JiAdsY1hS@fZaquNlii-JeoZjkj0S$XWPu|7FMmX=g8e8?3=c^WPmpzY|c%r7R4dVJ7sQf z2fsX}+D6RH7`Y2oM(M>$BuzivyNgo5t0@d6xptc!#E?z@p}sHc{Ranj-=7#`*DV~} zEYkcM!K2H4dIQISu#WUQj4OzC)^d4bBugq&WOLhJ3TGH!heVd$)HmnP=V`H?VsF*M zk!`_*S-W|`(J_p28$^+~s^{hB|Y|z1dYi3gi)vIOt z-ctK*kqir@N4Mzc)@*s-6Qjvqcs?Ld9d%A+x;xxo;cVZMY5zIs5wl^1-$2eGiMXLc zt`?9Rj*8wQ6BUAlbu!qiDGWb#+$mGmb5DtP=lm&V(P!TB#=BhbcqG@~YP)W4 zMmy}_n535yEuy!-yOMBt+UIB$#)}MDU-TZFISj5k|EX;^KY+ouk3)lYt{B60%za~{ z+E-Q@dSZURvfNsx$i@;i+E==mR|2auhCOzKS-JJlT0cCE!1A#;69ZQ~)%>B(MK)l>c?XEHJC&0>*vY#H9M@Ce@dl$dNnXvL1zK z?1V(}e+wK~xp`KpBBO+^_|&n+EAgpoFey2sB)l`0z@qYw z7UL-IDkv^$bVM19>vW5!^UW^M`X|yvTw8%RiyhZzr^&a>MuGJ|o>KQ(y+mX;`H}HG)AB7wjyLy`t)oolb0?+x}9<^H38IZrjM*0V> zH{F*|BwE&e*)Pe^@iZOtN|W1w`2Fw4zM>(*7p>t+Ls_1>n3J;R$*cRwRg7=>-G5(> zH)&cvU8hX9o4s&0h8V*m_yg1=MFt8UWMZ|EYe2f(E-$wo-&5tyjrD*Al1(Y0k)_=` zE2NO9Jv)==3(<`E`cEYh77SfDIKV&FGB$BS1_@+xp0U1P?r9jS*vOL1O-^5;hnO=5 zZ+|QaqK9c)U}7^>r$FmeOP@;sgoi?5OVPN{uB3EJ_Vwi9dIazI1~@<*Y9`+L=Fi>& zVw2GFx7q8I7Q%ERCeOJ}X=nwYH4WL%9upuX(NuR`J$I;kUaOTb<4$IzE>XO{fnD`# za41a2Sk3LoJQ13x`9h;Ou9`Oc&!N#Wea8e%fxIAMyb3cDkbES;!#j zel!yYxF42fAZAx1+Vr8=t&#J(c!uzy{)c^6_j2G9X+o=xurU$*HpqRio<+rH4&5|N z-**G)Xu2sOzA^H$wiLfGfwhSaa1HY#S|7aioJ;QEYY&kbnPdm2M%^bF$&!(UM;*VcM(uXC5Xkis0?_ zQSoJreiABqf1R~YP%vHfDZ#V>udB~w!$NPi7DNon8Vq9g{NUBZ=_&WzN3pg(akHDP zkGGqq;fL^Eop?7p@_T^(n<=Vl$h68BemSDW*b3-V{z+D`B5mXaPigH}AJBR*+|dTG z^QiMU6spPsoupfgtlw45@h}L)m)mT-+I!$@1Q!J?GL1?*efJp>|Fvu>J>dAmB^H@+ z*akZ=7ypWQ==Y)t>}G2d%N@q_bb?l&Ml$b&q1ZxP0I|;uIq-As!bd=%d@S9$LHrC& z|C24RedNOoscI=(r4Q+N+vG2&Yg}0?sJwUiJ%f=83}c$?tDiUfyjc-(@lsniqm z8E1fLxQ>t(dhOrSS3OMq_K9DW*An054YC5=Juo=`DIHC*ZTR6)(d%*#Z&8Dz-%6zc zH|(Wuo24)$o=wq2K%j_dh7L(Q%9&%9Ul7^kIIo+G@o3u%LwLTq?2RX1lZG$chjDEp zgNf?E9BHA`{P&R1jcXt4el1F6rfJiC=f>H|GO>WLgFMEOt?daVh%Lc@EUO+O;;+9N z7d%DZcP&Qgf^9>U;xr&DJ=(ndL7Oa$p|cY-0y{k^?$Z%S+j2mK_p=lNYfmdS0hb@B=P#ZpGz(50TMVvMQ&hjVv3*c^XoujqcHdBF zX`?8?F2Tzzvk>wW_WE2;O6!-?Ydi%}m6U_1i88CmIc#t1-;&6LAK36^@eZgy6BW83 zcp$%3pIq{6mF@VTd>m{4qy*zUIN(QR7&0xBDyECQlDrh_2lq1U$yNPSh5%fSW$Se& zhA18740O7}_GP{emTvXoGGk=Z>(2fZRP@b?aT6lo;<9~P_OCil2~o$DO={*0F)O_w z60}_-RQX8Em!zxwG{oAvSw%LKG(qEuYwj?}Ha^)1ami0UUL+;r3(TeACtmW{+KEZ! zh5%2Z=|?q0i@HB>ii1@nnzCnuPn{v7fH_dN=ek17Nbb1Bo0$e8;3+vXIU&1!^xfzc zs*QVs_n{T8>pU;~N_=C1A!0~*tuNPdu~{^VZB%?4j^4SPo~k6*>!@|S}4iYkDmL6 zQT_@CY!e{c`}!A512Ze}g;DzYtE2f>eV!L@FS(Yt&aU2^BYaAUoIbb{y+$%ppZ8v; zX&Ut2T_2K|p9T1I5w)YJ(k||~w`|MTo|he4VDK+DCEtgdRci43h;yfQ`Le;r^q2FVmQu-Q0jArP zW;o~G$2u8Ts-a8YZ0auSmREP@yA>sW@ohsZL@&yF zw9B9N^j5mZ3`(;8lhz_ z+O^buTem6aa|>p{8`Ts~f?^K^z-jWuCKNULMR=brkxfGefJ$nrj!q_YzalF4Cfz@Y zdq7N zIcMhF@#&4xktqrlbc@Y`8Vw)TCx> z%e3B+^;5%B4DMbAMk+%~Mp`jBylYzZwGLJ2Y$#RMfimMffyZk!-_N6A-y6`%po@#$jd4g$9D|PfH$hRbUA`F9?OV{jy@aqqNxT`oO$bJ> z90RXXYqj}=Oe~wzrpa@nS1>&=b>F-RM1WD!;M!OX!GA9uf_kw6p;vpaX^HE3f6TVH zi~TM3pY?wOW_($_Eg_3Du+|ns>^I?s>2dC#M#QJS(1f>^<|D z!lTh_+hZW=JX?%!271Fh&fP~+=%JrNxjw3Ada9>AaPw!KMb+!Bpo>p1W3oeb3XH_~ zbYXO&jeX-+NEl<;*}*Qo)h`>BAqk%X1Kx#;7W8)<-Ck{{vd8$B?pHcGuORz7um`@)bR3~%qAR?h^Kcv$@LkEaP{Kif{^MK2;1iej$}r}o`o z&YOE3!k()7SDpezD4deWy=foB-AS@)8EfmBEMqU^G8E=I)KLlyL)A0%e0zP_?o+1> zpMhur-DDRDMK;JR>B1u*TYG^}SbZ>*YV~!TDi8A7$h_vL+Bxs;+jS81mk-P7VJn!- zM(MJE!$o?MXp$MW{_u$U_rg%9j*mMTqvgSHUuAN4B`p*^Dug)3tfDEmE1Ff7h;}OsO)#DY3?!O62hAxs~}!7J=U8h9L-R6D+HJ z%+sOAk5~;kQ#=XBOqks4fW_IDBwf<)5z>74iLhVPlGytoPN7s9I$BxAZG4&kv1u^v zRnde)R4`ZJ7`sUU`V8{8@lRq`64{hDACb~&BOl>a+{Z5jWMaWdSqe@Yfh+xBEWw!< zf>fU3dA^iJa`Y~PV+aD&G4V85R6Gj@I>svt>f)EbRlil3$@}ljOJXZYyLl>0tbC(# ztk;Nf++VH`1LdkFJfD|(!@J`5zVz)}gRfF7`}*R0r*jbVPxb=6PjMPt%VKXy$iClW{}9tpY;O+djMS%GiYvbi_9l0id2c31<(?qc z&j6+~qv-;xn>kNEKHHu>`uOl7)GfMRWA}D3bYBbNLG%pP9&w7rtE^f4x!O9c4Vb5P z=E-P+%P>f!llB=J#d=Lwv@Z2V3zS=Nc70ItZD)_yntNH1%WW%}=sfwCf>~c1j9VRH}W2Xy6^w;;Wh~IJNW=Tlt+Rqgk3JtG;*Ai}+G9t*&){bN-F=ep!FQ z%})6|eYO9R#fU1c*1betQxo~$V@ss>84ida+l&_%RRh}FPm&o=6Iy98Fc8=23*QbW z-!|Bd;~hjU*d>j;G`IQ6Z_%E+jy}EM46M_;6sBf>IzBpMyzr%6Tmr_4rdskSgoR-E zn9C`tzVQ;>nYh+-fAPUV`tD?quX9I+CJc%R#H4pHyg*-g^bB3`2W~BK*G!&>s|iby z!Pj1QK8e04ico|YYbS=h`!zWQ80`hMY39^>A9DzqC~IXV%<{K3Iw5l&wS2`Xwimr{ z34gtcJeGwJ{@8is+!q^w`v4o|Xl7J*S^>-4&2oCYEnGcKp`pBK?>BUzY{N9B@875j zK!YZ_Dg<~9E0qnX8fHUx`#k9MtPGjeQdwG#-SDIZIuQ<*rynMI?Pw2fyZEA{fae*%#91J%fWNEYa`-bv& zr_>QyK-`;Mq1F}$Mw=@J5HNmb%hx-vCXuxRUZVyv{nx55^^~Gyu4nx!h_d;;$ntA`eD>t%RQh9s|^t$ zobwjv{a9Kuj}|scFZ;IBI*B9C_2A`ft$P{wi;wn&6HN)>X6EwgcHyTOB{f1A^4N9b;f~5VnrnY^iBLw%+mOIoAjy?xbi9$0c&)-zS zj0e~uk7L6TR0?r`-CQssGXpZOIs1~h26QlRYrwqZI#%%Hvyx81+WThyf3eC6a%Tx- zU&?!;^4YhQH0==r{zvk0Hw%`|`*qvBK_?VjaQtUixTWZwifaYzXgIV3cg;8B?ixbq z))M;#k_5V+rz#{IvV3T{Y|w{Z`%Jr6?e~)u3Xf;tsV9FG`D|gBCHIWzJxYgjA)o`A zq;u@3J%m$ojuk^%8)T}NysMWY2;WBkr1180k1LgW_gX}hpSB=CRRi@kdV9Hvhd!w_ z0oN9DigTg;w1-L7gE%wyPj_c}Zf~vfh-Ep^Yo0}6Hn^dp2sZD@vSNqzS}m4 zaWQ|^dh7vM{8W*-jTt4*`Fj#{ysbiiv*->T)X-hR=!9}pZp1!->-PM4e@&#l(Bfos zeHS{@w}dOnT2k-&2k35A570q*0n+EsNoW=LuBBN=XdL=}L4tqyp7F1I5OQpU00-c{ z;w0ii6XEK|U=Y)VkUt-x(Y>DzT!}{#kaDFd26*?ef=XOKEDi&{ z6UO6I4xOW3c!b~g7c>O6<35H$e(AJ(l68z{LrT0oeg3II^1sU57G67{aQ4B)lVc^$ zAeeW9EIed7RzclO_Q}6;a;|8M{yv>FJ~^AZK~q3O`P7V^Tp}+#;&^e*s9>xpI6|{y zVDnAeI#A)TAF+HilScuA`R6!eHui&x&dY&&LGG9|M(H!SWplKfgm?9P&UPqHYT%(* zQSvjJ)$hP`YC{+hB{e@2?eQ*px28-0mSjFxu@avLLj*gNux4qDo2Z{4%hhqdadun1 zeEkdT)igC1pDtPRLr8N<%VJ9?)gTR5AX|sCe|aMJ-c5RF<{fgv1y1+PA$`CCplQVQ z-jx+&VaCy!~yqvJTfQwqCWg)5{lc;Cb;q!1`oiG`f4{+Qa%V`QET#O+XwAJn`&npf z&L+mQi-5p1_PiUBA||Yw1$4n& z^Mz5SBhzE437~xixBQS&!_sRY3jtaa@L_1J$9PLVtp)~+46Ql97af| zpv;#^mFpK(+E&d|P1}4~25{dLgE%B(v5b!AaLROxFuLlkbP3-lKQl3&J4wEAMHb$vwnVVHo)GC2;{m8Q@EN%QEjWF2B^{u*+ z8b-6Kq4r_$!2OQRxejB`(RhY|<-?%)HlT8J|DJ0Pd+dA3Q2>-vHn*0R$mh}olku!m z>pH)aTDBq%s{q&-H$J<0Y{6dK@h|eiJMfYzvdk=pN@vRGTeS`tX@*&mpkP|Y-{n^A z{w&?~*l1>0F|nIP?DgbVzUJ!s$fZsK5mr^|1SvRWhf>+AzbG(l=qKCbYPU@;4IFoM z7Xc1@dHp#IPc#Jyjg~InuZ>n64SEf~p7xnQK?;ke7UAfm5Lf=g3yK>9Pja{x#p@;o zG(yo7ill!&SDwrr_yIn>J}X3?Kjs`Lv(@Kt$sGfL8*k@l{pj9m|CP1_WNa;T!BLRf zIpaQV%whBWKGMRIS=n zauG9RGCz47>UJNI^#72&TRfby#r`pq)WiE=X=9(5`@6lI3TZeYXm^ z>&n|yMBqo3ti|56gzsOBM|^_RKedGdoj(AaRcLox4c`5?9mO}mbNsmZF-_>N_5L@@ zQ5tD81U&l7SFB_2{z3KpV{h@d*t*{Q&(rP%r7!8gN06KfulS3B^fw<4OnH=_f@K{R6mk5ApTb}3F@y$I{$x+6PLpJgsui2zSy>=c^fwM2j_nM`xq9a4xx01$3!OAV8WnR) z{Z)$E|Gi+~13U46G9yFjvL1A`|NYz)z_+9yg#DNG3HaXyBVauuk$mE9|KAUXE;tT6 z9oa1NyZ__Y{ip%{Gd?_<$5a2kXwpdZ2>O~_3)27mb*{iS;?!tpz2bk;XJx>LzzKhg z@;`swIyh0bYqI-o|9c@W>uE zfP=hm3GIJfk2O-a0PS^I_+dR+cV2#db1p@{UG_hgrXGCz205=CB@h$Hr3rk-0a?bb z(r>2v=IF4aW4F|EeKB-7+hbQ;^eSoys7voBFe~AL$~C7!$6FbRUu^-DYl#T`@X^{& zMi995ZnY=52YC9qHSyN05awy+#9Ru0HwEu@q2vm+VF<{7s4vX2)em&jf5i5b+9PU(Y+VlZObwik3e#SkEoNp;}7>ygvJqfSm~n{ifUMLWr}r$DX*= zaf4X0X@-u?Sd^A--psWeF{S=8`kxsAJNWgli75O>ItRS?)>u^Z` z$lZO>K#bJ;w>VUj%ikLwxU9HpX31grPJ%wA2P7Cd#Mbv2+}T_G>wlfgZ5`1+QsOK*8N82>XXX*2JRrp{17?uvpdr%(4!^m)S7414j@P(XCinyB zM5mX3Z2#NVA{!el%KJqxlPUo_2tm!SrJy>-wNI6fO=9_1ZfAcq{@SGzjv zZj!r`^)F2#|9%z=*NAs7AjURgF45L}_WOFd+ZJ)U+0P7#klv3vGiTPT-Cu0_Xt@hX z(LJ9h{Q&MNBOMH-meSce0D!IHA#K-;zrRrhtrj= z!1r~FjvB_9>Y2&{0eNuKldE7oqjJRNzX( zlz_d9(%&ye+!;bn(7-RYE#WZE(=_9vr0Q#ou8TgdpanRXRtF2sm6uSI(3PJ;3AfMf zsE&4&KS`<_EJc47+MV_sxB?iaj?$r#Rmj@HDw$FY7Z^+E7GF!LVFkAo6z9_!*SZa& zHQinoU;_(IltF7YoqTOw+X2!s4f9w~c>rw%wkRzUa!>e7fUh8lhDdU8C}uUwnkaat zVq3K(8@DyAxF8v=NY6L8ui2=D$GDayH$(2GGtxDWyx?MUH79%BRGa{gueH!y7*D$sMBcLhd3Y@kI= z0n#Pq1C2Wv=jiYY;M&o-(xpXs!=_biBm#u$#qT+E6a_#WKuL&iv$!eO;c*L|)P$dB z$G)dWzl5g}D1=ag3zbJ!fi&2#@pnK0a5-Wz22Acr=f6cdLqv!h{^8WKdOgSY3zhbs zJ@AmlqR73k_{`N$W1){YE3%MzO{jV6QE_|}ftxPX38B5%!9MP5X`t;dCmG?c1ISo5 za03y=IwqC6K9J4R`100J9t%dwy@awYPiD-dCLyR`xDVyN2B&r0&LyF} zz?Fc*T(mtYm1YKSY)lS{4jg&Dn-s6W(QNYtUACvL0kb94uQW8#d##tEmgiPET~uYP zP~Rdp;kzpc|3H_-Cl4me=k6^?6YQDS{6HPE=99oG#d~pt0`+S+8R~KAmpE52GV*(G ztJQBOWIvUibsh64)Mj^KO0!_BS;{S(-vSqd2+n2C#8M=wb>`hyKqX5=lmID;zEmr8Kc0Rs0#?(R}70( zQpa4T?W-=5YCdr47OHFAS*y|anfKp26l;M9zEYQZERhiGyEz{iWH(*;)6)4r?;$_9ETXgGGaKgGew*TR@oH*7LA0K%EMS{2+qnAJmgmO8mjE z-V1msv2>D@11;dx<%_M)Y8$D~U~j>0>7lmi*#b(2%-F$OKq%g6KqzDlUF@x1qLG?G zM&q1l)x-zY=M%J;pVa~BcY1|l9ZnEY3Kdoc`*AAXM?&hsMotL7$&21nylqjrI!|Rj zArgNXV8AYx_@*Le&hryR+J3EP%MorQo91&U2}7CZ{#+&RCDSQd7XFR%RhWQl8YT1; z+@U%dcVa*CY^eZv8TL#S?#>cvNqr#=C(lxIIjs3?YO@dJlE!8^I$Hk zih!qGEHX0f)bzlq{WyHR9roiHj2uLmh~(1T|94%NHV>+k{{2IhvswD){eevRk#{r{ z?uKZ%X}Y@Q8&ICiXbhr=e6oIN&q@ag`j)r5iA}c=GeyGhsGLy>^6(09xWw^My$G6s zmBCk#jq@0~I{ETb0%&4d)0Q|PhgssjXVe$KY=j76IqMzs%CaX(%@VZTQ$LA1n3a;W z2d${EW>{4&f%@aUdO$bz7GhJ68jLLzPnB7jiI9ZNQ9Sr&3y&sRSi_+sI@1J&`>*MJ)zUF_Y-?@#qd#XdZ*bH5^X zz_k^IW1i1}qi_O`aszJ$wituc!_a;XcwZZ_QF@AMo>T5hc*hnC#%?vD;yn`wlypLZzK971y>afUi zfiVUI6}pCXKaC9hTD=s#c>wFbHSHUcDUKd3nPgSR4E^5?k8l&BKA&GsU8xI+w;K4| zY{O$l$}ESZNOY|GvR9am)(`*YBM?8VCtmHxdiIF>oJ9E@w#_ScqORRxsrk|uZUVmq z(b8R5y!8ts=sPCfR^F?aGvg77;2vYUJ25MB&AefF*pfz2&TZsSAo!+a~9V<*5ok6O~ z4AMyF7u{wP*AZbm72$z(u3ugHvE1j>=EEcVT9IlnnxKbf+KA1k8g}8ecmP#rJHPm!dNf;ww4j zW^dZO#tJ{Iz1s?DbGjjDe{o$Gvg+5JSSLek-gqvyUvFC=esf|bW=iG<)ZQGX{-=rD zLShJxL)qK*K;$1C_l^3Q_V>9)9MRy(u)ZR12VffFt`9Qxtlt{`-G~Gqr-4$(Tk=O& zO+$?^yaxlO<}O)dKKGVf#3DVsGtA<&Q8+)Q?z zwNc4{B!I7vb!NSTH^|n?WFQ}sPeA}#H>fVj++svh9=xoqaB2Lt6nO-S{*Md|?z6#* zwHO+ygk2Rp4Cn-0IhpS;@hy=#!95Ju+#3~#E$l1+T_2o3uu%0TV> zf7pA^c&z*XZ@gqnR;X;DjEp3inPo&|9riBSBV==+tjGwFJu(hL_9m+`viIJE5VCT; zj`OU}^Z)(+Zv5|D*WscK#COBQw(CLNBYB_p@(2&enAFs+bFjad} z=q#GI=e$s9>NZLxuqEJ=eD?rAzgGob1KR$re@3)LR(RuXKQU05DNXdM&9a|98z7&N z5TzuTi8(Nxg~9pSGm7K2bYNpOn~}}U$PB3|JaUnzVIqp_q3j3<;IJ~4jiV|02=FG` zH1URd@RU4DdB`CnAqhSY685Z2uaV+xx$356Nhu>5;UAAx(#wc3iA#vf zCNR6tZc?*>j9a-%IBo2HLDhPFL2O4X37tFM;ti`2sg8>wWys52TnwZOAIM}U9h8zmeTpXln+iOd55rDt>Ws5H6BWr?R_~2`6sCc ztdvaeKBrB}<_pcE-CZ2*<7BG7r)Z(umRumqdx{^o&+n(7T!B~vsXylFsY`heF6O2B+;QsPr{&QGPGH-YAM3Z$RxuPes-L2N*qE3N93Wt8Jj)t9nIvE*?*e8}M zC@Oa6tYg7fdBD*Mb2<8PtkMk=rjHujRomtH@F+TD2IL)^<5nqjazT_nJzZB>p%kvJ zyZJDGwG1{S7}pxehndQ&8rS&#IuF>0w*yityQ`6IUD*tX8oE1)E)N4X-0zp!w1%4HzsPdxh#CWRawxa-b!`7&SXx(3jA%EMop@c_4-h8+^vkHh6rZLxyOi|=)HAn{+xZ4^p zS%>C{G(5TjPl{Cnq|azOVo{-L3J#vhU2qF<8q9u_LjZ?^t-gBG0cG??T5nc|ki z(C8u6cGgBY*bvZYi<@5YYC$x6i~?SX#I8F!c}8J*4k9EO1JS~?sYDCX=-7q_yfWR@ zGF1%*M+-0Fb~^^hRba9wN6jxQ-maB3=6Lrl%$srf1`78s z2=5N1VFahjLMuq*Y-`x+2Q$5NA?I}_{xMr$(Jm^i{$i_Agbmp?*^6>$4t+%$@%~=n z#DvRYg8BMmgHDd7dC-*jMu*rfj$kJ&QJ0?%nW8wGVji6^T)Bh89D#GIB(hG(ZU&PT z!EGQ;#K$$LgC*{UHk_60nqiAjc60DYMo=3opv{hIlkW|Q<@}5|Zwy#CURzCBi7P!S z1rkX-FYi)-)SDsRWoOYXmaO?_?OJ&VS3G%ch7=pfYbbO`IcC&d4LbR`dB@A?Osw>_ zP?~{bw*8-pjS@Yv@lD89jy~+z%FfWXUv`+rKN~Y;_CQDHj;SO2!~2?rGg+k8*+S3B zDG8X@L0q2h??Vy_A(blDp){5!sV?D=(uWHAei$X<4EmOX%9|gCeFD5=xdC14MDC}v z0OWQbYxuPRR$kx}Vap*UR*3h^$3Bgml1D_ds8+6(j`ocW4O9-5+f%SpOx-r`GaH8f zuq>6xDE&H5k$Lq4Z;`b4}+^?_ez&97fM5^%Bovg@m&skv@AFiTBi>hy*TC zOxW#-GKnq4SkWPK+r6Ix5xk1 zjgLZadE+P_7yFpX6i^4s!iFHGY{K<3^~yC2T83}ovYtL+I%Nn%iB_p)1{NWQ4RO(( zZ%hxFr9}|-9S?XH;`F8sw<4?j+mJFh=uXkMaX-JH9H}62abZKxbAO&iUi0)JesmiT zYsRgXID_Wn3ObVZV0tZNYpoRc{#;wh^7Ee`sWkFf`tQ2r8K44p!AR2;ntl=5Y#Z(Ch;wU$TR{5?lJ0| zikz-2vm*UbNfcLMi%Rvn~wldw8MDZColzp5T8IPr-2 z4M?$^hpDOQ1ni|ek2deth?>{B@Aq%1#Ndd$i)0buf-y;2E&ka#n$*0;o04nPpx4&c z;wqoQ81+*53GS9pFBv2|QYP-8A45Wk)-%8M#WEUb4yNDs%GyIZHx5WwlrcERt~FG? zS&q`#e|z-37q5iVZ0REk65G!ImE3dP6vLum=4iQ>h^_Edr84pn+VpteD&({Oz1a8o z)41$0@$g{YTogAcwj5@ZiF$qAnSg;nV;&NHhAeR(x9i?eF9Bfsp7vEMe=lbphG$O1 z_1H!qxb_2YkFA1{^El_Nj2-|N#q(T+Enjd@t&bPZR_#Q7=q{eM5Asiz&(t4cOePT( zE~oHxudja|2`NFVd`e(JeTbE$Q806{!Tw%L+>4vzZB@4vA#0TQ0Z`+lh$*}L_%H83 zGi||+iVr)6AQ|@42O;)^p?hz>4e+!Uq+b4Vp5w^+ue)j`V)lPn!$HoiyvjqN&h_yk zvXhSAx-RZHC9dju)o&XOABbAB4Q_Ad7eTG{p2{cxO`;NEd9#$&L3JjVe1G!wVrIE0 z;_9V1Z?R0m>VOY?B+-`#Uvx)ZzDkTSPtRO>E>{3YyPa3MJ{{I=dLJ5=A}k zyfh`B|L~kB5*SN_Mzg%gLFlS$B)^1(k+Scjj-W6_f-;464~4ZS$2)_vu>O_sjk;aK zRYkbGRZLj8hA*hdcDJ`JU6u^XI!~q>SKW5c^OSAt!wRjpl-mx+=p9Sm(`|?MJBeqe zA2%iLT}D=&TlK>uGX>p}_*>)7Z^wI+?~-^BccypOGn+8kR~nI{xf=J6+bd@%O@CY{ z0{`Mg5!d3adqX~`m)Rf_kn@`)pF6N%`;d1G2;T$of#}z$WUCu>yzXanAYeuG1OORz zlG-FZ^I)8RrU)+d6ya>C^1TzdcX8k9Pc^)H#dp{dP(sT^V~MwIpmNy-E0=^0v4Ulh zB++C!x*J?{_T)|dNMyuugS%7!XE}ystk_G-$yyP$cgurbgFD+hgOguoI^OA-&xsT3 z+RL&wS0@)4Y(zrRz#W1VvwU)P>a^we`r{y5!&^|iEPi%oRy@nEk{HDz9wHItO1AJ! z!c5}4E16EiG->GhkJYB_;`vG`$o#M{HodSjx-Z+3Ad+)6jPrtXIra$@vdEfW3IAO1 zhjXN-K`+kFeG~h%J7c&aRrBBI;!}2}V>FvYspbAu6?Z_6AB~j;Q+A8-e;1a+*-p!tZyNxWwH2+%@~v^y{G zwOh3V_G@F`f6at6j9k9wX%?*_Nr!*#JSJiSSow?%&ksF6&+sKf{?VFVU<`Kov3 zTfcc7gU6#~Hc98Uik~dYyVCT1Z=xUAAa5kKt_on%O_j3y2mu=aolArbf<8Z2$M3dm zPmiQ67G2K39qA{_fN|yS&*!@P@-++6?S}p4ZoDynk&6Ff^?n@>F&X+`j4lk}{l+VP z!$$O{;So{iBBA|n2DAwi9-i0>*iOiQKH(P+S`XC~{qlbQjO%~CHxGIQWqIb4@XrbU z{ZZfG&fOuM=J_weSL_}r0$v0f8eI7|&HDGx|L-gPeZ~GyUnM&PhJeGvs78NYS=cWR z*B+|&zW4s^e*X9?_i51t5ISuLU4;zdO#Mz) zC<(~@1pNlUu31Jy#;?N9{pWPCoy*?eX8zp9ai_4@>HMVd;PYjl5pglX{^V@Ve{kUm z`dlC2-*^d$L-C`1qp(Mp@6GJ6oOmPfo>{xpdy0;t}IZ;NLIu7?np| zRc2gj0d1d!%fjnNPbPq4%YZNt*OR%Akv#>5X~~t3wv#~$n4^DxR2~XH5NNE?t)1qd z=k^wQOVvfbf8)vcGs5jpP&QF2BI@)t1f}n#qmH`8Cghx0v_FvmX&r2Q7A+t722Enl zUYwD?a$l65&fS(n^zw@hAX)U+f$hR{4v&VMQ$7P&oCo(H3y0Mw*(m5ueE`YjsEisD zB)p^qZ62(b&FZ9VC+Zdmx)6X9P1;SIp}-5=lSeS2Tt7yEwf=+sRT4B`~xG!`1z zvU()%i+RlL%ltgrzCR4jahxmNX;rHEI+`1Fuu%m;pp~M)>L^4$eS}b^zULYBF&XHX z&7b+VSC6N#{!xtlUf1w&&r+#Nan{~4z-v6}-Cc9Ol10XOhO?RM3Pp+9gx5*zz1Q~j zv~TBWs;9Vg%Ij;FxU`C8I_|oE*o*GTF=*Clffmcd2{K+XQg2-U3w+tSRlDXByPggg ziqTF^EC7B=vbs^n@3G(L%R<02JvjR@(fXGZlW3Km$qb|W}qR86} zmA6Zn7NC|j89>eKhHB&svpFm#(ov|lD^mlI>ShB0d@;tYN8<^sh-;bKu5TfWXlu%s zZ%2d{lKx=ia?zXQviVov(St~UMa+9d?vHqGeMGVySUGv{U%CJD@{3Ey6#WV0Y*Dfm zR4v+wm}^3e@-eibIWOkaVb76d-z}0KJ+LoisS+@UpZoY~_p-=7^eL;K&VIK1wMpku zBqL&4FG#e(^o9UlLn08bDBTB_AGbQ43VxELp zY+GFxrm|%Z{Mi&zl^2v4$x)D5^!niH7a6WF-$QW;FGxY)aydEPn}9OE@1#5FWUC8Ewz~)ZrE$ z=R7WTZT874y$EbNo-Y)B{f8S~$qQMX1S>=f-k{gOO?ZCT(0ZDQ*ZM&0__c^zXku58 zafm`k+-Z5sTbYog-|NAuu^yD{#Bd%;5prWbJ?_tWHD>!^=ioZJLsu{Q4xQBIqpi8c zo%il5eUF)osy=n6;d!OmQni#2E8$D@+KP`ub-<@|*{)o^n7wB;Y|&1j3QW|)V6zxN zIaO~q;E2DCzUJ0^eaoWlP^j)}QPCDuYPK=Q=%n6WpQ09CG_!#0=SqFgHSRxq9C|CX zc#vxLiK5%`3(~RDHS3aRW^)$VjB>VNv{-8*>FQBapzRs9fP^eHtukxVunr&u7&r=| za0V0zW4F3qbM;&sNx{@}K@y9o za~HU|&CcG_mExtnK6mlhuyJnRiXnjbo*6{%;spW7mX0||D0l);U+-YHQi=r9mE}xh znQ^Nk@@6=d+o(2N7y1tJagXlCHaFF)Qrvx4cK2y$>52 zuJInm^VNxn??#ll#;I^4?C+`;a6fvoDZU3X` z2|z1V3x#g-^u8~(+Ge*ft@bZ*+1CBk^MqyQCz$^g4!*ORtac@N$xOJir|h(-%glrx zG6qws?J-kWBMa0A-c8nPAsD#nZ;Y9Ykun^N&5l5bI>bUqil=@aY9M{_vF-|rC}vxNS}3w?AqFoUoDWY{VadKOEBze?LOpg?v- z@r$||KUe*lUrBj|DY#5tan=6l>3AT)p;u7Zb#B*Cr2Wms{NaXFS6E)JJDS(`oF!l% z(3M8^e=+@9bU1ku{Sg3h#~PSn*S(-0SbWx-Y_kDlt!l7-+bUE=vOwZi{GlWr3^lk< zGa;EFE;$TTKgt7}lgj;>@z#~Hfk)?dhrW6fCGyQG7;M$l2}ExE?BwZO5I$o0=2nkG z8Ts5n>8Nb%X)9zS zvD_(Hq;x*LzbJY&u8D@m%Q<&E*s8dSuC@?-g>tbH=?-$jtCC98n5{g^Ws^=HhYF2N zTSI9C38L$0MO?FDHVN*L&wC1R`DCzUEEGWe`vU@u%U|e+T0$;fhRBnOTG1x?NR}5^ zT*oXP5I*=xP@su=#VSEC47#vIOt#O_3TH81zhAhPd}_T6bUImiv-yPP*SlJ%)dObX zmHt{D|KRj0wI4p|!et=urFG=5=-5rVvQKC&bW%18*xvQ{x&Lts#{DU!s=NWzzStMR z3R^yqeO0^>AUo-9CPy7e?cn5R+e+W0ANnQ&Rf^@RMKkXs44>wn%3HW<13}(=%G;S^AJGtN9K{=NYJWF z`{SL{0D$g599{NggK96wKUeH=0K9H5T|&JdR=bx#eIu(t=cyqG{ArcqV#@@LTg3V5 zI3|KFJWg5}?8=prwAMae>gN6QX{U^|=;vpTp&;e2|q_ux(%q#M~T&$_W)z87nga=j;*}v6PHn?%U3zy)bPeBuI{0#E+fw%FC0` zns@AGh?$Frt*3NZkW(DIL2hu}EWu)5;0dMT@0_@VvMczsp8=azZIUw@Iw7xQ*N=_b zm7kR;)@1*Z?+kwh*(qj4o-0tl$pjP}#XBA6qEnW?F#J4t+7eQK(-D|?2*&T%qK>~Q zSz-7g0@pA&*@z|MnL+cL`SSAm4f?1bzU)=|2xJ)R`q3Ih-$;2dxwJn~o_IP-C~|)Y zP16e$eIw=`FhZ1R7n@yF?Kl*AZc(Z)#?k(fPp9DCeF#nR9hv?kAQl@zYqxK7vtEa>> ziPkA7IGo2d24|i&lWSa+?>(hWvweX!XFsX`BmWm&K*H_qwe}B28Lr~%w}<<&7t4YUh3|;tZRR>47I~jp{l>tA zaxZ)$)6Zb7KliP{*_Yp@Q$XY+PGP9~ZG$f0dH`=E+|U4$Nmtd+UP60AU7cns;#Z%I zHfq;DWv9RJ05CgA^*T`KW>}5hEFBX{8aPh4jQg5BWKGr_iX)y0E?wF(@Soq3;G|jq zg#?I=Fu>__YFR<;ecxXUW+RXm)5&puIg z5{GC4bZ1qwwQY=IVXH+;rMln|FvW9Kdejg%oZLWWZTCggj|PL|wO>}6^_RpbV$?*5 z4g|?Dp=pl_6J(yn8f?76qNL5M^L^WLZM~%B?mbzSGyEyVhJZ~@>cUxU4jaR`UhyXe zYP@*c3vu8T~|sNLwnKPkj%>46;BW zcv%;^Ca!2x&ZSpkR$&lXuiO`X%}pQaraWj&&xe`Io@}T4l(QOk=tbuJLgEyjW%t)> z55-yDv^5D#Oj2`QP$K+LdWCJ1$KL+S#p;FF}IgVm2_@p#&k9^wAY=kjYk zvmrs={B@$XB}tQRxyizON~p7XX4Ui_NGjbm}CQE}hIo<*aHi5L76S$oGi ztZP_|LxHLVmEooz_*NbFVcC?8xb5ZX@d?_)Qxs|G=+!ut4{m)PY}bmjgwrQd3( zjb`!Qs^dn!c3Gm;AhlZ)V~!hcHobYDvMFPh!Y$BxwE zO5v7_zDX6h8&OKID*RT7%vXGX;YrwbQLe;V`5BvoQGfNjl;f*mE z`bgMIQ=&c-ugNNeM4{T%scSJUu_^=#%mFj1{Z$6;a--aap1L0A@-Vg zn!IIN7%cB<)PK?J2YXy5UC$lK)d!*!!)x1M;FVdgSfurE!7P3}RG=JD6+wz5kLE$N z-IEZzgqaz5Q#?dGiopd-v)D?S4UuLw*ypu7Ofq8he6|VsE!Lr0n?Eabuz66MvK6}T z9wcJ$FEPFgHiI%OXw+oo^4_ZT=zrZw$8o|7ZHDoYBglR|nKgr2*0C=q+ewE{Y&ldG z9J`&)s6l}RTmPhHraAH&Cbv$2LgNF`chy@t0%u9hiz+^0=)MWyRt>Yttt_$tA zU0;(pYbHVd%et^pfC5LCZ=QbRmINAkG4SX(gJY0DgfQpvBHusonjtq)|Ov29RIC%BSd z;(h+q5fJGu)K-J5^gWXmhi>0IlWjR$b${bdJ{KVR>(cC*^917-0~|?^vMKM3m0xd* z7s}GyY#NoV5gmV3eGgEEf#ZEENAM4jr)KKqX%Xcb zXq9xN=sj#ISy6{gScM(VLQ5(s>Wk;v5O(UAUBz@CjHOzduah>dK$ibD9SE4pudsqd zuqa@3d(_MZ@M(>fZ6xP?o_I$86drK1_caX>aH?h|xGDSEx20Qoybb^#93Zi=3*nP5 zWZ{VBwO6^?fZss0P8{O-kuYSAlUW7IDChMiBoZRTA*C$^b89J?&rLxa+Qh@5%F^TBphHa63h|VI`x*_}BUTqt;|}Uc}aw`!tdbno}i; zrkPT%e>iqVkMQQ5F=j>EkeH+Hv{uYO8Wfd)?UWdm2{w{2T8uyF9eXvYgS_MAq{fj& z>`X}J)%qeBPOMK%NNmQ^&=aseM< zI)MmcNysGZoBt6ROZ7JILUSlpHSXIQfG4*a3AivzrpN~-_{^)EH(0=#P`K#+bANH` z>-#P&O^azbn>PAxbr-IbN6-p6wI@^|%TvgKE{ zPq*AJFzURyPU2{=0}A%wxaYKA=ZWPCpxRO6-L`omW&7Rr;rDMViYHRX!DVf7=C+G& z&!(_pwF1==m+&c_&9j9gbzWXOcBvs&RCLDRs(BbzNVdH3hGKx;Qur6y;By0AsoimI ze0cTg^K)2zTMRxi#^o4gW`*)KUy}mM&j3vy>3KY}Sis`=_)Qb%h2>z55g#f}#=;rq zVWw)64bb@>kFxs{P(C=pAEmVH(=0Lx)T;!K%gqe9W$g!9nt4d2nnP*o*t*|nXdAq^ zD*k$Mi~VY=M}-mgp1&h6NHdwC0OHGD=(YmVl#D{r#vbeJC*rwfNTC^A{lckP)Tb@7 zVl0)=EJ8)%i%oB0u-x&IA&vITo~JVQYL3Nn^N(pyo*;vfxR?*)c#Ja>$e>RyM~yvO zea*=R{KoS!Iman@Taghy^fHjndX~NI3nxcM>}OoN1qC#DP`ciLk$^ygQGX{BL5^Cw z(qsV4zuLS+yc|OOc9t%peSzEd2$kJTx#;#(KUKqd z#S69!e0gD1W%{B&ZxO3D&sB^*rwditX4)>-{KV)W*YV;=QqxR=U_6;D^_H!E`3Gqt z$M}%o;NJZ5K^=z@$LuGc3*QjxeXWBm0RGW+<3I?fJtJRKkFnoGwzr-2=Us!x~&eJ9e5mmnPZj=6I#V)3}_pIN#~nklhtb+uRu|$vi-32 z6O^rxsxHtPbk4%GeigSfic9~f=ng9@!cK%+N}sC=W%-g`@**mGX%_s$R;TFZ+`v&& z(RZu#%X&k;+CbljTbw%ON)?_qH#Nnz+b`C_#`%e!(dUu!hWLW^?s#(=P5%CDmAej- ziAjg3YyuKjaNDeYu-&=mVL7cu(2cvw($by&HcDt6dc!k`_^rpX#z#Tshw!ENd}>-# z%)1c$jCj$a_K}B&n_38EqJb_bp=ML$$8ljvKC5n3TxQT9u|MTY^pgDg^pT(=?I7*h z3ArDHhU01+#%I{`_3aNYt~;O8u$9ujgDkfhxxu|R{7zxvkHM}9-Rd$#6Cb;B5y{DC z_EJOh@~pH)F>>d9*Uz4YXl|mL1EfvE0N!Tlx^HeBLp#*tlsU({!tuwPz(JK_EVhNK zRDCxR%@KOb7f~x_QeTAatcd#tqFz=?83hLOBBA=aW?|tq@7ofps~0k!Alp^9aRJ z6#x-8sItsJX$63~jt%*>TQG88us_meSh|83$L3K7F`CMZK+?~I^6ji~*XiBOduVY2 zb0fiufuh-&x~jgXrHwnjrhgc&LIqeVOIxpGy2fznvt;WCR27AoJeXllLuu{2#gDVU zZbJ8$ir|rE-;rRuyzn&~q84pGiNq$f_tvNRf`bEtPB_4~(p@RLlG{Kt^b3A;v?AeH zgjZ`pYxvivzLpj8JyQ0ftAA`IFU8D((oncoWEq2Ilq1AXZRf&0Xg}IWsqfATNah2F zHvY$ZqmUu2S}}H_p(*%zRIt0U)@V2r%#v5jHmXpg&PMrbyGH-m9_W4EgCbyuLu`Q= zO`XtdVc1%rrO72lEKZ^e?(hV+@pG$XIlR61`VIZdo-0Z2sWI62j_0=jA$_JSftVJF zFLt?xemMsq#ljh-`z{rEV2;}2edgI&AHT9vQOW!8-r#y`rWJ=*UyWPX%hO@^M6Cb) zPoTLP?R1yFcsdzIA2h`XQ%rVDsrVFAdV-KwB%S9F8yYfmKU^!5#a9Qj+g+MGN{dNG z+L<~tL-udl06vN1tgp1=?UZnPW`}Lbcr}r^I>pxh;5*7dX+rPOGK_CWIp0jKJ zl0N_Wf4~aQ0=K#e#@zCs%m3$x|64vvrWeWgdatwhpOgCAGi?+r7Ds`C{l|bAcxXvK z1PuSH2=w=xKOM~r;PWN^%g+1zw5*^{3k?s~?{)gmS7&;89>zA=lop47ShwFF`XB+o zx}3`kSpWU22z1;dYv0pz|1D(5A%mlEY^webgFO6E>;Vu}EdH0e{up+C9XVVaM>vY? z&{#_P(+1wx{$v6C=cSjyhijOwG%N7W@&Eot*@|#P{UqD}bxVk0$f7}<^X9_;a$EoU zM)dvYaZPY$d-Z=}`sWB!C$K0@q5)9;JW=y@9vTwxG-I&-^RuU5SFpm|XsnNsA!iz1 z>A3w#O~ds4{A|k_=v76n!)k^#3Ss1NMgJ~O#n#M54ASbl}} znL-^e2kiOdj<$(zKVepU!T0N%O&!5ex&92b3L4k+!FX-*;~QgykaJ7&%`_6!LX*{~ zq8xO<&h@d@`dwlfi-1L`Es8ZV?lw8q+dT!(YaFEppeLTfKXAi@9{FQv%jgODs$8gv&sSEzn5Bxp`z#Q~C z=q7E>`Idr#@x1}(Dwwn`+Y*SzWQ+M=*tgR3n?j~?5ol>0hROBff2)(|vEdPGsi$vp zrPTQ!2=kkN6XrdQ=03L1F(3Gdf$VG^T(m3EzpU2x{BsLr|9R?uWwPv5n;n0=Lhz|y z10)jmTXVO2vbt@Q$2C$UUPs02|M9L*XN|~M&jSzl5$tgNJ%V1(t?)@yr$e89Mf5BV zwKO+Bj`_@s`{GSg6uSmz!~T*3is?HZ-g^4<1K?8Byz|G*Kc=OJ@wCuGI0q<`QyeIm zDfZl;s@z1AdOAAz5t{&q&Oib3&WO4%_Rjpz!;QhWf3xP+Dj!Gg2l6PY;|O1gf7BdF z)6Xzczah%Z(SBhYx->Fmw3Wv(*?(cW^)52-vJ|H7i>l3VTH6AD@LX|+M1e&4ow!d? zAK83yC`eU?J zVJbm=peMKUCp>keh|vFE)u~iz55^6aO_vy$QhXQx^84RjkhUdDP>zhMh3G z?S2ghvFxWuNglMNFF-AuD=N%bHmRo&Sfe9;Tt6mRZqBK_E7wLjg-6yBOi}@=X7$yH z^_?2pXnyfN1XI8ssPM4+sf2&9R(xwDaGZdW>F)%>(ZUsT5%QQGQgNal&(KyA*U6&_ zu%o2|C{&qf2vHP|1)hFOc3RabHY>#cQqrrsH{M8&PF7!;ZR-~o_vTJS^SThX&#&ft zT3lyFpd4CWku9fY%iZ=k*HSAjhp$i8R=wskA4}ngC&CsXc$!%62AUsaTUm;Z1H*MY z4<>Fss5FT?0qXsVBbs`bptTZ5K%_K|IV2J9^&kb3yF`T~7Nq!G7rMH1C(QE}wSw7ygu#Eb0o)9-UiZ*?}JO>-i%+`rdttg|JAqa z^Bw)FskwccWUP)~&UUo4>J@RI`!zKwy!Gz1~_aWN-)-d8e(iZOMmvzNX{xdZxzw?cnr#seUz%Cn5v!ef|)rz~#tp#9jGCnDlA zB>NyDQNj?^18?|*4t-A}vyR0~lWdXoxZtEY|M-*0Cre)@g0So4%+5&6K@z}sc13mC za)Z|~)B+f(!m7rIv?ul6KDAvKn8z;}y3ATqI`4{Nk|6P{h6)(OOJG1{ZE*JOY`q}y zO%?J9z^i_GdbH5^$~eo`|A)Q*amu@|+J%?TlkfY_-8G?f!2Mh&k9{A(r!(vthiE_C zh0P2q?<4Hn2Q`7*c+fRsrb4|*LHCqi3|^$GoOQ<(U%TzrO4QQf${QYHw7h@RbNs}Y`2_I&XrLeWL(2|NIv|aMkH6QZjPUF1Z~_2~L8#hB?WW(56TOcV zdJBRP(9CExx}Y)e=_!H5_5%19uGl*df_YvxNz|X?)BZNmM{OJC;h8A%;Fx5m%ogoqpee!jvA-O>NTZ72V2_C=y!CKYH zq`{jGmme=?hW%T8KT5h~^%j}tCfnJ*`{42CW#a`qz@Iv?hg_$ne$WUO2L#c_DKApr zvegsFrka05L-v+$(@ZmN*b&(BzP!hvec`iyED+rY8VVpw8v{q8GW07TaHw&5523 zzYaZW%ug{ah9sI?V$N>nM^>1AzEWh+fKfFk1NrE$s2&=#YUICJ!{M+gNUdZo!DPog zJ(jAG=X%8_*c714SB?U;bWa(Q1ROF^x`!zxG7Jx_pd>vnpdr{DEs7l6lps27DRm*A z-|HuaV~tuRA?~iw28scZ)XNlN3TYx8hDBxQZfZ~k3_BIvVMRF*v&md&g)JkdreICu zXaZM|!&Joa(RSo~yiILGN@@KdYTr9SB}lmZ(g(q{PDdv!_7(aDKJxsw1!Md~EL``? z^bPG6tgSBANsS$b3ik?J{cp8U(&>kcy8KcBUn7T(dLaN_VP0nVgbrffwMK4JDm3 zgm_;a)TgrzZ>a#iYGTk!(SECE|476G(IX3{lIyi+;f83xzNj(9j?o)&x-X&?&pm6-CIw7$pq$uJz&kuESohrO^b-+QN-teNYbYHb<)lR`}faTdE z3=$e5=c_mZ2gH(?vE`_w8u=|WB;UvE6@aT(x!+Q;>!ToJ-aP+}mc z4InKxUSmxe<550sp=9yKEn9aa^o9(f4S|giZQ`)(1sm0&Sn=c);=6%a-`)(Is9U)H1fiPQ*r{R!1LunrQ4MpW+ zwFNQ)*SyJCd0~?_B?r8!=I1!L+OvwGNVIQQ-$L}1KdG1VxZ_)4sF|v?0rS4vOLozP zz}ve+#-)=s)tk=}uUPW_9B-i3Ji7U!8v}g31%#0F~130 z7UAkK-oqjl4+4SMvKt!)ZUeq?#N_8%)@?22>Cj+$UYYSK=SViSoF$L)yAth{K2}e} zV{fmI-A7yj+=FDxy*y8X`{JM~VhpAobM5bRhZee=-ZdR# zmdSk)T_B@kXF+12wWO8Qr;#D1oP{wi#rj!F_45?!O6>v)*7hJaSo&LRu$p}GQ18Zy zksdE8N8%am?}LXwcyExzm}>km3N=X*^;oOOHy|_>;Cn^M5o@zA*>;iNN+l84I67@O z-1PV+oP?Ga@k2zM3xW>`3i0h8J}}1}0Hw>)j*;C9m`9X5mO~e<^Qo+bAY5sc&&NOp z7`bzr#{=3nYP}32L-rf)T6-t)whnz%5P0QVmjYcp71b}LKmC?82cTs!Qn5XcG8U7# zayVE{+htF5y%HMbVU9R=m)!Q_OLooc!A0rwYTb&ni#H@NiD;`^Rb_VvJba`Ks0Y=) zSXIMh^a*1-xf7{m`DF^P?3NiFXEr*Ez$IY!F>;>9XzzM= zhJt3gwp5&d71skJMl#2#JE24jGPVTPkUcQbN~cladhMXJr%ou~fd%S>tLA$|_0iS| zGAG^7z!8gfY(B~Tx}g}$UTXfL1lYkLC7|-h_|z&u%l{=%kh)WDf{M$U?KJ&B z0NH28nCre1m<&ZAVA!uaIjnmbZb!1z`UZj_lX6{ZKGbwz(%goejRtpdCMiY#=2oUX zY2l1i%&I-}eB;vCnCBJQEYr-?T(jLQ{EQr(g!~lix9TIt(`Bo_Y?qSd(CNiYE+!>0 z?Qbs*_Ct3p0U!1UiG)kn=}x;7x8Z#3a_nbNkHEjuyRuxul>S&q|n=7d-dhghpnMlb1hU3ONWyc+fn#;&L>dW zgi>ErOO7=92y)FY9xP{MV*9Z35}@s3!z`nK1!mDk=7Hmqpb zL0@8?XKU{`C(}^tb!BLx8rX+jO*glcMUrTZ@4{zSA&kLM$k<`G33yT3c35r53C#Hi z=0QRlhs?j!4_=ZDmqNKe|3;GRVEYotE4RnDj!qcRZhs_DY+WO-$=f+J+vLQi-ky)~ z0&{^jl@o&>#K}p42^5Yl>0B>i{(c1+d;_I)<{b}IPJcEv5WPYwm65cAo&Oq~q5*Ne zTADa_x5(b<5s)t&zNY7c8UfYSN1;41-^X`1ChxajiqV^PEXB%oe*6+bN~Gr^mTP#N z+o4(RZ4BlX*e(U^=Tw#T-Y=WpGca^&?oA65HTT_&J@C}VEQP28XRB}_?0_#vV-8)z zMKaFB;y)mPskgs|j`V2cN0-;nv?ixBx^s>Up?nQN^^&;fo<$8&8~54WJ_QBH&5kdL zznncCg$|MFve@~#P)`vaH<+(WbxZu%F{uoXjOE#PPwp$_oSg`_3+kGYW2KEA^l1is zO@Cr3($PrKrLrfE>K$|@Rbwuc-C z?)@x+3UNoq!kdr|CF{a5mK?ub834X(@N^_?-MP9ks=-C{OJI@kx4@!auLR;fLM;cJl4fD!8emNjaEM;Z5gP2IqHa-tAXFeF3V8>D>;g#gV{e(8>en`o zMEBx`o>Os1ajqM~edv@Yr$O(vqxMPa=Z>DxSfNnTMWgqimmFyx-k|1icmn#g6}MZq zr}QvR%jXS_gqYeHoF;lTCU$3nhM_S4no6s%KVMg<>gEc-GH78*!QRq(xjM~Y5CRMY1Q9hf3bOafyoWC85&mphdu6-69|1nlCuVJ415LbY1 z4XEMz>PL$DVRrg2IYvU**T3Z$B~14S9ObYDpmvtDEzKjwN5bGb=2hO0$9d?Sp7qLA zPL=d#eyMW)1|y-zJxr?)*Gv4;M6q&XE`|M~8t5HiF3vnRxSgZMzx3e2fMQ4VHQ)9` z-LdNpTeno+(iXI`mXIwIFy$|DUPBsJ>lmM7^^1{}4%SP?U?VKvzGsN#kJZ^{ccy2` zzZ4Met;M7U2M6%WUn?;ev5e~r_tqWM)DTPUfuajF@60kwkFR1`kR9`RVZS236iSxS zkreFnM%$dvxp%JtIXyTvdP96{#B_ z=!Vosm5un@W_tkW4Ae zDd8$szlrmUf%NI!EHAfL^TkTYDOqp>bjv@CJ~$?C*Vd{Y>7O5|U^YDzZff2L==9QT5wQBv*y9jz~2Yi3vGb4tjtuBbHQp_zc!b zbP0@%GG|8`nZDAma10ppF=8tioc(4hbG+kgc1DLKHTt4vr$uqn0k94r|=@&KaHWvvWKJQG%A>+Hnj|GVmX@Ei~GkpzsWT zE{UgpBZ%3`ppYMrE~vo054J`rdG)rlj!EQoqEEfb%m~)%MZlDDixp8I_Qhl7@_A8? zDgL!gnUlH{$W!@~fSHPxe~G+*;@n~!Hm^)#d&U7_w+-r#7_deCrT);_nz?k9OFslPi{DmBt*@>S{p<1weQTt_zb4Ko7_2E$L|c}ZW8G7S+d z#F>H2?T_IvLwOG1}sEeqWPU+IfgN3 zTGHw^L~f?%xy7!={g*tXzvwz8wq0YZzlNS>=6LnAC@4Wfp^jo|#G(gih%}wh*)x0$ zw?U^m)O?o|p-m?5sYkXzJ$ShR?ekHG>R75dPn#9#zZP|dmfssjrWdg7?kUg6eUH|L za8UWb%HWy`dSvbScjB{;0Simlxag7X8&YMLF%DBafea2GudBg#%u=YHNSw!654J8h zWf^0cotcS3SY{(JbZJaJ-f%QnZX(zL3#(}nspUrXwj#N7MX1w@??H-)K~YtQxv^8S zc$bte61#(Sr9VGp;wC)@iT9&}?-%hnawkeJ-N@qV&($D`a|jSDz~9LNN!o>qmusVUAg88OQIP13cbkEsUjRxeV z`ePNG)qDv{$+?PX1(+YT5h;chHQ?zIN1nBsje}IUV5jAl*k^L(Ct&=~swh>H5WNpg zMyi}k@gDKE{%%I%F=JB-27@E20 zW9H{b))g*$pVe7s`*f>KHVfut<8?6zwxp2y26?;jo}%shLzQ*L&gXKoeJAfi3|Bu+ zXuL-a_P1(=Zx=*g`pMs_Q%q=G6Mj<0naGc-3Zj4fLuMvs%=6jd33mQeKxqi3-6RC{ z)GfsR2_7Iu!sWx|Za>H3oh(myX-;jR?P>R=JcHw}@9UlvFt_`@DDe~Hrqp|yat`}U zI97}{?)i6A2IZc!(oi_b)i2)w!3d~L=(TWWsr7*$F47xUMn1%oetuG zKSpZgQ5{MSWtB{?vyNPEmz6$Y7&Gw4{9o*SWmHvL^sfPuN=U0TD6Jr=gaXo_fN*G# z5|Hi|5K)v85CM@EkwZ&L9l8;u8&SHEt~bv${#WmZ_vwxC#vAX;9gKVKg?;v3d#yR= zuWIg}6``+MJj+>^V`G3rQylXq^U)Qt+qBP7kY?TE(aq&M6@9CV;Q56&7ZExWiqEGf zqVx)xUQM2t(VEUXvvhJ&pIEzmbq_ldn29DMRX>zvtqQkEEx#m7Tw*I>!#Kdm7^1Cz z4*?Fc*QY;sP+>THz_GZb_iy^hkyIY!e7Ix+EcFvKwXkd>N$jdnyhc%`= zx_t{whm}Z?j9%37kIVidJU&fB%C?<}4H;&86Zb3|=zp~}wU`mx(zIb|l(o5g=kN_`yA;CmeYRqOD7 zC?q$Jt(T!GB<^#+DI^2@X3n}Uq*ak00gWqE{E(H65P1(XD?2Fp2i^_aw0M4by3O?P z!Q}stNPfB0tec=q0$L&9kko4y)HlcU54>6j#wG1om1<&p9JjHZub6DS$J$d}s!QF1 zzc7(sNdpZ6>zx1m|4nFn^rYUB{IOuXdi`;9*TDq^$HMODVcRNH?p;is-7Q21}2 zijM;b$9Z*5^IO0C&n29JOZdQ}w!rf1hW(;gq_9D?JZoO;n*X0ma6(@~T<$%kpM~D9 z?;}mCgYLf6YuaM}a|s{N%$vpMr0%kRlPP8c;r^6TS&g#)=MsLh|NB+`bANu?AN^QZ zzyCgZk^SHEh!hXordp%#fQ<~Jtu3YT-e$Pn_DXbU(En)yNQ_koI!*|R+(>qfyk-FK zIN_L(3(PM@n`KLfRhN!HXq_I22=8ZyT`|0s4pzbuoSx}GmC)3H;3*EdjBCYXLslQ} zdTmc&X%sGy3i<_vuqY6t=^TK~-C$KKlRdbV*9dWb03c#I$s3v>*T1z~+?elEr&+ga zNs@flgH^t0_CoO5uPBV%Tk!aMZ!wob!?$|-wXZUuVF(*lY7zw??B#=j6Esw?jWM7_ByBJh(8B2rShU?*5;g)E z?xsNIqP9b)B=@~qo1w*{1M6sZoziY<`-_W&4=ENuC6*fj>Gj>`pT2x@$e@kJunw80 z#7qu)N1!J+>q;@ZUFrJkon;LD-9nr9U(OzOx3+TcXb6tG^Rjp{?_S*qUR}C5D#RIcX>h}Np#0j0+Z$*DZ0+X3 z(0}DCd|p=!p&kJZRWlU|a=pMyx|b!G;kACIZg~vYe<|y&$9o@k_K5=JJaCJyx{_qSf$=zfd$RShXXu6Uu|h|^p5vQKQ1Hd%nyr*XBF3f zvRbmL{)g4_R-*2>`|D9>tBM_ygS7)l<9hVrJafPu0aT!qTofk<6m11a2q!pmA+U`A zCrjTS0Y)WW(u}Xc>79YT}$SfLV zg#j1g{>xPZ{~yUZ=xt>OeJ*#blv$$+a+U_{HH91l6>~uMeZ!=U)k-i^+f{X{JxIa8 z=$b3_A|o^6b9Lq|2KeVePRImKYrLou+OB~OR-Xa{S)4t@c=>zxeq98=xnn3%q2!!9 zxJ5LdAb%z5@{10`tNZRYGo`4=Xf<#oh)A)gZB#883%I9*tLe9Z`hKwh$MQfTH0t&` zGlM0?`sH;6Ll3>Fm4Z4${6|U>gt*x z&0r%xYPc{-nC5t4)h0UPVN+G>NP8VZ>W~>Zd2dy#t+9@17`L`w6CcPtJ&K0~lbXyd zwX22OXWfdDjDNAd@W>+m7x(oi>+fZIyV)ag>koU7PkFnGPYh z+}yf1s9na7mm_6>7W%+JyX^JSP>~+!Z#mFBv3@?fw}&7CZ@%EH8U=#5!JSaTXmp@M zjQ7XeV7)9i#&D}$gka<44uh<^f#k_MQ+JY}!GlD2#^UR@guQXW!l;(R?mY#;g-7n6DSx)RY0eTks}6zvkI(tOr-#!W^jF z?bH;rf!?62QTXA?d1 z)8F7%ITM%v#w{76$nv8WPHN+{DIMBe!e{4x@zd@=V*JE`G$m`0aI#hB4MGgT_4QUl z%j4^6?3&+CPzpJ`iU}Yi^dGge$0wH*wSAf@Amp@=kYQl0#t!HFD zVp3ommj4YDN!Y~C-#v4$ezwoshjHQ)Z3ou@3~<(j}Fsv*REqITu*& zp56D%Ayikwjr8`cGKOl3^TIuGREF;&`2y`F+7rItneodHcet6u^QXI`dA_xJxKf*3 z92k(7M6Ji-KuHM_<-7x$IT( z5YC}t!fGA_4Ph2Q#hXMe9E4gqhp5Lrq zUcBHuoY)bp(7Uo6xLmQPh;B4y_~w6>hO}*HGOXa2ewqaFfP2l{FO3W=d&~pI@5kDF zW{Uc%ax*W*Qp9=b#?DI3j20pQ-}M$2A@@m?Zyxy87&8U+9oK$tjJaiS!*AoW0^zOg z%K-#0t>DQQgMm$hW>#xC#2PdL<4WO0-JG-qU_I> zZ3ItfJZS4YMoN;7K%>umO_m`QfLQZ}=aiO@PrLY&4l*LrY!;rx4j&VGOTCyQViU(p zc4OGDu0Q7nCH*NfwGXx&NJ4#PgA2Ou9J9!t+w^aNJEUB+R4`@hiFxh&tY)`@pL8GP z@?*#P-Qr4nfh_C>GD)5wnj`Hzt`pB4kqLI5jvNi|8i+)JPPQ6-(`2GERgRpA{VWG^ zX_>@pY?T1V;;ZJ0c%~y9QkY~4{LuwYmDs4|q`kdJGGE>T@A#D?qNAwcBQ6)N)(h0w zOJgUx{WQQLlb0t#!48uR@oMbO*NLEGo1+!Co>Q=}sb^i)S@~6I&&r~!f7^yp{U&fQ;Kl*ComPbSwDgW5jOhi8tW&nb%RTVkn_^@bAsen2?AC% z98dFqrb{&Wlj$Ju+=OG4ljzgA4etltuc3c{46f|0p4NVh?H-$0(2KOc5 zH=wo_S`M;ZS*~EPlE@3-ef7kaqj`p$W)4!S=v$(=`smNDqsTE3ZIC z{~0p95qZ6Oq=xE2W^VBI2saKj0Vw@mfQ7r_QC9WhHbj+oR#r|eKQ=pOiJ}UsRDy7- z@3|?HN9aNI!dN_LwbCbRV(_#-Dy)$k43Hx42aGL)46zaZhCa1QR@>IL4R{!Zteu~| zx6Jd4cRvd;Y`nr|4WAIQM=aze%I4WB)W)vTsxkdVLY9MiYjxx@y_q(8U`9bdCw}|J z(EiFqzB$bd4wKQ=P-(Z3RmH&8^-k#4wQ|jO>jG{e1oeAV;yWXXsqX1a1(I`da+R%= znZ2+5)*-7(P-Gk~2vaWynyHhVn@Xit`MPu`!@%EZ%;;v%cXD~~PcE<;k>wW#_O@n7 z+Wu05gAVn9ru|JzEE>5A&h-GHOKnU zJO?r5MlP6*f}w|}k!9dZeb1@rv>x5^xl%pv6GQkeZM=>VyjN#W3ROIy5b=0a!ZGT& zIo%#qzpWE{eTQjJ61PIWDhjt#da3lLOU>HMG9rmuxHLn!TYZ*pwLRydcp06s8g(Zj z5{zgncKL77tx zzh&-0mB&+GA#kSMI)1Z%Eb0;(R0W}TeCavwti!k7y1(|fO!WT7J3+DJz4-tmM1}-n zH{YnzIBaIna!xGkY*g&JPJg>gpHRGeIkh`S_L|dcHL~Wf?#QwZf0g>30N|t*DXdOh zeR1Hc5OehQg9hkcMg5%Pnu6{t(c^w-)YmjR~W|Ho5lN7af%t!tEx+<8e1^atVG(aLYl6V^g-w z<{7tqaO}Cz(Dv~rfp3o4XOqoB=QzI-`C#e;B)YW|-2;O^7N5(_o8ev0`?v#zANO0# zaG}hf3)h-t5+>kru0}^onPajIYfi-Jqvy5^Xk9l8^T&IYX{!}gZTIndyAM5m6CUT> z^0jb=qGd7aOljB79S|cJo5dSdGHMjtB!;wad*~#gng)fG|(cwNyMY zW#GRsRvG^-1iMvN?!i^G@?0uNmbe-v!8{dwOb9#0khs{F>&3_RZJipSSn0yIF`yofMwTBp`EOfujJBqr_n!ws|_gr}8{$(1%&fi!?uZ1g6g&ue3zS zdO_BTO^>-Jx1D4N%EV2wN0~bZ`H`)^1ouMd85UM!u8>5DUCFm*w#lzyQn*@jY{AK> z+^b=4eNM`;Sm^2=P+%WuUFke1r0#SWDGxOX&UsaRVPih~NQsPNw<Kp|& zJ?(97&YUSPVA?L~BGenJ7V{*Zy?h%zW+C89+Dng6AMbrSc?rT4GyG;;(2MbTK>UCrB(&fm^a|V;5a`^oLHo=o8jack?RF8hwHv zRKCevLe>i;Tc(*SdP~#>xN72|>i_hqKHt%91*5fwHf0SoTv;OL8|I^}hnzGqsRv0r zwQ3utRi&yTRI*+@4dKvqK*SkSmCT$ry^RnY_c9$8DeoAsnFq(2h?ZGwnr9TlSakR* zFKkGj;WSR-M&HL)!|=J8a|v;+TINa8Zogs0-fEJW!A2?H7yK4Lj)i8rZFD-~>K;e>)fkoqN$+$B? zrC-=vSYBn~=9rM5JNo{RhS5udBv`*rSAD^i7Zy9)ZgBlr8iB~R7?vN8{f4t+5eF@W zx;trOE2DbO?hu#N;KbbFp-N7v(W@Vnb!jE^d{E}vt%lN#-V?01<-U}7y7)USI=veg zHLdZAZQ*>T;u9d-zllBkeKzfBR%9V}Am#bhhchJ`5poyVFCNxXv-?67oY$+iu)_*m z$v2oH<5_x@A~Vmy!Z-sNcIp}84Rpy?U3`R zYmALxgKAl6Bn<~vk(Ew?UUqmK-U)k5yGcog^LT#xx0z9y#7mLVVMzPSsK8^lnJ-0B zUi`EHHqN=7;qfj>&(I=6{<`Ip$o=1Ul}$Sne2Gj;RdkOD8-wR$;X<2BvSnJNeqAxk z&feF+R;UluH2fM|^-yX1P_=&rigmB!wpL$(g}VFL;xpf#dj^mHnaBg9wn9L7!)lLcdT>WTh195y8lY0_j8we{RL=2*}a12gIkVPv79XteZ^i2tBr z2%Ywwz++lV(Vv%uan(fes#$-$TtAY4Ib^0{Z~L9{2Qd!b>{FJJl-f={Pj>lYp3K{H zMc4NpBw-SEuxr0c2o@D2S(?0K5pYb>=72XVeM$H77B-gk*D+~kLipa5D2#as9Ap#` zQ6xA5S1C3tyaUBLM*;;lym>g|IC#xf`zC8{;;x=jL=m^s)dd)a`<9TDat@do8~D$> z5q5v6<8A$2l}E{b_)A?t57zscB?FMc?5RF{SDVjFq;1ypB4l6DcA@{upaKQIj@Hv9qFRJ zBI(O(UG?xHsKbJs&iHT(q-_B8DX-|{g=fc$5ExIdG*yCKey6AWSH)Nb;V#8F%vySRMBv~aHB(AFC#>yyn>z9t>(?mIbD++{yTZnbE+Cqg3~ z|8?3q2NovNw5gUT@e6_~qZP-48=^rm$RWk>85}rBefT;($&$<=;gvOMjw(KDmF~>q zb8Hxg^YDf+7TqW&td9J|*k|0|jj|-{?MLV2u&RGgq9>;F+k`v%>Pm7?=ar|!Ae2s^ zuMwGGkS4rzs$q3pUNt<)(!kO0g28hrRvH6nIQeS)%Sw}m#zsG~WtSZ6Cz}Ygo9Ll`Y9lRsa9vjdE&d95#1p5?O28%LBE_a7 z1vDkB7PGV}-F>wTwuKg3ecZ;)@9fROeU*0d`EJo0T^75HntN05w2;CYzyV+32Ljnkt@@?r5RQoN*H_Ohkz-8Jd4n!R zn=X*M_tbT$t z#ByW1--%$O@Izs+4ST>Glzuzs+$96*c(2`bkx3HEq*-G8c}`?m7-MUiLCvjAqVLDU zj5favo>M&4aI}B8cgs;;?w+cOHz(@;XrZOn1%Vb(6f;8!MFv^IW(*q9+wd zkh=8jKZKh`PEf=|d-`*u_F3;XCnJ?pyNk92JxqAK_PsQ6>21d2uxQv*Hrts>awaBp zJ}R=w)mwclq(IE<;u9N8K+>i<4P*R@h36wS+F|Ge-1zQS(SG;gId2fT5vb?UcmTdf z5p1g@mF_en$2ccm*UWhlj)F?*`%;|Iw=3Caif&;HTzRRe5<)Nl{kQL6xR$P#^KAk- zgP}qh&g^&ge*BP9+b(7FQSBUpJ@%?upp*lvPHBXl-+Ajm1D$eTQUa8*>v)xqtc$vQ z{aN;liXOV&*!*`iy#co)O<^m!ed}^G7Im?nmHP2V+HyruBwIBevLmM?sjl8n*ez{q zxM{XD(VqZS-(~%T4C!9V6O)jk*Q+z>IZ=474Ffe$>S&R!vlrjwB}J<}Zg$yf*dEdn zrxI#Rn5nU;FcP0)ked{9@5xPM6}Xalq8)SG)u1~XQ=MnXBur^y%+{}4zI?b$YeRY% z|C~mYPNR0|wlArt6bu#*p*=pkySBB3v*!sWiZ5I9%tudWZLGA51v1KB4pyutl9m4j zd5;1@@;TP!d2m32T+li4J7j_9H&25vG@CkgAL?Ze0iQ52QmN;CT-xxIA|BEyF=^0k z8pA>!xPU3D>0P^IwVcDYJgf#CtWzf^Hs>clEi@iGCU#6l;)ZIrh2dHagUACz9l~Q+ zOSw5tX^bdK^1Yq*H^Rvk7z3FjsVZFrZ_xQuXhYABC&X98`%A!U^Wg24Jt0>PRm}+H zP1285h{p-BGbA+9G#pG1Vvg#Q{efao6|z8h>?oM%I=} zzgnM8uw4>?XiRUvESyAd^#)fUb?uwIoIkE>1n=bYKv}n2aR%w_wFYQmf{z33r+ibT zjjcIcVd4r3vysvuy(?G~So7xKg5s!!Au#_b(Xf_BBE`amotAF=T>E*G-+BgVVK^td zd5j2tJca1zVzXVTjz)Ss90)|^_7}Vz&`L)p>`Q*E11Ei6*7r-59-D}cSbjY+4oxF! zJlAp%2!CjC2I3IpIm2M%BAQOpXgcs4tf##Sf8f*e{vRnAw5M<&tGnvdI#V%#1t`1~lE!-=Z~QeYt`6nO2%GD}Pi zm#n{tvzW`y)CxGJ4^qOSyECSMRTF94U#$7n3LnGSM%yfq^%%h(huIR3f&)o&FAj1e7%C$9Cv2>;$_bPWxX zZRL!Oc7VCcQ25)3;`a}Y$6&jmJQgSZ8~yw3;qnL?OR5+mt>6FR_YX$L;6C9$Y^VF1 zZSfG}CUgp?+n#XzTr0nC?L!RihfqD95}OYFo4g@*A`vE5k4h}#7bD)zxCk8e?AF44j0aIOelcy7q#a1!}x#qF*RT1 zK+ot8_w8fPUw66ux%KJUzui%MKA`zZYDUS!%Wy_<0@e5h2al{OCJ?X@RWAy4%o@Q`qf$YpAOP_YAo4GD!uW-wnGMfBq7%JDz;C zE&Pi>^z+RTP8GlT0jLw=xMb|_wEd1E!Wg7vZ&pu4I7NM#)<%Kpysq(%=k+?z)ILAJ z{{7tmZk^@5+VI!cm!^YPip00&T?1N*$DUc90!dMMAggE6lxmu&nPt;tLGYMw2y*_h za*fc*kXMRFVZIhIT27~l*90;>y5w8JY;f^1Mf@_E`fcGCL-du*%r_^%nF41s`Hg@r zJ#y=G`u=|o3Deapp!zq1q!dHS0LDB^cFG+)lPzTLl z+d}j+xXvlfkS8W86&|h}n$JjB=wtbAdWxr4@2fMK$DZRc#pQ?hoIW)6Y&Lh)0*U65%#aM;>LC;lc3+L|$vf^#dN zg=X?TbYZ!Z^eE`?*(uQ8#^RqBkS?<9nY&W5IVgc=0jH(s8-A%(u^9qN?%GkqAA_3T zn-lFidON#r5%wio?87}Ji`;v4U<>Hom&D7_L3P@hfbE1t(0RdXT-gQw3;b5E13!I~ ztz_FAFTCG594M;_u+}XtnbY{#lO^`k{UTsL<4$?a2{~FB$S3grt@qKPaz=06F3}T{ zC%VgFqQf=jPu6}Rdq194E}B~B)XO>}-x9%+xpfb)V)^(hxN@eNPkU`J=c{~_n$fiE z>C?|lAXXBV0Y}qljU^Up00PG>EhTGWt+Os#4u0tD7}tdWu1o~)g&W<~xOm5rF^#Yn z0J%zMs<1*iXLnrx$65R9d*4HIcjehtT*BF*Kyo5@9J?@BFmF`*glIyT!XN`kB<#uX zm3qr7;VYqWy}b)KYF(f+)L@$fN(XpEkk1#QgHh4O5h8tQN_rP42h<)#C+eR*OA`Cr zP7Zw#iZP?NtEXfPR4T43D6Fq2EShez=HAS+9O0caeTxj|QGu80lchv0XwF@C$w5L2 z@5}ONi0q!pH@;H|{98&m(A$GDAYL{p9oSDBn5moAkqB=1aA+G(p~jqLTD(!95D``dOw0i zwl7Ob8j2pv0VBnDk<29A<=YK2`|-eH@Ns0|+ZtiR%#ibQ{o@#YavJuP++0OE)7iit z2-%poR}dG8s6I7;-3#xl%A%xYOcGH}M~^$7ISdvtmQc(>xkZN9UwSh7?(@%pdxe`d z9;O91Bl7prhW^1v9vx)xnd{CBPU*c3(C8_DX+6^I{3Pt(M}HpW2KL1=U?OfAkP~xC zuHV~zyz015&v)PoDmuMndjq|F+OTcIqH?ybFxsC$B)(_pqAv$f3fZCyA|awI(D;w9 z(72C2W{;>a;}Y4_z$e`>n%~;%(`IKeC5)I$(w_`NekZ3=Biu2CE3E2IdLa=+4yQlX zqjvuLEDr|zumozZOaILu#lSs3SX~d0;bR(b`Qb_;cc&xUH-(u?G~jj1nc6{ES;kRY!$HA7tp7&C`?r={#8FEp$)~|*gqFs zR7Y~^l&aEVi(~Qy_F@bbSg@h(OqP}!!x*~W-?gaJ2|35Fh8{{U1DLH1AUFH{Wv&g7 z;edr!y7i5Ih_jWShUuS3$y#%U12ro0CHs!_bh&7K@P*`&M|UdGik+8< z<&%+`hb~J`^2`z)I1Lvm*gk;h_z|$^;mmc!E`C%cCk^iHku97bRj271p8Xbsos;Fk1WC1aCDU+A8`Rl4!n-`54!Lh`MLE=pQcwRFbFRtd!3unNX;O zi}OD8xBD0uopp~i9|^Qke2PzFrqzH}hQq+Gd4C7b2oBuMQMhp_P(BnsZ%q^rFq-cb zO$Axb;EDNLhdRJ7#izR3Uzn|${^B_mZ`VsY&8@|uv^Qg{SOnA&Ko6MnetUeW$a?I? z7>{FdFwN2H2u__rwZswFrH$YZy+2A>zh`;!&sP?%60N>|%ynb?tWDhb=9m3fu+t()-84coeX%v zf(JbYiA93gQ#)~YDH?eQ2l86KVdjgT{J#SGXeXhRHrc0o#C!7m+0XBL425z&9UY7v zHFc+d=9Wj^tA>QyFyNb9vY4+EF->;E%y2D%T%#tAqVA~eZ2=YI?Eb!8D28y`LrzB! zIu={>T}*+*B);MoX6}#~wgXX~1*s%2N5y7iEavVzn;|-IGa92xfQrWUv-wf#K!RPxbg3n@W=kr=z)IM$6_#E z6Cq=8aB!NmO-_nbo%^e9U?i-8|IE;3RlxC&odSMGV>5h`zc#lv^4C(6rhN=Iw0`A_ z?cCqLEi@8+tH1Sp`}o(p6Do!eO;FH8-DLM)@3%B98yZMy&S-J|-J1Q}A$=&&-B!)B zhV-BQUB5{0p<-%ifG<)#YWZKTkv}fxiahKWkI6$+{<`@ixD_hU|np$U)q;XdYx#JGN8IYRD z;Lg=055=!BIJ|Amb!Qtul;tbj!FXo0W(r7m7^(AE?SQv7Rii&4NPQu8o^T49ZZl{t-AUs5Sj@5Tai{-te*8W<6EGM%hj6vNh zy~px3>(r;amCu(GF;;BtuPs=ZkRVaaN+_!5ii0D`piwGZi2m31L2C?mOQl|cu&3zD zh(hY^pcd8c?$<;ccAMQYf-CEN&2?Lb-%feZj_14Ll847w#^-MJDb8`F5zu`2X2X++ zVF4U%MmoA1Qk|!ZIzBvzQbuWlM;jO?y@O+;UXd#TJO4C8EA0zglrN@d(mAPqeYW;O8asI#I9aM*m|IA zC8=cwf5c7SW4o&jG{z7+q$#j7?+rx%6R1ZF_jbR}vH=x)qfZ{j6HHJXe%gY(0Xno| z-mEWMPY$GsCy+vkJ_84z3CTnJt>kODL#w!eP=0 zcA`3$&`pjfL*NyODX?5L-dQ7sE>jCAZiN+FpigLoB0gh%+ZGJ2qyd<6+yS0_1bEA( z>#Hbyd!LcjU3U5C(W9EKw+iR>@VRZ`mq4tdZG*zx6}C@L(3XapN4=qC;RTFOWkSZ5kx%E~79(j#Te=g%UJmIBTVeFxuRHs@!= zNcA4PF8X~f(9A@N&#TK;KfY`CU@QK`wTgs@ibGwN+p8W!O{>B~#x+QT!t*lqYzVZh z0vuwxi;B1qm*T;|RintNeCuUv+_i?l0+e68vSlxmg&!_IaZY8j8Pqpy&|>y<+PAo?-er zwvtBat&wnY_QY0SMXOrlc=0i*Qy=+qsu6`PCY!`-w$kTX>4Il_@Q;NJ zq^p>sTw|@8*?k>X#&0O+nnDImw5!JYAtB3#gf?fyQRwttW~I&7cBO zLkNikRZWiulCpg*nXZrJT;$b6 zRudsXYfXem8X=i+#!o7c3VCCtGWAEvQw2i941(ZK{@ZqUQ<^IWTi!-B$TSUZr1qye zo)mGA){rOS?LV(D$#=bY(|urb;(EG`x*?0*#NDM#qaB`x;6`hn09NO5@unqz6^JqV zdH^z*#Xy2Z?c-OH9$eA8`1mRN{T!iMeE2ZJXf z#q49Q(-+oOY6$jPFZf4b_rmIVr>!N|Uoq~x2c5H~^ZjDJB5-Jc>6_6IEi93da`&Rv z*Mf2|n2LNrV2f^ZvkI8o;;t!)?5~J(Xx>o=O#~%?R#o?cF^-QUNy^3XizYR(M(Cq? z40@9p99{80jpgW{_1|EkP0jYiGU zH*)S-Bj@deJhrhpwp-7)0cuVi7C`L=06MQS3O8yPRP_TQIs8sDpT1@d-uJ zWkS$>%^{%J^EpU8esWiiuPQsWc8;7pEwcw3;s2RDdaIKdyKqYcy#LYIAwCuP+`*QuQPI(-yAwq;k+ zt{St-MxUd(eAn(vmDRu|3T=IJn|1WFs!sT@ie)l3cTTO9r?m-&5~KATDN?8OdZO>f zg5v1y9x>!i7fSwauoqT=xH*L(zGO_cO~dwB{=W8Qn72jAgzM(5ubbQo@ls<|eW#xR zNj{(odkMvpwkUy|)%q0230!&SWe#d=CPcj3oEdQ3Gvl;md9rRlO5Fk4PLGac?A^;K z%}h<+@`k>$liHpWYmf$;Spg##0*bFKW9!I&7yFGO=qf>b{{7MHCCm)nub+2o4|Vc( z?i%0ym=atYl}RsEm=$$0<4{SquUzXRUhKMxCv{+gjl6qf{ zI9zPo>rYD7saxJ%@r|~LGz4ID@ zpiMWPBpA+aIK5%juX5eA{lT6uHkp6Io&Q0=(5v}}PxzNK?SwT<<;BX7y^>_#g?EM~ zg&Z2R4O9EZ=1I*cIS^p7k{SHiwYn^((B%t7tXR6!qW563(I;kQl#p>V35)8bPEXzlUh;#F z3xKkF?c*4!sH<46q#e2`$5Xo(rk!O&)oI{b=BINqkhAALSn+FFu zHrNUA1~G$mQAF(0Fxvjy>DzV^F57^^zlVe+f{DPAc7<6<(T*}$^`G!QNi^mUr&y2A z`%l&hj~H}X!)^c@lrR;W(^&h($)MTZju_sSH?~xkYVd3}hkC(8CQi2B^~v2QYQG%} z|7o>XV9(efUX3u|$Q&(;Pvct*-19;(UlVaeDYoC_fxQ)DAnjwvCUK zpL8|=D@BVunmN^hSQc+&f~a`U6sM6`a+ZH5CY=>9I{+XXh&HClD~E~nYz)%MIgbqQ zuN`?J6@jV=ETRq9LX+zV4iNRQ!YHRp{p(rcGjb!PPxUwx;(py-2%OaRbW~o+5u09* zaYj*=p&bw;B}D6&na=*}oI8f&0$sG*Q&-1!f;`P z6e&=X4?eOtK0cHreksF<9Rde@-l7hQ>cP<^q%St&5k_JUGzLRh+&~5^AhH3Lk!Q51 zXjApnDXuk1YBZM?SLrp8WHmuca7L=$9Pm96Tjp6#e}?;p_K6RsS2D2&ID7 zmTu-}HMmQdsqDR{T76tY)G_Dv`gz{)-8YijDBR=ya9ZGeSU!8)7UY`7TT+M1-ZX4P zd^L)Oy~yYnTzX%wh=8eK6!>NjxLZw)9UT@4VQq|+HnR!ciB?7h=0e+MFkNIbF|-CO z!V>YlueOS_;P`WY9v+-7+cyxLrY2pg)ZgQwTxdFf&FMMm#5<)R{qpHI?y9%nN`%qK zUvdvA0R2#>38{QeZ>E+y3=oZMX1F9*zG46QbW$F}+Q)W-@*_;Z(Lq5oZIPyudCz3x_MGE>xF``4)idHVD#*HagUeZak^(G8^{j z#M;#UQcT0JYfC~{8^iXzlatq%H0-tY$3-=Vfs3{r|E#Y6Tl#4#&n zS{xK5PaGQG<3jOryim`%_gqP2N8+tgeBy{>+pDEc#&<*DDeAEB%7|B7=O=t90j$xY zaVQ?=xV@@wK0A1Bm5>0^1E?CcVy>D!Xt)k`JQW)t3Dpj93#SPK`H0VIX+dJ z;7e0Gs}1qnh=|qmwF@xY%cS7(G#CbLj;6DAx42mB6%__V`BGWshCq~ka;Kf-EIi?5VCBzx3tJ33}K^R*Tu=VeKxMJ!0CxD6D zOIUfbpfo7zyth`+&8rHli<9n!Esr&7l=nT}VdDrpye%1wV<%@3ugFDri7%!%=e_x4JH$zL_e2I+}4 zu*p?^E3d&sKj{#+SMhEI{9h#v?(*UIp55c>aHGG<;GzOLK#pslN6QZreYp+JMCmw1 zXDJ5hOJXf~8ARBUoMDf$wY4=bXPsf28v%}5F*yg+7Hry~M0Y9mG+$vHLUDEHXp=R= zMaGhnzta2uNoT8K$3Lgq4@KeSJbWkMNbW?zS%ODmXC6VixP1rJ$&+?wDcqy3MYdCJ zPP+ZNtLNaW6YZwL9}X`Hy3eJMyi*m&jq`q5Vw{cDckr%5yMXjgJ2;&;42q=~EF0!L zYRp925{)r~ks%FQGrvE|6Nw&~3tjuptRs(y!sXX4zQ`bOCkLa&2+GI@XS4M)L7qmc zYMxV0Bb}3Uyj|RKw5-JLY1RybcF2WmoYs})w?{pLw$|cY)Ovm$_6hrXEYplW9oQ?QY4nH@tV1zb9p+ekp&F z5L45;xZ{?)u)F4|73>6ffu8q4!JwXyBtV%L9p}0gnID4-V}|xU(`Km6DIBP~Wf%;_ZG;v2hQ zjI}qe&kXg(IfF1PSbX*TWo=G_JN?Jt!G#KjDcqtZK!96PWVi;oXqgq&UFKn#DZGYSHY?8N=ayu$Ia4 zc8K)EOxb$-=cQDE&-P$`y#^^=l2=8BRV=#SWntVU`j%CC<7t=2!P?K9U*E>&ECoRQt!k)m6!)&&j^Q>ABo4vcSOm%G{Tr0;EEzWh zdqm8OnQ9ivmI`u^r(&fNDw0vGx5q}^T1)QL1;WNlDy&`{Z#b&!Y_V+rlX3Wy*7FdC z9Olv(#cHM5{v;(Ute#u76>)1r_(yka?cY5~;~f%C9u7F$!8MZa@pNJLi*RK***gy( z)jexdN3H|j@YquApPa^&g1A_T=peBQW-x!#HCw_dO+3S062IQv7z zjG!16Uu&ilw43hDY>yKR`c!;8UJT;YPDc0hN!03HXvA5J)ZZ}mKP`Z5opSB?LK8@9 z-(J|7j#qC%yA42od>kVq<9#;X%?)&$UU+)5;LClgKT9N9p9mPcD+pc_iB`ZKfAX4$ z;jtE*#k;=x9i$&xC4KsTC}uyV@zR1YoruVv3?F!crkH^fh?lQL&LakGAjpxgQV;5T zuKl}N2e?cfww3|MZ#$zb^foXRm4mpw@11;8=ld;(x&=$md4{~!ruXo6ZD`K#>TW>>%5MRL)CTs8IJb?|KZiAenT!G|4ffBTHZbryF%5O7{pa?v!-yf;zppK4Ge#iaD6Yz=gpAm_u{=>vCJyp z)GS%8KW7BHS00p}cD?K0>d?+4n7Ch~z;L1wEOwLyaB2Qpj@S|peS7G_FR5j)<-%F= zMle-kepy57!x@5gq2j@9=L2Y6M0JVYsI_sH`A)Vh~|SX9bE4zwEBy6;4F z#9d3n@Mdriq5SiS`pf{+#ZllT(#fZml=VwDqe*`0{Wu=e!n~}h+~twfma}+{~4pJnb=p}YNo-C~PewQHe zykZ}GN%9~qCtk$xMo!n=0n;YLzqf@aH%<&_=1c{t-`gmQdBLO3S?+N049$!3SnsnQ zpE}NxXLDpqHs4*-=v^Rw(lniVmyY=OtS2ASH|csgHt5?%0U4NC`EzrS2oNhIMY?`j zmt)~jv)>Dq@6T5`v(#@sA9xqZiWwM{XKcisf1d-9lK_}_b#`R;G!s3$1U+rJj-ejY zRAgxAcsXg#`6d_8SNCH*D~|{49$(<%)~!pZKw;F(Is~RH8JfLu*6~%jXHZv`>rIh0 z!J<&oO)fUWP(CJ{y8g}n-*0_%lvp7N(x;a7vPgZ56k-#daqx-2-6M!3k} zpLjHV2!>EVea`?oi8$0-^CI+N&z(V!o&x?oyRO&@>!YIyxBEjZP7v@y-nLcAH?o6P zFco?q^4_d3D^AV&WNS4& zIy_i|foKz$>?Q7P92SHB^tXwCqs$C6gWvUVr?z0NP`m_q0bhZ;(NiR{J$}-4GKk;N z3kFWgr4D8nJaFy#noi&RmX%o&V$l{uE)7;J7-3;_d|~)f#fVDaqtKnS)bZLep1VN( z5-1tz$zHfKA~~bmCyrGH*nGYf{Wta!x`<(MITzPvx?3amBmaKV<_G3mvHpatx~Zk( zjpwYJVf1W0CSnI9XxB88mM0|FfW=37-6b^B{d?zQz7Y8gwUF8Jm`3Y?yt_D`Y7>MH zb~jYM%n++$$wLlxWCOK@@p8>gtUHc%r0V@b-jq)o0Vc&uT8<%Ua)HUt#}B}XyH2$d z$l&%|AN&M4m4Tx);xtmap`0RZz@k-%?8paE`HP8~vmyDmnPr6Ez)vIBvfS5kdu5^v zR9kGXEyXXc!=$kVqE+K!YS|xMt#A+<%ry*fnC}%{eHY6~p;#d?^2sUfIgbU64abw4hphTs^KXLYzf<>4N)cnE<((qUoO`V% zL8Q3c{qBx<2_U|nkNu7D>AMgmHfMX)`sT=hxEfmii+8vvFw=o(fmkji#wwwEwn|#C z9Zw!pBND+W`!6=bP4J-{pg9`9-Bm_`c;26gu+;H z=@*XM5&GDvzzo$WQZ7CMv3>`x@^|}&3q@?5UFS98bm0YX-5S}F@6@fK?6`WynIJuCM3Q=-2>C7i$!OvV1jzJ&rEJq7Gi;yE#b zk3I$zKxxknHd1>Zk6#glfFF+jPKd4Z|A0Bfr{Sw)+K0E*Y>13Y$f%${O^>n2SU$!pV2so$aC-cnfGxd(h%K5t^Y{7;DH@Cag zkxiHc8S957`YnI?b1TZxP!}kQR;EkQ8Ej-Hag09q8WSxb&SmTS{}XcbHr7bp`3z9& zD0xg80ok|B^UA6`bTgh^)SoZUDxsu9V4d+$<}96|7ruy)q`RsUWy+&bbioS-rxsQ^ z$ko)w=aionR2F4VN10pC_2(v2&EM21x0$%<=+Kom%KTUJqjzH9W)2zaUA3}?&)cc1 z&Z!m#yhOf52e0p!bSrdM^x{To8)vG#&GwAtZ_E|PlE2cHWy9;w^f|?O)KvI{N^M$DJ;Rfy8SD-GX|6lCAWmMH`_cppkkW>K)5s{FP zR8(3J5d=vk7K`qd5)f%gNkK|!MM7bb(kUq+ARvn_=@yW#cdotn^M5w%_nhV%rI$_L9&4IsM*r#Ek_y7+L z!&@Y!F|tH&Zu5<9LegE2!~?A)Xn`xwnh`+4tPw?-}kJUbqQ$`7Rn?VP=G2TAP1_DJlr_36>4r!6h&+#K46*b8dp%DCAz#3{Lb(@inm zo4!r8F1%S05t3aq-`apHY?2jj)BOaD854r4iC$d-u5xf?6xxfNLbrrL$Dv0>F;8Ej zIgT%PSuIp4)fI52sU8-|4rC7IecRtg# zUeNue7n9>~#n66f{DHnHRlh>J#1?4tz$jJ7h23JvbyHm8mW53wmmVX zG^3Ead)tP9IMXExDg0VqpZxx)^Fr4AwU}sU3V5=?1cqSKDK;|Ni`>K+axO+$F6C17 zj`p~4yfT{zY$(WuB&#=6y_IElct&~~Hy!r4orDJ%<{9cB*d=a>7~@LirsA0{`b z*rcwX&X*<2TyO|WdlAw#cBcJ7Lrf|&Q2&*HpKcu3oITQ1p>0b(dl^xDRrLuDX&C?c zB88-pXVq5|zq-qbhX}iF=ZaX({2ISHFt1+pglgCgK>}kq``5$er-Qh+h7c9oUp&1h zVMpyI>e9${zAAga0#_zgIw~A^0<#}nst$K8)bb~@Vc zo8am|=8qrIC7oO5=}Y_rZzjYY$~I%9OXWhgkjnS>;)FT~Tl_>`OZD%w#TWv(pj}a= z(f2et4VV2OcBJiX*_rmx!Dl1E)Fe)SaaB`BPZyk>LB_$xu0x}+9=ud0^M)m|Z^W{- zvx$rY`3S835j7)P{tgj{tX(yU3sAC{C%6c~A&GKa?KJ(HI-aft&*NWiwl--#->_TKkAB4 zxHZ}lLN%del0Wh>vw|d$_W78*+4pyzRgQ~&wr2e|JBJ6|MkXN*z)Z_pi48ekCS*5F zWPuN>QFh?|-g_#BdDSfx0yzLs{)G+hKKg$Y9-?T*FiRZv={gZB;Ne}VD%c#@3PJ{15UsJ{*x8@5pu;OkD_V%U_^wv(et62!wQUmrQC)oFb9B$2lV50lA zo9*VOhlkkg=mTHML_WDmkE1=LMwMm5C>6G}c{g)&7rr*eWNqSW=wKRP_5*?*%}j6l z1o^fjsrL!bj=*rv!FT~{kb>&lOuvaFK7-`dnvILqlqU+ZbDmGGBTuo0nL3aQiz%d1EjQ8V(VLf!hR(NGQ90pBl$GHO-871J4bQWnU1;JhYM zwTu84Bzhzz-+1e*ER7@OJ^3J0Le!oFZab3ZwrTF5CO9u!W=)lN{-FVMzw#n9aJ6K) zDst00-Y|jGIvKF?HzIDi|3T#bdSX0*4RI*P{MJ;?Ixmp56fGTjcW3effYgHdBKQ=1 zC1(sgQe04Y*gt>}V^r%CFi=Ux(3lbl&OMf5znHC`;;>BLgn+|OKy5FM;WW_32;?1@ z&Q6kEZhxMpguPvpsI96Q(Vd(G6s=R1nx1BddGC*;Gb@yXITmuX8q*ey#TJ zuoqZ1S*fc$u`OVTk*Zx87w+)cdBeO=n=5YZZ^g;eNm&)J7waE5gyopiDYqz))TW-|dVg(I;2((gpB8lL8A*+54Szt~QPg zaWF>O=8b!Px1^qd{{nUbXzB^x`+l$vgGBHQRQN+Qa-Arfm<40?Kp~sWlLx-RR=1|s z`X#cfb~6ka&gd_|VDu41-5L`9$hXl2QW)5I`jsbmf(Lkd~!q8j4wt>P~(xabW)JFf_4 zo3>rcGf%^Qj7%2CuX)Te;^X$NF`1w>?rvs+)0yRb<7x(MaR|-+mPMw;&9(WVcEGQ+ zbWeHsTxXhj4;$7gaLcl|PhhpB#z(vS{P`IJJxzZ{g2lU; zA!mPw&oksY1lxl$i$x~K6*OL8#=dc%#iNsyG-q>^X>o*}B{Z#iZ1q;Ep^E>I^HfxT zNv7Dhv5&+awIsD?(JB{ypQ#BGw4Z&8x_kUuU<6pkFqMhzM=*Zdq5Fdr>p~1RA$vRB z0cgOD+G2I=UwnYTu?MBU4qLzW*o{=|V7Sfe7jup+#PF_#nPIT^fmD3qyi=#o%nHZ7 z*I+I}R=Jjr;8Iz+{8vH!H~Qrn%m}~q_3sZiHZjCb3=`8OC9s-{gv@k#$Y~7>Aa~2# z1dk(>ATNjn%=y+-zBn%{b}N`aCn{$mKXB)!2N=k`Q-59M z*sG73VnkzvZC&QJ*(bj(ECjExSu?2;t!aMXg|(xdGgzu<}nv>mtg(iSkHmE zhz~Gxi`iP+fs@}B)`NMtHy~2)UxTG!3~lJMP3hX?Yge40rabSxsiFSQ?&`ULC!Z22 zI*g&DGu~H9F1Ciu`0LlhV3z@0^lQzBL`Xa zSYfX=J2(S-LuYo6g3DE-UGZ1?TPE6Lx_8e-xKBMhXQjw8d!mqSdKMk=ipd*WC{Fd4 z=V_T$G7&v1t{^-z8z_izJCeGIA?E@ur%!Uk+2VZ#prZd8DgJ?v5q$T&SIHm1Ayxh8 zuN3jNZ9drnYzJG)V!u{7{w?~mq>9A`(mXTbB49`$T?o3$_-bl zApz6E$$hQab6~1>5HGvodgblrBA2<;=Cyv4B&WDM*<%81xP5vgO`G6sb%>>yuP!Ix zu>Wy!xIlX{UMe7?=W{|Tc$}7D)$D*H7T%CoWixaE4}v4%k~qiBJ_Vgbs{6t2+C=DG z3_JFqNRR2{W9M_9PJ<9#u_}#9R8@L9-IA)7!0#%xX>}+!wi(O9rLCbJ6qz|$$6b!C zzvg77f(Ln}Ne2Jq?Eg8dQmID+> z@3izrfL% zZ4+67bx%grk1Ut0_PBR4*F^0T_V+4bFTM&Y!cNOy1|UIU(y4NN3W-W{U{WvI`F22n z?{BDGcp0E}w)L6oVHo;7`17(EwM3#BNTSyu7_bF$+v&jrG|!GGvUD~%==Z9K|J!&W z$1X~$bcLj7Ko8~AVstjk9VrjAoadOjz!oaa@YDpDSi$R zMXyp_smTW0*Q1Y)rD|(49oAb%UfjDecRi~1_t(vnOpXm|=sXw2=mzo8y87fn?(zxL zWiEBs%@r274}|_Wg{+WvsCmsd5=kX)0qmQ}{8p}Y2*jf=@*|>RgOV%XAyj1G`}Auw z5S>@9knMmk6x*o*YBlol;v@?FGU72@>~Vw8!hA<984jOCu&i1XjtFRs|BoA?V=4Hz zTfVLU5$HGK=Ip(#l{a5$SCSi^<;P_tLvZZ;ejoM0@Y*MhisyOX5)(A{fA06g51AQ@*haITz=w? zhU%ix@MqhEkvivnDX%eQ^t)u0gzms=wQ~s|J-P-fRZd54V+Qh_=qZi!7VM}*Wvz`U{y+?^*tBvEI)sQN;wUu$}-WTHcQ&U+Zdx|{$B5KLi~*cK)F%oz20O0#Pr*>zc;ŭQS=N!G(uA|Kr*0!7b&C^Jb065jS@EoEmi)5B zSm6#I;Zu$R@mnqL+;|`GD!Vmxpgj@8P~Efc`xyEUfT^X$Yy5iwPWLOQNdnw|S!onA zFF9<2+9i7FTg+!eU?e?7s4WlQ{@aIJ11D$^yl;Mss4CYslz^rT@m>Gh@~}%2oc`ji z|2p6NNq9i8Kn|n@7n7iL??U`NPjicoPYGbgpAZ`%gm0w!*0E8 zf2sBok8&-8a94f6g%rc)aOZ3OF(PieyAIVD@R_M7T=Utg=mRi`Ywu@A!Yr8)piTw9 zs%*jRbi0`p;c}RQMM6i=|E%NAdVz9|w$_^(TNt|J8@F9@88yr3F>ZTvqV^Hpq%f|*5dk(0}r`cZ{y`38h`bxD#(1TJE)b)6E09A8yZHW?wo zQQGW=3iW~qb7H8L9nShZ-S+Uz1aL&SD z>D2C}*G05OhwcoS9CupCzllL<$Iod_d#UT?e7IXfP(1blcXLj}#@%A>(nBobD3gx( z=md+X1rvV*nc770Fh3gy8vb7o2b00d9|{CxjZNd+4)W|8W+NZnkj;3lnqA;T^;f>1 zrWsxUP5`##3|%EmJJ!JdYt9uGK*Jv&UkirP)@UZ!R%=%}!w#$XJq6Smtxylxv`Xgc zSDQoEV_#WKd-Va)8_;pgYS^qUp|i@XjmwrnrM@Fhv6-#)1=q>@ScQ}S2j)cb1 zlo04ZJgN+ObPS_XvV4U&RYp>iBb1m~;yYI8Eke$+QNu>x-#Ta)$zv&8WB@;b8{UbZ{FMiS$9Y`!1fEZrka^d}{n6e+Mbfp23E|bIw&a>~ z`!6hFt|59CKGvS1POUjB9=4R;F2&PKE!FfRZUIsnvQaPF7L32~AB-l?!Fv;fGBG3C7pd28q@d#h?_Bb03 zf>)BVHR1Tp$Le}i zzSmk)>u;iL6z+6lU{k{xFIkAX#ON~ht081SXlU_L1!7tX zn_bXThHofEE>^_N&vk$GYud*gn+ZQ2UdQF3GTALX+B+Qo1aJ&bWA$t2>W7>TKsX*; zXqdN_M(qYZD3-gu&hK~TYvLDmg&gekeKO1DiZ9rL{+12m9lt=_IFD0B=IdwWQ50}PWJ&DJU#WfM*S50t4@)BLpY6bBY`1=LY%O66$@5t3v1IrL_(+%R43pXMV7nl)3KY z3+ktPt6Zk6iM?niFIyAKsliL*+T1?qOfPu`As@dpU%-XShUDhhtOMJpk$fMaD@Mcm zoGkM3*W!2&45PUJlW6f*|2*djqD9Ln;Q(|wJ%XF5Txb>?a2y_`&YF&9HxYY*IEtdA zF!8R(i1V$I0*0~I59MnDuUgyuKHCM>-znCkNDI`QH~Ua1*oIx}>j)6emx4zy{2YyT zx6?ipSe{evi$rCHJo!dHg=V0k1NlwQhSXuZUcwDMFEWnjp;qO(HDWu9pF5u1@^9lc z>k@}Zcs0si9iUNe;tljyRRNAtP)mO|iPpE0xA;(8 zFnoP}xV%_7>ylm3JdDUE3wvvY2_%s>^t9R%h07Cv!_}YM=q(?LqLd1;t73n*{pbWx zf^j;GIwU6k1K%@D*2~ucRCusYQ1qADy?F)csJjL&zFSEkFXJ6pt@RDUn8T!LaRQxvYAd5nzJz}K9_5*2Y#LpoS)=O!P0xUSVuZ}k%jAKdg z_;@^EEt3E_(j-O;tnuZ_UJ6MCZjB$5D@NC=EOvhI&y=4DI)4nb^0deJ6P)F6M`p?xROw<`88NPyuS&=%4 zDtrn9T#HTfw*0@E`L5G|Uj5E(ag{uA8A+vl0dGI-xwoDVbsmh*Tk!1?5I)&-@*g*s0yJ3aJY1jdI<|G1e;oojykT;_L5-}(3N;L5{r`ts^pwEkYfBWn z40JfZIlvu&Wu_yk*!VIT8Kc7j8sa-|wnFj+=Dk7C9A}`4VwuIkbsW$hRbG7th{x-( zu_w;iV1pM0gHerjP~7GKeNk?7wA4-#!_nzEvFTM#Qchf7?7^prBH5B?}?9dw!PoqQLbm>!A|*5FNA0)aZspcut*@ zYj2)-vX3v$kg7+!|_E?0$P{{t@=&PunUPY@rz zkNK4H3Aax(jISx1y14i^j78Z#2%iIZEwFjYo=yd7mOpEoc?;T=Xs9yhibSY)KN6ig zhc0}cD9q%m+wl3OVG|wDkc;jH9=BhEXBBAEJigb_K!jk2{xs@oizSs834Z6(qy2RS za577LGPM1{9xU@SR9uvMId!Tu!KdW?`g8|M?R7W=sMZ_~z!vZjG|5w7#P|l-H);k9 zyIhTh>5w5JQJ4jt#14)ZIle)>unS@nV6M-`63sBWUeX#`BWF{7v~GPBhmhijov1fB zK(+uu8r->9cOgQ(5DGdk0fQ>yOsVJT;1JmamH>uru^kRE2OWghE9gQlRb~W1L?Ig} zD~eP#cED{*3Y%;3Qjg)KIHl&rkhyx=S$GwU*G^ZqPGW*GTL^cu^i^I-VNvj z;PFI-&6^I#1#9K{`T4bg{)~}>evTz79~Pa*6H7%RC@H#wlZ2Ng8QHi7Ly zciqcs&ao->dyHEvwC^Q~%~XNWO2zx+W0h|SXtaFen(DXLrz@=k#$dcH1GK_##OOl# zg!EL%qu)IQ#-{Yg;?MJMPk4LcfgB=JpF%2fY-{FQ)KqIUuDsxvE2U4T6e*e>hVxh; z-Xs!>O>fTZg#QpwC>mfDMo)f3B zFz~KM29u1jFk(2CY%%2U*l*{Hv_)fZhX53dp%;+JOZXJ>j0RM^4#Zi|xbYV6mH`|c zH2Ri%r3n=KKNXK4d9=*m)w;F_2;Ugr&S6JPAeKR$)EnF9$4eqcV({xgG-QH?s7vHd zRIavmZhWgt*RJ2kS+jm(|9lpJH)$FQ80ux%njV zR{%*XU0MasdHC;z-VP!bjp9QN2r0|oED`$yo+*hdZnqn8sLs+O={4nAUSE9)-V1f4 z@2?%Lc)V$WvUUL4Q1w3ZlFo4f0Xtnbq_dL5A7XH}e`>#4m{h+LhB}sW3d{ zpa#B2HRhv7muP4>fiUG@yVG#%vr%hWR*!L&e5MUdBBFc+rjZ{Y?o4KD*}6>D0nBcl ziOL-YnyETOg%}Ggz(jlSj^>%Ev&Xlu7do(cxsxz?oG!OuMZE{?c;nI#AOm2Xgl0?- zBOu=tM(Mb1M2SnZ6%BmlyJh-a!+GWUt~Ge$J_x;HaCT$FPq^gNrVMxOBi`JT0bg*zch7b5FntF~_MS*i_wqmI_4yVxOyt93Ke$@}Mew zxCKBB27+ZUG+egeuXgDBDyS>!Lk2^GVu$74f)#vdiLzwlc!w9>f)q{}Ju!}Oql2uc zu{Sza@AgK@9AwlBOwB?jzI};uI^1_ctb)w2P^N(O1)<&YQ0c}Jkk%skhd-@9v*5-; z^ki;%kq><`_$rSkxew@nI6QsxB0BCnsoxT53@mvj)=vyyi9xx9Xdp_SlZYd<7`tfT zGF0ZElqMHY_`DHaFKjYOIA^AiYM1i(!vks9Qyuc|)?B(W@_0;e;ksUj2_Us8im5JHFUw6-ElCA=Lg5i!=b6ruzLl!Fl%nnPq!}<&lH4 zPLPUVzXd#<2MkwD=Jrc$4K`NqHnveN*Fi7W<$xhbL(@1{q4kS_bhXAC*FoUuSj`B6 zEKIekPbn3t>+x~Cc5plD;=PHStYYWA!$;-M*U%$ZZeQcZwy5(vdSnv8n=hVHJQMqL z?}~;vkNeRRG#(!+*o-mZ6itD0hn46*g7dVjM@m@7X|#hl{UzJ0 zaDT&Ojm_NJBk2R&3MPO+dM!!WkQjH&4v{@n>pJmA{5@e?#x^)-m6TCar|t2VS=YWi zs|kGdjBo)^B8+y4YeK*p>}U-GCPc9;i1>`$bWrwNv2n$PiV$Z=dLKVkk?B2^ZJf z4^P>GttVuglc^R065zA5T2?*od%B3C<&&w(iSR|;;7jgl5{g-bU2M;8viz^s4g}qm-J`9ScTkik-CNS1jv$t~f z0iPSkc`LtjG-+FfB5O@o%g%L%(ObowJS5COe4OZl8+LiaIqw{x-_q#Z>RA%#i@?vr zZGHa`p9IzJU+2HPu(VBGuF`9!hcQK%Y>tprXfA1s-4V#yylV7_(qA_VwC91MLp_&B zAG?rL@>StmeLvbaxj%dmbiGPB`8PMsy=~YC0iG4IK$g(g(NN*vOSO5GBcT3Kt9%nc zQ}RsClXc_&EV38G$fD&Zrh{tCXizTuN_Yn*26Fdm}lGTDg15x`$6Soe{X%_>09 zoE97|XIvCuAjNX;9=9b127o`ge4VmTkR-PPqR0YUu3$CHs2p6|ue~X13?x!D3l1se z?{IXO`$B!JIHdD@0YxjDA;woTef|#3jXU$3JJaD-aC~WXgUF# zu@^k&hF*<2nFLb=Al|oNGax(9n`HhBR*Cp^`1Z4#+>Io7vo#Qp{C}ad21^RK50;`0 zl&0e^v_Lyg&yR~v1cwI}rF3Qvu>!X{$Nib;DnUi6QvJe59RF~p^{g;KQvJ4`3TpdZ zKEYuMXYRy%k#As_zL4xz zcH7s2)9Xr&8@l9s@~L_zjz}qaTT@3R-kLD`y6PjkvKz^4R~2&}nmU4vZDR%H<45u6 zNGxl$v(f!>$ecm8{HfqPU=ODXyyYzs)QWk`>$+{@;J(0R_^+oK1JZcCRm5RO7i*S2 zWt&x`Hp1arWGKtlEM)^f=_qn`k6nkq!LQPM!paU@eTZ(@n!%hug1mX7v8F^sV5<5GUzAhCd|k z6Lzi_C*UV&xhsT4Nsy#x&PQNv=Cc)bg~Ik;VS?pfx|T&M}w zUG)*YX$JmdYhO;EpVd&Xs@OCzsI3!{wzn^sn_ng1<~99J$M-t85yEsyFRNU*au_=m zSPoY3pcl!z^3@zXLhc;7YVlR|1(iQv#a)8}-{RDqT<$=J@P?rt&-n)KTjS&7=JF~W zTc%1c*?mlue>^cdHEeeMSt~9Mj#;s(!Kzm2)6_DZN%T1!C@Ma4G#q-#I9-0>d!o%2 zfhT*n-p-MYK6-7c)kJu|)|XIZ_|?^`SEDkmYF%wU#%3y_^<{&LKT5}VHR2S&l{n|*oHFq&1V zF_vaC02%}}iREFGmNV>wtgs=5!&zup=H?V?mG`ZSWf7dj>80rY?A+f6`T1ACJYEcept-e_lz-wXG*>FbDWj0kr(*=3$s*o2Q@vCt$xfmQUqax4rzWL1v43M= z63nBHvCAj63Hav_d{joScj|aGiNP$Y-0_YD;aHY#ts=Sxmwbz9evm0f!OichHz5iO%c#XOx1=WvQ5ZqpFW zpFH=v`z|UREA+?XqePM)4J?my&pgP2?O(CtIrp&H(tyKLsKhN^yn9FY38cv|x>vIr zsbGSb@Phd+>FF4g#MhSv^3(gbWY`z#xBhurQtnu0+PTI}#Eda^GeION58jH!GbH7_ zz&2_J8#KGUqQ%QwenT2FD)^t&2ieZwzF%|cVjcwBNx>E{Y}OL_Dc}9T+2RGb>$Loy z>;8QJK_d`cF^$ktZ%WzNk|DIHcl_tCD{;Z@s?g=^U81RR?=E2^K$kp{-sgoEPA1Hx zDeN9tk?g#%S)Z0G1-10g>w=QU7Bx?PVyShn!u_}jP1MJ#x3HWhN7y@H{&Q}v1SWgJ zxyE|9jEPgdK(?%5rs>$bGX`$+nP<TFx^h8Qea+k5(;xo%%8~-A*>ffg z{#>Q{Ook#uHE-KZ9Qz4Hpm`z&^;7L@0{u(jLPP?!yOnpr$B5+j3;=ykmj-x}PJ{Mb z4QNm)gS$^=KiuT!NA~`7+KeRgBJZfx{sy|OLE5OFYlmK3o-W{AJ_XJAYNE?K3lm3t zND>+8>;EUJOGg6h#{gZLc#Shy6iH*);+m!T>NkKgMB;I{lMYM;1zxND$AZrmuk~aI zXN(%ctT5kohhR`6;9D#?E9m`x)Yz3hTVe*!;z*!RX@eKBVMxGi`NiHujHIWhDB8zo zlG6VQBlehp%O(m~>yjbVOvNgOMmnDW>M}pHOwq0Jaz1AoBq{=IvWVu0^jQmid^8wv z5Kag0h@lw96Sy=>=-3gcFdhq$UZc&sn6R_k=D#zz1i?WTV+XHoIR)ls448TI7St0; z6K?uFF|q)a0k^Apmm(fw>lPb-6!54jc=0GC-syswD~3JDvHbk}<*oHjNf|?!JfxNP zTDYREe$PH8rJ!KmzJc}nN%+C()9%)@mW=OC`$qavteV?557gR=V=d%UcAY{emw;HmCTR9u2dONC*ODA z^RJz5(DYoQ9iL zu5ML>^|!Z?o}B3)aj^La?Q&0_m6l+2`EvmZzVgI7A>wfuBdZZ~Eek_wW*{`w*M ziYne0Ky;fvgf^DYeW1r?_sM*i+tqd)B>Sx`TM`eRz*?m@UutmWq*=f7>R}CrX5zii zkT~#m{jZQ(bwJOG;A-A_D|yXg&Q%S@!w%;c7Qxp)2hf#67hq5Msl1dG7xz(yHbADo z#CF0EEHJr@Y@*;krE}F?yx6MqlmJoil1@8U_q{8)`s|*@d3$%Yeqw-U2+yS;$p0c8 z?zzjNi1d1-5K+A_iu=yan}5uF#+ISwD9oy%ahRTLUmc!GWYLb^S24dQQ2%43lqRBQ zD??Um)uW79?onv;N7bWO+3_rI6fTQDtWbnj52mXk2pwyyx5U?pi-?7pcP^mtvat!T z4mk;@0&!_pIQygb_PQ}seH9Y>g_t@p3tiWm(*;BCLa7?@MmxiL`2J-vMnNUOpAEqr zmkV7dij(PfWC4{o^p!mgQP^FkQc6P=PHJ67+?PKP_g#7o# zXA1=pw-P;{NtyPRIZzinl@RT2g|O5FI_^S(@^GxdUE4QYdFUrID-7J|bLUfa9qxBv z{m(uRgQ#+Gx;8>IQH;J9jv4nS31+GL$e%|B*}KzRoG;S94rs~fowWpu*50uP@--7= ziWf(#UT$RORE2;1*q?ZX`ceP8d)A*sA5GaO!DOI$w$lK0xKhd2IdDXvHD+%AFb{ z!p}a1wua;s-uJ-lj)wnikUb~q!lrR7@>B&MK1$&$ z5rQ7ZJvXMu9~7Tx*ah9hi|aEScqcAlH(aEhoghS|L8EI`>w_On$gZhD($}P#uR(Qy zj}WgpfJfHt>`d{wJ@9k%4+CU+uBiPWc2oGhzp0SrfPIcZH2A9EtWsI^;4&cf9)rB< zOxX&j5sh_caw^ZOTc?W$Fu6Ys7-}$AXWAcJ-!Pup#dR-3AN{mXZy(HRz(cC!j1VGh z(t)R_CP}ohJS>B8tl7f|wQjmR3oh&lURjzaL*a=PKAn=bZksBdN$h_7M$Q}HY?rgn zMgx60hv;*btjMMMzXQtusw+z3{;VjDrup$(F1v`oyxwPge!K>Q(c=cM$=a+*Nof5a_N)G?92* zP3>cMFMfqzN1=tshsSS?KLK^c_e*@lHG!1{U;$9z_w2x5mt2EtZz#d)+i-a`eW>u} zTdSbT53gT;ws#*Y$=ltgotP%v8VCOPTp1v#O{-_C4l7$CK9Py6O(Wu!mX-r=5IR&*kEl**3d znI$>p0a0xBS0gn7Ijax*>TUrC18G8A-A@b#L(?`Alp1_?4Np=F{?jUr57Y9-$VCYyTa~~AGGr#wO9j$Zg02W_94#BNCR zOIr87K&&T}s9DqET=~R161-3P#%?CAH*$ReJWtr=P^P0UxY(rQO2o$VKkaPpP)%fn zT&n;)%Fzr=J+ThtjcM6ONIFFGabE=n$A3ybHA6b#N5p;|RVf8d@hYAvezUHchx|Ae z&@N6vY=d^W;NYNE#RY?O~n%rVIwB4kL@ky6}0lj(^}1-|5l$1AQX4;2?EW8 zY=4Ri*#7jX3^0aLmP`voe*zGl(}@uM_AYk)lt41y8E1{x19ISV-99VB(2Ne4aV!2(4X_BvGU5ne$hksNJKl1=0FMSL5$ujaPCpcJkL=+SCi=ZWe%Q zAqL_WDy4+eqeM(7ywKh5hUvNzCa#gQ-RYsN+K7VF-N0->Z?}JNA~jgL!7sviar~7F zGS1eX^teA5BOj*pTSe9kAo0-`i)Az%;y>da2}|Ikhi$D^vh*4P&$DIfddO@$nd6dR zlW2TWWYS7_R3m8o&2%CDF%e##)Albt8k{6PCgz|1qn99=H zIS}Xu_v9O~x78HX^vtyc=a1LD%v{$n@V3Ok!I}H4)Akix!E$lsrL#~FI8--7ZsG4d zL6}yH7e?hWyX`fq-+TNTY4I{|(KFY^13F&;hxtg6a)1{+KKLJ3EQVtS-)HkkP+Mp- zMtYT`f*$N>;S$4q%{!Aq`j(oK95CW1DEsjskc{v-rFj4xfo<2Lr5wqt96P z1+=_6uV9faH`vf_MuEmh$mw^dIU2lFQ5VZgo<`C92ejS!Oo1tbiItlf@fNQL>oefQ z-PF{h_k$4Y&4ZLQBBDjE)@!u9iZbkY6r;uAjpp#;FQZ3dOfreY&0(x)29p=i z0-I0!v1{^>e8WTY;4wx(^~8Yjn5){DY_uqj?*Gsdd)Uri-}mmG_mKF_0q7WIY?S4m zZ(BsOF9T{nHSG9R@MY%~rh1)8%307qC4n=fO?mxLROD#iZpq3VJ6|bR-{Yge7MT}h zHcnqj@-{H8t*h&a&pPBW&YYhI;qqpPn3HnwYX?gXpHWVS9{Z{-n~+9@2aqM!RL=ozdjHr`8FoQND#mGugJ+ z$8HI3LODm_?T^Vsu?jA)u(#7;MQ4~aZVm=&BSD2>*!V1U->>e8WME#e5|BC(M}ZDT(6Qn-&Vl1M)3}pyn%i-_mJ1=5M83YSN`?S zS@5hXULM@{t$xYUI519ycgeSOsLD;I6enqON8>ji%Ly($9d_3z-HniI*JKdQu`AY@ zD2hT4LXD`G-&M}#h~V=7>SQdnf1cC9Tg9fwR97WyFr`suA2Z@O_etSDJt&(A-IYwQ zlVfdCDNNeUY0X@^Dd~7MHKWhdA>?`72z4f7yO}pcEtjGn)daHYDHuavg6h{xnuQ)j zWpbpgWq^tk%CJbN#~uPklEvHC3$&g^r}qe)lOr_7FbpM*`De1xBNJES_6Qv-?ZD{4 z-W+CAL-9!(VdqFAqYb``n?9hr6Q@o1nZvno5@4p|!7%4)GRXj`IDJMOFT09#(|dD; zmY)BN@A20f;HNGE3~4Vn91xnW8b_M~x&IxMP2>|nfPSrX3=um;`X4$~>_3{qzxmxU z030!2FcmowW{RQpVYKg_tNIrI=%fBp7<(FGV0GDdI~V``(HHo>GmSx6Cr|YSb~r{z zebaN=;Ga<1Uw_BKnEhV7UUZVe2$Vl&IEZHK*wB;1hyQa@|GkX=-?>xxe9fhHI!^Z=It>v=)A5A-!R~JF5;33T9m?0h%Q?+7z&=f}S|%_v%kq8M$|V zBh?8y<l;BzY;{MzVsjq0d~(d%!7imgh2 ztTOwFg22*nq+*N7Zu;Ugz)HgW{ZG|Lyu$kyb4$|8`|})M;!UFrluq@?In*V+KmMRT z{ZRa#vh&`*5bNXo%fEkp`S)8POh@+>ntDEeo$7io94_GKKgp%?SUi9`#ZIF-;)2eB zP~wMllvPbljk6f>dBF2F1WHQ^I6(^&OwEVBGy|&*CS!CVF{S{M*SeI$JsS4kca;R+WB5_V7(u2^Bqhrc^Gzgz8VFtrxojc_w>17{1VxnCFQ578RlhA z)?v!Fgx~^tOq)IN1ju`kMLOdki%1cMx5~^~Zs);&;qNdq>@F}fjl3Fac(znBf4W-o zrZFLAIcv^ZP@S5eGkCi3jhnWXtMtLRNb3FaOiw^9% z<-R!s)mb?3%*-jYW4AfZNQx()_3^15cavseT&N^NQBFWzP z!L=+vyuM&rC{W!r4&T$*EK0Op+GpKy+Z^0vJ~ac=?&}J7R!e+*eILTKz`+BX6#^zI zTp>6B1M^oKK$@ur2FQn`PU|HJ-(TR$=Y>M%iJ?(DLzcmy+mQlIghMF_O-X4g1FcTA zyVjc|0lNp_zRluU&_mOcmv|4zF)zlk^uJ<@iqPq zi-Pb*B%N+V02k4CmE+3FO}$#|>SThi9}AxJi$PrbHO!>JV6?(X36r=67}`T|1g6jC$;W7+N!@` zcvboXrFNe#`}Hp(|0*C@N@J{1RaBJ*imlTZfGy=n#naLge%At#;;yid_~&?I-5XCr z?6+31g~E2ij|>%=BLtC2u%{zf2#4xsS?#Uf{s>v{1(t)2Aw1i%04Uf=bJVD(eLLM% z=3r5HMIy_gL5QBe5A4vd)4FfJ9u?Kw+&bpFLT5xGrQ=mtNQ%pL>cIRMj*X_aGyVD5{ zn=W_(hX+@&YwJ_|{qZ<2w^gRIb3{U3-J|tj7mZu(KKK)b?`jS(lK3EshUJYcAWl>O zM`@U>7JQXbhZ8@N?zQZ^}s5Q9!qp-?P0m zF&5tZ^f8Uog(U3vPDck@8d`dCcO2#m3_Gr%P&)L{sbpt$^}NZuVj4qfSupBznLLuz zMrUI-dUY^Ovb2ioDX0|XXE5qW9A^7^hpr{;+-3fc*sH%@48(f=WJAii*!f10baVha zmeBieHfXFdnjAfFc(7MqATb5Jx8E)?vtJv#OqUZ(ylcJqjAc>e7nbNRfB5jB@E0%I zdR-Uk57R0ms|nYJTfaD5yqGQ?1s9S#ASFNh0q=O)e1y=An*s%{ip9AcDB|XAt^NpG zYCpoFJn0WtmYXpH7we35;A0pDn7S~DJo#e&WctOQykqG zaq2XrkgV-?692J%{;5ApMEuY3?bQo6F;E9gKdi8N2SC`)p63uc#{fd`-e{rBu@zam zJ;jLu-bXcM;1llfY~gupIML%o_&cq z&<&LvTPtXWa!dQHB>Bf zElqdsa~#jWzBe3_JLmN()!KiuiE&G54xV8^o~IQ_-fY?Iu`4*LDZkH1HJ-2Ez~bzY zZnnO=kT3<~IKJY6B}%N8nC0>n5zZHj`mL0b-IS+F%D14MJzM0QqM%*Uv{aA!P(o~$jo;{6O%U- zM@@2&7$k^KHJmP=?2Bz^0Y{ix^U9Bh27*>x)#xv;zO7ytiCnKn*+n)UP%secx2Ayq zi_37584Mnnq$9thMU>9uVOb=kV=~)62?yk5f63()`=eh;Q{vigeW4|tS5I$$j=|R| zcH(%c>ixAK(!`b7JBNJ|%vjg-lCq0`*AiZr%0zH?CUiEkCesCjyG2%c-A^DSYK-^= zs$#P5ICCn|HS-G=ZQo77U}vC>!U?$W6jLy$GL3y_Ncn<4h;l){%VkBb05$vC>#dwm*)3p(x zftHdYyG`7D@v;H=t%YARiAhu2l(Y|PSg567!n8J%nDun0?`TLIWkx%@vEMP;x_bQ$ z_CQ;zFh`Qz44cKuC_efZWZ_a$NT%ZpOj|IgoCSj?q5Z+%87Ep)!K_& zT5es9VMp~t(=C;!-(U}kRgNV{{UruqW)$AUjIu&m)$&s|@ot=rN4eo6T;sn;5=1}` zk(^Aq!c%Oex+fU~?6!IT?^Yqlm|kJ}_$g{Nmk{g!tF1E+hq7(Mcws^+>yWIG6r)Y{ zUC0_K43Vv|P4*}ah4k8Dh*H$3k?dm~OV%NKW(YHuK_RjXN+Iia&$}FNj`#ELVCI?Q zzMtp1uk$>Am#z?=!VN?XcK4nbXLr9R!DfxQlmPB>%=#~B75u^#rR59baG$$B?(`x^ zuY%+mrW!n#BSqxfI-aBl@fZ?xk(=a>XJ?h5t*^7Z+Ntb8E#0i~SJa5gIcYwGRAqqs2=lHR{>mn(^ z;LCdhG8OM~G}t7L$hm*N|8(OoYkUvlerd%o2MvGVjqhU){nHyi1{I{$v-eVfx^+1k zq*XH_HdEf_4EMYLx>d3Q&;!$St_b;A*k-vejFfQnLP6awuE?8U26yu!mkx}Puo=1k z)d%Y&1cXCrZEad4C)8w)`)3e~8RM$M#;D;2xPT<8WiO@@=0trI~IEJpq5#X(E#cQ zRL;m6SPaPTot4D+t#YqkrUb>_xw#m%Y!0#)P`l*A;dsZU`}!GrajG#_HvCQQfjYCp z@JJ~I%K4Z;JXU!frQAgBo0yHopC-hV-T+N&goqR|Xx_iMim*#t$cfZU1=Hs&(v6qC z$@$u8NA+imTr=IbDd3hDTT=V~e)Qme<{ zCK6QorC31MvhqhMvt^p&7Z_}vCMmfd9uX%rR{|`f@*<6$>JLU`Y0;b9ppSJe z05em13LTCRm>Abj1+C^h{raAD1%x_g03xkCB$E#w35npqR{3bUrg-NPeeIJ$dvG?Y z*+un!y{C?4%eM0hNtnnJKwPTu{zU) ziYPu__urY=VPyuQCi}@BX=C5-l0BSGO{7;>WM}v|*&XHfzj@yo!pw|}eO0`$1-cjK zJo?;53iRTRNEsrnkSr{cEZJ+vt66k;uIo(vd^-N;we^0S=h2%I0_dnh5)yx{uof>D zqH0HT#bfLKcIca$jC63gu`vwiPY;$(PXZPKh*9Bh7cskO2Wd0q*$Fzq{?yeD!n%ue z#Fb?7WnGL@RD-^MRld*p9Gw0N<2_>HMrk)Z)4B8eLGzk2G0sj!b0&Q7Nd-l|`dq(9 z!|wnQ%~Y|3DJEn~KEZt9prGgDqtSe`@$+dahB%BG<}1m)`;$ZfacZY`Lag$!f`T4A z$Du%58Q9|0(Of~Bt*Y4aBe5xk&TtMPzQn)>;peb7d z;`!za0^R}xd^p^Ss8%1gXtYR1(ZcTE`QFOCa^^D4;un z7+2W=0bYS97F-(!E37is&z;GKpOFi7U>HK#V{$Dl)VR*K`n%(7;W-Z}`3n zXwF-RRj2t~tBa7T=mS|cI=%N)D}N1ugcV#9*j+Z*GPqwVnmS=?Xm~zEwmsTj`FpkC z+EVSYpm?=C>=DrLVMWG$bSFQT&6dpB6*AYOC{m%N0Z|q+yRQ~Ex`%;AS3|~ygdq#wFWzv z%)HD2S1J>*GsznnRCmW_Z&vNmrKU~50ZiCVaB2w~{-(0{$QPxdf-L(f2?q7%mam6$ z%z4G(fjcmz^CD9e3O>-KZvQAY)QF|#{Vw6+F3TGwLTarU>&Zc|yJO$j#Qf7JGx#GC z!Lj4$&GnuH+E!p*lK9XTH%j6g=~&TqIo3|+co z=d8|`Z~OEMB(2M_(CVw(A&i{$fF%N$i8-eXvK<~m-vI@YoFOXz&5NZn!Y}J5|G}5x zP{iMn4Kbv|2k72fQEhNl-XhFqi-2n!=TAJ*^i3NCNG!INSs0=Rtv8079&PV>+?+&f zrgG<7FOP{2G|d`Qh%c`u23K@|ei;NSZ~9y+*I=KkY>3EK{Y$@@rR%I6$+~_TX4WMS zp@GQTo1GGV+tZ699o%`ZKn_>A@^LXdNPw>qAR7V~M`>gxY+zdgLA@D0^8+yZa@CSC zj9(he* zmEfz&iI`EV6V9Cb1ntf;wNJ@N-wbqO{JnR;qb1tKN;X#VGZ>^?tZLYDo<6Qrem9X? z71Ak1vcT5xY`IFdzk=DX-1<=p`QAztDZn1!51$-$Jz}seg}#Pp6SO^NeM)#}!u;ug zg3oDM&x8q0dxi(+)80IK6|NWpSqTd`u#m*AcC}e|^I28nIut55-1TJuu$G+B7QGvi zj$3m6ggU|@p`wajx#mn7$O}TWS=(p09*GBiB1TV=Bo3pD02l1!NFX?=da%#VSn`W^mNn)Cbrh5xjoRlaJp^{J2j28KRcAl zq+kPQ1HQwB65{E4swUuzVbhM5oQBP>+!!+w1nEao*Y(8@6H1^_XYSg?TTZ5w?X_Ck zgPd@w`#b0IHo6naOQVaPEi58d^yd6xSW7FXcmi0txFH~HcRPpY_2P%Nfm=4Uv)7bT z+)_gMy!tDBCm5DzRanj^yK4+)%%59aizbo3R5(zZsc`yYC+7KsNn)3PSEqSV;DwV* z`a*e|XgiJeo+r!sz(|@cGjcECM!Nua4de^zEqk&6-_9A6$D8|&%%iy^`bV47!b276 zbaJ!W8zk^PpBv5d;b&!VqM;mJKLHaOlZujgkardq`Zdz6WOSv(DO7XlZioYe)Kaj& zEgRL=G5W{TZr2U<(<*FzRnNV zel`Pejkb{l3%nM%) zo-{UULzWL6BI53+tcixAg?8=UoHY9Gg~yi^qLaajoO`0Q)2Xbq-5e=w#fqz2t(eV# z85Wg{CO+7~Nb#{RtPIHK>#4EkS({QuYSyymG3pJ@D!gw68KP`rzv7SU>KyQ4Ww_Dd z`>+~}SwaMG=HF#e|6+7zXydr0`nhu}H!Y$Zm@2*}7o`M(F;Pz?Zh`Eza%xdlIc!(_ zAgs?A6grkNnopo??MaCKItPBA7i`qY!= z!^{S#04IS>oU^j5G1dCA?lrw7F_hWKdFkfukCT^J4nS_(BmpDvQNZKr-uuFV@K9RT zHYWYfxNj#{Y&n>O4W`#65%0QBHSLBSA5)-LkVyh!=_!7!in_1rpJP;m41I)iEBw{A zewym5QQb1IE;HFpzWmHj9p*LY;?cy%7oPu0VRYTH9{?&$0*qQ%nGN?$M~&NB&0qQX zMBaN88;|9m&NFySarA}}RSN*0o#aZe(#^ zRpdF}xff@3=1ujQVet8XWe*S_Vxog*9B$12pOlawkgby*oJ;@RQTErbahw4PaA;yN z2PbX>m(S_tg9l`tl`%(j42G?sj^sm0~&zrVufe)c{VwwNHFYV=C+qvv|n~+iP RO>7VNG0?rFgVS~h{~wfkMwb8p diff --git a/docs/reference-manual/native-image/guides/include-reachability-metadata-gradle.md b/docs/reference-manual/native-image/guides/include-reachability-metadata-gradle.md index d931ba440a73..7df8790da7e3 100644 --- a/docs/reference-manual/native-image/guides/include-reachability-metadata-gradle.md +++ b/docs/reference-manual/native-image/guides/include-reachability-metadata-gradle.md @@ -123,7 +123,7 @@ For other installation options, visit the [Downloads section](https://www.graalv 5. Open the Gradle configuration file _build.gradle_, and replace its contents with the following: - ```groovy + ```shell plugins { id 'application' // 1. Native Image Gradle plugin @@ -169,7 +169,7 @@ For other installation options, visit the [Downloads section](https://www.graalv 6. The plugin is not yet available on the Gradle Plugin Portal, so declare an additional plugin repository. Open the _settings.gradle_ file and replace the default content with this: - ```groovy + ```shell pluginManagement { repositories { mavenCentral() @@ -183,7 +183,7 @@ For other installation options, visit the [Downloads section](https://www.graalv Note that the `pluginManagement {}` block must appear before any other statements in the file. 7. (Optional) Build the application. From the root directory of the repository, run the following command: - ```bash + ```shell ./gradlew run ``` This generates an "executable" JAR file, one that contains all of the application's dependencies and also a correctly configured _MANIFEST_ file. @@ -197,13 +197,13 @@ The support needs to be enabled explicitly. 1. Open the _build.gradle_ file, and enable the GraalVM Reachability Metadata Repository in the `graalvmNative` plugin configuration: - ```groovy + ```shell metadataRepository { enabled = true } ``` The whole configuration block should look like: - ```groovy + ```shell graalvmNative { agent { defaultMode = "standard" @@ -243,7 +243,7 @@ You can configure the agent by either passing the options on the command line, o See below how to collect metadata with the tracing agent, and build a native executable applying the provided configuration. 1. Open the _build.gradle_ file and see the agent mode specified in the `graalvmNative` plugin configuration: - ```groovy + ```shell graalvmNative { agent { defaultMode = "standard" @@ -266,9 +266,6 @@ See below how to collect metadata with the tracing agent, and build a native exe ``` It is not required but recommended that the output directory is _/resources/META-INF/native-image/_. The `native-image` tool picks up metadata from that location automatically. For more information about how to collect metadata for your application automatically, see [Collecting Metadata Automatically](../AutomaticMetadataCollection.md). - Here is the expected files tree after this step: - - ![Configuration Files Generated by the Agent](img/H2Example-json-configs.png) 4. Build a native executable using configuration collected by the agent: From 7047a6000c772d33baba23ff26b6ccfc0a396e1d Mon Sep 17 00:00:00 2001 From: Olya Gupalo Date: Fri, 15 Dec 2023 13:04:26 +0100 Subject: [PATCH 251/593] Highlight that type is required for a language/tool dependency --- .../embedding/embed-languages.md | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/docs/reference-manual/embedding/embed-languages.md b/docs/reference-manual/embedding/embed-languages.md index ffb0581821ed..d8bdf20b8020 100644 --- a/docs/reference-manual/embedding/embed-languages.md +++ b/docs/reference-manual/embedding/embed-languages.md @@ -30,12 +30,12 @@ The GraalVM Polyglot API lets you embed and run code from guest languages in JVM Throughout this section, you will learn how to create a host application in Java that runs on GraalVM and directly calls a guest language. You can use the tabs beneath each code example to choose between JavaScript, R, Ruby, and Python. -> Note: The usage description for polyglot embeddings was revised with the GraalVM for JDK 21 (23.1.0) release. If you are still using an older GraalVM version, ensure the correct version of the documentation is displayed. More information on the change can be found in the [release notes](https://www.graalvm.org/release-notes/JDK_21/). +> Note: The usage description for polyglot embeddings was revised with the GraalVM for JDK 21 (23.1.1) release. If you are still using an older GraalVM version, ensure the correct version of the documentation is displayed. More information on the change can be found in the [release notes](https://www.graalvm.org/release-notes/JDK_21/). ## Dependency Setup -Since Polyglot version 23.1, all necessary artifacts can be downloaded directly from Maven Central. +Since GraalVM Polyglot API version 23.1.0, all necessary artifacts can be downloaded directly from Maven Central. All artifacts relevant to embedders can be found in the Maven dependency group [`org.graalvm.polyglot`](https://central.sonatype.com/namespace/org.graalvm.polyglot). See the [polyglot embedding demonstration](https://github.com/graalvm/polyglot-embedding-demo) on GitHub for a complete runnable example. @@ -45,13 +45,13 @@ Here is an example Maven dependency setup that you can put into your project: org.graalvm.polyglot polyglot - 23.1.0 + 23.1.1 org.graalvm.polyglot js - 23.1.0 + 23.1.1 pom @@ -59,18 +59,20 @@ Here is an example Maven dependency setup that you can put into your project: org.graalvm.polyglot tools - 23.1.0 + 23.1.1 pom - + ``` Language and tool dependencies use the [GraalVM Free Terms and Conditions (GFTC)](https://www.oracle.com/downloads/licenses/graal-free-license.html) license To use community-licensed versions instead, add the `-community` suffix to each artifact (e.g., `js-community`). To access [polyglot isolate](#polyglot-isolates) artifacts, use the `-isolate` suffix instead (e.g. `js-isolate`). -The artifacts `languages` and `tools` include all available languages and tools as dependencies. -This artifact might grow or shrink between major releases. We recommend selecting only the needed languages for a production deployment. +The artifacts `polyglot` and `tools` include all available languages and tools as dependencies. +This artifact might grow or shrink between major releases. We recommend selecting only the needed language(s) for a production deployment. + +>The `pom` type is a requirement for a language or tool dependency. Additionally, your _module-info.java_ file should require `org.graalvm.polyglot` when using Java modules. From 8e62323d2de79da68295a6953cfa038f784dd3ad Mon Sep 17 00:00:00 2001 From: Olya Gupalo Date: Fri, 15 Dec 2023 13:39:56 +0100 Subject: [PATCH 252/593] Mention mention javac -g in Debug Info doc and user guide; Fix formating of Debug Native Executables with GDB guide --- .../native-image/DebugInfo.md | 36 +-- .../debug-native-executables-with-gdb.md | 217 ++++++++++-------- 2 files changed, 137 insertions(+), 116 deletions(-) diff --git a/docs/reference-manual/native-image/DebugInfo.md b/docs/reference-manual/native-image/DebugInfo.md index fef7e03fef54..6a448f24c8ec 100644 --- a/docs/reference-manual/native-image/DebugInfo.md +++ b/docs/reference-manual/native-image/DebugInfo.md @@ -8,12 +8,26 @@ redirect_from: /reference-manual/native-image/DebugInfo/ # Debug Info Feature -To add debug information to a generated native image, provide the `-g` option to the `native-image` builder: +### Table of Contents + +- [Introduction](#introduction) +- [Source File Caching](#source-file-caching) +- [Special Considerations for Debugging Java from GDB](#special-considerations-for-debugging-java-from-gdb) +- [Identifying Source Code Location](#identifying-source-code-location) +- [Configuring Source Paths in GNU Debugger](#configuring-source-paths-in-gnu-debugger) +- [Checking Debug Info on Linux](#checking-debug-info-on-linux) +- [Debugging with Isolates](#debugging-with-isolates) +- [Debugging Helper Methods](#debugging-helper-methods) +- [Special Considerations for using perf and valgrind](#special-considerations-for-using-perf-and-valgrind) + +## Introduction + +To build a native executable with debug information, provide the `-g` command-line option for `javac` when compiling the application, and then to the `native-image` builder: ```shell +javac -g Hello.java native-image -g Hello ``` - -The `-g` flag instructs `native-image` to generate debug information. +This enables source-level debugging, and the debugger (GDB) then correlates machine instructions with specific source lines in Java files. The resulting image will contain debug records in a format the GNU Debugger (GDB) understands. Additionally, you can pass `-O0` to the builder which specifies that no compiler optimizations should be performed. Disabling all optimizations is not required, but in general it makes the debugging experience better. @@ -22,10 +36,7 @@ Debug information is not just useful to the debugger. It can also be used by the By default, debug info will only include details of some of the values of parameters and local variables. This means that the debugger will report many parameters and local variables as being undefined. If you pass `-O0` to the builder then full debug information will be included. -If you -want more parameter and local variable information to be included when employing higher -levels of optimization (`-O1` or, the default, `-O2`) you need to pass an extra command -line flag to the `native-image` command +If you want more parameter and local variable information to be included when employing higher levels of optimization (`-O1` or, the default, `-O2`) you need to pass an extra command line flag to the `native-image` command: ```shell native-image -g -H:+SourceLevelDebug Hello @@ -53,17 +64,6 @@ resulting image file. > Note: Debug info support for `perf` and `valgrind` on Linux is an experimental feature. -### Table of Contents - -- [Source File Caching](#source-file-caching) -- [Special Considerations for Debugging Java from GDB](#special-considerations-for-debugging-java-from-gdb) -- [Identifying Source Code Location](#identifying-source-code-location) -- [Configuring Source Paths in GNU Debugger](#configuring-source-paths-in-gnu-debugger) -- [Checking Debug Info on Linux](#checking-debug-info-on-linux) -- [Debugging with Isolates](#debugging-with-isolates) -- [Debugging Helper Methods](#debugging-helper-methods) -- [Special Considerations for using perf and valgrind](#special-considerations-for-using-perf-and-valgrind) - ## Source File Caching The `-g` option also enables caching of sources for any JDK runtime classes, GraalVM classes, and application classes which can be located when generating a native executable. diff --git a/docs/reference-manual/native-image/guides/debug-native-executables-with-gdb.md b/docs/reference-manual/native-image/guides/debug-native-executables-with-gdb.md index 2ee54057f0da..a7ad816f63e7 100644 --- a/docs/reference-manual/native-image/guides/debug-native-executables-with-gdb.md +++ b/docs/reference-manual/native-image/guides/debug-native-executables-with-gdb.md @@ -7,35 +7,38 @@ permalink: /reference-manual/native-image/guides/debug-native-image-process/ # Debug Native Executables with GDB -### Which GDB to use? +### Which GDB to Use? * Please use GDB 10.2 or later. The debug info is tested via `mx debuginfotest` against 10.2. * Note that later versions might have slightly different formatting of debugger output (makes e.g. gate checks fail) * GDB bundled in recent Linux releases works just fine for debugging sessions -### Building images with debuginfo +### Building Images with Debug Information -* Adding `-g` to the `native-image` arguments causes debuginfo to be generated. - * Next to the image, there will be an `.debug` file that contains debuginfo and a `sources` folder that contains Java source files, which the debugger uses to show sources for lineinfo. For example: - ```text - hello_image - hello_image.debug - sources - ``` - * GDB automatically loads the `.debug` file for a given native executable ``. (There is a link between the image and its `*.debug`-file) -* For a better debugging experience, we recommend combining `-g` with `-O0`. -The latter option disables inlining and other optimizations of the Graal compiler, which otherwise would be observable in the debugger (for example, the debugger may jump back and forth between lines instead of allowing you to step from one line to the next one). -At the same time, `-O0` also enables additional metadata to be collected in the compiler, which then helps the debugger to resolve, for example, local variables. +To build a native executable with debug information, provide the `-g` command-line option for `javac` when compiling the application, and then to the `native-image` builder. This enables source-level debugging, and the debugger (GDB) then correlates machine instructions with specific source lines in Java files. -### Using GDB with the new debuginfo +Adding `-g` to the `native-image` arguments causes debuginfo to be generated. +Next to the image, there will be an `.debug` file that contains debuginfo and a `sources` folder that contains Java source files, which the debugger uses to show sources for lineinfo. For example: +``` +hello_image +hello_image.debug +sources +``` +GDB automatically loads the `.debug` file for a given native executable ``. (There is a link between the image and its `*.debug`-file) + +> For a better debugging experience, we recommend combining `-g` with `-O0`. +> The latter option disables inlining and other optimizations of the Graal compiler, which otherwise would be observable in the debugger (for example, the debugger may jump back and forth between lines instead of allowing you to step from one line to the next one). +> At the same time, `-O0` also enables additional metadata to be collected in the compiler, which then helps the debugger to resolve, for example, local variables. + +### Using GDB with New Debug Information #### Image build information The `*.debug`-file contains additional information about the image build, which can be accessed as follows: -```text +```bash readelf -p .debug.svm.imagebuild.classpath hello_image.debug ``` -gives a list of all classpath entries that were used to build the image. -```text +It gives a list of all classpath entries that were used to build the image: +``` String dump of section '.debug.svm.imagebuild.classpath': [ 0] /home/user/.mx/cache/HAMCREST_e237ae735aac4fa5a7253ec693191f42ef7ddce384c11d29fbf605981c0be077d086757409acad53cb5b9e53d86a07cc428d459ff0f5b00d32a8cbbca390be49/hamcrest.jar [ b0] /home/user/.mx/cache/JUNIT_5974670c3d178a12da5929ba5dd9b4f5ff461bdc1b92618c2c36d53e88650df7adbf3c1684017bb082b477cb8f40f15dcf7526f06f06183f93118ba9ebeaccce/junit.jar @@ -50,11 +53,11 @@ The following sections are available #### Where is the main method? Use -```text +```bash info functions ::main ``` to find all methods named `main` and then use `b
    `, for example: -```text +```bash (gdb) info functions ::main All functions matching regular expression "::main": @@ -70,7 +73,7 @@ Breakpoint 1 at 0x83c030: file hello/Hello.java, line 76. #### Setting breakpoints First, find the type of the method you want to set a breakpoint in, for example: -```text +```bash (gdb) info types ArrayList All types matching regular expression "ArrayList": @@ -82,12 +85,12 @@ File java/util/ArrayList.java: java.util.ArrayList$ListItr; ... ``` -Now use the following GDB autocompletion -```text +Now use the following GDB autocompletion: +```bash (gdb) b 'java.util.ArrayList:: ``` Pressing tab twice now shows all `ArrayList` methods to choose from: -```text +``` java.util.ArrayList::ArrayList(int) java.util.ArrayList::iterator() java.util.ArrayList::ArrayList(java.util.Collection*) java.util.ArrayList::lastIndexOf(java.lang.Object*) java.util.ArrayList::add(int, java.lang.Object*) java.util.ArrayList::lastIndexOfRange(java.lang.Object*, int, int) @@ -97,15 +100,15 @@ java.util.ArrayList::addAll(int, java.util.Collection*) java.util.ArrayList::addAll(java.util.Collection*) java.util.ArrayList::outOfBoundsMsg(int) ... ``` -If we complete with -```text +If to complete with +```bash (gdb) b 'java.util.ArrayList::add` ``` breakpoints in all variants of `add` are installed. #### Arrays Arrays have a **`data`-field** that can be accessed via an index to get the individual array elements, for example: -```text +``` Thread 1 "hello_image" hit Breakpoint 1, hello.Hello::main(java.lang.String[]*) (args=0x7ff33f800898) at hello/Hello.java:76 76 Greeter greeter = Greeter.greeter(args); (gdb) p args @@ -127,20 +130,22 @@ type = class _z_.java.lang.String : public java.lang.String { } *[0] ``` Here `args.data` can be accessed via an index. + In this case, the first of the four array elements is a pointer to a String: -```text +``` (gdb) p args.data[0] $4 = (_z_.java.lang.String *) 0x27011a ``` #### Strings -To see the actual contents of a Java String object, we have to look at its **`value`-field**, for example: -```text +To see the actual contents of a Java String object, look at its **`value`-field**, for example: +```bash (gdb) p args.data[0] $4 = (_z_.java.lang.String *) 0x27011a ``` + `args.data[0]` points to a String object. Let's deref: -```text +```bash (gdb) p *args.data[0] $5 = { = { @@ -158,48 +163,53 @@ $5 = { static COMPACT_STRINGS = true }, } ``` + The `value` field holds the String data. Let's check the type of `value`: -```text +```bash (gdb) p args.data[0].value $3 = (_z_.byte[] *) 0x250119 ``` `value` is of type `byte[]`. -As we already learned before, the elements of an array can be accessed via its `data`-field. -```text + +As you already learned before, the elements of an array can be accessed via its `data`-field. +```bash (gdb) p args.data[0].value.data $10 = 0x7ff33f8008c8 "this\376\376\376\376\200G\273\001\030\001'" ``` + GDB is smart enough to interpret the byte-pointer as a C string out of the box. But in essence, it is an array. The following gives us the `t` from `this`. -```text +```bash (gdb) p args.data[0].value.data[0] $13 = 116 't' ``` + The reason for the garbage after the last char is that Java String values are not 0-terminated (unlike C strings). -To know where the garbage starts we can inspect the `len`-field. -```text +To know where the garbage starts you can inspect the `len`-field. +```bash (gdb) p args.data[0].value.len $14 = 4 ``` #### Downcasting Suppose your source uses a variable of static type `Greeter` and you want to inspect its data. -```text +``` 75 public static void main(String[] args) { 76 Greeter greeter = Greeter.greeter(args); -77 greeter.greet(); // Here we might have a NamedGreeter +77 greeter.greet(); // Here you might have a NamedGreeter ``` As you can see, currently GDB only knows about the static type of greeter in line 77: -```text +``` Thread 1 "hello_image" hit Breakpoint 2, hello.Hello::main(java.lang.String[]*) (args=) at hello/Hello.java:77 77 greeter.greet(); (gdb) p greeter $17 = (hello.Hello$Greeter *) 0x7ff7f9101208 ``` -Also, we are not able to see fields that only exist for the `NamedGreeter` subclass. -```text + +Also, you are not able to see fields that only exist for the `NamedGreeter` subclass. +```bash (gdb) p *greeter $18 = { = { @@ -207,9 +217,10 @@ $18 = { hub = 0x1d1cae0 }, }, } ``` -But we do have the `hub`-field, which points to the class-object of an object. -Therefore, it allows us to determine the runtime-type of the Greeter object at address `0x7ff7f9101208`: -```text + +But you do have the `hub`-field, which points to the class-object of an object. +Therefore, it allows you to determine the runtime-type of the Greeter object at address `0x7ff7f9101208`: +```bash (gdb) p greeter.hub $19 = (_z_.java.lang.Class *) 0x1d1cae0 (gdb) p *greeter.hub @@ -234,12 +245,14 @@ $21 = (_z_.java.lang.String *) 0xb94a2 (gdb) p greeter.hub.name.value.data $22 = 0x7ff7f80705b8 "hello.Hello$NamedGreeter\351\001~*" ``` -So we learned that the actual type of that object is `hello.Hello$NamedGreeter`. We can now cast to that type: -```text + +So you learned that the actual type of that object is `hello.Hello$NamedGreeter`. +Now cast to that type: +```bash (gdb) set $rt_greeter = ('hello.Hello$NamedGreeter' *) greeter ``` -Now we can inspect the downcasted convenience variable `rt_greeter`: -```text +Now you can inspect the downcasted convenience variable `rt_greeter`: +```bash (gdb) p $rt_greeter $23 = (hello.Hello$NamedGreeter *) 0x7ff7f9101208 (gdb) p *$rt_greeter @@ -253,33 +266,35 @@ $24 = { name = 0x270119 } ``` -Now we can see the `name`-field that only exists in the `NamedGreeter` subtype. -```text +Now you can see the `name`-field that only exists in the `NamedGreeter` subtype. +```bash (gdb) p $rt_greeter.name $25 = (_z_.java.lang.String *) 0x270119 ``` -So the `name`-field is of type String. We already know how to see the contents of a String: -```text +So the `name`-field is of type String. You already know how to see the contents of a String: +```bash (gdb) p $rt_greeter.name.value.data $26 = 0x7ff7f91008c0 "FooBar\376\376\200G\273\001\027\001'" ``` ##### ⚠️ If the static type that you want to downcast from is a compressed reference then the type used in the downcast also needs to be that of a compressed reference. -For example if you have: -```text +For example, if you have: +```bash (gdb) p elementData.data[0] $38 = (_z_.java.lang.Object *) 0x290fcc ``` -in the internal array of an `ArrayList`, the first entry points to a `java.lang.Object` with a `_z_.` prefix, which denotes that this is a **compressed ref**. -To check what the runtime-type of that object is, we use: -```text +In the internal array of an `ArrayList`, the first entry points to a `java.lang.Object` with a `_z_.` prefix, which denotes that this is a **compressed ref**. + +To check what the runtime-type of that object is, use: +```bash (gdb) p elementData.data[0].hub.name.value.data $40 = 0x7ff7f8665600 "java.lang.String=\256\271`" ``` -Now we know that the compressed ref actually points to a `java.lang.String`. -**When we now cast, we must not forget to use the `_z_.` prefix.** -```text +Now you know that the compressed ref actually points to a `java.lang.String`. + +**Then, when you cast, do not forget to use the `_z_.` prefix.** +```bash (gdb) p ('_z_.java.lang.String' *) elementData.data[0] $41 = (_z_.java.lang.String *) 0x290fcc @@ -295,15 +310,15 @@ $43 = { value = 0x290fce, ... ``` -To see the contents of that String, we again use: -```text +To see the contents of that String, again use: +```bash (gdb) p $41.value.data $44 = 0x7ff7f9207e78 "#subsys_name\thierarchy\tnum_cgroups\tenabled" ``` #### Using the `this` variable in instance methods -```text +```bash (gdb) bt #0 hello.Hello$NamedGreeter::greet() (this=0x7ff7f9101208) at hello/Hello.java:71 #1 0x000000000083c060 in hello.Hello::main(java.lang.String[]*) (args=) at hello/Hello.java:77 @@ -328,8 +343,9 @@ $2 = { (gdb) p this.name $3 = (_z_.java.lang.String *) 0x270119 ``` + Just like in Java or C++ code, in instance-methods, prefixing with `this.` is not needed. -```text +```bash (gdb) p name $7 = (_z_.java.lang.String *) 0x270119 (gdb) p name.value.data @@ -337,19 +353,19 @@ $8 = 0x7ff7f91008c0 "FooBar\376\376\200G\273\001\027\001'" ``` #### Accessing static fields -While static fields are shown whenever we print an instance of an object sometimes, we just want to see the value of a specific static field. -```text +While static fields are shown whenever an instance of an object is printed, you just want to see the value of a specific static field. +```bash (gdb) p 'java.math.BigDecimal::BIG_TEN_POWERS_TABLE' $23 = (_z_.java.math.BigInteger[] *) 0x132b95 ``` To get a list of all static fields, use: -```text +```bash (gdb) info variables :: ``` #### Inspecting `.class` Objects For every Java type in the image, there exists an easy way to access its class object (aka the hub). -```text +```bash (gdb) info types PrintStream All types matching regular expression "PrintStream": @@ -359,8 +375,8 @@ File java/io/PrintStream.java: java.io.PrintStream$1; ... ``` -To access the hub of `java.io.PrintStream`, we can use the `.class` suffix: -```text +To access the hub of `java.io.PrintStream`, you can use the `.class` suffix: +```bash (gdb) p 'java.io.PrintStream.class' $4 = { = { @@ -382,20 +398,20 @@ $4 = { ... } ``` -This allows us, for example, to check which module `java.io.PrintStream` belongs to: -```text +This allows you, for example, to check which module `java.io.PrintStream` belongs to: +```bash (gdb) p 'java.io.PrintStream.class'.module.name.value.data $12 = 0x7ff7f866b000 "java.base" ``` #### Inlined methods Setting a breakpoint in `PrintStream.writeln` -```text +```bash (gdb) b java.io.PrintStream::writeln Breakpoint 2 at 0x4080cb: java.io.PrintStream::writeln. (35 locations) ``` -Now we navigate to -```text +Now you navigate to: +```bash (gdb) bt #0 java.io.BufferedWriter::min(int, int) (this=, a=8192, b=14) at java/io/BufferedWriter.java:216 #1 java.io.BufferedWriter::implWrite(java.lang.String*, int, int) (this=0x7ff7f884e828, s=0x7ff7f9101230, off=, len=) at java/io/BufferedWriter.java:329 @@ -413,8 +429,8 @@ Now we navigate to #13 com.oracle.svm.core.code.IsolateEnterStub::JavaMainWrapper_run_e6899342f5939c89e6e2f78e2c71f5f4926b786d(int, org.graalvm.nativeimage.c.type.CCharPointerPointer*) (__0=, __1=) at com/oracle/svm/core/code/IsolateEnterStub.java:1 ``` -If we query extra info about the top frame, we see -```text +If you query extra info about the top frame, you see that `min` got inlined into `implWrite`: +```bash (gdb) info frame Stack level 0, frame at 0x7fffffffdb20: rip = 0x84af8a in java.io.BufferedWriter::min(int, int) (java/io/BufferedWriter.java:216); saved rip = 0x84c50d @@ -423,31 +439,32 @@ Stack level 0, frame at 0x7fffffffdb20: Arglist at unknown address. Locals at unknown address, Previous frame's sp in rsp ``` -that `min` got inlined into `implWrite`. -Now stepping into the use-site of `min`, we see -```text + +Now stepping into the use-site of `min`, you see that value `14` was returned by `min` (as expected): +```bash (gdb) bt #0 java.lang.String::getChars(int, int, char[]*, int) (this=0x7ff7f9101230, srcBegin=0, srcEnd=14, dst=0x7ff7f858ac58, dstBegin=0) at java/lang/String.java:1688 #1 java.io.BufferedWriter::implWrite(java.lang.String*, int, int) (this=0x7ff7f884e828, s=0x7ff7f9101230, off=, len=) at java/io/BufferedWriter.java:330 ... ``` -that value `14` was returned by `min` (as expected). #### Calling `svm_dbg_`-helper functions during debugging When the image gets built with `-H:+IncludeDebugHelperMethods`, additional `@CEntryPoint`-functions are defined that can be called from GDB during debugging, for example: -```text +```bash (gdb) p greeter $3 = (hello.Hello$Greeter *) 0x7ffff6881900 ``` -Here again, we have a local named `greeter` with the static-type `hello.Hello$Greeter`. -To see its runtime-type, we can use the methods already described above. -Alternatively, we can make use of the `svm_dbg_`-helper functions. -For example, we can call -```text +Here again, you have a local named `greeter` with the static-type `hello.Hello$Greeter`. +To see its runtime-type, you can use the methods already described above.\ + +Alternatively, you can make use of the `svm_dbg_`-helper functions. +For example, from within the running debug session, you can call: +```java void svm_dbg_print_hub(graal_isolatethread_t* thread, size_t hubPtr) ``` -from within the running debug session. We have to pass a value for `graal_isolatethread_t` and the absolute address of the hub we want to get printed. + +You have to pass a value for `graal_isolatethread_t` and the absolute address of the hub you want to get printed. In most situations, the value for `graal_isolatethread_t` is just the value of the current `IsolateThread` that can be found in a platform-specific register: | Platform | Register | @@ -455,33 +472,33 @@ In most situations, the value for `graal_isolatethread_t` is just the value of t | `amd64` | `$r15` | | `aarch64` | `$r28` | -Finally, before we can call `svm_dbg_print_hub` we also have to make sure we have the **absolute address** of the hub we want to print. Using -```text +Finally, before you can call `svm_dbg_print_hub`, make sure you have the **absolute address** of the hub you want to print. Using +```bash (gdb) p greeter.hub $4 = (_z_.java.lang.Class *) 0x837820 ``` reveals that in the current situation, the `hub`-field in `greeter` holds a compressed reference to the hub (the `hub-type` is prefixed with `_z_.`). -Thus, we first need to get the absolute address of the hub field by using another `svm_dbg_`-helper method. -```text +Thus, you first need to get the absolute address of the hub field by using another `svm_dbg_`-helper method. +```bash (gdb) call svm_dbg_obj_uncompress($r15, greeter.hub) $5 = 140737339160608 (gdb) p/x $5 $6 = 0x7ffff71b7820 ``` -With the help of calling `svm_dbg_obj_uncompress`, we now know that the hub is located at address `0x7ffff71b7820` and we can finally call `svm_dbg_print_hub`: -```text +With the help of calling `svm_dbg_obj_uncompress`, you now know that the hub is located at address `0x7ffff71b7820` and you can finally call `svm_dbg_print_hub`: +```bash (gdb) call (void) svm_dbg_print_hub($r15, 0x7ffff71b7820) hello.Hello$NamedGreeter ``` Both calls to `svm_dbg_`-helper can be combined into a single command line: -```text +```bash (gdb) call (void) svm_dbg_print_hub($r15, svm_dbg_obj_uncompress($r15, greeter.hub)) hello.Hello$NamedGreeter ``` -##### The following `svm_dbg_`-helper methods are currently defined: +The following `svm_dbg_`-helper methods are currently defined: -```text +``` int svm_dbg_ptr_isInImageHeap(graal_isolatethread_t* thread, size_t ptr); int svm_dbg_ptr_isObject(graal_isolatethread_t* thread, size_t ptr); int svm_dbg_hub_getLayoutEncoding(graal_isolatethread_t* thread, size_t hubPtr); @@ -509,4 +526,8 @@ void svm_dbg_print_obj(graal_isolatethread_t* thread, size_t objPtr); void svm_dbg_print_string(graal_isolatethread_t* thread, size_t strPtr); void svm_dbg_print_fatalErrorDiagnostics(graal_isolatethread_t* thread, size_t sp, void * ip); void svm_dbg_print_locationInfo(graal_isolatethread_t* thread, size_t mem); -``` \ No newline at end of file +``` + +### Related Documentation + +* [Debug Info Feature](../DebugInfo.md) \ No newline at end of file From 3581e3197eb6d573bf576f35285d434fce906a2b Mon Sep 17 00:00:00 2001 From: Olya Gupalo Date: Fri, 15 Dec 2023 15:03:55 +0100 Subject: [PATCH 253/593] Updated Native Image Bundles doc to be frameworks-neutral; Added Maven and Gradle commands --- .../embedding/embed-languages.md | 2 +- .../java-on-truffle/HotSwap.md | 24 +- docs/reference-manual/native-image/Bundles.md | 237 +++++++----------- .../debug-native-executables-with-gdb.md | 76 +++--- .../include-reachability-metadata-gradle.md | 15 +- .../native-image/visual-bundle-compare.png | Bin 32973 -> 0 bytes 6 files changed, 151 insertions(+), 203 deletions(-) delete mode 100644 docs/reference-manual/native-image/visual-bundle-compare.png diff --git a/docs/reference-manual/embedding/embed-languages.md b/docs/reference-manual/embedding/embed-languages.md index d8bdf20b8020..eb93eab5f6d3 100644 --- a/docs/reference-manual/embedding/embed-languages.md +++ b/docs/reference-manual/embedding/embed-languages.md @@ -72,7 +72,7 @@ To access [polyglot isolate](#polyglot-isolates) artifacts, use the `-isolate` s The artifacts `polyglot` and `tools` include all available languages and tools as dependencies. This artifact might grow or shrink between major releases. We recommend selecting only the needed language(s) for a production deployment. ->The `pom` type is a requirement for a language or tool dependency. +> The `pom` type is a requirement for a language or tool dependency. Additionally, your _module-info.java_ file should require `org.graalvm.polyglot` when using Java modules. diff --git a/docs/reference-manual/java-on-truffle/HotSwap.md b/docs/reference-manual/java-on-truffle/HotSwap.md index a0a88e850762..4f7fa9f9a923 100644 --- a/docs/reference-manual/java-on-truffle/HotSwap.md +++ b/docs/reference-manual/java-on-truffle/HotSwap.md @@ -240,22 +240,22 @@ Download, unzip and open the project in your IDE. Before you proceed, make sure that you have Java on Truffle [installed](README.md#install-java-on-truffle) and set the GraalVM as the project SDK. 1. In your IDE navigate to the root `build.gradle` within the sample project. Add: -```groovy -run.jvmArgs+="-truffle" -``` + ``` + run.jvmArgs+="-truffle" + ``` 2. Also add maven local repository where we previously published the enhanced Micronaut framework. For example: -```groovy -repositories { - mavenLocal() - ... -} -``` + ``` + repositories { + mavenLocal() + ... + } + ``` 3. In `gradle.properties` update the Micronaut version that you published. For example: -```groovy -micronautVersion=2.5.8-SNAPSHOT -``` + ``` + micronautVersion=2.5.8-SNAPSHOT + ``` Now you are all setup. 4. Execute`assemble` task and create a run configuration using the defined `run` gradle task. diff --git a/docs/reference-manual/native-image/Bundles.md b/docs/reference-manual/native-image/Bundles.md index 0e3de86ac14c..7e93e8c46e9b 100644 --- a/docs/reference-manual/native-image/Bundles.md +++ b/docs/reference-manual/native-image/Bundles.md @@ -47,8 +47,9 @@ Here is the option description: Oracle Linux 8 base images for GraalVM (see https://github.com/graalvm/container) ``` -For example, assuming a Micronaut application is built with Maven, make sure the `--bundle-create` option is used. -For that, the following needs to be added to the plugins section of `pom.xml`: +### Creating Bundles with Maven + +Assuming a Java application is built with Maven, pass the `--bundle-create` as a build argument in the [Maven plugin for Native Image building configuration](https://graalvm.github.io/native-build-tools/latest/maven-plugin.html#configuration-options): ```xml org.graalvm.buildtools @@ -61,94 +62,87 @@ For that, the following needs to be added to the plugins section of `pom.xml`: ``` -Then, when you run the Maven package command `mvn -Pnative native:compile`, you will get the following build artifacts: +Then, run the Maven package command: +```shell +./mvnw -Pnative native:compile +``` +>Note: The command to create a native executable with Maven for a Micaonut project is: `./mvnw package -Dpackaging=native-image`. + +You get the following build artifacts: ``` -Finished generating 'micronautguide' in 2m 0s. +Finished generating 'application' in 2m 0s. -Native Image Bundles: Bundle build output written to /home/testuser/micronaut-data-jdbc-repository-maven-java/target/micronautguide.output -Native Image Bundles: Bundle written to /home/testuser/micronaut-data-jdbc-repository-maven-java/target/micronautguide.nib +Native Image Bundles: Bundle build output written to /application/target/application.output +Native Image Bundles: Bundle written to /application/target/application.nib ``` -This output indicates that you have created a native executable, `micronautguide`, and a bundle, _micronautguide.nib_. +This output indicates that you have created a native executable, `application`, and a bundle, _application.nib_. The bundle file is created in the _target/_ directory. It should be copied to some safe place where it can be found if the native executable needs to be rebuilt later. -Obviously, a bundle file can be large because it contains all input files as well as the executable itself (the executable is compressed within the bundle). -Having the image inside the bundle allows comparing a native executable rebuilt from the bundle against the original one. -In the case of the `micronaut-data-jdbc-repository` example, the bundle is 60.7 MB (the executable is 103.4 MB). -To see what is inside a bundle, run `jar tf *.nib`: +### Creating Bundles with Gradle + +Assuming a Java application is built with Gradle, pass the `--bundle-create` as a build argument in the [Gradle plugin for Native Image building configuration](https://graalvm.github.io/native-build-tools/latest/gradle-plugin.html#_native_image_options): + ```shell -$ jar tf micronautguide.nib -META-INF/MANIFEST.MF -META-INF/nibundle.properties -output/default/micronautguide -com/oracle/svm/driver/launcher/BundleLauncherUtil.class -com/oracle/svm/driver/launcher/ContainerSupport$TargetPath.class -com/oracle/svm/driver/launcher/BundleLauncherHelp.txt -com/oracle/svm/driver/launcher/BundleLauncher.class -com/oracle/svm/driver/launcher/configuration/BundleConfigurationParser.class -com/oracle/svm/driver/launcher/configuration/BundleEnvironmentParser.class -com/oracle/svm/driver/launcher/configuration/BundleArgsParser.class -com/oracle/svm/driver/launcher/configuration/BundlePathMapParser.class -com/oracle/svm/driver/launcher/configuration/BundleContainerSettingsParser.class -com/oracle/svm/driver/launcher/ContainerSupport.class -com/oracle/svm/driver/launcher/json/BundleJSONParser.class -com/oracle/svm/driver/launcher/json/BundleJSONParserException.class -input/classes/cp/micronaut-core-3.8.7.jar -input/classes/cp/netty-buffer-4.1.87.Final.jar -input/classes/cp/jackson-databind-2.14.1.jar -input/classes/cp/micronaut-context-3.8.7.jar -input/classes/cp/reactive-streams-1.0.4.jar -... -input/classes/cp/netty-handler-4.1.87.Final.jar -input/classes/cp/micronaut-jdbc-4.7.2.jar -input/classes/cp/jackson-core-2.14.0.jar -input/classes/cp/micronaut-runtime-3.8.7.jar -input/classes/cp/micronautguide-0.1.jar -input/stage/path_substitutions.json -input/stage/path_canonicalizations.json -input/stage/build.json -input/stage/run.json -input/stage/environment.json -input/stage/Dockerfile +graalvmNative { + binaries { + main { + buildArgs.add("--bundle-create") + } + } +} ``` -As you can see, a bundle is just a JAR file with a specific layout. -This is explained in detail [below](#bundle-file-format). - -Next to the bundle, you can also find the output directory: _target/micronautguide.output_. -It contains the native executable and all other files that were created as part of the build. -Since you did not specify any options that would produce extra output (for example, `-g` to generate debugging information or `--diagnostics-mode`), only the executable can be found there: +Then, run the Gradle build command: ```shell -$ tree target/micronautguide.output -target/micronautguide.output -├── default -│ └── micronautguide -└── other +./gradlew nativeCompile ``` -### Combining --bundle-create with dry-run +You get the following build artifacts: +``` +Finished generating 'application' in 2m 0s. -As mentioned in the `--bundle-create` option description, it is also possible to let `native-image` build a bundle but not actually perform the image building. -This might be useful if a user wants to move the bundle to a more powerful machine and build the image there. -Modify the `--bundle-create` argument in the `native-maven-plugin` configuration above to `--bundle-create,dry-run`. -Then running `mvn -Pnative native:compile` takes only seconds and the created bundle is much smaller: +Native Image Bundles: Bundle build output written to /application/build/native/nativeCompile/application.output +Native Image Bundles: Bundle written to /application/build/native/nativeCompile/application.nib ``` -Native Image Bundles: Bundle written to /home/testuser/micronaut-data-jdbc-repository-maven-java/target/micronautguide.nib + +This output indicates that you have created a native executable, `application`, and a bundle, _application.nib_. +The bundle file is created in the _build/native/nativeCompile/_ directory. + +### Bundle File and Output Directory + +Obviously, a bundle file can be large because it contains all input files as well as the executable itself (the executable is compressed within the bundle). +Having the native image inside the bundle allows comparing a native executable rebuilt from the bundle against the original one. + +A bundle is just a JAR file with a specific layout. +This is explained in detail [below](#bundle-file-format). +To see what is inside a bundle, run: +```shell +jar tf application.nib ``` -Now _micronautguide.nib_ is only 20 MB in file size and the executable is not included: +Next to the bundle, you can also find the output directory: _application.output_. +It contains the native executable and all other files that were created as part of the build. +Since you did not specify any options that would produce extra output (for example, `-g` to generate debugging information or `--diagnostics-mode`), only the executable can be found there. + +### Combining --bundle-create with dry-run + +As mentioned in the `--bundle-create` option description, it is also possible to let `native-image` build a bundle but not actually create the image. +This might be useful if a user wants to move the bundle to a more powerful machine and build the image there. +Modify the `--bundle-create` argument in the Maven / Gradle Native Image plugin configuration above to `--bundle-create,dry-run`. +Then building a project takes only seconds and the created bundle is much smaller. +For example, check the contents of _target/application.nib_ and notice that the executable is not included: ```shell -$ jar tf micronautguide.nib +jar tf application.nib META-INF/MANIFEST.MF META-INF/nibundle.properties -input/classes/cp/micronaut-core-3.8.7.jar ... ``` Note that this time you do not see the following message in the Maven output: ``` -Native Image Bundles: Bundle build output written to /home/testuser/micronaut-data-jdbc-repository-maven-java/target/micronautguide.output +Native Image Bundles: Bundle build output written to /application/target/application.output ``` Since no executable is created, no bundle build output is available. @@ -156,40 +150,12 @@ Since no executable is created, no bundle build output is available. Assuming that the native executable is used in production and once in a while, an unexpected exception is thrown at run time. Since you still have the bundle that was used to create the executable, it is trivial to build a variant of that executable with debugging support. -Use `--bundle-apply=micronautguide.nib` like this: +Use `--bundle-apply=application.nib` like this: ```shell -$ native-image --bundle-apply=micronautguide.nib -g - -Native Image Bundles: Loaded Bundle from /home/testuser/micronautguide.nib -Native Image Bundles: Bundle created at 'Tuesday, March 28, 2023, 11:12:04 AM Central European Summer Time' -Native Image Bundles: Using version: '20.0.1+8' (vendor 'Oracle Corporation') on platform: 'linux-amd64' -Warning: Native Image Bundles are an experimental feature. -======================================================================================================================== -GraalVM Native Image: Generating 'micronautguide' (executable)... -======================================================================================================================== -... -Finished generating 'micronautguide' in 2m 16s. - -Native Image Bundles: Bundle build output written to /home/testuser/micronautguide.output +native-image --bundle-apply=application.nib -g ``` -After running this command, the executable is rebuilt with an extra option `-g` passed after `--bundle-apply`. -The output of this build is in the directory _micronautguide.output_: -``` -micronautguide.output -micronautguide.output/other -micronautguide.output/default -micronautguide.output/default/micronautguide.debug -micronautguide.output/default/micronautguide -micronautguide.output/default/sources -micronautguide.output/default/sources/javax -micronautguide.output/default/sources/javax/smartcardio -micronautguide.output/default/sources/javax/smartcardio/TerminalFactory.java -... -micronautguide.output/default/sources/java/lang/Object.java -``` - -You successfully rebuilt the application from the bundle with debug info enabled. +After running this command, the executable is rebuilt from the bundle with debug info enabled. The full option help of `--bundle-apply` shows a more advanced use case that will be discussed [later](#combining---bundle-create-and---bundle-apply) in detail: ``` @@ -208,11 +174,13 @@ The full option help of `--bundle-apply` shows a more advanced use case that wil ### Building in a Container -Another addition to the `--bundle-create` and `--bundle-apply` options, as mentioned above, is to perform image building inside a container image. +Another addition to the `--bundle-create` and `--bundle-apply` options is to perform image building inside a container image. This ensures that during the image build `native-image` can not access any resources that were not explicitly specified via the classpath or module path. -Modify the `--bundle-create` argument in the `native-maven-plugin` configuration to `--bundle-create,container`. + +Modify the `--bundle-create` argument in the Maven / Gradle Native Image plugin configuration above to `--bundle-create,container`. This still creates the same bundle as before. -However, a container image is built and then used for building the native image executable. +However, a container image is built and then used for building the native executable. + If the container image is newly created, you can also see the build output from the container tool. The name of the container image is the hash of the used Dockerfile. If the container image already exists you will see the following line in the build output instead: @@ -222,8 +190,9 @@ Native Image Bundles: Reusing container image c253ca50f50b380da0e23b168349271976 ``` For building in a container you require either _podman_ or _rootless docker_ to be available on your system. -Additionally, building in a container is currently only supported for Linux. -Using any other OS native image will not create and use a container image. + +> Building in a container is currently only supported for Linux. Using any other OS native image will not create and use a container image. + The container tool used for running the image build can be specified with `--bundle-create,container=podman` or `--bundle-create,container=docker`. If not specified, `native-image` uses one of the supported tools. If available, `podman` is preferred and rootless `docker` is the fallback. @@ -236,11 +205,10 @@ Even if you do not use the `container` option, `native-image` creates a Dockerfi Other than creating a container image on the host system, building inside a container does not create any additional build output. However, the created bundle contains some additional files: ```shell -$ jar tf micronautguide.nib +jar tf application.nib META-INF/MANIFEST.MF META-INF/nibundle.properties ... -input/classes/cp/micronaut-management-3.8.7.jar input/stage/path_substitutions.json input/stage/path_canonicalizations.json input/stage/build.json @@ -249,7 +217,7 @@ input/stage/environment.json input/stage/Dockerfile input/stage/container.json ``` -The bundle contains the Dockerfile used for building the container image and stores the used container tool, its version and the name of the container image in `container.json`: +The bundle contains the Dockerfile used for building the container image and stores the used container tool, its version and the name of the container image in `container.json`. For example: ```json { "containerTool":"podman", @@ -300,71 +268,54 @@ As already mentioned in [Building with Bundles](#building-with-bundles), it is p The `--bundle-apply` help message has a simple example. A more interesting example arises if an existing bundle is used to create a new bundle that builds a PGO-optimized version of the original application. -Assuming you have already built the `micronaut-data-jdbc-repository` example into a bundle named _micronautguide.nib_. +Assuming you have already built your application into a bundle named _application.nib_. To produce a PGO-optimized variant of that bundle, first build a variant of the native executable that generates PGO profiling information at run time (you will use it later): ```shell -$ native-image --bundle-apply=micronautguide.nib --pgo-instrument +native-image --bundle-apply=application.nib --pgo-instrument ``` Now run the generated executable so that profile information is collected: ```shell -$ /home/testuser/micronautguide.output/default/micronautguide +./target/application ``` -Based on this walkthrough, you use the running native executable to add new database entries and query the information in the database afterwards so that you get real-world profiling information. -Once completed, stop the Micronaut application using `Ctrl+C` (`SIGTERM`). -Looking into the current working directory, you can find a new file: -```shell -$ ls -lh *.iprof --rw------- 1 testuser testuser 19M Mar 28 14:52 default.iprof -``` +Once completed, stop the application. -The file `default.iprof` contains the profiling information that was created because you ran the Micronaut application from the executable built with `--pgo-instrument`. +Looking into the current working directory, you can find a new file, _default.iprof_. +It contains the profiling information that was created because you ran the application from the executable built with `--pgo-instrument`. Now you can create a new optimized bundle out of the existing one: ```shell -native-image --bundle-apply=micronautguide.nib --bundle-create=micronautguide-pgo-optimized.nib,dry-run --pgo +native-image --bundle-apply=application.nib --bundle-create=application-pgo-optimized.nib,dry-run --pgo ``` -Now take a look how _micronautguide-pgo-optimized.nib_ is different from _micronautguide.nib_: +Now take a look how _application-pgo-optimized.nib_ is different from _application.nib_: ```shell $ ls -lh *.nib --rw-r--r-- 1 testuser testuser 20M Mar 28 11:12 micronautguide.nib --rw-r--r-- 1 testuser testuser 23M Mar 28 15:02 micronautguide-pgo-optimized.nib +-rw-r--r-- 1 testuser testuser 20M Mar 28 11:12 application.nib +-rw-r--r-- 1 testuser testuser 23M Mar 28 15:02 application-pgo-optimized.nib ``` -You can see that the new bundle is 3 MB larger than the original. +The new bundle should be larger than the original. The reason, as can be guessed, is that now the bundle contains the _default.iprof_ file. -Using a tool to compare directories, you can inspect the differences in detail: +Using a tool to compare directories, you can inspect the differences in detail. -![visual-bundle-compare](visual-bundle-compare.png) - -As you can see, _micronautguide-pgo-optimized.nib_ contains _default.iprof_ in the directory _input/auxiliary_, and there -are also changes in other files. The contents of _META-INF/nibundle.properties_, _input/stage/path_substitutions.json_ -and _input/stage/path_canonicalizations.json_ will be explained [later](#bundle-file-format). +As you can see that _application-pgo-optimized.nib_ contains _default.iprof_ in the directory _input/auxiliary_, and there are also changes in other files. +The contents of _META-INF/nibundle.properties_, _input/stage/path_substitutions.json_ and _input/stage/path_canonicalizations.json_ will be explained [later](#bundle-file-format). For now, look at the diff in _build.json_: ``` @@ -4,5 +4,6 @@ "--no-fallback", - "-H:Name=micronautguide", - "-H:Class=example.micronaut.Application", + "-H:Name=application", + "-H:Class=example.com.Application", - "--no-fallback" + "--no-fallback", + "--pgo" - ] ``` As expected, the new bundle contains the `--pgo` option that you passed to `native-image` to build an optimized bundle. Building a native executable from this new bundle generates a PGO-optimized executable out of the box (see `PGO: on` in build output): ```shell -$ native-image --bundle-apply=micronautguide-pgo-optimized.nib -... -[1/8] Initializing... (3.9s @ 0.27GB) - Java version: 20.0.1+8, vendor version: GraalVM EE 20.0.1+8.1 - Graal compiler: optimization level: '2', target machine: 'x86-64-v3', PGO: on - C compiler: gcc (redhat, x86_64, 13.0.1) - Garbage collector: Serial GC (max heap size: 80% of RAM) - 6 user-specific feature(s) -... +native-image --bundle-apply=application-pgo-optimized.nib ``` ## Executing a Bundled Application @@ -373,7 +324,7 @@ As described later in [Bundle File Format](#bundle-file-format), a bundle file i This means you can use a native image bundle with any JDK and execute it as a JAR file with `/bin/java -jar [bundle-file.nib]`. The launcher uses the command line arguments stored in _run.json_ and adds all JAR files and folders in _input/classes/cp_ and _input/classes/p_ to the classpath and module path respectively. -The launcher also comes with a separate command line interface described in its help text: +The launcher also comes with a separate command-line interface described in its help text: ``` This native image bundle can be used to launch the bundled application. @@ -410,7 +361,7 @@ Every bundle contains a Dockerfile which is used for executing the bundled appli However, this Dockerfile can be overwritten by adding `,dockerfile=` to the `--container` argument. The bundle launcher only consumes options it knows, all other arguments are passed on to the bundled application. -If the bundle launcher parses ` -- ` without a specified option, the launcher stops parsing arguments. +If the bundle launcher parses `--` without a specified option, the launcher stops parsing arguments. All remaining arguments are then also passed on to the bundled application. ## Bundle File Format @@ -465,7 +416,7 @@ BundleFileVersionMinor=9 Future versions of GraalVM might alter or extend the internal structure of bundle files. The versioning enables us to evolve the bundle format with backwards compatibility in mind. -### input +### Input Data This directory contains all input data that gets passed to the `native-image` builder. The file _input/stage/build.json_ holds the original command line that was passed to `native-image` when the bundle was created. @@ -480,9 +431,9 @@ The state of environment variables that are relevant for the build are captured For every `-E` argument that was seen when the bundle was created, a snapshot of its key-value pair is recorded in the file. The remaining files _path_canonicalizations.json_ and _path_substitutions.json_ contain a record of the file-path transformations that were performed by the `native-image` tool based on the input file paths as specified by the original command line arguments. -### output +### Output Data -If a native executable is built as part of building the bundle (for example, the `,dry-run` option was not used), you also have an _output_ directory in the bundle. +If a native executable is built as part of building the bundle (for example, the `dry-run` option was not used), you also have an _output_ directory in the bundle. It contains the executable that was built along with any other files that were generated as part of building. Most output files are located in the directory _output/default_ (the executable, its debug info, and debug sources). Builder output files, that would have been written to arbitrary absolute paths if the executable had not been built in the bundle mode, can be found in _output/other_. diff --git a/docs/reference-manual/native-image/guides/debug-native-executables-with-gdb.md b/docs/reference-manual/native-image/guides/debug-native-executables-with-gdb.md index a7ad816f63e7..1a3992292fc5 100644 --- a/docs/reference-manual/native-image/guides/debug-native-executables-with-gdb.md +++ b/docs/reference-manual/native-image/guides/debug-native-executables-with-gdb.md @@ -34,7 +34,7 @@ GDB automatically loads the `.debug` file for a given native executab #### Image build information The `*.debug`-file contains additional information about the image build, which can be accessed as follows: -```bash +``` readelf -p .debug.svm.imagebuild.classpath hello_image.debug ``` It gives a list of all classpath entries that were used to build the image: @@ -53,11 +53,11 @@ The following sections are available #### Where is the main method? Use -```bash +``` info functions ::main ``` to find all methods named `main` and then use `b
    `, for example: -```bash +``` (gdb) info functions ::main All functions matching regular expression "::main": @@ -73,7 +73,7 @@ Breakpoint 1 at 0x83c030: file hello/Hello.java, line 76. #### Setting breakpoints First, find the type of the method you want to set a breakpoint in, for example: -```bash +``` (gdb) info types ArrayList All types matching regular expression "ArrayList": @@ -86,7 +86,7 @@ File java/util/ArrayList.java: ... ``` Now use the following GDB autocompletion: -```bash +``` (gdb) b 'java.util.ArrayList:: ``` Pressing tab twice now shows all `ArrayList` methods to choose from: @@ -101,7 +101,7 @@ java.util.ArrayList::addAll(java.util.Collection*) ... ``` If to complete with -```bash +``` (gdb) b 'java.util.ArrayList::add` ``` breakpoints in all variants of `add` are installed. @@ -139,13 +139,13 @@ $4 = (_z_.java.lang.String *) 0x27011a #### Strings To see the actual contents of a Java String object, look at its **`value`-field**, for example: -```bash +``` (gdb) p args.data[0] $4 = (_z_.java.lang.String *) 0x27011a ``` `args.data[0]` points to a String object. Let's deref: -```bash +``` (gdb) p *args.data[0] $5 = { = { @@ -166,14 +166,14 @@ $5 = { The `value` field holds the String data. Let's check the type of `value`: -```bash +``` (gdb) p args.data[0].value $3 = (_z_.byte[] *) 0x250119 ``` `value` is of type `byte[]`. As you already learned before, the elements of an array can be accessed via its `data`-field. -```bash +``` (gdb) p args.data[0].value.data $10 = 0x7ff33f8008c8 "this\376\376\376\376\200G\273\001\030\001'" ``` @@ -181,14 +181,14 @@ $10 = 0x7ff33f8008c8 "this\376\376\376\376\200G\273\001\030\001'" GDB is smart enough to interpret the byte-pointer as a C string out of the box. But in essence, it is an array. The following gives us the `t` from `this`. -```bash +``` (gdb) p args.data[0].value.data[0] $13 = 116 't' ``` The reason for the garbage after the last char is that Java String values are not 0-terminated (unlike C strings). To know where the garbage starts you can inspect the `len`-field. -```bash +``` (gdb) p args.data[0].value.len $14 = 4 ``` @@ -209,7 +209,7 @@ $17 = (hello.Hello$Greeter *) 0x7ff7f9101208 ``` Also, you are not able to see fields that only exist for the `NamedGreeter` subclass. -```bash +``` (gdb) p *greeter $18 = { = { @@ -220,7 +220,7 @@ $18 = { But you do have the `hub`-field, which points to the class-object of an object. Therefore, it allows you to determine the runtime-type of the Greeter object at address `0x7ff7f9101208`: -```bash +``` (gdb) p greeter.hub $19 = (_z_.java.lang.Class *) 0x1d1cae0 (gdb) p *greeter.hub @@ -248,11 +248,11 @@ $22 = 0x7ff7f80705b8 "hello.Hello$NamedGreeter\351\001~*" So you learned that the actual type of that object is `hello.Hello$NamedGreeter`. Now cast to that type: -```bash +``` (gdb) set $rt_greeter = ('hello.Hello$NamedGreeter' *) greeter ``` Now you can inspect the downcasted convenience variable `rt_greeter`: -```bash +``` (gdb) p $rt_greeter $23 = (hello.Hello$NamedGreeter *) 0x7ff7f9101208 (gdb) p *$rt_greeter @@ -267,18 +267,18 @@ $24 = { } ``` Now you can see the `name`-field that only exists in the `NamedGreeter` subtype. -```bash +``` (gdb) p $rt_greeter.name $25 = (_z_.java.lang.String *) 0x270119 ``` So the `name`-field is of type String. You already know how to see the contents of a String: -```bash +``` (gdb) p $rt_greeter.name.value.data $26 = 0x7ff7f91008c0 "FooBar\376\376\200G\273\001\027\001'" ``` ##### ⚠️ If the static type that you want to downcast from is a compressed reference then the type used in the downcast also needs to be that of a compressed reference. For example, if you have: -```bash +``` (gdb) p elementData.data[0] $38 = (_z_.java.lang.Object *) 0x290fcc @@ -286,7 +286,7 @@ $38 = (_z_.java.lang.Object *) 0x290fcc In the internal array of an `ArrayList`, the first entry points to a `java.lang.Object` with a `_z_.` prefix, which denotes that this is a **compressed ref**. To check what the runtime-type of that object is, use: -```bash +``` (gdb) p elementData.data[0].hub.name.value.data $40 = 0x7ff7f8665600 "java.lang.String=\256\271`" @@ -294,7 +294,7 @@ $40 = 0x7ff7f8665600 "java.lang.String=\256\271`" Now you know that the compressed ref actually points to a `java.lang.String`. **Then, when you cast, do not forget to use the `_z_.` prefix.** -```bash +``` (gdb) p ('_z_.java.lang.String' *) elementData.data[0] $41 = (_z_.java.lang.String *) 0x290fcc @@ -311,14 +311,14 @@ $43 = { ... ``` To see the contents of that String, again use: -```bash +``` (gdb) p $41.value.data $44 = 0x7ff7f9207e78 "#subsys_name\thierarchy\tnum_cgroups\tenabled" ``` #### Using the `this` variable in instance methods -```bash +``` (gdb) bt #0 hello.Hello$NamedGreeter::greet() (this=0x7ff7f9101208) at hello/Hello.java:71 #1 0x000000000083c060 in hello.Hello::main(java.lang.String[]*) (args=) at hello/Hello.java:77 @@ -345,7 +345,7 @@ $3 = (_z_.java.lang.String *) 0x270119 ``` Just like in Java or C++ code, in instance-methods, prefixing with `this.` is not needed. -```bash +``` (gdb) p name $7 = (_z_.java.lang.String *) 0x270119 (gdb) p name.value.data @@ -354,18 +354,18 @@ $8 = 0x7ff7f91008c0 "FooBar\376\376\200G\273\001\027\001'" #### Accessing static fields While static fields are shown whenever an instance of an object is printed, you just want to see the value of a specific static field. -```bash +``` (gdb) p 'java.math.BigDecimal::BIG_TEN_POWERS_TABLE' $23 = (_z_.java.math.BigInteger[] *) 0x132b95 ``` To get a list of all static fields, use: -```bash +``` (gdb) info variables :: ``` #### Inspecting `.class` Objects For every Java type in the image, there exists an easy way to access its class object (aka the hub). -```bash +``` (gdb) info types PrintStream All types matching regular expression "PrintStream": @@ -376,7 +376,7 @@ File java/io/PrintStream.java: ... ``` To access the hub of `java.io.PrintStream`, you can use the `.class` suffix: -```bash +``` (gdb) p 'java.io.PrintStream.class' $4 = { = { @@ -399,19 +399,19 @@ $4 = { } ``` This allows you, for example, to check which module `java.io.PrintStream` belongs to: -```bash +``` (gdb) p 'java.io.PrintStream.class'.module.name.value.data $12 = 0x7ff7f866b000 "java.base" ``` #### Inlined methods Setting a breakpoint in `PrintStream.writeln` -```bash +``` (gdb) b java.io.PrintStream::writeln Breakpoint 2 at 0x4080cb: java.io.PrintStream::writeln. (35 locations) ``` Now you navigate to: -```bash +``` (gdb) bt #0 java.io.BufferedWriter::min(int, int) (this=, a=8192, b=14) at java/io/BufferedWriter.java:216 #1 java.io.BufferedWriter::implWrite(java.lang.String*, int, int) (this=0x7ff7f884e828, s=0x7ff7f9101230, off=, len=) at java/io/BufferedWriter.java:329 @@ -430,7 +430,7 @@ Now you navigate to: at com/oracle/svm/core/code/IsolateEnterStub.java:1 ``` If you query extra info about the top frame, you see that `min` got inlined into `implWrite`: -```bash +``` (gdb) info frame Stack level 0, frame at 0x7fffffffdb20: rip = 0x84af8a in java.io.BufferedWriter::min(int, int) (java/io/BufferedWriter.java:216); saved rip = 0x84c50d @@ -441,7 +441,7 @@ Stack level 0, frame at 0x7fffffffdb20: ``` Now stepping into the use-site of `min`, you see that value `14` was returned by `min` (as expected): -```bash +``` (gdb) bt #0 java.lang.String::getChars(int, int, char[]*, int) (this=0x7ff7f9101230, srcBegin=0, srcEnd=14, dst=0x7ff7f858ac58, dstBegin=0) at java/lang/String.java:1688 #1 java.io.BufferedWriter::implWrite(java.lang.String*, int, int) (this=0x7ff7f884e828, s=0x7ff7f9101230, off=, len=) at java/io/BufferedWriter.java:330 @@ -451,7 +451,7 @@ Now stepping into the use-site of `min`, you see that value `14` was returned by #### Calling `svm_dbg_`-helper functions during debugging When the image gets built with `-H:+IncludeDebugHelperMethods`, additional `@CEntryPoint`-functions are defined that can be called from GDB during debugging, for example: -```bash +``` (gdb) p greeter $3 = (hello.Hello$Greeter *) 0x7ffff6881900 ``` @@ -473,25 +473,25 @@ In most situations, the value for `graal_isolatethread_t` is just the value of t | `aarch64` | `$r28` | Finally, before you can call `svm_dbg_print_hub`, make sure you have the **absolute address** of the hub you want to print. Using -```bash +``` (gdb) p greeter.hub $4 = (_z_.java.lang.Class *) 0x837820 ``` reveals that in the current situation, the `hub`-field in `greeter` holds a compressed reference to the hub (the `hub-type` is prefixed with `_z_.`). Thus, you first need to get the absolute address of the hub field by using another `svm_dbg_`-helper method. -```bash +``` (gdb) call svm_dbg_obj_uncompress($r15, greeter.hub) $5 = 140737339160608 (gdb) p/x $5 $6 = 0x7ffff71b7820 ``` With the help of calling `svm_dbg_obj_uncompress`, you now know that the hub is located at address `0x7ffff71b7820` and you can finally call `svm_dbg_print_hub`: -```bash +``` (gdb) call (void) svm_dbg_print_hub($r15, 0x7ffff71b7820) hello.Hello$NamedGreeter ``` Both calls to `svm_dbg_`-helper can be combined into a single command line: -```bash +``` (gdb) call (void) svm_dbg_print_hub($r15, svm_dbg_obj_uncompress($r15, greeter.hub)) hello.Hello$NamedGreeter ``` diff --git a/docs/reference-manual/native-image/guides/include-reachability-metadata-gradle.md b/docs/reference-manual/native-image/guides/include-reachability-metadata-gradle.md index 7df8790da7e3..82328362f3bc 100644 --- a/docs/reference-manual/native-image/guides/include-reachability-metadata-gradle.md +++ b/docs/reference-manual/native-image/guides/include-reachability-metadata-gradle.md @@ -123,7 +123,7 @@ For other installation options, visit the [Downloads section](https://www.graalv 5. Open the Gradle configuration file _build.gradle_, and replace its contents with the following: - ```shell + ``` plugins { id 'application' // 1. Native Image Gradle plugin @@ -169,7 +169,7 @@ For other installation options, visit the [Downloads section](https://www.graalv 6. The plugin is not yet available on the Gradle Plugin Portal, so declare an additional plugin repository. Open the _settings.gradle_ file and replace the default content with this: - ```shell + ``` pluginManagement { repositories { mavenCentral() @@ -197,13 +197,13 @@ The support needs to be enabled explicitly. 1. Open the _build.gradle_ file, and enable the GraalVM Reachability Metadata Repository in the `graalvmNative` plugin configuration: - ```shell + ``` metadataRepository { enabled = true } ``` The whole configuration block should look like: - ```shell + ``` graalvmNative { agent { defaultMode = "standard" @@ -243,7 +243,7 @@ You can configure the agent by either passing the options on the command line, o See below how to collect metadata with the tracing agent, and build a native executable applying the provided configuration. 1. Open the _build.gradle_ file and see the agent mode specified in the `graalvmNative` plugin configuration: - ```shell + ``` graalvmNative { agent { defaultMode = "standard" @@ -260,22 +260,19 @@ See below how to collect metadata with the tracing agent, and build a native exe The agent captures and records calls to the H2 Database and all the dynamic features encountered during a test run into multiple _*-config.json_ files. 3. Once the metadata is collected, copy it into the project's _/META-INF/native-image/_ directory using the `metadataCopy` task: - ```shell ./gradlew metadataCopy --task run --dir src/main/resources/META-INF/native-image ``` It is not required but recommended that the output directory is _/resources/META-INF/native-image/_. The `native-image` tool picks up metadata from that location automatically. For more information about how to collect metadata for your application automatically, see [Collecting Metadata Automatically](../AutomaticMetadataCollection.md). -4. Build a native executable using configuration collected by the agent: - +4. Build a native executable using configuration collected by the agent: ```shell ./gradlew nativeCompile ``` The native executable, named _h2example_, is created in the _build/native/nativeCompile_ directory. 5. Run the application from the native executable: - ```shell ./build/native/nativeCompile/h2example ``` diff --git a/docs/reference-manual/native-image/visual-bundle-compare.png b/docs/reference-manual/native-image/visual-bundle-compare.png deleted file mode 100644 index 76d265d7f0cc211c24a59b8b2ca2aa8e91f5d8d4..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 32973 zcmcG$Wn5fcvptxE5Zr@XfB?ZEK^kZvxH|-I0t9z=2<{dvxLa_y27(g^jk~)v65L^$ zB=>pV`QLj#%x`ACbsx^zdv{gswX4>uLx_T$I2tk$@{=b|&?F^9l%70!w)N!6QzgU~ zuq%q&wy{s1e10M+BBV=t|Yi zlBmL7LiS@t9Yg?-3}9%^Q+M0-<@C24+uyB77TX3kT%}B}T!1ziwPYfJx=e50+wEu0 z8m8sNjfUo=b1OLm>g5Tt+VO3VC0?!SQ|kQ~5Y~t-*n3Ay+w1n-Kl+%Ki>p@?LqrGj ztX=CU>%cIL+CMrp0QR67fTiIJ4q@b2@3WY+w1|=tnZ&bxp^>QEuIJEP3YMI>gciab z(@D4JVt;N$^6atzcSiodYj)X9qH+wfw>?~Gj1|YS4y`mnhMSv?wqD$6HFO470F4gIP-f zw~{>oKZ3ihJBj8XmX21rTg{!CnzG%3{-RYuY67<{B^%VxToBpR&m&Ej7cVSt|GJYq zuSVrm#ig+6_tLme*~MXQ3dO zc95Z#F@t|{kE$Q_M5LDV`Mg^)RTvp0zGHt7Z~wS_eQ&;&xUsSEgMq=?FR6Mm=Gfp0 z(}Bt9D%Wah-l`w{{xP|yoh10hjVy)+?3^BR$Sn6Ya7WC4)`V2Rde`#7MenDG^Zk+&c?3l1?ztet;y(ftwh1-V>_(E6>ex)TrH-2 zc56bUhL)hhYsEBU4>gTsoUpOVKpl;@+#d?Dei9rKDHv7n)+|FL#5U5m-*>&2tG5`H z#nKXd&rq&W&eOU zWbIZ#%qm27rQs_?dIY5xSQFw)Aw;rgCpm`NwdzXy4b`89N(;EF`c{D4bnV6GA@99F zVA902w1D~fRG}s|*z6SQ*S5BnXaFiQc|}q<0ll zdrc)4>}w6B71|QfiSgicWDM0r$I0drmMc4w@lp%NNt1+!E4oN(cPp6t4T&J4S>$YH zFVo$#8VBM@jBn0w5b;^kolS?ztmTM~5OuEwfOC%QzQ}T#>~iI#A@_Vdt5-d;BMqL; z;KMdtHJo_EkQhMgJO;Uwd6Y3Rm-xWcQYXH*RriL=O&y#1ovSpM&yMW2&4rj$v*mN( zU~}eBG%mn#gB1^*@UvB#*2>Ig+Q=HzblRC?(X{!4i**OR4B;smPrYf`UOmF~eG{g5 zwgvRHc2{Ik+p-^5^K!S5?C^58-1hm5ivqQ`3i zfmEyQv$0lND8FCgs!L7JkrcoO$(mF2;zvQW`tX!Q$z|8#gNt_h3I8r{8zkf5C4;^N zlqQhkBV@>>JcwZIgUJ-sJe>4|aP~YY@??_jVzM>mND5Vad0zL|J#pGdu7-5Y{uzAh zUEw<-06t#%R`s?UJ@66HtozSIx67Dco7~>9=zHp?8K%|NX(c;;=!D7)RBB8eIYolE z9o?-x&m6qgZJ9!*s*icAwsSges%H_=+O$z()tBa6N9?S^vS9JEy)v(P3DjaWohBPf zGqH@bFJ=5!TdnNl-w3Vj(^a7 zbYhIv;K*%c4G8fUc?TIH|BSB*j-VL8SRHS~ndUwe2WP*`O$<5|EpfadD7mYmOSf9W z@Mc^J!@-A8ne5v*c&~7?o6NxJ$}9wbez#?7Hl*z_y5q`zW5>}^Dyn2L^<2Kz1!ZYy zAu{vbmW@lN3wY|>mHoktL#R}Ao03!h2It)e3*qlS-T~^|*;)^eo~1vSQ23(EDx5Dg zP`N#Dq7*xkeqUV6>i|te-mcW=k;1^3Tuw`<3;)YNall* zNazVgx-vxavIAozbFh3`58JcS+W85cX`N%-U60i@It%AP7$LsMT*%~Ih`Y+koP_9Y zV0m1dP+M<4K%986bt$q7)sXL~LsCw}Zr#meri!U`E+!M0_+YwLGp=58eJbieP)B}b zwx%$@R`Kw~l}O(Cj_DXcyVm7@U^46pj0~+`1V<$1XQ!+Ga$4k{YjK)9TXkC9La*bW zjbxCWdDsb&vraQL(x75A8O2y@&A@NhS&F&XuP`A~T7wd*j-ToB!(xz-!ru)*S zDK=g-Zd|VTW6S_Pt6O@p=SezKeD6rDIlbW4) zQ8MF=@|ytitQCeF%#T&I8>Zl&v}_}qf`?6Zw;E ze)8~FANPtY-;BD17+9}1>M(6p4>#K9sSf?+T50Kb%b!_||C{le&=_PijD~ z!skK-ONnuB$xw(<)k6{E?{N1zcO3IKrrFb|Fz$wHS^`@`d(F0b9ks416&|3CnVw^W zKko|BlFxK~2l~n5R=KUWsO35vnb`3}hsQ`Xj8?$PiDi=+To&`&Rq54BsMm{4imKJp}=aklrE6~Bxhk0qRr_P`~n4MwE@dm?WR3@Drxjx25 zk8{zh46Su3%{MjGg4RAdE&Y>@I2poO-6?rc!BN~4)3$X??@TxYN-7PS^;%w0VKF|n zqWY4;HQ=DZo?QClD1ZZgp{1sH!vjzJPcjG9Xl!-)h9dfKH>I1g2d#kc@Etm)Y8dZt zy<4;hocUx&knsSC2MgTrr|KGOM#|1{+bv;OJ_3kKiIbOheLQ(HS*)j)eEHU`qrR=a znJ&B44fTfrY7J}0%JYSRM&3^Nkf001C5dy%b8SGs{EsOhMAkRg=%YIr{zGlT3 zESI_&6qn;9u?Cl;>;b!Gq$8RQ(U(EfU*8ORj%1r~33`F{7(gI3ps}4BNd#$|)Auj| zOYzjZ#=hFi(*PP5`(4Sd0m~k%Zs*dJ%sGFmew4luqrOr3;hI7DX>2MoalMFr(GSD< z$B72_Cbm3v1(IB7%zb0{9e*5Oaa&&1A#~_KoZ>3WW(#dp3G%=CS6P=B)-I$X&H{ z$WX$5xqS%dW=CI0aqOwrqKZ~xEi*dY5*=uauOBIbLAgq&>%ci_No>#JoqJ4tlBp`F zcg7ZnMt#b=`S4~^zN&vC7&hx#+t!KfpLiwL*T;7(EVn3p)~*rQR9jbn*El_V1RGy0clCo^Jj*s(*DKDygwc3;z%jWjYc{ynm1}~@B zo$t}eXsZW_E#U3FEO4z-hXsa3>bp~auxNJ5FwODCy@(V2o24lq`lQBEY4sv(>qHIS za3AL;?AM-7EL_F(s(LXpc0jrHF>XQDp_~F1A~q@j%CdkBV#2)Jqn&-Q33q+>7z}Yv zZJ5hUTx`duE8*1~Pa7<6I1}qqWff?`U6dL1bEr5jx>Gi(VvmdlCSB~0^?v)TC&Rj4 zteRih<~5|%iXC0vgIHFpHRy-9LCH|JZfclwN^95-e(D@MgLfXh!P>U`aP2-y;lpj1 z%h3jCTfmC9ELm1UF7kUjq2F+|G77uNC^G3HNw98Wx<8#LIE}F`s-~sSiLxwnP@RO> z+TAvp^d@x9#ND6Jf+6Q#|GNxY&y4R!Z*aVMpKy!E`lMy7z%AyTu5S&dpt9ys`d5xSyuhY*c4u z+9SL?+RG5Fg56133tD{{m)E$!lLML5`iQ8DbDb#Rn&#fg1ACSl z@kB2#b#|y$jn@#{K{}-11c3Lq@HN+k6*LQndDno#+Pph}x^ZpYp&Ln_*6-AcEM>}m zUE^@h99n$+$G_t@Zjr*%t3EE9gj2H@8D&%@<*?%fwj-G$(>ME+(6&~U*Y6E_akXcT z@*8yRuKHCcAArJE12dyv*|BkyqvO*8N>mE)6+NDfzO9aqP0GF<<(ZU~8+b8pN^TD29eKN~Gwj&0IL^^%eNPK_+xt5FAB0JL5WJf~o7wWxv~?B3B@Or+ zIeA4g2FqNxY3EiWXkC)NcGsPT{?E5cG0EFrB;&KkULI}HV_k50wH#^bIz$*w|Oc4|C9;T#>R`x0daOi+?ys9S`sA>bsq zLLn6q`LiV5{4x4~kQ`Cmby+rZDiHf~pSjus9@#GFHzC;oBP1OI>}_ZGsJW4lj*PT< zoUw15t$H?2j4_ExSE^1%<6>XrwH6e@Ws~hKH6kU(d5flDo(Xw1N4h2ao-W;OQ(|F7 z`}OU5t_T!=E=U^~lS@4^ubWR6!<+;RM59R~DuIiWeboa!CnB6G3M=EJ@&YFKNM95~I zUizlYz%$}0ST!hYm;&`yTQ!sKXd0LJhDOBldaWNRp1MGI;N6aUP)rd&q<3#}&fA@03 zZTAN@%GMv!cy#rLjofddxF||p)We(UH+u|Y5KEs4Asz{?Ga!k@V+tXTz;$v{bkW8L zmnl;FV+x&qw~<3Ul3b5AS3#oi$K+#8#S!wr=3XaK6+)yC!9d;e$IK8xZ~Px0U8YGj zUY+kD{0cCnr(v3o7?v@$wR%%GlpGo|R!;#?(-cFbp#Dr^7xB$q-554{!zxFreCk_L z6u9i@eel=V7Zka1kLz&6fHK17R%7?K?FdxEc|8n#sJ zBN9jfq;vOdfK4?CkYCR0_d3k7@~x@GTCN}>o#^9FSm@-DMx^M%Wm)l{I1dnAT^`-( zAF{99Q6efi2?UycO0roQMlaE*B(OIc?203_ulzVDN77=XCBTCIR65__xL+8t74tLN z0KQ&NxW?CNJ6gG(d@Ale#JUnts7CeX$Hjh90A5mhTbkn>yEbnnaWVc-_c&oSoAD0M z9sn!k)E5_#0vGGidKVQCY#~J3Zg)Ubzp&9I=w}K&e@zYTgRt~*Zj2``?or@!INNKVV(1TI@ zn5&^ZHf1lNaVXQQ?wa>O3HpAOs!jNBdGC=U_ZEEPrSbJAez`2;5>k^x}OcT=P|8*gP>Y8M2E}|r+w9XsEAw76@3~EW8x(OME@f; zMo1t&z}KmoL8eme>8(b52}3qAL<#Hm>g6(TVvR~W4&G%22Xjz-TGEHk^`9|raHPKh_IlI!azz_ez&)t*tT4C=@U#($th8$k0URSP#js+#cLW1l+LPAs* zpw<_H-j!_{KpO#`7FK_gp29;M#&ytDC(FP(&?Lu3i?;sieA^7Fnj12K-}YHa z#axZ;qnIj$g)@cQM*yw=0u9Rk_EqSJ+*n>bOo=jgZEO;GZMCz!%i6bok?!MP+)+_HeUPr$?kqamQ*qIhwdTD z%oAiD3ja%fR2WufsKCOewggM9PnVoX0rTg+6FJ`ZVi?ZpKOuk#ZTv;BpJOKZ&Q$Ho zfcgyXfXEa4dKe6Ydn?|;W@Ue77A=uU>+GnC$Xs5Sf?I6q=PHy9hS|oKj-n=-ETcdZU)YrZ#%F@ z41=L>rKF`{VKVWhhfQqPu`cG=y=mFR_l(TmmLW{x`N@?ycEyP{(kU$qiS%{7NXpO@ zWe+9GYi1Loa_!X1E6H&)Aac9w@!RaseA|illC^7i=~~$tu}nbxEI1l&ET)oRhnU2PX6Q!-p=-`t3~NhJ*&VF=yjvh$RoA@#r0xu))!l~#AfUuvW&K-+z$ek@B$zo2h%ywf%PH+%xaL@=MK*8^9%9BuD&(}Ii-jm_M8}k zH#n?kGI$+IOnnkV?JL4YV1Aw#ei(+!7D8mBqxQDDDwNlec8d_-1}a;Z#iG)w1X=?% z6=o$nMhU6@9v{zDGU%;i)B*cSeI}~56hzp=<{7B+#W3Qjdc3bETcgAPL|DdxhLaxZ z$cWf?b;k>4A&ZqWUimiKRx?gQ!b1{8)@cbv4H0^X|i*C1>JxN{=GiOnU7 z8wlmX7u1XA#3<_`q&c6qt>w$S{3go1L%{yC)#~-Ng_P)f2j(wT$2R+#JT&`~;<AWdG}4e_dFKby%X{7xI1FR zB1uR~<+(d@+&-u{z@2|Su*A1+)YfZztF7G-2U%o>nq4x`ccz*dSQ|S>$ zQO&!V5S^%O!-p9_ygpRgilFZPh=PaxlJ}ss@rBv^^(!LqIRmHo`fNf*_aT~DR@M^y zbh@HMyRX{bo!aiyc6s}68Rt^K+tb9s$_~)YsQE0)vZNUOIl?6?7d_sgQ@6XGRW~gpVGF_1(D62zXNBT{9w<>0AReAKssw?eskgVlH z+PxELKCT}V0F9T#<(MPksaJbNZ3$TU`iVX@mkho4aKpo6xH;gU#>;pkcxsmb-;Q7q zFPU%iuvzkMg*4CGGfvp-^Kpqp+ zp@=}S>@e)%cd<%GGusk1M1+bq+U3?iM5;!6siC6e2CN@t-#&}=+0zd^DeJ%g0<0~z z7&CXq`?5N^%*FDeTt;DXCN8p~#NuZ<;fez~9aH-66yn#*;RSemL0f1E9F~;X>h+D* zO7TvL?d7=SUK%eZnpIgOQN2J2S0HnHnL&Zgr_MJHp4%_xM+}f;CV^Bzl+^DB-O(;4 z-H8t6r-OxQqx3F9iwIgyUsmnk6uJr|pWndQPg%Bac231H*2CiUNR21Nx4%ow0ZsZ|n*x5iH;O8|D2~RVsa0O}6 z4Ngj|hj$mDHhz32rY1{{U^`n|ZRzooapt#Jr_ylao_kEUjr%W|b@@Y>)|%F0QpkFz z5Wt?K`O~^+D#dE#p1mbK_iMeC&MU8Kz*{foPkOLLw1%<*f0L3~hVF-+j^2-IVbWAJ z^*chN*edd3TL5nh!$D)wQ!gIIMaN?&P)(|q5IBbj5}?cS4vM@fNM!ky8Gq0N)Fjt619<3<8t*nt8W!iebZc#h)BxrN|( zbD~rKi2^2X_=y$n^%|A8%=Cpyipg`;XM!szNlgh&FI7%em0g_dwFZU(jIwt7219&u z^%*8+x;*H43*8~0SyHQxo*H0@)*eY0)zKLI21e{>^^GX90xu;^)W;)=uhL@Xtxmi4 zt0~zQp6JeqSEMP|ixEVYG;>0!uO4;{Bbpz=m?m-a_U)b>oe7w)U18y;J^Pk+>uBw5 zj{7Ao12XIPa94{CA|ZYz4pQ_TEX*(TlvZO5#^+Uo>Y_(_JOIpqM>vtqjczI6ZPj^| zdag+$Ap_Wo=R`K0JWfB)_mYr2>>%|rAt%o!MpBvMzqs#~ZvMe=w7Kt`eL++(6-7;E z5Bla8BrvCYNveuJ-ZS`Y>2e4u@n{rd~Np8?0OGu6bkc30H)7q@z($D+SIUmQ~D zaLus|0VKrw&AijTp)WW0ZXNL#N&WewCyp*)ie*0Gx^AEI6Q%G~acdNl1Q!vZpLJcq z$Ifn<)JTY+dMLcB#?EEc*A?(cMhGBpv{z^?r^wS3+*N7pZdE^$`#Mz_S;naj-c$qq zUHn!ydN*6@7`F0bx=jpux}e31-{+`Yjy^6V8M%8`nZ)3}x~b)^7l8;Kb#hg^9jVzA z_@$busrg|psA_Nn%cX1+=W<76#Zp8|*6bcfS8GmbZqm0wiRn;X|b3&r29ROzniJ-k`r!Dc3x?dqMWdMw0)45$t*}% z7yhr*^d2TPeNO!-W95xtWzCC~Xc4r$5B_8ZsP{K%Hvr&=YH9l)pP2Q>eg=_R76s`} z*tB*D1MmfvkjCwen$A^0Q}-S@A(DU`Y>(0vZKSfXg2tsf1pql-(3Pz#B7c0ays=2m z0y&n8;EuVHq`!S$R6#ty+&N};Z7oYg;^=_}%f4nW1s8@n-Vq+2X47K|Y$oV$$MiS8 z6;P;m1u5+(Qmi^<4hX3$#$BH4lBqPO7uR7Jrq~M~$qdpSorH8u&6WzbO|D(u7d9`` zbhw&}1LPMXhRB+6quMs2YJ-?5=-Ei=iruoTNV!upE-=$4I&}|R1=v-tF9#&I_?u9+ z(q|KUp!0_&%Xtf6hMbYp9^PSN&!#aR$R{d}MT_P$N?rS^1_RAZPOJXDB%@5>K?K&1 z#&t0D!zpt9LU`_c@rGW3SDOYs**^{eA(dty764;_tFOX2G(9wvPJ;^b3>rCT(S@?rFE^oF=a{~|EL#$TyTF<)+6fv8387w!vF zSduO_R=?QA;NNiw3&aL*fy3tx+{BC8VH#{*K&R{Z{m_xkV8T~|m4ev9?)rd&6#T0PcZ%s-r)&3TTv zVcrynxLGs$oy^E-pP(PKY#9CwsW#z-$5nw_RSASdk+)M zY4S_Iix01<-cV!o*3AkRU)Mok7|`&X1X8uUNAYeki68=mf?aW`nZ8z+uw-#jSYWJo zUZoD^XL|uRnYa8^sUmgG)5-~%(%!zpLy~>=&7HL&F9fv8Z<805635?KdRjSD^?FaX z2HDdQ8ZQXjTd#;OD%;Nqlrx5C|P1iM5+MxPO(dT#C$$DWu`UW9 zep%0}mm{@;oDjDlr0ttU8JRme6DYMQEnD6$+daL%R=y1cM}&U<(NsFxo00zE`tpri zq-Kz?vE177ar^e^GMXIu!PukpLK`e;q(hJglk;46Af~Yi^j^IoS5$^ipQ^W6zsM?a%uio(yzcZS#qP@~_ z^-|-J`+6LmkQ5fZtn!mT)=$RJ1NpvQzI?x!Bxv;Dy;gIPRCA)AGV3QTo@|r|_vcNe z6`p*CW$-&YjSYn*7YomO)fF_g|5TfeR=X2|NCAXUW&Fz1Vu;IXdWwxfM2hXjQbzlL zfVF7qS@Fva&*{F1u1G!W)tMkG(TLglwL>(X<(wZuF$&Rq6Ls-c=86g0>eJ+dEykxc9DGvW50j0>ime)&ygRroioaE6__$?e35LJwiQMP?DWdt%ji^kTeqUl2Is^a@YM$9f&rV9@3N=*k>AUF*@2Bel z7M_Ey+$_m3ho>Kn*vN&gA_UpRbH62HQcX}aWBrIm*ZCqpw&iy z3pfVUWuM1KhsuTop2V07h33tZO{_$lgtr*AH>R=CUrZ^R0smtJzxfk_$wJQb`~8~! zyR%jyEI8{%5-qG7DGB%j5m?F2OMIQes_zcGmJJh245=h=U`09lv2zL8fh&w7(s-n| z^tBmBQdo_qfffR8SnXTrAKURGYKRe`l_~jY#(W6m*daR6Tk} z0VA9P{vo`G2(kJS$s*r#wLK{w@TDvn!V*HHMi3l zp7Kl>dA8I352YRv+8}g)J^b1CqgDM)#S;)8t$(yq7j5TNu8t)0()>p?Mk;?5k4HAo z6W7}D!*d%L*FyqvM@9Jr-`sjhNh` z@&TcvZvUH#ATGZ3`!Pl0Uw3WA#f zku>UuY%mTDQIs{q`?ZfFOrpV53MHUS9e6sQg1!e|%|mv>gLzJuh3QH`Fa_rP_Q5`l z-3)jI&zZ&-b+VP#^0~rarAwz#;n#dp?L%jq)h+FHIgj$M`G9EkT;6>egB$V7ftI11 z9|C5}JM9Hop0hUZOjXJwi64&GoccMI26MB#81b=U_PpLw=K>!I-80pi@tMHT43?;F zAayiK_s}Z$B&^i~=DC%%6>vocGpB*1Lb7-_5Bf36=2@*-&N*qhfnLeL8OEo*JJbj8 z9p|`eWA@sc@$?^jd;||gSI@n84h~8e9W1VvpWfyz(d^wE=oTt^BSOqfxX2q>uAu})$-=l^PZsw`(3OPr5`|t@7Q61$) zx0B3%0hPlL{^bNC6Q%Yr5nr!uRzaJ%^>&7Sfbl7W*G4(!2 z51+ktgZ`qM-}L8aI+mv?0v-fsnvuPR?gszN$*z~?_#LLu6upVl1mL?Q1LkE3p7G)M zC!_Dh_Pi7+An!_yS`6P@6Z+V4GlU%#-*V6?z`qa{9-j9tHgGq{-OQm|$h7qgX!_bf zwY>RP;yrJ)sb^}y0=a-c(a@cbbaH5e_GuaoT9_R{CBv`DJLlC6jg`7Jr407*$c-ih z1pUO5pd!R0ipLEnO+2ab6s9}nt}1+6(XM!`D{%tfr$0a4{cbv1vA(jK%h_-iBVWlS zOm~Vep7q0$iIrJ|t~P1+_ez+>UTHMtjjrX!G?4Hex*)D@gW*AST|%M z$36y{zE7er8+3(tUU;BM2y^FKkRdYbwW9#!|MHCUzr=jRB16~`{w!j5MSB@&>ypCy z{IT3afW!tKvl=q+du(%pfzY>g=MThW9@cy%=FLg$HLapMUZWMS^dz0fOE=v(@}wq+ zN5+?&9O=yeR6rXXJVS!MwP=kj$GKV2#Ni>9R-K*XR$}_;*ST3|>WD|Uj}{m}{uA}x znKB)X?`7~bX;6KDNZS)W?53~q@x_2qJl;0~zz-LMsN9yt*?AnM>Oa*l&G>-7AkR{n zPbV}BSj(q83ui1)g-WZ%IF;50S(9YolVhtbmP#2eL=8tVnNqLdWOw-^SuQ}`4st}f z&t5%d-w73vDwsAFE}s-&&)4@@TlK{THo)6aFE-uq%%9H+z4Ta9qmv~{XmH)OgSNPM zS3^^hi;CS>&XZa6=T)t(8~Z&KGuY$&zQ<%h*Cwyw*ec*@(e(eK=wnjx6j}m3_s3Ln zpw|K5U!doU1iX6tqsX@@2?i@?9CbS2@PWiMG%*qVl^=qhFgqH3FrN3=no}=+E1>oB zEehH7)2?S6KgbaaQoE>Apb zYVoqssKU*9%UN4I8L4LBaIqXw!W)@G1%$Ij^>pvHyl`slSgk3M!4EjLgKH%e_?{TC zfo~P5t#*RiY)4<=K6yMsbw$fk++aHd+QdiU|1u4k3?{FL{Z_fuVxajTmzUJlLf!;+@v1S_uq%8TOwrZ* zM^1_-wGFsE%X$jmK5uoQ_Y~|Vhe$!Ml5Ep@E|DK*keE>|g?PmG7_|&Ib`iJ-jReLm z@uKKke1Y(9VS-gKay;xji47ou5Dp{#y${9Cv$py6eZ#IL(|{jkbl;pNOc@T4!iA)D zHrzH$Kjq^>$!Tj1O=%X@zoZU32H-5U68qBcQ~nb72ip-wCq^s@D4j2Hk_f=_UeJ>G zmG?2kK3hML=tp}LY5IMed3de5xuFyGwo#1@@uF{hU1Q3U2ih`9s(VEEqx_?VRKD3T zGX$OJ!=H}7bl86xPG2fKY--QUn9A;vzFsJ^#~Z)=Rrm)EkXF`OHGYvXtB0& zA}M086?HC3*sY+#)kUo1o$tH0L> zzO7&16V;#_^<(D2-Ko=aF|^hVILP_f)`(6a=a~B6?Pu_sR+W zpK2`0!@s2&R8VTIwZe0As|(P+kX=OS9%Knv&CnIel8pLz7%OJQT*ng9jdJLp?bOTA z@X&$?ZefQTag~Dt49vGS4{<7OElHBwh(onNjiChyNvu;a7R~WnTk)x@HxNW>gX_o} zkiEsM<;~;@Xr1s+j5lbkH9$0LAqq6=#HkomadD5jsVLjZJG8oq39Ica&opCz6)>oR zW4PRXu|qitcW=7V<+{Avkb7HLf|jq()oglGR!rJn!HG5$Crn4fa)(mJNBDvPn9^IA zgUeL$_X0%dm{sSr+gm(4j%=nd%}0tRned90Qzv6+(JJK%ie2=-bKI6n-*Zm2VEJtz z4Re^f%-1XV*UKYzqLs!w@&v9P-B10hu+$}^MKf$3H0XAsXt?ux1HKbyPi`%;n7T$z z*G+|=XckJl8KZa^<>i1D)k;sAXqooSQb-{uZQB{qY7aA#oH>lrqP;QztD(E7{M@!N zD+*~&Bw?fqgUQo*E(%DZg&%}|s3XXcH|W-XZjBz%z1%5xQ87D|6L`1YO`T(apLge! zW%5fHb@4o`U0PRLIO?qb^*XzQ2>B!2#lts7x{bjz)ym!9eM(a;vW7Ke5TwEO(gp)h z6^J&1Q*C7HeOWE0`WK}UEp0Ya(onD7)X*xR>6@rFo)mAxS1fF#Vcsm>o#iAyi>oeIl(~;@X0W z;SHYi%(YwAvRx2-uTcO4JdnUSQc64_(DSwFPBVPuDZJo@!0?Ot-NBm1_) zc}t=|GRO0!5%pa11i%z<$b0g!q_#q5iRG!WqYROT_^OS(`B9xEdk@**_c9#x3+w97l(NV%&|0vx)w? zG+mjlhYW@J7WQi}pOtVPVaxtmr@FC*@rDH2pSgPEuA0{eS>*bofVaZhqR8z6`JaSP zYjI79Wesv`;=df6vU0$eJK*WP!d6~QOQ&u6g9v?&<0;IAcdb>Brc$5B$jMz*fP-gDwqr5pDFVIkgGK_Txzu;-fl(Q))SfEPKA4}8l0GU*5#ZUEEEL(kgR*}Gg3oIg z@lOne)BZtoUGpyadr7Tmd8FPO2gs4eIu3hrRJyG+V;@70J^_@bG?N*1$xLQw1 zUDbYDZ!RUjxFIpi%?~8$cH=g&<)id|K&@JWb7QEn7pH-te?NbS(H}suBR$JUF>5Qg zD~+9kRYAH-Fl=FCMBSpt#+XL2HN7t&H>|{1J^6Q2uliIK`oOLUNyHSsT+x0dk9zPL z^d`&~gm?3bKMGbkni&d}75u(Nqz=30|1v}h2O^22hzH-ocrNJiyX8p8K^c#u0`?V= z4jXk#gxpYZctD@LYwLISp9q(sA{^|ie>CO4j0G&m{D0O2_;3GUgxr7j>%=kt(>plP z_uu<<{tuSqe@qXhF#c&MGE?coJ)R1B@$$KS^Fk2(uU&3fE=&o_g=zPtI^MPED69Ve z$E29P{fW~1<(_F|^Q1Po5|B;nQ)$D0G{*wzCy#Ierm$M*F$|?qCTBbzTQPAXl#sTbG2sNw`cv3AZ-}M8n%{W^ zC;hjXgYjl<%33%~aO{`)P|szrj-$d>nfOT6gGH)TWgBgBn;f(~jCD25$mR4vOX0$Y zb|im^okY5>G}axjjjJ#q&d=B|{6UI%y@a2CtVI(X9WhDY0n>uS@WWeM90#E@; zF{PpaWl0WTzpI?cE*I(Z+ZLBG3^TArW2Zgtxr6GhVi-gao=Cd&#G$O!BE-)R%{I&l< zC^YhM^J#qNfxUr`SOkc31K8KyQIDq{aVQl<{c#yMK^3U8HU&%i?Ht?CvRm6eSnlH8zu&2O&?$)k^ z_N$EVL5N};Wj;ati~Hk|(A*eStt9r}(v&f|P%zEoXr8!_C9{vV+D7lQ$8krHI~#X% z72#Bim!g~mm_@%go&c(>2tZd*S(n=rzW(u7eeE&i_YuTUj`pbm^p*KWs%hXE4tons zVyvsaxW&L&xFq1$b|kD+#9}p^y^#DjR39~a=(k(-M+%5SQxBj9NXAHFsu z08?r5(fil*FpbIl=#loqbiVuqAaA6}Rma1CH5&h6hJRP}n!v|ryGUW+GJyZjpG43e zjbn?@*@yyj#1Z_X=|YGe`;u4D|3Rt$k2@y+ExiASX3HRCQpgm1xBhZX^|w$%f6S#v zo}e}x*0+eAezl+cO`i~kHqcc(I&Naw5d!Ok-|_W z4|&V($%RppKHJLh?Fd2hIsrD*DiU|Pgy6+ZTU(&>8e{7aSM+HnUrS3i-)E_-g(GpZ5G2JwC_cKHyZ!EizK zy8Aq^pxYm=T1@|3uzE}@Qv*=lK~`pug%7~EUsGEv@g&}8oQAVs7O>@G*4U!u4tICm zE0v!-yJLI!PEE1|CK&6zG1yxb2DDm{i2dZ%zMTA8BCXD4MKYxXXPQp;)_0QLs0m(;o#fk#O9afQH8$rRG^M|nK@2V z<&pC!`a+&vw35Dv&RH~XQO7p32K#Oj?dr(}6Gkn2^0JfWr%_f5ftS9l_bjNP5Jilw zQ6A8Zp;p`VI7{W~Du#>Wxvrw~`ogyB`5UppVxMpQttlkvf*>zwpEOYr{zKvaRmxk( zMcIAt!YU$4cQ;6bG(!l|ASEJQ!bsN)-6-8iDioIi$tZuWieSbJU9y4Kn|eDj*}Jyip*+GF(=L|g68k#@L!EAHBpMQh@Whj1n2 z4Kr)YvVpR)42%2fwx4*=ua#73b(QZKA=7s0WRe*2z{`zt+%sXJ)qAUv>CxLJRl0K6 z^K;Z*oAEAJc%e=+UX2@(Pd0V00O(VFyc~2TyJQ`Ca#o1i& zwbq@N{=h4;6KMBpWLMJRNNE#l zviOU;dK>>W^{ugzhh>fG-o9Is+HrqtJQ>v-xr8JIXS462A^x%XbZHoIZB0LK!q`Wa zAgvlpCDN5VcHAwt_4~AF4xI2A{pPLBi!o??DhXWK9Gj!|^RGG^#V;SCvlD)b7htTK zg@#i^=qfo#jlpB!(=0}U%z}~VXMXYxBp`$>s6D`&UuXH&T3A0&~lWbURsK5S81OMtg z&`z!~*QO}2)jzR1YopZD{XmMBgA8MEteLGq?dAz{+JQJ-Ai(4+hzmD9DCvnbZHQeX z@kgrQZH+4)yKNJL=ty~MbL<~n#T{$vg1l^eH^DY7LidoP+@gv(^=09fMVI63zuf(#9D%6=gPZ=Krv z|J_U70Q#cE88rj2BG`!!X}LY+UTiF%iXuC}|hIb(Ol z-KMWQ^a3j?m;@W43uYMXZ6+^>@xnd1Rwo*Rx^&FE)6Y!|a5lniDi`;CAki`9Us(}7 z?%QS8{jLO7zf=IP3-j4q*${oT9Rnr({Id`VIVap{UW3t3_Z|~RlLzVQ56}y+^x$*grtQ6YC76V`-$&ILT*s9*KYhwIv+9PqdwSLtx_3iM(iP!FNI+K9}GY) zT-fEK8%nNX*ZFW*a#L8k5~TG@+ZTHpNzB!f2CT965FYuNAbAV1@Ot^s6;-&HD6T|* zK~O;(jpPkG-bD4m4Jg1^V5Z5Lyf~B>fuF;`?EzNV6e>3ysT24{V=a39&~ZJxzNw5GAIf{l`HugVf_n~{(f7Z zMx)i;MXbSt4__u;*X#G>D8(xm9m5K7Pds5ZNs*`4{6=4V(X3-?$Z#C=A{dih8V-BR ze6)GnBs%8X?F4-*hmPGJ&VOSJbPt5j1Q4Y(fNUZB=t|L|vn0}?ICq-#P;6V35j#rK zA=w&0%G*YXxmOv;&m8EUClzuaoT^IP6RvDOp{0Ci93D?3A&MJto7B)7BD-a4THYL? zfH~~StAeclACsYpBuMdJCI}nRPBr;>4sidvM>R9;=D=2J<}MM!CY<#4bf6wj^J-%u zcciQ#Hwbr;DEOdTVHNc|*=Ed2{>aMHz*EdyHk0ERPa#CA7I7mydSlkBVsYD_e@k%u zUmkw>|D(ZQ&Juxn5 z&ON%9;+vjt$gUsyhIhp#d;Wajv4U^B$1Wa5;%0&rmM=@pO}9}n+fc}#w_vZy zVj?`c_y(<<1>R7(vQvMa#_vNkL_gURX{#VFfY10Zw@Xh@RiVkpi5YBk8oV!ND9j2s z=5!V@V=JH1wgyT*27iDXpjn$3Ao=WmjS^s-dhjUZU=$d^?YOThv)rW=9$*6)08|n( z+{}cR;?Jt>vHn{x^hil!5QZsB`27NChx9>Cxq=YO7;@h+&~7jm%Mjl;@_r|f<#_hj z9k=HjG=L>IRWIg4w3ra%K|O;(PnM26LYP19;)AwY>}B@V{sL5IyEQBXF(Zxc`&bP( zx&oQDZ|bccR#Xyu0(ZfO_+S5}LdcqifIBW6)U=d{P|rIN>QxWRl(l+zybAwkK-&G= z+5=;6m{DTog@Aj#VWiKk`I-84gN`C@+8-l8_KMOInOHjfOKOqFG!cqUT0lQg98x9) zx%525JU9q|%$h8fvI6dFKM(@0fA1niNIYP;ylMZQc!3vZYBOls`aze0=OSZropX>Q zO&3lH{nF;)d+)lkEYxU@`=Ub{rIPO-(r0AQqKBeA%=LWy*wa}`^TkWokt9YX z^7XEy6F+lTA>Ag?)XCVVpC=oP2M#ouDAz!LLr<`(gj2gz@burbgRXsMS^i=Zh` z7P0n^Hoxe7MvK!fiqi`d*|d3o*--?BNL*0qbyRiO86UN@l~bfs^cxD=&RtAlpKB!g{E~)Ey0w7#t3)mJ#+hb(uG2>&*Lx9F*eyWFyno?hO7{9;RgK4< z#-}vfgTogHN6b%5oDxMi#2&j(oJst`?KL(teYf6zPar{mj9AgB-+67~r!r{e!26(B z@=fuDmvX1Gd$WC{7W?Af>@}YI;RrjpD{>QjvOlEb486F4xP6g>TobUXH3VH7&%75L zDQW)*Y!ZfZU|;W(pZof9>Z#d;M=UyYK*phOH8Q=6{UI3oV_!pAB1!vQaNDZ2P#qcE z=3n=I+Cy!Uu#^pcj*C*`RA>~~WK085T zhlwa-Rb7)VmXFX?xw)2=P{`R+LF$)sc~|_Z+lCQmWh1{QllVI&D85qr{oIm`eSukP z&N(cPIj={w#v$m?fTfaiPuFiM(ekEaw#G`1K&|FGCZcxYcVmMxgF#aUPP!3El&VvT zQjbBT#P+%D#w+Zt*%OX)PTPn_@e~<AQ$a-ko{hFt&U_{EgumDqJ6Qj-Mcw>Q|i~vs`l)!*S-%5Eug?{ z#haed+*31I4)Mt}E>5Z`JE|4=X34F{N4*(Q|Q}`YB9{&UXr*kqttA z#KGs(_ayD0{!z|B`8sg#QbA&HOE+>I%nr^OJ#b-xsjV^x8QPzS9}7K%ppaju4ePd9(J!Zfw}4LwHo2H&tY`0le+x$774S)lL4d<&5~xQPmw zbK4koSOK-b_Z`HAb;{1sS!)Daq`l%6&XMPsi5KlSTUtGOsYv7XGB_5wX2W?7R%jGb z7EL^q6Yn>nirAi#%Xd?DqmtI%)J2eF8mDe!?d(f>PuZ%)VyZMYGWU{s0PqV|;~GT6*0P2r z=S&{FFc{JhOf?qlB!u42xNvoI+#(Gz45{~(#rhGvU@D1~Boa`NV^iLO`-&zW8uq1gK7Z09%ahqhtnFx`Br?u)+-aMj zChh*&Nzqc!)C1e{i)M9?9W<%gGp{mtYq4Kn(0^UODW=rUF+Io!pW5~rrHOor$l^uo zR{P!(IiU%#|HzJD5sq9LF<-hM^Z;)3)Rem|M!Y{*dd@r|(Wdr!zm5&2hNpP984%tj zX~|#6^B(R(G3H@IwD5+Rb9`TB)Zs_v*TJXDMH4A{ni6I??lAmCDm&1cx@{t zyeV2|=1!{{_WQ{^l4R;3axh8p5uaPB(=Fs8 zbkk#p8B(?}?&K@sIoaj%i75HKaY6w8_+9}Z$YpQw?0&ef;?LfgU+{$eW2c2Zjd%Fc z#kvuPcqNfGiJhNCiEvblV$L;o+b2fF2JAS^QhBWH$Lu(F;ySvED3Le%h2*QfL#AY3 zXHqLfM2mk|-AAKO?v)82e%w=f6{0^_%9~cw#`oGix%%qzn}OL)uEm^&{pWA!h%k5Q zCq2XNTTPszrMs}>mz~WnJ*q2wg6M8+T6R?L)90H$j9D1AwAEHLo51+QV6V$?cD;u% zkC>}vb|K{p#N&HQ-7(V4XWktZurtWNhbA;SSyEDIjKuBKJdRmYr42Z;-t z3npEukvmoKr)$)g?l0+hA4?aUAdfjy(F}x`Jz2ap;k0Xs879G}@MO_EccC14e(G?V;0Pj)pJf9WCs8e=@cftw$oPt%6LcOh~>7miIUbk^~?5 zJdz6&hsCT9$L;V<)bmsGiQhb_%7A-|nEN)~r%3h*)&+x4*G4*YDmkC*%hK$o`v*FO z)#I|(Yc2J}t}}H*%8)Soe282 zgmsu!`P5RZ0L@!qrklm02)zaGF9(`PGzqH!bDq9IPgVKD3lkpfs!qMF%p$jJH^ehZjqY zOzXZ=Fzpnu!NbG5tvvrVZC(Au2Q@GDPl3%mq+jRqF zWC%myX`z_6I8jum+VqkO?LbbQ{Z+{UZ|<^R&;2jjgJGe_P7}n^g&}*aIo_q+iRN8X z$ouKSdLh9OS;8liL!Z@l#;iZEICnCvspK0S8mV;qGKKsxihR|irzr5=Z$xBG1TERH}mJSE1V=Z!YF=Yezc&G&o@XHzU0|+ID5=U{> zvYAw3eJKeS^5~y!5$?YlGaqXo>(XZ(0M|g*W7@`Kq(~7O&WhaOEc~kE*sZVkGzjkqC-5QpQ>0kRm%=Ma)q+DD(qHoGd-In6JwE8+{s z8BpR1gO!#xe=|}~>F<q6!Cj)C`N z{!@GMdMfgI23~=?j|KYtia>tNI@YSSw%2cQFopZwB4b81TWws~yS2WWuU4WnV^_MD zHmid&8;Oy!=W2doHvRqLp#JwU-Oc>L zW_zZa$QxDi{_Nds;8L)q<4{M<>0*KPTn%2aj|)39R=DNuuKtX5!EwQXH^!wAb=nB{#XOU7C^?BN4mp^Ub2!25|K+{NcXs6QW3PiwEnJBN%!2 zm0q20Ygmp9i&|ZZkevwZz7Gqz+KD1$!b)~|BqCrJ0pEOinM7AWac7(ix0XBwtOFH? z0G_NBWf+j1W;xjK@0LG48&38xR)~j=JzGL+R>RS>^}`Yp@WZ5;E||;U)IV@u$@#G8 zLONGWCeq|JvD@8S8~=#SbrDj{-y)z^B2_hY(IA7Te7D({k5w9p2yaKFj)@pch`HEO zJ6)cw)v4U(R?VG!J9$B5bn3%5b2;U@BCSXy5d}R`+5M?BpYH#>EqIIf%(|E3@@O%s z1~Ha9akW`8QEkE{_Z+0VGF{Xi@^P+-f~2yBO4@YXbRgEaln-urSXUJ`kCtelaNU42 zC2&o3En*^!A3s3Lyac$ewncSa0TE|*G9lfmRt~{M-rT+k(pl`k1(f7@8{{{`(A3=I zLN=!}&B|9TeO$c6j)(Inj2G-?iZN~7%SG**8&Fe>&*haTxYVAm0GbYo#5{XeEWu?6 zZKp=Q6BjY>T8H6}fZ;Ne;TM!F;FE8|_=yE?arK33`L!4aBt^Pe{iv z>F$`vo&1c3fFo|zkyV4YHXOMV|3u!*Q6v0mPyo|R!4-E}HL`t9Z(sv9yG*kgu z(euB4#L}?eO{u`nq51M!2v0o+StS0~3tHu|{~MxW1OJ97PIR0zwpz+w3fZC;jr~0d zaW|Z3&PI~VSqiQHKwMCWcaZnbkb1U&+LA}AlO2T!8A5er)T~!t!jZ8^5X~wp182A$ z$U5_}POYy9Sgtk^sVN5JZJ7g@vqD>u;UYj635xf>uz3F!Dqe3C22xoSR97-GPJJAh z)(d6vM@DZM#L$kCLaeoZ-pfs0j1AdI?lC6uZvo|$e9-(1%|om9H0KLDA*@}!j-aa= zw%;v1!;Z7Vzg^?>y#+z_GL?S_6SEHF%5sHgWuw+Rrq-K1!oZOmr^dQpTuFurb{n`p zmAAwHCYTXoGt9!)PS6x60XFbKvrJ>4{VtW&4wM?fc$+jrwfVF$1kA zYI;NaVT8`!d=wEyb4*6+f%l&y`z!y5n8=IT5kZupf5JGr`z0um=z3bQEs$Vr24fxc zb~ahp{j~O7#YTMOG}LSXE~(hUj0LX8zj$^=y5~t=ykR4`w4+r)l@h#ToS3!GrB;oB zCS;zy+euilW7Q&irLl+jBxc)vY(HP$$5gWXb|sJUFe$12dkm4#oUom^?i=HT^fo2<=p~W)K4VL#I5_Ln0Nbt!zD__qRaTxqK_?s61LE zqAKHO#`?zE>^nMAVR-h`-J@nyre0@|Rni)2lEObTX)#okT%j7{+_2KX0F0rSb$x&|_kFGL|8+3m|t?JIzY&nm?YG0j0=+J0-WPlo1HRk;SSx!07cH%lvw-V-R z0H1|{=f#%`#V|$&74-5AZJ%^^*s(oyFycB$jFsz}`tvT`2y+4^AMpxJDgW!g&K23h~!+cq>WV%15h z%4jbd5msLQdySi&Tw&VwT#D;hMC`(HX%-gSt%w5n(e5NR-kzKxWtTdfQ-(a-P5$Qj zt?yExIo3Va&8myOjmW~Iv{1j=W_%<4yms|bRgr9tdd0(w*Se9wUY;l2Lrl@bYyWIE z-RxzNM~y_mx#AMm?s!wz&(G;0Xe%x`Vehu+cBhLvo{|dm?rv*UqZF=MWFc}WzgHF7 zYU>r2whOtlG(%4I=Jo?!$qyWJg;^MAzASesPr=quntT+d-4(^D*|Vza3VemQnX!id z=r(_u$ggrLE5AIEY%l8uSiO4u$5-6Z%ngxS55z90NAz?0#j_hXF7tjsl>Uvm zY~dQev!?{fW_dwMK6~}UT@~fFF`pvKlSr(#Bq9^&^so%R?eIrJ>H+y1MEp=z2$4_+ z(GtgUA^XZF8b5NXNBUqzXEy4vE?9vB-w;!`mu!9oA;C>-WYUnJvdAL#L@`4pE|7V0 z&^NR~*$pG*NU5c9cX@##)i~P?Q0faNruOa*H&-XFppJ|7b;1Boc+uq7s34D+p?|pZ zgfSEHm2CGez9V@4ns~`H!isKZ%3RXt{7;UuhWCtqoHDBS{iP{geAW7ljr5&X$Yhsd z8mWIGSt6vj!%$t(60nRZm>hw0IvjV_CQ$}?#Lj1mBp;lZh#U|}!rQdV``Pxap>tao zOC&OtcaDJ`X_NHmsBOX?3CZxjy?h>X8`&{PBvXOxT?D9!Y@UUSJa_dcB9oPo$w6xq z#v_Zn?YNALjOYK>BY2|r>I*%SZ?E^8!$Rq?{&@kRxFfA`(|GV&SABwBtfdAu1ARE- zKjEjkd#85S%G)^>Yt#)Fqda7ADSUhD9-b`zKakHNw#>eaB0i%@*6Skx>gGZohrYwq z_)|poO1K&zj}R{?=5CH56Tp@8^>(rqEn=QDoRlA_NRX#T7A9gZzM~6vdgPq-8}E-~ zcTre^@0#;%?pNGLOKEWj8@jB=w;+wo#5EUJzTe?!Yfi7sFnU8iR~fD*M{6N$9;qf- zxHb|hyiN=mQ`^1_@}g-O9rdjsHKR1Tox)i0mh&xn_83;}ffcXb6@A_1xB!nRBLVGA zf>@53=aT=?;+^FmJRD_;O?kYAN@jMt_lot{?5weLEX9bC{ogSeJjbbe*Y@##WBt90 zGnGhQ>}P+xOj&cdk84LX|0PS1b1m00nxv+2p|uZvTu?pp*DuYWT@=YCHzC=Bn!~6XBKLEcW>f2cA*{OXWnb^54FPDcHs+(FT zl)ezr$LR(ZChi+(1u|%WH6<`oj+LQ(z#rTm%>?@tZ*73zzs?IkIb!SaS7oOHouwF6 zzrnl~qj)Z#li>n+Hv^c87DnD*c~-<%jS(Vfc8BomR+16dtfxz<9uvC70)lU-jpMZ) zOC2?^J(Z?w{(*R3;KySyDBFUjDA&heRD#Gax~nbEb{9X>HhNuVdb5YUm5eN$qhl>;{jm^yGr(sbbpSeeN>qNc4J4TcBD^AUS@hG z7k2~r$8kmgV|S9xdFg_hIHkAh0&75jS4kZ3M360{)7~Cc|Ul@M0)3S)h`}C{jgV;!~ zx$f4H`0_yu1Cd8X@l0&Hbm`KhA;;%%G7IiM8_Settl-{OdAE4${?waw6%#Vii|;1q z9ApHy2GsSUA&VhtHD`#E2#D=v?24L8deCr4zhTNlHGRW16XHXC8A+eih}xw zBp?DB%n;MABj0RciTa@*P~s9`a#X|DlaoGGxN0ma^jJV__bNK4bC*xnuvMX8 zxTx4>{Q$Aa1g#aOVI0r?dy1V)sl!e7?QD4wCU?Iqw^ib$Gm~_u-xJo&?381+^0puo z3NL~9;O01j+M4F-(bMxuT$>`#;wc|XpIvVlexB1CFbl=Fi;7e>+?Asekh$--TpI|s zETSm}Kl&3zw22q;RN)$Fn0VQRH?kT4Eg%BQkf%T-T1z&VW^3MOqlm}Su+zk$(T$6S z?yH^gbaZ2s)7C!Tg_$j6B3=(x#h^yjyU(R;{?47TVquxMbmiRL~5&m>#=Uzp)M~I65GAw zKe(gHb2P?7_e!3}LlePIS^C5xc4C+_CFh+RY6>3f$0ReD?$91Tf zZ7WZ#*Q2t~Vc`A@@TDzRpo$jDw1q+wE6X;Y%I-}{y~APyQ`18tx~7g#!PO&?N;|D`Ume&tsXM+M;-dw$rEAD*J)R=; z(x`#SAw?x&38|YUKna1i!e_(TZVZX_+B=Nyp`R>QYF0p7`8f$QP%azJBOu& zS*Xe{EFvC+ zGYPZY6`$!C_I&2iFL|i7UWQx6AXo#6yu#W&o>Sc~rsBpHiY^h4>dDzQICSK4#ef_S z&4m0q>92>BeqpfcYsH^e&A9ZPg?TZv(tJ-zW|!FhS#b7wO_&v}aQiW7$gguaMZU;i zNOMP|Cx15zPFhqB#L7YVJ^vWvzo?@~&olnBHh#fNa4BN@yE%hnsfx8!w6PONU+8R` zlYOc=Hi(X3cu@7a?#JG}v*{m$TGpyZUin#@A+C|r2ARIHQV8TV@XcF3XVyU#+dExr z+~Nd{uv|EFs1~q>X=0nn|9E|~vW&HR`s2R%j{8_}{Uf~ur$KXDao?m8{=gqp;LitC z^%d7Md+A=M#eTEVCvK>|ba{PC$3Q-A7HIT!NnS>n*te+8j{8>JcjR?HQmwX?QMH|XGsGsXUuo+{?FEpt3}4|v_@q^1@{u4We_@F(V}dl=?t-nV8wWU3W=JWGn?VsG6cff z)O3fWJX_{?MKE|a%fV`IG?!wHo%NHIU4q87w-<9NY}(pp*{h%k7;^RL)b z6fbP~xQYD2gd=3mKowA8>j2Q-oU=UUm-O(EgFPMgh3|+Y%e1=wsyCF2^R>Ge%@ssV zE`nNXhEO}Qyj9%)I=qCd%iTU^W~=fE?=>oYM`k9Z z%%3rC`BqMb=6&yHv~VK@dTCIC>ESCY{K%Iuudc;-0k!`KRU>=f`Xoh$!3~(frjNA> ztii(|#+5~`m7-?a6~CvU8#(*&!#50n@!pfgR{6VEa>zeO zm=*X&%#4*~o%lC74myXV6{Ftbk2)4I36RbE_U;>h>q-B+g4BP?Sgq_Oy&o!CUn7$s z1bDLK|Dw0v%P*R|OR$FG-B>H>hw{YaWC#^W`@=dv-twlb-ycijdRiLPN6|+&89T~k z@l=--CbB5-ZxxH-SljsNmV!oO(NnsiVDGtKQZjgf$aof69q4OlbH8z4O)DR6Sa|vl ztL~$p$h2-W*^Nf9Asi@sCsa-^7%C#Z^0eDb>hDd^oibcp16jNcY-M+l;2N zm1XJcT>uj+Zt6#Lu@z2bb*hfO?r7MF<6m%$c05_IB9&8D+%0Y$gyg`C$Vf^ujnP}% znb@HVSrtXXl~G@YD1XDhVS5*$o>NDERb=Soc^SjJEgaD`Pq^f+>(UcMKT)?RZXKZx zRrmTk2$e>{7Lyzq+EDFnwNuIRY4TJ%*yN#=tBdI{ZctrX%7JdOwf|p1pZ=tUX6XRF zEdMRC5d;E+LkU7l9=KCj7YZHh&8G0VA5OkA*mpl8; z_!9GPe~wIry))VOWnLDV{RP!gZ+61p&`d)8q9wAhFR*FcK)uf~W$C-Qp$ScTq9LG$hr&nxC88o9mE=gR z0|MMHWu3lgaQpH<>1CP-@l&3{S7afp=O*O&>i;;>qi0CwJJRe=Q;wbpwk)Q}1LJFk zAk7T?da&SLlN_zUxAW(5;ESI1n#N{XD zoE5K0-1tT4hf0gVC1IpovuSW{`Y71f5?1e(yWZ|MZCF&}=}vCHhL}C375(LrYT;sF zfj(FcsqlTnyW_!*p{CX^1p%* za7K?+ba{#kN=jwL)@ur`*k-ihhjZ771xr@EVic*%TTjz23Ui$NMhMc)$YrL>3SMn~ z(tNx$Xe1%F#E<_U&huDz45-y2uJq_{X=*JrSJ=u~spC`IT(YMmD^%=RBdA{I_wR7@ z-1~sb`HOhpm&SXNKSpOb+!Z{;JEsGi?A%mZoJ7BLyBgF6kpgHHJ#0tmwjtx}*k((0 z#fp~vGts%k%nzbpl#?x`nV+1i4~YK}01>33PXVv;Drt&3&0l>q2s~Nh z{XOW!YB>$_hZ>4Gpt+vDwzntm>%TEls7BcX=ECZ9_73}T$)yxo=R7+u1am3|R#Aor z%{-}_s=dasa>>wyp%9W>O=@86FW-vjvPaBO`!b@%AE6USEiqc#$P>Kuvz6a!ma!s& zQ_|yS&9ZFTC!sl~oe+CB8;E{vjY`x}o1iMn-Dl1Ot@8VuA$Dmp ztU7NksA{}U(taLWljV8h2r%7@-H@@E-ip>GT(HKP@~P3`zb5Co`T9^(vWVbE+on;tAGjXEU3xM zib>=pfocR2B%I9g9H|fzR)E(SJg#wA+aZkEX8)#V>W|eG&)_!*@nC76RA$Zc31aGN z1(G=^Vd;J1=lVx(T@{9^?jlSZPoA|0{eW1`Ci6js%{pkzGPqK9A1ULlxm~1DAhfCr#<_3?r!95Zn#g9RJ*v6TnES~{+5hR zq5s~JusiLsk=$?*ZR#Z)&zf4`Vrc=Kp~%g?#%&btq#5{%a!1t2q2fw(NTSF91l*C) zk70j_t)KWO+3(%E7pf>D`NrJlj$1PP(;^eu0tNU_s`CGgTK@lOb$Ua0lp+C5RheR`xBmYR0D3pQ From bc88fb414fb5a637f9086c54638ccde18a1f19a4 Mon Sep 17 00:00:00 2001 From: Olya Gupalo Date: Mon, 18 Dec 2023 16:29:47 +0100 Subject: [PATCH 254/593] Fix the path to Native Image demo repository --- .../native-image/guides/use-graalvm-dashboard.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/reference-manual/native-image/guides/use-graalvm-dashboard.md b/docs/reference-manual/native-image/guides/use-graalvm-dashboard.md index 19926d26dcac..996e13209d51 100644 --- a/docs/reference-manual/native-image/guides/use-graalvm-dashboard.md +++ b/docs/reference-manual/native-image/guides/use-graalvm-dashboard.md @@ -26,7 +26,7 @@ For other installation options, visit the [Downloads section](https://www.graalv git clone https://github.com/graalvm/graalvm-demos ``` ```shell - cd fortune-demo/fortune + cd fortune-demo/fortune-maven ``` 3. Build the project: From b7718e93a7288d24dc3c3ca88cdefea6f6ff8e23 Mon Sep 17 00:00:00 2001 From: Gilles Duboscq Date: Wed, 8 Mar 2023 15:39:12 +0100 Subject: [PATCH 255/593] Build GraalVM on Big Sur Ensure we don't use older macos versions --- ci/common.jsonnet | 2 +- espresso/ci/ci_common/common.jsonnet | 6 +++--- sulong/ci/ci_common/sulong-common.jsonnet | 3 +-- vm/ci/ci_common/common.jsonnet | 6 +++--- wasm/ci/ci_common/common.jsonnet | 4 +--- 5 files changed, 9 insertions(+), 12 deletions(-) diff --git a/ci/common.jsonnet b/ci/common.jsonnet index a9e64dc11602..3960c9bf8050 100644 --- a/ci/common.jsonnet +++ b/ci/common.jsonnet @@ -344,7 +344,7 @@ local common_json = import "../common.json"; }, local linux = { os:: "linux", capabilities+: [self.os] }, - local darwin = { os:: "darwin", capabilities+: [self.os] }, + local darwin = { os:: "darwin", capabilities+: [self.os, "!darwin_sierra", "!darwin_mojave", "!darwin_catalina"] }, local windows = { os:: "windows", capabilities+: [self.os] }, local amd64 = { arch:: "amd64", capabilities+: [self.arch] }, diff --git a/espresso/ci/ci_common/common.jsonnet b/espresso/ci/ci_common/common.jsonnet index 34488276e63f..59db9238612e 100644 --- a/espresso/ci/ci_common/common.jsonnet +++ b/espresso/ci/ci_common/common.jsonnet @@ -39,10 +39,10 @@ local benchmark_suites = ['dacapo', 'renaissance', 'scala-dacapo']; darwin_amd64: self.common + graal_common.darwin_amd64 + { environment+: { - // for compatibility with macOS High Sierra - MACOSX_DEPLOYMENT_TARGET: '10.13', + // for compatibility with macOS Big Sur + MACOSX_DEPLOYMENT_TARGET: '11.0', }, - capabilities+: ['darwin_mojave', 'ram32gb'], + capabilities+: ['ram32gb'], }, darwin_aarch64: self.common + graal_common.darwin_aarch64 + { diff --git a/sulong/ci/ci_common/sulong-common.jsonnet b/sulong/ci/ci_common/sulong-common.jsonnet index d051496e3f28..bef5b36e1924 100644 --- a/sulong/ci/ci_common/sulong-common.jsonnet +++ b/sulong/ci/ci_common/sulong-common.jsonnet @@ -78,8 +78,7 @@ local sulong_deps = common.deps.sulong; linux_amd64:: linux_amd64 + sulong_deps, linux_aarch64:: linux_aarch64 + sulong_deps, - # Avoid darwin_sierra builders in our CI. This is missing a declaration (fmemopen) that some of our tests need. - darwin_amd64:: darwin_amd64 + sulong_deps + { capabilities+: ["!darwin_sierra"] }, + darwin_amd64:: darwin_amd64 + sulong_deps, darwin_aarch64:: darwin_aarch64 + sulong_deps, windows_amd64:: windows_amd64 + sulong_deps + { local jdk = if self.jdk_name == "jdk-latest" then "jdkLatest" else self.jdk_name, diff --git a/vm/ci/ci_common/common.jsonnet b/vm/ci/ci_common/common.jsonnet index be3c970b9063..2758a8dd5157 100644 --- a/vm/ci/ci_common/common.jsonnet +++ b/vm/ci/ci_common/common.jsonnet @@ -171,13 +171,13 @@ local devkits = graal_common.devkits; vm_ol9_aarch64: self.vm_linux_aarch64_ol9, vm_darwin_amd64: self.common_vm_darwin + graal_common.darwin_amd64 + { - capabilities+: ['darwin_mojave', 'ram16gb'], + capabilities+: ['darwin_bigsur', 'ram16gb'], packages+: { gcc: '==4.9.2', }, environment+: { - # for compatibility with macOS Sierra - MACOSX_DEPLOYMENT_TARGET: '10.13', + # for compatibility with macOS BigSur + MACOSX_DEPLOYMENT_TARGET: '11.0', }, }, diff --git a/wasm/ci/ci_common/common.jsonnet b/wasm/ci/ci_common/common.jsonnet index 2f65920730c2..79b0b4ede4fa 100644 --- a/wasm/ci/ci_common/common.jsonnet +++ b/wasm/ci/ci_common/common.jsonnet @@ -40,9 +40,7 @@ local graal_suite_root = root_ci.graal_suite_root; linux_aarch64:: common.linux_aarch64 + self.linux_common, darwin_aarch64:: common.darwin_aarch64, - darwin_amd64:: common.darwin_amd64 + { - capabilities+: ['darwin_catalina'], - }, + darwin_amd64:: common.darwin_amd64, windows_common:: { packages+: $.devkits["windows-" + self.jdk_name].packages, From c798fb4ec5048bb200c2125cd6af0e2a35d84fa9 Mon Sep 17 00:00:00 2001 From: Gilles Duboscq Date: Fri, 10 Nov 2023 17:29:09 +0100 Subject: [PATCH 256/593] Revert "ci: disable darwin-amd64 on JDK latest [GR-49652]" This reverts commit 6560ce2fdfbf2ad6ad3179e023ef8beca87aaa43. --- compiler/ci/ci_common/gate.jsonnet | 9 +++------ sdk/ci/ci.jsonnet | 4 +--- sulong/ci/ci.jsonnet | 16 +++++----------- truffle/ci/ci.jsonnet | 5 +---- 4 files changed, 10 insertions(+), 24 deletions(-) diff --git a/compiler/ci/ci_common/gate.jsonnet b/compiler/ci/ci_common/gate.jsonnet index 3911b3769c5c..337e7c238307 100644 --- a/compiler/ci/ci_common/gate.jsonnet +++ b/compiler/ci/ci_common/gate.jsonnet @@ -208,14 +208,12 @@ local gates = { "gate-compiler-test-labsjdk-latest-linux-amd64": t("1:00:00") + c.mach5_target, "gate-compiler-test-labsjdk-latest-linux-aarch64": t("1:50:00") + s.avoid_xgene3, - # JDK latest only works on MacOS Ventura (GR-49652) - # "gate-compiler-test-labsjdk-latest-darwin-amd64": t("1:00:00") + c.mach5_target + s.ram16gb, + "gate-compiler-test-labsjdk-latest-darwin-amd64": t("1:00:00") + c.mach5_target + s.ram16gb, "gate-compiler-test-labsjdk-latest-darwin-aarch64": t("1:00:00"), "gate-compiler-test-labsjdk-latest-windows-amd64": t("1:30:00"), "gate-compiler-test_zgc-labsjdk-latest-linux-amd64": t("1:00:00") + c.mach5_target, "gate-compiler-test_zgc-labsjdk-latest-linux-aarch64": t("1:50:00") + s.avoid_xgene3, - # JDK latest only works on MacOS Ventura (GR-49652) - # "gate-compiler-test_zgc-labsjdk-latest-darwin-amd64": t("1:00:00") + c.mach5_target + s.ram16gb, + "gate-compiler-test_zgc-labsjdk-latest-darwin-amd64": t("1:00:00") + c.mach5_target + s.ram16gb, "gate-compiler-test_zgc-labsjdk-latest-darwin-aarch64": t("1:00:00"), # Style jobs need to stay on a JDK compatible with all the style @@ -236,8 +234,7 @@ "gate-compiler-truffle_xcomp-labsjdk-latest-linux-amd64": t("1:30:00"), "gate-compiler-truffle_xcomp_zgc-labsjdk-latest-linux-amd64": t("1:30:00"), - # JDK latest only works on MacOS Ventura (GR-49652) - # "gate-compiler-bootstrap_lite-labsjdk-latest-darwin-amd64": t("1:00:00") + c.mach5_target, + "gate-compiler-bootstrap_lite-labsjdk-latest-darwin-amd64": t("1:00:00") + c.mach5_target, "gate-compiler-bootstrap_full-labsjdk-latest-linux-amd64": s.many_cores + c.mach5_target, "gate-compiler-bootstrap_full_zgc-labsjdk-latest-linux-amd64": s.many_cores + c.mach5_target diff --git a/sdk/ci/ci.jsonnet b/sdk/ci/ci.jsonnet index 562a140c284d..2090ddd90637 100644 --- a/sdk/ci/ci.jsonnet +++ b/sdk/ci/ci.jsonnet @@ -20,9 +20,7 @@ builds: [ common.linux_amd64 + common.oraclejdkLatest + sdk_gate + common.deps.eclipse + common.deps.jdt, common.linux_amd64 + common.oraclejdk21 + sdk_gate + common.deps.eclipse + common.deps.jdt + common.mach5_target, - # JDK latest only works on MacOS Ventura (GR-49652) - # common.darwin_amd64 + common.oraclejdkLatest + sdk_gate, - common.darwin_aarch64 + common.oraclejdkLatest + sdk_gate, + common.darwin_amd64 + common.oraclejdkLatest + sdk_gate, common.darwin_amd64 + common.oraclejdk21 + sdk_gate + common.mach5_target, ] } diff --git a/sulong/ci/ci.jsonnet b/sulong/ci/ci.jsonnet index b1ce24742a05..a7ec87fe9a62 100644 --- a/sulong/ci/ci.jsonnet +++ b/sulong/ci/ci.jsonnet @@ -38,11 +38,8 @@ local sc = (import "ci_common/sulong-common.jsonnet"); sc.weekly + $.sulong + sc.labsjdkLatest + sc.linux_amd64 + sc.llvm6 + sc.requireGMP + sc.requireGCC + sc.gateTags(basicTags) + { name: "weekly-sulong-basic-nwcc-llvm-v60-jdk-latest-linux-amd64" }, sc.weekly + $.sulong + sc.labsjdkLatest + sc.linux_amd64 + sc.llvm8 + sc.requireGMP + sc.requireGCC + sc.gateTags(basicTags) + { name: "weekly-sulong-basic-nwcc-llvm-v80-jdk-latest-linux-amd64" }, - # JDK latest only works on MacOS Ventura (GR-49652) - # sc.weekly + $.sulong + sc.labsjdkLatest + sc.darwin_amd64 + sc.llvm4 + sc.gateTags(basicTags) + { name: "weekly-sulong-basic-nwcc-llvm-v40-jdk-latest-darwin-amd64", timelimit: "0:45:00" }, - # sc.gate + $.sulong + sc.labsjdkLatest + sc.darwin_amd64 + sc.llvmBundled + sc.gateTags(basicTags) + { name: "gate-sulong-basic-nwcc-llvm-jdk-latest-darwin-amd64", timelimit: "0:45:00", capabilities+: ["!darwin_bigsur", "ram16gb"] }, - # remove the following build once GR-49652 is fixed - sc.gate + $.sulong + sc.labsjdk21 + sc.darwin_amd64 + sc.llvmBundled + sc.gateTags(basicTags) + { name: "gate-sulong-basic-nwcc-llvm-jdk21-darwin-amd64", timelimit: "0:45:00", capabilities+: ["!darwin_bigsur", "ram16gb"] }, + sc.weekly + $.sulong + sc.labsjdkLatest + sc.darwin_amd64 + sc.llvm4 + sc.gateTags(basicTags) + { name: "weekly-sulong-basic-nwcc-llvm-v40-jdk-latest-darwin-amd64", timelimit: "0:45:00" }, + sc.gate + $.sulong + sc.labsjdkLatest + sc.darwin_amd64 + sc.llvmBundled + sc.gateTags(basicTags) + { name: "gate-sulong-basic-nwcc-llvm-jdk-latest-darwin-amd64", timelimit: "0:45:00", capabilities+: ["!darwin_bigsur", "ram16gb"] }, sc.gate + $.sulong + sc.labsjdkLatest + sc.linux_amd64 + sc.llvmBundled + sc.requireGMP + sc.requireGCC + sc.gateTags(basicTags) + { name: "gate-sulong-basic-nwcc-llvm-jdk-latest-linux-amd64" }, sc.gate + $.sulong + sc.labsjdk21 + sc.linux_amd64 + sc.llvmBundled + sc.requireGMP + sc.requireGCC + sc.gateTags(basicTags) + { name: "gate-sulong-basic-nwcc-llvm-jdk21-linux-amd64" }, @@ -69,22 +66,19 @@ local sc = (import "ci_common/sulong-common.jsonnet"); ], [ [sc.linux_amd64, [sc.labsjdkLatest]], - # JDK latest only works on MacOS Ventura (GR-49652) - # [sc.darwin_amd64, [sc.labsjdkLatest]], + [sc.darwin_amd64, [sc.labsjdkLatest]], [sc.windows_amd64 + { capabilities+: ["windows_server_2016"] /* work around native-image bug GR-48515 */ }, [sc.labsjdkLatest]], [sc.linux_aarch64, [sc.labsjdkLatest]], [sc.darwin_aarch64, [sc.labsjdkLatest]], ], [ { name: "gate-sulong-test-ce-standalones-jvm-jdk-latest-linux-amd64", timelimit: "1:00:00" }, - # JDK latest only works on MacOS Ventura (GR-49652) - # { name: "daily-sulong-test-ce-standalones-jvm-jdk-latest-darwin-amd64", timelimit: "1:00:00", targets: [] } + sc.daily, + { name: "daily-sulong-test-ce-standalones-jvm-jdk-latest-darwin-amd64", timelimit: "1:00:00", targets: [] } + sc.daily, { name: "gate-sulong-test-ce-standalones-jvm-jdk-latest-windows-amd64", timelimit: "1:00:00" }, { name: "gate-sulong-test-ce-standalones-jvm-jdk-latest-linux-aarch64", timelimit: "1:00:00" }, { name: "gate-sulong-test-ce-standalones-jvm-jdk-latest-darwin-aarch64", timelimit: "1:00:00" }, { name: "gate-sulong-test-ce-standalones-native-jdk-latest-linux-amd64", timelimit: "1:00:00" }, - # JDK latest only works on MacOS Ventura (GR-49652) - # { name: "daily-sulong-test-ce-standalones-native-jdk-latest-darwin-amd64", timelimit: "1:00:00", targets: [] } + sc.daily, + { name: "daily-sulong-test-ce-standalones-native-jdk-latest-darwin-amd64", timelimit: "1:00:00", targets: [] } + sc.daily, { name: "gate-sulong-test-ce-standalones-native-jdk-latest-windows-amd64", timelimit: "1:00:00" }, { name: "gate-sulong-test-ce-standalones-native-jdk-latest-linux-aarch64", timelimit: "1:00:00" }, { name: "gate-sulong-test-ce-standalones-native-jdk-latest-darwin-aarch64", timelimit: "1:00:00" }, diff --git a/truffle/ci/ci.jsonnet b/truffle/ci/ci.jsonnet index 89e27e10cd2c..bdfb42748338 100644 --- a/truffle/ci/ci.jsonnet +++ b/truffle/ci/ci.jsonnet @@ -105,14 +105,11 @@ builds: std.flattenArrays([ [ linux_amd64 + jdk + sigtest + guard, - # JDK latest only works on MacOS Ventura (GR-49652) - # darwin_amd64 + jdk + truffle_weekly + gate_lite + guard, + darwin_amd64 + jdk + truffle_weekly + gate_lite + guard, darwin_aarch64 + jdk + truffle_weekly + gate_lite + guard, ] for jdk in [common.oraclejdk21, common.oraclejdkLatest] ]) + [ - # JDK latest only works on MacOS Ventura (GR-49652) - darwin_amd64 + common.oraclejdk21 + truffle_weekly + gate_lite + guard, # The simple_language_maven_project_gate uses native-image, so we must run on labsjdk rather than oraclejdk linux_amd64 + common.labsjdk21 + simple_language_maven_project_gate, linux_amd64 + common.labsjdkLatest + simple_language_maven_project_gate, From e0ac1fa345bbe4de8d38569d7aa2fa481a675392 Mon Sep 17 00:00:00 2001 From: Gilles Duboscq Date: Fri, 10 Nov 2023 17:30:29 +0100 Subject: [PATCH 257/593] Add new darwin-aarch64 gates back --- sdk/ci/ci.jsonnet | 1 + 1 file changed, 1 insertion(+) diff --git a/sdk/ci/ci.jsonnet b/sdk/ci/ci.jsonnet index 2090ddd90637..37c46a92f8d0 100644 --- a/sdk/ci/ci.jsonnet +++ b/sdk/ci/ci.jsonnet @@ -21,6 +21,7 @@ common.linux_amd64 + common.oraclejdkLatest + sdk_gate + common.deps.eclipse + common.deps.jdt, common.linux_amd64 + common.oraclejdk21 + sdk_gate + common.deps.eclipse + common.deps.jdt + common.mach5_target, common.darwin_amd64 + common.oraclejdkLatest + sdk_gate, + common.darwin_aarch64 + common.oraclejdkLatest + sdk_gate, common.darwin_amd64 + common.oraclejdk21 + sdk_gate + common.mach5_target, ] } From 421e12ab56d6ed25a8fadb3a58bcec82648d8f36 Mon Sep 17 00:00:00 2001 From: Gilles Duboscq Date: Fri, 10 Nov 2023 17:31:31 +0100 Subject: [PATCH 258/593] Allow sulong gate to run on big sur --- sulong/ci/ci.jsonnet | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sulong/ci/ci.jsonnet b/sulong/ci/ci.jsonnet index a7ec87fe9a62..4af99fa9a846 100644 --- a/sulong/ci/ci.jsonnet +++ b/sulong/ci/ci.jsonnet @@ -39,7 +39,7 @@ local sc = (import "ci_common/sulong-common.jsonnet"); sc.weekly + $.sulong + sc.labsjdkLatest + sc.linux_amd64 + sc.llvm8 + sc.requireGMP + sc.requireGCC + sc.gateTags(basicTags) + { name: "weekly-sulong-basic-nwcc-llvm-v80-jdk-latest-linux-amd64" }, sc.weekly + $.sulong + sc.labsjdkLatest + sc.darwin_amd64 + sc.llvm4 + sc.gateTags(basicTags) + { name: "weekly-sulong-basic-nwcc-llvm-v40-jdk-latest-darwin-amd64", timelimit: "0:45:00" }, - sc.gate + $.sulong + sc.labsjdkLatest + sc.darwin_amd64 + sc.llvmBundled + sc.gateTags(basicTags) + { name: "gate-sulong-basic-nwcc-llvm-jdk-latest-darwin-amd64", timelimit: "0:45:00", capabilities+: ["!darwin_bigsur", "ram16gb"] }, + sc.gate + $.sulong + sc.labsjdkLatest + sc.darwin_amd64 + sc.llvmBundled + sc.gateTags(basicTags) + { name: "gate-sulong-basic-nwcc-llvm-jdk-latest-darwin-amd64", timelimit: "0:45:00", capabilities+: ["ram16gb"] }, sc.gate + $.sulong + sc.labsjdkLatest + sc.linux_amd64 + sc.llvmBundled + sc.requireGMP + sc.requireGCC + sc.gateTags(basicTags) + { name: "gate-sulong-basic-nwcc-llvm-jdk-latest-linux-amd64" }, sc.gate + $.sulong + sc.labsjdk21 + sc.linux_amd64 + sc.llvmBundled + sc.requireGMP + sc.requireGCC + sc.gateTags(basicTags) + { name: "gate-sulong-basic-nwcc-llvm-jdk21-linux-amd64" }, From 1b246ab2f6a5b9868a3d4be58ff8f7b68427a4f7 Mon Sep 17 00:00:00 2001 From: Gilles Duboscq Date: Fri, 10 Nov 2023 17:32:37 +0100 Subject: [PATCH 259/593] Revert "disable latest-darwin-amd64 jobs (GR-49652)" This reverts commit 009f2a5d76b0edf495f6935e5c163bf3fa05e729. --- ci.jsonnet | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/ci.jsonnet b/ci.jsonnet index cb9554e02dde..c3533eb4f3c5 100644 --- a/ci.jsonnet +++ b/ci.jsonnet @@ -40,16 +40,13 @@ local visualizer = import 'visualizer/ci/ci.jsonnet'; local verify_ci = (import 'ci/ci_common/ci-check.libsonnet').verify_ci; -# JDK latest only works on MacOS Ventura (GR-49652) -local exclude_latest_darwin_amd64(builds) = [b for b in builds if !(import 'ci/ci_common/common-utils.libsonnet').contains(b.name, "labsjdk-latest-darwin-amd64")]; - { # Ensure that non-hidden entries in ci/common.jsonnet and ci/ci_common/common.jsonnet can be resolved. assert std.length(std.toString(import 'ci/ci_common/common.jsonnet')) > 0, ci_resources:: (import 'ci/ci_common/ci-resources.libsonnet'), overlay: graal_common.ci.overlay, specVersion: "3", - builds: exclude_latest_darwin_amd64([common.add_excludes_guard(b) for b in ( + builds: [common.add_excludes_guard(b) for b in ( common.with_components(compiler.builds, ["compiler"]) + common.with_components(wasm.builds, ["wasm"]) + common.with_components(espresso.builds, ["espresso"]) + @@ -62,7 +59,7 @@ local exclude_latest_darwin_amd64(builds) = [b for b in builds if !(import 'ci/c common.with_components(javadoc.builds, ["javadoc"]) + common.with_components(vm.builds, ["vm"]) + common.with_components(visualizer.builds, ["visualizer"]) - )]), + )], assert verify_ci(self.builds), // verify that the run-spec demo works assert (import "ci/ci_common/run-spec-demo.jsonnet").check(), From 34bdfdb8e5a673a7641ce89847fe3b96ee038f6c Mon Sep 17 00:00:00 2001 From: Gilles Duboscq Date: Wed, 13 Dec 2023 15:32:35 +0100 Subject: [PATCH 260/593] Simplify vm_darwin_amd64_jdkLatest --- vm/ci/ci_common/common.jsonnet | 11 +---------- 1 file changed, 1 insertion(+), 10 deletions(-) diff --git a/vm/ci/ci_common/common.jsonnet b/vm/ci/ci_common/common.jsonnet index 2758a8dd5157..f2a6c921cc41 100644 --- a/vm/ci/ci_common/common.jsonnet +++ b/vm/ci/ci_common/common.jsonnet @@ -181,16 +181,7 @@ local devkits = graal_common.devkits; }, }, - vm_darwin_amd64_jdkLatest: self.common_vm_darwin + graal_common.darwin_amd64 + { - capabilities+: ['darwin_bigsur', 'ram16gb'], - packages+: { - gcc: '==4.9.2', - }, - environment+: { - # for compatibility with macOS BigSur - MACOSX_DEPLOYMENT_TARGET: '11.0', - }, - }, + vm_darwin_amd64_jdkLatest: self.vm_darwin_amd64, vm_darwin_aarch64: self.common_vm_darwin + graal_common.darwin_aarch64 + { capabilities+: ['darwin_bigsur'], From 73b57e6f1d3795bf3d85bff4cb8a4e309678ae59 Mon Sep 17 00:00:00 2001 From: Gilles Duboscq Date: Thu, 14 Dec 2023 18:32:08 +0100 Subject: [PATCH 261/593] Add a comment about the usage of exclusion to get Big Sur or above --- ci/common.jsonnet | 1 + 1 file changed, 1 insertion(+) diff --git a/ci/common.jsonnet b/ci/common.jsonnet index 3960c9bf8050..81b854e71687 100644 --- a/ci/common.jsonnet +++ b/ci/common.jsonnet @@ -344,6 +344,7 @@ local common_json = import "../common.json"; }, local linux = { os:: "linux", capabilities+: [self.os] }, + # Run darwin jobs on Big Sur or later by excluding all older versions local darwin = { os:: "darwin", capabilities+: [self.os, "!darwin_sierra", "!darwin_mojave", "!darwin_catalina"] }, local windows = { os:: "windows", capabilities+: [self.os] }, From 60fb4b62a7c70a067578f3042949757e3e90fcd8 Mon Sep 17 00:00:00 2001 From: Christian Haeubl Date: Fri, 15 Dec 2023 18:24:41 +0100 Subject: [PATCH 262/593] Remove non-chunked image heap. --- .../AbstractImageHeapLayouter.java | 274 ------------------ .../core/genscavenge/AlignedHeapChunk.java | 10 +- .../genscavenge/ChunkedImageHeapLayouter.java | 173 +++++++++-- .../ChunkedImageHeapPartition.java | 65 ++++- .../oracle/svm/core/genscavenge/GCImpl.java | 4 +- .../svm/core/genscavenge/HeapChunk.java | 6 +- .../oracle/svm/core/genscavenge/HeapImpl.java | 45 +-- .../svm/core/genscavenge/HeapVerifier.java | 148 +++------- .../svm/core/genscavenge/ImageHeapInfo.java | 9 +- .../svm/core/genscavenge/ImageHeapWalker.java | 37 +-- .../genscavenge/LinearImageHeapAllocator.java | 52 ---- .../genscavenge/LinearImageHeapLayouter.java | 85 ------ .../genscavenge/LinearImageHeapPartition.java | 87 ------ .../core/genscavenge/ObjectHeaderImpl.java | 18 +- .../core/genscavenge/UnalignedHeapChunk.java | 14 +- .../graal/GenScavengeGCFeature.java | 9 +- .../core/genscavenge/remset/CardTable.java | 44 +-- .../genscavenge/remset/NoRememberedSet.java | 2 +- .../posix/linux/LinuxImageHeapProvider.java | 11 +- .../src/com/oracle/svm/core/heap/Heap.java | 13 +- .../os/AbstractCommittedMemoryProvider.java | 4 +- .../os/AbstractCopyingImageHeapProvider.java | 17 +- .../oracle/svm/core/os/ImageHeapProvider.java | 10 +- 23 files changed, 366 insertions(+), 771 deletions(-) delete mode 100644 substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/AbstractImageHeapLayouter.java delete mode 100644 substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/LinearImageHeapAllocator.java delete mode 100644 substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/LinearImageHeapLayouter.java delete mode 100644 substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/LinearImageHeapPartition.java diff --git a/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/AbstractImageHeapLayouter.java b/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/AbstractImageHeapLayouter.java deleted file mode 100644 index f5ead5771f61..000000000000 --- a/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/AbstractImageHeapLayouter.java +++ /dev/null @@ -1,274 +0,0 @@ -/* - * Copyright (c) 2019, 2019, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.oracle.svm.core.genscavenge; - -import java.nio.ByteBuffer; -import java.util.ArrayList; -import java.util.List; - -import com.oracle.svm.core.config.ConfigurationValues; -import com.oracle.svm.core.hub.DynamicHub; -import com.oracle.svm.core.image.ImageHeap; -import com.oracle.svm.core.image.ImageHeapLayoutInfo; -import com.oracle.svm.core.image.ImageHeapLayouter; -import com.oracle.svm.core.image.ImageHeapObject; -import com.oracle.svm.core.image.ImageHeapPartition; -import com.oracle.svm.core.util.VMError; - -public abstract class AbstractImageHeapLayouter implements ImageHeapLayouter { - /** A partition holding objects with only read-only primitive values, but no references. */ - private static final int READ_ONLY_PRIMITIVE = 0; - /** A partition holding objects with read-only references and primitive values. */ - private static final int READ_ONLY_REFERENCE = 1; - /** - * A pseudo-partition used during image building to consolidate objects that contain relocatable - * references. - *

    - * Collecting the relocations together means the dynamic linker has to operate on less of the - * image heap during image startup, and it means that less of the image heap has to be - * copied-on-write if the image heap is relocated in a new process. - *

    - * A relocated reference is read-only once relocated, e.g., at runtime. The read-only relocation - * partition does not exist as a separate partition in the generated image. Instead, the - * read-only reference partition is resized to include the read-only relocation partition as - * well. - */ - private static final int READ_ONLY_RELOCATABLE = 2; - /** A partition holding objects with writable primitive values, but no references. */ - private static final int WRITABLE_PRIMITIVE = 3; - /** A partition holding objects with writable references and primitive values. */ - private static final int WRITABLE_REFERENCE = 4; - /** A partition holding very large writable objects with or without references. */ - private static final int WRITABLE_HUGE = 5; - /** - * A partition holding very large read-only objects with or without references, but never with - * relocatable references. - */ - private static final int READ_ONLY_HUGE = 6; - - private static final int PARTITION_COUNT = 7; - - private final T[] partitions; - - @Override - public T[] getPartitions() { - return partitions; - } - - private T getLastPartition() { - return getPartitions()[PARTITION_COUNT - 1]; - } - - @SuppressWarnings("this-escape") - public AbstractImageHeapLayouter() { - this.partitions = createPartitionsArray(PARTITION_COUNT); - this.partitions[READ_ONLY_PRIMITIVE] = createPartition("readOnlyPrimitive", false, false, false); - this.partitions[READ_ONLY_REFERENCE] = createPartition("readOnlyReference", true, false, false); - this.partitions[READ_ONLY_RELOCATABLE] = createPartition("readOnlyRelocatable", true, false, false); - this.partitions[WRITABLE_PRIMITIVE] = createPartition("writablePrimitive", false, true, false); - this.partitions[WRITABLE_REFERENCE] = createPartition("writableReference", true, true, false); - this.partitions[WRITABLE_HUGE] = createPartition("writableHuge", true, true, true); - this.partitions[READ_ONLY_HUGE] = createPartition("readOnlyHuge", true, false, true); - } - - @Override - public void assignObjectToPartition(ImageHeapObject info, boolean immutable, boolean references, boolean relocatable) { - T partition = choosePartition(info, immutable, references, relocatable); - info.setHeapPartition(partition); - partition.assign(info); - } - - @Override - public ImageHeapLayoutInfo layout(ImageHeap imageHeap, int pageSize) { - int objectAlignment = ConfigurationValues.getObjectLayout().getAlignment(); - assert pageSize % objectAlignment == 0 : "Page size does not match object alignment"; - - for (T partition : getPartitions()) { - int startAlignment = objectAlignment; - int endAlignment = objectAlignment; - if (partition == getReadOnlyRelocatable()) { - startAlignment = pageSize; - endAlignment = pageSize; - } else if (partition == getWritablePrimitive()) { - startAlignment = pageSize; - } else if (partition == getWritableHuge()) { - endAlignment = pageSize; - } - - /* Make sure the image heap size is a multiple of the page size. */ - if (partition == getLastPartition()) { - endAlignment = pageSize; - } - - partition.setStartAlignment(startAlignment); - partition.setEndAlignment(endAlignment); - } - - ImageHeapLayoutInfo layoutInfo = doLayout(imageHeap); - - for (T partition : getPartitions()) { - assert partition.getStartOffset() % partition.getStartAlignment() == 0 : partition; - assert (partition.getStartOffset() + partition.getSize()) % partition.getEndAlignment() == 0 : partition; - } - - assert layoutInfo.getReadOnlyRelocatableOffset() % pageSize == 0 && layoutInfo.getReadOnlyRelocatableSize() % pageSize == 0 : layoutInfo; - assert layoutInfo.getWritableOffset() % pageSize == 0 && layoutInfo.getWritableSize() % pageSize == 0 : layoutInfo; - - return layoutInfo; - } - - @Override - public void writeMetadata(ByteBuffer imageHeapBytes, long imageHeapOffsetInBuffer) { - // For implementation in subclasses, if necessary. - } - - protected abstract ImageHeapLayoutInfo doLayout(ImageHeap imageHeap); - - protected T getReadOnlyPrimitive() { - return getPartitions()[READ_ONLY_PRIMITIVE]; - } - - protected T getReadOnlyReference() { - return getPartitions()[READ_ONLY_REFERENCE]; - } - - protected T getReadOnlyRelocatable() { - return getPartitions()[READ_ONLY_RELOCATABLE]; - } - - protected T getWritablePrimitive() { - return getPartitions()[WRITABLE_PRIMITIVE]; - } - - protected T getWritableReference() { - return getPartitions()[WRITABLE_REFERENCE]; - } - - protected T getWritableHuge() { - return getPartitions()[WRITABLE_HUGE]; - } - - protected T getReadOnlyHuge() { - return getPartitions()[READ_ONLY_HUGE]; - } - - /** The size in bytes at and above which an object should be assigned to the huge partitions. */ - protected long getHugeObjectThreshold() { - // Do not use huge partitions by default, they remain empty and should not consume space - return Long.MAX_VALUE; - } - - private T choosePartition(@SuppressWarnings("unused") ImageHeapObject info, boolean immutable, boolean hasReferences, boolean hasRelocatables) { - if (immutable) { - if (hasRelocatables) { - VMError.guarantee(info.getSize() < getHugeObjectThreshold(), "Objects with relocatable pointers cannot be huge objects"); - return getReadOnlyRelocatable(); - } - if (info.getSize() >= getHugeObjectThreshold()) { - VMError.guarantee(info.getObjectClass() != DynamicHub.class, "Class metadata (dynamic hubs) cannot be huge objects"); - return getReadOnlyHuge(); - } - return hasReferences ? getReadOnlyReference() : getReadOnlyPrimitive(); - } else { - assert info.getObjectClass() != DynamicHub.class : "Class metadata (dynamic hubs) cannot be writable"; - if (info.getSize() >= getHugeObjectThreshold()) { - return getWritableHuge(); - } - return hasReferences ? getWritableReference() : getWritablePrimitive(); - } - } - - protected ImageHeapLayoutInfo createLayoutInfo(long heapStartOffset, long writableBeginOffset) { - long writableEnd = getWritableHuge().getStartOffset() + getWritableHuge().getSize(); - long writableSize = writableEnd - writableBeginOffset; - long imageHeapSize = getReadOnlyHuge().getStartOffset() + getReadOnlyHuge().getSize() - heapStartOffset; - return new ImageHeapLayoutInfo(writableBeginOffset, writableSize, getReadOnlyRelocatable().getStartOffset(), getReadOnlyRelocatable().getSize(), imageHeapSize); - } - - protected abstract T[] createPartitionsArray(int count); - - protected abstract T createPartition(String name, boolean containsReferences, boolean writable, boolean hugeObjects); - - /** - * The native image heap comes in partitions. Each partition holds objects with different - * properties (read-only/writable, primitives/objects). - */ - public abstract static class AbstractImageHeapPartition implements ImageHeapPartition { - private final String name; - private final boolean writable; - - private int startAlignment = -1; - private int endAlignment = -1; - private final List objects = new ArrayList<>(); - - public AbstractImageHeapPartition(String name, boolean writable) { - this.name = name; - this.writable = writable; - } - - public void assign(ImageHeapObject obj) { - assert obj.getPartition() == this : obj; - objects.add(obj); - } - - public void setStartAlignment(int alignment) { - assert this.startAlignment == -1 : "Start alignment already assigned: " + this.startAlignment; - this.startAlignment = alignment; - } - - public final int getStartAlignment() { - assert startAlignment >= 0 : "Start alignment not yet assigned"; - return startAlignment; - } - - public void setEndAlignment(int endAlignment) { - assert this.endAlignment == -1 : "End alignment already assigned: " + this.endAlignment; - this.endAlignment = endAlignment; - } - - public final int getEndAlignment() { - assert endAlignment >= 0 : "End alignment not yet assigned"; - return endAlignment; - } - - public List getObjects() { - return objects; - } - - @Override - public String getName() { - return name; - } - - public boolean isWritable() { - return writable; - } - - @Override - public String toString() { - return name; - } - } -} diff --git a/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/AlignedHeapChunk.java b/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/AlignedHeapChunk.java index 9745a24a5f98..e45c244257d0 100644 --- a/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/AlignedHeapChunk.java +++ b/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/AlignedHeapChunk.java @@ -24,8 +24,6 @@ */ package com.oracle.svm.core.genscavenge; -import jdk.graal.compiler.api.replacements.Fold; -import jdk.graal.compiler.word.Word; import org.graalvm.nativeimage.ImageSingletons; import org.graalvm.nativeimage.Platform; import org.graalvm.nativeimage.Platforms; @@ -40,8 +38,13 @@ import com.oracle.svm.core.feature.AutomaticallyRegisteredImageSingleton; import com.oracle.svm.core.genscavenge.remset.RememberedSet; import com.oracle.svm.core.heap.ObjectVisitor; +import com.oracle.svm.core.os.CommittedMemoryProvider; import com.oracle.svm.core.util.PointerUtils; +import jdk.graal.compiler.api.directives.GraalDirectives; +import jdk.graal.compiler.api.replacements.Fold; +import jdk.graal.compiler.word.Word; + /** * An AlignedHeapChunk can hold many Objects. *

    @@ -127,6 +130,9 @@ public static AlignedHeader getEnclosingChunk(Object obj) { @Uninterruptible(reason = "Called from uninterruptible code.", mayBeInlined = true) public static AlignedHeader getEnclosingChunkFromObjectPointer(Pointer ptr) { + if (!GraalDirectives.inIntrinsic()) { + assert !HeapImpl.getHeapImpl().isInImageHeap(ptr) || CommittedMemoryProvider.get().guaranteesHeapPreferredAddressSpaceAlignment() : "can't be used because the image heap is unaligned"; + } return (AlignedHeader) PointerUtils.roundDown(ptr, HeapParameters.getAlignedHeapChunkAlignment()); } diff --git a/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/ChunkedImageHeapLayouter.java b/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/ChunkedImageHeapLayouter.java index 001775088ae8..bbb083e3af19 100644 --- a/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/ChunkedImageHeapLayouter.java +++ b/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/ChunkedImageHeapLayouter.java @@ -27,30 +27,77 @@ import java.nio.ByteBuffer; import java.util.List; -import jdk.graal.compiler.core.common.NumUtil; import org.graalvm.word.UnsignedWord; import com.oracle.svm.core.SubstrateUtil; +import com.oracle.svm.core.config.ConfigurationValues; import com.oracle.svm.core.genscavenge.ChunkedImageHeapAllocator.AlignedChunk; import com.oracle.svm.core.genscavenge.ChunkedImageHeapAllocator.Chunk; import com.oracle.svm.core.genscavenge.ChunkedImageHeapAllocator.UnalignedChunk; import com.oracle.svm.core.genscavenge.remset.RememberedSet; import com.oracle.svm.core.heap.Heap; +import com.oracle.svm.core.hub.DynamicHub; import com.oracle.svm.core.image.ImageHeap; import com.oracle.svm.core.image.ImageHeapLayoutInfo; +import com.oracle.svm.core.image.ImageHeapLayouter; +import com.oracle.svm.core.image.ImageHeapObject; +import com.oracle.svm.core.util.VMError; + +import jdk.graal.compiler.core.common.NumUtil; -public class ChunkedImageHeapLayouter extends AbstractImageHeapLayouter { +public class ChunkedImageHeapLayouter implements ImageHeapLayouter { + /** A partition holding objects with only read-only primitive values, but no references. */ + private static final int READ_ONLY_PRIMITIVE = 0; + /** A partition holding objects with read-only references and primitive values. */ + private static final int READ_ONLY_REFERENCE = READ_ONLY_PRIMITIVE + 1; + /** + * A pseudo-partition used during image building to consolidate objects that contain relocatable + * references. + *

    + * Collecting the relocations together means the dynamic linker has to operate on less of the + * image heap during image startup, and it means that less of the image heap has to be + * copied-on-write if the image heap is relocated in a new process. + *

    + * A relocated reference is read-only once relocated, e.g., at runtime. The read-only relocation + * partition does not exist as a separate partition in the generated image. Instead, the + * read-only reference partition is resized to include the read-only relocation partition as + * well. + */ + private static final int READ_ONLY_RELOCATABLE = READ_ONLY_REFERENCE + 1; + /** A partition holding objects with writable primitive values, but no references. */ + private static final int WRITABLE_PRIMITIVE = READ_ONLY_RELOCATABLE + 1; + /** A partition holding objects with writable references and primitive values. */ + private static final int WRITABLE_REFERENCE = WRITABLE_PRIMITIVE + 1; + /** A partition holding very large writable objects with or without references. */ + private static final int WRITABLE_HUGE = WRITABLE_REFERENCE + 1; + /** + * A partition holding very large read-only objects with or without references, but never with + * relocatable references. + */ + private static final int READ_ONLY_HUGE = WRITABLE_HUGE + 1; + private static final int PARTITION_COUNT = READ_ONLY_HUGE + 1; + + private final ChunkedImageHeapPartition[] partitions; private final ImageHeapInfo heapInfo; private final long startOffset; - private final int nullRegionSize; private final long hugeObjectThreshold; private ChunkedImageHeapAllocator allocator; - public ChunkedImageHeapLayouter(ImageHeapInfo heapInfo, long startOffset, int nullRegionSize) { + @SuppressWarnings("this-escape") + public ChunkedImageHeapLayouter(ImageHeapInfo heapInfo, long startOffset) { assert startOffset == 0 || startOffset >= Heap.getHeap().getImageHeapOffsetInAddressSpace() : "must be relative to the heap base"; + + this.partitions = new ChunkedImageHeapPartition[PARTITION_COUNT]; + this.partitions[READ_ONLY_PRIMITIVE] = new ChunkedImageHeapPartition("readOnlyPrimitive", false, false); + this.partitions[READ_ONLY_REFERENCE] = new ChunkedImageHeapPartition("readOnlyReference", false, false); + this.partitions[READ_ONLY_RELOCATABLE] = new ChunkedImageHeapPartition("readOnlyRelocatable", false, false); + this.partitions[WRITABLE_PRIMITIVE] = new ChunkedImageHeapPartition("writablePrimitive", true, false); + this.partitions[WRITABLE_REFERENCE] = new ChunkedImageHeapPartition("writableReference", true, false); + this.partitions[WRITABLE_HUGE] = new ChunkedImageHeapPartition("writableHuge", true, true); + this.partitions[READ_ONLY_HUGE] = new ChunkedImageHeapPartition("readOnlyHuge", false, true); + this.heapInfo = heapInfo; this.startOffset = startOffset; - this.nullRegionSize = nullRegionSize; UnsignedWord alignedHeaderSize = RememberedSet.get().getHeaderSizeOfAlignedChunk(); UnsignedWord unalignedHeaderSize = RememberedSet.get().getHeaderSizeOfUnalignedChunk(); UnsignedWord hugeThreshold = HeapParameters.getAlignedHeapChunkSize().subtract(alignedHeaderSize); @@ -61,24 +108,82 @@ public ChunkedImageHeapLayouter(ImageHeapInfo heapInfo, long startOffset, int nu } @Override - protected ChunkedImageHeapPartition[] createPartitionsArray(int count) { - return new ChunkedImageHeapPartition[count]; + public ChunkedImageHeapPartition[] getPartitions() { + return partitions; } - @Override - protected ChunkedImageHeapPartition createPartition(String name, boolean containsReferences, boolean writable, boolean hugeObjects) { - return new ChunkedImageHeapPartition(name, writable, hugeObjects); + private ChunkedImageHeapPartition getLastPartition() { + return partitions[PARTITION_COUNT - 1]; } @Override - protected long getHugeObjectThreshold() { - return hugeObjectThreshold; + public void assignObjectToPartition(ImageHeapObject info, boolean immutable, boolean references, boolean relocatable) { + ChunkedImageHeapPartition partition = choosePartition(info, immutable, references, relocatable); + info.setHeapPartition(partition); + partition.assign(info); + } + + private ChunkedImageHeapPartition choosePartition(@SuppressWarnings("unused") ImageHeapObject info, boolean immutable, boolean hasReferences, boolean hasRelocatables) { + if (immutable) { + if (hasRelocatables) { + VMError.guarantee(info.getSize() < hugeObjectThreshold, "Objects with relocatable pointers cannot be huge objects"); + return getReadOnlyRelocatable(); + } + if (info.getSize() >= hugeObjectThreshold) { + VMError.guarantee(info.getObjectClass() != DynamicHub.class, "Class metadata (dynamic hubs) cannot be huge objects"); + return getReadOnlyHuge(); + } + return hasReferences ? getReadOnlyReference() : getReadOnlyPrimitive(); + } else { + assert info.getObjectClass() != DynamicHub.class : "Class metadata (dynamic hubs) cannot be writable"; + if (info.getSize() >= hugeObjectThreshold) { + return getWritableHuge(); + } + return hasReferences ? getWritableReference() : getWritablePrimitive(); + } } @Override - protected ImageHeapLayoutInfo doLayout(ImageHeap imageHeap) { - long position = startOffset + nullRegionSize; - allocator = new ChunkedImageHeapAllocator(imageHeap, position); + public ImageHeapLayoutInfo layout(ImageHeap imageHeap, int pageSize) { + int objectAlignment = ConfigurationValues.getObjectLayout().getAlignment(); + assert pageSize % objectAlignment == 0 : "Page size does not match object alignment"; + + for (ChunkedImageHeapPartition partition : getPartitions()) { + int startAlignment = objectAlignment; + int endAlignment = objectAlignment; + if (partition == getReadOnlyRelocatable()) { + startAlignment = pageSize; + endAlignment = pageSize; + } else if (partition == getWritablePrimitive()) { + startAlignment = pageSize; + } else if (partition == getWritableHuge()) { + endAlignment = pageSize; + } + + /* Make sure the image heap size is a multiple of the page size. */ + if (partition == getLastPartition()) { + endAlignment = pageSize; + } + + partition.setStartAlignment(startAlignment); + partition.setEndAlignment(endAlignment); + } + + ImageHeapLayoutInfo layoutInfo = doLayout(imageHeap); + + for (ChunkedImageHeapPartition partition : getPartitions()) { + assert partition.getStartOffset() % partition.getStartAlignment() == 0 : partition; + assert (partition.getStartOffset() + partition.getSize()) % partition.getEndAlignment() == 0 : partition; + } + + assert layoutInfo.getReadOnlyRelocatableOffset() % pageSize == 0 && layoutInfo.getReadOnlyRelocatableSize() % pageSize == 0 : layoutInfo; + assert layoutInfo.getWritableOffset() % pageSize == 0 && layoutInfo.getWritableSize() % pageSize == 0 : layoutInfo; + + return layoutInfo; + } + + private ImageHeapLayoutInfo doLayout(ImageHeap imageHeap) { + allocator = new ChunkedImageHeapAllocator(imageHeap, startOffset); for (ChunkedImageHeapPartition partition : getPartitions()) { partition.layout(allocator); } @@ -127,6 +232,13 @@ private void initializeHeapInfo(int dynamicHubCount, long offsetOfFirstWritableA getReadOnlyHuge().firstObject, getReadOnlyHuge().lastObject, writableAligned, writableUnaligned, dynamicHubCount); } + protected ImageHeapLayoutInfo createLayoutInfo(long heapStartOffset, long writableBeginOffset) { + long writableEnd = getWritableHuge().getStartOffset() + getWritableHuge().getSize(); + long writableSize = writableEnd - writableBeginOffset; + long imageHeapSize = getReadOnlyHuge().getStartOffset() + getReadOnlyHuge().getSize() - heapStartOffset; + return new ImageHeapLayoutInfo(writableBeginOffset, writableSize, getReadOnlyRelocatable().getStartOffset(), getReadOnlyRelocatable().getSize(), imageHeapSize); + } + @Override public void writeMetadata(ByteBuffer imageHeapBytes, long imageHeapOffsetInBuffer) { long layoutToBufferOffsetAddend = imageHeapOffsetInBuffer - startOffset; @@ -152,8 +264,7 @@ private static void writeHeader(ImageHeapChunkWriter writer, Chunk previous, Chu long offsetToPrevious = (previous != null) ? (previous.getBegin() - current.getBegin()) : 0; long offsetToNext = (next != null) ? (next.getBegin() - current.getBegin()) : 0; int chunkPosition = NumUtil.safeToInt(current.getBegin()); - if (current instanceof AlignedChunk) { - AlignedChunk aligned = (AlignedChunk) current; + if (current instanceof AlignedChunk aligned) { writer.initializeAlignedChunk(chunkPosition, current.getTopOffset(), current.getEndOffset(), offsetToPrevious, offsetToNext); writer.enableRememberedSetForAlignedChunk(chunkPosition, aligned.getObjects()); } else { @@ -163,4 +274,32 @@ private static void writeHeader(ImageHeapChunkWriter writer, Chunk previous, Chu } } } + + private ChunkedImageHeapPartition getReadOnlyPrimitive() { + return getPartitions()[READ_ONLY_PRIMITIVE]; + } + + private ChunkedImageHeapPartition getReadOnlyReference() { + return getPartitions()[READ_ONLY_REFERENCE]; + } + + private ChunkedImageHeapPartition getReadOnlyRelocatable() { + return getPartitions()[READ_ONLY_RELOCATABLE]; + } + + private ChunkedImageHeapPartition getWritablePrimitive() { + return getPartitions()[WRITABLE_PRIMITIVE]; + } + + private ChunkedImageHeapPartition getWritableReference() { + return getPartitions()[WRITABLE_REFERENCE]; + } + + private ChunkedImageHeapPartition getWritableHuge() { + return getPartitions()[WRITABLE_HUGE]; + } + + private ChunkedImageHeapPartition getReadOnlyHuge() { + return getPartitions()[READ_ONLY_HUGE]; + } } diff --git a/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/ChunkedImageHeapPartition.java b/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/ChunkedImageHeapPartition.java index 1e23506521d0..9e636d812940 100644 --- a/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/ChunkedImageHeapPartition.java +++ b/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/ChunkedImageHeapPartition.java @@ -25,6 +25,7 @@ package com.oracle.svm.core.genscavenge; import java.util.ArrayDeque; +import java.util.ArrayList; import java.util.Arrays; import java.util.Comparator; import java.util.List; @@ -34,15 +35,20 @@ import java.util.TreeMap; import com.oracle.svm.core.config.ConfigurationValues; -import com.oracle.svm.core.genscavenge.AbstractImageHeapLayouter.AbstractImageHeapPartition; import com.oracle.svm.core.image.ImageHeapObject; +import com.oracle.svm.core.image.ImageHeapPartition; import com.oracle.svm.core.meta.SubstrateObjectConstant; /** - * An unstructured image heap partition that just contains a linear sequence of image heap objects. + * The image heap comes in partitions. Each partition holds objects with different properties + * (read-only/writable, primitives/objects). */ -public class ChunkedImageHeapPartition extends AbstractImageHeapPartition { +public class ChunkedImageHeapPartition implements ImageHeapPartition { + private final String name; + private final boolean writable; private final boolean hugeObjects; + private final int minimumObjectSize; + private final List objects = new ArrayList<>(); Object firstObject; Object lastObject; @@ -50,18 +56,21 @@ public class ChunkedImageHeapPartition extends AbstractImageHeapPartition { long startOffset = -1; long endOffset = -1; - private final int minimumObjectSize; + private int startAlignment = -1; + private int endAlignment = -1; ChunkedImageHeapPartition(String name, boolean writable, boolean hugeObjects) { - super(name, writable); + this.name = name; + this.writable = writable; this.hugeObjects = hugeObjects; /* Cache to prevent frequent lookups of the object layout from ImageSingletons. */ this.minimumObjectSize = ConfigurationValues.getObjectLayout().getMinImageHeapObjectSize(); } - boolean usesUnalignedObjects() { - return hugeObjects; + public void assign(ImageHeapObject obj) { + assert obj.getPartition() == this : obj; + objects.add(obj); } void layout(ChunkedImageHeapAllocator allocator) { @@ -139,6 +148,7 @@ private static NavigableMap> createSortedObjectsMap currentQueue = new ArrayDeque<>(); map.put(currentObjectsSize, currentQueue); } + assert currentQueue != null; currentQueue.add(obj); } return map; @@ -170,6 +180,43 @@ private static Object extractObject(ImageHeapObject info) { } } + public List getObjects() { + return objects; + } + + @Override + public String getName() { + return name; + } + + public boolean isWritable() { + return writable; + } + + boolean usesUnalignedObjects() { + return hugeObjects; + } + + public final int getStartAlignment() { + assert startAlignment >= 0 : "Start alignment not yet assigned"; + return startAlignment; + } + + public void setStartAlignment(int alignment) { + assert this.startAlignment == -1 : "Start alignment already assigned: " + this.startAlignment; + this.startAlignment = alignment; + } + + public final int getEndAlignment() { + assert endAlignment >= 0 : "End alignment not yet assigned"; + return endAlignment; + } + + public void setEndAlignment(int endAlignment) { + assert this.endAlignment == -1 : "End alignment already assigned: " + this.endAlignment; + this.endAlignment = endAlignment; + } + @Override public long getStartOffset() { assert startOffset >= 0 : "Start offset not yet set"; @@ -186,6 +233,10 @@ public long getSize() { return getEndOffset() - getStartOffset(); } + public String toString() { + return name; + } + private static class SizeComparator implements Comparator { @Override public int compare(ImageHeapObject o1, ImageHeapObject o2) { diff --git a/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/GCImpl.java b/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/GCImpl.java index 0bfc16bfd4a7..82d65d75e344 100644 --- a/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/GCImpl.java +++ b/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/GCImpl.java @@ -331,7 +331,7 @@ private void verifyBeforeGC() { if (!success) { String kind = getGCKind(); Log.log().string("Heap verification failed before ").string(kind).string(" garbage collection.").newline(); - VMError.shouldNotReachHereAtRuntime(); + VMError.shouldNotReachHere("Heap verification failed"); } } finally { verifyBeforeTimer.close(); @@ -350,7 +350,7 @@ private void verifyAfterGC() { if (!success) { String kind = getGCKind(); Log.log().string("Heap verification failed after ").string(kind).string(" garbage collection.").newline(); - VMError.shouldNotReachHereAtRuntime(); + VMError.shouldNotReachHere("Heap verification failed"); } } finally { verifyAfterTime.close(); diff --git a/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/HeapChunk.java b/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/HeapChunk.java index 44b7dcc2db9a..33d7acb9f0b6 100644 --- a/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/HeapChunk.java +++ b/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/HeapChunk.java @@ -26,8 +26,6 @@ import java.util.function.IntUnaryOperator; -import jdk.graal.compiler.api.directives.GraalDirectives; -import jdk.graal.compiler.word.Word; import org.graalvm.nativeimage.Platform; import org.graalvm.nativeimage.Platforms; import org.graalvm.nativeimage.c.struct.RawField; @@ -50,6 +48,9 @@ import com.oracle.svm.core.hub.LayoutEncoding; import com.oracle.svm.core.identityhashcode.IdentityHashCodeSupport; +import jdk.graal.compiler.api.directives.GraalDirectives; +import jdk.graal.compiler.word.Word; + /** * The common structure of the chunks of memory which make up the heap. HeapChunks are aggregated * into {@linkplain Space spaces}. A specific "subtype" of chunk should be accessed via its own @@ -332,7 +333,6 @@ public static Pointer asPointer(Header that) { @Uninterruptible(reason = "Called from uninterruptible code.", mayBeInlined = true) public static HeapChunk.Header getEnclosingHeapChunk(Object obj) { if (!GraalDirectives.inIntrinsic()) { - assert !HeapImpl.getHeapImpl().isInImageHeap(obj) || HeapImpl.usesImageHeapChunks() : "Must be checked before calling this method"; assert !ObjectHeaderImpl.isPointerToForwardedObject(Word.objectToUntrackedPointer(obj)) : "Forwarded objects must be a pointer and not an object"; } if (ObjectHeaderImpl.isAlignedObject(obj)) { diff --git a/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/HeapImpl.java b/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/HeapImpl.java index 2374e7bb7e38..9ec3bd2c2b10 100644 --- a/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/HeapImpl.java +++ b/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/HeapImpl.java @@ -28,13 +28,6 @@ import java.util.ArrayList; import java.util.List; -import jdk.graal.compiler.api.directives.GraalDirectives; -import jdk.graal.compiler.api.replacements.Fold; -import jdk.graal.compiler.core.common.NumUtil; -import jdk.graal.compiler.core.common.SuppressFBWarnings; -import jdk.graal.compiler.nodes.extended.MembarNode; -import jdk.graal.compiler.nodes.memory.address.OffsetAddressNode; -import jdk.graal.compiler.word.Word; import org.graalvm.nativeimage.CurrentIsolate; import org.graalvm.nativeimage.IsolateThread; import org.graalvm.nativeimage.Platform; @@ -42,6 +35,7 @@ import org.graalvm.word.Pointer; import org.graalvm.word.UnsignedWord; +import com.oracle.svm.core.Isolates; import com.oracle.svm.core.MemoryWalker; import com.oracle.svm.core.NeverInline; import com.oracle.svm.core.SubstrateDiagnostics; @@ -92,6 +86,14 @@ import com.oracle.svm.core.util.UnsignedUtils; import com.oracle.svm.core.util.UserError; +import jdk.graal.compiler.api.directives.GraalDirectives; +import jdk.graal.compiler.api.replacements.Fold; +import jdk.graal.compiler.core.common.NumUtil; +import jdk.graal.compiler.core.common.SuppressFBWarnings; +import jdk.graal.compiler.nodes.extended.MembarNode; +import jdk.graal.compiler.nodes.memory.address.OffsetAddressNode; +import jdk.graal.compiler.word.Word; + public final class HeapImpl extends Heap { /** Synchronization means for notifying {@link #refPendingList} waiters without deadlocks. */ private static final VMMutex REF_MUTEX = new VMMutex("referencePendingList"); @@ -390,12 +392,6 @@ public void detachThread(IsolateThread isolateThread) { ThreadLocalAllocation.disableAndFlushForThread(isolateThread); } - @Fold - public static boolean usesImageHeapChunks() { - // Chunks are needed for card marking and not very useful without it - return usesImageHeapCardMarking(); - } - @Fold public static boolean usesImageHeapCardMarking() { Boolean enabled = SerialGCOptions.ImageHeapCardMarking.getValue(); @@ -430,20 +426,6 @@ public int getImageHeapOffsetInAddressSpace() { return 0; } - @Fold - @Override - public int getImageHeapNullRegionSize() { - if (SubstrateOptions.SpawnIsolates.getValue() && SubstrateOptions.UseNullRegion.getValue() && !CommittedMemoryProvider.get().guaranteesHeapPreferredAddressSpaceAlignment()) { - /* - * Prepend a single null page to the image heap so that there is a memory protected gap - * between the heap base and the start of the image heap. The null page is placed - * directly into the native image file, so it makes the file slightly larger. - */ - return pageSize; - } - return 0; - } - @Fold @Override public boolean allowPageSizeMismatch() { @@ -713,13 +695,8 @@ public long getIdentityHashSalt(Object obj) { @Uninterruptible(reason = "Called from uninterruptible code.", mayBeInlined = true) static Pointer getImageHeapStart() { - int imageHeapOffsetInAddressSpace = Heap.getHeap().getImageHeapOffsetInAddressSpace(); - if (imageHeapOffsetInAddressSpace > 0) { - return KnownIntrinsics.heapBase().add(imageHeapOffsetInAddressSpace); - } else { - int nullRegionSize = Heap.getHeap().getImageHeapNullRegionSize(); - return KnownIntrinsics.heapBase().add(nullRegionSize); - } + Pointer heapBase = (Pointer) Isolates.getHeapBase(CurrentIsolate.getIsolate()); + return heapBase.add(Heap.getHeap().getImageHeapOffsetInAddressSpace()); } private boolean printLocationInfo(Log log, Pointer ptr, boolean allowJavaHeapAccess, boolean allowUnsafeOperations) { diff --git a/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/HeapVerifier.java b/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/HeapVerifier.java index 48054b4d9b04..f5356dd150d0 100644 --- a/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/HeapVerifier.java +++ b/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/HeapVerifier.java @@ -26,13 +26,11 @@ import java.lang.ref.Reference; -import jdk.graal.compiler.word.Word; import org.graalvm.nativeimage.Platform; import org.graalvm.nativeimage.Platforms; import org.graalvm.word.Pointer; import org.graalvm.word.WordFactory; -import com.oracle.svm.core.MemoryWalker; import com.oracle.svm.core.SubstrateOptions; import com.oracle.svm.core.config.ConfigurationValues; import com.oracle.svm.core.genscavenge.AlignedHeapChunk.AlignedHeader; @@ -46,11 +44,13 @@ import com.oracle.svm.core.hub.DynamicHub; import com.oracle.svm.core.hub.InteriorObjRefWalker; import com.oracle.svm.core.log.Log; +import com.oracle.svm.core.os.CommittedMemoryProvider; import com.oracle.svm.core.snippets.KnownIntrinsics; +import jdk.graal.compiler.word.Word; + public final class HeapVerifier { private static final ObjectVerifier OBJECT_VERIFIER = new ObjectVerifier(); - private static final ImageHeapRegionVerifier IMAGE_HEAP_OBJECT_VERIFIER = new ImageHeapRegionVerifier(); private static final ObjectReferenceVerifier REFERENCE_VERIFIER = new ObjectReferenceVerifier(); @Platforms(Platform.HOSTED_ONLY.class) @@ -59,21 +59,13 @@ private HeapVerifier() { public static boolean verify(Occasion occasion) { boolean success = true; - success &= verifyImageHeapObjects(); + success &= verifyChunkedImageHeap(); success &= verifyYoungGeneration(occasion); success &= verifyOldGeneration(); success &= verifyRememberedSets(); return success; } - private static boolean verifyImageHeapObjects() { - if (HeapImpl.usesImageHeapChunks()) { - return verifyChunkedImageHeap(); - } else { - return verifyNonChunkedImageHeap(); - } - } - private static boolean verifyChunkedImageHeap() { boolean success = true; ImageHeapInfo info = HeapImpl.getImageHeapInfo(); @@ -82,12 +74,6 @@ private static boolean verifyChunkedImageHeap() { return success; } - private static boolean verifyNonChunkedImageHeap() { - IMAGE_HEAP_OBJECT_VERIFIER.initialize(); - ImageHeapWalker.walkRegions(HeapImpl.getImageHeapInfo(), IMAGE_HEAP_OBJECT_VERIFIER); - return IMAGE_HEAP_OBJECT_VERIFIER.getResult(); - } - private static boolean verifyYoungGeneration(Occasion occasion) { boolean success = true; YoungGeneration youngGeneration = HeapImpl.getHeapImpl().getYoungGeneration(); @@ -155,15 +141,13 @@ private static boolean verifyRememberedSets() { boolean success = true; RememberedSet rememberedSet = RememberedSet.get(); - if (HeapImpl.usesImageHeapChunks()) { - /* - * For the image heap, we can't verify that all cards are clean after a GC because the - * GC itself may result in dirty cards. - */ - ImageHeapInfo info = HeapImpl.getImageHeapInfo(); - success &= rememberedSet.verify(info.getFirstWritableAlignedChunk()); - success &= rememberedSet.verify(info.getFirstWritableUnalignedChunk()); - } + /* + * For the image heap, we can't verify that all cards are clean after a GC because the GC + * itself may result in dirty cards. + */ + ImageHeapInfo info = HeapImpl.getImageHeapInfo(); + success &= rememberedSet.verify(info.getFirstWritableAlignedChunk()); + success &= rememberedSet.verify(info.getFirstWritableUnalignedChunk()); OldGeneration oldGeneration = HeapImpl.getHeapImpl().getOldGeneration(); Space toSpace = oldGeneration.getToSpace(); @@ -269,49 +253,49 @@ private static boolean verifyObject(Object obj, AlignedHeader aChunk, UnalignedH return false; } - if (HeapImpl.usesImageHeapChunks() || !HeapImpl.getHeapImpl().isInImageHeap(obj)) { - assert aChunk.isNonNull() ^ uChunk.isNonNull(); - HeapChunk.Header expectedChunk = aChunk.isNonNull() ? aChunk : uChunk; - HeapChunk.Header chunk = HeapChunk.getEnclosingHeapChunk(obj); - if (chunk.notEqual(expectedChunk)) { - Log.log().string("Object ").zhex(ptr).string(" should have ").zhex(expectedChunk).string(" as its enclosing chunk but getEnclosingHeapChunk returned ").zhex(chunk).newline(); + assert aChunk.isNonNull() ^ uChunk.isNonNull(); + HeapChunk.Header chunk = aChunk.isNonNull() ? aChunk : uChunk; + if (CommittedMemoryProvider.get().guaranteesHeapPreferredAddressSpaceAlignment()) { + HeapChunk.Header enclosingHeapChunk = HeapChunk.getEnclosingHeapChunk(obj); + if (chunk.notEqual(enclosingHeapChunk)) { + Log.log().string("Object ").zhex(ptr).string(" should have ").zhex(chunk).string(" as its enclosing chunk but getEnclosingHeapChunk returned ").zhex(enclosingHeapChunk).newline(); return false; } + } + + Pointer chunkStart = HeapChunk.asPointer(chunk); + Pointer chunkTop = HeapChunk.getTopPointer(chunk); + if (chunkStart.aboveOrEqual(ptr) || chunkTop.belowOrEqual(ptr)) { + Log.log().string("Object ").zhex(ptr).string(" is not within the allocated part of the chunk: ").zhex(chunkStart).string(" - ").zhex(chunkTop).string("").newline(); + return false; + } - Pointer chunkStart = HeapChunk.asPointer(chunk); - Pointer chunkTop = HeapChunk.getTopPointer(chunk); - if (chunkStart.aboveOrEqual(ptr) || chunkTop.belowOrEqual(ptr)) { - Log.log().string("Object ").zhex(ptr).string(" is not within the allocated part of the chunk: ").zhex(chunkStart).string(" - ").zhex(chunkTop).string("").newline(); + if (aChunk.isNonNull()) { + if (!ObjectHeaderImpl.isAlignedHeader(header)) { + Log.log().string("Header of object ").zhex(ptr).string(" is not marked as aligned: ").zhex(header).newline(); + return false; + } + } else { + assert uChunk.isNonNull(); + if (!ObjectHeaderImpl.isUnalignedHeader(header)) { + Log.log().string("Header of object ").zhex(ptr).string(" is not marked as unaligned: ").zhex(header).newline(); return false; } + } - if (aChunk.isNonNull()) { - if (!ObjectHeaderImpl.isAlignedHeader(header)) { - Log.log().string("Header of object ").zhex(ptr).string(" is not marked as aligned: ").zhex(header).newline(); - return false; - } - } else { - assert uChunk.isNonNull(); - if (!ObjectHeaderImpl.isUnalignedHeader(header)) { - Log.log().string("Header of object ").zhex(ptr).string(" is not marked as unaligned: ").zhex(header).newline(); - return false; - } + Space space = chunk.getSpace(); + if (space == null) { + if (!HeapImpl.getHeapImpl().isInImageHeap(obj)) { + Log.log().string("Object ").zhex(ptr).string(" is not an image heap object even though the space of the parent chunk ").zhex(chunk).string(" is null.").newline(); + return false; } + // Not all objects in the image heap have the remembered set bit in the header, so + // we can't verify that this bit is set. - Space space = chunk.getSpace(); - if (space == null) { - if (!HeapImpl.getHeapImpl().isInImageHeap(obj)) { - Log.log().string("Object ").zhex(ptr).string(" is not an image heap object even though the space of the parent chunk ").zhex(chunk).string(" is null.").newline(); - return false; - } - // Not all objects in the image heap have the remembered set bit in the header, so - // we can't verify that this bit is set. - - } else if (space.isOldSpace()) { - if (SubstrateOptions.useRememberedSet() && !RememberedSet.get().hasRememberedSet(header)) { - Log.log().string("Object ").zhex(ptr).string(" is in old generation chunk ").zhex(chunk).string(" but does not have a remembered set.").newline(); - return false; - } + } else if (space.isOldSpace()) { + if (SubstrateOptions.useRememberedSet() && !RememberedSet.get().hasRememberedSet(header)) { + Log.log().string("Object ").zhex(ptr).string(" is in old generation chunk ").zhex(chunk).string(" but does not have a remembered set.").newline(); + return false; } } @@ -383,29 +367,6 @@ private static void printParent(Object parentObject) { } } - private static class ImageHeapRegionVerifier implements MemoryWalker.ImageHeapRegionVisitor { - private final ImageHeapObjectVerifier objectVerifier; - - @Platforms(Platform.HOSTED_ONLY.class) - ImageHeapRegionVerifier() { - objectVerifier = new ImageHeapObjectVerifier(); - } - - public void initialize() { - objectVerifier.initialize(WordFactory.nullPointer(), WordFactory.nullPointer()); - } - - public boolean getResult() { - return objectVerifier.result; - } - - @Override - public boolean visitNativeImageHeapRegion(T region, MemoryWalker.NativeImageHeapRegionAccess access) { - access.visitObjects(region, objectVerifier); - return true; - } - } - private static class ObjectVerifier implements ObjectVisitor { protected boolean result; private AlignedHeader aChunk; @@ -429,23 +390,6 @@ public boolean visitObject(Object object) { } } - private static class ImageHeapObjectVerifier extends ObjectVerifier { - @Platforms(Platform.HOSTED_ONLY.class) - ImageHeapObjectVerifier() { - } - - @Override - public boolean visitObject(Object object) { - Word pointer = Word.objectToUntrackedPointer(object); - if (!HeapImpl.getHeapImpl().isInImageHeap(object)) { - Log.log().string("Image heap object ").zhex(pointer).string(" is not considered as part of the image heap.").newline(); - result = false; - } - - return super.visitObject(object); - } - } - private static class ObjectReferenceVerifier implements ObjectReferenceVisitor { private boolean result; diff --git a/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/ImageHeapInfo.java b/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/ImageHeapInfo.java index e7dddf3ed31f..637b534b64d9 100644 --- a/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/ImageHeapInfo.java +++ b/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/ImageHeapInfo.java @@ -24,12 +24,13 @@ */ package com.oracle.svm.core.genscavenge; -import jdk.graal.compiler.word.Word; +import org.graalvm.nativeimage.CurrentIsolate; import org.graalvm.word.Pointer; import org.graalvm.word.UnsignedWord; import org.graalvm.word.WordFactory; import com.oracle.svm.core.BuildPhaseProvider.AfterHeapLayout; +import com.oracle.svm.core.Isolates; import com.oracle.svm.core.Uninterruptible; import com.oracle.svm.core.genscavenge.AlignedHeapChunk.AlignedHeader; import com.oracle.svm.core.genscavenge.UnalignedHeapChunk.UnalignedHeader; @@ -37,7 +38,8 @@ import com.oracle.svm.core.heap.UnknownPrimitiveField; import com.oracle.svm.core.hub.LayoutEncoding; import com.oracle.svm.core.log.Log; -import com.oracle.svm.core.snippets.KnownIntrinsics; + +import jdk.graal.compiler.word.Word; /** * Information on the multiple partitions that make up the image heap, which don't necessarily form @@ -213,7 +215,8 @@ private static > T asImageHeapChunk(long offsetInI return (T) WordFactory.nullPointer(); } UnsignedWord offset = WordFactory.unsigned(offsetInImageHeap); - return (T) KnownIntrinsics.heapBase().add(offset); + Pointer heapBase = (Pointer) Isolates.getHeapBase(CurrentIsolate.getIsolate()); + return (T) heapBase.add(offset); } public void print(Log log) { diff --git a/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/ImageHeapWalker.java b/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/ImageHeapWalker.java index ec12e0b1e200..504f477c9776 100644 --- a/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/ImageHeapWalker.java +++ b/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/ImageHeapWalker.java @@ -24,7 +24,6 @@ */ package com.oracle.svm.core.genscavenge; -import jdk.graal.compiler.word.Word; import org.graalvm.nativeimage.Platform; import org.graalvm.nativeimage.Platforms; import org.graalvm.word.Pointer; @@ -36,9 +35,10 @@ import com.oracle.svm.core.Uninterruptible; import com.oracle.svm.core.heap.ObjectVisitor; import com.oracle.svm.core.hub.LayoutEncoding; -import com.oracle.svm.core.os.CommittedMemoryProvider; import com.oracle.svm.core.util.UnsignedUtils; +import jdk.graal.compiler.word.Word; + public final class ImageHeapWalker { private static final MemoryWalker.NativeImageHeapRegionAccess READ_ONLY_PRIMITIVE_WALKER = new ReadOnlyPrimitiveMemoryWalkerAccess(); private static final MemoryWalker.NativeImageHeapRegionAccess READ_ONLY_REFERENCE_WALKER = new ReadOnlyReferenceMemoryWalkerAccess(); @@ -91,27 +91,22 @@ private static boolean walkPartitionInline(Object firstObject, Object lastObject Pointer firstPointer = Word.objectToUntrackedPointer(firstObject); Pointer lastPointer = Word.objectToUntrackedPointer(lastObject); Pointer current = firstPointer; - HeapChunk.Header currentChunk = WordFactory.nullPointer(); - if (HeapImpl.usesImageHeapChunks()) { - Pointer base = WordFactory.zero(); - if (!CommittedMemoryProvider.get().guaranteesHeapPreferredAddressSpaceAlignment()) { - base = HeapImpl.getImageHeapStart(); - } - Pointer offset = current.subtract(base); - UnsignedWord chunkOffset = alignedChunks ? UnsignedUtils.roundDown(offset, HeapParameters.getAlignedHeapChunkAlignment()) - : offset.subtract(UnalignedHeapChunk.getObjectStartOffset()); - currentChunk = (HeapChunk.Header) chunkOffset.add(base); - // Assumption: the order of chunks in their linked list is the same order as in memory, - // and objects are laid out as a continuous sequence without any gaps. - } + /* Compute the enclosing chunk without assuming that the image heap is aligned. */ + Pointer base = HeapImpl.getImageHeapStart(); + Pointer offset = current.subtract(base); + UnsignedWord chunkOffset = alignedChunks ? UnsignedUtils.roundDown(offset, HeapParameters.getAlignedHeapChunkAlignment()) + : offset.subtract(UnalignedHeapChunk.getObjectStartOffset()); + HeapChunk.Header currentChunk = (HeapChunk.Header) chunkOffset.add(base); + + // Assumption: the order of chunks in their linked list is the same order as in memory, + // and objects are laid out as a continuous sequence without any gaps. + do { Pointer limit = lastPointer; - if (HeapImpl.usesImageHeapChunks()) { - Pointer chunkTop = HeapChunk.getTopPointer(currentChunk); - if (lastPointer.aboveThan(chunkTop)) { - limit = chunkTop.subtract(1); // lastObject in another chunk, visit all objects - } + Pointer chunkTop = HeapChunk.getTopPointer(currentChunk); + if (lastPointer.aboveThan(chunkTop)) { + limit = chunkTop.subtract(1); // lastObject in another chunk, visit all objects } while (current.belowOrEqual(limit)) { Object currentObject = current.toObject(); @@ -124,7 +119,7 @@ private static boolean walkPartitionInline(Object firstObject, Object lastObject } current = LayoutEncoding.getImageHeapObjectEnd(current.toObject()); } - if (HeapImpl.usesImageHeapChunks() && current.belowThan(lastPointer)) { + if (current.belowThan(lastPointer)) { currentChunk = HeapChunk.getNext(currentChunk); current = alignedChunks ? AlignedHeapChunk.getObjectsStart((AlignedHeapChunk.AlignedHeader) currentChunk) : UnalignedHeapChunk.getObjectStart((UnalignedHeapChunk.UnalignedHeader) currentChunk); diff --git a/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/LinearImageHeapAllocator.java b/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/LinearImageHeapAllocator.java deleted file mode 100644 index 8f2bde217382..000000000000 --- a/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/LinearImageHeapAllocator.java +++ /dev/null @@ -1,52 +0,0 @@ -/* - * Copyright (c) 2020, 2020, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.oracle.svm.core.genscavenge; - -public class LinearImageHeapAllocator { - private long position; - - public LinearImageHeapAllocator(long position) { - this.position = position; - } - - public long getPosition() { - return position; - } - - public long allocate(long size) { - long begin = position; - position += size; - return begin; - } - - public void align(int multiple) { - allocate(computePadding(position, multiple)); - } - - static long computePadding(long offset, int alignment) { - long remainder = offset % alignment; - return remainder == 0 ? 0 : alignment - remainder; - } -} diff --git a/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/LinearImageHeapLayouter.java b/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/LinearImageHeapLayouter.java deleted file mode 100644 index 569a999b8c63..000000000000 --- a/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/LinearImageHeapLayouter.java +++ /dev/null @@ -1,85 +0,0 @@ -/* - * Copyright (c) 2019, 2019, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.oracle.svm.core.genscavenge; - -import com.oracle.svm.core.config.ConfigurationValues; -import com.oracle.svm.core.heap.Heap; -import com.oracle.svm.core.image.ImageHeap; -import com.oracle.svm.core.image.ImageHeapLayoutInfo; - -public class LinearImageHeapLayouter extends AbstractImageHeapLayouter { - private final ImageHeapInfo heapInfo; - private final long startOffset; - private final int nullRegionSize; - - public LinearImageHeapLayouter(ImageHeapInfo heapInfo, long startOffset, int nullRegionSize) { - assert startOffset >= 0; - assert startOffset == 0 || startOffset >= Heap.getHeap().getImageHeapOffsetInAddressSpace() : "must be relative to the heap base"; - assert nullRegionSize >= 0; - this.heapInfo = heapInfo; - this.startOffset = startOffset; - this.nullRegionSize = nullRegionSize; - } - - @Override - protected LinearImageHeapPartition[] createPartitionsArray(int count) { - return new LinearImageHeapPartition[count]; - } - - @Override - protected LinearImageHeapPartition createPartition(String name, boolean containsReferences, boolean writable, boolean hugeObjects) { - return new LinearImageHeapPartition(name, writable); - } - - @Override - protected ImageHeapLayoutInfo doLayout(ImageHeap imageHeap) { - long beginOffset = startOffset + spaceReservedForNull(); - assert beginOffset >= ConfigurationValues.getObjectLayout().getAlignment() : "Zero designates null"; - LinearImageHeapAllocator allocator = new LinearImageHeapAllocator(beginOffset); - for (LinearImageHeapPartition partition : getPartitions()) { - partition.allocateObjects(allocator); - } - initializeHeapInfo(imageHeap.countDynamicHubs()); - return createLayoutInfo(startOffset, getWritablePrimitive().getStartOffset()); - } - - private long spaceReservedForNull() { - if (startOffset == 0 && nullRegionSize == 0) { - return ConfigurationValues.getObjectLayout().getAlignment(); - } - return nullRegionSize; - } - - /** - * Store which objects are at the boundaries of the image heap partitions. Here, we also merge - * the read-only reference partition with the read-only relocatable partition. - */ - private void initializeHeapInfo(int dynamicHubCount) { - heapInfo.initialize(getReadOnlyPrimitive().firstObject, getReadOnlyPrimitive().lastObject, getReadOnlyReference().firstObject, getReadOnlyReference().lastObject, - getReadOnlyRelocatable().firstObject, getReadOnlyRelocatable().lastObject, getWritablePrimitive().firstObject, getWritablePrimitive().lastObject, - getWritableReference().firstObject, getWritableReference().lastObject, getWritableHuge().firstObject, getWritableHuge().lastObject, - getReadOnlyHuge().firstObject, getReadOnlyHuge().lastObject, ImageHeapInfo.NO_CHUNK, ImageHeapInfo.NO_CHUNK, dynamicHubCount); - } -} diff --git a/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/LinearImageHeapPartition.java b/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/LinearImageHeapPartition.java deleted file mode 100644 index 5be426e4e560..000000000000 --- a/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/LinearImageHeapPartition.java +++ /dev/null @@ -1,87 +0,0 @@ -/* - * Copyright (c) 2019, 2019, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.oracle.svm.core.genscavenge; - -import com.oracle.svm.core.config.ConfigurationValues; -import com.oracle.svm.core.genscavenge.AbstractImageHeapLayouter.AbstractImageHeapPartition; -import com.oracle.svm.core.image.ImageHeapObject; - -/** - * An unstructured image heap partition that just contains a linear sequence of image heap objects. - */ -public class LinearImageHeapPartition extends AbstractImageHeapPartition { - Object firstObject; - Object lastObject; - - long startOffset = -1; - long endOffset = -1; - - LinearImageHeapPartition(String name, boolean writable) { - super(name, writable); - } - - void allocateObjects(LinearImageHeapAllocator allocator) { - allocator.align(getStartAlignment()); - startOffset = allocator.getPosition(); - for (ImageHeapObject info : getObjects()) { - allocate(info, allocator); - } - allocator.align(getEndAlignment()); - endOffset = allocator.getPosition(); - } - - private void allocate(ImageHeapObject info, LinearImageHeapAllocator allocator) { - assert info.getPartition() == this; - if (firstObject == null) { - firstObject = info.getObject(); - } - long offsetInPartition = allocator.allocate(info.getSize()) - startOffset; - assert ConfigurationValues.getObjectLayout().isAligned(offsetInPartition) : "start: " + offsetInPartition + " must be aligned."; - info.setOffsetInPartition(offsetInPartition); - lastObject = info.getObject(); - } - - @Override - public void assign(ImageHeapObject obj) { - assert startOffset == -1 && endOffset == -1 : "Adding objects late is not supported"; - super.assign(obj); - } - - @Override - public long getStartOffset() { - assert startOffset >= 0 : "Start offset not yet set"; - return startOffset; - } - - public long getEndOffset() { - assert endOffset >= 0 : "End offset not yet set"; - return endOffset; - } - - @Override - public long getSize() { - return getEndOffset() - getStartOffset(); - } -} diff --git a/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/ObjectHeaderImpl.java b/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/ObjectHeaderImpl.java index 6c414ee63a13..c9f5af276171 100644 --- a/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/ObjectHeaderImpl.java +++ b/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/ObjectHeaderImpl.java @@ -305,17 +305,15 @@ public long encodeAsImageHeapObjectHeader(ImageHeapObject obj, long hubOffsetFro long header = hubOffsetFromHeapBase << numReservedExtraBits; VMError.guarantee((header >>> numReservedExtraBits) == hubOffsetFromHeapBase, "Hub is too far from heap base for encoding in object header"); assert (header & reservedBitsMask) == 0 : "Object header bits must be zero initially"; - if (HeapImpl.usesImageHeapCardMarking()) { - if (obj.getPartition() instanceof ChunkedImageHeapPartition partition) { - if (partition.isWritable()) { - header |= REMEMBERED_SET_BIT.rawValue(); - } - if (partition.usesUnalignedObjects()) { - header |= UNALIGNED_BIT.rawValue(); - } - } else { - assert obj.getPartition() instanceof FillerObjectDummyPartition; + if (obj.getPartition() instanceof ChunkedImageHeapPartition partition) { + if (partition.isWritable() && HeapImpl.usesImageHeapCardMarking()) { + header |= REMEMBERED_SET_BIT.rawValue(); + } + if (partition.usesUnalignedObjects()) { + header |= UNALIGNED_BIT.rawValue(); } + } else { + assert obj.getPartition() instanceof FillerObjectDummyPartition; } if (isIdentityHashFieldOptional()) { header |= (IDHASH_STATE_IN_FIELD.rawValue() << IDHASH_STATE_SHIFT); diff --git a/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/UnalignedHeapChunk.java b/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/UnalignedHeapChunk.java index 7841fc6e0b34..afcdc50fa19e 100644 --- a/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/UnalignedHeapChunk.java +++ b/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/UnalignedHeapChunk.java @@ -24,8 +24,6 @@ */ package com.oracle.svm.core.genscavenge; -import jdk.graal.compiler.api.replacements.Fold; -import jdk.graal.compiler.word.Word; import org.graalvm.nativeimage.ImageSingletons; import org.graalvm.nativeimage.Platform; import org.graalvm.nativeimage.Platforms; @@ -41,8 +39,13 @@ import com.oracle.svm.core.feature.AutomaticallyRegisteredImageSingleton; import com.oracle.svm.core.genscavenge.remset.RememberedSet; import com.oracle.svm.core.heap.ObjectVisitor; +import com.oracle.svm.core.os.CommittedMemoryProvider; import com.oracle.svm.core.util.UnsignedUtils; +import jdk.graal.compiler.api.directives.GraalDirectives; +import jdk.graal.compiler.api.replacements.Fold; +import jdk.graal.compiler.word.Word; + /** * An UnalignedHeapChunk holds exactly one Object. *

    @@ -131,8 +134,11 @@ public static UnalignedHeader getEnclosingChunk(Object obj) { } @Uninterruptible(reason = "Called from uninterruptible code.", mayBeInlined = true) - static UnalignedHeader getEnclosingChunkFromObjectPointer(Pointer objPointer) { - Pointer chunkPointer = objPointer.subtract(getObjectStartOffset()); + static UnalignedHeader getEnclosingChunkFromObjectPointer(Pointer ptr) { + if (!GraalDirectives.inIntrinsic()) { + assert !HeapImpl.getHeapImpl().isInImageHeap(ptr) || CommittedMemoryProvider.get().guaranteesHeapPreferredAddressSpaceAlignment() : "can't be used because the image heap is unaligned"; + } + Pointer chunkPointer = ptr.subtract(getObjectStartOffset()); return (UnalignedHeader) chunkPointer; } diff --git a/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/graal/GenScavengeGCFeature.java b/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/graal/GenScavengeGCFeature.java index 6727381fad42..a5a1cc983c51 100644 --- a/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/graal/GenScavengeGCFeature.java +++ b/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/graal/GenScavengeGCFeature.java @@ -43,7 +43,6 @@ import com.oracle.svm.core.genscavenge.HeapImplMemoryMXBean; import com.oracle.svm.core.genscavenge.ImageHeapInfo; import com.oracle.svm.core.genscavenge.IncrementalGarbageCollectorMXBean; -import com.oracle.svm.core.genscavenge.LinearImageHeapLayouter; import com.oracle.svm.core.genscavenge.jvmstat.EpsilonGCPerfData; import com.oracle.svm.core.genscavenge.jvmstat.SerialGCPerfData; import com.oracle.svm.core.genscavenge.remset.CardTableBasedRememberedSet; @@ -143,13 +142,7 @@ public void beforeAnalysis(BeforeAnalysisAccess access) { @Override public void afterAnalysis(AfterAnalysisAccess access) { - ImageHeapLayouter heapLayouter; - int imageHeapNullRegionSize = Heap.getHeap().getImageHeapNullRegionSize(); - if (HeapImpl.usesImageHeapChunks()) { // needs CommittedMemoryProvider: registered late - heapLayouter = new ChunkedImageHeapLayouter(HeapImpl.getImageHeapInfo(), 0, imageHeapNullRegionSize); - } else { - heapLayouter = new LinearImageHeapLayouter(HeapImpl.getImageHeapInfo(), 0, imageHeapNullRegionSize); - } + ImageHeapLayouter heapLayouter = new ChunkedImageHeapLayouter(HeapImpl.getImageHeapInfo(), 0); ImageSingletons.add(ImageHeapLayouter.class, heapLayouter); } diff --git a/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/remset/CardTable.java b/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/remset/CardTable.java index ada7186fb4b5..d9fb3d7e1d3d 100644 --- a/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/remset/CardTable.java +++ b/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/remset/CardTable.java @@ -26,9 +26,6 @@ import java.lang.ref.Reference; -import jdk.graal.compiler.core.common.SuppressFBWarnings; -import jdk.graal.compiler.nodes.extended.BranchProbabilityNode; -import jdk.graal.compiler.word.Word; import org.graalvm.word.Pointer; import org.graalvm.word.UnsignedWord; import org.graalvm.word.WordFactory; @@ -48,6 +45,10 @@ import com.oracle.svm.core.snippets.KnownIntrinsics; import com.oracle.svm.core.util.UnsignedUtils; +import jdk.graal.compiler.core.common.SuppressFBWarnings; +import jdk.graal.compiler.nodes.extended.BranchProbabilityNode; +import jdk.graal.compiler.word.Word; + /** * A card table is a remembered set that summarizes pointer stores into a region. A card is "dirty" * if a pointer has been stored recently into the memory summarized by the card, or "clean" @@ -173,23 +174,26 @@ private static boolean verifyReferent(Reference ref, Pointer cardTableStart, } private static boolean verifyReference(Object parentObject, Pointer cardTableStart, Pointer objectsStart, Pointer reference, Pointer referencedObject) { - if (referencedObject.isNonNull() && !HeapImpl.getHeapImpl().isInImageHeap(referencedObject)) { - Object obj = referencedObject.toObject(); - HeapChunk.Header objChunk = HeapChunk.getEnclosingHeapChunk(obj); - // Fail if we find a reference from the image heap to the runtime heap, or from the - // old generation (which is the only one with remembered sets) to the young generation. - boolean fromImageHeap = HeapImpl.usesImageHeapCardMarking() && HeapImpl.getHeapImpl().isInImageHeap(parentObject); - if (fromImageHeap || HeapChunk.getSpace(objChunk).isYoungSpace()) { - UnsignedWord cardTableIndex = memoryOffsetToIndex(Word.objectToUntrackedPointer(parentObject).subtract(objectsStart)); - Pointer cardTableAddress = cardTableStart.add(cardTableIndex); - Log.log().string("Object ").zhex(Word.objectToUntrackedPointer(parentObject)).string(" (").string(parentObject.getClass().getName()).character(')') - .string(fromImageHeap ? ", which is in the image heap, " : " ") - .string("has an object reference at ") - .zhex(reference).string(" that points to ").zhex(referencedObject).string(" (").string(obj.getClass().getName()).string("), ") - .string("which is in the ").string(fromImageHeap ? "runtime heap" : "young generation").string(". ") - .string("However, the card table at ").zhex(cardTableAddress).string(" is clean.").newline(); - return false; - } + if (referencedObject.isNull() || + HeapImpl.getHeapImpl().isInImageHeap(referencedObject) || + HeapImpl.getHeapImpl().isInImageHeap(parentObject) && !HeapImpl.usesImageHeapCardMarking()) { + return true; + } + + Object obj = referencedObject.toObject(); + HeapChunk.Header objChunk = HeapChunk.getEnclosingHeapChunk(obj); + /* Fail if we find a reference to the young generation. */ + boolean fromImageHeap = HeapImpl.getHeapImpl().isInImageHeap(parentObject); + if (fromImageHeap || HeapChunk.getSpace(objChunk).isYoungSpace()) { + UnsignedWord cardTableIndex = memoryOffsetToIndex(Word.objectToUntrackedPointer(parentObject).subtract(objectsStart)); + Pointer cardTableAddress = cardTableStart.add(cardTableIndex); + Log.log().string("Object ").zhex(Word.objectToUntrackedPointer(parentObject)).string(" (").string(parentObject.getClass().getName()).character(')') + .string(fromImageHeap ? ", which is in the image heap, " : " ") + .string("has an object reference at ") + .zhex(reference).string(" that points to ").zhex(referencedObject).string(" (").string(obj.getClass().getName()).string("), ") + .string("which is in the ").string(fromImageHeap ? "runtime heap" : "young generation").string(". ") + .string("However, the card table at ").zhex(cardTableAddress).string(" is clean.").newline(); + return false; } return true; } diff --git a/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/remset/NoRememberedSet.java b/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/remset/NoRememberedSet.java index b0544608c316..16b1d7f0b4bd 100644 --- a/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/remset/NoRememberedSet.java +++ b/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/remset/NoRememberedSet.java @@ -26,7 +26,6 @@ import java.util.List; -import jdk.graal.compiler.nodes.gc.BarrierSet; import org.graalvm.nativeimage.Platform; import org.graalvm.nativeimage.Platforms; import org.graalvm.nativeimage.c.struct.SizeOf; @@ -46,6 +45,7 @@ import com.oracle.svm.core.util.UnsignedUtils; import com.oracle.svm.core.util.VMError; +import jdk.graal.compiler.nodes.gc.BarrierSet; import jdk.vm.ci.meta.MetaAccessProvider; /** diff --git a/substratevm/src/com.oracle.svm.core.posix/src/com/oracle/svm/core/posix/linux/LinuxImageHeapProvider.java b/substratevm/src/com.oracle.svm.core.posix/src/com/oracle/svm/core/posix/linux/LinuxImageHeapProvider.java index 555a381ff406..163428a33c3f 100644 --- a/substratevm/src/com.oracle.svm.core.posix/src/com/oracle/svm/core/posix/linux/LinuxImageHeapProvider.java +++ b/substratevm/src/com.oracle.svm.core.posix/src/com/oracle/svm/core/posix/linux/LinuxImageHeapProvider.java @@ -38,7 +38,6 @@ import java.util.concurrent.ThreadLocalRandom; -import jdk.graal.compiler.word.Word; import org.graalvm.nativeimage.StackValue; import org.graalvm.nativeimage.c.type.CCharPointer; import org.graalvm.nativeimage.c.type.WordPointer; @@ -67,6 +66,8 @@ import com.oracle.svm.core.posix.headers.Unistd; import com.oracle.svm.core.util.PointerUtils; +import jdk.graal.compiler.word.Word; + /** * An optimal image heap provider for Linux which creates isolate image heaps that retain the * copy-on-write, lazy loading and reclamation semantics provided by the original heap's backing @@ -171,14 +172,6 @@ public int initialize(Pointer reservedAddressSpace, UnsignedWord reservedSize, W return CEntryPointErrors.PROTECT_HEAP_FAILED; } - // Protect the null region. - int nullRegionSize = Heap.getHeap().getImageHeapNullRegionSize(); - if (nullRegionSize > 0) { - if (VirtualMemoryProvider.get().protect(imageHeapBegin, WordFactory.unsigned(nullRegionSize), Access.NONE) != 0) { - return CEntryPointErrors.PROTECT_HEAP_FAILED; - } - } - basePointer.write(imageHeapBegin); if (endPointer.isNonNull()) { endPointer.write(IMAGE_HEAP_END.get()); diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/heap/Heap.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/heap/Heap.java index 0e4873ad4a35..103ee02581c7 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/heap/Heap.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/heap/Heap.java @@ -29,7 +29,6 @@ import java.util.List; import java.util.function.Consumer; -import jdk.graal.compiler.api.replacements.Fold; import org.graalvm.nativeimage.ImageSingletons; import org.graalvm.nativeimage.IsolateThread; import org.graalvm.nativeimage.Platform; @@ -45,7 +44,8 @@ import com.oracle.svm.core.log.Log; import com.oracle.svm.core.option.RuntimeOptionKey; import com.oracle.svm.core.os.CommittedMemoryProvider; -import com.oracle.svm.core.os.ImageHeapProvider; + +import jdk.graal.compiler.api.replacements.Fold; public abstract class Heap { @Fold @@ -157,15 +157,6 @@ public void visitLoadedClasses(Consumer> visitor) { @Fold public abstract int getImageHeapOffsetInAddressSpace(); - /** - * Returns the number of null bytes that should be prepended to the image heap during the image - * build. This value must be a multiple of the page size. When the image heap is mapped at - * runtime, this extra memory gets mapped as well but is marked as inaccessible (see - * {@link ImageHeapProvider} for more details). - */ - @Fold - public abstract int getImageHeapNullRegionSize(); - /** * Returns whether the runtime page size doesn't have to match the page size set at image * creation ({@link SubstrateOptions#getPageSize()}). If there is a mismatch, then the page size diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/os/AbstractCommittedMemoryProvider.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/os/AbstractCommittedMemoryProvider.java index 55c4add3af9e..fcbdbdf643d5 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/os/AbstractCommittedMemoryProvider.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/os/AbstractCommittedMemoryProvider.java @@ -32,7 +32,6 @@ import java.util.EnumSet; -import jdk.graal.compiler.api.replacements.Fold; import org.graalvm.word.Pointer; import org.graalvm.word.PointerBase; import org.graalvm.word.UnsignedWord; @@ -47,6 +46,8 @@ import com.oracle.svm.core.util.UnsignedUtils; import com.oracle.svm.core.util.VMError; +import jdk.graal.compiler.api.replacements.Fold; + public abstract class AbstractCommittedMemoryProvider implements CommittedMemoryProvider { @Fold @Override @@ -57,7 +58,6 @@ public boolean guaranteesHeapPreferredAddressSpaceAlignment() { @Uninterruptible(reason = "Still being initialized.") protected static int protectSingleIsolateImageHeap() { assert !SubstrateOptions.SpawnIsolates.getValue() : "Must be handled by ImageHeapProvider when SpawnIsolates is enabled"; - assert Heap.getHeap().getImageHeapNullRegionSize() == 0 : "A null region only makes sense with a heap base."; Pointer heapBegin = IMAGE_HEAP_BEGIN.get(); if (Heap.getHeap().getImageHeapOffsetInAddressSpace() != 0) { return CEntryPointErrors.MAP_HEAP_FAILED; diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/os/AbstractCopyingImageHeapProvider.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/os/AbstractCopyingImageHeapProvider.java index afe8fde670ff..1bca6c7217ef 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/os/AbstractCopyingImageHeapProvider.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/os/AbstractCopyingImageHeapProvider.java @@ -29,8 +29,6 @@ import static com.oracle.svm.core.Isolates.IMAGE_HEAP_WRITABLE_END; import static com.oracle.svm.core.util.PointerUtils.roundUp; -import com.oracle.svm.core.code.DynamicMethodAddressResolutionHeapSupport; -import jdk.graal.compiler.word.Word; import org.graalvm.nativeimage.c.type.WordPointer; import org.graalvm.word.Pointer; import org.graalvm.word.PointerBase; @@ -39,10 +37,13 @@ import com.oracle.svm.core.Uninterruptible; import com.oracle.svm.core.c.function.CEntryPointErrors; +import com.oracle.svm.core.code.DynamicMethodAddressResolutionHeapSupport; import com.oracle.svm.core.heap.Heap; import com.oracle.svm.core.os.VirtualMemoryProvider.Access; import com.oracle.svm.core.util.UnsignedUtils; +import jdk.graal.compiler.word.Word; + public abstract class AbstractCopyingImageHeapProvider extends AbstractImageHeapProvider { @Override public boolean guaranteesHeapPreferredAddressSpaceAlignment() { @@ -108,9 +109,8 @@ public int initialize(Pointer reservedAddressSpace, UnsignedWord reservedSize, W // Protect the read-only parts at the start of the image heap. UnsignedWord pageSize = VirtualMemoryProvider.get().getGranularity(); - int nullRegionSize = Heap.getHeap().getImageHeapNullRegionSize(); - Pointer firstPartOfReadOnlyImageHeap = imageHeap.add(nullRegionSize); - UnsignedWord writableBeginPageOffset = UnsignedUtils.roundDown(IMAGE_HEAP_WRITABLE_BEGIN.get().subtract(imageHeapBegin.add(nullRegionSize)), pageSize); + Pointer firstPartOfReadOnlyImageHeap = imageHeap; + UnsignedWord writableBeginPageOffset = UnsignedUtils.roundDown(IMAGE_HEAP_WRITABLE_BEGIN.get().subtract(imageHeapBegin), pageSize); if (writableBeginPageOffset.aboveThan(0)) { if (VirtualMemoryProvider.get().protect(firstPartOfReadOnlyImageHeap, writableBeginPageOffset, Access.READ) != 0) { freeImageHeap(allocatedMemory); @@ -129,13 +129,6 @@ public int initialize(Pointer reservedAddressSpace, UnsignedWord reservedSize, W } } - // Protect the null region. - if (nullRegionSize > 0) { - if (VirtualMemoryProvider.get().protect(imageHeapBegin, WordFactory.unsigned(nullRegionSize), Access.NONE) != 0) { - return CEntryPointErrors.PROTECT_HEAP_FAILED; - } - } - // Update the heap base and end pointers. basePointer.write(heapBase); if (endPointer.isNonNull()) { diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/os/ImageHeapProvider.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/os/ImageHeapProvider.java index b277db95d154..a20f821b0ec0 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/os/ImageHeapProvider.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/os/ImageHeapProvider.java @@ -24,7 +24,6 @@ */ package com.oracle.svm.core.os; -import jdk.graal.compiler.api.replacements.Fold; import org.graalvm.nativeimage.ImageSingletons; import org.graalvm.nativeimage.c.type.WordPointer; import org.graalvm.word.Pointer; @@ -34,15 +33,16 @@ import com.oracle.svm.core.c.function.CEntryPointErrors; import com.oracle.svm.core.heap.Heap; +import jdk.graal.compiler.api.replacements.Fold; + /** * Provides new instances of the image heap for creating isolates. The same image heap provider * implementation can be shared by different garbage collectors. *

    * When a heap base is used, then the image heap is always mapped in a way that the memory at the - * heap base is protected and marked as inaccessible. Depending on the specific scenario, that - * memory may or may not be part of the Native Image file (see - * {@link Heap#getImageHeapNullRegionSize()} and {@link Heap#getImageHeapOffsetInAddressSpace()} for - * more details). This is done regardless of the used GC, platform, or CPU architecture: + * heap base is protected and marked as inaccessible (see + * {@link Heap#getImageHeapOffsetInAddressSpace()} for more details). This is done regardless of the + * used GC, platform, or CPU architecture: * *

      * | protected memory | image heap |
    
    From b942c315686d6ec9aab5be65c961662b0cf259db Mon Sep 17 00:00:00 2001
    From: Marouane El Hallaoui 
    Date: Tue, 19 Dec 2023 00:24:28 +0100
    Subject: [PATCH 263/593] deploy snapshots
    
    ---
     common.json | 12 ++++++------
     1 file changed, 6 insertions(+), 6 deletions(-)
    
    diff --git a/common.json b/common.json
    index 37d8ee191165..903eb2ce446e 100644
    --- a/common.json
    +++ b/common.json
    @@ -45,12 +45,12 @@
         "labsjdk-ee-21-llvm": {"name": "labsjdk",   "version": "ee-21.0.1+11-jvmci-23.1-b26-sulong", "platformspecific": true },
     
         "oraclejdk-latest":       {"name": "jpg-jdk",   "version": "23",      "build_id": "1", "release": true, "platformspecific": true, "extrabundles": ["static-libs"]},
    -    "labsjdk-ce-latest":      {"name": "labsjdk",   "version": "ce-23+1-jvmci-b01-20231213123324-6bfc73c47c", "platformspecific": true },
    -    "labsjdk-ce-latestDebug": {"name": "labsjdk",   "version": "ce-23+1-jvmci-b01-20231213123324-6bfc73c47c-debug", "platformspecific": true },
    -    "labsjdk-ce-latest-llvm": {"name": "labsjdk",   "version": "ce-23+1-jvmci-b01-20231213123324-6bfc73c47c-sulong", "platformspecific": true },
    -    "labsjdk-ee-latest":      {"name": "labsjdk",   "version": "ee-23+1-jvmci-b01-20231213123324-6bfc73c47c+c0ce404a4b", "platformspecific": true },
    -    "labsjdk-ee-latestDebug": {"name": "labsjdk",   "version": "ee-23+1-jvmci-b01-20231213123324-6bfc73c47c+c0ce404a4b-debug", "platformspecific": true },
    -    "labsjdk-ee-latest-llvm": {"name": "labsjdk",   "version": "ee-23+1-jvmci-b01-20231213123324-6bfc73c47c+c0ce404a4b-sulong", "platformspecific": true }
    +    "labsjdk-ce-latest":      {"name": "labsjdk",   "version": "ce-23+1-jvmci-b01", "platformspecific": true },
    +    "labsjdk-ce-latestDebug": {"name": "labsjdk",   "version": "ce-23+1-jvmci-b01-debug", "platformspecific": true },
    +    "labsjdk-ce-latest-llvm": {"name": "labsjdk",   "version": "ce-23+1-jvmci-b01-sulong", "platformspecific": true },
    +    "labsjdk-ee-latest":      {"name": "labsjdk",   "version": "ee-23+1-jvmci-b01", "platformspecific": true },
    +    "labsjdk-ee-latestDebug": {"name": "labsjdk",   "version": "ee-23+1-jvmci-b01-debug", "platformspecific": true },
    +    "labsjdk-ee-latest-llvm": {"name": "labsjdk",   "version": "ee-23+1-jvmci-b01-sulong", "platformspecific": true }
       },
     
       "eclipse": {
    
    From 641e918f1e00eb8eb8a92bff2c069788ec58012e Mon Sep 17 00:00:00 2001
    From: Michael Simacek 
    Date: Tue, 19 Dec 2023 08:19:05 +0000
    Subject: [PATCH 264/593] [GR-21590] Update imports
    
    PullRequest: graalpython/3122
    ---
     vm/mx.vm/suite.py | 2 +-
     1 file changed, 1 insertion(+), 1 deletion(-)
    
    diff --git a/vm/mx.vm/suite.py b/vm/mx.vm/suite.py
    index 6ee5e0ce9198..6d3a0cb9e348 100644
    --- a/vm/mx.vm/suite.py
    +++ b/vm/mx.vm/suite.py
    @@ -65,7 +65,7 @@
                 },
                 {
                     "name": "graalpython",
    -                "version": "b997a4beb1392e459502712ffa7cdd8f227dc1b4",
    +                "version": "d80162246f7b03bf2d71647316033df8ed9e1550",
                     "dynamic": True,
                     "urls": [
                         {"url": "https://github.com/graalvm/graalpython.git", "kind": "git"},
    
    From cfdc2074286e7df64a65f15c5a99589e786a3588 Mon Sep 17 00:00:00 2001
    From: Christian Haeubl 
    Date: Fri, 15 Dec 2023 17:55:49 +0100
    Subject: [PATCH 265/593] Execute LogManager shutdown hook after all other
     shutdown hooks.
    
    ---
     .../svm/core/jdk/JavaUtilSubstitutions.java   | 17 +++++--------
     .../core/jdk/Target_java_lang_Shutdown.java   | 24 +++++++++++++------
     vm/mx.vm/mx_vm_benchmark.py                   |  3 +--
     3 files changed, 24 insertions(+), 20 deletions(-)
    
    diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/JavaUtilSubstitutions.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/JavaUtilSubstitutions.java
    index 5feb7f6b421a..1e79daf96c57 100644
    --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/JavaUtilSubstitutions.java
    +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/JavaUtilSubstitutions.java
    @@ -213,7 +213,7 @@ final class Target_java_util_Currency {
     @TargetClass(className = "java.util.logging.LogManager", onlyWith = JavaLoggingModule.IsPresent.class)
     final class Target_java_util_logging_LogManager {
     
    -    @Inject @RecomputeFieldValue(kind = Kind.NewInstance, declClass = AtomicBoolean.class) private AtomicBoolean addedShutdownHook = new AtomicBoolean();
    +    @Inject @RecomputeFieldValue(kind = Kind.NewInstance, declClass = AtomicBoolean.class, isFinal = true) private AtomicBoolean addedShutdownHook = new AtomicBoolean();
     
         @Alias static Target_java_util_logging_LogManager manager;
     
    @@ -222,22 +222,17 @@ final class Target_java_util_logging_LogManager {
     
         @Substitute
         public static Target_java_util_logging_LogManager getLogManager() {
    -        /* First performing logic originally in getLogManager. */
    +        /* Logic from original JDK method. */
             if (manager == null) {
    -            return manager;
    +            return null;
             }
             manager.ensureLogManagerInitialized();
     
    -        /* Logic for adding shutdown hook. */
    +        /* Add a shutdown hook to close the global handlers. */
             if (!manager.addedShutdownHook.getAndSet(true)) {
    -            /* Add a shutdown hook to close the global handlers. */
    -            try {
    -                Runtime.getRuntime().addShutdownHook(SubstrateUtil.cast(new Target_java_util_logging_LogManager_Cleaner(manager), Thread.class));
    -            } catch (IllegalStateException e) {
    -                /* If the VM is already shutting down, we do not need to register shutdownHook. */
    -            }
    +            Runnable hook = SubstrateUtil.cast(new Target_java_util_logging_LogManager_Cleaner(manager), Runnable.class);
    +            Util_java_lang_Shutdown.registerLogManagerShutdownHook(hook);
             }
    -
             return manager;
         }
     }
    diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/Target_java_lang_Shutdown.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/Target_java_lang_Shutdown.java
    index e02f8eea04bb..743a0eced415 100644
    --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/Target_java_lang_Shutdown.java
    +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/Target_java_lang_Shutdown.java
    @@ -29,6 +29,7 @@
     import com.oracle.svm.core.annotate.Substitute;
     import com.oracle.svm.core.annotate.TargetClass;
     import com.oracle.svm.core.annotate.TargetElement;
    +import com.oracle.svm.core.util.VMError;
     
     @TargetClass(className = "java.lang.Shutdown")
     public final class Target_java_lang_Shutdown {
    @@ -41,12 +42,7 @@ public final class Target_java_lang_Shutdown {
     
         static {
             hooks = new Runnable[Util_java_lang_Shutdown.MAX_SYSTEM_HOOKS];
    -        /*
    -         * We use the last system hook slot (index 9), which is currently not used by the JDK, for
    -         * our own shutdown hooks that are registered during image generation. The JDK currently
    -         * uses slots 0, 1, and 2.
    -         */
    -        hooks[hooks.length - 1] = RuntimeSupport::executeShutdownHooks;
    +        hooks[Util_java_lang_Shutdown.NATIVE_IMAGE_SHUTDOWN_HOOKS_SLOT] = RuntimeSupport::executeShutdownHooks;
         }
     
         @Substitute
    @@ -73,7 +69,21 @@ final class Util_java_lang_Shutdown {
     
         /**
          * Value *copied* from {@code java.lang.Shutdown.MAX_SYSTEM_HOOKS} so that the value can be used
    -     * during image generation (@Alias values are only visible at run time).
    +     * during image generation (@Alias values are only visible at run time). The JDK currently uses
    +     * slots 0, 1, and 2.
          */
         static final int MAX_SYSTEM_HOOKS = 10;
    +
    +    static final int LOG_MANAGER_SHUTDOWN_HOOK_SLOT = MAX_SYSTEM_HOOKS - 1;
    +    static final int NATIVE_IMAGE_SHUTDOWN_HOOKS_SLOT = LOG_MANAGER_SHUTDOWN_HOOK_SLOT - 1;
    +
    +    public static void registerLogManagerShutdownHook(Runnable hook) {
    +        /*
    +         * Execute the LogManager shutdown hook after all other shutdown hooks. This is a workaround
    +         * for GR-39429.
    +         */
    +        Runnable[] hooks = Target_java_lang_Shutdown.hooks;
    +        VMError.guarantee(hooks[LOG_MANAGER_SHUTDOWN_HOOK_SLOT] == null, "slot must not be used");
    +        hooks[LOG_MANAGER_SHUTDOWN_HOOK_SLOT] = hook;
    +    }
     }
    diff --git a/vm/mx.vm/mx_vm_benchmark.py b/vm/mx.vm/mx_vm_benchmark.py
    index c3f4d6d4d21e..38ee533e5455 100644
    --- a/vm/mx.vm/mx_vm_benchmark.py
    +++ b/vm/mx.vm/mx_vm_benchmark.py
    @@ -216,8 +216,7 @@ def __init__(self, vm, bm_suite, args):
                     base_image_build_args += ['-R:+FlightRecorder',
                                               '-R:StartFlightRecording=filename=default.jfr',
                                               '--enable-monitoring=jfr',
    -                                          # We should enable this flag, but after we fix GR-39429.
    -                                          # '-R:+JfrBasedExecutionSamplerStatistics'
    +                                          '-R:+JfrBasedExecutionSamplerStatistics'
                                               ]
                     for stage in ('instrument-image', 'instrument-run'):
                         if stage in self.stages:
    
    From fce46ca723ee08be11f0dd1752e98f25a7bc827a Mon Sep 17 00:00:00 2001
    From: Christian Haeubl 
    Date: Tue, 19 Dec 2023 11:35:44 +0100
    Subject: [PATCH 266/593] Remove exception throw.
    
    ---
     .../com/oracle/svm/core/jfr/Target_jdk_jfr_internal_JVM.java | 5 ++---
     1 file changed, 2 insertions(+), 3 deletions(-)
    
    diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jfr/Target_jdk_jfr_internal_JVM.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jfr/Target_jdk_jfr_internal_JVM.java
    index 4f4330b8a4af..f24d53912021 100644
    --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jfr/Target_jdk_jfr_internal_JVM.java
    +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jfr/Target_jdk_jfr_internal_JVM.java
    @@ -27,7 +27,6 @@
     import java.util.List;
     import java.util.function.BooleanSupplier;
     
    -import jdk.jfr.internal.LogLevel;
     import org.graalvm.nativeimage.Platform;
     import org.graalvm.nativeimage.Platforms;
     import org.graalvm.nativeimage.ProcessProperties;
    @@ -46,6 +45,7 @@
     
     import jdk.graal.compiler.api.replacements.Fold;
     import jdk.jfr.internal.JVM;
    +import jdk.jfr.internal.LogLevel;
     import jdk.jfr.internal.LogTag;
     import jdk.jfr.internal.Logger;
     
    @@ -177,9 +177,8 @@ public static void unregisterStackFilter(long stackFilterId) {
         @Substitute
         @TargetElement(onlyWith = JDK22OrLater.class)
         public static void setMiscellaneous(long eventTypeId, long value) {
    -        // Add logging here since JDK code obfuscates root exception message.
             Logger.log(LogTag.JFR_SETTING, LogLevel.WARN, "@Deprecated JFR events, and leak profiling are not yet supported.");
    -        throw VMError.unimplemented("@Deprecated JFR events, and leak profiling are not yet supported.");
    +        /* Explicitly don't throw an exception (would result in an unspecific warning). */
         }
     
         /** See {@link JVM#getThreadId}. */
    
    From 6539d8f6444afef600540f5824a47dfb8dfbdcde Mon Sep 17 00:00:00 2001
    From: Josef Haider 
    Date: Mon, 18 Dec 2023 16:11:08 +0100
    Subject: [PATCH 267/593] Make sure ByteBuffer object is kept alive in
     TStringOpsTest.testWithNative
    
    ---
     .../strings/TStringOpsRegionEqualsConstantStrideTest.java  | 2 +-
     .../compiler/truffle/test/strings/TStringOpsTest.java      | 7 +++++--
     2 files changed, 6 insertions(+), 3 deletions(-)
    
    diff --git a/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/truffle/test/strings/TStringOpsRegionEqualsConstantStrideTest.java b/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/truffle/test/strings/TStringOpsRegionEqualsConstantStrideTest.java
    index c4f3fefafbfe..301fc38ab817 100644
    --- a/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/truffle/test/strings/TStringOpsRegionEqualsConstantStrideTest.java
    +++ b/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/truffle/test/strings/TStringOpsRegionEqualsConstantStrideTest.java
    @@ -51,7 +51,7 @@ public TStringOpsRegionEqualsConstantStrideTest(
             super(arrayA, offsetA, lengthA, strideA, fromIndexA, arrayB, offsetB, lengthB, strideB, fromIndexB, lengthCMP);
         }
     
    -    @Parameters(name = "{index}: offset: {1}, {6}, stride: {3}, {8}, length: {12}")
    +    @Parameters(name = "{index}: offset: {1}, {6}, stride: {3}, {8}, length: {10}")
         public static List data() {
             return TStringOpsRegionEqualsTest.data();
         }
    diff --git a/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/truffle/test/strings/TStringOpsTest.java b/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/truffle/test/strings/TStringOpsTest.java
    index 7bbbc3e72c8a..2316451d0c0c 100644
    --- a/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/truffle/test/strings/TStringOpsTest.java
    +++ b/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/truffle/test/strings/TStringOpsTest.java
    @@ -24,6 +24,7 @@
      */
     package jdk.graal.compiler.truffle.test.strings;
     
    +import java.lang.ref.Reference;
     import java.lang.reflect.Constructor;
     import java.lang.reflect.Field;
     import java.lang.reflect.InvocationTargetException;
    @@ -92,8 +93,8 @@ protected void testWithNative(ResolvedJavaMethod method, Object receiver, Object
     
         protected void testWithNativeExcept(ResolvedJavaMethod method, Object receiver, long ignore, Object... args) {
             test(method, receiver, args);
    +        Object[] argsWithNative = Arrays.copyOf(args, args.length);
             try {
    -            Object[] argsWithNative = Arrays.copyOf(args, args.length);
                 ResolvedJavaMethod.Parameter[] parameters = method.getParameters();
                 Assert.assertTrue(parameters.length <= 64);
                 for (int i = 0; i < parameters.length; i++) {
    @@ -103,12 +104,14 @@ protected void testWithNativeExcept(ResolvedJavaMethod method, Object receiver,
                         ByteBuffer buffer = ByteBuffer.allocateDirect(array.length);
                         long bufferAddress = getBufferAddress(buffer);
                         UNSAFE.copyMemory(array, Unsafe.ARRAY_BYTE_BASE_OFFSET, null, bufferAddress, array.length);
    -                    argsWithNative[i] = T_STRING_NATIVE_POINTER_CONSTRUCTOR.newInstance(null, bufferAddress);
    +                    argsWithNative[i] = T_STRING_NATIVE_POINTER_CONSTRUCTOR.newInstance(buffer, bufferAddress);
                     }
                 }
                 test(method, receiver, argsWithNative);
             } catch (InstantiationException | IllegalAccessException | InvocationTargetException e) {
                 throw new RuntimeException(e);
    +        } finally {
    +            Reference.reachabilityFence(argsWithNative);
             }
         }
     
    
    From 68aa1b509dcc2cd9fa1d6551534a2f50f36731c7 Mon Sep 17 00:00:00 2001
    From: Foivos Zakkak 
    Date: Mon, 11 Dec 2023 17:32:56 +0200
    Subject: [PATCH 268/593] Use JDK 17 for building Quarkus and switch to Temurin
     builds
    
    Quarkus no longer supports JDK 11. Furthermore, no actual tests are
    being run with GraalVM in JVM-mode so using it instead of Temurin builds
    doesn't seem to have any benefits.
    ---
     .github/workflows/quarkus.yml | 10 +++++++---
     1 file changed, 7 insertions(+), 3 deletions(-)
    
    diff --git a/.github/workflows/quarkus.yml b/.github/workflows/quarkus.yml
    index 0b608f95ea99..aa249a96fb37 100644
    --- a/.github/workflows/quarkus.yml
    +++ b/.github/workflows/quarkus.yml
    @@ -128,6 +128,11 @@ jobs:
           with:
             name: graalvm
             path: graalvm.tgz
    +    # Use Java 17 to build Quarkus as that's the lowest supported JDK version currently
    +    - uses: actions/setup-java@v4
    +      with:
    +        distribution: 'temurin'
    +        java-version: '17'
         - name: Build Quarkus
           run: |
             cd ${QUARKUS_PATH}
    @@ -189,11 +194,10 @@ jobs:
             if: startsWith(matrix.os-name, 'ubuntu')
             shell: bash
             run: tar -xzf maven-repo.tgz -C ~
    -      - uses: graalvm/setup-graalvm@v1
    +      - uses: actions/setup-java@v4
             with:
    -          version: 'latest'
    +          distribution: 'temurin'
               java-version: '17'
    -          github-token: ${{ secrets.GITHUB_TOKEN }}
           - name: Build with Maven
             if: startsWith(matrix.os-name, 'ubuntu')
             env:
    
    From bf5140612cbba0f76c3e038954f440f15ecf8cb4 Mon Sep 17 00:00:00 2001
    From: Josef Haider 
    Date: Tue, 19 Dec 2023 11:25:07 +0100
    Subject: [PATCH 269/593] TRegex: move gate to jdk-latest
    
    ---
     regex/ci/ci.jsonnet | 25 +++++++------------------
     1 file changed, 7 insertions(+), 18 deletions(-)
    
    diff --git a/regex/ci/ci.jsonnet b/regex/ci/ci.jsonnet
    index 2a57a0586039..084455f3d67a 100644
    --- a/regex/ci/ci.jsonnet
    +++ b/regex/ci/ci.jsonnet
    @@ -8,23 +8,14 @@
         timelimit: "30:00",
       },
     
    -  local regex_gate = regex_common + common.deps.eclipse + common.deps.jdt + {
    -    name: 'gate-regex-jdk' + self.jdk_version,
    +  local regex_gate = regex_common + common.deps.eclipse + common.deps.jdt + common.deps.spotbugs + {
    +    name: 'gate-regex-' + self.jdk_name,
         run: [["mx", "--strict-compliance", "gate", "--strict-mode"]],
         targets: ["gate"],
       },
     
    -  local regex_gate_jdkLatest = regex_common + common.deps.eclipse + common.deps.jdt + {
    -    name: 'gate-regex-jdk' + self.jdk_version,
    -    run: [
    -      ["mx", "build"],
    -      ["mx", "unittest", "com.oracle.truffle.regex"],
    -    ],
    -    targets: ["gate"],
    -  },
    -
       local regex_gate_lite = regex_common + {
    -    name: 'gate-regex-mac-lite-jdk' + self.jdk_version,
    +    name: 'gate-regex-mac-lite-' + self.jdk_name,
         run: [
           ["mx", "build"],
           ["mx", "unittest", "--verbose", "com.oracle.truffle.regex"],
    @@ -34,7 +25,7 @@
       },
     
       local regex_downstream_js = regex_common + {
    -    name: 'gate-regex-downstream-js-jdk' + self.jdk_version,
    +    name: 'gate-regex-downstream-js-' + self.jdk_name,
         run: [
           # checkout graal-js and js-tests suites at the imported (downstream-branch) revisions.
           ["mx", "-p", "../vm", "--dynamicimports", "/graal-js", "sforceimports"],
    @@ -51,11 +42,9 @@
         [
           common.linux_amd64  + jdk + regex_gate,
           common.linux_amd64  + jdk + regex_downstream_js,
    -      common.darwin_amd64 + jdk + regex_gate_lite,
    +      common.darwin_aarch64 + jdk + regex_gate_lite,
         ] for jdk in [
    -      common.labsjdk21,
    +      common.labsjdkLatest,
         ]
    -  ]) + [
    -      common.linux_amd64  + common.labsjdkLatest + regex_gate_jdkLatest,
    -  ],
    +  ]),
     }
    
    From 3416eabd860682d27a854c88887d48e442b5b958 Mon Sep 17 00:00:00 2001
    From: Josef Haider 
    Date: Tue, 19 Dec 2023 14:30:37 +0100
    Subject: [PATCH 270/593] TRegex: add gate predicates
    
    ---
     regex/ci/ci.jsonnet | 5 +++--
     1 file changed, 3 insertions(+), 2 deletions(-)
    
    diff --git a/regex/ci/ci.jsonnet b/regex/ci/ci.jsonnet
    index 084455f3d67a..add9da89d95d 100644
    --- a/regex/ci/ci.jsonnet
    +++ b/regex/ci/ci.jsonnet
    @@ -1,4 +1,5 @@
     {
    +  local utils = (import '../../ci/ci_common/common-utils.libsonnet'),
       local common = import '../../ci/ci_common/common.jsonnet',
     
       local regex_common = {
    @@ -38,7 +39,7 @@
         targets: ["gate"],
       },
     
    -  builds: std.flattenArrays([
    +  builds: [utils.add_gate_predicate(b, ["sdk", "truffle", "regex", "compiler", "vm", "substratevm"]) for b in std.flattenArrays([
         [
           common.linux_amd64  + jdk + regex_gate,
           common.linux_amd64  + jdk + regex_downstream_js,
    @@ -46,5 +47,5 @@
         ] for jdk in [
           common.labsjdkLatest,
         ]
    -  ]),
    +  ])],
     }
    
    From abd12d8a1301d7dd6334b8c01c1918d8f5cbd6c6 Mon Sep 17 00:00:00 2001
    From: Jirka Marsik 
    Date: Thu, 23 Nov 2023 23:02:25 +0100
    Subject: [PATCH 271/593] Initial support for a few vector ops
    
    ---
     .../src/org/graalvm/wasm/BinaryParser.java    | 34 ++++++++
     .../org/graalvm/wasm/BinaryStreamParser.java  | 16 ++++
     .../src/org/graalvm/wasm/WasmType.java        | 14 +++-
     .../src/org/graalvm/wasm/api/ValueType.java   |  7 ++
     .../src/org/graalvm/wasm/api/Vector128.java   | 79 +++++++++++++++++++
     .../org/graalvm/wasm/constants/Bytecode.java  |  7 +-
     .../graalvm/wasm/constants/Instructions.java  |  7 ++
     .../src/org/graalvm/wasm/nodes/WasmFrame.java | 14 ++++
     .../graalvm/wasm/nodes/WasmFunctionNode.java  | 50 ++++++++++++
     .../wasm/parser/bytecode/BytecodeGen.java     | 13 +++
     .../wasm/parser/bytecode/BytecodeParser.java  | 14 ++++
     .../parser/bytecode/RuntimeBytecodeGen.java   | 14 ++++
     .../wasm/parser/validation/ParserState.java   | 18 +++++
     .../parser/validation/ValidationErrors.java   |  2 +
     14 files changed, 286 insertions(+), 3 deletions(-)
     create mode 100644 wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/api/Vector128.java
    
    diff --git a/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/BinaryParser.java b/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/BinaryParser.java
    index 0345ac25d02c..72a618167adc 100644
    --- a/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/BinaryParser.java
    +++ b/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/BinaryParser.java
    @@ -55,6 +55,7 @@
     import static org.graalvm.wasm.WasmType.I32_TYPE;
     import static org.graalvm.wasm.WasmType.I64_TYPE;
     import static org.graalvm.wasm.WasmType.NULL_TYPE;
    +import static org.graalvm.wasm.WasmType.V128_TYPE;
     import static org.graalvm.wasm.WasmType.VOID_TYPE;
     import static org.graalvm.wasm.constants.Sizes.MAX_MEMORY_64_DECLARATION_SIZE;
     import static org.graalvm.wasm.constants.Sizes.MAX_MEMORY_DECLARATION_SIZE;
    @@ -71,6 +72,7 @@
     import com.oracle.truffle.api.CompilerDirectives;
     import org.graalvm.collections.EconomicMap;
     import org.graalvm.collections.Pair;
    +import org.graalvm.wasm.api.Vector128;
     import org.graalvm.wasm.collection.ByteArrayList;
     import org.graalvm.wasm.collection.LongArrayList;
     import org.graalvm.wasm.constants.Bytecode;
    @@ -1796,6 +1798,30 @@ private void readNumericInstructions(ParserState state, int opcode) {
                             fail(Failure.UNSPECIFIED_MALFORMED, "Unknown opcode: 0xFE 0x%02x", atomicOpcode);
                     }
                     break;
    +            case Instructions.VECTOR:
    +                int vectorOpcode = read1() & 0xFF;
    +                state.addVectorFlag();
    +                switch (vectorOpcode) {
    +                    case Instructions.VECTOR_V128_CONST:
    +                        final Vector128 value = readUnsignedInt128();
    +                        state.push(V128_TYPE);
    +                        state.addInstruction(Bytecode.VECTOR_V128_CONST_I128, value);
    +                        break;
    +                    case Instructions.VECTOR_I32X4_ALL_TRUE:
    +                        state.popChecked(V128_TYPE);
    +                        state.push(I32_TYPE);
    +                        state.addInstruction(Bytecode.VECTOR_I32X4_ALL_TRUE);
    +                        break;
    +                    case Instructions.VECTOR_I32X4_ADD:
    +                        state.popChecked(V128_TYPE);
    +                        state.popChecked(V128_TYPE);
    +                        state.push(V128_TYPE);
    +                        state.addInstruction(Bytecode.VECTOR_I32X4_ADD);
    +                        break;
    +                    default:
    +                        fail(Failure.UNSPECIFIED_MALFORMED, "Unknown opcode: 0xFD 0x%02x", vectorOpcode);
    +                }
    +                break;
                 default:
                     fail(Failure.UNSPECIFIED_MALFORMED, "Unknown opcode: 0x%02x", opcode);
                     break;
    @@ -2733,6 +2759,14 @@ private long readSignedInt64() {
             return value;
         }
     
    +    private Vector128 readUnsignedInt128() {
    +        byte[] bytes = new byte[16];
    +        for (int i = 0; i < 16; i++) {
    +            bytes[i] = read1();
    +        }
    +        return new Vector128(bytes);
    +    }
    +
         /**
          * Creates a runtime bytecode of a function with added debug opcodes.
          *
    diff --git a/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/BinaryStreamParser.java b/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/BinaryStreamParser.java
    index 96cfdfe45383..0cc45e0f50c2 100644
    --- a/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/BinaryStreamParser.java
    +++ b/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/BinaryStreamParser.java
    @@ -42,6 +42,7 @@
     
     import static com.oracle.truffle.api.nodes.ExplodeLoop.LoopExplosionKind.FULL_EXPLODE_UNTIL_RETURN;
     
    +import org.graalvm.wasm.api.Vector128;
     import org.graalvm.wasm.constants.GlobalModifier;
     import org.graalvm.wasm.exception.Failure;
     import org.graalvm.wasm.exception.WasmException;
    @@ -49,6 +50,8 @@
     import com.oracle.truffle.api.CompilerDirectives.CompilationFinal;
     import com.oracle.truffle.api.nodes.ExplodeLoop;
     
    +import java.util.Arrays;
    +
     public abstract class BinaryStreamParser {
         protected static final int SINGLE_RESULT_VALUE = 0;
         protected static final int MULTI_RESULT_VALUE = 1;
    @@ -308,6 +311,7 @@ protected static byte peekValueType(byte[] data, int offset, boolean allowRefTyp
                 case WasmType.I64_TYPE:
                 case WasmType.F32_TYPE:
                 case WasmType.F64_TYPE:
    +            case WasmType.V128_TYPE:
                     break;
                 case WasmType.FUNCREF_TYPE:
                 case WasmType.EXTERNREF_TYPE:
    @@ -451,5 +455,17 @@ public static void writeI64(byte[] bytecode, int offset, long value) {
             bytecode[offset + 7] = (byte) ((value >> 56) & 0xFF);
         }
     
    +    /**
    +     * Reads the {@link Vector128} value at the given bytecode offset.
    +     *
    +     * @param bytecode The bytecode
    +     * @param offset The offset in the bytecode.
    +     * @return The {@link Vector128} value at the given bytecode offset.
    +     */
    +    public static Vector128 rawPeekI128(byte[] bytecode, int offset) {
    +        byte[] bytes = Arrays.copyOfRange(bytecode, offset, offset + 16);
    +        return new Vector128(bytes);
    +    }
    +
         // endregion
     }
    diff --git a/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/WasmType.java b/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/WasmType.java
    index 6bc7acae5cab..0eb0c8844d08 100644
    --- a/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/WasmType.java
    +++ b/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/WasmType.java
    @@ -76,6 +76,9 @@ public class WasmType implements TruffleObject {
         public static final byte F64_TYPE = 0x7C;
         @CompilationFinal(dimensions = 1) public static final byte[] F64_TYPE_ARRAY = {F64_TYPE};
     
    +    public static final byte V128_TYPE = 0x7B;
    +    @CompilationFinal(dimensions = 1) public static final byte[] V128_TYPE_ARRAY = {V128_TYPE};
    +
         /**
          * Reference Types.
          */
    @@ -93,8 +96,9 @@ public class WasmType implements TruffleObject {
          */
         public static final int NONE_COMMON_TYPE = 0;
         public static final int NUM_COMMON_TYPE = 1;
    -    public static final int REF_COMMON_TYPE = 2;
    -    public static final int MIX_COMMON_TYPE = NUM_COMMON_TYPE | REF_COMMON_TYPE;
    +    public static final int VEC_COMMON_TYPE = 2;
    +    public static final int REF_COMMON_TYPE = 3;
    +    public static final int MIX_COMMON_TYPE = NUM_COMMON_TYPE | VEC_COMMON_TYPE | REF_COMMON_TYPE;
     
         public static String toString(int valueType) {
             CompilerAsserts.neverPartOfCompilation();
    @@ -107,6 +111,8 @@ public static String toString(int valueType) {
                     return "f32";
                 case F64_TYPE:
                     return "f64";
    +            case V128_TYPE:
    +                return "v128";
                 case VOID_TYPE:
                     return "void";
                 case FUNCREF_TYPE:
    @@ -122,6 +128,10 @@ public static boolean isNumberType(byte type) {
             return type == I32_TYPE || type == I64_TYPE || type == F32_TYPE || type == F64_TYPE || type == UNKNOWN_TYPE;
         }
     
    +    public static boolean isVectorType(byte type) {
    +        return type == V128_TYPE || type == UNKNOWN_TYPE;
    +    }
    +
         public static boolean isReferenceType(byte type) {
             return type == FUNCREF_TYPE || type == EXTERNREF_TYPE || type == UNKNOWN_TYPE;
         }
    diff --git a/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/api/ValueType.java b/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/api/ValueType.java
    index 6784998dab8c..a498188d96bb 100644
    --- a/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/api/ValueType.java
    +++ b/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/api/ValueType.java
    @@ -51,6 +51,7 @@ public enum ValueType {
         i64(WasmType.I64_TYPE),
         f32(WasmType.F32_TYPE),
         f64(WasmType.F64_TYPE),
    +    v128(WasmType.V128_TYPE),
         anyfunc(WasmType.FUNCREF_TYPE),
         externref(WasmType.EXTERNREF_TYPE);
     
    @@ -71,6 +72,8 @@ public static ValueType fromByteValue(byte value) {
                     return f32;
                 case WasmType.F64_TYPE:
                     return f64;
    +            case WasmType.V128_TYPE:
    +                return v128;
                 case WasmType.FUNCREF_TYPE:
                     return anyfunc;
                 case WasmType.EXTERNREF_TYPE:
    @@ -88,6 +91,10 @@ public static boolean isNumberType(ValueType valueType) {
             return valueType == i32 || valueType == i64 || valueType == f32 || valueType == f64;
         }
     
    +    public static boolean isVectorType(ValueType valueType) {
    +        return valueType == v128;
    +    }
    +
         public static boolean isReferenceType(ValueType valueType) {
             return valueType == anyfunc || valueType == externref;
         }
    diff --git a/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/api/Vector128.java b/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/api/Vector128.java
    new file mode 100644
    index 000000000000..54ca070c7b6c
    --- /dev/null
    +++ b/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/api/Vector128.java
    @@ -0,0 +1,79 @@
    +/*
    + * Copyright (c) 2023, 2023, Oracle and/or its affiliates. All rights reserved.
    + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
    + *
    + * The Universal Permissive License (UPL), Version 1.0
    + *
    + * Subject to the condition set forth below, permission is hereby granted to any
    + * person obtaining a copy of this software, associated documentation and/or
    + * data (collectively the "Software"), free of charge and under any and all
    + * copyright rights in the Software, and any and all patent rights owned or
    + * freely licensable by each licensor hereunder covering either (i) the
    + * unmodified Software as contributed to or provided by such licensor, or (ii)
    + * the Larger Works (as defined below), to deal in both
    + *
    + * (a) the Software, and
    + *
    + * (b) any piece of software and/or hardware listed in the lrgrwrks.txt file if
    + * one is included with the Software each a "Larger Work" to which the Software
    + * is contributed by such licensors),
    + *
    + * without restriction, including without limitation the rights to copy, create
    + * derivative works of, display, perform, and distribute the Software and make,
    + * use, sell, offer for sale, import, export, have made, and have sold the
    + * Software and the Larger Work(s), and to sublicense the foregoing rights on
    + * either these or other terms.
    + *
    + * This license is subject to the following condition:
    + *
    + * The above copyright notice and either this complete permission notice or at a
    + * minimum a reference to the UPL must be included in all copies or substantial
    + * portions of the Software.
    + *
    + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
    + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
    + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
    + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
    + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
    + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
    + * SOFTWARE.
    + */
    +
    +package org.graalvm.wasm.api;
    +
    +public class Vector128 {
    +
    +    public static final Vector128 ZERO = new Vector128(new byte[16]);
    +
    +    private final byte[] bytes;
    +
    +    public Vector128(byte[] bytes) {
    +        assert bytes.length == 16;
    +        this.bytes = bytes;
    +    }
    +
    +    public byte[] asBytes() {
    +        return bytes;
    +    }
    +
    +    public static Vector128 ofBytes(byte[] bytes) {
    +        return new Vector128(bytes);
    +    }
    +
    +    public int[] asInts() {
    +        int[] ints = new int[4];
    +        for (int i = 0; i < 4; i++) {
    +            ints[i] = (bytes[4 * i + 3] & 0xFF) << 24 | (bytes[4 * i + 2] & 0xFF) << 16 | (bytes[4 * i + 1] & 0xFF) << 8 | bytes[4 * i] & 0xFF;
    +        }
    +        return ints;
    +    }
    +
    +    public static Vector128 ofInts(int[] ints) {
    +        assert ints.length == 4;
    +        byte[] bytes = new byte[16];
    +        for (int i = 0; i < 16; i++) {
    +            bytes[i] = (byte) ((ints[i / 4] >> 8 * (i % 4)) & 0xFF);
    +        }
    +        return new Vector128(bytes);
    +    }
    +}
    diff --git a/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/constants/Bytecode.java b/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/constants/Bytecode.java
    index e6666e9ad1b6..bc723f387a44 100644
    --- a/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/constants/Bytecode.java
    +++ b/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/constants/Bytecode.java
    @@ -336,7 +336,7 @@ public class Bytecode {
         public static final int MISC = 0xFB;
     
         public static final int ATOMIC = 0xFC;
    -
    +    public static final int VECTOR = 0xFD;
         public static final int NOTIFY = 0xFE;
     
         // Misc opcodes
    @@ -443,6 +443,11 @@ public class Bytecode {
         public static final int ATOMIC_WAIT32 = 0x41;
         public static final int ATOMIC_WAIT64 = 0x42;
     
    +    // Vector opcodes
    +    public static final int VECTOR_V128_CONST_I128 = 0x0C;
    +    public static final int VECTOR_I32X4_ALL_TRUE = 0xA3;
    +    public static final int VECTOR_I32X4_ADD = 0xAE;
    +
         public static final byte[] EMPTY_BYTES = {};
         public static final int COMMON_BYTECODE_OFFSET = Bytecode.I32_EQ - Instructions.I32_EQ;
     }
    diff --git a/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/constants/Instructions.java b/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/constants/Instructions.java
    index fc7440446e7f..59f7865cc9a9 100644
    --- a/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/constants/Instructions.java
    +++ b/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/constants/Instructions.java
    @@ -344,6 +344,13 @@ public final class Instructions {
         public static final int ATOMIC_I64_RMW8_U_CMPXCHG = 0x4C;
         public static final int ATOMIC_I64_RMW16_U_CMPXCHG = 0x4D;
         public static final int ATOMIC_I64_RMW32_U_CMPXCHG = 0x4E;
    +
    +    public static final int VECTOR = 0xFD;
    +
    +    public static final int VECTOR_V128_CONST = 0x0C;
    +    public static final int VECTOR_I32X4_ALL_TRUE = 0xA3;
    +    public static final int VECTOR_I32X4_ADD = 0xAE;
    +
         // GraalWasm specific opcodes (these are reserved for future webassembly extensions and might be
         // used in other ways in the future)
     
    diff --git a/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/nodes/WasmFrame.java b/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/nodes/WasmFrame.java
    index 2e0f21613ead..6b8e71be486c 100644
    --- a/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/nodes/WasmFrame.java
    +++ b/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/nodes/WasmFrame.java
    @@ -42,6 +42,7 @@
     
     import com.oracle.truffle.api.CompilerDirectives;
     import com.oracle.truffle.api.frame.VirtualFrame;
    +import org.graalvm.wasm.api.Vector128;
     
     public abstract class WasmFrame {
     
    @@ -137,6 +138,19 @@ public static void pushDouble(VirtualFrame frame, int slot, double value) {
             frame.setDoubleStatic(slot, value);
         }
     
    +    public static Vector128 popVector128(VirtualFrame frame, int slot) {
    +        Vector128 result = (Vector128) frame.getObjectStatic(slot);
    +        frame.clearObjectStatic(slot);
    +        if (result == null) {
    +            return Vector128.ZERO;
    +        }
    +        return result;
    +    }
    +
    +    public static void pushVector128(VirtualFrame frame, int slot, Vector128 value) {
    +        frame.setObjectStatic(slot, value);
    +    }
    +
         public static Object popReference(VirtualFrame frame, int slot) {
             Object result = frame.getObjectStatic(slot);
             frame.clearObjectStatic(slot);
    diff --git a/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/nodes/WasmFunctionNode.java b/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/nodes/WasmFunctionNode.java
    index 777fdfe09e85..3c7c8e98ad59 100644
    --- a/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/nodes/WasmFunctionNode.java
    +++ b/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/nodes/WasmFunctionNode.java
    @@ -40,6 +40,7 @@
      */
     package org.graalvm.wasm.nodes;
     
    +import static org.graalvm.wasm.BinaryStreamParser.rawPeekI128;
     import static org.graalvm.wasm.BinaryStreamParser.rawPeekI32;
     import static org.graalvm.wasm.BinaryStreamParser.rawPeekI64;
     import static org.graalvm.wasm.BinaryStreamParser.rawPeekI8;
    @@ -55,11 +56,13 @@
     import static org.graalvm.wasm.nodes.WasmFrame.popInt;
     import static org.graalvm.wasm.nodes.WasmFrame.popLong;
     import static org.graalvm.wasm.nodes.WasmFrame.popReference;
    +import static org.graalvm.wasm.nodes.WasmFrame.popVector128;
     import static org.graalvm.wasm.nodes.WasmFrame.pushDouble;
     import static org.graalvm.wasm.nodes.WasmFrame.pushFloat;
     import static org.graalvm.wasm.nodes.WasmFrame.pushInt;
     import static org.graalvm.wasm.nodes.WasmFrame.pushLong;
     import static org.graalvm.wasm.nodes.WasmFrame.pushReference;
    +import static org.graalvm.wasm.nodes.WasmFrame.pushVector128;
     
     import org.graalvm.wasm.BinaryStreamParser;
     import org.graalvm.wasm.SymbolTable;
    @@ -75,6 +78,7 @@
     import org.graalvm.wasm.WasmModule;
     import org.graalvm.wasm.WasmTable;
     import org.graalvm.wasm.WasmType;
    +import org.graalvm.wasm.api.Vector128;
     import org.graalvm.wasm.constants.Bytecode;
     import org.graalvm.wasm.constants.BytecodeBitEncoding;
     import org.graalvm.wasm.exception.Failure;
    @@ -1715,6 +1719,30 @@ public Object executeBodyFromOffset(WasmContext context, WasmInstance instance,
                         stackPointer -= stackPointerDecrement;
                         break;
                     }
    +                case Bytecode.VECTOR: {
    +                    final int vectorOpcode = rawPeekU8(bytecode, offset);
    +                    offset++;
    +                    CompilerAsserts.partialEvaluationConstant(vectorOpcode);
    +                    switch (vectorOpcode) {
    +                        case Bytecode.VECTOR_V128_CONST_I128:
    +                            final Vector128 value = rawPeekI128(bytecode, offset);
    +                            offset += 16;
    +
    +                            pushVector128(frame, stackPointer, value);
    +                            stackPointer++;
    +                            break;
    +                        case Bytecode.VECTOR_I32X4_ALL_TRUE:
    +                            i32x4_all_true(frame, stackPointer);
    +                            break;
    +                        case Bytecode.VECTOR_I32X4_ADD:
    +                            i32x4_add(frame, stackPointer);
    +                            stackPointer--;
    +                            break;
    +                        default:
    +                            throw CompilerDirectives.shouldNotReachHere();
    +                    }
    +                    break;
    +                }
                     case Bytecode.NOTIFY: {
                         final int nextLine = rawPeekI32(bytecode, offset);
                         final int sourceCodeLocation = rawPeekI32(bytecode, offset + 4);
    @@ -3807,6 +3835,28 @@ private void memory_copy(WasmInstance instance, long length, long source, long d
             destMemory.copyFrom(srcMemory, source, destination, length);
         }
     
    +    private static void i32x4_all_true(VirtualFrame frame, int stackPointer) {
    +        int[] x = popVector128(frame, stackPointer - 1).asInts();
    +        int result = 1;
    +        for (int i = 0; i < 4; i++) {
    +            if (x[i] == 0) {
    +                result = 0;
    +                break;
    +            }
    +        }
    +        pushInt(frame, stackPointer - 1, result);
    +    }
    +
    +    private static void i32x4_add(VirtualFrame frame, int stackPointer) {
    +        int[] x = popVector128(frame, stackPointer - 1).asInts();
    +        int[] y = popVector128(frame, stackPointer - 2).asInts();
    +        int[] result = new int[4];
    +        for (int i = 0; i < 4; i++) {
    +            result[i] = y[i] + x[i];
    +        }
    +        pushVector128(frame, stackPointer - 2, Vector128.ofInts(result));
    +    }
    +
         // Checkstyle: resume method name check
     
         private static boolean checkOutOfBounds(long offset, long length, long size) {
    diff --git a/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/parser/bytecode/BytecodeGen.java b/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/parser/bytecode/BytecodeGen.java
    index 2b3abc2d3a56..d7ad6554b5c2 100644
    --- a/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/parser/bytecode/BytecodeGen.java
    +++ b/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/parser/bytecode/BytecodeGen.java
    @@ -41,6 +41,7 @@
     
     package org.graalvm.wasm.parser.bytecode;
     
    +import org.graalvm.wasm.api.Vector128;
     import org.graalvm.wasm.collection.ByteArrayList;
     
     /**
    @@ -174,6 +175,18 @@ protected void add8(long value) {
             data.add((byte) ((value >>> 56) & 0x0000_00FF));
         }
     
    +    /**
    +     * Adds a {@link Vector128} value as sixteen bytes in little endian to the bytecode.
    +     *
    +     * @param value the {@link Vector128} value
    +     */
    +    protected void add16(Vector128 value) {
    +        byte[] bytes = value.asBytes();
    +        for (int i = 0; i < 16; i++) {
    +            data.add(bytes[i]);
    +        }
    +    }
    +
         /**
          * Sets a byte at the given location.
          * 
    diff --git a/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/parser/bytecode/BytecodeParser.java b/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/parser/bytecode/BytecodeParser.java
    index 6eba8dbdf4d2..a873f68762ec 100644
    --- a/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/parser/bytecode/BytecodeParser.java
    +++ b/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/parser/bytecode/BytecodeParser.java
    @@ -895,6 +895,20 @@ private static List readCallNodes(byte[] bytecode, int startOffset, in
                                 throw CompilerDirectives.shouldNotReachHere();
                         }
                         break;
    +                case Bytecode.VECTOR:
    +                    final int vectorOpcode = rawPeekU8(bytecode, offset);
    +                    offset++;
    +                    switch (vectorOpcode) {
    +                        case Bytecode.VECTOR_V128_CONST_I128:
    +                            offset += 16;
    +                            break;
    +                        case Bytecode.VECTOR_I32X4_ALL_TRUE:
    +                        case Bytecode.VECTOR_I32X4_ADD:
    +                            break;
    +                        default:
    +                            throw CompilerDirectives.shouldNotReachHere();
    +                    }
    +                    break;
                     default:
                         throw CompilerDirectives.shouldNotReachHere();
                 }
    diff --git a/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/parser/bytecode/RuntimeBytecodeGen.java b/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/parser/bytecode/RuntimeBytecodeGen.java
    index 46694adbc09e..7be5afd545f5 100644
    --- a/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/parser/bytecode/RuntimeBytecodeGen.java
    +++ b/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/parser/bytecode/RuntimeBytecodeGen.java
    @@ -44,6 +44,7 @@
     import com.oracle.truffle.api.CompilerDirectives;
     import org.graalvm.wasm.WasmType;
     
    +import org.graalvm.wasm.api.Vector128;
     import org.graalvm.wasm.constants.Bytecode;
     import org.graalvm.wasm.constants.BytecodeBitEncoding;
     import org.graalvm.wasm.constants.SegmentMode;
    @@ -126,6 +127,19 @@ public void add(int opcode, long value) {
             add8(value);
         }
     
    +    /**
    +     * Adds an opcode and an i128 immediate value to the bytecode. See {@link Bytecode} for a list
    +     * of opcodes.
    +     *
    +     * @param opcode The opcode
    +     * @param value The immediate value
    +     */
    +    public void add(int opcode, Vector128 value) {
    +        assert fitsIntoUnsignedByte(opcode) : "opcode does not fit into byte";
    +        add1(opcode);
    +        add16(value);
    +    }
    +
         /**
          * Adds an opcode and two i32 immediate values to the bytecode. See {@link Bytecode} for a list
          * of opcodes.
    diff --git a/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/parser/validation/ParserState.java b/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/parser/validation/ParserState.java
    index 5bab89eb410a..858659c1df9c 100644
    --- a/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/parser/validation/ParserState.java
    +++ b/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/parser/validation/ParserState.java
    @@ -45,6 +45,7 @@
     
     import org.graalvm.wasm.Assert;
     import org.graalvm.wasm.WasmType;
    +import org.graalvm.wasm.api.Vector128;
     import org.graalvm.wasm.collection.ByteArrayList;
     import org.graalvm.wasm.constants.Bytecode;
     import org.graalvm.wasm.exception.Failure;
    @@ -415,6 +416,13 @@ public void addAtomicFlag() {
             bytecode.add(Bytecode.ATOMIC);
         }
     
    +    /**
    +     * Adds the vector flag to the bytecode.
    +     */
    +    public void addVectorFlag() {
    +        bytecode.add(Bytecode.VECTOR);
    +    }
    +
         /**
          * Adds the given instruction and an i32 immediate value to the bytecode.
          * 
    @@ -435,6 +443,16 @@ public void addInstruction(int instruction, long value) {
             bytecode.add(instruction, value);
         }
     
    +    /**
    +     * Adds the given instruction and an i128 immediate value to the bytecode.
    +     *
    +     * @param instruction The instruction
    +     * @param value The immediate value
    +     */
    +    public void addInstruction(int instruction, Vector128 value) {
    +        bytecode.add(instruction, value);
    +    }
    +
         /**
          * Adds the given instruction and two i32 immediate values to the bytecode.
          * 
    diff --git a/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/parser/validation/ValidationErrors.java b/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/parser/validation/ValidationErrors.java
    index 7cfd64ecb34a..7088d502788f 100644
    --- a/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/parser/validation/ValidationErrors.java
    +++ b/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/parser/validation/ValidationErrors.java
    @@ -61,6 +61,8 @@ private static String getValueTypeString(byte valueType) {
                     return "f32";
                 case WasmType.F64_TYPE:
                     return "f64";
    +            case WasmType.V128_TYPE:
    +                return "v128";
                 case WasmType.FUNCREF_TYPE:
                     return "funcref";
                 case WasmType.EXTERNREF_TYPE:
    
    From 3d51860818bd79b5f5e23dcdf2b5619013f9d5e1 Mon Sep 17 00:00:00 2001
    From: Jirka Marsik 
    Date: Thu, 23 Nov 2023 23:02:48 +0100
    Subject: [PATCH 272/593] Simple benchmark trying to suss out vector
     instructions
    
    ---
     .../benchcases/bench/WatBenchmarkSuite.java   |  4 ++
     .../src/bench/wat/vector.opts                 |  5 ++
     .../src/bench/wat/vector.result               |  1 +
     .../src/bench/wat/vector.wat                  | 68 +++++++++++++++++++
     4 files changed, 78 insertions(+)
     create mode 100644 wasm/src/org.graalvm.wasm.benchcases/src/bench/wat/vector.opts
     create mode 100644 wasm/src/org.graalvm.wasm.benchcases/src/bench/wat/vector.result
     create mode 100644 wasm/src/org.graalvm.wasm.benchcases/src/bench/wat/vector.wat
    
    diff --git a/wasm/src/org.graalvm.wasm.benchcases.bench/src/org/graalvm/wasm/benchcases/bench/WatBenchmarkSuite.java b/wasm/src/org.graalvm.wasm.benchcases.bench/src/org/graalvm/wasm/benchcases/bench/WatBenchmarkSuite.java
    index af80925a866b..b15e54b0be72 100644
    --- a/wasm/src/org.graalvm.wasm.benchcases.bench/src/org/graalvm/wasm/benchcases/bench/WatBenchmarkSuite.java
    +++ b/wasm/src/org.graalvm.wasm.benchcases.bench/src/org/graalvm/wasm/benchcases/bench/WatBenchmarkSuite.java
    @@ -42,9 +42,13 @@
     
     import org.graalvm.wasm.benchmark.WasmBenchmarkSuiteBase;
     import org.openjdk.jmh.annotations.Benchmark;
    +import org.openjdk.jmh.annotations.Measurement;
     import org.openjdk.jmh.annotations.Scope;
     import org.openjdk.jmh.annotations.State;
    +import org.openjdk.jmh.annotations.Warmup;
     
    +@Warmup(iterations = 2)
    +@Measurement(iterations = 4)
     public class WatBenchmarkSuite extends WasmBenchmarkSuiteBase {
         @State(Scope.Benchmark)
         public static class WatBenchmarkState extends WasmBenchmarkState {
    diff --git a/wasm/src/org.graalvm.wasm.benchcases/src/bench/wat/vector.opts b/wasm/src/org.graalvm.wasm.benchcases/src/bench/wat/vector.opts
    new file mode 100644
    index 000000000000..e73749053ddb
    --- /dev/null
    +++ b/wasm/src/org.graalvm.wasm.benchcases/src/bench/wat/vector.opts
    @@ -0,0 +1,5 @@
    +zero-memory = true
    +interpreter-iterations = 1
    +sync-noinline-iterations = 1
    +sync-inline-iterations = 0
    +async-iterations = 1050
    \ No newline at end of file
    diff --git a/wasm/src/org.graalvm.wasm.benchcases/src/bench/wat/vector.result b/wasm/src/org.graalvm.wasm.benchcases/src/bench/wat/vector.result
    new file mode 100644
    index 000000000000..4f92b536bf12
    --- /dev/null
    +++ b/wasm/src/org.graalvm.wasm.benchcases/src/bench/wat/vector.result
    @@ -0,0 +1 @@
    +int 1
    \ No newline at end of file
    diff --git a/wasm/src/org.graalvm.wasm.benchcases/src/bench/wat/vector.wat b/wasm/src/org.graalvm.wasm.benchcases/src/bench/wat/vector.wat
    new file mode 100644
    index 000000000000..7f9cf26a12bd
    --- /dev/null
    +++ b/wasm/src/org.graalvm.wasm.benchcases/src/bench/wat/vector.wat
    @@ -0,0 +1,68 @@
    +;;
    +;; Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved.
    +;; DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
    +;;
    +;; The Universal Permissive License (UPL), Version 1.0
    +;;
    +;; Subject to the condition set forth below, permission is hereby granted to any
    +;; person obtaining a copy of this software, associated documentation and/or
    +;; data (collectively the "Software"), free of charge and under any and all
    +;; copyright rights in the Software, and any and all patent rights owned or
    +;; freely licensable by each licensor hereunder covering either (i) the
    +;; unmodified Software as contributed to or provided by such licensor, or (ii)
    +;; the Larger Works (as defined below), to deal in both
    +;;
    +;; (a) the Software, and
    +;;
    +;; (b) any piece of software and/or hardware listed in the lrgrwrks.txt file if
    +;; one is included with the Software each a "Larger Work" to which the Software
    +;; is contributed by such licensors),
    +;;
    +;; without restriction, including without limitation the rights to copy, create
    +;; derivative works of, display, perform, and distribute the Software and make,
    +;; use, sell, offer for sale, import, export, have made, and have sold the
    +;; Software and the Larger Work(s), and to sublicense the foregoing rights on
    +;; either these or other terms.
    +;;
    +;; This license is subject to the following condition:
    +;;
    +;; The above copyright notice and either this complete permission notice or at a
    +;; minimum a reference to the UPL must be included in all copies or substantial
    +;; portions of the Software.
    +;;
    +;; THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
    +;; IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
    +;; FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
    +;; AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
    +;; LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
    +;; OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
    +;; SOFTWARE.
    +;;
    +(module
    +  (type $int_func (func (result i32)))
    +  (type $proc (func))
    +
    +  (global $iterations i32 (i32.const 10000000))
    +
    +  (memory $memory (export "memory") 0)
    +
    +  (func (export "benchmarkSetupEach") (type $proc))
    +
    +  (func (export "benchmarkTeardownEach") (type $proc))
    +
    +  (func (export "benchmarkRun") (type $int_func)
    +    (local $i i32)
    +    (local $v v128)
    +
    +    (loop $bench_loop
    +      ;; Perform vector addition
    +      (local.set $v (i32x4.add (local.get $v) (v128.const i32x4 1 256 65536 16777216)))
    +
    +      ;; Increment loop counter and exit loop
    +      (local.set $i (i32.add (local.get $i) (i32.const 1)))
    +      (br_if $bench_loop (i32.lt_s (local.get $i) (global.get $iterations)))
    +    )
    +
    +    (i32x4.all_true (local.get $v))
    +  )
    +)
    
    From b4bab43f91a6587e74ffaf19f8c2c8113a02efda Mon Sep 17 00:00:00 2001
    From: Jirka Marsik 
    Date: Mon, 27 Nov 2023 22:35:05 +0100
    Subject: [PATCH 273/593] Use Unsafe to interpret byte arrays in v128 values
    
    ---
     .../src/org/graalvm/wasm/api/Vector128.java   | 24 +++++++++++++++++--
     1 file changed, 22 insertions(+), 2 deletions(-)
    
    diff --git a/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/api/Vector128.java b/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/api/Vector128.java
    index 54ca070c7b6c..2798dd8d0d92 100644
    --- a/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/api/Vector128.java
    +++ b/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/api/Vector128.java
    @@ -41,8 +41,28 @@
     
     package org.graalvm.wasm.api;
     
    +import sun.misc.Unsafe;
    +
    +import java.lang.reflect.Field;
    +
     public class Vector128 {
     
    +    private static final Unsafe unsafe = initUnsafe();
    +
    +    private static Unsafe initUnsafe() {
    +        try {
    +            return Unsafe.getUnsafe();
    +        } catch (SecurityException se) {
    +            try {
    +                Field theUnsafe = Unsafe.class.getDeclaredField("theUnsafe");
    +                theUnsafe.setAccessible(true);
    +                return (Unsafe) theUnsafe.get(Unsafe.class);
    +            } catch (Exception e) {
    +                throw new RuntimeException("exception while trying to get Unsafe", e);
    +            }
    +        }
    +    }
    +
         public static final Vector128 ZERO = new Vector128(new byte[16]);
     
         private final byte[] bytes;
    @@ -63,7 +83,7 @@ public static Vector128 ofBytes(byte[] bytes) {
         public int[] asInts() {
             int[] ints = new int[4];
             for (int i = 0; i < 4; i++) {
    -            ints[i] = (bytes[4 * i + 3] & 0xFF) << 24 | (bytes[4 * i + 2] & 0xFF) << 16 | (bytes[4 * i + 1] & 0xFF) << 8 | bytes[4 * i] & 0xFF;
    +            ints[i] = unsafe.getInt(bytes, Unsafe.ARRAY_BYTE_BASE_OFFSET + i * Unsafe.ARRAY_INT_INDEX_SCALE);
             }
             return ints;
         }
    @@ -72,7 +92,7 @@ public static Vector128 ofInts(int[] ints) {
             assert ints.length == 4;
             byte[] bytes = new byte[16];
             for (int i = 0; i < 16; i++) {
    -            bytes[i] = (byte) ((ints[i / 4] >> 8 * (i % 4)) & 0xFF);
    +            bytes[i] = unsafe.getByte(ints, Unsafe.ARRAY_INT_BASE_OFFSET + i * Unsafe.ARRAY_BYTE_INDEX_SCALE);
             }
             return new Vector128(bytes);
         }
    
    From 54c3b3fe6b1991cb4e6552ca4043aca7ec5bef3b Mon Sep 17 00:00:00 2001
    From: Jirka Marsik 
    Date: Fri, 1 Dec 2023 11:57:56 +0100
    Subject: [PATCH 274/593] Switch from Unsafe to Truffle's ByteArraySupport
    
    ---
     .../src/org/graalvm/wasm/api/Vector128.java   | 27 +++++--------------
     1 file changed, 6 insertions(+), 21 deletions(-)
    
    diff --git a/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/api/Vector128.java b/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/api/Vector128.java
    index 2798dd8d0d92..54842efb9561 100644
    --- a/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/api/Vector128.java
    +++ b/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/api/Vector128.java
    @@ -41,27 +41,12 @@
     
     package org.graalvm.wasm.api;
     
    -import sun.misc.Unsafe;
    -
    -import java.lang.reflect.Field;
    +import com.oracle.truffle.api.memory.ByteArraySupport;
     
     public class Vector128 {
     
    -    private static final Unsafe unsafe = initUnsafe();
    -
    -    private static Unsafe initUnsafe() {
    -        try {
    -            return Unsafe.getUnsafe();
    -        } catch (SecurityException se) {
    -            try {
    -                Field theUnsafe = Unsafe.class.getDeclaredField("theUnsafe");
    -                theUnsafe.setAccessible(true);
    -                return (Unsafe) theUnsafe.get(Unsafe.class);
    -            } catch (Exception e) {
    -                throw new RuntimeException("exception while trying to get Unsafe", e);
    -            }
    -        }
    -    }
    +    // v128 component values are stored in little-endian order
    +    private static final ByteArraySupport byteArraySupport = ByteArraySupport.littleEndian();
     
         public static final Vector128 ZERO = new Vector128(new byte[16]);
     
    @@ -83,7 +68,7 @@ public static Vector128 ofBytes(byte[] bytes) {
         public int[] asInts() {
             int[] ints = new int[4];
             for (int i = 0; i < 4; i++) {
    -            ints[i] = unsafe.getInt(bytes, Unsafe.ARRAY_BYTE_BASE_OFFSET + i * Unsafe.ARRAY_INT_INDEX_SCALE);
    +            ints[i] = byteArraySupport.getInt(bytes, i * 4);
             }
             return ints;
         }
    @@ -91,8 +76,8 @@ public int[] asInts() {
         public static Vector128 ofInts(int[] ints) {
             assert ints.length == 4;
             byte[] bytes = new byte[16];
    -        for (int i = 0; i < 16; i++) {
    -            bytes[i] = unsafe.getByte(ints, Unsafe.ARRAY_INT_BASE_OFFSET + i * Unsafe.ARRAY_BYTE_INDEX_SCALE);
    +        for (int i = 0; i < 4; i++) {
    +            byteArraySupport.putInt(bytes, i * 4, ints[i]);
             }
             return new Vector128(bytes);
         }
    
    From ba629a1e1c61284951cac212e9e7c6c0b36520c0 Mon Sep 17 00:00:00 2001
    From: Jirka Marsik 
    Date: Fri, 1 Dec 2023 12:57:41 +0100
    Subject: [PATCH 275/593] Use ExplodeLoop annotation on vector ops
    
    ---
     .../org.graalvm.wasm/src/org/graalvm/wasm/api/Vector128.java   | 3 +++
     .../src/org/graalvm/wasm/nodes/WasmFunctionNode.java           | 2 ++
     2 files changed, 5 insertions(+)
    
    diff --git a/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/api/Vector128.java b/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/api/Vector128.java
    index 54842efb9561..32dbba62a9a2 100644
    --- a/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/api/Vector128.java
    +++ b/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/api/Vector128.java
    @@ -42,6 +42,7 @@
     package org.graalvm.wasm.api;
     
     import com.oracle.truffle.api.memory.ByteArraySupport;
    +import com.oracle.truffle.api.nodes.ExplodeLoop;
     
     public class Vector128 {
     
    @@ -65,6 +66,7 @@ public static Vector128 ofBytes(byte[] bytes) {
             return new Vector128(bytes);
         }
     
    +    @ExplodeLoop
         public int[] asInts() {
             int[] ints = new int[4];
             for (int i = 0; i < 4; i++) {
    @@ -73,6 +75,7 @@ public int[] asInts() {
             return ints;
         }
     
    +    @ExplodeLoop
         public static Vector128 ofInts(int[] ints) {
             assert ints.length == 4;
             byte[] bytes = new byte[16];
    diff --git a/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/nodes/WasmFunctionNode.java b/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/nodes/WasmFunctionNode.java
    index 3c7c8e98ad59..3ae382bc4702 100644
    --- a/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/nodes/WasmFunctionNode.java
    +++ b/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/nodes/WasmFunctionNode.java
    @@ -3835,6 +3835,7 @@ private void memory_copy(WasmInstance instance, long length, long source, long d
             destMemory.copyFrom(srcMemory, source, destination, length);
         }
     
    +    @ExplodeLoop(kind = ExplodeLoop.LoopExplosionKind.FULL_UNROLL)
         private static void i32x4_all_true(VirtualFrame frame, int stackPointer) {
             int[] x = popVector128(frame, stackPointer - 1).asInts();
             int result = 1;
    @@ -3847,6 +3848,7 @@ private static void i32x4_all_true(VirtualFrame frame, int stackPointer) {
             pushInt(frame, stackPointer - 1, result);
         }
     
    +    @ExplodeLoop
         private static void i32x4_add(VirtualFrame frame, int stackPointer) {
             int[] x = popVector128(frame, stackPointer - 1).asInts();
             int[] y = popVector128(frame, stackPointer - 2).asInts();
    
    From 827771ce70e88fc9a0393bce046c470d23f33fa6 Mon Sep 17 00:00:00 2001
    From: Jirka Marsik 
    Date: Tue, 5 Dec 2023 12:33:12 +0100
    Subject: [PATCH 276/593] Add flat benchmarks and benchmarks for multiplication
     of ints and doubles
    
    ---
     .../src/bench/wat/flat-double-mul.opts        |  5 ++
     .../src/bench/wat/flat-double-mul.result      |  1 +
     .../src/bench/wat/flat-double-mul.wat         | 72 +++++++++++++++++
     .../src/bench/wat/flat-int-add.opts           |  5 ++
     .../src/bench/wat/flat-int-add.result         |  1 +
     .../src/bench/wat/flat-int-add.wat            | 74 ++++++++++++++++++
     .../src/bench/wat/flat-int-mul.opts           |  5 ++
     .../src/bench/wat/flat-int-mul.result         |  1 +
     .../src/bench/wat/flat-int-mul.wat            | 78 +++++++++++++++++++
     .../src/bench/wat/vector-double-mul.opts      |  5 ++
     .../src/bench/wat/vector-double-mul.result    |  1 +
     .../src/bench/wat/vector-double-mul.wat       | 69 ++++++++++++++++
     .../src/bench/wat/vector-int-add.opts         |  5 ++
     .../src/bench/wat/vector-int-add.result       |  1 +
     .../wat/{vector.wat => vector-int-add.wat}    |  0
     .../src/bench/wat/vector-int-mul.opts         |  5 ++
     .../src/bench/wat/vector-int-mul.result       |  1 +
     .../src/bench/wat/vector-int-mul.wat          | 69 ++++++++++++++++
     18 files changed, 398 insertions(+)
     create mode 100644 wasm/src/org.graalvm.wasm.benchcases/src/bench/wat/flat-double-mul.opts
     create mode 100644 wasm/src/org.graalvm.wasm.benchcases/src/bench/wat/flat-double-mul.result
     create mode 100644 wasm/src/org.graalvm.wasm.benchcases/src/bench/wat/flat-double-mul.wat
     create mode 100644 wasm/src/org.graalvm.wasm.benchcases/src/bench/wat/flat-int-add.opts
     create mode 100644 wasm/src/org.graalvm.wasm.benchcases/src/bench/wat/flat-int-add.result
     create mode 100644 wasm/src/org.graalvm.wasm.benchcases/src/bench/wat/flat-int-add.wat
     create mode 100644 wasm/src/org.graalvm.wasm.benchcases/src/bench/wat/flat-int-mul.opts
     create mode 100644 wasm/src/org.graalvm.wasm.benchcases/src/bench/wat/flat-int-mul.result
     create mode 100644 wasm/src/org.graalvm.wasm.benchcases/src/bench/wat/flat-int-mul.wat
     create mode 100644 wasm/src/org.graalvm.wasm.benchcases/src/bench/wat/vector-double-mul.opts
     create mode 100644 wasm/src/org.graalvm.wasm.benchcases/src/bench/wat/vector-double-mul.result
     create mode 100644 wasm/src/org.graalvm.wasm.benchcases/src/bench/wat/vector-double-mul.wat
     create mode 100644 wasm/src/org.graalvm.wasm.benchcases/src/bench/wat/vector-int-add.opts
     create mode 100644 wasm/src/org.graalvm.wasm.benchcases/src/bench/wat/vector-int-add.result
     rename wasm/src/org.graalvm.wasm.benchcases/src/bench/wat/{vector.wat => vector-int-add.wat} (100%)
     create mode 100644 wasm/src/org.graalvm.wasm.benchcases/src/bench/wat/vector-int-mul.opts
     create mode 100644 wasm/src/org.graalvm.wasm.benchcases/src/bench/wat/vector-int-mul.result
     create mode 100644 wasm/src/org.graalvm.wasm.benchcases/src/bench/wat/vector-int-mul.wat
    
    diff --git a/wasm/src/org.graalvm.wasm.benchcases/src/bench/wat/flat-double-mul.opts b/wasm/src/org.graalvm.wasm.benchcases/src/bench/wat/flat-double-mul.opts
    new file mode 100644
    index 000000000000..e73749053ddb
    --- /dev/null
    +++ b/wasm/src/org.graalvm.wasm.benchcases/src/bench/wat/flat-double-mul.opts
    @@ -0,0 +1,5 @@
    +zero-memory = true
    +interpreter-iterations = 1
    +sync-noinline-iterations = 1
    +sync-inline-iterations = 0
    +async-iterations = 1050
    \ No newline at end of file
    diff --git a/wasm/src/org.graalvm.wasm.benchcases/src/bench/wat/flat-double-mul.result b/wasm/src/org.graalvm.wasm.benchcases/src/bench/wat/flat-double-mul.result
    new file mode 100644
    index 000000000000..4f92b536bf12
    --- /dev/null
    +++ b/wasm/src/org.graalvm.wasm.benchcases/src/bench/wat/flat-double-mul.result
    @@ -0,0 +1 @@
    +int 1
    \ No newline at end of file
    diff --git a/wasm/src/org.graalvm.wasm.benchcases/src/bench/wat/flat-double-mul.wat b/wasm/src/org.graalvm.wasm.benchcases/src/bench/wat/flat-double-mul.wat
    new file mode 100644
    index 000000000000..24dbc178255c
    --- /dev/null
    +++ b/wasm/src/org.graalvm.wasm.benchcases/src/bench/wat/flat-double-mul.wat
    @@ -0,0 +1,72 @@
    +;;
    +;; Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved.
    +;; DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
    +;;
    +;; The Universal Permissive License (UPL), Version 1.0
    +;;
    +;; Subject to the condition set forth below, permission is hereby granted to any
    +;; person obtaining a copy of this software, associated documentation and/or
    +;; data (collectively the "Software"), free of charge and under any and all
    +;; copyright rights in the Software, and any and all patent rights owned or
    +;; freely licensable by each licensor hereunder covering either (i) the
    +;; unmodified Software as contributed to or provided by such licensor, or (ii)
    +;; the Larger Works (as defined below), to deal in both
    +;;
    +;; (a) the Software, and
    +;;
    +;; (b) any piece of software and/or hardware listed in the lrgrwrks.txt file if
    +;; one is included with the Software each a "Larger Work" to which the Software
    +;; is contributed by such licensors),
    +;;
    +;; without restriction, including without limitation the rights to copy, create
    +;; derivative works of, display, perform, and distribute the Software and make,
    +;; use, sell, offer for sale, import, export, have made, and have sold the
    +;; Software and the Larger Work(s), and to sublicense the foregoing rights on
    +;; either these or other terms.
    +;;
    +;; This license is subject to the following condition:
    +;;
    +;; The above copyright notice and either this complete permission notice or at a
    +;; minimum a reference to the UPL must be included in all copies or substantial
    +;; portions of the Software.
    +;;
    +;; THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
    +;; IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
    +;; FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
    +;; AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
    +;; LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
    +;; OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
    +;; SOFTWARE.
    +;;
    +(module
    +  (type $int_func (func (result i32)))
    +  (type $proc (func))
    +
    +  (global $iterations i32 (i32.const 10000000))
    +
    +  (memory $memory (export "memory") 0)
    +
    +  (func (export "benchmarkSetupEach") (type $proc))
    +
    +  (func (export "benchmarkTeardownEach") (type $proc))
    +
    +  (func (export "benchmarkRun") (type $int_func)
    +    (local $i i32)
    +    (local $x f64)
    +    (local $y f64)
    +    (local.set $x (f64.const 1))
    +    (local.set $y (f64.const 1))
    +
    +    (loop $bench_loop
    +      ;; Perform two double multiplications
    +      (local.set $x (f64.mul (local.get $x) (f64.const 2.7)))
    +      (local.set $y (f64.mul (local.get $y) (f64.const 3.14)))
    +
    +      ;; Increment loop counter and exit loop
    +      (local.set $i (i32.add (local.get $i) (i32.const 1)))
    +      (br_if $bench_loop (i32.lt_s (local.get $i) (global.get $iterations)))
    +    )
    +
    +    (i32.or (f64.ne (local.get $x) (f64.const 0)) (f64.ne (local.get $y) (f64.const 0)))
    +  )
    +)
    diff --git a/wasm/src/org.graalvm.wasm.benchcases/src/bench/wat/flat-int-add.opts b/wasm/src/org.graalvm.wasm.benchcases/src/bench/wat/flat-int-add.opts
    new file mode 100644
    index 000000000000..e73749053ddb
    --- /dev/null
    +++ b/wasm/src/org.graalvm.wasm.benchcases/src/bench/wat/flat-int-add.opts
    @@ -0,0 +1,5 @@
    +zero-memory = true
    +interpreter-iterations = 1
    +sync-noinline-iterations = 1
    +sync-inline-iterations = 0
    +async-iterations = 1050
    \ No newline at end of file
    diff --git a/wasm/src/org.graalvm.wasm.benchcases/src/bench/wat/flat-int-add.result b/wasm/src/org.graalvm.wasm.benchcases/src/bench/wat/flat-int-add.result
    new file mode 100644
    index 000000000000..4f92b536bf12
    --- /dev/null
    +++ b/wasm/src/org.graalvm.wasm.benchcases/src/bench/wat/flat-int-add.result
    @@ -0,0 +1 @@
    +int 1
    \ No newline at end of file
    diff --git a/wasm/src/org.graalvm.wasm.benchcases/src/bench/wat/flat-int-add.wat b/wasm/src/org.graalvm.wasm.benchcases/src/bench/wat/flat-int-add.wat
    new file mode 100644
    index 000000000000..0cf5bc629363
    --- /dev/null
    +++ b/wasm/src/org.graalvm.wasm.benchcases/src/bench/wat/flat-int-add.wat
    @@ -0,0 +1,74 @@
    +;;
    +;; Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved.
    +;; DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
    +;;
    +;; The Universal Permissive License (UPL), Version 1.0
    +;;
    +;; Subject to the condition set forth below, permission is hereby granted to any
    +;; person obtaining a copy of this software, associated documentation and/or
    +;; data (collectively the "Software"), free of charge and under any and all
    +;; copyright rights in the Software, and any and all patent rights owned or
    +;; freely licensable by each licensor hereunder covering either (i) the
    +;; unmodified Software as contributed to or provided by such licensor, or (ii)
    +;; the Larger Works (as defined below), to deal in both
    +;;
    +;; (a) the Software, and
    +;;
    +;; (b) any piece of software and/or hardware listed in the lrgrwrks.txt file if
    +;; one is included with the Software each a "Larger Work" to which the Software
    +;; is contributed by such licensors),
    +;;
    +;; without restriction, including without limitation the rights to copy, create
    +;; derivative works of, display, perform, and distribute the Software and make,
    +;; use, sell, offer for sale, import, export, have made, and have sold the
    +;; Software and the Larger Work(s), and to sublicense the foregoing rights on
    +;; either these or other terms.
    +;;
    +;; This license is subject to the following condition:
    +;;
    +;; The above copyright notice and either this complete permission notice or at a
    +;; minimum a reference to the UPL must be included in all copies or substantial
    +;; portions of the Software.
    +;;
    +;; THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
    +;; IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
    +;; FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
    +;; AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
    +;; LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
    +;; OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
    +;; SOFTWARE.
    +;;
    +(module
    +  (type $int_func (func (result i32)))
    +  (type $proc (func))
    +
    +  (global $iterations i32 (i32.const 10000000))
    +
    +  (memory $memory (export "memory") 0)
    +
    +  (func (export "benchmarkSetupEach") (type $proc))
    +
    +  (func (export "benchmarkTeardownEach") (type $proc))
    +
    +  (func (export "benchmarkRun") (type $int_func)
    +    (local $i i32)
    +    (local $x i32)
    +    (local $y i32)
    +    (local $z i32)
    +    (local $w i32)
    +
    +    (loop $bench_loop
    +      ;; Perform four int additions
    +      (local.set $x (i32.add (local.get $x) (i32.const 1)))
    +      (local.set $y (i32.add (local.get $y) (i32.const 256)))
    +      (local.set $z (i32.add (local.get $z) (i32.const 65536)))
    +      (local.set $w (i32.add (local.get $w) (i32.const 16777216)))
    +
    +      ;; Increment loop counter and exit loop
    +      (local.set $i (i32.add (local.get $i) (i32.const 1)))
    +      (br_if $bench_loop (i32.lt_s (local.get $i) (global.get $iterations)))
    +    )
    +
    +    (i32.and (i32.and (i32.ne (local.get $x) (i32.const 0)) (i32.ne (local.get $y) (i32.const 0))) (i32.and (i32.ne (local.get $z) (i32.const 0)) (i32.ne (local.get $w) (i32.const 0))))
    +  )
    +)
    diff --git a/wasm/src/org.graalvm.wasm.benchcases/src/bench/wat/flat-int-mul.opts b/wasm/src/org.graalvm.wasm.benchcases/src/bench/wat/flat-int-mul.opts
    new file mode 100644
    index 000000000000..e73749053ddb
    --- /dev/null
    +++ b/wasm/src/org.graalvm.wasm.benchcases/src/bench/wat/flat-int-mul.opts
    @@ -0,0 +1,5 @@
    +zero-memory = true
    +interpreter-iterations = 1
    +sync-noinline-iterations = 1
    +sync-inline-iterations = 0
    +async-iterations = 1050
    \ No newline at end of file
    diff --git a/wasm/src/org.graalvm.wasm.benchcases/src/bench/wat/flat-int-mul.result b/wasm/src/org.graalvm.wasm.benchcases/src/bench/wat/flat-int-mul.result
    new file mode 100644
    index 000000000000..4f92b536bf12
    --- /dev/null
    +++ b/wasm/src/org.graalvm.wasm.benchcases/src/bench/wat/flat-int-mul.result
    @@ -0,0 +1 @@
    +int 1
    \ No newline at end of file
    diff --git a/wasm/src/org.graalvm.wasm.benchcases/src/bench/wat/flat-int-mul.wat b/wasm/src/org.graalvm.wasm.benchcases/src/bench/wat/flat-int-mul.wat
    new file mode 100644
    index 000000000000..0c30dc2c7dd2
    --- /dev/null
    +++ b/wasm/src/org.graalvm.wasm.benchcases/src/bench/wat/flat-int-mul.wat
    @@ -0,0 +1,78 @@
    +;;
    +;; Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved.
    +;; DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
    +;;
    +;; The Universal Permissive License (UPL), Version 1.0
    +;;
    +;; Subject to the condition set forth below, permission is hereby granted to any
    +;; person obtaining a copy of this software, associated documentation and/or
    +;; data (collectively the "Software"), free of charge and under any and all
    +;; copyright rights in the Software, and any and all patent rights owned or
    +;; freely licensable by each licensor hereunder covering either (i) the
    +;; unmodified Software as contributed to or provided by such licensor, or (ii)
    +;; the Larger Works (as defined below), to deal in both
    +;;
    +;; (a) the Software, and
    +;;
    +;; (b) any piece of software and/or hardware listed in the lrgrwrks.txt file if
    +;; one is included with the Software each a "Larger Work" to which the Software
    +;; is contributed by such licensors),
    +;;
    +;; without restriction, including without limitation the rights to copy, create
    +;; derivative works of, display, perform, and distribute the Software and make,
    +;; use, sell, offer for sale, import, export, have made, and have sold the
    +;; Software and the Larger Work(s), and to sublicense the foregoing rights on
    +;; either these or other terms.
    +;;
    +;; This license is subject to the following condition:
    +;;
    +;; The above copyright notice and either this complete permission notice or at a
    +;; minimum a reference to the UPL must be included in all copies or substantial
    +;; portions of the Software.
    +;;
    +;; THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
    +;; IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
    +;; FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
    +;; AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
    +;; LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
    +;; OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
    +;; SOFTWARE.
    +;;
    +(module
    +  (type $int_func (func (result i32)))
    +  (type $proc (func))
    +
    +  (global $iterations i32 (i32.const 10000000))
    +
    +  (memory $memory (export "memory") 0)
    +
    +  (func (export "benchmarkSetupEach") (type $proc))
    +
    +  (func (export "benchmarkTeardownEach") (type $proc))
    +
    +  (func (export "benchmarkRun") (type $int_func)
    +    (local $i i32)
    +    (local $x i32)
    +    (local $y i32)
    +    (local $z i32)
    +    (local $w i32)
    +    (local.set $x (i32.const 1))
    +    (local.set $y (i32.const 1))
    +    (local.set $z (i32.const 1))
    +    (local.set $w (i32.const 1))
    +
    +    (loop $bench_loop
    +      ;; Perform four int multiplications
    +      (local.set $x (i32.mul (local.get $x) (i32.const 3)))
    +      (local.set $y (i32.mul (local.get $y) (i32.const 5)))
    +      (local.set $z (i32.mul (local.get $z) (i32.const 7)))
    +      (local.set $w (i32.mul (local.get $w) (i32.const 11)))
    +
    +      ;; Increment loop counter and exit loop
    +      (local.set $i (i32.add (local.get $i) (i32.const 1)))
    +      (br_if $bench_loop (i32.lt_s (local.get $i) (global.get $iterations)))
    +    )
    +
    +    (i32.and (i32.and (i32.ne (local.get $x) (i32.const 0)) (i32.ne (local.get $y) (i32.const 0))) (i32.and (i32.ne (local.get $z) (i32.const 0)) (i32.ne (local.get $w) (i32.const 0))))
    +  )
    +)
    diff --git a/wasm/src/org.graalvm.wasm.benchcases/src/bench/wat/vector-double-mul.opts b/wasm/src/org.graalvm.wasm.benchcases/src/bench/wat/vector-double-mul.opts
    new file mode 100644
    index 000000000000..e73749053ddb
    --- /dev/null
    +++ b/wasm/src/org.graalvm.wasm.benchcases/src/bench/wat/vector-double-mul.opts
    @@ -0,0 +1,5 @@
    +zero-memory = true
    +interpreter-iterations = 1
    +sync-noinline-iterations = 1
    +sync-inline-iterations = 0
    +async-iterations = 1050
    \ No newline at end of file
    diff --git a/wasm/src/org.graalvm.wasm.benchcases/src/bench/wat/vector-double-mul.result b/wasm/src/org.graalvm.wasm.benchcases/src/bench/wat/vector-double-mul.result
    new file mode 100644
    index 000000000000..4f92b536bf12
    --- /dev/null
    +++ b/wasm/src/org.graalvm.wasm.benchcases/src/bench/wat/vector-double-mul.result
    @@ -0,0 +1 @@
    +int 1
    \ No newline at end of file
    diff --git a/wasm/src/org.graalvm.wasm.benchcases/src/bench/wat/vector-double-mul.wat b/wasm/src/org.graalvm.wasm.benchcases/src/bench/wat/vector-double-mul.wat
    new file mode 100644
    index 000000000000..a9e640bbef55
    --- /dev/null
    +++ b/wasm/src/org.graalvm.wasm.benchcases/src/bench/wat/vector-double-mul.wat
    @@ -0,0 +1,69 @@
    +;;
    +;; Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved.
    +;; DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
    +;;
    +;; The Universal Permissive License (UPL), Version 1.0
    +;;
    +;; Subject to the condition set forth below, permission is hereby granted to any
    +;; person obtaining a copy of this software, associated documentation and/or
    +;; data (collectively the "Software"), free of charge and under any and all
    +;; copyright rights in the Software, and any and all patent rights owned or
    +;; freely licensable by each licensor hereunder covering either (i) the
    +;; unmodified Software as contributed to or provided by such licensor, or (ii)
    +;; the Larger Works (as defined below), to deal in both
    +;;
    +;; (a) the Software, and
    +;;
    +;; (b) any piece of software and/or hardware listed in the lrgrwrks.txt file if
    +;; one is included with the Software each a "Larger Work" to which the Software
    +;; is contributed by such licensors),
    +;;
    +;; without restriction, including without limitation the rights to copy, create
    +;; derivative works of, display, perform, and distribute the Software and make,
    +;; use, sell, offer for sale, import, export, have made, and have sold the
    +;; Software and the Larger Work(s), and to sublicense the foregoing rights on
    +;; either these or other terms.
    +;;
    +;; This license is subject to the following condition:
    +;;
    +;; The above copyright notice and either this complete permission notice or at a
    +;; minimum a reference to the UPL must be included in all copies or substantial
    +;; portions of the Software.
    +;;
    +;; THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
    +;; IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
    +;; FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
    +;; AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
    +;; LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
    +;; OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
    +;; SOFTWARE.
    +;;
    +(module
    +  (type $int_func (func (result i32)))
    +  (type $proc (func))
    +
    +  (global $iterations i32 (i32.const 10000000))
    +
    +  (memory $memory (export "memory") 0)
    +
    +  (func (export "benchmarkSetupEach") (type $proc))
    +
    +  (func (export "benchmarkTeardownEach") (type $proc))
    +
    +  (func (export "benchmarkRun") (type $int_func)
    +    (local $i i32)
    +    (local $v v128)
    +    (local.set $v (v128.const f64x2 1 1))
    +
    +    (loop $bench_loop
    +      ;; Perform double vector multiplication
    +      (local.set $v (f64x2.mul (local.get $v) (v128.const f64x2 2.7 3.14)))
    +
    +      ;; Increment loop counter and exit loop
    +      (local.set $i (i32.add (local.get $i) (i32.const 1)))
    +      (br_if $bench_loop (i32.lt_s (local.get $i) (global.get $iterations)))
    +    )
    +
    +    (v128.any_true (local.get $v))
    +  )
    +)
    diff --git a/wasm/src/org.graalvm.wasm.benchcases/src/bench/wat/vector-int-add.opts b/wasm/src/org.graalvm.wasm.benchcases/src/bench/wat/vector-int-add.opts
    new file mode 100644
    index 000000000000..e73749053ddb
    --- /dev/null
    +++ b/wasm/src/org.graalvm.wasm.benchcases/src/bench/wat/vector-int-add.opts
    @@ -0,0 +1,5 @@
    +zero-memory = true
    +interpreter-iterations = 1
    +sync-noinline-iterations = 1
    +sync-inline-iterations = 0
    +async-iterations = 1050
    \ No newline at end of file
    diff --git a/wasm/src/org.graalvm.wasm.benchcases/src/bench/wat/vector-int-add.result b/wasm/src/org.graalvm.wasm.benchcases/src/bench/wat/vector-int-add.result
    new file mode 100644
    index 000000000000..4f92b536bf12
    --- /dev/null
    +++ b/wasm/src/org.graalvm.wasm.benchcases/src/bench/wat/vector-int-add.result
    @@ -0,0 +1 @@
    +int 1
    \ No newline at end of file
    diff --git a/wasm/src/org.graalvm.wasm.benchcases/src/bench/wat/vector.wat b/wasm/src/org.graalvm.wasm.benchcases/src/bench/wat/vector-int-add.wat
    similarity index 100%
    rename from wasm/src/org.graalvm.wasm.benchcases/src/bench/wat/vector.wat
    rename to wasm/src/org.graalvm.wasm.benchcases/src/bench/wat/vector-int-add.wat
    diff --git a/wasm/src/org.graalvm.wasm.benchcases/src/bench/wat/vector-int-mul.opts b/wasm/src/org.graalvm.wasm.benchcases/src/bench/wat/vector-int-mul.opts
    new file mode 100644
    index 000000000000..e73749053ddb
    --- /dev/null
    +++ b/wasm/src/org.graalvm.wasm.benchcases/src/bench/wat/vector-int-mul.opts
    @@ -0,0 +1,5 @@
    +zero-memory = true
    +interpreter-iterations = 1
    +sync-noinline-iterations = 1
    +sync-inline-iterations = 0
    +async-iterations = 1050
    \ No newline at end of file
    diff --git a/wasm/src/org.graalvm.wasm.benchcases/src/bench/wat/vector-int-mul.result b/wasm/src/org.graalvm.wasm.benchcases/src/bench/wat/vector-int-mul.result
    new file mode 100644
    index 000000000000..4f92b536bf12
    --- /dev/null
    +++ b/wasm/src/org.graalvm.wasm.benchcases/src/bench/wat/vector-int-mul.result
    @@ -0,0 +1 @@
    +int 1
    \ No newline at end of file
    diff --git a/wasm/src/org.graalvm.wasm.benchcases/src/bench/wat/vector-int-mul.wat b/wasm/src/org.graalvm.wasm.benchcases/src/bench/wat/vector-int-mul.wat
    new file mode 100644
    index 000000000000..b544dfc562f7
    --- /dev/null
    +++ b/wasm/src/org.graalvm.wasm.benchcases/src/bench/wat/vector-int-mul.wat
    @@ -0,0 +1,69 @@
    +;;
    +;; Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved.
    +;; DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
    +;;
    +;; The Universal Permissive License (UPL), Version 1.0
    +;;
    +;; Subject to the condition set forth below, permission is hereby granted to any
    +;; person obtaining a copy of this software, associated documentation and/or
    +;; data (collectively the "Software"), free of charge and under any and all
    +;; copyright rights in the Software, and any and all patent rights owned or
    +;; freely licensable by each licensor hereunder covering either (i) the
    +;; unmodified Software as contributed to or provided by such licensor, or (ii)
    +;; the Larger Works (as defined below), to deal in both
    +;;
    +;; (a) the Software, and
    +;;
    +;; (b) any piece of software and/or hardware listed in the lrgrwrks.txt file if
    +;; one is included with the Software each a "Larger Work" to which the Software
    +;; is contributed by such licensors),
    +;;
    +;; without restriction, including without limitation the rights to copy, create
    +;; derivative works of, display, perform, and distribute the Software and make,
    +;; use, sell, offer for sale, import, export, have made, and have sold the
    +;; Software and the Larger Work(s), and to sublicense the foregoing rights on
    +;; either these or other terms.
    +;;
    +;; This license is subject to the following condition:
    +;;
    +;; The above copyright notice and either this complete permission notice or at a
    +;; minimum a reference to the UPL must be included in all copies or substantial
    +;; portions of the Software.
    +;;
    +;; THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
    +;; IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
    +;; FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
    +;; AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
    +;; LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
    +;; OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
    +;; SOFTWARE.
    +;;
    +(module
    +  (type $int_func (func (result i32)))
    +  (type $proc (func))
    +
    +  (global $iterations i32 (i32.const 10000000))
    +
    +  (memory $memory (export "memory") 0)
    +
    +  (func (export "benchmarkSetupEach") (type $proc))
    +
    +  (func (export "benchmarkTeardownEach") (type $proc))
    +
    +  (func (export "benchmarkRun") (type $int_func)
    +    (local $i i32)
    +    (local $v v128)
    +    (local.set $v (v128.const i32x4 1 1 1 1))
    +
    +    (loop $bench_loop
    +      ;; Perform int vector multiplication
    +      (local.set $v (i32x4.mul (local.get $v) (v128.const i32x4 3 5 7 11)))
    +
    +      ;; Increment loop counter and exit loop
    +      (local.set $i (i32.add (local.get $i) (i32.const 1)))
    +      (br_if $bench_loop (i32.lt_s (local.get $i) (global.get $iterations)))
    +    )
    +
    +    (i32x4.all_true (local.get $v))
    +  )
    +)
    
    From fca48c8d53151fcbb86e694855a7a9fa5c71c959 Mon Sep 17 00:00:00 2001
    From: Jirka Marsik 
    Date: Tue, 5 Dec 2023 12:35:07 +0100
    Subject: [PATCH 277/593] Add f64x2, support all binops on i32x4 and f64x2
    
    ---
     .../src/org/graalvm/wasm/BinaryParser.java    |  15 ++-
     .../src/org/graalvm/wasm/api/Vector128.java   |  20 +++-
     .../org/graalvm/wasm/api/VectorOperators.java |  68 +++++++++++
     .../org/graalvm/wasm/constants/Bytecode.java  |  11 ++
     .../graalvm/wasm/constants/Instructions.java  |  11 ++
     .../graalvm/wasm/nodes/WasmFunctionNode.java  | 111 +++++++++++++++++-
     6 files changed, 228 insertions(+), 8 deletions(-)
     create mode 100644 wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/api/VectorOperators.java
    
    diff --git a/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/BinaryParser.java b/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/BinaryParser.java
    index 72a618167adc..3d16872e8179 100644
    --- a/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/BinaryParser.java
    +++ b/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/BinaryParser.java
    @@ -1807,16 +1807,27 @@ private void readNumericInstructions(ParserState state, int opcode) {
                             state.push(V128_TYPE);
                             state.addInstruction(Bytecode.VECTOR_V128_CONST_I128, value);
                             break;
    +                    case Instructions.VECTOR_V128_ANY_TRUE:
                         case Instructions.VECTOR_I32X4_ALL_TRUE:
                             state.popChecked(V128_TYPE);
                             state.push(I32_TYPE);
    -                        state.addInstruction(Bytecode.VECTOR_I32X4_ALL_TRUE);
    +                        state.addInstruction(vectorOpcode);
                             break;
                         case Instructions.VECTOR_I32X4_ADD:
    +                    case Instructions.VECTOR_I32X4_SUB:
    +                    case Instructions.VECTOR_I32X4_MUL:
    +                    case Instructions.VECTOR_F64X2_ADD:
    +                    case Instructions.VECTOR_F64X2_SUB:
    +                    case Instructions.VECTOR_F64X2_MUL:
    +                    case Instructions.VECTOR_F64X2_DIV:
    +                    case Instructions.VECTOR_F64X2_MIN:
    +                    case Instructions.VECTOR_F64X2_MAX:
    +                    case Instructions.VECTOR_F64X2_PMIN:
    +                    case Instructions.VECTOR_F64X2_PMAX:
                             state.popChecked(V128_TYPE);
                             state.popChecked(V128_TYPE);
                             state.push(V128_TYPE);
    -                        state.addInstruction(Bytecode.VECTOR_I32X4_ADD);
    +                        state.addInstruction(vectorOpcode);
                             break;
                         default:
                             fail(Failure.UNSPECIFIED_MALFORMED, "Unknown opcode: 0xFD 0x%02x", vectorOpcode);
    diff --git a/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/api/Vector128.java b/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/api/Vector128.java
    index 32dbba62a9a2..6ca4f01f0d84 100644
    --- a/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/api/Vector128.java
    +++ b/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/api/Vector128.java
    @@ -38,7 +38,6 @@
      * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
      * SOFTWARE.
      */
    -
     package org.graalvm.wasm.api;
     
     import com.oracle.truffle.api.memory.ByteArraySupport;
    @@ -84,4 +83,23 @@ public static Vector128 ofInts(int[] ints) {
             }
             return new Vector128(bytes);
         }
    +
    +    @ExplodeLoop
    +    public double[] asDoubles() {
    +        double[] doubles = new double[2];
    +        for (int i = 0; i < 2; i++) {
    +            doubles[i] = byteArraySupport.getDouble(bytes, i * 8);
    +        }
    +        return doubles;
    +    }
    +
    +    @ExplodeLoop
    +    public static Vector128 ofDoubles(double[] doubles) {
    +        assert doubles.length == 2;
    +        byte[] bytes = new byte[16];
    +        for (int i = 0; i < 2; i++) {
    +            byteArraySupport.putDouble(bytes, i * 8, doubles[i]);
    +        }
    +        return new Vector128(bytes);
    +    }
     }
    diff --git a/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/api/VectorOperators.java b/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/api/VectorOperators.java
    new file mode 100644
    index 000000000000..9b92fbcec543
    --- /dev/null
    +++ b/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/api/VectorOperators.java
    @@ -0,0 +1,68 @@
    +/*
    + * Copyright (c) 2023, 2023, Oracle and/or its affiliates. All rights reserved.
    + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
    + *
    + * The Universal Permissive License (UPL), Version 1.0
    + *
    + * Subject to the condition set forth below, permission is hereby granted to any
    + * person obtaining a copy of this software, associated documentation and/or
    + * data (collectively the "Software"), free of charge and under any and all
    + * copyright rights in the Software, and any and all patent rights owned or
    + * freely licensable by each licensor hereunder covering either (i) the
    + * unmodified Software as contributed to or provided by such licensor, or (ii)
    + * the Larger Works (as defined below), to deal in both
    + *
    + * (a) the Software, and
    + *
    + * (b) any piece of software and/or hardware listed in the lrgrwrks.txt file if
    + * one is included with the Software each a "Larger Work" to which the Software
    + * is contributed by such licensors),
    + *
    + * without restriction, including without limitation the rights to copy, create
    + * derivative works of, display, perform, and distribute the Software and make,
    + * use, sell, offer for sale, import, export, have made, and have sold the
    + * Software and the Larger Work(s), and to sublicense the foregoing rights on
    + * either these or other terms.
    + *
    + * This license is subject to the following condition:
    + *
    + * The above copyright notice and either this complete permission notice or at a
    + * minimum a reference to the UPL must be included in all copies or substantial
    + * portions of the Software.
    + *
    + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
    + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
    + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
    + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
    + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
    + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
    + * SOFTWARE.
    + */
    +package org.graalvm.wasm.api;
    +
    +public class VectorOperators {
    +
    +    /**
    +     * Vectorized integer binary operators. Corresponds to the {@code vibinop} production in the
    +     * WebAssembly spec.
    +     */
    +    public enum VIBinOp {
    +        Add,
    +        Sub
    +    }
    +
    +    /**
    +     * Vectorized floating-point binary operators. Corresponds to the {@code vfbinop} production in
    +     * the WebAssembly spec.
    +     */
    +    public enum VFBinOp {
    +        Add,
    +        Sub,
    +        Mul,
    +        Div,
    +        Min,
    +        Max,
    +        Pmin,
    +        Pmax
    +    }
    +}
    diff --git a/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/constants/Bytecode.java b/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/constants/Bytecode.java
    index bc723f387a44..73b8d8257bd5 100644
    --- a/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/constants/Bytecode.java
    +++ b/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/constants/Bytecode.java
    @@ -445,8 +445,19 @@ public class Bytecode {
     
         // Vector opcodes
         public static final int VECTOR_V128_CONST_I128 = 0x0C;
    +    public static final int VECTOR_V128_ANY_TRUE = 0x53;
         public static final int VECTOR_I32X4_ALL_TRUE = 0xA3;
         public static final int VECTOR_I32X4_ADD = 0xAE;
    +    public static final int VECTOR_I32X4_SUB = 0xB1;
    +    public static final int VECTOR_I32X4_MUL = 0xB5;
    +    public static final int VECTOR_F64X2_ADD = 0xF0;
    +    public static final int VECTOR_F64X2_SUB = 0xF1;
    +    public static final int VECTOR_F64X2_MUL = 0xF2;
    +    public static final int VECTOR_F64X2_DIV = 0xF3;
    +    public static final int VECTOR_F64X2_MIN = 0xF4;
    +    public static final int VECTOR_F64X2_MAX = 0xF5;
    +    public static final int VECTOR_F64X2_PMIN = 0xF6;
    +    public static final int VECTOR_F64X2_PMAX = 0xF7;
     
         public static final byte[] EMPTY_BYTES = {};
         public static final int COMMON_BYTECODE_OFFSET = Bytecode.I32_EQ - Instructions.I32_EQ;
    diff --git a/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/constants/Instructions.java b/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/constants/Instructions.java
    index 59f7865cc9a9..951f0b3b5b13 100644
    --- a/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/constants/Instructions.java
    +++ b/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/constants/Instructions.java
    @@ -348,8 +348,19 @@ public final class Instructions {
         public static final int VECTOR = 0xFD;
     
         public static final int VECTOR_V128_CONST = 0x0C;
    +    public static final int VECTOR_V128_ANY_TRUE = 0x53;
         public static final int VECTOR_I32X4_ALL_TRUE = 0xA3;
         public static final int VECTOR_I32X4_ADD = 0xAE;
    +    public static final int VECTOR_I32X4_SUB = 0xB1;
    +    public static final int VECTOR_I32X4_MUL = 0xB5;
    +    public static final int VECTOR_F64X2_ADD = 0xF0;
    +    public static final int VECTOR_F64X2_SUB = 0xF1;
    +    public static final int VECTOR_F64X2_MUL = 0xF2;
    +    public static final int VECTOR_F64X2_DIV = 0xF3;
    +    public static final int VECTOR_F64X2_MIN = 0xF4;
    +    public static final int VECTOR_F64X2_MAX = 0xF5;
    +    public static final int VECTOR_F64X2_PMIN = 0xF6;
    +    public static final int VECTOR_F64X2_PMAX = 0xF7;
     
         // GraalWasm specific opcodes (these are reserved for future webassembly extensions and might be
         // used in other ways in the future)
    diff --git a/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/nodes/WasmFunctionNode.java b/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/nodes/WasmFunctionNode.java
    index 3ae382bc4702..eb95b221c2ac 100644
    --- a/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/nodes/WasmFunctionNode.java
    +++ b/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/nodes/WasmFunctionNode.java
    @@ -79,6 +79,7 @@
     import org.graalvm.wasm.WasmTable;
     import org.graalvm.wasm.WasmType;
     import org.graalvm.wasm.api.Vector128;
    +import org.graalvm.wasm.api.VectorOperators;
     import org.graalvm.wasm.constants.Bytecode;
     import org.graalvm.wasm.constants.BytecodeBitEncoding;
     import org.graalvm.wasm.exception.Failure;
    @@ -1731,11 +1732,54 @@ public Object executeBodyFromOffset(WasmContext context, WasmInstance instance,
                                 pushVector128(frame, stackPointer, value);
                                 stackPointer++;
                                 break;
    +                        case Bytecode.VECTOR_V128_ANY_TRUE:
    +                            v128_any_true(frame, stackPointer);
    +                            break;
                             case Bytecode.VECTOR_I32X4_ALL_TRUE:
                                 i32x4_all_true(frame, stackPointer);
                                 break;
                             case Bytecode.VECTOR_I32X4_ADD:
    -                            i32x4_add(frame, stackPointer);
    +                            i32x4_vibinop(frame, stackPointer, VectorOperators.VIBinOp.Add);
    +                            stackPointer--;
    +                            break;
    +                        case Bytecode.VECTOR_I32X4_SUB:
    +                            i32x4_vibinop(frame, stackPointer, VectorOperators.VIBinOp.Sub);
    +                            stackPointer--;
    +                            break;
    +                        case Bytecode.VECTOR_I32X4_MUL:
    +                            i32x4_mul(frame, stackPointer);
    +                            stackPointer--;
    +                            break;
    +                        case Bytecode.VECTOR_F64X2_ADD:
    +                            f64x2_vfbinop(frame, stackPointer, VectorOperators.VFBinOp.Add);
    +                            stackPointer--;
    +                            break;
    +                        case Bytecode.VECTOR_F64X2_SUB:
    +                            f64x2_vfbinop(frame, stackPointer, VectorOperators.VFBinOp.Sub);
    +                            stackPointer--;
    +                            break;
    +                        case Bytecode.VECTOR_F64X2_MUL:
    +                            f64x2_vfbinop(frame, stackPointer, VectorOperators.VFBinOp.Mul);
    +                            stackPointer--;
    +                            break;
    +                        case Bytecode.VECTOR_F64X2_DIV:
    +                            f64x2_vfbinop(frame, stackPointer, VectorOperators.VFBinOp.Div);
    +                            stackPointer--;
    +                            break;
    +                        case Bytecode.VECTOR_F64X2_MIN:
    +                            f64x2_vfbinop(frame, stackPointer, VectorOperators.VFBinOp.Min);
    +                            stackPointer--;
    +                            break;
    +                        case Bytecode.VECTOR_F64X2_MAX:
    +                            f64x2_vfbinop(frame, stackPointer, VectorOperators.VFBinOp.Max);
    +                            stackPointer--;
    +                            break;
    +                        case Bytecode.VECTOR_F64X2_PMIN:
    +                            f64x2_vfbinop(frame, stackPointer, VectorOperators.VFBinOp.Pmin);
    +                            stackPointer--;
    +                            break;
    +                        case Bytecode.VECTOR_F64X2_PMAX:
    +                            f64x2_vfbinop(frame, stackPointer, VectorOperators.VFBinOp.Pmax);
                                 stackPointer--;
                                 break;
                             default:
    @@ -3835,12 +3879,26 @@ private void memory_copy(WasmInstance instance, long length, long source, long d
             destMemory.copyFrom(srcMemory, source, destination, length);
         }
     
    +    @ExplodeLoop(kind = ExplodeLoop.LoopExplosionKind.FULL_UNROLL)
    +    private static void v128_any_true(VirtualFrame frame, int stackPointer) {
    +        byte[] bytes = popVector128(frame, stackPointer - 1).asBytes();
    +        int result = 0;
    +        for (int i = 0; i < 16; i++) {
    +            if (bytes[i] != 0) {
    +                result = 1;
    +                break;
    +            }
    +        }
    +        pushInt(frame, stackPointer - 1, result);
    +    }
    +
         @ExplodeLoop(kind = ExplodeLoop.LoopExplosionKind.FULL_UNROLL)
         private static void i32x4_all_true(VirtualFrame frame, int stackPointer) {
    -        int[] x = popVector128(frame, stackPointer - 1).asInts();
    +        int[] ints = popVector128(frame, stackPointer - 1).asInts();
    +        CompilerDirectives.ensureVirtualized(ints);
             int result = 1;
             for (int i = 0; i < 4; i++) {
    -            if (x[i] == 0) {
    +            if (ints[i] == 0) {
                     result = 0;
                     break;
                 }
    @@ -3849,16 +3907,59 @@ private static void i32x4_all_true(VirtualFrame frame, int stackPointer) {
         }
     
         @ExplodeLoop
    -    private static void i32x4_add(VirtualFrame frame, int stackPointer) {
    +    private static void i32x4_vibinop(VirtualFrame frame, int stackPointer, VectorOperators.VIBinOp operator) {
    +        int[] x = popVector128(frame, stackPointer - 1).asInts();
    +        int[] y = popVector128(frame, stackPointer - 2).asInts();
    +        int[] result = new int[4];
    +        CompilerDirectives.ensureVirtualized(x);
    +        CompilerDirectives.ensureVirtualized(y);
    +        CompilerDirectives.ensureVirtualized(result);
    +        for (int i = 0; i < 4; i++) {
    +            result[i] = switch (operator) {
    +                case Add -> y[i] + x[i];
    +                case Sub -> y[i] - x[i];
    +            };
    +        }
    +        pushVector128(frame, stackPointer - 2, Vector128.ofInts(result));
    +    }
    +
    +    @ExplodeLoop
    +    private static void i32x4_mul(VirtualFrame frame, int stackPointer) {
             int[] x = popVector128(frame, stackPointer - 1).asInts();
             int[] y = popVector128(frame, stackPointer - 2).asInts();
             int[] result = new int[4];
    +        CompilerDirectives.ensureVirtualized(x);
    +        CompilerDirectives.ensureVirtualized(y);
    +        CompilerDirectives.ensureVirtualized(result);
             for (int i = 0; i < 4; i++) {
    -            result[i] = y[i] + x[i];
    +            result[i] = y[i] * x[i];
             }
             pushVector128(frame, stackPointer - 2, Vector128.ofInts(result));
         }
     
    +    @ExplodeLoop
    +    private static void f64x2_vfbinop(VirtualFrame frame, int stackPointer, VectorOperators.VFBinOp operator) {
    +        double[] x = popVector128(frame, stackPointer - 1).asDoubles();
    +        double[] y = popVector128(frame, stackPointer - 2).asDoubles();
    +        double[] result = new double[2];
    +        CompilerDirectives.ensureVirtualized(x);
    +        CompilerDirectives.ensureVirtualized(y);
    +        CompilerDirectives.ensureVirtualized(result);
    +        for (int i = 0; i < 2; i++) {
    +            result[i] = switch (operator) {
    +                case Add -> y[i] + x[i];
    +                case Sub -> y[i] - x[i];
    +                case Mul -> y[i] * x[i];
    +                case Div -> y[i] / x[i];
    +                case Min -> Math.min(y[i], x[i]);
    +                case Max -> Math.max(y[i], x[i]);
    +                case Pmin -> x[i] < y[i] ? x[i] : y[i];
    +                case Pmax -> y[i] < x[i] ? x[i] : y[i];
    +            };
    +        }
    +        pushVector128(frame, stackPointer - 2, Vector128.ofDoubles(result));
    +    }
    +
         // Checkstyle: resume method name check
     
         private static boolean checkOutOfBounds(long offset, long length, long size) {
    
    From ec1620008a77b2007c4f1d87c9fb953ca1491b99 Mon Sep 17 00:00:00 2001
    From: Jirka Marsik 
    Date: Sun, 17 Dec 2023 14:56:08 +0100
    Subject: [PATCH 278/593] Support Vector128 values in globals
    
    ---
     .../org/graalvm/wasm/test/WasmFileSuite.java  |  2 +-
     .../src/org/graalvm/wasm/BinaryParser.java    | 71 +++++++++-------
     .../src/org/graalvm/wasm/GlobalRegistry.java  | 84 +++++++++++++------
     .../src/org/graalvm/wasm/Linker.java          | 35 ++++----
     .../src/org/graalvm/wasm/SymbolTable.java     | 41 ++++-----
     .../src/org/graalvm/wasm/WasmContext.java     |  2 +-
     .../org/graalvm/wasm/WasmInstantiator.java    | 12 +--
     .../src/org/graalvm/wasm/api/WebAssembly.java | 10 +--
     .../org/graalvm/wasm/constants/Bytecode.java  |  2 +-
     .../wasm/globals/DefaultWasmGlobal.java       | 18 ++--
     .../wasm/globals/ExportedWasmGlobal.java      |  8 +-
     .../org/graalvm/wasm/globals/WasmGlobal.java  |  4 +-
     .../graalvm/wasm/nodes/WasmFunctionNode.java  |  8 +-
     .../wasm/parser/bytecode/BytecodeParser.java  | 11 +--
     .../wasm/predefined/BuiltinModule.java        |  2 +-
     15 files changed, 163 insertions(+), 147 deletions(-)
    
    diff --git a/wasm/src/org.graalvm.wasm.test/src/org/graalvm/wasm/test/WasmFileSuite.java b/wasm/src/org.graalvm.wasm.test/src/org/graalvm/wasm/test/WasmFileSuite.java
    index 9df54c0faecf..208e81bebe3a 100644
    --- a/wasm/src/org.graalvm.wasm.test/src/org/graalvm/wasm/test/WasmFileSuite.java
    +++ b/wasm/src/org.graalvm.wasm.test/src/org/graalvm/wasm/test/WasmFileSuite.java
    @@ -571,7 +571,7 @@ protected String suiteName() {
     
         private static ContextState saveContext(WasmContext context) {
             final MemoryRegistry memories = context.memories().duplicate();
    -        final GlobalRegistry globals = context.globals().duplicate(context.getContextOptions().supportBulkMemoryAndRefTypes());
    +        final GlobalRegistry globals = context.globals().duplicate();
             return new ContextState(memories, globals, context.fdManager().size());
         }
     
    diff --git a/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/BinaryParser.java b/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/BinaryParser.java
    index 3d16872e8179..0314f7011ff3 100644
    --- a/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/BinaryParser.java
    +++ b/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/BinaryParser.java
    @@ -68,13 +68,13 @@
     import java.nio.charset.CodingErrorAction;
     import java.nio.charset.StandardCharsets;
     import java.util.ArrayList;
    +import java.util.List;
     
     import com.oracle.truffle.api.CompilerDirectives;
     import org.graalvm.collections.EconomicMap;
     import org.graalvm.collections.Pair;
     import org.graalvm.wasm.api.Vector128;
     import org.graalvm.wasm.collection.ByteArrayList;
    -import org.graalvm.wasm.collection.LongArrayList;
     import org.graalvm.wasm.constants.Bytecode;
     import org.graalvm.wasm.constants.ExportIdentifier;
     import org.graalvm.wasm.constants.GlobalModifier;
    @@ -1805,7 +1805,7 @@ private void readNumericInstructions(ParserState state, int opcode) {
                         case Instructions.VECTOR_V128_CONST:
                             final Vector128 value = readUnsignedInt128();
                             state.push(V128_TYPE);
    -                        state.addInstruction(Bytecode.VECTOR_V128_CONST_I128, value);
    +                        state.addInstruction(Bytecode.VECTOR_V128_CONST, value);
                             break;
                         case Instructions.VECTOR_V128_ANY_TRUE:
                         case Instructions.VECTOR_I32X4_ALL_TRUE:
    @@ -1983,25 +1983,30 @@ private Pair readOffsetExpression() {
             // Table offset expression must be a constant expression with result type i32.
             // https://webassembly.github.io/spec/core/syntax/modules.html#element-segments
             // https://webassembly.github.io/spec/core/valid/instructions.html#constant-expressions
    -        Pair result = readConstantExpression(I32_TYPE, false);
    +        Pair result = readConstantExpression(I32_TYPE, false);
             if (result.getRight() == null) {
    -            return Pair.create((int) (long) result.getLeft(), null);
    +            return Pair.create((int) result.getLeft(), null);
             } else {
                 return Pair.create(-1, result.getRight());
             }
         }
     
         private Pair readLongOffsetExpression() {
    -        return readConstantExpression(I64_TYPE, false);
    +        Pair result = readConstantExpression(I64_TYPE, false);
    +        if (result.getRight() == null) {
    +            return Pair.create((long) result.getLeft(), null);
    +        } else {
    +            return Pair.create(-1L, result.getRight());
    +        }
         }
     
    -    private Pair readConstantExpression(byte resultType, boolean onlyImportedGlobals) {
    +    private Pair readConstantExpression(byte resultType, boolean onlyImportedGlobals) {
             // Read the constant expression.
             // https://webassembly.github.io/spec/core/valid/instructions.html#constant-expressions
             final RuntimeBytecodeGen bytecode = new RuntimeBytecodeGen();
             final ParserState state = new ParserState(bytecode);
     
    -        final LongArrayList stack = new LongArrayList();
    +        final List stack = new ArrayList<>();
             boolean calculable = true;
     
             state.enterFunction(new byte[]{resultType});
    @@ -2027,18 +2032,29 @@ private Pair readConstantExpression(byte resultType, boolean onlyI
                         break;
                     }
                     case Instructions.F32_CONST: {
    -                    final int value = readFloatAsInt32();
    +                    final int rawValue = readFloatAsInt32();
    +                    final float value = Float.intBitsToFloat(rawValue);
                         state.push(F32_TYPE);
    -                    state.addInstruction(Bytecode.F32_CONST, value);
    +                    state.addInstruction(Bytecode.F32_CONST, rawValue);
                         if (calculable) {
                             stack.add(value);
                         }
                         break;
                     }
                     case Instructions.F64_CONST: {
    -                    final long value = readFloatAsInt64();
    +                    final long rawValue = readFloatAsInt64();
    +                    final double value = Double.longBitsToDouble(rawValue);
                         state.push(F64_TYPE);
    -                    state.addInstruction(Bytecode.F64_CONST, value);
    +                    state.addInstruction(Bytecode.F64_CONST, rawValue);
    +                    if (calculable) {
    +                        stack.add(value);
    +                    }
    +                    break;
    +                }
    +                case Instructions.VECTOR_V128_CONST: {
    +                    final Vector128 value = readUnsignedInt128();
    +                    state.push(V128_TYPE);
    +                    state.addInstruction(Bytecode.VECTOR_V128_CONST, value);
                         if (calculable) {
                             stack.add(value);
                         }
    @@ -2050,7 +2066,7 @@ private Pair readConstantExpression(byte resultType, boolean onlyI
                         state.push(type);
                         state.addInstruction(Bytecode.REF_NULL);
                         if (calculable) {
    -                        stack.add(0);
    +                        stack.add(null);
                         }
                         break;
                     case Instructions.REF_FUNC:
    @@ -2086,8 +2102,8 @@ private Pair readConstantExpression(byte resultType, boolean onlyI
                         state.push(I32_TYPE);
                         state.addInstruction(opcode + Bytecode.COMMON_BYTECODE_OFFSET);
                         if (calculable) {
    -                        int x = (int) stack.popBack();
    -                        int y = (int) stack.popBack();
    +                        int x = (int) stack.removeLast();
    +                        int y = (int) stack.removeLast();
                             stack.add(switch (opcode) {
                                 case Instructions.I32_ADD -> y + x;
                                 case Instructions.I32_SUB -> y - x;
    @@ -2107,8 +2123,8 @@ private Pair readConstantExpression(byte resultType, boolean onlyI
                         state.push(I64_TYPE);
                         state.addInstruction(opcode + Bytecode.COMMON_BYTECODE_OFFSET);
                         if (calculable) {
    -                        long x = stack.popBack();
    -                        long y = stack.popBack();
    +                        long x = (long) stack.removeLast();
    +                        long y = (long) stack.removeLast();
                             stack.add(switch (opcode) {
                                 case Instructions.I64_ADD -> y + x;
                                 case Instructions.I64_SUB -> y - x;
    @@ -2125,9 +2141,9 @@ private Pair readConstantExpression(byte resultType, boolean onlyI
             assertIntEqual(state.valueStackSize(), 1, "Multiple results on stack at constant expression end", Failure.TYPE_MISMATCH);
             state.exit(multiValue);
             if (calculable) {
    -            return Pair.create(stack.popBack(), null);
    +            return Pair.create(stack.removeLast(), null);
             } else {
    -            return Pair.create(-1L, bytecode.toArray());
    +            return Pair.create(null, bytecode.toArray());
             }
         }
     
    @@ -2161,6 +2177,7 @@ private long[] readElemExpressions(byte elemType) {
                     case Instructions.I64_CONST:
                     case Instructions.F32_CONST:
                     case Instructions.F64_CONST:
    +                case Instructions.VECTOR_V128_CONST:
                         throw WasmException.format(Failure.TYPE_MISMATCH, "Invalid constant expression for table elem expression: 0x%02X", opcode);
                     case Instructions.I32_ADD:
                     case Instructions.I32_SUB:
    @@ -2349,24 +2366,16 @@ private void readGlobalSection() {
                 final byte mutability = readMutability();
                 // Global initialization expressions must be constant expressions:
                 // https://webassembly.github.io/spec/core/valid/instructions.html#constant-expressions
    -            Pair initExpression = readConstantExpression(type, true);
    -            final long value = initExpression.getLeft();
    +            Pair initExpression = readConstantExpression(type, true);
    +            final Object initValue = initExpression.getLeft();
                 final byte[] initBytecode = initExpression.getRight();
                 final boolean isInitialized = initBytecode == null;
    -            final boolean isReference = WasmType.isReferenceType(type);
     
    -            module.symbolTable().declareGlobal(globalIndex, type, mutability, isInitialized, isReference, initBytecode, value);
    +            module.symbolTable().declareGlobal(globalIndex, type, mutability, isInitialized, initBytecode, initValue);
                 final int currentGlobalIndex = globalIndex;
                 module.addLinkAction((context, instance) -> {
    -                final GlobalRegistry globals = context.globals();
    -                final int address = instance.globalAddress(currentGlobalIndex);
                     if (isInitialized) {
    -                    if (isReference) {
    -                        // Only null is possible
    -                        globals.storeReference(address, WasmConstant.NULL);
    -                    } else {
    -                        globals.storeLong(address, value);
    -                    }
    +                    context.globals().store(type, instance.globalAddress(currentGlobalIndex), initValue);
                         context.linker().resolveGlobalInitialization(instance, currentGlobalIndex);
                     } else {
                         context.linker().resolveGlobalInitialization(context, instance, currentGlobalIndex, initBytecode);
    @@ -2422,7 +2431,7 @@ private void readDataSection(RuntimeBytecodeGen bytecode) {
                             offsetBytecode = offsetExpression.getRight();
                         }
                     } else {
    -                    offsetAddress = 0;
    +                    offsetAddress = -1;
                         offsetBytecode = null;
                     }
                 } else {
    diff --git a/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/GlobalRegistry.java b/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/GlobalRegistry.java
    index 0f7a60b8355c..74d50c8e24dd 100644
    --- a/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/GlobalRegistry.java
    +++ b/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/GlobalRegistry.java
    @@ -40,6 +40,8 @@
      */
     package org.graalvm.wasm;
     
    +import com.oracle.truffle.api.CompilerDirectives;
    +import org.graalvm.wasm.api.Vector128;
     import org.graalvm.wasm.exception.Failure;
     import org.graalvm.wasm.exception.WasmException;
     import org.graalvm.wasm.globals.WasmGlobal;
    @@ -62,18 +64,14 @@ public class GlobalRegistry {
         // Such an assumption can be invalidated if the late-linking causes this array
         // to be replaced with a larger array.
         @CompilationFinal(dimensions = 0) private long[] globals;
    -    @CompilationFinal(dimensions = 0) private Object[] globalReferences;
    +    @CompilationFinal(dimensions = 0) private Object[] objectGlobals;
         @CompilationFinal(dimensions = 1) private WasmGlobal[] externalGlobals;
         private int globalCount;
         private int externalGlobalCount;
     
    -    public GlobalRegistry(boolean useReferenceTypes) {
    +    public GlobalRegistry() {
             this.globals = new long[INITIAL_GLOBALS_SIZE];
    -        if (useReferenceTypes) {
    -            this.globalReferences = new Object[INITIAL_GLOBALS_SIZE];
    -        } else {
    -            this.globalReferences = null;
    -        }
    +        this.objectGlobals = new Object[INITIAL_GLOBALS_SIZE];
             this.externalGlobals = new WasmGlobal[INITIAL_GLOBALS_SIZE];
             this.globalCount = 0;
             this.externalGlobalCount = 0;
    @@ -88,11 +86,9 @@ private void ensureGlobalCapacity() {
                 final long[] nGlobals = new long[globals.length * 2];
                 System.arraycopy(globals, 0, nGlobals, 0, globals.length);
                 globals = nGlobals;
    -            if (globalReferences != null) {
    -                final Object[] nGlobalReferences = new Object[globalReferences.length * 2];
    -                System.arraycopy(globalReferences, 0, nGlobalReferences, 0, globalReferences.length);
    -                globalReferences = nGlobalReferences;
    -            }
    +            final Object[] nObjectGlobals = new Object[objectGlobals.length * 2];
    +            System.arraycopy(objectGlobals, 0, nObjectGlobals, 0, objectGlobals.length);
    +            objectGlobals = nObjectGlobals;
             }
         }
     
    @@ -107,9 +103,7 @@ private void ensureExternalGlobalCapacity() {
         public int allocateGlobal() {
             ensureGlobalCapacity();
             globals[globalCount] = 0;
    -        if (globalReferences != null) {
    -            globalReferences[globalCount] = null;
    -        }
    +        objectGlobals[globalCount] = null;
             int idx = globalCount;
             globalCount++;
             return idx;
    @@ -135,13 +129,46 @@ public long loadAsLong(int address) {
             return globals[address];
         }
     
    +    public Vector128 loadAsVector128(int address) {
    +        return (Vector128) loadAsObject(address);
    +    }
    +
         public Object loadAsReference(int address) {
    -        assert globalReferences != null;
    +        return loadAsObject(address);
    +    }
    +
    +    public Object loadAsObject(int address) {
             if (address < 0) {
                 final WasmGlobal global = externalGlobals[-address - 1];
    -            return global.loadAsReference();
    +            return global.loadAsObject();
    +        }
    +        return objectGlobals[address];
    +    }
    +
    +    public void store(byte globalValueType, int address, Object value) {
    +        switch (globalValueType) {
    +            case WasmType.I32_TYPE:
    +                storeInt(address, (int) value);
    +                break;
    +            case WasmType.I64_TYPE:
    +                storeLong(address, (long) value);
    +                break;
    +            case WasmType.F32_TYPE:
    +                storeInt(address, Float.floatToRawIntBits((float) value));
    +                break;
    +            case WasmType.F64_TYPE:
    +                storeLong(address, Double.doubleToRawLongBits((double) value));
    +                break;
    +            case WasmType.V128_TYPE:
    +                storeVector128(address, (Vector128) value);
    +                break;
    +            case WasmType.FUNCREF_TYPE:
    +            case WasmType.EXTERNREF_TYPE:
    +                storeReference(address, value);
    +                break;
    +            default:
    +                throw CompilerDirectives.shouldNotReachHere();
             }
    -        return globalReferences[address];
         }
     
         public void storeInt(int address, int value) {
    @@ -157,24 +184,31 @@ public void storeLong(int address, long value) {
             }
         }
     
    +    public void storeVector128(int address, Vector128 value) {
    +        storeObject(address, value);
    +    }
    +
         public void storeReference(int address, Object value) {
    -        assert globalReferences != null;
    +        storeObject(address, value);
    +    }
    +
    +    public void storeObject(int address, Object value) {
             if (address < 0) {
                 final WasmGlobal global = externalGlobals[-address - 1];
    -            global.storeReference(value);
    +            global.storeObject(value);
             } else {
    -            globalReferences[address] = value;
    +            objectGlobals[address] = value;
             }
         }
     
    -    public GlobalRegistry duplicate(boolean useReferenceTypes) {
    -        final GlobalRegistry other = new GlobalRegistry(useReferenceTypes);
    +    public GlobalRegistry duplicate() {
    +        final GlobalRegistry other = new GlobalRegistry();
             for (int i = 0; i < globalCount; i++) {
                 final int address = other.allocateGlobal();
                 final long value = this.loadAsLong(address);
    -            final Object referenceValue = this.loadAsReference(address);
    +            final Object objectValue = this.loadAsObject(address);
                 other.storeLong(address, value);
    -            other.storeReference(address, referenceValue);
    +            other.storeObject(address, objectValue);
             }
             for (int i = 0; i < externalGlobalCount; i++) {
                 other.allocateExternalGlobal(this.externalGlobals[i]);
    diff --git a/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/Linker.java b/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/Linker.java
    index 4420d8b550e6..d961e5a89426 100644
    --- a/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/Linker.java
    +++ b/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/Linker.java
    @@ -48,6 +48,7 @@
     import static org.graalvm.wasm.Assert.assertUnsignedLongGreaterOrEqual;
     import static org.graalvm.wasm.Assert.assertUnsignedLongLessOrEqual;
     import static org.graalvm.wasm.Assert.fail;
    +import static org.graalvm.wasm.BinaryStreamParser.rawPeekI128;
     import static org.graalvm.wasm.BinaryStreamParser.rawPeekI32;
     import static org.graalvm.wasm.BinaryStreamParser.rawPeekI64;
     import static org.graalvm.wasm.BinaryStreamParser.rawPeekI8;
    @@ -59,6 +60,7 @@
     import static org.graalvm.wasm.WasmType.FUNCREF_TYPE;
     import static org.graalvm.wasm.WasmType.I32_TYPE;
     import static org.graalvm.wasm.WasmType.I64_TYPE;
    +import static org.graalvm.wasm.WasmType.V128_TYPE;
     
     import java.util.ArrayList;
     import java.util.Comparator;
    @@ -87,6 +89,7 @@
     import org.graalvm.wasm.Linker.ResolutionDag.Resolver;
     import org.graalvm.wasm.Linker.ResolutionDag.Sym;
     import org.graalvm.wasm.SymbolTable.FunctionType;
    +import org.graalvm.wasm.api.Vector128;
     import org.graalvm.wasm.constants.Bytecode;
     import org.graalvm.wasm.constants.BytecodeBitEncoding;
     import org.graalvm.wasm.constants.GlobalModifier;
    @@ -315,26 +318,7 @@ void resolveGlobalInitialization(WasmInstance instance, int globalIndex) {
     
         public static void initializeGlobal(WasmContext context, WasmInstance instance, int globalIndex, byte[] initBytecode) {
             Object initValue = evalConstantExpression(context, instance, initBytecode);
    -        final int address = instance.globalAddress(globalIndex);
    -        final GlobalRegistry globals = context.globals();
    -        switch (instance.module().globalValueType(globalIndex)) {
    -            case I32_TYPE:
    -                globals.storeInt(address, (int) initValue);
    -                break;
    -            case I64_TYPE:
    -                globals.storeLong(address, (long) initValue);
    -                break;
    -            case F32_TYPE:
    -                globals.storeInt(address, Float.floatToIntBits((float) initValue));
    -                break;
    -            case F64_TYPE:
    -                globals.storeLong(address, Double.doubleToLongBits((double) initValue));
    -                break;
    -            case FUNCREF_TYPE:
    -            case EXTERNREF_TYPE:
    -                globals.storeReference(address, initValue);
    -                break;
    -        }
    +        context.globals().store(instance.module().globalValueType(globalIndex), instance.globalAddress(globalIndex), initValue);
         }
     
         void resolveGlobalInitialization(WasmContext context, WasmInstance instance, int globalIndex, byte[] initBytecode) {
    @@ -455,6 +439,8 @@ private static Object lookupGlobal(WasmContext context, WasmInstance instance, i
                     return context.globals().loadAsLong(globalAddress);
                 case F64_TYPE:
                     return Double.longBitsToDouble(context.globals().loadAsLong(globalAddress));
    +            case V128_TYPE:
    +                return context.globals().loadAsVector128(globalAddress);
                 case FUNCREF_TYPE:
                 case EXTERNREF_TYPE:
                     return context.globals().loadAsReference(globalAddress);
    @@ -518,6 +504,12 @@ public static Object evalConstantExpression(WasmContext context, WasmInstance in
                         stack.add(value);
                         break;
                     }
    +                case Bytecode.VECTOR_V128_CONST: {
    +                    Vector128 value = rawPeekI128(bytecode, offset);
    +                    offset += 16;
    +                    stack.add(value);
    +                    break;
    +                }
                     case Bytecode.REF_NULL:
                         stack.add(WasmConstant.NULL);
                         break;
    @@ -596,6 +588,9 @@ private static List dependenciesOfConstantExpression(WasmInstance instance,
                     case Bytecode.F64_CONST:
                         offset += 8;
                         break;
    +                case Bytecode.VECTOR_V128_CONST:
    +                    offset += 16;
    +                    break;
                     case Bytecode.REF_FUNC:
                         final int functionIndex = rawPeekI32(bytecode, offset);
                         final WasmFunction function = instance.symbolTable().function(functionIndex);
    diff --git a/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/SymbolTable.java b/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/SymbolTable.java
    index c7f819506e3c..a7370a8830c5 100644
    --- a/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/SymbolTable.java
    +++ b/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/SymbolTable.java
    @@ -81,7 +81,6 @@ public abstract class SymbolTable {
         private static final byte GLOBAL_MUTABLE_BIT = 0x01;
         private static final byte GLOBAL_EXPORT_BIT = 0x02;
         private static final byte GLOBAL_INITIALIZED_BIT = 0x04;
    -    private static final byte GLOBAL_REFERENCE_BIT = 0x08;
         private static final byte GLOBAL_IMPORTED_BIT = 0x10;
         private static final byte GLOBAL_FUNCTION_INITIALIZER_BIT = 0x20;
     
    @@ -311,7 +310,7 @@ public MemoryInfo(long initialSize, long maximumSize, boolean indexType64, boole
         /**
          * The values or indices used for initializing globals.
          */
    -    @CompilationFinal(dimensions = 1) private long[] globalInitializers;
    +    @CompilationFinal(dimensions = 1) private Object[] globalInitializers;
     
         /**
          * The bytecodes used for initializing globals.
    @@ -429,7 +428,7 @@ public MemoryInfo(long initialSize, long maximumSize, boolean indexType64, boole
             this.exportedFunctionsByIndex = EconomicMap.create();
             this.startFunctionIndex = -1;
             this.globalTypes = new byte[2 * INITIAL_GLOBALS_SIZE];
    -        this.globalInitializers = new long[INITIAL_GLOBALS_SIZE];
    +        this.globalInitializers = new Object[INITIAL_GLOBALS_SIZE];
             this.globalInitializersBytecode = new byte[INITIAL_GLOBALS_BYTECODE_SIZE][];
             this.importedGlobals = EconomicMap.create();
             this.exportedGlobals = EconomicMap.create();
    @@ -750,7 +749,7 @@ public WasmFunction importedFunction(ImportDescriptor descriptor) {
         private void ensureGlobalsCapacity(int index) {
             while (index >= globalInitializers.length) {
                 final byte[] nGlobalTypes = new byte[globalTypes.length * 2];
    -            final long[] nGlobalInitializers = new long[globalInitializers.length * 2];
    +            final Object[] nGlobalInitializers = new Object[globalInitializers.length * 2];
                 System.arraycopy(globalTypes, 0, nGlobalTypes, 0, globalTypes.length);
                 System.arraycopy(globalInitializers, 0, nGlobalInitializers, 0, globalInitializers.length);
                 globalTypes = nGlobalTypes;
    @@ -770,7 +769,7 @@ private void ensureGlobalInitializersBytecodeCapacity(int index) {
          * Allocates a global index in the symbol table, for a global variable that was already
          * allocated.
          */
    -    void allocateGlobal(int index, byte valueType, byte mutability, boolean initialized, boolean isReference, boolean imported, byte[] initBytecode, long initialValue) {
    +    void allocateGlobal(int index, byte valueType, byte mutability, boolean initialized, boolean imported, byte[] initBytecode, Object initialValue) {
             assert (valueType & 0xff) == valueType;
             checkNotParsed();
             ensureGlobalsCapacity(index);
    @@ -786,9 +785,6 @@ void allocateGlobal(int index, byte valueType, byte mutability, boolean initiali
             if (initialized) {
                 flags |= GLOBAL_INITIALIZED_BIT;
             }
    -        if (isReference) {
    -            flags |= GLOBAL_REFERENCE_BIT;
    -        }
             if (imported) {
                 flags |= GLOBAL_IMPORTED_BIT;
             }
    @@ -808,19 +804,17 @@ void allocateGlobal(int index, byte valueType, byte mutability, boolean initiali
         void declareExternalGlobal(int index, WasmGlobal global) {
             final byte valueType = global.getValueType().byteValue();
             final byte mutability = global.isMutable() ? GlobalModifier.MUTABLE : GlobalModifier.CONSTANT;
    -        allocateGlobal(index, valueType, mutability, false, false, false, null, 0);
    +        allocateGlobal(index, valueType, mutability, false, false, null, null);
             module().addLinkAction((context, instance) -> {
    -            final GlobalRegistry globals = context.globals();
    -            final int address = globals.allocateExternalGlobal(global);
    +            final int address = context.globals().allocateExternalGlobal(global);
                 instance.setGlobalAddress(index, address);
             });
         }
     
    -    void declareGlobal(int index, byte valueType, byte mutability, boolean initialized, boolean isReference, byte[] initBytecode, long initialValue) {
    -        allocateGlobal(index, valueType, mutability, initialized, isReference, false, initBytecode, initialValue);
    +    void declareGlobal(int index, byte valueType, byte mutability, boolean initialized, byte[] initBytecode, Object initialValue) {
    +        allocateGlobal(index, valueType, mutability, initialized, false, initBytecode, initialValue);
             module().addLinkAction((context, instance) -> {
    -            final GlobalRegistry globals = context.globals();
    -            final int address = globals.allocateGlobal();
    +            final int address = context.globals().allocateGlobal();
                 instance.setGlobalAddress(index, address);
             });
         }
    @@ -829,7 +823,7 @@ void importGlobal(String moduleName, String globalName, int index, byte valueTyp
             final ImportDescriptor descriptor = new ImportDescriptor(moduleName, globalName, ImportIdentifier.GLOBAL);
             importedGlobals.put(index, descriptor);
             importSymbol(descriptor);
    -        allocateGlobal(index, valueType, mutability, false, false, true, null, 0);
    +        allocateGlobal(index, valueType, mutability, false, true, null, null);
             module().addLinkAction((context, instance) -> instance.setGlobalAddress(index, UNINITIALIZED_ADDRESS));
             module().addLinkAction((context, instance) -> context.linker().resolveGlobalImport(context, instance, descriptor, index, valueType, mutability));
         }
    @@ -871,10 +865,6 @@ public boolean globalInitialized(int index) {
             return (globalTypes[2 * index + 1] & GLOBAL_INITIALIZED_BIT) != 0;
         }
     
    -    public boolean globalIsReference(int index) {
    -        return (globalTypes[2 * index + 1] & GLOBAL_REFERENCE_BIT) != 0;
    -    }
    -
         public byte[] globalInitializerBytecode(int index) {
             if ((globalTypes[2 * index + 1] & GLOBAL_FUNCTION_INITIALIZER_BIT) != 0) {
                 return null;
    @@ -883,7 +873,7 @@ public byte[] globalInitializerBytecode(int index) {
             }
         }
     
    -    public long globalInitialValue(int index) {
    +    public Object globalInitialValue(int index) {
             if ((globalTypes[2 * index + 1] & GLOBAL_FUNCTION_INITIALIZER_BIT) != 0) {
                 return globalInitializers[index];
             } else {
    @@ -924,14 +914,11 @@ public void declareExportedExternalGlobal(String name, int index, WasmGlobal glo
             exportGlobal(name, index);
         }
     
    -    public void declareExportedGlobalWithValue(String name, int index, byte valueType, byte mutability, long value) {
    +    public void declareExportedGlobalWithValue(String name, int index, byte valueType, byte mutability, Object value) {
             checkNotParsed();
    -        declareGlobal(index, valueType, mutability, true, false, null, 0);
    +        declareGlobal(index, valueType, mutability, true, null, value);
             exportGlobal(name, index);
    -        module().addLinkAction((context, instance) -> {
    -            final int address = instance.globalAddress(index);
    -            context.globals().storeLong(address, value);
    -        });
    +        module().addLinkAction((context, instance) -> context.globals().store(valueType, instance.globalAddress(index), value));
         }
     
         private void ensureTableCapacity(int index) {
    diff --git a/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/WasmContext.java b/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/WasmContext.java
    index fa3ff18983d1..fca78769a116 100644
    --- a/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/WasmContext.java
    +++ b/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/WasmContext.java
    @@ -71,7 +71,7 @@ public WasmContext(Env env, WasmLanguage language) {
             this.env = env;
             this.language = language;
             this.contextOptions = WasmContextOptions.fromOptionValues(env.getOptions());
    -        this.globals = new GlobalRegistry(contextOptions.supportBulkMemoryAndRefTypes());
    +        this.globals = new GlobalRegistry();
             this.tableRegistry = new TableRegistry();
             this.memoryRegistry = new MemoryRegistry();
             this.moduleInstances = new LinkedHashMap<>();
    diff --git a/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/WasmInstantiator.java b/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/WasmInstantiator.java
    index a548a6161ead..deac5ddd2f65 100644
    --- a/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/WasmInstantiator.java
    +++ b/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/WasmInstantiator.java
    @@ -153,24 +153,16 @@ static List> recreateLinkActions(WasmModul
                     linkActions.add((context, instance) -> context.linker().resolveGlobalImport(context, instance, globalDescriptor, globalIndex, globalValueType, globalMutability));
                 } else {
                     final boolean initialized = module.globalInitialized(globalIndex);
    -                final boolean isReference = module.globalIsReference(globalIndex);
                     final byte[] initBytecode = module.globalInitializerBytecode(globalIndex);
    -                final long initialValue = module.globalInitialValue(globalIndex);
    +                final Object initialValue = module.globalInitialValue(globalIndex);
                     linkActions.add((context, instance) -> {
                         final GlobalRegistry registry = context.globals();
                         final int address = registry.allocateGlobal();
                         instance.setGlobalAddress(globalIndex, address);
                     });
                     linkActions.add((context, instance) -> {
    -                    final GlobalRegistry registry = context.globals();
    -                    final int address = instance.globalAddress(globalIndex);
                         if (initialized) {
    -                        if (isReference) {
    -                            // Only null is possible
    -                            registry.storeReference(address, WasmConstant.NULL);
    -                        } else {
    -                            registry.storeLong(address, initialValue);
    -                        }
    +                        context.globals().store(globalValueType, instance.globalAddress(globalIndex), initialValue);
                             context.linker().resolveGlobalInitialization(instance, globalIndex);
                         } else {
                             context.linker().resolveGlobalInitialization(context, instance, globalIndex, initBytecode);
    diff --git a/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/api/WebAssembly.java b/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/api/WebAssembly.java
    index 7abfd541e691..46c76d6b9858 100644
    --- a/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/api/WebAssembly.java
    +++ b/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/api/WebAssembly.java
    @@ -886,7 +886,7 @@ public static Object globalRead(WasmGlobal global) {
                     return Double.longBitsToDouble(global.loadAsLong());
                 case anyfunc:
                 case externref:
    -                return global.loadAsReference();
    +                return global.loadAsObject();
     
             }
             throw new WasmJsApiException(WasmJsApiException.Kind.TypeError, "Incorrect internal Global type");
    @@ -936,11 +936,11 @@ public Object globalWrite(WasmGlobal global, Object value) {
                         throw WasmJsApiException.format(WasmJsApiException.Kind.TypeError, "Invalid value type. Reference types are not enabled");
                     }
                     if (InteropLibrary.getUncached(value).isNull(value)) {
    -                    global.storeReference(WasmConstant.NULL);
    +                    global.storeObject(WasmConstant.NULL);
                     } else if (!(value instanceof WasmFunctionInstance)) {
                         throw WasmJsApiException.format(WasmJsApiException.Kind.TypeError, "Global type %s, value: %s", valueType, value);
                     } else {
    -                    global.storeReference(value);
    +                    global.storeObject(value);
                     }
                     break;
                 case externref:
    @@ -948,9 +948,9 @@ public Object globalWrite(WasmGlobal global, Object value) {
                         throw WasmJsApiException.format(WasmJsApiException.Kind.TypeError, "Invalid value type. Reference types are not enabled");
                     }
                     if (InteropLibrary.getUncached(value).isNull(value)) {
    -                    global.storeReference(WasmConstant.NULL);
    +                    global.storeObject(WasmConstant.NULL);
                     } else {
    -                    global.storeReference(value);
    +                    global.storeObject(value);
                     }
                     break;
             }
    diff --git a/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/constants/Bytecode.java b/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/constants/Bytecode.java
    index 73b8d8257bd5..af45b17e9939 100644
    --- a/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/constants/Bytecode.java
    +++ b/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/constants/Bytecode.java
    @@ -444,7 +444,7 @@ public class Bytecode {
         public static final int ATOMIC_WAIT64 = 0x42;
     
         // Vector opcodes
    -    public static final int VECTOR_V128_CONST_I128 = 0x0C;
    +    public static final int VECTOR_V128_CONST = 0x0C;
         public static final int VECTOR_V128_ANY_TRUE = 0x53;
         public static final int VECTOR_I32X4_ALL_TRUE = 0xA3;
         public static final int VECTOR_I32X4_ADD = 0xAE;
    diff --git a/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/globals/DefaultWasmGlobal.java b/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/globals/DefaultWasmGlobal.java
    index c6c7b44d6746..d5c6cc220047 100644
    --- a/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/globals/DefaultWasmGlobal.java
    +++ b/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/globals/DefaultWasmGlobal.java
    @@ -45,7 +45,7 @@
     
     public class DefaultWasmGlobal extends WasmGlobal {
         private long globalValue;
    -    private Object globalReferenceValue;
    +    private Object globalObjectValue;
     
         @SuppressWarnings("this-escape")
         public DefaultWasmGlobal(ValueType valueType, boolean mutable, int value) {
    @@ -62,7 +62,7 @@ public DefaultWasmGlobal(ValueType valueType, boolean mutable, long value) {
         @SuppressWarnings("this-escape")
         public DefaultWasmGlobal(ValueType valueType, boolean mutable, Object value) {
             super(valueType, mutable);
    -        storeReference(value);
    +        storeObject(value);
         }
     
         @Override
    @@ -78,10 +78,10 @@ public long loadAsLong() {
         }
     
         @Override
    -    public Object loadAsReference() {
    -        assert globalReferenceValue != null;
    -        assert ValueType.isReferenceType(getValueType());
    -        return globalReferenceValue;
    +    public Object loadAsObject() {
    +        assert globalObjectValue != null;
    +        assert ValueType.isReferenceType(getValueType()) || ValueType.isVectorType(getValueType());
    +        return globalObjectValue;
         }
     
         @Override
    @@ -97,8 +97,8 @@ public void storeLong(long value) {
         }
     
         @Override
    -    public void storeReference(Object value) {
    -        assert ValueType.isReferenceType(getValueType());
    -        this.globalReferenceValue = value;
    +    public void storeObject(Object value) {
    +        assert ValueType.isReferenceType(getValueType()) || ValueType.isVectorType(getValueType());
    +        this.globalObjectValue = value;
         }
     }
    diff --git a/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/globals/ExportedWasmGlobal.java b/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/globals/ExportedWasmGlobal.java
    index e2d034de0ec2..f80d295d16ce 100644
    --- a/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/globals/ExportedWasmGlobal.java
    +++ b/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/globals/ExportedWasmGlobal.java
    @@ -64,8 +64,8 @@ public long loadAsLong() {
         }
     
         @Override
    -    public Object loadAsReference() {
    -        return globals.loadAsReference(address);
    +    public Object loadAsObject() {
    +        return globals.loadAsObject(address);
         }
     
         @Override
    @@ -79,7 +79,7 @@ public void storeLong(long value) {
         }
     
         @Override
    -    public void storeReference(Object value) {
    -        globals.storeReference(address, value);
    +    public void storeObject(Object value) {
    +        globals.storeObject(address, value);
         }
     }
    diff --git a/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/globals/WasmGlobal.java b/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/globals/WasmGlobal.java
    index 4aa32314eddd..a85b4e05c7a3 100644
    --- a/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/globals/WasmGlobal.java
    +++ b/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/globals/WasmGlobal.java
    @@ -67,11 +67,11 @@ public boolean isMutable() {
     
         public abstract long loadAsLong();
     
    -    public abstract Object loadAsReference();
    +    public abstract Object loadAsObject();
     
         public abstract void storeInt(int value);
     
         public abstract void storeLong(long value);
     
    -    public abstract void storeReference(Object value);
    +    public abstract void storeObject(Object value);
     }
    diff --git a/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/nodes/WasmFunctionNode.java b/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/nodes/WasmFunctionNode.java
    index eb95b221c2ac..dc56e28c2f29 100644
    --- a/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/nodes/WasmFunctionNode.java
    +++ b/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/nodes/WasmFunctionNode.java
    @@ -1725,7 +1725,7 @@ public Object executeBodyFromOffset(WasmContext context, WasmInstance instance,
                         offset++;
                         CompilerAsserts.partialEvaluationConstant(vectorOpcode);
                         switch (vectorOpcode) {
    -                        case Bytecode.VECTOR_V128_CONST_I128:
    +                        case Bytecode.VECTOR_V128_CONST:
                                 final Vector128 value = rawPeekI128(bytecode, offset);
                                 offset += 16;
     
    @@ -2685,6 +2685,9 @@ private void global_set(WasmContext context, WasmInstance instance, VirtualFrame
                 case WasmType.F64_TYPE:
                     context.globals().storeLong(instance.globalAddress(index), Double.doubleToRawLongBits(popDouble(frame, stackPointer)));
                     break;
    +            case WasmType.V128_TYPE:
    +                context.globals().storeVector128(instance.globalAddress(index), popVector128(frame, stackPointer));
    +                break;
                 case WasmType.FUNCREF_TYPE:
                 case WasmType.EXTERNREF_TYPE:
                     context.globals().storeReference(instance.globalAddress(index), popReference(frame, stackPointer));
    @@ -2710,6 +2713,9 @@ private void global_get(WasmContext context, WasmInstance instance, VirtualFrame
                 case WasmType.F64_TYPE:
                     pushDouble(frame, stackPointer, Double.longBitsToDouble(context.globals().loadAsLong(instance.globalAddress(index))));
                     break;
    +            case WasmType.V128_TYPE:
    +                pushVector128(frame, stackPointer, context.globals().loadAsVector128(instance.globalAddress(index)));
    +                break;
                 case WasmType.FUNCREF_TYPE:
                 case WasmType.EXTERNREF_TYPE:
                     pushReference(frame, stackPointer, context.globals().loadAsReference(instance.globalAddress(index)));
    diff --git a/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/parser/bytecode/BytecodeParser.java b/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/parser/bytecode/BytecodeParser.java
    index a873f68762ec..584d8ede5918 100644
    --- a/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/parser/bytecode/BytecodeParser.java
    +++ b/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/parser/bytecode/BytecodeParser.java
    @@ -46,7 +46,6 @@
     import org.graalvm.wasm.BinaryStreamParser;
     import org.graalvm.wasm.GlobalRegistry;
     import org.graalvm.wasm.Linker;
    -import org.graalvm.wasm.WasmConstant;
     import org.graalvm.wasm.WasmContext;
     import org.graalvm.wasm.WasmInstance;
     import org.graalvm.wasm.WasmModule;
    @@ -83,14 +82,8 @@ public static void resetGlobalState(WasmContext context, WasmModule module, Wasm
                 if (module.globalImported(i)) {
                     continue;
                 }
    -            final int address = instance.globalAddress(i);
    -            final long value = module.globalInitialValue(i);
                 if (module.globalInitialized(i)) {
    -                if (module.globalIsReference(i)) {
    -                    globals.storeReference(address, WasmConstant.NULL);
    -                } else {
    -                    globals.storeLong(address, value);
    -                }
    +                globals.store(module.globalValueType(i), instance.globalAddress(i), module.globalInitialValue(i));
                 } else {
                     Linker.initializeGlobal(context, instance, i, module.globalInitializerBytecode(i));
                 }
    @@ -899,7 +892,7 @@ private static List readCallNodes(byte[] bytecode, int startOffset, in
                         final int vectorOpcode = rawPeekU8(bytecode, offset);
                         offset++;
                         switch (vectorOpcode) {
    -                        case Bytecode.VECTOR_V128_CONST_I128:
    +                        case Bytecode.VECTOR_V128_CONST:
                                 offset += 16;
                                 break;
                             case Bytecode.VECTOR_I32X4_ALL_TRUE:
    diff --git a/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/predefined/BuiltinModule.java b/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/predefined/BuiltinModule.java
    index cfed0af752ad..6b4e1a83cd1f 100644
    --- a/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/predefined/BuiltinModule.java
    +++ b/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/predefined/BuiltinModule.java
    @@ -134,7 +134,7 @@ protected int defineExternalGlobal(WasmModule module, String globalName, WasmGlo
             return index;
         }
     
    -    protected int defineGlobal(WasmModule module, String name, byte valueType, byte mutability, long value) {
    +    protected int defineGlobal(WasmModule module, String name, byte valueType, byte mutability, Object value) {
             int index = module.symbolTable().numGlobals();
             module.symbolTable().declareExportedGlobalWithValue(name, index, valueType, mutability, value);
             return index;
    
    From 6e675bd6da834648b72eec0af790191af541381e Mon Sep 17 00:00:00 2001
    From: Jirka Marsik 
    Date: Sun, 17 Dec 2023 17:48:12 +0100
    Subject: [PATCH 279/593] Fix common type handling for references and vectors
    
    ---
     .../wasm/test/suites/bytecode/BytecodeSuite.java       |  6 +++---
     .../src/org/graalvm/wasm/WasmType.java                 |  7 +++----
     .../src/org/graalvm/wasm/nodes/WasmFunctionNode.java   | 10 +++++-----
     .../wasm/parser/bytecode/RuntimeBytecodeGen.java       |  6 +++---
     4 files changed, 14 insertions(+), 15 deletions(-)
    
    diff --git a/wasm/src/org.graalvm.wasm.test/src/org/graalvm/wasm/test/suites/bytecode/BytecodeSuite.java b/wasm/src/org.graalvm.wasm.test/src/org/graalvm/wasm/test/suites/bytecode/BytecodeSuite.java
    index 8af97a3ff7b3..d842478257c9 100644
    --- a/wasm/src/org.graalvm.wasm.test/src/org/graalvm/wasm/test/suites/bytecode/BytecodeSuite.java
    +++ b/wasm/src/org.graalvm.wasm.test/src/org/graalvm/wasm/test/suites/bytecode/BytecodeSuite.java
    @@ -83,7 +83,7 @@ public void testLabelU8ResultNum() {
     
         @Test
         public void testLabelU8ResultRef() {
    -        test(b -> b.addLabel(1, 0, WasmType.REF_COMMON_TYPE), new byte[]{Bytecode.SKIP_LABEL_U8, Bytecode.LABEL_U8, (byte) 0xC0});
    +        test(b -> b.addLabel(1, 0, WasmType.OBJ_COMMON_TYPE), new byte[]{Bytecode.SKIP_LABEL_U8, Bytecode.LABEL_U8, (byte) 0xC0});
         }
     
         @Test
    @@ -98,7 +98,7 @@ public void testLabelU16ResultNum() {
     
         @Test
         public void testLabelU16ResultRef() {
    -        test(b -> b.addLabel(2, 0, WasmType.REF_COMMON_TYPE), new byte[]{Bytecode.SKIP_LABEL_U16, Bytecode.LABEL_U16, (byte) 0x82, 0x00});
    +        test(b -> b.addLabel(2, 0, WasmType.OBJ_COMMON_TYPE), new byte[]{Bytecode.SKIP_LABEL_U16, Bytecode.LABEL_U16, (byte) 0x82, 0x00});
         }
     
         @Test
    @@ -113,7 +113,7 @@ public void testLabelI32ResultNum() {
     
         @Test
         public void testLabelI32ResultRef() {
    -        test(b -> b.addLabel(64, 0, WasmType.REF_COMMON_TYPE), new byte[]{Bytecode.SKIP_LABEL_I32, Bytecode.LABEL_I32, 0x02, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00});
    +        test(b -> b.addLabel(64, 0, WasmType.OBJ_COMMON_TYPE), new byte[]{Bytecode.SKIP_LABEL_I32, Bytecode.LABEL_I32, 0x02, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00});
         }
     
         @Test
    diff --git a/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/WasmType.java b/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/WasmType.java
    index 0eb0c8844d08..b90c85f4988f 100644
    --- a/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/WasmType.java
    +++ b/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/WasmType.java
    @@ -96,9 +96,8 @@ public class WasmType implements TruffleObject {
          */
         public static final int NONE_COMMON_TYPE = 0;
         public static final int NUM_COMMON_TYPE = 1;
    -    public static final int VEC_COMMON_TYPE = 2;
    -    public static final int REF_COMMON_TYPE = 3;
    -    public static final int MIX_COMMON_TYPE = NUM_COMMON_TYPE | VEC_COMMON_TYPE | REF_COMMON_TYPE;
    +    public static final int OBJ_COMMON_TYPE = 2;
    +    public static final int MIX_COMMON_TYPE = NUM_COMMON_TYPE | OBJ_COMMON_TYPE;
     
         public static String toString(int valueType) {
             CompilerAsserts.neverPartOfCompilation();
    @@ -140,7 +139,7 @@ public static int getCommonValueType(byte[] types) {
             int type = 0;
             for (byte resultType : types) {
                 type |= WasmType.isNumberType(resultType) ? NUM_COMMON_TYPE : 0;
    -            type |= WasmType.isReferenceType(resultType) ? REF_COMMON_TYPE : 0;
    +            type |= WasmType.isVectorType(resultType) || WasmType.isReferenceType(resultType) ? OBJ_COMMON_TYPE : 0;
             }
             return type;
         }
    diff --git a/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/nodes/WasmFunctionNode.java b/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/nodes/WasmFunctionNode.java
    index dc56e28c2f29..02220f2f0acd 100644
    --- a/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/nodes/WasmFunctionNode.java
    +++ b/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/nodes/WasmFunctionNode.java
    @@ -336,8 +336,8 @@ public Object executeBodyFromOffset(WasmContext context, WasmInstance instance,
                             case BytecodeBitEncoding.LABEL_U16_RESULT_TYPE_NUM:
                                 unwindPrimitiveStack(frame, stackPointer, targetStackPointer, resultCount);
                                 break;
    -                        case BytecodeBitEncoding.LABEL_U16_RESULT_TYPE_REF:
    -                            unwindReferenceStack(frame, stackPointer, targetStackPointer, resultCount);
    +                        case BytecodeBitEncoding.LABEL_U16_RESULT_TYPE_OBJ:
    +                            unwindObjectStack(frame, stackPointer, targetStackPointer, resultCount);
                                 break;
                             case BytecodeBitEncoding.LABEL_U16_RESULT_TYPE_MIX:
                                 unwindStack(frame, stackPointer, targetStackPointer, resultCount);
    @@ -357,8 +357,8 @@ public Object executeBodyFromOffset(WasmContext context, WasmInstance instance,
                             case BytecodeBitEncoding.LABEL_RESULT_TYPE_NUM:
                                 unwindPrimitiveStack(frame, stackPointer, targetStackPointer, resultCount);
                                 break;
    -                        case BytecodeBitEncoding.LABEL_RESULT_TYPE_REF:
    -                            unwindReferenceStack(frame, stackPointer, targetStackPointer, resultCount);
    +                        case BytecodeBitEncoding.LABEL_RESULT_TYPE_OBJ:
    +                            unwindObjectStack(frame, stackPointer, targetStackPointer, resultCount);
                                 break;
                             case BytecodeBitEncoding.LABEL_RESULT_TYPE_MIX:
                                 unwindStack(frame, stackPointer, targetStackPointer, resultCount);
    @@ -4029,7 +4029,7 @@ private static void unwindPrimitiveStack(VirtualFrame frame, int stackPointer, i
         }
     
         @ExplodeLoop
    -    private static void unwindReferenceStack(VirtualFrame frame, int stackPointer, int targetStackPointer, int targetResultCount) {
    +    private static void unwindObjectStack(VirtualFrame frame, int stackPointer, int targetStackPointer, int targetResultCount) {
             CompilerAsserts.partialEvaluationConstant(stackPointer);
             CompilerAsserts.partialEvaluationConstant(targetResultCount);
             for (int i = 0; i < targetResultCount; ++i) {
    diff --git a/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/parser/bytecode/RuntimeBytecodeGen.java b/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/parser/bytecode/RuntimeBytecodeGen.java
    index 7be5afd545f5..5e72caae59ce 100644
    --- a/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/parser/bytecode/RuntimeBytecodeGen.java
    +++ b/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/parser/bytecode/RuntimeBytecodeGen.java
    @@ -302,7 +302,7 @@ public void addAtomicMemoryInstruction(int opcode, int memoryIndex, long offset,
          * @return The location of the label in the bytecode.
          */
         public int addLabel(int resultCount, int stackSize, int commonResultType) {
    -        assert commonResultType == WasmType.NONE_COMMON_TYPE || commonResultType == WasmType.NUM_COMMON_TYPE || commonResultType == WasmType.REF_COMMON_TYPE ||
    +        assert commonResultType == WasmType.NONE_COMMON_TYPE || commonResultType == WasmType.NUM_COMMON_TYPE || commonResultType == WasmType.OBJ_COMMON_TYPE ||
                             commonResultType == WasmType.MIX_COMMON_TYPE : "invalid result type";
             final int location;
             if (resultCount == 0 && stackSize <= 63) {
    @@ -317,8 +317,8 @@ public int addLabel(int resultCount, int stackSize, int commonResultType) {
                 add1(Bytecode.LABEL_U8);
                 if (commonResultType == BytecodeBitEncoding.LABEL_RESULT_TYPE_NUM) {
                     add1(BytecodeBitEncoding.LABEL_U8_RESULT_NUM | stackSize);
    -            } else if (commonResultType == BytecodeBitEncoding.LABEL_RESULT_TYPE_REF) {
    -                add1(BytecodeBitEncoding.LABEL_U8_RESULT_REF | stackSize);
    +            } else if (commonResultType == BytecodeBitEncoding.LABEL_RESULT_TYPE_OBJ) {
    +                add1(BytecodeBitEncoding.LABEL_U8_RESULT_OBJ | stackSize);
                 }
             } else if (resultCount <= 63 && fitsIntoUnsignedByte(stackSize)) {
                 add1(Bytecode.SKIP_LABEL_U16);
    
    From ac34fafd5ddddf809443bb48a44810d11fee9135 Mon Sep 17 00:00:00 2001
    From: Jirka Marsik 
    Date: Sun, 17 Dec 2023 17:48:47 +0100
    Subject: [PATCH 280/593] Initialize reference globals to WasmConstant.NULL,
     not Java null
    
    ---
     .../src/org.graalvm.wasm/src/org/graalvm/wasm/BinaryParser.java | 2 +-
     1 file changed, 1 insertion(+), 1 deletion(-)
    
    diff --git a/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/BinaryParser.java b/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/BinaryParser.java
    index 0314f7011ff3..4f35756212ba 100644
    --- a/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/BinaryParser.java
    +++ b/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/BinaryParser.java
    @@ -2066,7 +2066,7 @@ private Pair readConstantExpression(byte resultType, boolean onl
                         state.push(type);
                         state.addInstruction(Bytecode.REF_NULL);
                         if (calculable) {
    -                        stack.add(null);
    +                        stack.add(WasmConstant.NULL);
                         }
                         break;
                     case Instructions.REF_FUNC:
    
    From d85bc439381b7ba24f9b383afb3f1dced076f846 Mon Sep 17 00:00:00 2001
    From: Jirka Marsik 
    Date: Sun, 17 Dec 2023 17:49:23 +0100
    Subject: [PATCH 281/593] Generalize _REF instructions to _OBJ (references and
     vectors)
    
    ---
     .../src/org/graalvm/wasm/BinaryParser.java    | 16 ++---
     .../org/graalvm/wasm/constants/Bytecode.java  | 16 ++---
     .../wasm/constants/BytecodeBitEncoding.java   |  6 +-
     .../graalvm/wasm/constants/Instructions.java  |  8 +--
     .../src/org/graalvm/wasm/nodes/WasmFrame.java |  4 +-
     .../graalvm/wasm/nodes/WasmFunctionNode.java  | 58 +++++++++----------
     .../wasm/parser/bytecode/BytecodeParser.java  | 16 ++---
     7 files changed, 62 insertions(+), 62 deletions(-)
    
    diff --git a/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/BinaryParser.java b/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/BinaryParser.java
    index 4f35756212ba..e8ce3d432158 100644
    --- a/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/BinaryParser.java
    +++ b/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/BinaryParser.java
    @@ -744,7 +744,7 @@ private CodeEntry readFunction(int functionIndex, byte[] locals, byte[] resultTy
                         if (WasmType.isNumberType(type)) {
                             state.addInstruction(Bytecode.DROP);
                         } else {
    -                        state.addInstruction(Bytecode.DROP_REF);
    +                        state.addInstruction(Bytecode.DROP_OBJ);
                         }
                         break;
                     case Instructions.SELECT: {
    @@ -769,12 +769,12 @@ private CodeEntry readFunction(int functionIndex, byte[] locals, byte[] resultTy
                         if (WasmType.isNumberType(t)) {
                             state.addInstruction(Bytecode.SELECT);
                         } else {
    -                        state.addInstruction(Bytecode.SELECT_REF);
    +                        state.addInstruction(Bytecode.SELECT_OBJ);
                         }
                         break;
                     }
                     case Instructions.LOCAL_GET:
    -                case Instructions.LOCAL_GET_REF: {
    +                case Instructions.LOCAL_GET_OBJ: {
                         final int localIndex = readLocalIndex();
                         assertUnsignedIntLess(localIndex, locals.length, Failure.UNKNOWN_LOCAL);
                         final byte localType = locals[localIndex];
    @@ -782,12 +782,12 @@ private CodeEntry readFunction(int functionIndex, byte[] locals, byte[] resultTy
                         if (WasmType.isNumberType(localType)) {
                             state.addUnsignedInstruction(Bytecode.LOCAL_GET_U8, localIndex);
                         } else {
    -                        state.addUnsignedInstruction(Bytecode.LOCAL_GET_REF_U8, localIndex);
    +                        state.addUnsignedInstruction(Bytecode.LOCAL_GET_OBJ_U8, localIndex);
                         }
                         break;
                     }
                     case Instructions.LOCAL_SET:
    -                case Instructions.LOCAL_SET_REF: {
    +                case Instructions.LOCAL_SET_OBJ: {
                         final int localIndex = readLocalIndex();
                         assertUnsignedIntLess(localIndex, locals.length, Failure.UNKNOWN_LOCAL);
                         final byte localType = locals[localIndex];
    @@ -795,12 +795,12 @@ private CodeEntry readFunction(int functionIndex, byte[] locals, byte[] resultTy
                         if (WasmType.isNumberType(localType)) {
                             state.addUnsignedInstruction(Bytecode.LOCAL_SET_U8, localIndex);
                         } else {
    -                        state.addUnsignedInstruction(Bytecode.LOCAL_SET_REF_U8, localIndex);
    +                        state.addUnsignedInstruction(Bytecode.LOCAL_SET_OBJ_U8, localIndex);
                         }
                         break;
                     }
                     case Instructions.LOCAL_TEE:
    -                case Instructions.LOCAL_TEE_REF: {
    +                case Instructions.LOCAL_TEE_OBJ: {
                         final int localIndex = readLocalIndex();
                         assertUnsignedIntLess(localIndex, locals.length, Failure.UNKNOWN_LOCAL);
                         final byte localType = locals[localIndex];
    @@ -809,7 +809,7 @@ private CodeEntry readFunction(int functionIndex, byte[] locals, byte[] resultTy
                         if (WasmType.isNumberType(localType)) {
                             state.addUnsignedInstruction(Bytecode.LOCAL_TEE_U8, localIndex);
                         } else {
    -                        state.addUnsignedInstruction(Bytecode.LOCAL_TEE_REF_U8, localIndex);
    +                        state.addUnsignedInstruction(Bytecode.LOCAL_TEE_OBJ_U8, localIndex);
                         }
                         break;
                     }
    diff --git a/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/constants/Bytecode.java b/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/constants/Bytecode.java
    index af45b17e9939..a7dc231e4fae 100644
    --- a/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/constants/Bytecode.java
    +++ b/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/constants/Bytecode.java
    @@ -76,25 +76,25 @@ public class Bytecode {
         public static final int CALL_INDIRECT_I32 = 0x14;
     
         public static final int DROP = 0x15;
    -    public static final int DROP_REF = 0x16;
    +    public static final int DROP_OBJ = 0x16;
     
         public static final int SELECT = 0x17;
    -    public static final int SELECT_REF = 0x18;
    +    public static final int SELECT_OBJ = 0x18;
     
         public static final int LOCAL_GET_U8 = 0x19;
         public static final int LOCAL_GET_I32 = 0x1A;
    -    public static final int LOCAL_GET_REF_U8 = 0x1B;
    -    public static final int LOCAL_GET_REF_I32 = 0x1C;
    +    public static final int LOCAL_GET_OBJ_U8 = 0x1B;
    +    public static final int LOCAL_GET_OBJ_I32 = 0x1C;
     
         public static final int LOCAL_SET_U8 = 0x1D;
         public static final int LOCAL_SET_I32 = 0x1E;
    -    public static final int LOCAL_SET_REF_U8 = 0x1F;
    -    public static final int LOCAL_SET_REF_I32 = 0x20;
    +    public static final int LOCAL_SET_OBJ_U8 = 0x1F;
    +    public static final int LOCAL_SET_OBJ_I32 = 0x20;
     
         public static final int LOCAL_TEE_U8 = 0x21;
         public static final int LOCAL_TEE_I32 = 0x22;
    -    public static final int LOCAL_TEE_REF_U8 = 0x23;
    -    public static final int LOCAL_TEE_REF_I32 = 0x24;
    +    public static final int LOCAL_TEE_OBJ_U8 = 0x23;
    +    public static final int LOCAL_TEE_OBJ_I32 = 0x24;
     
         public static final int GLOBAL_GET_U8 = 0x25;
         public static final int GLOBAL_GET_I32 = 0x26;
    diff --git a/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/constants/BytecodeBitEncoding.java b/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/constants/BytecodeBitEncoding.java
    index 70178a74a90e..2beabfb28f14 100644
    --- a/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/constants/BytecodeBitEncoding.java
    +++ b/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/constants/BytecodeBitEncoding.java
    @@ -49,18 +49,18 @@ public class BytecodeBitEncoding {
     
         public static final int LABEL_U8_RESULT_MASK = 0b1100_0000;
         public static final int LABEL_U8_RESULT_NUM = 0b1000_0000;
    -    public static final int LABEL_U8_RESULT_REF = 0b1100_0000;
    +    public static final int LABEL_U8_RESULT_OBJ = 0b1100_0000;
         public static final int LABEL_U8_STACK_VALUE = 0b0011_1111;
     
         public static final int LABEL_U16_RESULT_TYPE_MASK = 0b1100_0000;
         public static final int LABEL_U16_RESULT_TYPE_NUM = 0b0100_0000;
    -    public static final int LABEL_U16_RESULT_TYPE_REF = 0b1000_0000;
    +    public static final int LABEL_U16_RESULT_TYPE_OBJ = 0b1000_0000;
         public static final int LABEL_U16_RESULT_TYPE_MIX = 0b1100_0000;
         public static final int LABEL_U16_RESULT_TYPE_SHIFT = 6;
         public static final int LABEL_U16_RESULT_VALUE = 0b0011_1111;
     
         public static final int LABEL_RESULT_TYPE_NUM = 0b0000_0001;
    -    public static final int LABEL_RESULT_TYPE_REF = 0b0000_0010;
    +    public static final int LABEL_RESULT_TYPE_OBJ = 0b0000_0010;
         public static final int LABEL_RESULT_TYPE_MIX = 0b0000_0011;
     
         public static final int MEMORY_64_FLAG = 0b1000_0000;
    diff --git a/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/constants/Instructions.java b/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/constants/Instructions.java
    index 951f0b3b5b13..28a70b2c7028 100644
    --- a/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/constants/Instructions.java
    +++ b/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/constants/Instructions.java
    @@ -365,10 +365,10 @@ public final class Instructions {
         // GraalWasm specific opcodes (these are reserved for future webassembly extensions and might be
         // used in other ways in the future)
     
    -    public static final int DROP_REF = 0x19;
    -    public static final int LOCAL_GET_REF = 0x1D;
    -    public static final int LOCAL_SET_REF = 0x1E;
    -    public static final int LOCAL_TEE_REF = 0x1F;
    +    public static final int DROP_OBJ = 0x19;
    +    public static final int LOCAL_GET_OBJ = 0x1D;
    +    public static final int LOCAL_SET_OBJ = 0x1E;
    +    public static final int LOCAL_TEE_OBJ = 0x1F;
     
         private static String[] decodingTable = new String[256];
     
    diff --git a/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/nodes/WasmFrame.java b/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/nodes/WasmFrame.java
    index 6b8e71be486c..be71b8e8b53f 100644
    --- a/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/nodes/WasmFrame.java
    +++ b/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/nodes/WasmFrame.java
    @@ -57,7 +57,7 @@ public static void dropPrimitive(VirtualFrame frame, int slot) {
             }
         }
     
    -    public static void dropReference(VirtualFrame frame, int slot) {
    +    public static void dropObject(VirtualFrame frame, int slot) {
             frame.clearObjectStatic(slot);
         }
     
    @@ -69,7 +69,7 @@ public static void copyPrimitive(VirtualFrame frame, int sourceSlot, int targetS
             frame.copyPrimitiveStatic(sourceSlot, targetSlot);
         }
     
    -    public static void copyReference(VirtualFrame frame, int sourceSlot, int targetSlot) {
    +    public static void copyObject(VirtualFrame frame, int sourceSlot, int targetSlot) {
             frame.copyObjectStatic(sourceSlot, targetSlot);
         }
     
    diff --git a/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/nodes/WasmFunctionNode.java b/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/nodes/WasmFunctionNode.java
    index 02220f2f0acd..02bd089cf1ed 100644
    --- a/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/nodes/WasmFunctionNode.java
    +++ b/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/nodes/WasmFunctionNode.java
    @@ -49,7 +49,7 @@
     import static org.graalvm.wasm.BinaryStreamParser.rawPeekU8;
     import static org.graalvm.wasm.nodes.WasmFrame.drop;
     import static org.graalvm.wasm.nodes.WasmFrame.dropPrimitive;
    -import static org.graalvm.wasm.nodes.WasmFrame.dropReference;
    +import static org.graalvm.wasm.nodes.WasmFrame.dropObject;
     import static org.graalvm.wasm.nodes.WasmFrame.popBoolean;
     import static org.graalvm.wasm.nodes.WasmFrame.popDouble;
     import static org.graalvm.wasm.nodes.WasmFrame.popFloat;
    @@ -313,8 +313,8 @@ public Object executeBodyFromOffset(WasmContext context, WasmInstance instance,
                                 dropStack(frame, stackPointer, targetStackPointer + 1);
                                 stackPointer = targetStackPointer + 1;
                                 break;
    -                        case BytecodeBitEncoding.LABEL_U8_RESULT_REF:
    -                            WasmFrame.copyReference(frame, stackPointer - 1, targetStackPointer);
    +                        case BytecodeBitEncoding.LABEL_U8_RESULT_OBJ:
    +                            WasmFrame.copyObject(frame, stackPointer - 1, targetStackPointer);
                                 dropStack(frame, stackPointer, targetStackPointer + 1);
                                 stackPointer = targetStackPointer + 1;
                                 break;
    @@ -625,9 +625,9 @@ public Object executeBodyFromOffset(WasmContext context, WasmInstance instance,
                         dropPrimitive(frame, stackPointer);
                         break;
                     }
    -                case Bytecode.DROP_REF: {
    +                case Bytecode.DROP_OBJ: {
                         stackPointer--;
    -                    dropReference(frame, stackPointer);
    +                    dropObject(frame, stackPointer);
                         break;
                     }
                     case Bytecode.SELECT: {
    @@ -640,12 +640,12 @@ public Object executeBodyFromOffset(WasmContext context, WasmInstance instance,
                         stackPointer -= 2;
                         break;
                     }
    -                case Bytecode.SELECT_REF: {
    +                case Bytecode.SELECT_OBJ: {
                         if (popBoolean(frame, stackPointer - 1)) {
    -                        dropReference(frame, stackPointer - 2);
    +                        dropObject(frame, stackPointer - 2);
                         } else {
    -                        WasmFrame.copyReference(frame, stackPointer - 2, stackPointer - 3);
    -                        dropReference(frame, stackPointer - 2);
    +                        WasmFrame.copyObject(frame, stackPointer - 2, stackPointer - 3);
    +                        dropObject(frame, stackPointer - 2);
                         }
                         stackPointer -= 2;
                         break;
    @@ -664,17 +664,17 @@ public Object executeBodyFromOffset(WasmContext context, WasmInstance instance,
                         stackPointer++;
                         break;
                     }
    -                case Bytecode.LOCAL_GET_REF_U8: {
    +                case Bytecode.LOCAL_GET_OBJ_U8: {
                         final int index = rawPeekU8(bytecode, offset);
                         offset++;
    -                    local_get_ref(frame, stackPointer, index);
    +                    local_get_obj(frame, stackPointer, index);
                         stackPointer++;
                         break;
                     }
    -                case Bytecode.LOCAL_GET_REF_I32: {
    +                case Bytecode.LOCAL_GET_OBJ_I32: {
                         final int index = rawPeekI32(bytecode, offset);
                         offset += 4;
    -                    local_get_ref(frame, stackPointer, index);
    +                    local_get_obj(frame, stackPointer, index);
                         stackPointer++;
                         break;
                     }
    @@ -692,18 +692,18 @@ public Object executeBodyFromOffset(WasmContext context, WasmInstance instance,
                         local_set(frame, stackPointer, index);
                         break;
                     }
    -                case Bytecode.LOCAL_SET_REF_U8: {
    +                case Bytecode.LOCAL_SET_OBJ_U8: {
                         final int index = rawPeekU8(bytecode, offset);
                         offset++;
                         stackPointer--;
    -                    local_set_ref(frame, stackPointer, index);
    +                    local_set_obj(frame, stackPointer, index);
                         break;
                     }
    -                case Bytecode.LOCAL_SET_REF_I32: {
    +                case Bytecode.LOCAL_SET_OBJ_I32: {
                         final int index = rawPeekI32(bytecode, offset);
                         offset += 4;
                         stackPointer--;
    -                    local_set_ref(frame, stackPointer, index);
    +                    local_set_obj(frame, stackPointer, index);
                         break;
                     }
                     case Bytecode.LOCAL_TEE_U8: {
    @@ -718,16 +718,16 @@ public Object executeBodyFromOffset(WasmContext context, WasmInstance instance,
                         local_tee(frame, stackPointer - 1, index);
                         break;
                     }
    -                case Bytecode.LOCAL_TEE_REF_U8: {
    +                case Bytecode.LOCAL_TEE_OBJ_U8: {
                         final int index = rawPeekU8(bytecode, offset);
                         offset++;
    -                    local_tee_ref(frame, stackPointer - 1, index);
    +                    local_tee_obj(frame, stackPointer - 1, index);
                         break;
                     }
    -                case Bytecode.LOCAL_TEE_REF_I32: {
    +                case Bytecode.LOCAL_TEE_OBJ_I32: {
                         final int index = rawPeekI32(bytecode, offset);
                         offset += 4;
    -                    local_tee_ref(frame, stackPointer - 1, index);
    +                    local_tee_obj(frame, stackPointer - 1, index);
                         break;
                     }
                     case Bytecode.GLOBAL_GET_U8: {
    @@ -2729,8 +2729,8 @@ private static void local_tee(VirtualFrame frame, int stackPointer, int index) {
             WasmFrame.copyPrimitive(frame, stackPointer, index);
         }
     
    -    private static void local_tee_ref(VirtualFrame frame, int stackPointer, int index) {
    -        WasmFrame.copyReference(frame, stackPointer, index);
    +    private static void local_tee_obj(VirtualFrame frame, int stackPointer, int index) {
    +        WasmFrame.copyObject(frame, stackPointer, index);
         }
     
         private static void local_set(VirtualFrame frame, int stackPointer, int index) {
    @@ -2740,10 +2740,10 @@ private static void local_set(VirtualFrame frame, int stackPointer, int index) {
             }
         }
     
    -    private static void local_set_ref(VirtualFrame frame, int stackPointer, int index) {
    -        WasmFrame.copyReference(frame, stackPointer, index);
    +    private static void local_set_obj(VirtualFrame frame, int stackPointer, int index) {
    +        WasmFrame.copyObject(frame, stackPointer, index);
             if (CompilerDirectives.inCompiledCode()) {
    -            WasmFrame.dropReference(frame, stackPointer);
    +            WasmFrame.dropObject(frame, stackPointer);
             }
         }
     
    @@ -2751,8 +2751,8 @@ private static void local_get(VirtualFrame frame, int stackPointer, int index) {
             WasmFrame.copyPrimitive(frame, index, stackPointer);
         }
     
    -    private static void local_get_ref(VirtualFrame frame, int stackPointer, int index) {
    -        WasmFrame.copyReference(frame, index, stackPointer);
    +    private static void local_get_obj(VirtualFrame frame, int stackPointer, int index) {
    +        WasmFrame.copyObject(frame, index, stackPointer);
         }
     
         private static void i32_eqz(VirtualFrame frame, int stackPointer) {
    @@ -4033,7 +4033,7 @@ private static void unwindObjectStack(VirtualFrame frame, int stackPointer, int
             CompilerAsserts.partialEvaluationConstant(stackPointer);
             CompilerAsserts.partialEvaluationConstant(targetResultCount);
             for (int i = 0; i < targetResultCount; ++i) {
    -            WasmFrame.copyReference(frame, stackPointer + i - targetResultCount, targetStackPointer + i);
    +            WasmFrame.copyObject(frame, stackPointer + i - targetResultCount, targetStackPointer + i);
             }
         }
     
    diff --git a/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/parser/bytecode/BytecodeParser.java b/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/parser/bytecode/BytecodeParser.java
    index 584d8ede5918..40db11845af4 100644
    --- a/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/parser/bytecode/BytecodeParser.java
    +++ b/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/parser/bytecode/BytecodeParser.java
    @@ -464,9 +464,9 @@ private static List readCallNodes(byte[] bytecode, int startOffset, in
                     case Bytecode.RETURN:
                     case Bytecode.LOOP:
                     case Bytecode.DROP:
    -                case Bytecode.DROP_REF:
    +                case Bytecode.DROP_OBJ:
                     case Bytecode.SELECT:
    -                case Bytecode.SELECT_REF:
    +                case Bytecode.SELECT_OBJ:
                     case Bytecode.I32_EQZ:
                     case Bytecode.I32_EQ:
                     case Bytecode.I32_NE:
    @@ -607,11 +607,11 @@ private static List readCallNodes(byte[] bytecode, int startOffset, in
                     case Bytecode.LABEL_U8:
                     case Bytecode.BR_U8:
                     case Bytecode.LOCAL_GET_U8:
    -                case Bytecode.LOCAL_GET_REF_U8:
    +                case Bytecode.LOCAL_GET_OBJ_U8:
                     case Bytecode.LOCAL_SET_U8:
    -                case Bytecode.LOCAL_SET_REF_U8:
    +                case Bytecode.LOCAL_SET_OBJ_U8:
                     case Bytecode.LOCAL_TEE_U8:
    -                case Bytecode.LOCAL_TEE_REF_U8:
    +                case Bytecode.LOCAL_TEE_OBJ_U8:
                     case Bytecode.GLOBAL_GET_U8:
                     case Bytecode.GLOBAL_SET_U8:
                     case Bytecode.I32_LOAD_U8:
    @@ -653,11 +653,11 @@ private static List readCallNodes(byte[] bytecode, int startOffset, in
                     case Bytecode.MEMORY_GROW:
                     case Bytecode.BR_I32:
                     case Bytecode.LOCAL_GET_I32:
    -                case Bytecode.LOCAL_GET_REF_I32:
    +                case Bytecode.LOCAL_GET_OBJ_I32:
                     case Bytecode.LOCAL_SET_I32:
    -                case Bytecode.LOCAL_SET_REF_I32:
    +                case Bytecode.LOCAL_SET_OBJ_I32:
                     case Bytecode.LOCAL_TEE_I32:
    -                case Bytecode.LOCAL_TEE_REF_I32:
    +                case Bytecode.LOCAL_TEE_OBJ_I32:
                     case Bytecode.GLOBAL_GET_I32:
                     case Bytecode.GLOBAL_SET_I32:
                     case Bytecode.I32_LOAD_I32:
    
    From 7a46b8fbd6badfbec526ac9027b064ed4409b2ef Mon Sep 17 00:00:00 2001
    From: Jirka Marsik 
    Date: Sun, 17 Dec 2023 18:05:47 +0100
    Subject: [PATCH 282/593] Support vectors in function arguments and return
     values
    
    ---
     .../org/graalvm/wasm/WasmFunctionInstance.java | 13 +++++++------
     .../src/org/graalvm/wasm/WasmLanguage.java     | 10 +++++-----
     .../wasm/api/ExecuteInParentContextNode.java   | 13 ++++++++++---
     .../graalvm/wasm/nodes/WasmFunctionNode.java   | 12 +++++++++---
     .../org/graalvm/wasm/nodes/WasmRootNode.java   | 18 ++++++++++++++++--
     5 files changed, 47 insertions(+), 19 deletions(-)
    
    diff --git a/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/WasmFunctionInstance.java b/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/WasmFunctionInstance.java
    index 6c679cdfc1f4..c685c500df7b 100644
    --- a/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/WasmFunctionInstance.java
    +++ b/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/WasmFunctionInstance.java
    @@ -41,6 +41,7 @@
     package org.graalvm.wasm;
     
     import org.graalvm.wasm.api.InteropArray;
    +import org.graalvm.wasm.api.Vector128;
     import org.graalvm.wasm.exception.Failure;
     import org.graalvm.wasm.exception.WasmException;
     import org.graalvm.wasm.nodes.WasmIndirectCallNode;
    @@ -156,10 +157,10 @@ Object execute(Object[] arguments,
         private Object multiValueStackAsArray(WasmLanguage language) {
             final var multiValueStack = language.multiValueStack();
             final long[] primitiveMultiValueStack = multiValueStack.primitiveStack();
    -        final Object[] referenceMultiValueStack = multiValueStack.referenceStack();
    +        final Object[] objectMultiValueStack = multiValueStack.objectStack();
             final int resultCount = function.resultCount();
             assert primitiveMultiValueStack.length >= resultCount;
    -        assert referenceMultiValueStack.length >= resultCount;
    +        assert objectMultiValueStack.length >= resultCount;
             final Object[] values = new Object[resultCount];
             for (int i = 0; i < resultCount; i++) {
                 byte resultType = function.resultTypeAt(i);
    @@ -168,10 +169,10 @@ private Object multiValueStackAsArray(WasmLanguage language) {
                     case WasmType.I64_TYPE -> primitiveMultiValueStack[i];
                     case WasmType.F32_TYPE -> Float.intBitsToFloat((int) primitiveMultiValueStack[i]);
                     case WasmType.F64_TYPE -> Double.longBitsToDouble(primitiveMultiValueStack[i]);
    -                case WasmType.FUNCREF_TYPE, WasmType.EXTERNREF_TYPE -> {
    -                    Object ref = referenceMultiValueStack[i];
    -                    referenceMultiValueStack[i] = null;
    -                    yield ref;
    +                case WasmType.V128_TYPE, WasmType.FUNCREF_TYPE, WasmType.EXTERNREF_TYPE -> {
    +                    Object obj = objectMultiValueStack[i];
    +                    objectMultiValueStack[i] = null;
    +                    yield obj;
                     }
                     default -> throw WasmException.create(Failure.UNSPECIFIED_INTERNAL);
                 };
    diff --git a/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/WasmLanguage.java b/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/WasmLanguage.java
    index a8dc034b2812..9319be01847c 100644
    --- a/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/WasmLanguage.java
    +++ b/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/WasmLanguage.java
    @@ -213,7 +213,7 @@ public MultiValueStack multiValueStack() {
     
         public static final class MultiValueStack {
             private long[] primitiveStack;
    -        private Object[] referenceStack;
    +        private Object[] objectStack;
             // Initialize size to 1, so we only create the stack for more than 1 result value.
             private int size = 1;
     
    @@ -225,10 +225,10 @@ public long[] primitiveStack() {
             }
     
             /**
    -         * @return the current reference multi-value stack or null if it has never been resized.
    +         * @return the current object multi-value stack or null if it has never been resized.
              */
    -        public Object[] referenceStack() {
    -            return referenceStack;
    +        public Object[] objectStack() {
    +            return objectStack;
             }
     
             /**
    @@ -241,7 +241,7 @@ public Object[] referenceStack() {
             public void resize(int expectedSize) {
                 if (expectedSize > size) {
                     primitiveStack = new long[expectedSize];
    -                referenceStack = new Object[expectedSize];
    +                objectStack = new Object[expectedSize];
                     size = expectedSize;
                 }
             }
    diff --git a/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/api/ExecuteInParentContextNode.java b/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/api/ExecuteInParentContextNode.java
    index 476029bed3a2..30424d976161 100644
    --- a/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/api/ExecuteInParentContextNode.java
    +++ b/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/api/ExecuteInParentContextNode.java
    @@ -129,7 +129,7 @@ private Object convertResult(Object result, byte resultType) throws UnsupportedM
                 case WasmType.I64_TYPE -> asLong(result);
                 case WasmType.F32_TYPE -> asFloat(result);
                 case WasmType.F64_TYPE -> asDouble(result);
    -            case WasmType.FUNCREF_TYPE, WasmType.EXTERNREF_TYPE -> result;
    +            case WasmType.V128_TYPE, WasmType.FUNCREF_TYPE, WasmType.EXTERNREF_TYPE -> result;
                 default -> {
                     throw WasmException.format(Failure.UNSPECIFIED_TRAP, this, "Unknown result type: %d", resultType);
                 }
    @@ -152,7 +152,7 @@ private void pushMultiValueResult(Object result, int resultCount) {
                 final var multiValueStack = WasmLanguage.get(this).multiValueStack();
                 multiValueStack.resize(resultCount);
                 final long[] primitiveMultiValueStack = multiValueStack.primitiveStack();
    -            final Object[] referenceMultiValueStack = multiValueStack.referenceStack();
    +            final Object[] objectMultiValueStack = multiValueStack.objectStack();
                 for (int i = 0; i < resultCount; i++) {
                     byte resultType = module().symbolTable().functionTypeResultTypeAt(functionTypeIndex, i);
                     CompilerAsserts.partialEvaluationConstant(resultType);
    @@ -162,7 +162,14 @@ private void pushMultiValueResult(Object result, int resultCount) {
                         case WasmType.I64_TYPE -> primitiveMultiValueStack[i] = asLong(value);
                         case WasmType.F32_TYPE -> primitiveMultiValueStack[i] = Float.floatToRawIntBits(asFloat(value));
                         case WasmType.F64_TYPE -> primitiveMultiValueStack[i] = Double.doubleToRawLongBits(asDouble(value));
    -                    case WasmType.FUNCREF_TYPE, WasmType.EXTERNREF_TYPE -> referenceMultiValueStack[i] = value;
    +                    case WasmType.V128_TYPE -> {
    +                        if (!(value instanceof Vector128)) {
    +                            errorBranch.enter();
    +                            throw WasmException.create(Failure.INVALID_TYPE_IN_MULTI_VALUE);
    +                        }
    +                        objectMultiValueStack[i] = value;
    +                    }
    +                    case WasmType.FUNCREF_TYPE, WasmType.EXTERNREF_TYPE -> objectMultiValueStack[i] = value;
                         default -> {
                             errorBranch.enter();
                             throw WasmException.format(Failure.UNSPECIFIED_TRAP, this, "Unknown result type: %d", resultType);
    diff --git a/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/nodes/WasmFunctionNode.java b/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/nodes/WasmFunctionNode.java
    index 02bd089cf1ed..2ef063dde309 100644
    --- a/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/nodes/WasmFunctionNode.java
    +++ b/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/nodes/WasmFunctionNode.java
    @@ -4002,6 +4002,7 @@ private Object[] createArgumentsForCall(VirtualFrame frame, int functionTypeInde
                     case WasmType.I64_TYPE -> popLong(frame, stackPointer);
                     case WasmType.F32_TYPE -> popFloat(frame, stackPointer);
                     case WasmType.F64_TYPE -> popDouble(frame, stackPointer);
    +                case WasmType.V128_TYPE -> popVector128(frame, stackPointer);
                     case WasmType.FUNCREF_TYPE, WasmType.EXTERNREF_TYPE -> popReference(frame, stackPointer);
                     default -> throw WasmException.format(Failure.UNSPECIFIED_TRAP, this, "Unknown type: %d", type);
                 };
    @@ -4172,6 +4173,7 @@ private void pushResult(VirtualFrame frame, int stackPointer, byte resultType, O
                 case WasmType.I64_TYPE -> pushLong(frame, stackPointer, (long) result);
                 case WasmType.F32_TYPE -> pushFloat(frame, stackPointer, (float) result);
                 case WasmType.F64_TYPE -> pushDouble(frame, stackPointer, (double) result);
    +            case WasmType.V128_TYPE -> pushVector128(frame, stackPointer, (Vector128) result);
                 case WasmType.FUNCREF_TYPE, WasmType.EXTERNREF_TYPE -> pushReference(frame, stackPointer, result);
                 default -> {
                     throw WasmException.format(Failure.UNSPECIFIED_TRAP, this, "Unknown result type: %d", resultType);
    @@ -4195,6 +4197,7 @@ private void extractMultiValueResult(VirtualFrame frame, int stackPointer, Objec
             assert result == WasmConstant.MULTI_VALUE : result;
             final var multiValueStack = language.multiValueStack();
             final long[] primitiveMultiValueStack = multiValueStack.primitiveStack();
    +        final Object[] objectMultiValueStack = multiValueStack.objectStack();
             for (int i = 0; i < resultCount; i++) {
                 final byte resultType = module.symbolTable().functionTypeResultTypeAt(functionTypeIndex, i);
                 CompilerAsserts.partialEvaluationConstant(resultType);
    @@ -4203,10 +4206,13 @@ private void extractMultiValueResult(VirtualFrame frame, int stackPointer, Objec
                     case WasmType.I64_TYPE -> pushLong(frame, stackPointer + i, primitiveMultiValueStack[i]);
                     case WasmType.F32_TYPE -> pushFloat(frame, stackPointer + i, Float.intBitsToFloat((int) primitiveMultiValueStack[i]));
                     case WasmType.F64_TYPE -> pushDouble(frame, stackPointer + i, Double.longBitsToDouble(primitiveMultiValueStack[i]));
    +                case WasmType.V128_TYPE -> {
    +                    pushVector128(frame, stackPointer + i, (Vector128) objectMultiValueStack[i]);
    +                    objectMultiValueStack[i] = null;
    +                }
                     case WasmType.FUNCREF_TYPE, WasmType.EXTERNREF_TYPE -> {
    -                    final Object[] referenceMultiValueStack = multiValueStack.referenceStack();
    -                    pushReference(frame, stackPointer + i, referenceMultiValueStack[i]);
    -                    referenceMultiValueStack[i] = null;
    +                    pushReference(frame, stackPointer + i, objectMultiValueStack[i]);
    +                    objectMultiValueStack[i] = null;
                     }
                     default -> {
                         enterErrorBranch();
    diff --git a/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/nodes/WasmRootNode.java b/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/nodes/WasmRootNode.java
    index b6d952d83a25..2cb0f8665439 100644
    --- a/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/nodes/WasmRootNode.java
    +++ b/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/nodes/WasmRootNode.java
    @@ -45,11 +45,13 @@
     import static org.graalvm.wasm.nodes.WasmFrame.popInt;
     import static org.graalvm.wasm.nodes.WasmFrame.popLong;
     import static org.graalvm.wasm.nodes.WasmFrame.popReference;
    +import static org.graalvm.wasm.nodes.WasmFrame.popVector128;
     import static org.graalvm.wasm.nodes.WasmFrame.pushDouble;
     import static org.graalvm.wasm.nodes.WasmFrame.pushFloat;
     import static org.graalvm.wasm.nodes.WasmFrame.pushInt;
     import static org.graalvm.wasm.nodes.WasmFrame.pushLong;
     import static org.graalvm.wasm.nodes.WasmFrame.pushReference;
    +import static org.graalvm.wasm.nodes.WasmFrame.pushVector128;
     
     import org.graalvm.wasm.WasmArguments;
     import org.graalvm.wasm.WasmConstant;
    @@ -58,6 +60,7 @@
     import org.graalvm.wasm.WasmLanguage;
     import org.graalvm.wasm.WasmModule;
     import org.graalvm.wasm.WasmType;
    +import org.graalvm.wasm.api.Vector128;
     import org.graalvm.wasm.exception.Failure;
     import org.graalvm.wasm.exception.WasmException;
     import org.graalvm.wasm.memory.WasmMemory;
    @@ -192,6 +195,8 @@ public Object executeWithContext(VirtualFrame frame, WasmContext context, WasmIn
                         return popFloat(frame, localCount);
                     case WasmType.F64_TYPE:
                         return popDouble(frame, localCount);
    +                case WasmType.V128_TYPE:
    +                    return popVector128(frame, localCount);
                     case WasmType.FUNCREF_TYPE:
                     case WasmType.EXTERNREF_TYPE:
                         return popReference(frame, localCount);
    @@ -209,7 +214,7 @@ private void moveResultValuesToMultiValueStack(VirtualFrame frame, int resultCou
             CompilerAsserts.partialEvaluationConstant(resultCount);
             final var multiValueStack = WasmLanguage.get(this).multiValueStack();
             final long[] primitiveMultiValueStack = multiValueStack.primitiveStack();
    -        final Object[] referenceMultiValueStack = multiValueStack.referenceStack();
    +        final Object[] objectMultiValueStack = multiValueStack.objectStack();
             for (int i = 0; i < resultCount; i++) {
                 final int resultType = functionNode.resultType(i);
                 CompilerAsserts.partialEvaluationConstant(resultType);
    @@ -226,9 +231,12 @@ private void moveResultValuesToMultiValueStack(VirtualFrame frame, int resultCou
                     case WasmType.F64_TYPE:
                         primitiveMultiValueStack[i] = Double.doubleToRawLongBits(popDouble(frame, localCount + i));
                         break;
    +                case WasmType.V128_TYPE:
    +                    objectMultiValueStack[i] = popVector128(frame, localCount + i);
    +                    break;
                     case WasmType.FUNCREF_TYPE:
                     case WasmType.EXTERNREF_TYPE:
    -                    referenceMultiValueStack[i] = popReference(frame, localCount + i);
    +                    objectMultiValueStack[i] = popReference(frame, localCount + i);
                         break;
                     default:
                         throw WasmException.format(Failure.UNSPECIFIED_INTERNAL, this, "Unknown result type: %d", resultType);
    @@ -257,6 +265,9 @@ private void moveArgumentsToLocals(VirtualFrame frame) {
                     case WasmType.F64_TYPE:
                         pushDouble(frame, i, (double) arg);
                         break;
    +                case WasmType.V128_TYPE:
    +                    pushVector128(frame, i, (Vector128) arg);
    +                    break;
                     case WasmType.FUNCREF_TYPE:
                     case WasmType.EXTERNREF_TYPE:
                         pushReference(frame, i, arg);
    @@ -283,6 +294,9 @@ private void initializeLocals(VirtualFrame frame) {
                     case WasmType.F64_TYPE:
                         pushDouble(frame, i, 0D);
                         break;
    +                case WasmType.V128_TYPE:
    +                    pushVector128(frame, i, Vector128.ZERO);
    +                    break;
                     case WasmType.FUNCREF_TYPE:
                     case WasmType.EXTERNREF_TYPE:
                         pushReference(frame, i, WasmConstant.NULL);
    
    From cb80217b655fb3dc76d9cf664bf56d07f94b3463 Mon Sep 17 00:00:00 2001
    From: Jirka Marsik 
    Date: Sun, 17 Dec 2023 18:20:09 +0100
    Subject: [PATCH 283/593] Add missing v128 support to other parts of the code
     base
    
    ---
     .../src/org.graalvm.wasm/src/org/graalvm/wasm/BinaryParser.java | 2 ++
     .../src/org/graalvm/wasm/BinaryStreamParser.java                | 1 +
     .../src/org/graalvm/wasm/WasmFunctionInstance.java              | 1 -
     .../src/org.graalvm.wasm/src/org/graalvm/wasm/WasmInstance.java | 2 ++
     4 files changed, 5 insertions(+), 1 deletion(-)
    
    diff --git a/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/BinaryParser.java b/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/BinaryParser.java
    index e8ce3d432158..77386f4dc5c0 100644
    --- a/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/BinaryParser.java
    +++ b/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/BinaryParser.java
    @@ -558,6 +558,8 @@ private static byte[] encapsulateResultType(int type) {
                     return WasmType.F32_TYPE_ARRAY;
                 case F64_TYPE:
                     return WasmType.F64_TYPE_ARRAY;
    +            case V128_TYPE:
    +                return WasmType.V128_TYPE_ARRAY;
                 case FUNCREF_TYPE:
                     return WasmType.FUNCREF_TYPE_ARRAY;
                 case EXTERNREF_TYPE:
    diff --git a/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/BinaryStreamParser.java b/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/BinaryStreamParser.java
    index 0cc45e0f50c2..b1d2e990525b 100644
    --- a/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/BinaryStreamParser.java
    +++ b/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/BinaryStreamParser.java
    @@ -284,6 +284,7 @@ protected void readBlockType(int[] result, boolean allowRefTypes) {
                 case WasmType.I64_TYPE:
                 case WasmType.F32_TYPE:
                 case WasmType.F64_TYPE:
    +            case WasmType.V128_TYPE:
                     offset++;
                     result[0] = type;
                     result[1] = SINGLE_RESULT_VALUE;
    diff --git a/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/WasmFunctionInstance.java b/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/WasmFunctionInstance.java
    index c685c500df7b..1f9952bcfb3f 100644
    --- a/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/WasmFunctionInstance.java
    +++ b/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/WasmFunctionInstance.java
    @@ -41,7 +41,6 @@
     package org.graalvm.wasm;
     
     import org.graalvm.wasm.api.InteropArray;
    -import org.graalvm.wasm.api.Vector128;
     import org.graalvm.wasm.exception.Failure;
     import org.graalvm.wasm.exception.WasmException;
     import org.graalvm.wasm.nodes.WasmIndirectCallNode;
    diff --git a/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/WasmInstance.java b/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/WasmInstance.java
    index eab79e236f18..f82d45408a03 100644
    --- a/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/WasmInstance.java
    +++ b/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/WasmInstance.java
    @@ -227,6 +227,8 @@ private static Object readGlobal(WasmInstance instance, SymbolTable symbolTable,
                     return Float.intBitsToFloat(globals.loadAsInt(address));
                 case WasmType.F64_TYPE:
                     return Double.longBitsToDouble(globals.loadAsLong(address));
    +            case WasmType.V128_TYPE:
    +                return globals.loadAsVector128(address);
                 case WasmType.FUNCREF_TYPE:
                 case WasmType.EXTERNREF_TYPE:
                     return globals.loadAsReference(address);
    
    From 56c814b56b1466c8150ed31f1bad1d16378b025d Mon Sep 17 00:00:00 2001
    From: Jirka Marsik 
    Date: Sun, 17 Dec 2023 18:55:36 +0100
    Subject: [PATCH 284/593] Drop unneeded hack for missing v128 local
     initialization
    
    ---
     .../org.graalvm.wasm/src/org/graalvm/wasm/nodes/WasmFrame.java | 3 ---
     1 file changed, 3 deletions(-)
    
    diff --git a/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/nodes/WasmFrame.java b/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/nodes/WasmFrame.java
    index be71b8e8b53f..f1a9bf5f37a5 100644
    --- a/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/nodes/WasmFrame.java
    +++ b/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/nodes/WasmFrame.java
    @@ -141,9 +141,6 @@ public static void pushDouble(VirtualFrame frame, int slot, double value) {
         public static Vector128 popVector128(VirtualFrame frame, int slot) {
             Vector128 result = (Vector128) frame.getObjectStatic(slot);
             frame.clearObjectStatic(slot);
    -        if (result == null) {
    -            return Vector128.ZERO;
    -        }
             return result;
         }
     
    
    From cac1c584936cf3ecdf9db0576395cc0ca63da069 Mon Sep 17 00:00:00 2001
    From: Jirka Marsik 
    Date: Sun, 17 Dec 2023 23:55:00 +0100
    Subject: [PATCH 285/593] Add support for storing and reading all primitives in
     Vector128
    
    ---
     .../src/org/graalvm/wasm/api/Vector128.java   | 57 +++++++++++++++++++
     1 file changed, 57 insertions(+)
    
    diff --git a/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/api/Vector128.java b/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/api/Vector128.java
    index 6ca4f01f0d84..cbe9bf59027e 100644
    --- a/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/api/Vector128.java
    +++ b/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/api/Vector128.java
    @@ -65,6 +65,25 @@ public static Vector128 ofBytes(byte[] bytes) {
             return new Vector128(bytes);
         }
     
    +    @ExplodeLoop
    +    public short[] asShorts() {
    +        short[] shorts = new short[8];
    +        for (int i = 0; i < 8; i++) {
    +            shorts[i] = byteArraySupport.getShort(bytes, i * 2);
    +        }
    +        return shorts;
    +    }
    +
    +    @ExplodeLoop
    +    public static Vector128 ofShorts(short[] shorts) {
    +        assert shorts.length == 8;
    +        byte[] bytes = new byte[16];
    +        for (int i = 0; i < 8; i++) {
    +            byteArraySupport.putShort(bytes, i * 2, shorts[i]);
    +        }
    +        return new Vector128(bytes);
    +    }
    +
         @ExplodeLoop
         public int[] asInts() {
             int[] ints = new int[4];
    @@ -84,6 +103,44 @@ public static Vector128 ofInts(int[] ints) {
             return new Vector128(bytes);
         }
     
    +    @ExplodeLoop
    +    public long[] asLongs() {
    +        long[] longs = new long[2];
    +        for (int i = 0; i < 2; i++) {
    +            longs[i] = byteArraySupport.getLong(bytes, i * 8);
    +        }
    +        return longs;
    +    }
    +
    +    @ExplodeLoop
    +    public static Vector128 ofLongs(long[] longs) {
    +        assert longs.length == 2;
    +        byte[] bytes = new byte[16];
    +        for (int i = 0; i < 2; i++) {
    +            byteArraySupport.putLong(bytes, i * 8, longs[i]);
    +        }
    +        return new Vector128(bytes);
    +    }
    +
    +    @ExplodeLoop
    +    public float[] asFloats() {
    +        float[] floats = new float[4];
    +        for (int i = 0; i < 4; i++) {
    +            floats[i] = byteArraySupport.getFloat(bytes, i * 4);
    +        }
    +        return floats;
    +    }
    +
    +    @ExplodeLoop
    +    public static Vector128 ofFloats(float[] floats) {
    +        assert floats.length == 4;
    +        byte[] bytes = new byte[16];
    +        for (int i = 0; i < 4; i++) {
    +            byteArraySupport.putFloat(bytes, i * 4, floats[i]);
    +        }
    +        return new Vector128(bytes);
    +    }
    +
         @ExplodeLoop
         public double[] asDoubles() {
             double[] doubles = new double[2];
    
    From b90e2ad64234d46da684c8732272725f8ea7f44e Mon Sep 17 00:00:00 2001
    From: Jirka Marsik 
    Date: Sun, 17 Dec 2023 23:55:27 +0100
    Subject: [PATCH 286/593] Implement InteropLibrary for Vector128
    
    ---
     .../src/org/graalvm/wasm/api/Vector128.java   | 31 ++++++++++++++++++-
     1 file changed, 30 insertions(+), 1 deletion(-)
    
    diff --git a/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/api/Vector128.java b/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/api/Vector128.java
    index cbe9bf59027e..f97fad797565 100644
    --- a/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/api/Vector128.java
    +++ b/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/api/Vector128.java
    @@ -40,10 +40,16 @@
      */
     package org.graalvm.wasm.api;
     
    +import com.oracle.truffle.api.interop.InteropLibrary;
    +import com.oracle.truffle.api.interop.InvalidArrayIndexException;
    +import com.oracle.truffle.api.interop.TruffleObject;
    +import com.oracle.truffle.api.library.ExportLibrary;
    +import com.oracle.truffle.api.library.ExportMessage;
     import com.oracle.truffle.api.memory.ByteArraySupport;
     import com.oracle.truffle.api.nodes.ExplodeLoop;
     
    -public class Vector128 {
    +@ExportLibrary(InteropLibrary.class)
    +public class Vector128 implements TruffleObject {
     
         // v128 component values are stored in little-endian order
         private static final ByteArraySupport byteArraySupport = ByteArraySupport.littleEndian();
    @@ -159,4 +165,27 @@ public static Vector128 ofDoubles(double[] doubles) {
             }
             return new Vector128(bytes);
         }
    +
    +    @ExportMessage
    +    protected boolean hasArrayElements() {
    +        return true;
    +    }
    +
    +    @ExportMessage
    +    protected int getArraySize() {
    +        return 16;
    +    }
    +
    +    @ExportMessage
    +    protected boolean isArrayElementReadable(long index) {
    +        return index < 16;
    +    }
    +
    +    @ExportMessage
    +    protected byte readArrayElement(long index) throws InvalidArrayIndexException {
    +        if (index >= 16) {
    +            throw InvalidArrayIndexException.create(index);
    +        }
    +        return bytes[(int) index];
    +    }
     }
    
    From 3c5edfca3333eec722cd3c7cbc6b314be17f9ff9 Mon Sep 17 00:00:00 2001
    From: Jirka Marsik 
    Date: Sun, 17 Dec 2023 23:55:38 +0100
    Subject: [PATCH 287/593] Fix global initialization in spectest module
    
    ---
     .../org/graalvm/wasm/predefined/spectest/SpectestModule.java  | 4 ++--
     1 file changed, 2 insertions(+), 2 deletions(-)
    
    diff --git a/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/predefined/spectest/SpectestModule.java b/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/predefined/spectest/SpectestModule.java
    index 7db473d51f21..4d0fc735c644 100644
    --- a/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/predefined/spectest/SpectestModule.java
    +++ b/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/predefined/spectest/SpectestModule.java
    @@ -67,8 +67,8 @@ protected WasmModule createModule(WasmLanguage language, WasmContext context, St
             defineFunction(context, module, "print_f64_f64", types(F64_TYPE, F64_TYPE), types(), new PrintNode(language, module));
             defineGlobal(module, "global_i32", I32_TYPE, GlobalModifier.CONSTANT, 666);
             defineGlobal(module, "global_i64", I64_TYPE, GlobalModifier.CONSTANT, 666L);
    -        defineGlobal(module, "global_f32", F32_TYPE, GlobalModifier.CONSTANT, Float.floatToRawIntBits(666.0f));
    -        defineGlobal(module, "global_f64", F64_TYPE, GlobalModifier.CONSTANT, Double.doubleToRawLongBits(666.0));
    +        defineGlobal(module, "global_f32", F32_TYPE, GlobalModifier.CONSTANT, 666.0f);
    +        defineGlobal(module, "global_f64", F64_TYPE, GlobalModifier.CONSTANT, 666.0);
             defineTable(context, module, "table", 10, 20, WasmType.FUNCREF_TYPE);
             defineMemory(context, module, "memory", 1, 2, false, false);
             if (context.getContextOptions().supportThreads() && context.getContextOptions().useUnsafeMemory()) {
    
    From 715a07ecd477945246c2a4ca725af2b5c1443713 Mon Sep 17 00:00:00 2001
    From: Jirka Marsik 
    Date: Mon, 18 Dec 2023 10:53:00 +0100
    Subject: [PATCH 288/593] Add support for all f64x2 ops and for v128.load
    
    ---
     .../src/org/graalvm/wasm/BinaryParser.java    | 153 ++++++++++--------
     .../org/graalvm/wasm/api/VectorOperators.java |  31 +++-
     .../org/graalvm/wasm/constants/Bytecode.java  |  18 +++
     .../graalvm/wasm/constants/Instructions.java  |  18 +++
     .../wasm/memory/ByteArrayWasmMemory.java      |  10 ++
     .../graalvm/wasm/memory/NativeWasmMemory.java |   9 ++
     .../graalvm/wasm/memory/UnsafeWasmMemory.java |   9 ++
     .../org/graalvm/wasm/memory/WasmMemory.java   |   3 +
     .../graalvm/wasm/nodes/WasmFunctionNode.java  | 136 ++++++++++++++--
     .../wasm/parser/bytecode/BytecodeParser.java  |  36 +++++
     .../parser/bytecode/RuntimeBytecodeGen.java   |   6 +-
     .../wasm/parser/validation/ParserState.java   |   9 +-
     12 files changed, 351 insertions(+), 87 deletions(-)
    
    diff --git a/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/BinaryParser.java b/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/BinaryParser.java
    index 77386f4dc5c0..9ce7d5f4228d 100644
    --- a/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/BinaryParser.java
    +++ b/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/BinaryParser.java
    @@ -1530,15 +1530,15 @@ private void readNumericInstructions(ParserState state, int opcode) {
                     switch (atomicOpcode) {
                         case Instructions.ATOMIC_NOTIFY:
                             atomicNotify(state, longMultiResult);
    -                        state.addAtomicMemoryInstruction(Bytecode.ATOMIC_NOTIFY, (int) longMultiResult[0], longMultiResult[1], module.memoryHasIndexType64((int) longMultiResult[0]));
    +                        state.addExtendedMemoryInstruction(Bytecode.ATOMIC_NOTIFY, (int) longMultiResult[0], longMultiResult[1], module.memoryHasIndexType64((int) longMultiResult[0]));
                             break;
                         case Instructions.ATOMIC_WAIT32:
                             atomicWait(state, I32_TYPE, 32, longMultiResult);
    -                        state.addAtomicMemoryInstruction(Bytecode.ATOMIC_WAIT32, (int) longMultiResult[0], longMultiResult[1], module.memoryHasIndexType64((int) longMultiResult[0]));
    +                        state.addExtendedMemoryInstruction(Bytecode.ATOMIC_WAIT32, (int) longMultiResult[0], longMultiResult[1], module.memoryHasIndexType64((int) longMultiResult[0]));
                             break;
                         case Instructions.ATOMIC_WAIT64:
                             atomicWait(state, I64_TYPE, 64, longMultiResult);
    -                        state.addAtomicMemoryInstruction(Bytecode.ATOMIC_WAIT64, (int) longMultiResult[0], longMultiResult[1], module.memoryHasIndexType64((int) longMultiResult[0]));
    +                        state.addExtendedMemoryInstruction(Bytecode.ATOMIC_WAIT64, (int) longMultiResult[0], longMultiResult[1], module.memoryHasIndexType64((int) longMultiResult[0]));
                             break;
                         case Instructions.ATOMIC_FENCE:
                             read1();
    @@ -1546,255 +1546,255 @@ private void readNumericInstructions(ParserState state, int opcode) {
                             break;
                         case Instructions.ATOMIC_I32_LOAD:
                             atomicLoad(state, I32_TYPE, 32, longMultiResult);
    -                        state.addAtomicMemoryInstruction(Bytecode.ATOMIC_I32_LOAD, (int) longMultiResult[0], longMultiResult[1], module.memoryHasIndexType64((int) longMultiResult[0]));
    +                        state.addExtendedMemoryInstruction(Bytecode.ATOMIC_I32_LOAD, (int) longMultiResult[0], longMultiResult[1], module.memoryHasIndexType64((int) longMultiResult[0]));
                             break;
                         case Instructions.ATOMIC_I64_LOAD:
                             atomicLoad(state, I64_TYPE, 64, longMultiResult);
    -                        state.addAtomicMemoryInstruction(Bytecode.ATOMIC_I64_LOAD, (int) longMultiResult[0], longMultiResult[1], module.memoryHasIndexType64((int) longMultiResult[0]));
    +                        state.addExtendedMemoryInstruction(Bytecode.ATOMIC_I64_LOAD, (int) longMultiResult[0], longMultiResult[1], module.memoryHasIndexType64((int) longMultiResult[0]));
                             break;
                         case Instructions.ATOMIC_I32_LOAD8_U:
                             atomicLoad(state, I32_TYPE, 8, longMultiResult);
    -                        state.addAtomicMemoryInstruction(Bytecode.ATOMIC_I32_LOAD8_U, (int) longMultiResult[0], longMultiResult[1], module.memoryHasIndexType64((int) longMultiResult[0]));
    +                        state.addExtendedMemoryInstruction(Bytecode.ATOMIC_I32_LOAD8_U, (int) longMultiResult[0], longMultiResult[1], module.memoryHasIndexType64((int) longMultiResult[0]));
                             break;
                         case Instructions.ATOMIC_I32_LOAD16_U:
                             atomicLoad(state, I32_TYPE, 16, longMultiResult);
    -                        state.addAtomicMemoryInstruction(Bytecode.ATOMIC_I32_LOAD16_U, (int) longMultiResult[0], longMultiResult[1], module.memoryHasIndexType64((int) longMultiResult[0]));
    +                        state.addExtendedMemoryInstruction(Bytecode.ATOMIC_I32_LOAD16_U, (int) longMultiResult[0], longMultiResult[1], module.memoryHasIndexType64((int) longMultiResult[0]));
                             break;
                         case Instructions.ATOMIC_I64_LOAD8_U:
                             atomicLoad(state, I64_TYPE, 8, longMultiResult);
    -                        state.addAtomicMemoryInstruction(Bytecode.ATOMIC_I64_LOAD8_U, (int) longMultiResult[0], longMultiResult[1], module.memoryHasIndexType64((int) longMultiResult[0]));
    +                        state.addExtendedMemoryInstruction(Bytecode.ATOMIC_I64_LOAD8_U, (int) longMultiResult[0], longMultiResult[1], module.memoryHasIndexType64((int) longMultiResult[0]));
                             break;
                         case Instructions.ATOMIC_I64_LOAD16_U:
                             atomicLoad(state, I64_TYPE, 16, longMultiResult);
    -                        state.addAtomicMemoryInstruction(Bytecode.ATOMIC_I64_LOAD16_U, (int) longMultiResult[0], longMultiResult[1], module.memoryHasIndexType64((int) longMultiResult[0]));
    +                        state.addExtendedMemoryInstruction(Bytecode.ATOMIC_I64_LOAD16_U, (int) longMultiResult[0], longMultiResult[1], module.memoryHasIndexType64((int) longMultiResult[0]));
                             break;
                         case Instructions.ATOMIC_I64_LOAD32_U:
                             atomicLoad(state, I64_TYPE, 32, longMultiResult);
    -                        state.addAtomicMemoryInstruction(Bytecode.ATOMIC_I64_LOAD32_U, (int) longMultiResult[0], longMultiResult[1], module.memoryHasIndexType64((int) longMultiResult[0]));
    +                        state.addExtendedMemoryInstruction(Bytecode.ATOMIC_I64_LOAD32_U, (int) longMultiResult[0], longMultiResult[1], module.memoryHasIndexType64((int) longMultiResult[0]));
                             break;
                         case Instructions.ATOMIC_I32_STORE:
                             atomicStore(state, I32_TYPE, 32, longMultiResult);
    -                        state.addAtomicMemoryInstruction(Bytecode.ATOMIC_I32_STORE, (int) longMultiResult[0], longMultiResult[1], module.memoryHasIndexType64((int) longMultiResult[0]));
    +                        state.addExtendedMemoryInstruction(Bytecode.ATOMIC_I32_STORE, (int) longMultiResult[0], longMultiResult[1], module.memoryHasIndexType64((int) longMultiResult[0]));
                             break;
                         case Instructions.ATOMIC_I64_STORE:
                             atomicStore(state, I64_TYPE, 64, longMultiResult);
    -                        state.addAtomicMemoryInstruction(Bytecode.ATOMIC_I64_STORE, (int) longMultiResult[0], longMultiResult[1], module.memoryHasIndexType64((int) longMultiResult[0]));
    +                        state.addExtendedMemoryInstruction(Bytecode.ATOMIC_I64_STORE, (int) longMultiResult[0], longMultiResult[1], module.memoryHasIndexType64((int) longMultiResult[0]));
                             break;
                         case Instructions.ATOMIC_I32_STORE8:
                             atomicStore(state, I32_TYPE, 8, longMultiResult);
    -                        state.addAtomicMemoryInstruction(Bytecode.ATOMIC_I32_STORE8, (int) longMultiResult[0], longMultiResult[1], module.memoryHasIndexType64((int) longMultiResult[0]));
    +                        state.addExtendedMemoryInstruction(Bytecode.ATOMIC_I32_STORE8, (int) longMultiResult[0], longMultiResult[1], module.memoryHasIndexType64((int) longMultiResult[0]));
                             break;
                         case Instructions.ATOMIC_I32_STORE16:
                             atomicStore(state, I32_TYPE, 16, longMultiResult);
    -                        state.addAtomicMemoryInstruction(Bytecode.ATOMIC_I32_STORE16, (int) longMultiResult[0], longMultiResult[1], module.memoryHasIndexType64((int) longMultiResult[0]));
    +                        state.addExtendedMemoryInstruction(Bytecode.ATOMIC_I32_STORE16, (int) longMultiResult[0], longMultiResult[1], module.memoryHasIndexType64((int) longMultiResult[0]));
                             break;
                         case Instructions.ATOMIC_I64_STORE8:
                             atomicStore(state, I64_TYPE, 8, longMultiResult);
    -                        state.addAtomicMemoryInstruction(Bytecode.ATOMIC_I64_STORE8, (int) longMultiResult[0], longMultiResult[1], module.memoryHasIndexType64((int) longMultiResult[0]));
    +                        state.addExtendedMemoryInstruction(Bytecode.ATOMIC_I64_STORE8, (int) longMultiResult[0], longMultiResult[1], module.memoryHasIndexType64((int) longMultiResult[0]));
                             break;
                         case Instructions.ATOMIC_I64_STORE16:
                             atomicStore(state, I64_TYPE, 16, longMultiResult);
    -                        state.addAtomicMemoryInstruction(Bytecode.ATOMIC_I64_STORE16, (int) longMultiResult[0], longMultiResult[1], module.memoryHasIndexType64((int) longMultiResult[0]));
    +                        state.addExtendedMemoryInstruction(Bytecode.ATOMIC_I64_STORE16, (int) longMultiResult[0], longMultiResult[1], module.memoryHasIndexType64((int) longMultiResult[0]));
                             break;
                         case Instructions.ATOMIC_I64_STORE32:
                             atomicStore(state, I64_TYPE, 32, longMultiResult);
    -                        state.addAtomicMemoryInstruction(Bytecode.ATOMIC_I64_STORE32, (int) longMultiResult[0], longMultiResult[1], module.memoryHasIndexType64((int) longMultiResult[0]));
    +                        state.addExtendedMemoryInstruction(Bytecode.ATOMIC_I64_STORE32, (int) longMultiResult[0], longMultiResult[1], module.memoryHasIndexType64((int) longMultiResult[0]));
                             break;
                         case Instructions.ATOMIC_I32_RMW_ADD:
                             atomicReadModifyWrite(state, I32_TYPE, 32, longMultiResult);
    -                        state.addAtomicMemoryInstruction(Bytecode.ATOMIC_I32_RMW_ADD, (int) longMultiResult[0], longMultiResult[1], module.memoryHasIndexType64((int) longMultiResult[0]));
    +                        state.addExtendedMemoryInstruction(Bytecode.ATOMIC_I32_RMW_ADD, (int) longMultiResult[0], longMultiResult[1], module.memoryHasIndexType64((int) longMultiResult[0]));
                             break;
                         case Instructions.ATOMIC_I64_RMW_ADD:
                             atomicReadModifyWrite(state, I64_TYPE, 64, longMultiResult);
    -                        state.addAtomicMemoryInstruction(Bytecode.ATOMIC_I64_RMW_ADD, (int) longMultiResult[0], longMultiResult[1], module.memoryHasIndexType64((int) longMultiResult[0]));
    +                        state.addExtendedMemoryInstruction(Bytecode.ATOMIC_I64_RMW_ADD, (int) longMultiResult[0], longMultiResult[1], module.memoryHasIndexType64((int) longMultiResult[0]));
                             break;
                         case Instructions.ATOMIC_I32_RMW8_U_ADD:
                             atomicReadModifyWrite(state, I32_TYPE, 8, longMultiResult);
    -                        state.addAtomicMemoryInstruction(Bytecode.ATOMIC_I32_RMW8_U_ADD, (int) longMultiResult[0], longMultiResult[1], module.memoryHasIndexType64((int) longMultiResult[0]));
    +                        state.addExtendedMemoryInstruction(Bytecode.ATOMIC_I32_RMW8_U_ADD, (int) longMultiResult[0], longMultiResult[1], module.memoryHasIndexType64((int) longMultiResult[0]));
                             break;
                         case Instructions.ATOMIC_I32_RMW16_U_ADD:
                             atomicReadModifyWrite(state, I32_TYPE, 16, longMultiResult);
    -                        state.addAtomicMemoryInstruction(Bytecode.ATOMIC_I32_RMW16_U_ADD, (int) longMultiResult[0], longMultiResult[1], module.memoryHasIndexType64((int) longMultiResult[0]));
    +                        state.addExtendedMemoryInstruction(Bytecode.ATOMIC_I32_RMW16_U_ADD, (int) longMultiResult[0], longMultiResult[1], module.memoryHasIndexType64((int) longMultiResult[0]));
                             break;
                         case Instructions.ATOMIC_I64_RMW8_U_ADD:
                             atomicReadModifyWrite(state, I64_TYPE, 8, longMultiResult);
    -                        state.addAtomicMemoryInstruction(Bytecode.ATOMIC_I64_RMW8_U_ADD, (int) longMultiResult[0], longMultiResult[1], module.memoryHasIndexType64((int) longMultiResult[0]));
    +                        state.addExtendedMemoryInstruction(Bytecode.ATOMIC_I64_RMW8_U_ADD, (int) longMultiResult[0], longMultiResult[1], module.memoryHasIndexType64((int) longMultiResult[0]));
                             break;
                         case Instructions.ATOMIC_I64_RMW16_U_ADD:
                             atomicReadModifyWrite(state, I64_TYPE, 16, longMultiResult);
    -                        state.addAtomicMemoryInstruction(Bytecode.ATOMIC_I64_RMW16_U_ADD, (int) longMultiResult[0], longMultiResult[1], module.memoryHasIndexType64((int) longMultiResult[0]));
    +                        state.addExtendedMemoryInstruction(Bytecode.ATOMIC_I64_RMW16_U_ADD, (int) longMultiResult[0], longMultiResult[1], module.memoryHasIndexType64((int) longMultiResult[0]));
                             break;
                         case Instructions.ATOMIC_I64_RMW32_U_ADD:
                             atomicReadModifyWrite(state, I64_TYPE, 32, longMultiResult);
    -                        state.addAtomicMemoryInstruction(Bytecode.ATOMIC_I64_RMW32_U_ADD, (int) longMultiResult[0], longMultiResult[1], module.memoryHasIndexType64((int) longMultiResult[0]));
    +                        state.addExtendedMemoryInstruction(Bytecode.ATOMIC_I64_RMW32_U_ADD, (int) longMultiResult[0], longMultiResult[1], module.memoryHasIndexType64((int) longMultiResult[0]));
                             break;
                         case Instructions.ATOMIC_I32_RMW_SUB:
                             atomicReadModifyWrite(state, I32_TYPE, 32, longMultiResult);
    -                        state.addAtomicMemoryInstruction(Bytecode.ATOMIC_I32_RMW_SUB, (int) longMultiResult[0], longMultiResult[1], module.memoryHasIndexType64((int) longMultiResult[0]));
    +                        state.addExtendedMemoryInstruction(Bytecode.ATOMIC_I32_RMW_SUB, (int) longMultiResult[0], longMultiResult[1], module.memoryHasIndexType64((int) longMultiResult[0]));
                             break;
                         case Instructions.ATOMIC_I64_RMW_SUB:
                             atomicReadModifyWrite(state, I64_TYPE, 64, longMultiResult);
    -                        state.addAtomicMemoryInstruction(Bytecode.ATOMIC_I64_RMW_SUB, (int) longMultiResult[0], longMultiResult[1], module.memoryHasIndexType64((int) longMultiResult[0]));
    +                        state.addExtendedMemoryInstruction(Bytecode.ATOMIC_I64_RMW_SUB, (int) longMultiResult[0], longMultiResult[1], module.memoryHasIndexType64((int) longMultiResult[0]));
                             break;
                         case Instructions.ATOMIC_I32_RMW8_U_SUB:
                             atomicReadModifyWrite(state, I32_TYPE, 8, longMultiResult);
    -                        state.addAtomicMemoryInstruction(Bytecode.ATOMIC_I32_RMW8_U_SUB, (int) longMultiResult[0], longMultiResult[1], module.memoryHasIndexType64((int) longMultiResult[0]));
    +                        state.addExtendedMemoryInstruction(Bytecode.ATOMIC_I32_RMW8_U_SUB, (int) longMultiResult[0], longMultiResult[1], module.memoryHasIndexType64((int) longMultiResult[0]));
                             break;
                         case Instructions.ATOMIC_I32_RMW16_U_SUB:
                             atomicReadModifyWrite(state, I32_TYPE, 16, longMultiResult);
    -                        state.addAtomicMemoryInstruction(Bytecode.ATOMIC_I32_RMW16_U_SUB, (int) longMultiResult[0], longMultiResult[1], module.memoryHasIndexType64((int) longMultiResult[0]));
    +                        state.addExtendedMemoryInstruction(Bytecode.ATOMIC_I32_RMW16_U_SUB, (int) longMultiResult[0], longMultiResult[1], module.memoryHasIndexType64((int) longMultiResult[0]));
                             break;
                         case Instructions.ATOMIC_I64_RMW8_U_SUB:
                             atomicReadModifyWrite(state, I64_TYPE, 8, longMultiResult);
    -                        state.addAtomicMemoryInstruction(Bytecode.ATOMIC_I64_RMW8_U_SUB, (int) longMultiResult[0], longMultiResult[1], module.memoryHasIndexType64((int) longMultiResult[0]));
    +                        state.addExtendedMemoryInstruction(Bytecode.ATOMIC_I64_RMW8_U_SUB, (int) longMultiResult[0], longMultiResult[1], module.memoryHasIndexType64((int) longMultiResult[0]));
                             break;
                         case Instructions.ATOMIC_I64_RMW16_U_SUB:
                             atomicReadModifyWrite(state, I64_TYPE, 16, longMultiResult);
    -                        state.addAtomicMemoryInstruction(Bytecode.ATOMIC_I64_RMW16_U_SUB, (int) longMultiResult[0], longMultiResult[1], module.memoryHasIndexType64((int) longMultiResult[0]));
    +                        state.addExtendedMemoryInstruction(Bytecode.ATOMIC_I64_RMW16_U_SUB, (int) longMultiResult[0], longMultiResult[1], module.memoryHasIndexType64((int) longMultiResult[0]));
                             break;
                         case Instructions.ATOMIC_I64_RMW32_U_SUB:
                             atomicReadModifyWrite(state, I64_TYPE, 32, longMultiResult);
    -                        state.addAtomicMemoryInstruction(Bytecode.ATOMIC_I64_RMW32_U_SUB, (int) longMultiResult[0], longMultiResult[1], module.memoryHasIndexType64((int) longMultiResult[0]));
    +                        state.addExtendedMemoryInstruction(Bytecode.ATOMIC_I64_RMW32_U_SUB, (int) longMultiResult[0], longMultiResult[1], module.memoryHasIndexType64((int) longMultiResult[0]));
                             break;
                         case Instructions.ATOMIC_I32_RMW_AND:
                             atomicReadModifyWrite(state, I32_TYPE, 32, longMultiResult);
    -                        state.addAtomicMemoryInstruction(Bytecode.ATOMIC_I32_RMW_AND, (int) longMultiResult[0], longMultiResult[1], module.memoryHasIndexType64((int) longMultiResult[0]));
    +                        state.addExtendedMemoryInstruction(Bytecode.ATOMIC_I32_RMW_AND, (int) longMultiResult[0], longMultiResult[1], module.memoryHasIndexType64((int) longMultiResult[0]));
                             break;
                         case Instructions.ATOMIC_I64_RMW_AND:
                             atomicReadModifyWrite(state, I64_TYPE, 64, longMultiResult);
    -                        state.addAtomicMemoryInstruction(Bytecode.ATOMIC_I64_RMW_AND, (int) longMultiResult[0], longMultiResult[1], module.memoryHasIndexType64((int) longMultiResult[0]));
    +                        state.addExtendedMemoryInstruction(Bytecode.ATOMIC_I64_RMW_AND, (int) longMultiResult[0], longMultiResult[1], module.memoryHasIndexType64((int) longMultiResult[0]));
                             break;
                         case Instructions.ATOMIC_I32_RMW8_U_AND:
                             atomicReadModifyWrite(state, I32_TYPE, 8, longMultiResult);
    -                        state.addAtomicMemoryInstruction(Bytecode.ATOMIC_I32_RMW8_U_AND, (int) longMultiResult[0], longMultiResult[1], module.memoryHasIndexType64((int) longMultiResult[0]));
    +                        state.addExtendedMemoryInstruction(Bytecode.ATOMIC_I32_RMW8_U_AND, (int) longMultiResult[0], longMultiResult[1], module.memoryHasIndexType64((int) longMultiResult[0]));
                             break;
                         case Instructions.ATOMIC_I32_RMW16_U_AND:
                             atomicReadModifyWrite(state, I32_TYPE, 16, longMultiResult);
    -                        state.addAtomicMemoryInstruction(Bytecode.ATOMIC_I32_RMW16_U_AND, (int) longMultiResult[0], longMultiResult[1], module.memoryHasIndexType64((int) longMultiResult[0]));
    +                        state.addExtendedMemoryInstruction(Bytecode.ATOMIC_I32_RMW16_U_AND, (int) longMultiResult[0], longMultiResult[1], module.memoryHasIndexType64((int) longMultiResult[0]));
                             break;
                         case Instructions.ATOMIC_I64_RMW8_U_AND:
                             atomicReadModifyWrite(state, I64_TYPE, 8, longMultiResult);
    -                        state.addAtomicMemoryInstruction(Bytecode.ATOMIC_I64_RMW8_U_AND, (int) longMultiResult[0], longMultiResult[1], module.memoryHasIndexType64((int) longMultiResult[0]));
    +                        state.addExtendedMemoryInstruction(Bytecode.ATOMIC_I64_RMW8_U_AND, (int) longMultiResult[0], longMultiResult[1], module.memoryHasIndexType64((int) longMultiResult[0]));
                             break;
                         case Instructions.ATOMIC_I64_RMW16_U_AND:
                             atomicReadModifyWrite(state, I64_TYPE, 16, longMultiResult);
    -                        state.addAtomicMemoryInstruction(Bytecode.ATOMIC_I64_RMW16_U_AND, (int) longMultiResult[0], longMultiResult[1], module.memoryHasIndexType64((int) longMultiResult[0]));
    +                        state.addExtendedMemoryInstruction(Bytecode.ATOMIC_I64_RMW16_U_AND, (int) longMultiResult[0], longMultiResult[1], module.memoryHasIndexType64((int) longMultiResult[0]));
                             break;
                         case Instructions.ATOMIC_I64_RMW32_U_AND:
                             atomicReadModifyWrite(state, I64_TYPE, 32, longMultiResult);
    -                        state.addAtomicMemoryInstruction(Bytecode.ATOMIC_I64_RMW32_U_AND, (int) longMultiResult[0], longMultiResult[1], module.memoryHasIndexType64((int) longMultiResult[0]));
    +                        state.addExtendedMemoryInstruction(Bytecode.ATOMIC_I64_RMW32_U_AND, (int) longMultiResult[0], longMultiResult[1], module.memoryHasIndexType64((int) longMultiResult[0]));
                             break;
                         case Instructions.ATOMIC_I32_RMW_OR:
                             atomicReadModifyWrite(state, I32_TYPE, 32, longMultiResult);
    -                        state.addAtomicMemoryInstruction(Bytecode.ATOMIC_I32_RMW_OR, (int) longMultiResult[0], longMultiResult[1], module.memoryHasIndexType64((int) longMultiResult[0]));
    +                        state.addExtendedMemoryInstruction(Bytecode.ATOMIC_I32_RMW_OR, (int) longMultiResult[0], longMultiResult[1], module.memoryHasIndexType64((int) longMultiResult[0]));
                             break;
                         case Instructions.ATOMIC_I64_RMW_OR:
                             atomicReadModifyWrite(state, I64_TYPE, 64, longMultiResult);
    -                        state.addAtomicMemoryInstruction(Bytecode.ATOMIC_I64_RMW_OR, (int) longMultiResult[0], longMultiResult[1], module.memoryHasIndexType64((int) longMultiResult[0]));
    +                        state.addExtendedMemoryInstruction(Bytecode.ATOMIC_I64_RMW_OR, (int) longMultiResult[0], longMultiResult[1], module.memoryHasIndexType64((int) longMultiResult[0]));
                             break;
                         case Instructions.ATOMIC_I32_RMW8_U_OR:
                             atomicReadModifyWrite(state, I32_TYPE, 8, longMultiResult);
    -                        state.addAtomicMemoryInstruction(Bytecode.ATOMIC_I32_RMW8_U_OR, (int) longMultiResult[0], longMultiResult[1], module.memoryHasIndexType64((int) longMultiResult[0]));
    +                        state.addExtendedMemoryInstruction(Bytecode.ATOMIC_I32_RMW8_U_OR, (int) longMultiResult[0], longMultiResult[1], module.memoryHasIndexType64((int) longMultiResult[0]));
                             break;
                         case Instructions.ATOMIC_I32_RMW16_U_OR:
                             atomicReadModifyWrite(state, I32_TYPE, 16, longMultiResult);
    -                        state.addAtomicMemoryInstruction(Bytecode.ATOMIC_I32_RMW16_U_OR, (int) longMultiResult[0], longMultiResult[1], module.memoryHasIndexType64((int) longMultiResult[0]));
    +                        state.addExtendedMemoryInstruction(Bytecode.ATOMIC_I32_RMW16_U_OR, (int) longMultiResult[0], longMultiResult[1], module.memoryHasIndexType64((int) longMultiResult[0]));
                             break;
                         case Instructions.ATOMIC_I64_RMW8_U_OR:
                             atomicReadModifyWrite(state, I64_TYPE, 8, longMultiResult);
    -                        state.addAtomicMemoryInstruction(Bytecode.ATOMIC_I64_RMW8_U_OR, (int) longMultiResult[0], longMultiResult[1], module.memoryHasIndexType64((int) longMultiResult[0]));
    +                        state.addExtendedMemoryInstruction(Bytecode.ATOMIC_I64_RMW8_U_OR, (int) longMultiResult[0], longMultiResult[1], module.memoryHasIndexType64((int) longMultiResult[0]));
                             break;
                         case Instructions.ATOMIC_I64_RMW16_U_OR:
                             atomicReadModifyWrite(state, I64_TYPE, 16, longMultiResult);
    -                        state.addAtomicMemoryInstruction(Bytecode.ATOMIC_I64_RMW16_U_OR, (int) longMultiResult[0], longMultiResult[1], module.memoryHasIndexType64((int) longMultiResult[0]));
    +                        state.addExtendedMemoryInstruction(Bytecode.ATOMIC_I64_RMW16_U_OR, (int) longMultiResult[0], longMultiResult[1], module.memoryHasIndexType64((int) longMultiResult[0]));
                             break;
                         case Instructions.ATOMIC_I64_RMW32_U_OR:
                             atomicReadModifyWrite(state, I64_TYPE, 32, longMultiResult);
    -                        state.addAtomicMemoryInstruction(Bytecode.ATOMIC_I64_RMW32_U_OR, (int) longMultiResult[0], longMultiResult[1], module.memoryHasIndexType64((int) longMultiResult[0]));
    +                        state.addExtendedMemoryInstruction(Bytecode.ATOMIC_I64_RMW32_U_OR, (int) longMultiResult[0], longMultiResult[1], module.memoryHasIndexType64((int) longMultiResult[0]));
                             break;
                         case Instructions.ATOMIC_I32_RMW_XOR:
                             atomicReadModifyWrite(state, I32_TYPE, 32, longMultiResult);
    -                        state.addAtomicMemoryInstruction(Bytecode.ATOMIC_I32_RMW_XOR, (int) longMultiResult[0], longMultiResult[1], module.memoryHasIndexType64((int) longMultiResult[0]));
    +                        state.addExtendedMemoryInstruction(Bytecode.ATOMIC_I32_RMW_XOR, (int) longMultiResult[0], longMultiResult[1], module.memoryHasIndexType64((int) longMultiResult[0]));
                             break;
                         case Instructions.ATOMIC_I64_RMW_XOR:
                             atomicReadModifyWrite(state, I64_TYPE, 64, longMultiResult);
    -                        state.addAtomicMemoryInstruction(Bytecode.ATOMIC_I64_RMW_XOR, (int) longMultiResult[0], longMultiResult[1], module.memoryHasIndexType64((int) longMultiResult[0]));
    +                        state.addExtendedMemoryInstruction(Bytecode.ATOMIC_I64_RMW_XOR, (int) longMultiResult[0], longMultiResult[1], module.memoryHasIndexType64((int) longMultiResult[0]));
                             break;
                         case Instructions.ATOMIC_I32_RMW8_U_XOR:
                             atomicReadModifyWrite(state, I32_TYPE, 8, longMultiResult);
    -                        state.addAtomicMemoryInstruction(Bytecode.ATOMIC_I32_RMW8_U_XOR, (int) longMultiResult[0], longMultiResult[1], module.memoryHasIndexType64((int) longMultiResult[0]));
    +                        state.addExtendedMemoryInstruction(Bytecode.ATOMIC_I32_RMW8_U_XOR, (int) longMultiResult[0], longMultiResult[1], module.memoryHasIndexType64((int) longMultiResult[0]));
                             break;
                         case Instructions.ATOMIC_I32_RMW16_U_XOR:
                             atomicReadModifyWrite(state, I32_TYPE, 16, longMultiResult);
    -                        state.addAtomicMemoryInstruction(Bytecode.ATOMIC_I32_RMW16_U_XOR, (int) longMultiResult[0], longMultiResult[1], module.memoryHasIndexType64((int) longMultiResult[0]));
    +                        state.addExtendedMemoryInstruction(Bytecode.ATOMIC_I32_RMW16_U_XOR, (int) longMultiResult[0], longMultiResult[1], module.memoryHasIndexType64((int) longMultiResult[0]));
                             break;
                         case Instructions.ATOMIC_I64_RMW8_U_XOR:
                             atomicReadModifyWrite(state, I64_TYPE, 8, longMultiResult);
    -                        state.addAtomicMemoryInstruction(Bytecode.ATOMIC_I64_RMW8_U_XOR, (int) longMultiResult[0], longMultiResult[1], module.memoryHasIndexType64((int) longMultiResult[0]));
    +                        state.addExtendedMemoryInstruction(Bytecode.ATOMIC_I64_RMW8_U_XOR, (int) longMultiResult[0], longMultiResult[1], module.memoryHasIndexType64((int) longMultiResult[0]));
                             break;
                         case Instructions.ATOMIC_I64_RMW16_U_XOR:
                             atomicReadModifyWrite(state, I64_TYPE, 16, longMultiResult);
    -                        state.addAtomicMemoryInstruction(Bytecode.ATOMIC_I64_RMW16_U_XOR, (int) longMultiResult[0], longMultiResult[1], module.memoryHasIndexType64((int) longMultiResult[0]));
    +                        state.addExtendedMemoryInstruction(Bytecode.ATOMIC_I64_RMW16_U_XOR, (int) longMultiResult[0], longMultiResult[1], module.memoryHasIndexType64((int) longMultiResult[0]));
                             break;
                         case Instructions.ATOMIC_I64_RMW32_U_XOR:
                             atomicReadModifyWrite(state, I64_TYPE, 32, longMultiResult);
    -                        state.addAtomicMemoryInstruction(Bytecode.ATOMIC_I64_RMW32_U_XOR, (int) longMultiResult[0], longMultiResult[1], module.memoryHasIndexType64((int) longMultiResult[0]));
    +                        state.addExtendedMemoryInstruction(Bytecode.ATOMIC_I64_RMW32_U_XOR, (int) longMultiResult[0], longMultiResult[1], module.memoryHasIndexType64((int) longMultiResult[0]));
                             break;
                         case Instructions.ATOMIC_I32_RMW_XCHG:
                             atomicReadModifyWrite(state, I32_TYPE, 32, longMultiResult);
    -                        state.addAtomicMemoryInstruction(Bytecode.ATOMIC_I32_RMW_XCHG, (int) longMultiResult[0], longMultiResult[1], module.memoryHasIndexType64((int) longMultiResult[0]));
    +                        state.addExtendedMemoryInstruction(Bytecode.ATOMIC_I32_RMW_XCHG, (int) longMultiResult[0], longMultiResult[1], module.memoryHasIndexType64((int) longMultiResult[0]));
                             break;
                         case Instructions.ATOMIC_I64_RMW_XCHG:
                             atomicReadModifyWrite(state, I64_TYPE, 64, longMultiResult);
    -                        state.addAtomicMemoryInstruction(Bytecode.ATOMIC_I64_RMW_XCHG, (int) longMultiResult[0], longMultiResult[1], module.memoryHasIndexType64((int) longMultiResult[0]));
    +                        state.addExtendedMemoryInstruction(Bytecode.ATOMIC_I64_RMW_XCHG, (int) longMultiResult[0], longMultiResult[1], module.memoryHasIndexType64((int) longMultiResult[0]));
                             break;
                         case Instructions.ATOMIC_I32_RMW8_U_XCHG:
                             atomicReadModifyWrite(state, I32_TYPE, 8, longMultiResult);
    -                        state.addAtomicMemoryInstruction(Bytecode.ATOMIC_I32_RMW8_U_XCHG, (int) longMultiResult[0], longMultiResult[1], module.memoryHasIndexType64((int) longMultiResult[0]));
    +                        state.addExtendedMemoryInstruction(Bytecode.ATOMIC_I32_RMW8_U_XCHG, (int) longMultiResult[0], longMultiResult[1], module.memoryHasIndexType64((int) longMultiResult[0]));
                             break;
                         case Instructions.ATOMIC_I32_RMW16_U_XCHG:
                             atomicReadModifyWrite(state, I32_TYPE, 16, longMultiResult);
    -                        state.addAtomicMemoryInstruction(Bytecode.ATOMIC_I32_RMW16_U_XCHG, (int) longMultiResult[0], longMultiResult[1], module.memoryHasIndexType64((int) longMultiResult[0]));
    +                        state.addExtendedMemoryInstruction(Bytecode.ATOMIC_I32_RMW16_U_XCHG, (int) longMultiResult[0], longMultiResult[1], module.memoryHasIndexType64((int) longMultiResult[0]));
                             break;
                         case Instructions.ATOMIC_I64_RMW8_U_XCHG:
                             atomicReadModifyWrite(state, I64_TYPE, 8, longMultiResult);
    -                        state.addAtomicMemoryInstruction(Bytecode.ATOMIC_I64_RMW8_U_XCHG, (int) longMultiResult[0], longMultiResult[1], module.memoryHasIndexType64((int) longMultiResult[0]));
    +                        state.addExtendedMemoryInstruction(Bytecode.ATOMIC_I64_RMW8_U_XCHG, (int) longMultiResult[0], longMultiResult[1], module.memoryHasIndexType64((int) longMultiResult[0]));
                             break;
                         case Instructions.ATOMIC_I64_RMW16_U_XCHG:
                             atomicReadModifyWrite(state, I64_TYPE, 16, longMultiResult);
    -                        state.addAtomicMemoryInstruction(Bytecode.ATOMIC_I64_RMW16_U_XCHG, (int) longMultiResult[0], longMultiResult[1], module.memoryHasIndexType64((int) longMultiResult[0]));
    +                        state.addExtendedMemoryInstruction(Bytecode.ATOMIC_I64_RMW16_U_XCHG, (int) longMultiResult[0], longMultiResult[1], module.memoryHasIndexType64((int) longMultiResult[0]));
                             break;
                         case Instructions.ATOMIC_I64_RMW32_U_XCHG:
                             atomicReadModifyWrite(state, I64_TYPE, 32, longMultiResult);
    -                        state.addAtomicMemoryInstruction(Bytecode.ATOMIC_I64_RMW32_U_XCHG, (int) longMultiResult[0], longMultiResult[1], module.memoryHasIndexType64((int) longMultiResult[0]));
    +                        state.addExtendedMemoryInstruction(Bytecode.ATOMIC_I64_RMW32_U_XCHG, (int) longMultiResult[0], longMultiResult[1], module.memoryHasIndexType64((int) longMultiResult[0]));
                             break;
                         case Instructions.ATOMIC_I32_RMW_CMPXCHG:
                             atomicCompareExchange(state, I32_TYPE, 32, longMultiResult);
    -                        state.addAtomicMemoryInstruction(Bytecode.ATOMIC_I32_RMW_CMPXCHG, (int) longMultiResult[0], longMultiResult[1], module.memoryHasIndexType64((int) longMultiResult[0]));
    +                        state.addExtendedMemoryInstruction(Bytecode.ATOMIC_I32_RMW_CMPXCHG, (int) longMultiResult[0], longMultiResult[1], module.memoryHasIndexType64((int) longMultiResult[0]));
                             break;
                         case Instructions.ATOMIC_I64_RMW_CMPXCHG:
                             atomicCompareExchange(state, I64_TYPE, 64, longMultiResult);
    -                        state.addAtomicMemoryInstruction(Bytecode.ATOMIC_I64_RMW_CMPXCHG, (int) longMultiResult[0], longMultiResult[1], module.memoryHasIndexType64((int) longMultiResult[0]));
    +                        state.addExtendedMemoryInstruction(Bytecode.ATOMIC_I64_RMW_CMPXCHG, (int) longMultiResult[0], longMultiResult[1], module.memoryHasIndexType64((int) longMultiResult[0]));
                             break;
                         case Instructions.ATOMIC_I32_RMW8_U_CMPXCHG:
                             atomicCompareExchange(state, I32_TYPE, 8, longMultiResult);
    -                        state.addAtomicMemoryInstruction(Bytecode.ATOMIC_I32_RMW8_U_CMPXCHG, (int) longMultiResult[0], longMultiResult[1], module.memoryHasIndexType64((int) longMultiResult[0]));
    +                        state.addExtendedMemoryInstruction(Bytecode.ATOMIC_I32_RMW8_U_CMPXCHG, (int) longMultiResult[0], longMultiResult[1], module.memoryHasIndexType64((int) longMultiResult[0]));
                             break;
                         case Instructions.ATOMIC_I32_RMW16_U_CMPXCHG:
                             atomicCompareExchange(state, I32_TYPE, 16, longMultiResult);
    -                        state.addAtomicMemoryInstruction(Bytecode.ATOMIC_I32_RMW16_U_CMPXCHG, (int) longMultiResult[0], longMultiResult[1], module.memoryHasIndexType64((int) longMultiResult[0]));
    +                        state.addExtendedMemoryInstruction(Bytecode.ATOMIC_I32_RMW16_U_CMPXCHG, (int) longMultiResult[0], longMultiResult[1], module.memoryHasIndexType64((int) longMultiResult[0]));
                             break;
                         case Instructions.ATOMIC_I64_RMW8_U_CMPXCHG:
                             atomicCompareExchange(state, I64_TYPE, 8, longMultiResult);
    -                        state.addAtomicMemoryInstruction(Bytecode.ATOMIC_I64_RMW8_U_CMPXCHG, (int) longMultiResult[0], longMultiResult[1], module.memoryHasIndexType64((int) longMultiResult[0]));
    +                        state.addExtendedMemoryInstruction(Bytecode.ATOMIC_I64_RMW8_U_CMPXCHG, (int) longMultiResult[0], longMultiResult[1], module.memoryHasIndexType64((int) longMultiResult[0]));
                             break;
                         case Instructions.ATOMIC_I64_RMW16_U_CMPXCHG:
                             atomicCompareExchange(state, I64_TYPE, 16, longMultiResult);
    -                        state.addAtomicMemoryInstruction(Bytecode.ATOMIC_I64_RMW16_U_CMPXCHG, (int) longMultiResult[0], longMultiResult[1], module.memoryHasIndexType64((int) longMultiResult[0]));
    +                        state.addExtendedMemoryInstruction(Bytecode.ATOMIC_I64_RMW16_U_CMPXCHG, (int) longMultiResult[0], longMultiResult[1], module.memoryHasIndexType64((int) longMultiResult[0]));
                             break;
                         case Instructions.ATOMIC_I64_RMW32_U_CMPXCHG:
                             atomicCompareExchange(state, I64_TYPE, 32, longMultiResult);
    -                        state.addAtomicMemoryInstruction(Bytecode.ATOMIC_I64_RMW32_U_CMPXCHG, (int) longMultiResult[0], longMultiResult[1], module.memoryHasIndexType64((int) longMultiResult[0]));
    +                        state.addExtendedMemoryInstruction(Bytecode.ATOMIC_I64_RMW32_U_CMPXCHG, (int) longMultiResult[0], longMultiResult[1], module.memoryHasIndexType64((int) longMultiResult[0]));
                             break;
                         default:
                             fail(Failure.UNSPECIFIED_MALFORMED, "Unknown opcode: 0xFE 0x%02x", atomicOpcode);
    @@ -1804,6 +1804,10 @@ private void readNumericInstructions(ParserState state, int opcode) {
                     int vectorOpcode = read1() & 0xFF;
                     state.addVectorFlag();
                     switch (vectorOpcode) {
    +                    case Instructions.VECTOR_V128_LOAD:
    +                        load(state, V128_TYPE, 128, longMultiResult);
    +                        state.addExtendedMemoryInstruction(Bytecode.VECTOR_V128_LOAD, (int) longMultiResult[0], longMultiResult[1], module.memoryHasIndexType64((int) longMultiResult[0]));
    +                        break;
                         case Instructions.VECTOR_V128_CONST:
                             final Vector128 value = readUnsignedInt128();
                             state.push(V128_TYPE);
    @@ -1815,6 +1819,23 @@ private void readNumericInstructions(ParserState state, int opcode) {
                             state.push(I32_TYPE);
                             state.addInstruction(vectorOpcode);
                             break;
    +                    case Instructions.VECTOR_F64X2_CEIL:
    +                    case Instructions.VECTOR_F64X2_FLOOR:
    +                    case Instructions.VECTOR_F64X2_TRUNC:
    +                    case Instructions.VECTOR_F64X2_NEAREST:
    +                    case Instructions.VECTOR_F64X2_ABS:
    +                    case Instructions.VECTOR_F64X2_NEG:
    +                    case Instructions.VECTOR_F64X2_SQRT:
    +                        state.popChecked(V128_TYPE);
    +                        state.push(V128_TYPE);
    +                        state.addInstruction(vectorOpcode);
    +                        break;
    +                    case Instructions.VECTOR_F64X2_EQ:
    +                    case Instructions.VECTOR_F64X2_NE:
    +                    case Instructions.VECTOR_F64X2_LT:
    +                    case Instructions.VECTOR_F64X2_GT:
    +                    case Instructions.VECTOR_F64X2_LE:
    +                    case Instructions.VECTOR_F64X2_GE:
                         case Instructions.VECTOR_I32X4_ADD:
                         case Instructions.VECTOR_I32X4_SUB:
                         case Instructions.VECTOR_I32X4_MUL:
    diff --git a/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/api/VectorOperators.java b/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/api/VectorOperators.java
    index 9b92fbcec543..6424186712a5 100644
    --- a/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/api/VectorOperators.java
    +++ b/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/api/VectorOperators.java
    @@ -46,16 +46,30 @@ public class VectorOperators {
          * Vectorized integer binary operators. Corresponds to the {@code vibinop} production in the
          * WebAssembly spec.
          */
    -    public enum VIBinOp {
    +    public enum IBinOp {
             Add,
             Sub
         }
     
    +    /**
    +     * Vectorized floating-point unary operators. Corresponds to the {@code vfunop} production in
    +     * the WebAssembly spec.
    +     */
    +    public enum FUnOp {
    +        Abs,
    +        Neg,
    +        Sqrt,
    +        Ceil,
    +        Floor,
    +        Trunc,
    +        Nearest
    +    }
    +
         /**
          * Vectorized floating-point binary operators. Corresponds to the {@code vfbinop} production in
          * the WebAssembly spec.
          */
    -    public enum VFBinOp {
    +    public enum FBinOp {
             Add,
             Sub,
             Mul,
    @@ -65,4 +79,17 @@ public enum VFBinOp {
             Pmin,
             Pmax
         }
    +
    +    /**
    +     * Vectorized floating-point relational operators. Corresponds to the {@code vfrelop} production
    +     * in the WebAssembly spec.
    +     */
    +    public enum FRelOp {
    +        Eq,
    +        Ne,
    +        Lt,
    +        Gt,
    +        Le,
    +        Ge
    +    }
     }
    diff --git a/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/constants/Bytecode.java b/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/constants/Bytecode.java
    index a7dc231e4fae..99b9964a7736 100644
    --- a/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/constants/Bytecode.java
    +++ b/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/constants/Bytecode.java
    @@ -444,12 +444,30 @@ public class Bytecode {
         public static final int ATOMIC_WAIT64 = 0x42;
     
         // Vector opcodes
    +    public static final int VECTOR_V128_LOAD = 0x00;
         public static final int VECTOR_V128_CONST = 0x0C;
    +
    +    public static final int VECTOR_F64X2_EQ = 0x47;
    +    public static final int VECTOR_F64X2_NE = 0x48;
    +    public static final int VECTOR_F64X2_LT = 0x49;
    +    public static final int VECTOR_F64X2_GT = 0x4A;
    +    public static final int VECTOR_F64X2_LE = 0x4B;
    +    public static final int VECTOR_F64X2_GE = 0x4C;
    +
         public static final int VECTOR_V128_ANY_TRUE = 0x53;
    +
         public static final int VECTOR_I32X4_ALL_TRUE = 0xA3;
         public static final int VECTOR_I32X4_ADD = 0xAE;
         public static final int VECTOR_I32X4_SUB = 0xB1;
         public static final int VECTOR_I32X4_MUL = 0xB5;
    +
    +    public static final int VECTOR_F64X2_CEIL = 0x74;
    +    public static final int VECTOR_F64X2_FLOOR = 0x75;
    +    public static final int VECTOR_F64X2_TRUNC = 0x7A;
    +    public static final int VECTOR_F64X2_NEAREST = 0x94;
    +    public static final int VECTOR_F64X2_ABS = 0xEC;
    +    public static final int VECTOR_F64X2_NEG = 0xED;
    +    public static final int VECTOR_F64X2_SQRT = 0xEF;
         public static final int VECTOR_F64X2_ADD = 0xF0;
         public static final int VECTOR_F64X2_SUB = 0xF1;
         public static final int VECTOR_F64X2_MUL = 0xF2;
    diff --git a/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/constants/Instructions.java b/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/constants/Instructions.java
    index 28a70b2c7028..19a03c1682bd 100644
    --- a/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/constants/Instructions.java
    +++ b/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/constants/Instructions.java
    @@ -347,12 +347,30 @@ public final class Instructions {
     
         public static final int VECTOR = 0xFD;
     
    +    public static final int VECTOR_V128_LOAD = 0x00;
         public static final int VECTOR_V128_CONST = 0x0C;
    +
    +    public static final int VECTOR_F64X2_EQ = 0x47;
    +    public static final int VECTOR_F64X2_NE = 0x48;
    +    public static final int VECTOR_F64X2_LT = 0x49;
    +    public static final int VECTOR_F64X2_GT = 0x4A;
    +    public static final int VECTOR_F64X2_LE = 0x4B;
    +    public static final int VECTOR_F64X2_GE = 0x4C;
    +
         public static final int VECTOR_V128_ANY_TRUE = 0x53;
    +
         public static final int VECTOR_I32X4_ALL_TRUE = 0xA3;
         public static final int VECTOR_I32X4_ADD = 0xAE;
         public static final int VECTOR_I32X4_SUB = 0xB1;
         public static final int VECTOR_I32X4_MUL = 0xB5;
    +
    +    public static final int VECTOR_F64X2_CEIL = 0x74;
    +    public static final int VECTOR_F64X2_FLOOR = 0x75;
    +    public static final int VECTOR_F64X2_TRUNC = 0x7A;
    +    public static final int VECTOR_F64X2_NEAREST = 0x94;
    +    public static final int VECTOR_F64X2_ABS = 0xEC;
    +    public static final int VECTOR_F64X2_NEG = 0xED;
    +    public static final int VECTOR_F64X2_SQRT = 0xEF;
         public static final int VECTOR_F64X2_ADD = 0xF0;
         public static final int VECTOR_F64X2_SUB = 0xF1;
         public static final int VECTOR_F64X2_MUL = 0xF2;
    diff --git a/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/memory/ByteArrayWasmMemory.java b/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/memory/ByteArrayWasmMemory.java
    index b8636a852cde..5d7423e0b247 100644
    --- a/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/memory/ByteArrayWasmMemory.java
    +++ b/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/memory/ByteArrayWasmMemory.java
    @@ -52,6 +52,7 @@
     import java.util.Arrays;
     
     import com.oracle.truffle.api.CompilerDirectives;
    +import org.graalvm.wasm.api.Vector128;
     import org.graalvm.wasm.exception.Failure;
     import org.graalvm.wasm.exception.WasmException;
     
    @@ -235,6 +236,15 @@ public long load_i64_32u(Node node, long address) {
             }
         }
     
    +    @Override
    +    public Vector128 load_i128(Node node, long address) {
    +        try {
    +            return Vector128.ofBytes(Arrays.copyOfRange(byteArrayBuffer.buffer(), (int) address, (int) address + 16));
    +        } catch (final IndexOutOfBoundsException e) {
    +            throw trapOutOfBounds(node, address, 16);
    +        }
    +    }
    +
         @Override
         public void store_i32(Node node, long address, int value) {
             try {
    diff --git a/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/memory/NativeWasmMemory.java b/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/memory/NativeWasmMemory.java
    index 24a3345c296b..0e9848f72cf3 100644
    --- a/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/memory/NativeWasmMemory.java
    +++ b/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/memory/NativeWasmMemory.java
    @@ -48,6 +48,7 @@
     import java.lang.reflect.Field;
     import java.nio.ByteBuffer;
     
    +import org.graalvm.wasm.api.Vector128;
     import org.graalvm.wasm.exception.Failure;
     import org.graalvm.wasm.exception.WasmException;
     
    @@ -241,6 +242,14 @@ public long load_i64_32u(Node node, long address) {
             return 0x0000_0000_ffff_ffffL & unsafe.getInt(startAddress + address);
         }
     
    +    @Override
    +    public Vector128 load_i128(Node node, long address) {
    +        validateAddress(node, address, 16);
    +        byte[] bytes = new byte[16];
    +        unsafe.copyMemory(null, startAddress + address, bytes, 0, 16);
    +        return Vector128.ofBytes(bytes);
    +    }
    +
         @Override
         public void store_i32(Node node, long address, int value) {
             validateAddress(node, address, 4);
    diff --git a/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/memory/UnsafeWasmMemory.java b/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/memory/UnsafeWasmMemory.java
    index 04fd36e01151..7e68401f2c15 100644
    --- a/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/memory/UnsafeWasmMemory.java
    +++ b/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/memory/UnsafeWasmMemory.java
    @@ -52,6 +52,7 @@
     import java.nio.Buffer;
     import java.nio.ByteBuffer;
     
    +import org.graalvm.wasm.api.Vector128;
     import org.graalvm.wasm.exception.Failure;
     import org.graalvm.wasm.exception.WasmException;
     
    @@ -241,6 +242,14 @@ public long load_i64_32u(Node node, long address) {
             return 0x0000_0000_ffff_ffffL & unsafe.getInt(startAddress + address);
         }
     
    +    @Override
    +    public Vector128 load_i128(Node node, long address) {
    +        validateAddress(node, address, 16);
    +        byte[] bytes = new byte[16];
    +        unsafe.copyMemory(null, startAddress + address, bytes, 0, 16);
    +        return Vector128.ofBytes(bytes);
    +    }
    +
         @Override
         public void store_i32(Node node, long address, int value) {
             validateAddress(node, address, 4);
    diff --git a/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/memory/WasmMemory.java b/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/memory/WasmMemory.java
    index e5201e623c17..2e494506e561 100644
    --- a/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/memory/WasmMemory.java
    +++ b/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/memory/WasmMemory.java
    @@ -54,6 +54,7 @@
     import java.nio.charset.StandardCharsets;
     
     import org.graalvm.wasm.EmbedderDataHolder;
    +import org.graalvm.wasm.api.Vector128;
     import org.graalvm.wasm.api.WebAssembly;
     import org.graalvm.wasm.collection.ByteArrayList;
     import org.graalvm.wasm.constants.Sizes;
    @@ -253,6 +254,8 @@ public final boolean isShared() {
     
         public abstract long load_i64_32u(Node node, long address);
     
    +    public abstract Vector128 load_i128(Node node, long address);
    +
         public abstract void store_i32(Node node, long address, int value);
     
         public abstract void store_i64(Node node, long address, long value);
    diff --git a/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/nodes/WasmFunctionNode.java b/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/nodes/WasmFunctionNode.java
    index 2ef063dde309..43ac7931649f 100644
    --- a/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/nodes/WasmFunctionNode.java
    +++ b/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/nodes/WasmFunctionNode.java
    @@ -1725,6 +1725,32 @@ public Object executeBodyFromOffset(WasmContext context, WasmInstance instance,
                         offset++;
                         CompilerAsserts.partialEvaluationConstant(vectorOpcode);
                         switch (vectorOpcode) {
    +                        case Bytecode.VECTOR_V128_LOAD: {
    +                            final int encoding = rawPeekU8(bytecode, offset);
    +                            offset++;
    +                            final int indexType64 = encoding & BytecodeBitEncoding.MEMORY_64_FLAG;
    +                            final int memoryIndex = rawPeekI32(bytecode, offset);
    +                            offset += 4;
    +                            final long memOffset;
    +                            if (indexType64 == 0) {
    +                                memOffset = rawPeekU32(bytecode, offset);
    +                                offset += 4;
    +                            } else {
    +                                memOffset = rawPeekI64(bytecode, offset);
    +                                offset += 8;
    +                            }
    +                            final long baseAddress;
    +                            if (indexType64 == 0) {
    +                                baseAddress = Integer.toUnsignedLong(popInt(frame, stackPointer - 1));
    +                            } else {
    +                                baseAddress = popLong(frame, stackPointer - 1);
    +                            }
    +                            final long address = effectiveMemoryAddress64(memOffset, baseAddress);
    +                            final WasmMemory memory = memory(instance, memoryIndex);
    +                            final Vector128 value = memory.load_i128(this, address);
    +                            pushVector128(frame, stackPointer - 1, value);
    +                            break;
    +                        }
                             case Bytecode.VECTOR_V128_CONST:
                                 final Vector128 value = rawPeekI128(bytecode, offset);
                                 offset += 16;
    @@ -1732,6 +1758,30 @@ public Object executeBodyFromOffset(WasmContext context, WasmInstance instance,
                                 pushVector128(frame, stackPointer, value);
                                 stackPointer++;
                                 break;
    +                        case Bytecode.VECTOR_F64X2_EQ:
    +                            f64x2_frelop(frame, stackPointer, VectorOperators.FRelOp.Eq);
    +                            stackPointer--;
    +                            break;
    +                        case Bytecode.VECTOR_F64X2_NE:
    +                            f64x2_frelop(frame, stackPointer, VectorOperators.FRelOp.Ne);
    +                            stackPointer--;
    +                            break;
    +                        case Bytecode.VECTOR_F64X2_LT:
    +                            f64x2_frelop(frame, stackPointer, VectorOperators.FRelOp.Lt);
    +                            stackPointer--;
    +                            break;
    +                        case Bytecode.VECTOR_F64X2_GT:
    +                            f64x2_frelop(frame, stackPointer, VectorOperators.FRelOp.Gt);
    +                            stackPointer--;
    +                            break;
    +                        case Bytecode.VECTOR_F64X2_LE:
    +                            f64x2_frelop(frame, stackPointer, VectorOperators.FRelOp.Le);
    +                            stackPointer--;
    +                            break;
    +                        case Bytecode.VECTOR_F64X2_GE:
    +                            f64x2_frelop(frame, stackPointer, VectorOperators.FRelOp.Ge);
    +                            stackPointer--;
    +                            break;
                             case Bytecode.VECTOR_V128_ANY_TRUE:
                                 v128_any_true(frame, stackPointer);
                                 break;
    @@ -1739,47 +1789,68 @@ public Object executeBodyFromOffset(WasmContext context, WasmInstance instance,
                                 i32x4_all_true(frame, stackPointer);
                                 break;
                             case Bytecode.VECTOR_I32X4_ADD:
    -                            i32x4_vibinop(frame, stackPointer, VectorOperators.VIBinOp.Add);
    +                            i32x4_ibinop(frame, stackPointer, VectorOperators.IBinOp.Add);
                                 stackPointer--;
                                 break;
                             case Bytecode.VECTOR_I32X4_SUB:
    -                            i32x4_vibinop(frame, stackPointer, VectorOperators.VIBinOp.Sub);
    +                            i32x4_ibinop(frame, stackPointer, VectorOperators.IBinOp.Sub);
                                 stackPointer--;
                                 break;
                             case Bytecode.VECTOR_I32X4_MUL:
                                 i32x4_mul(frame, stackPointer);
                                 stackPointer--;
                                 break;
    +                        case Bytecode.VECTOR_F64X2_CEIL:
    +                            f64x2_funop(frame, stackPointer, VectorOperators.FUnOp.Ceil);
    +                            break;
    +                        case Bytecode.VECTOR_F64X2_FLOOR:
    +                            f64x2_funop(frame, stackPointer, VectorOperators.FUnOp.Floor);
    +                            break;
    +                        case Bytecode.VECTOR_F64X2_TRUNC:
    +                            f64x2_funop(frame, stackPointer, VectorOperators.FUnOp.Trunc);
    +                            break;
    +                        case Bytecode.VECTOR_F64X2_NEAREST:
    +                            f64x2_funop(frame, stackPointer, VectorOperators.FUnOp.Nearest);
    +                            break;
    +                        case Bytecode.VECTOR_F64X2_ABS:
    +                            f64x2_funop(frame, stackPointer, VectorOperators.FUnOp.Abs);
    +                            break;
    +                        case Bytecode.VECTOR_F64X2_NEG:
    +                            f64x2_funop(frame, stackPointer, VectorOperators.FUnOp.Neg);
    +                            break;
    +                        case Bytecode.VECTOR_F64X2_SQRT:
    +                            f64x2_funop(frame, stackPointer, VectorOperators.FUnOp.Sqrt);
    +                            break;
                             case Bytecode.VECTOR_F64X2_ADD:
    -                            f64x2_vfbinop(frame, stackPointer, VectorOperators.VFBinOp.Add);
    +                            f64x2_fbinop(frame, stackPointer, VectorOperators.FBinOp.Add);
                                 stackPointer--;
                                 break;
                             case Bytecode.VECTOR_F64X2_SUB:
    -                            f64x2_vfbinop(frame, stackPointer, VectorOperators.VFBinOp.Sub);
    +                            f64x2_fbinop(frame, stackPointer, VectorOperators.FBinOp.Sub);
                                 stackPointer--;
                                 break;
                             case Bytecode.VECTOR_F64X2_MUL:
    -                            f64x2_vfbinop(frame, stackPointer, VectorOperators.VFBinOp.Mul);
    +                            f64x2_fbinop(frame, stackPointer, VectorOperators.FBinOp.Mul);
                                 stackPointer--;
                                 break;
                             case Bytecode.VECTOR_F64X2_DIV:
    -                            f64x2_vfbinop(frame, stackPointer, VectorOperators.VFBinOp.Div);
    +                            f64x2_fbinop(frame, stackPointer, VectorOperators.FBinOp.Div);
                                 stackPointer--;
                                 break;
                             case Bytecode.VECTOR_F64X2_MIN:
    -                            f64x2_vfbinop(frame, stackPointer, VectorOperators.VFBinOp.Min);
    +                            f64x2_fbinop(frame, stackPointer, VectorOperators.FBinOp.Min);
                                 stackPointer--;
                                 break;
                             case Bytecode.VECTOR_F64X2_MAX:
    -                            f64x2_vfbinop(frame, stackPointer, VectorOperators.VFBinOp.Max);
    +                            f64x2_fbinop(frame, stackPointer, VectorOperators.FBinOp.Max);
                                 stackPointer--;
                                 break;
                             case Bytecode.VECTOR_F64X2_PMIN:
    -                            f64x2_vfbinop(frame, stackPointer, VectorOperators.VFBinOp.Pmin);
    +                            f64x2_fbinop(frame, stackPointer, VectorOperators.FBinOp.Pmin);
                                 stackPointer--;
                                 break;
                             case Bytecode.VECTOR_F64X2_PMAX:
    -                            f64x2_vfbinop(frame, stackPointer, VectorOperators.VFBinOp.Pmax);
    +                            f64x2_fbinop(frame, stackPointer, VectorOperators.FBinOp.Pmax);
                                 stackPointer--;
                                 break;
                             default:
    @@ -3913,7 +3984,7 @@ private static void i32x4_all_true(VirtualFrame frame, int stackPointer) {
         }
     
         @ExplodeLoop
    -    private static void i32x4_vibinop(VirtualFrame frame, int stackPointer, VectorOperators.VIBinOp operator) {
    +    private static void i32x4_ibinop(VirtualFrame frame, int stackPointer, VectorOperators.IBinOp operator) {
             int[] x = popVector128(frame, stackPointer - 1).asInts();
             int[] y = popVector128(frame, stackPointer - 2).asInts();
             int[] result = new int[4];
    @@ -3944,7 +4015,48 @@ private static void i32x4_mul(VirtualFrame frame, int stackPointer) {
         }
     
         @ExplodeLoop
    -    private static void f64x2_vfbinop(VirtualFrame frame, int stackPointer, VectorOperators.VFBinOp operator) {
    +    private static void f64x2_frelop(VirtualFrame frame, int stackPointer, VectorOperators.FRelOp operator) {
    +        double[] x = popVector128(frame, stackPointer - 1).asDoubles();
    +        double[] y = popVector128(frame, stackPointer - 2).asDoubles();
    +        double[] result = new double[2];
    +        CompilerDirectives.ensureVirtualized(x);
    +        CompilerDirectives.ensureVirtualized(y);
    +        CompilerDirectives.ensureVirtualized(result);
    +        for (int i = 0; i < 2; i++) {
    +            result[i] = switch (operator) {
    +                case Eq -> y[i] == x[i];
    +                case Ne -> y[i] != x[i];
    +                case Lt -> y[i] < x[i];
    +                case Gt -> y[i] > x[i];
    +                case Le -> y[i] <= x[i];
    +                case Ge -> y[i] >= x[i];
    +            } ? Double.longBitsToDouble(0xffff_ffff_ffff_ffffL) : Double.longBitsToDouble(0x0000_0000_0000_0000L);
    +        }
    +        pushVector128(frame, stackPointer - 2, Vector128.ofDoubles(result));
    +    }
    +
    +    @ExplodeLoop
    +    private static void f64x2_funop(VirtualFrame frame, int stackPointer, VectorOperators.FUnOp operator) {
    +        double[] x = popVector128(frame, stackPointer - 1).asDoubles();
    +        double[] result = new double[2];
    +        CompilerDirectives.ensureVirtualized(x);
    +        CompilerDirectives.ensureVirtualized(result);
    +        for (int i = 0; i < 2; i++) {
    +            result[i] = switch (operator) {
    +                case Abs -> Math.abs(x[i]);
    +                case Neg -> -x[i];
    +                case Sqrt -> Math.sqrt(x[i]);
    +                case Ceil -> Math.ceil(x[i]);
    +                case Floor -> Math.floor(x[i]);
    +                case Trunc -> ExactMath.truncate(x[i]);
    +                case Nearest -> Math.rint(x[i]);
    +            };
    +        }
    +        pushVector128(frame, stackPointer - 1, Vector128.ofDoubles(result));
    +    }
    +
    +    @ExplodeLoop
    +    private static void f64x2_fbinop(VirtualFrame frame, int stackPointer, VectorOperators.FBinOp operator) {
             double[] x = popVector128(frame, stackPointer - 1).asDoubles();
             double[] y = popVector128(frame, stackPointer - 2).asDoubles();
             double[] result = new double[2];
    diff --git a/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/parser/bytecode/BytecodeParser.java b/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/parser/bytecode/BytecodeParser.java
    index 40db11845af4..d76a80d1d1b3 100644
    --- a/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/parser/bytecode/BytecodeParser.java
    +++ b/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/parser/bytecode/BytecodeParser.java
    @@ -892,11 +892,47 @@ private static List readCallNodes(byte[] bytecode, int startOffset, in
                         final int vectorOpcode = rawPeekU8(bytecode, offset);
                         offset++;
                         switch (vectorOpcode) {
    +                        case Bytecode.VECTOR_V128_LOAD: {
    +                            final int encoding = rawPeekU8(bytecode, offset);
    +                            offset++;
    +                            final int indexType64 = encoding & BytecodeBitEncoding.MEMORY_64_FLAG;
    +                            offset += 4;
    +                            if (indexType64 == 0) {
    +                                offset += 4;
    +                            } else {
    +                                offset += 8;
    +                            }
    +                            break;
    +                        }
                             case Bytecode.VECTOR_V128_CONST:
                                 offset += 16;
                                 break;
    +                        case Bytecode.VECTOR_F64X2_EQ:
    +                        case Bytecode.VECTOR_F64X2_NE:
    +                        case Bytecode.VECTOR_F64X2_LT:
    +                        case Bytecode.VECTOR_F64X2_GT:
    +                        case Bytecode.VECTOR_F64X2_LE:
    +                        case Bytecode.VECTOR_F64X2_GE:
    +                        case Bytecode.VECTOR_V128_ANY_TRUE:
                             case Bytecode.VECTOR_I32X4_ALL_TRUE:
                             case Bytecode.VECTOR_I32X4_ADD:
    +                        case Bytecode.VECTOR_I32X4_SUB:
    +                        case Bytecode.VECTOR_I32X4_MUL:
    +                        case Bytecode.VECTOR_F64X2_CEIL:
    +                        case Bytecode.VECTOR_F64X2_FLOOR:
    +                        case Bytecode.VECTOR_F64X2_TRUNC:
    +                        case Bytecode.VECTOR_F64X2_NEAREST:
    +                        case Bytecode.VECTOR_F64X2_ABS:
    +                        case Bytecode.VECTOR_F64X2_NEG:
    +                        case Bytecode.VECTOR_F64X2_SQRT:
    +                        case Bytecode.VECTOR_F64X2_ADD:
    +                        case Bytecode.VECTOR_F64X2_SUB:
    +                        case Bytecode.VECTOR_F64X2_MUL:
    +                        case Bytecode.VECTOR_F64X2_DIV:
    +                        case Bytecode.VECTOR_F64X2_MIN:
    +                        case Bytecode.VECTOR_F64X2_MAX:
    +                        case Bytecode.VECTOR_F64X2_PMIN:
    +                        case Bytecode.VECTOR_F64X2_PMAX:
                                 break;
                             default:
                                 throw CompilerDirectives.shouldNotReachHere();
    diff --git a/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/parser/bytecode/RuntimeBytecodeGen.java b/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/parser/bytecode/RuntimeBytecodeGen.java
    index 5e72caae59ce..b53c2dac4781 100644
    --- a/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/parser/bytecode/RuntimeBytecodeGen.java
    +++ b/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/parser/bytecode/RuntimeBytecodeGen.java
    @@ -267,13 +267,13 @@ public void addMemoryInstruction(int opcode, int opcodeU8, int opcodeI32, int me
         }
     
         /**
    -     * Adds an atomic memory access instruction to the bytecode.
    +     * Adds an extended (atomic or vector) memory access instruction to the bytecode.
          *
    -     * @param opcode The atomic memory opcode
    +     * @param opcode The extended memory opcode
          * @param offset The offset value
          * @param indexType64 If the accessed memory has index type 64.
          */
    -    public void addAtomicMemoryInstruction(int opcode, int memoryIndex, long offset, boolean indexType64) {
    +    public void addExtendedMemoryInstruction(int opcode, int memoryIndex, long offset, boolean indexType64) {
             assert fitsIntoUnsignedByte(opcode) : "opcode does not fit into byte";
             if (!indexType64) {
                 assert fitsIntoUnsignedInt(offset) : "offset does not fit into int";
    diff --git a/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/parser/validation/ParserState.java b/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/parser/validation/ParserState.java
    index 858659c1df9c..0f82a4bb496f 100644
    --- a/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/parser/validation/ParserState.java
    +++ b/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/parser/validation/ParserState.java
    @@ -513,15 +513,16 @@ public void addMemoryInstruction(int baseInstruction, int memoryIndex, long valu
         }
     
         /**
    -     * Adds an atomic memory instruction based on the given values and index type.
    +     * Adds an extended (atomic or vector) memory instruction based on the given values and index
    +     * type.
          *
    -     * @param instruction The atomic memory instruction
    +     * @param instruction The extended memory instruction
          * @param memoryIndex The index of the memory being accessed
          * @param value The immediate value
          * @param indexType64 If the index type is 64 bit.
          */
    -    public void addAtomicMemoryInstruction(int instruction, int memoryIndex, long value, boolean indexType64) {
    -        bytecode.addAtomicMemoryInstruction(instruction, memoryIndex, value, indexType64);
    +    public void addExtendedMemoryInstruction(int instruction, int memoryIndex, long value, boolean indexType64) {
    +        bytecode.addExtendedMemoryInstruction(instruction, memoryIndex, value, indexType64);
         }
     
         /**
    
    From 4ec673a4617d7a0d35ec019ad1defbdd3cc1d3f3 Mon Sep 17 00:00:00 2001
    From: Jirka Marsik 
    Date: Tue, 19 Dec 2023 11:04:28 +0100
    Subject: [PATCH 289/593] Fix storing of boolean values in vectors
    
    ---
     .../src/org/graalvm/wasm/nodes/WasmFunctionNode.java        | 6 +++---
     1 file changed, 3 insertions(+), 3 deletions(-)
    
    diff --git a/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/nodes/WasmFunctionNode.java b/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/nodes/WasmFunctionNode.java
    index 43ac7931649f..37f37e0c98b9 100644
    --- a/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/nodes/WasmFunctionNode.java
    +++ b/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/nodes/WasmFunctionNode.java
    @@ -4018,7 +4018,7 @@ private static void i32x4_mul(VirtualFrame frame, int stackPointer) {
         private static void f64x2_frelop(VirtualFrame frame, int stackPointer, VectorOperators.FRelOp operator) {
             double[] x = popVector128(frame, stackPointer - 1).asDoubles();
             double[] y = popVector128(frame, stackPointer - 2).asDoubles();
    -        double[] result = new double[2];
    +        long[] result = new long[2];
             CompilerDirectives.ensureVirtualized(x);
             CompilerDirectives.ensureVirtualized(y);
             CompilerDirectives.ensureVirtualized(result);
    @@ -4030,9 +4030,9 @@ private static void f64x2_frelop(VirtualFrame frame, int stackPointer, VectorOpe
                     case Gt -> y[i] > x[i];
                     case Le -> y[i] <= x[i];
                     case Ge -> y[i] >= x[i];
    -            } ? Double.longBitsToDouble(0xffff_ffff_ffff_ffffL) : Double.longBitsToDouble(0x0000_0000_0000_0000L);
    +            } ? 0xffff_ffff_ffff_ffffL : 0x0000_0000_0000_0000L;
             }
    -        pushVector128(frame, stackPointer - 2, Vector128.ofDoubles(result));
    +        pushVector128(frame, stackPointer - 2, Vector128.ofLongs(result));
         }
     
         @ExplodeLoop
    
    From 125f8754eb5c1a90f7af9432dfdefb16532c3219 Mon Sep 17 00:00:00 2001
    From: Jirka Marsik 
    Date: Tue, 19 Dec 2023 12:11:13 +0100
    Subject: [PATCH 290/593] Drop custom enums in VectorOperators in favor of
     bytecodes
    
    ---
     .../org/graalvm/wasm/api/VectorOperators.java |  95 ------------
     .../graalvm/wasm/nodes/WasmFunctionNode.java  | 144 +++++-------------
     2 files changed, 40 insertions(+), 199 deletions(-)
     delete mode 100644 wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/api/VectorOperators.java
    
    diff --git a/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/api/VectorOperators.java b/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/api/VectorOperators.java
    deleted file mode 100644
    index 6424186712a5..000000000000
    --- a/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/api/VectorOperators.java
    +++ /dev/null
    @@ -1,95 +0,0 @@
    -/*
    - * Copyright (c) 2023, 2023, Oracle and/or its affiliates. All rights reserved.
    - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
    - *
    - * The Universal Permissive License (UPL), Version 1.0
    - *
    - * Subject to the condition set forth below, permission is hereby granted to any
    - * person obtaining a copy of this software, associated documentation and/or
    - * data (collectively the "Software"), free of charge and under any and all
    - * copyright rights in the Software, and any and all patent rights owned or
    - * freely licensable by each licensor hereunder covering either (i) the
    - * unmodified Software as contributed to or provided by such licensor, or (ii)
    - * the Larger Works (as defined below), to deal in both
    - *
    - * (a) the Software, and
    - *
    - * (b) any piece of software and/or hardware listed in the lrgrwrks.txt file if
    - * one is included with the Software each a "Larger Work" to which the Software
    - * is contributed by such licensors),
    - *
    - * without restriction, including without limitation the rights to copy, create
    - * derivative works of, display, perform, and distribute the Software and make,
    - * use, sell, offer for sale, import, export, have made, and have sold the
    - * Software and the Larger Work(s), and to sublicense the foregoing rights on
    - * either these or other terms.
    - *
    - * This license is subject to the following condition:
    - *
    - * The above copyright notice and either this complete permission notice or at a
    - * minimum a reference to the UPL must be included in all copies or substantial
    - * portions of the Software.
    - *
    - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
    - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
    - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
    - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
    - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
    - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
    - * SOFTWARE.
    - */
    -package org.graalvm.wasm.api;
    -
    -public class VectorOperators {
    -
    -    /**
    -     * Vectorized integer binary operators. Corresponds to the {@code vibinop} production in the
    -     * WebAssembly spec.
    -     */
    -    public enum IBinOp {
    -        Add,
    -        Sub
    -    }
    -
    -    /**
    -     * Vectorized floating-point unary operators. Corresponds to the {@code vfunop} production in
    -     * the WebAssembly spec.
    -     */
    -    public enum FUnOp {
    -        Abs,
    -        Neg,
    -        Sqrt,
    -        Ceil,
    -        Floor,
    -        Trunc,
    -        Nearest
    -    }
    -
    -    /**
    -     * Vectorized floating-point binary operators. Corresponds to the {@code vfbinop} production in
    -     * the WebAssembly spec.
    -     */
    -    public enum FBinOp {
    -        Add,
    -        Sub,
    -        Mul,
    -        Div,
    -        Min,
    -        Max,
    -        Pmin,
    -        Pmax
    -    }
    -
    -    /**
    -     * Vectorized floating-point relational operators. Corresponds to the {@code vfrelop} production
    -     * in the WebAssembly spec.
    -     */
    -    public enum FRelOp {
    -        Eq,
    -        Ne,
    -        Lt,
    -        Gt,
    -        Le,
    -        Ge
    -    }
    -}
    diff --git a/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/nodes/WasmFunctionNode.java b/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/nodes/WasmFunctionNode.java
    index 37f37e0c98b9..7b18a1eda1db 100644
    --- a/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/nodes/WasmFunctionNode.java
    +++ b/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/nodes/WasmFunctionNode.java
    @@ -79,7 +79,6 @@
     import org.graalvm.wasm.WasmTable;
     import org.graalvm.wasm.WasmType;
     import org.graalvm.wasm.api.Vector128;
    -import org.graalvm.wasm.api.VectorOperators;
     import org.graalvm.wasm.constants.Bytecode;
     import org.graalvm.wasm.constants.BytecodeBitEncoding;
     import org.graalvm.wasm.exception.Failure;
    @@ -1759,27 +1758,12 @@ public Object executeBodyFromOffset(WasmContext context, WasmInstance instance,
                                 stackPointer++;
                                 break;
                             case Bytecode.VECTOR_F64X2_EQ:
    -                            f64x2_frelop(frame, stackPointer, VectorOperators.FRelOp.Eq);
    -                            stackPointer--;
    -                            break;
                             case Bytecode.VECTOR_F64X2_NE:
    -                            f64x2_frelop(frame, stackPointer, VectorOperators.FRelOp.Ne);
    -                            stackPointer--;
    -                            break;
                             case Bytecode.VECTOR_F64X2_LT:
    -                            f64x2_frelop(frame, stackPointer, VectorOperators.FRelOp.Lt);
    -                            stackPointer--;
    -                            break;
                             case Bytecode.VECTOR_F64X2_GT:
    -                            f64x2_frelop(frame, stackPointer, VectorOperators.FRelOp.Gt);
    -                            stackPointer--;
    -                            break;
                             case Bytecode.VECTOR_F64X2_LE:
    -                            f64x2_frelop(frame, stackPointer, VectorOperators.FRelOp.Le);
    -                            stackPointer--;
    -                            break;
                             case Bytecode.VECTOR_F64X2_GE:
    -                            f64x2_frelop(frame, stackPointer, VectorOperators.FRelOp.Ge);
    +                            f64x2_relop(frame, stackPointer, vectorOpcode);
                                 stackPointer--;
                                 break;
                             case Bytecode.VECTOR_V128_ANY_TRUE:
    @@ -1789,68 +1773,29 @@ public Object executeBodyFromOffset(WasmContext context, WasmInstance instance,
                                 i32x4_all_true(frame, stackPointer);
                                 break;
                             case Bytecode.VECTOR_I32X4_ADD:
    -                            i32x4_ibinop(frame, stackPointer, VectorOperators.IBinOp.Add);
    -                            stackPointer--;
    -                            break;
                             case Bytecode.VECTOR_I32X4_SUB:
    -                            i32x4_ibinop(frame, stackPointer, VectorOperators.IBinOp.Sub);
    -                            stackPointer--;
    -                            break;
                             case Bytecode.VECTOR_I32X4_MUL:
    -                            i32x4_mul(frame, stackPointer);
    +                            i32x4_binop(frame, stackPointer, vectorOpcode);
                                 stackPointer--;
                                 break;
                             case Bytecode.VECTOR_F64X2_CEIL:
    -                            f64x2_funop(frame, stackPointer, VectorOperators.FUnOp.Ceil);
    -                            break;
                             case Bytecode.VECTOR_F64X2_FLOOR:
    -                            f64x2_funop(frame, stackPointer, VectorOperators.FUnOp.Floor);
    -                            break;
                             case Bytecode.VECTOR_F64X2_TRUNC:
    -                            f64x2_funop(frame, stackPointer, VectorOperators.FUnOp.Trunc);
    -                            break;
                             case Bytecode.VECTOR_F64X2_NEAREST:
    -                            f64x2_funop(frame, stackPointer, VectorOperators.FUnOp.Nearest);
    -                            break;
                             case Bytecode.VECTOR_F64X2_ABS:
    -                            f64x2_funop(frame, stackPointer, VectorOperators.FUnOp.Abs);
    -                            break;
                             case Bytecode.VECTOR_F64X2_NEG:
    -                            f64x2_funop(frame, stackPointer, VectorOperators.FUnOp.Neg);
    -                            break;
                             case Bytecode.VECTOR_F64X2_SQRT:
    -                            f64x2_funop(frame, stackPointer, VectorOperators.FUnOp.Sqrt);
    +                            f64x2_unop(frame, stackPointer, vectorOpcode);
                                 break;
                             case Bytecode.VECTOR_F64X2_ADD:
    -                            f64x2_fbinop(frame, stackPointer, VectorOperators.FBinOp.Add);
    -                            stackPointer--;
    -                            break;
                             case Bytecode.VECTOR_F64X2_SUB:
    -                            f64x2_fbinop(frame, stackPointer, VectorOperators.FBinOp.Sub);
    -                            stackPointer--;
    -                            break;
                             case Bytecode.VECTOR_F64X2_MUL:
    -                            f64x2_fbinop(frame, stackPointer, VectorOperators.FBinOp.Mul);
    -                            stackPointer--;
    -                            break;
                             case Bytecode.VECTOR_F64X2_DIV:
    -                            f64x2_fbinop(frame, stackPointer, VectorOperators.FBinOp.Div);
    -                            stackPointer--;
    -                            break;
                             case Bytecode.VECTOR_F64X2_MIN:
    -                            f64x2_fbinop(frame, stackPointer, VectorOperators.FBinOp.Min);
    -                            stackPointer--;
    -                            break;
                             case Bytecode.VECTOR_F64X2_MAX:
    -                            f64x2_fbinop(frame, stackPointer, VectorOperators.FBinOp.Max);
    -                            stackPointer--;
    -                            break;
                             case Bytecode.VECTOR_F64X2_PMIN:
    -                            f64x2_fbinop(frame, stackPointer, VectorOperators.FBinOp.Pmin);
    -                            stackPointer--;
    -                            break;
                             case Bytecode.VECTOR_F64X2_PMAX:
    -                            f64x2_fbinop(frame, stackPointer, VectorOperators.FBinOp.Pmax);
    +                            f64x2_binop(frame, stackPointer, vectorOpcode);
                                 stackPointer--;
                                 break;
                             default:
    @@ -3984,7 +3929,7 @@ private static void i32x4_all_true(VirtualFrame frame, int stackPointer) {
         }
     
         @ExplodeLoop
    -    private static void i32x4_ibinop(VirtualFrame frame, int stackPointer, VectorOperators.IBinOp operator) {
    +    private static void i32x4_binop(VirtualFrame frame, int stackPointer, int vectorOpcode) {
             int[] x = popVector128(frame, stackPointer - 1).asInts();
             int[] y = popVector128(frame, stackPointer - 2).asInts();
             int[] result = new int[4];
    @@ -3992,30 +3937,18 @@ private static void i32x4_ibinop(VirtualFrame frame, int stackPointer, VectorOpe
             CompilerDirectives.ensureVirtualized(y);
             CompilerDirectives.ensureVirtualized(result);
             for (int i = 0; i < 4; i++) {
    -            result[i] = switch (operator) {
    -                case Add -> y[i] + x[i];
    -                case Sub -> y[i] - x[i];
    +            result[i] = switch (vectorOpcode) {
    +                case Bytecode.VECTOR_I32X4_ADD -> y[i] + x[i];
    +                case Bytecode.VECTOR_I32X4_SUB -> y[i] - x[i];
    +                case Bytecode.VECTOR_I32X4_MUL -> y[i] * x[i];
    +                default -> throw CompilerDirectives.shouldNotReachHere();
                 };
             }
             pushVector128(frame, stackPointer - 2, Vector128.ofInts(result));
         }
     
         @ExplodeLoop
    -    private static void i32x4_mul(VirtualFrame frame, int stackPointer) {
    -        int[] x = popVector128(frame, stackPointer - 1).asInts();
    -        int[] y = popVector128(frame, stackPointer - 2).asInts();
    -        int[] result = new int[4];
    -        CompilerDirectives.ensureVirtualized(x);
    -        CompilerDirectives.ensureVirtualized(y);
    -        CompilerDirectives.ensureVirtualized(result);
    -        for (int i = 0; i < 4; i++) {
    -            result[i] = y[i] * x[i];
    -        }
    -        pushVector128(frame, stackPointer - 2, Vector128.ofInts(result));
    -    }
    -
    -    @ExplodeLoop
    -    private static void f64x2_frelop(VirtualFrame frame, int stackPointer, VectorOperators.FRelOp operator) {
    +    private static void f64x2_relop(VirtualFrame frame, int stackPointer, int vectorOpcode) {
             double[] x = popVector128(frame, stackPointer - 1).asDoubles();
             double[] y = popVector128(frame, stackPointer - 2).asDoubles();
             long[] result = new long[2];
    @@ -4023,40 +3956,42 @@ private static void f64x2_frelop(VirtualFrame frame, int stackPointer, VectorOpe
             CompilerDirectives.ensureVirtualized(y);
             CompilerDirectives.ensureVirtualized(result);
             for (int i = 0; i < 2; i++) {
    -            result[i] = switch (operator) {
    -                case Eq -> y[i] == x[i];
    -                case Ne -> y[i] != x[i];
    -                case Lt -> y[i] < x[i];
    -                case Gt -> y[i] > x[i];
    -                case Le -> y[i] <= x[i];
    -                case Ge -> y[i] >= x[i];
    +            result[i] = switch (vectorOpcode) {
    +                case Bytecode.VECTOR_F64X2_EQ -> y[i] == x[i];
    +                case Bytecode.VECTOR_F64X2_NE -> y[i] != x[i];
    +                case Bytecode.VECTOR_F64X2_LT -> y[i] < x[i];
    +                case Bytecode.VECTOR_F64X2_GT -> y[i] > x[i];
    +                case Bytecode.VECTOR_F64X2_LE -> y[i] <= x[i];
    +                case Bytecode.VECTOR_F64X2_GE -> y[i] >= x[i];
    +                default -> throw CompilerDirectives.shouldNotReachHere();
                 } ? 0xffff_ffff_ffff_ffffL : 0x0000_0000_0000_0000L;
             }
             pushVector128(frame, stackPointer - 2, Vector128.ofLongs(result));
         }
     
         @ExplodeLoop
    -    private static void f64x2_funop(VirtualFrame frame, int stackPointer, VectorOperators.FUnOp operator) {
    +    private static void f64x2_unop(VirtualFrame frame, int stackPointer, int vectorOpcode) {
             double[] x = popVector128(frame, stackPointer - 1).asDoubles();
             double[] result = new double[2];
             CompilerDirectives.ensureVirtualized(x);
             CompilerDirectives.ensureVirtualized(result);
             for (int i = 0; i < 2; i++) {
    -            result[i] = switch (operator) {
    -                case Abs -> Math.abs(x[i]);
    -                case Neg -> -x[i];
    -                case Sqrt -> Math.sqrt(x[i]);
    -                case Ceil -> Math.ceil(x[i]);
    -                case Floor -> Math.floor(x[i]);
    -                case Trunc -> ExactMath.truncate(x[i]);
    -                case Nearest -> Math.rint(x[i]);
    +            result[i] = switch (vectorOpcode) {
    +                case Bytecode.VECTOR_F64X2_ABS -> Math.abs(x[i]);
    +                case Bytecode.VECTOR_F64X2_NEG -> -x[i];
    +                case Bytecode.VECTOR_F64X2_SQRT -> Math.sqrt(x[i]);
    +                case Bytecode.VECTOR_F64X2_CEIL -> Math.ceil(x[i]);
    +                case Bytecode.VECTOR_F64X2_FLOOR -> Math.floor(x[i]);
    +                case Bytecode.VECTOR_F64X2_TRUNC -> ExactMath.truncate(x[i]);
    +                case Bytecode.VECTOR_F64X2_NEAREST -> Math.rint(x[i]);
    +                default -> throw CompilerDirectives.shouldNotReachHere();
                 };
             }
             pushVector128(frame, stackPointer - 1, Vector128.ofDoubles(result));
         }
     
         @ExplodeLoop
    -    private static void f64x2_fbinop(VirtualFrame frame, int stackPointer, VectorOperators.FBinOp operator) {
    +    private static void f64x2_binop(VirtualFrame frame, int stackPointer, int vectorOpcode) {
             double[] x = popVector128(frame, stackPointer - 1).asDoubles();
             double[] y = popVector128(frame, stackPointer - 2).asDoubles();
             double[] result = new double[2];
    @@ -4064,15 +3999,16 @@ private static void f64x2_fbinop(VirtualFrame frame, int stackPointer, VectorOpe
             CompilerDirectives.ensureVirtualized(y);
             CompilerDirectives.ensureVirtualized(result);
             for (int i = 0; i < 2; i++) {
    -            result[i] = switch (operator) {
    -                case Add -> y[i] + x[i];
    -                case Sub -> y[i] - x[i];
    -                case Mul -> y[i] * x[i];
    -                case Div -> y[i] / x[i];
    -                case Min -> Math.min(y[i], x[i]);
    -                case Max -> Math.max(y[i], x[i]);
    -                case Pmin -> x[i] < y[i] ? x[i] : y[i];
    -                case Pmax -> y[i] < x[i] ? x[i] : y[i];
    +            result[i] = switch (vectorOpcode) {
    +                case Bytecode.VECTOR_F64X2_ADD -> y[i] + x[i];
    +                case Bytecode.VECTOR_F64X2_SUB -> y[i] - x[i];
    +                case Bytecode.VECTOR_F64X2_MUL -> y[i] * x[i];
    +                case Bytecode.VECTOR_F64X2_DIV -> y[i] / x[i];
    +                case Bytecode.VECTOR_F64X2_MIN -> Math.min(y[i], x[i]);
    +                case Bytecode.VECTOR_F64X2_MAX -> Math.max(y[i], x[i]);
    +                case Bytecode.VECTOR_F64X2_PMIN -> x[i] < y[i] ? x[i] : y[i];
    +                case Bytecode.VECTOR_F64X2_PMAX -> y[i] < x[i] ? x[i] : y[i];
    +                default -> throw CompilerDirectives.shouldNotReachHere();
                 };
             }
             pushVector128(frame, stackPointer - 2, Vector128.ofDoubles(result));
    
    From 711c04be16567e9f6ada661d76603e342b3b9673 Mon Sep 17 00:00:00 2001
    From: Jirka Marsik 
    Date: Tue, 19 Dec 2023 13:34:21 +0100
    Subject: [PATCH 291/593] Cleanup leftover benchmark files
    
    ---
     .../org.graalvm.wasm.benchcases/src/bench/wat/vector.opts    | 5 -----
     .../org.graalvm.wasm.benchcases/src/bench/wat/vector.result  | 1 -
     2 files changed, 6 deletions(-)
     delete mode 100644 wasm/src/org.graalvm.wasm.benchcases/src/bench/wat/vector.opts
     delete mode 100644 wasm/src/org.graalvm.wasm.benchcases/src/bench/wat/vector.result
    
    diff --git a/wasm/src/org.graalvm.wasm.benchcases/src/bench/wat/vector.opts b/wasm/src/org.graalvm.wasm.benchcases/src/bench/wat/vector.opts
    deleted file mode 100644
    index e73749053ddb..000000000000
    --- a/wasm/src/org.graalvm.wasm.benchcases/src/bench/wat/vector.opts
    +++ /dev/null
    @@ -1,5 +0,0 @@
    -zero-memory = true
    -interpreter-iterations = 1
    -sync-noinline-iterations = 1
    -sync-inline-iterations = 0
    -async-iterations = 1050
    \ No newline at end of file
    diff --git a/wasm/src/org.graalvm.wasm.benchcases/src/bench/wat/vector.result b/wasm/src/org.graalvm.wasm.benchcases/src/bench/wat/vector.result
    deleted file mode 100644
    index 4f92b536bf12..000000000000
    --- a/wasm/src/org.graalvm.wasm.benchcases/src/bench/wat/vector.result
    +++ /dev/null
    @@ -1 +0,0 @@
    -int 1
    \ No newline at end of file
    
    From 64b4ac8f84773b00c3b1c0f395e74fb6c6730b3d Mon Sep 17 00:00:00 2001
    From: Fabio Niephaus 
    Date: Tue, 19 Dec 2023 13:21:59 +0100
    Subject: [PATCH 292/593] Use `os.makedirs` instead of `mkpath`.
    
    `distutils` is removed from Python 3.12.
    ---
     substratevm/mx.substratevm/mx_substratevm.py | 7 +++----
     1 file changed, 3 insertions(+), 4 deletions(-)
    
    diff --git a/substratevm/mx.substratevm/mx_substratevm.py b/substratevm/mx.substratevm/mx_substratevm.py
    index 5f0929ff3c71..a7c74f48ea6d 100644
    --- a/substratevm/mx.substratevm/mx_substratevm.py
    +++ b/substratevm/mx.substratevm/mx_substratevm.py
    @@ -28,7 +28,6 @@
     import tempfile
     from glob import glob
     from contextlib import contextmanager
    -from distutils.dir_util import mkpath  # pylint: disable=no-name-in-module
     from os.path import join, exists, dirname
     import pipes
     from argparse import ArgumentParser
    @@ -494,9 +493,9 @@ def native_unittests_task(extra_build_args=None):
         resources_from_dir = join(cp_entry_name, 'resourcesFromDir')
         simple_dir = join(cp_entry_name, 'simpleDir')
     
    -    mkpath(cp_entry_name)
    -    mkpath(resources_from_dir)
    -    mkpath(simple_dir)
    +    os.makedirs(cp_entry_name)
    +    os.makedirs(resources_from_dir)
    +    os.makedirs(simple_dir)
     
         for i in range(4):
             with open(join(cp_entry_name, "resourcesFromDir", f'cond-resource{i}.txt'), 'w') as out:
    
    From 162d5c09216d12d53e37f4e92df0ba24445021a8 Mon Sep 17 00:00:00 2001
    From: Fabio Niephaus 
    Date: Mon, 18 Dec 2023 19:46:27 +0100
    Subject: [PATCH 293/593] Preprocess `_MSC_FULL_VER` to detect `cl.exe` version
     info.
    
    The previous approach relied on the version string of `cl.exe`, which is localized and thus not always correctly detected when the system language is not English.
    ---
     .../hosted/c/codegen/CCompilerInvoker.java    | 69 ++++++++++---------
     1 file changed, 37 insertions(+), 32 deletions(-)
    
    diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/c/codegen/CCompilerInvoker.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/c/codegen/CCompilerInvoker.java
    index 10deb97fc8c9..58f19553d3b8 100644
    --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/c/codegen/CCompilerInvoker.java
    +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/c/codegen/CCompilerInvoker.java
    @@ -32,7 +32,6 @@
     import java.nio.file.Paths;
     import java.util.ArrayList;
     import java.util.Arrays;
    -import java.util.Collections;
     import java.util.List;
     import java.util.NoSuchElementException;
     import java.util.Optional;
    @@ -50,6 +49,7 @@
     import com.oracle.svm.core.option.SubstrateOptionsParser;
     import com.oracle.svm.core.util.InterruptImageBuilding;
     import com.oracle.svm.core.util.UserError;
    +import com.oracle.svm.core.util.VMError;
     import com.oracle.svm.hosted.c.libc.HostedLibCBase;
     import com.oracle.svm.hosted.c.util.FileUtils;
     import com.oracle.svm.util.ClassUtil;
    @@ -139,47 +139,52 @@ protected InputStream getCompilerErrorStream(Process compilingProcess) {
     
             @Override
             protected List getVersionInfoOptions() {
    -            return Collections.emptyList();
    +            Path detectVersionInfoFile = tempDirectory.resolve("detect-cl-version-info.c").toAbsolutePath();
    +            try {
    +                Files.write(detectVersionInfoFile, List.of("M_X64=_M_X64", "M_ARM64EC=_M_ARM64EC", "MSC_FULL_VER=_MSC_FULL_VER"));
    +            } catch (IOException ioe) {
    +                throw VMError.shouldNotReachHere("Unable to create file to detect cl version info", ioe);
    +            }
    +            return List.of("/EP", detectVersionInfoFile.toString());
             }
     
             @Override
    -        protected CompilerInfo createCompilerInfo(Path compilerPath, Scanner outerScanner) {
    -            try (Scanner scanner = new Scanner(outerScanner.nextLine())) {
    -                String targetArch = null;
    -                /* For cl.exe the first line holds all necessary information */
    -                if (scanner.hasNext("\u7528\u4E8E")) {
    -                    /* Simplified-Chinese has targetArch first */
    -                    scanner.next();
    -                    targetArch = scanner.next();
    +        protected CompilerInfo createCompilerInfo(Path compilerPath, Scanner scanner) {
    +            try {
    +                if (scanner.findInLine("Microsoft.*\\(R\\)") == null) {
    +                    return null; // not a Microsoft compiler
                     }
    -                /*
    -                 * Some cl.exe print "... Microsoft (R) C/C++ ... ##.##.#####" while others print
    -                 * "...C/C++ ... Microsoft (R) ... ##.##.#####".
    -                 */
    -                if (scanner.findInLine("Microsoft.*\\(R\\) C/C\\+\\+") == null &&
    -                                scanner.findInLine("C/C\\+\\+.*Microsoft.*\\(R\\)") == null) {
    +                scanner.nextLine(); // skip rest of first line
    +                scanner.nextLine(); // skip copyright line
    +                scanner.nextLine(); // skip blank separator line
    +                skipLineIfHasNext(scanner, "detect-cl-version-info.c");
    +                scanner.nextLine(); // skip blank separator line
    +                skipLineIfHasNext(scanner, "M_X64=100"); // _M_X64 is defined
    +                skipLineIfHasNext(scanner, "M_ARM64EC=_M_ARM64EC"); // _M_ARM64EC is not defined
    +                if (scanner.findInLine("MSC_FULL_VER=") == null) {
                         return null;
                     }
    -                scanner.useDelimiter("\\D");
    -                while (!scanner.hasNextInt()) {
    -                    scanner.next();
    -                }
    -                int major = scanner.nextInt();
    -                int minor0 = scanner.nextInt();
    -                int minor1 = scanner.nextInt();
    -                if (targetArch == null) {
    -                    scanner.reset();
    -                    while (scanner.hasNext()) {
    -                        /* targetArch is last token in line */
    -                        targetArch = scanner.next();
    -                    }
    +                String mscFullVerValue = scanner.nextLine();
    +                if (mscFullVerValue.length() < 5) {
    +                    return null;
                     }
    -                return new CompilerInfo(compilerPath, "microsoft", "C/C++ Optimizing Compiler", "cl", major, minor0, minor1, targetArch);
    -            } catch (NoSuchElementException e) {
    +                int major = Integer.parseInt(mscFullVerValue.substring(0, 2));
    +                int minor0 = Integer.parseInt(mscFullVerValue.substring(2, 4));
    +                int minor1 = Integer.parseInt(mscFullVerValue.substring(4));
    +                return new CompilerInfo(compilerPath, "microsoft", "C/C++ Optimizing Compiler", "cl", major, minor0, minor1, "x64");
    +            } catch (NoSuchElementException | NumberFormatException e) {
                     return null;
                 }
             }
     
    +        private void skipLineIfHasNext(Scanner scanner, String expectedToken) {
    +            if (scanner.hasNext(expectedToken)) {
    +                scanner.nextLine();
    +            } else {
    +                throw new NoSuchElementException(expectedToken);
    +            }
    +        }
    +
             @Override
             protected void verify() {
                 // See details on _MSC_VER at
    @@ -416,7 +421,7 @@ private CompilerInfo getCCompilerInfo() {
         }
     
         protected List getVersionInfoOptions() {
    -        return Arrays.asList("-v");
    +        return List.of("-v");
         }
     
         protected abstract CompilerInfo createCompilerInfo(Path compilerPath, Scanner scanner);
    
    From b2bcc76941ebd8c264974fe380294610d81c12d0 Mon Sep 17 00:00:00 2001
    From: Carlo Refice 
    Date: Tue, 19 Dec 2023 15:39:50 +0100
    Subject: [PATCH 294/593] Fix AArch64 signExtend constant folding ignoring
     output bits
    
    ---
     .../compiler/core/aarch64/AArch64ArithmeticLIRGenerator.java | 5 ++---
     1 file changed, 2 insertions(+), 3 deletions(-)
    
    diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/core/aarch64/AArch64ArithmeticLIRGenerator.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/core/aarch64/AArch64ArithmeticLIRGenerator.java
    index 9a4bc06b42f2..73082f13097f 100644
    --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/core/aarch64/AArch64ArithmeticLIRGenerator.java
    +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/core/aarch64/AArch64ArithmeticLIRGenerator.java
    @@ -363,12 +363,11 @@ public Value emitSignExtend(Value inputVal, int fromBits, int toBits) {
                 /*
                  * Performing sign extend via a left shift followed by an arithmetic right shift. First,
                  * a left shift of (64 - fromBits) is performed to remove non-meaningful bits, and then
    -             * an arithmetic right shift is used to set correctly all sign bits. Note the "toBits"
    -             * size is not considered, as the constant is saved as a long value.
    +             * an arithmetic right shift is used to set correctly all sign bits.
                  */
                 int shiftSize = 64 - fromBits;
                 long signExtendedValue = (constant << shiftSize) >> shiftSize;
    -            return new ConstantValue(resultKind, JavaConstant.forLong(signExtendedValue));
    +            return new ConstantValue(resultKind, JavaConstant.forPrimitiveInt(toBits, signExtendedValue));
             }
             Variable result = getLIRGen().newVariable(resultKind);
             getLIRGen().append(new AArch64Convert.SignExtendOp(result, asAllocatable(inputVal), fromBits, toBits));
    
    From 4e424bc3fbf424027df8765b9c0ef9e0fe7ae419 Mon Sep 17 00:00:00 2001
    From: Florian Huemer 
    Date: Tue, 19 Dec 2023 17:46:22 +0100
    Subject: [PATCH 295/593] Changed owner files
    
    ---
     wasm/OWNERS.toml                      | 2 +-
     wasm/src/org.graalvm.wasm/OWNERS.toml | 7 +++++++
     2 files changed, 8 insertions(+), 1 deletion(-)
     create mode 100644 wasm/src/org.graalvm.wasm/OWNERS.toml
    
    diff --git a/wasm/OWNERS.toml b/wasm/OWNERS.toml
    index 904bdcd3d23d..708923611a66 100644
    --- a/wasm/OWNERS.toml
    +++ b/wasm/OWNERS.toml
    @@ -1,6 +1,6 @@
     [[rule]]
     files = "*"
    -all = [
    +any = [
         "aleksandar.prokopec@oracle.com",
         "andreas.woess@oracle.com",
         "florian.huemer@oracle.com",
    diff --git a/wasm/src/org.graalvm.wasm/OWNERS.toml b/wasm/src/org.graalvm.wasm/OWNERS.toml
    new file mode 100644
    index 000000000000..904bdcd3d23d
    --- /dev/null
    +++ b/wasm/src/org.graalvm.wasm/OWNERS.toml
    @@ -0,0 +1,7 @@
    +[[rule]]
    +files = "*"
    +all = [
    +    "aleksandar.prokopec@oracle.com",
    +    "andreas.woess@oracle.com",
    +    "florian.huemer@oracle.com",
    +]
    \ No newline at end of file
    
    From 54a0bfc6ef0a2ec20adc0c249af8ee5dcfe55ed2 Mon Sep 17 00:00:00 2001
    From: Jirka Marsik 
    Date: Tue, 19 Dec 2023 21:52:58 +0100
    Subject: [PATCH 296/593] Remove obsolete GraalWasm opcodes
    
    ---
     .../src/org/graalvm/wasm/BinaryParser.java               | 9 +++------
     .../src/org/graalvm/wasm/constants/Instructions.java     | 8 --------
     2 files changed, 3 insertions(+), 14 deletions(-)
    
    diff --git a/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/BinaryParser.java b/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/BinaryParser.java
    index 9ce7d5f4228d..bb35f13f84af 100644
    --- a/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/BinaryParser.java
    +++ b/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/BinaryParser.java
    @@ -775,8 +775,7 @@ private CodeEntry readFunction(int functionIndex, byte[] locals, byte[] resultTy
                         }
                         break;
                     }
    -                case Instructions.LOCAL_GET:
    -                case Instructions.LOCAL_GET_OBJ: {
    +                case Instructions.LOCAL_GET: {
                         final int localIndex = readLocalIndex();
                         assertUnsignedIntLess(localIndex, locals.length, Failure.UNKNOWN_LOCAL);
                         final byte localType = locals[localIndex];
    @@ -788,8 +787,7 @@ private CodeEntry readFunction(int functionIndex, byte[] locals, byte[] resultTy
                         }
                         break;
                     }
    -                case Instructions.LOCAL_SET:
    -                case Instructions.LOCAL_SET_OBJ: {
    +                case Instructions.LOCAL_SET: {
                         final int localIndex = readLocalIndex();
                         assertUnsignedIntLess(localIndex, locals.length, Failure.UNKNOWN_LOCAL);
                         final byte localType = locals[localIndex];
    @@ -801,8 +799,7 @@ private CodeEntry readFunction(int functionIndex, byte[] locals, byte[] resultTy
                         }
                         break;
                     }
    -                case Instructions.LOCAL_TEE:
    -                case Instructions.LOCAL_TEE_OBJ: {
    +                case Instructions.LOCAL_TEE: {
                         final int localIndex = readLocalIndex();
                         assertUnsignedIntLess(localIndex, locals.length, Failure.UNKNOWN_LOCAL);
                         final byte localType = locals[localIndex];
    diff --git a/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/constants/Instructions.java b/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/constants/Instructions.java
    index 19a03c1682bd..8165d9772e18 100644
    --- a/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/constants/Instructions.java
    +++ b/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/constants/Instructions.java
    @@ -380,14 +380,6 @@ public final class Instructions {
         public static final int VECTOR_F64X2_PMIN = 0xF6;
         public static final int VECTOR_F64X2_PMAX = 0xF7;
     
    -    // GraalWasm specific opcodes (these are reserved for future webassembly extensions and might be
    -    // used in other ways in the future)
    -
    -    public static final int DROP_OBJ = 0x19;
    -    public static final int LOCAL_GET_OBJ = 0x1D;
    -    public static final int LOCAL_SET_OBJ = 0x1E;
    -    public static final int LOCAL_TEE_OBJ = 0x1F;
    -
         private static String[] decodingTable = new String[256];
     
         private Instructions() {
    
    From b1892810c2609b813cc06f3ac3f074477629f1a8 Mon Sep 17 00:00:00 2001
    From: Jirka Marsik 
    Date: Tue, 19 Dec 2023 21:56:51 +0100
    Subject: [PATCH 297/593] Use data.addRange in BytecodeGen#add16
    
    ---
     .../src/org/graalvm/wasm/parser/bytecode/BytecodeGen.java    | 5 +----
     1 file changed, 1 insertion(+), 4 deletions(-)
    
    diff --git a/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/parser/bytecode/BytecodeGen.java b/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/parser/bytecode/BytecodeGen.java
    index d7ad6554b5c2..ec43f5f18b01 100644
    --- a/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/parser/bytecode/BytecodeGen.java
    +++ b/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/parser/bytecode/BytecodeGen.java
    @@ -181,10 +181,7 @@ protected void add8(long value) {
          * @param value the {@link Vector128} value
          */
         protected void add16(Vector128 value) {
    -        byte[] bytes = value.asBytes();
    -        for (int i = 0; i < 16; i++) {
    -            data.add(bytes[i]);
    -        }
    +        data.addRange(value.asBytes(), 0, 16);
         }
     
         /**
    
    From 020b17fe9492d371d89c97c58e4b861d3659cc97 Mon Sep 17 00:00:00 2001
    From: Raphael Mosaner 
    Date: Mon, 18 Dec 2023 18:46:38 +0100
    Subject: [PATCH 298/593] [GR-49481] Remove explicit null check exceptions from
     genCheckCast and genInstanceof.
    
    ---
     .../src/jdk/graal/compiler/java/BytecodeParser.java         | 4 ++--
     .../nodes/graphbuilderconf/GraphBuilderContext.java         | 6 +++++-
     2 files changed, 7 insertions(+), 3 deletions(-)
    
    diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/java/BytecodeParser.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/java/BytecodeParser.java
    index 028745acca5d..2d0902c10edf 100644
    --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/java/BytecodeParser.java
    +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/java/BytecodeParser.java
    @@ -4560,7 +4560,7 @@ protected void genCheckCast(ResolvedJavaType resolvedType, ValueNode objectIn) {
                 if (profile.getNullSeen().isFalse()) {
                     SpeculationLog.Speculation speculation = mayUseTypeProfile();
                     if (speculation != null) {
    -                    object = nullCheckedValue(object);
    +                    object = addNonNullCast(object, InvalidateReprofile);
                         ResolvedJavaType singleType = profile.asSingleType();
                         if (singleType != null && checkedType.getType().isAssignableFrom(singleType)) {
                             LogicNode typeCheck = append(createInstanceOf(TypeReference.createExactTrusted(singleType), object, profile));
    @@ -4623,7 +4623,7 @@ protected void genInstanceOf(ResolvedJavaType resolvedType, ValueNode objectIn)
             LogicNode instanceOfNode = null;
             if (profile != null) {
                 if (profile.getNullSeen().isFalse()) {
    -                object = nullCheckedValue(object);
    +                object = addNonNullCast(object, InvalidateReprofile);
                     boolean createGuard = true;
                     ResolvedJavaType singleType = profile.asSingleType();
                     if (singleType != null) {
    diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/nodes/graphbuilderconf/GraphBuilderContext.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/nodes/graphbuilderconf/GraphBuilderContext.java
    index ad738d733e13..3742b8bf73b8 100644
    --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/nodes/graphbuilderconf/GraphBuilderContext.java
    +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/nodes/graphbuilderconf/GraphBuilderContext.java
    @@ -142,12 +142,16 @@ default Node canonicalizeAndAdd(Node value) {
         }
     
         default ValueNode addNonNullCast(ValueNode value) {
    +        return addNonNullCast(value, DeoptimizationAction.None);
    +    }
    +
    +    default ValueNode addNonNullCast(ValueNode value, DeoptimizationAction action) {
             AbstractPointerStamp valueStamp = (AbstractPointerStamp) value.stamp(NodeView.DEFAULT);
             if (valueStamp.nonNull()) {
                 return value;
             } else {
                 LogicNode isNull = add(IsNullNode.create(value));
    -            FixedGuardNode fixedGuard = add(new FixedGuardNode(isNull, DeoptimizationReason.NullCheckException, DeoptimizationAction.None, true));
    +            FixedGuardNode fixedGuard = add(new FixedGuardNode(isNull, DeoptimizationReason.NullCheckException, action, true));
                 Stamp newStamp = valueStamp.improveWith(StampFactory.objectNonNull());
                 return add(PiNode.create(value, newStamp, fixedGuard));
             }
    
    From 4c79426ec3655e6863c57ed88ce77e5affa9d42f Mon Sep 17 00:00:00 2001
    From: Raphael Mosaner 
    Date: Tue, 12 Dec 2023 09:38:28 +0100
    Subject: [PATCH 299/593] [GR-49481] Regression test for check cast
     optimizations with allowed null values.
    
    ---
     .../core/test/CheckCastWithNullTest.java      | 146 ++++++++++++++++++
     1 file changed, 146 insertions(+)
     create mode 100644 compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/core/test/CheckCastWithNullTest.java
    
    diff --git a/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/core/test/CheckCastWithNullTest.java b/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/core/test/CheckCastWithNullTest.java
    new file mode 100644
    index 000000000000..27654b0fc761
    --- /dev/null
    +++ b/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/core/test/CheckCastWithNullTest.java
    @@ -0,0 +1,146 @@
    +/*
    + * Copyright (c) 2023, 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 jdk.graal.compiler.core.test;
    +
    +import org.junit.Test;
    +import jdk.graal.compiler.nodes.java.InstanceOfNode;
    +import jdk.vm.ci.code.InstalledCode;
    +import jdk.vm.ci.code.InvalidInstalledCodeException;
    +
    +/**
    + * Tests the correct behavior of (optimized) type casts with {@code null} values. Check casts use
    + * {@code instanceof} guards. While casts of null values always succeed, {@code instanceof} yields
    + * {@code false} for {@code null} values. {@link InstanceOfNode#createAllowNull} would be needed to
    + * create {@code instanceof} checks which yield {@code true} for {@code null} values. Explicit
    + * {@code null} checks are not allowed, as they can result in wrongly thrown
    + * {@code NullPointerExceptions} in user code.
    + */
    +public class CheckCastWithNullTest extends GraalCompilerTest {
    +
    +    public static class A {
    +    }
    +
    +    static class B extends A {
    +    }
    +
    +    static class C {
    +    }
    +
    +    public static final A NULL = null;
    +
    +    /*
    +     * Snippets are duplicated to have different profiles.
    +     */
    +    public static int snippetNoProfile(Object o) {
    +        A a = (A) o;
    +        return a == null ? 1 : 2;
    +    }
    +
    +    public static int snippetWithSingleTypeProfile(Object o) {
    +        A a = (A) o;
    +        return a == null ? 1 : 2;
    +    }
    +
    +    public static int snippetWithMultipleTypeProfile(Object o) {
    +        A a = (A) o;
    +        return a == null ? 1 : 2;
    +    }
    +
    +    public static int snippetNullSeen(Object o) {
    +        A a = (A) o;
    +        return a == null ? 1 : 2;
    +    }
    +
    +    public static int snippetExceptionSeen(Object o) {
    +        A a = (A) o;
    +        return a == null ? 1 : 2;
    +    }
    +
    +    @Test
    +    public void testNoProfile() throws InvalidInstalledCodeException {
    +        resetCache();
    +        // compile without type profile
    +        InstalledCode c = getCode(getResolvedJavaMethod("snippetNoProfile"), null, true, false, getInitialOptions());
    +        // null not seen until now
    +        assert c.executeVarargs(NULL).equals(1);
    +        assert c.isValid();
    +    }
    +
    +    @Test
    +    public void testWithSingleTypeProfile() throws InvalidInstalledCodeException {
    +        resetCache();
    +        for (int i = 0; i < 10000; i++) {
    +            test("snippetWithSingleTypeProfile", new B());
    +        }
    +        // compiles with single type profile
    +        InstalledCode c = getCode(getResolvedJavaMethod("snippetWithSingleTypeProfile"), null, true, false, getInitialOptions());
    +        // null not seen until now
    +        assert c.executeVarargs(NULL).equals(1);
    +        assert !c.isValid();
    +    }
    +
    +    @Test
    +    public void testWithMultipleTypeProfile() throws InvalidInstalledCodeException {
    +        resetCache();
    +        for (int i = 0; i < 10000; i++) {
    +            test("snippetWithMultipleTypeProfile", new B());
    +            test("snippetWithMultipleTypeProfile", new A());
    +        }
    +        // compiles with multiple type profile
    +        InstalledCode c = getCode(getResolvedJavaMethod("snippetWithMultipleTypeProfile"), null, true, false, getInitialOptions());
    +        // null not seen until now
    +        assert c.executeVarargs(NULL).equals(1);
    +        assert !c.isValid();
    +    }
    +
    +    @Test
    +    public void testNullSeen() throws InvalidInstalledCodeException {
    +        resetCache();
    +        for (int i = 0; i < 10000; i++) {
    +            test("snippetNullSeen", new B());
    +            test("snippetNullSeen", NULL);
    +        }
    +        // compiles with null seen in profile
    +        InstalledCode c = getCode(getResolvedJavaMethod("snippetNullSeen"), null, true, false, getInitialOptions());
    +        // null not seen until now
    +        assert c.executeVarargs(NULL).equals(1);
    +        assert c.isValid();
    +    }
    +
    +    @Test
    +    public void testExceptionSeen() throws InvalidInstalledCodeException {
    +        resetCache();
    +        for (int i = 0; i < 10000; i++) {
    +            test("snippetExceptionSeen", new B());
    +        }
    +        // trigger deopt because of ClassCastException for C
    +        test("snippetExceptionSeen", new C());
    +        // compiles with exception seen
    +        InstalledCode c = getCode(getResolvedJavaMethod("snippetExceptionSeen"), null, true, false, getInitialOptions());
    +        // null not seen until now
    +        assert c.executeVarargs(NULL).equals(1);
    +        assert !c.isValid();
    +    }
    +}
    
    From e31b87d093b29b95104aa8b10bf4b280c0599ec4 Mon Sep 17 00:00:00 2001
    From: Raphael Mosaner 
    Date: Fri, 15 Dec 2023 10:11:54 +0100
    Subject: [PATCH 300/593] [GR-49481] Document explicit NPE for
     GraphBuilderContext#nullCheckedValue.
    
    ---
     .../nodes/graphbuilderconf/GraphBuilderContext.java    | 10 ++++++++--
     1 file changed, 8 insertions(+), 2 deletions(-)
    
    diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/nodes/graphbuilderconf/GraphBuilderContext.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/nodes/graphbuilderconf/GraphBuilderContext.java
    index 3742b8bf73b8..23cc93d846c2 100644
    --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/nodes/graphbuilderconf/GraphBuilderContext.java
    +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/nodes/graphbuilderconf/GraphBuilderContext.java
    @@ -318,6 +318,11 @@ default boolean isPluginEnabled(GraphBuilderPlugin plugin) {
     
         BailoutException bailout(String string);
     
    +    /**
    +     * Gets a version of a given value that has a non-null stamp. Emits a guard or an explicit
    +     * exception check which is triggered if the value is null. Thus,  use only for values where
    +     * the underlying bytecode can throw a {@link NullPointerException}! 
    +     */
         default ValueNode nullCheckedValue(ValueNode value) {
             return nullCheckedValue(value, InvalidateReprofile);
         }
    @@ -336,8 +341,9 @@ default GuardingNode intrinsicRangeCheck(LogicNode condition, boolean negated) {
         }
     
         /**
    -     * Gets a version of a given value that has a {@linkplain StampTool#isPointerNonNull(ValueNode)
    -     * non-null} stamp.
    +     * Gets a version of a given value that has a non-null stamp. Emits a guard or an explicit
    +     * exception check which is triggered if the value is null. Thus,  use only for values where
    +     * the underlying bytecode can throw a {@link NullPointerException}! 
          */
         default ValueNode nullCheckedValue(ValueNode value, DeoptimizationAction action) {
             if (!StampTool.isPointerNonNull(value)) {
    
    From cd7bbf6d0c457873fa8454a42564faf1db08a5c4 Mon Sep 17 00:00:00 2001
    From: ol-automation_ww 
    Date: Wed, 20 Dec 2023 08:37:29 +0000
    Subject: [PATCH 301/593] update to 23+2-jvmci-b01
    
    ---
     common.json | 12 ++++++------
     1 file changed, 6 insertions(+), 6 deletions(-)
    
    diff --git a/common.json b/common.json
    index 903eb2ce446e..c16a604da129 100644
    --- a/common.json
    +++ b/common.json
    @@ -45,12 +45,12 @@
         "labsjdk-ee-21-llvm": {"name": "labsjdk",   "version": "ee-21.0.1+11-jvmci-23.1-b26-sulong", "platformspecific": true },
     
         "oraclejdk-latest":       {"name": "jpg-jdk",   "version": "23",      "build_id": "1", "release": true, "platformspecific": true, "extrabundles": ["static-libs"]},
    -    "labsjdk-ce-latest":      {"name": "labsjdk",   "version": "ce-23+1-jvmci-b01", "platformspecific": true },
    -    "labsjdk-ce-latestDebug": {"name": "labsjdk",   "version": "ce-23+1-jvmci-b01-debug", "platformspecific": true },
    -    "labsjdk-ce-latest-llvm": {"name": "labsjdk",   "version": "ce-23+1-jvmci-b01-sulong", "platformspecific": true },
    -    "labsjdk-ee-latest":      {"name": "labsjdk",   "version": "ee-23+1-jvmci-b01", "platformspecific": true },
    -    "labsjdk-ee-latestDebug": {"name": "labsjdk",   "version": "ee-23+1-jvmci-b01-debug", "platformspecific": true },
    -    "labsjdk-ee-latest-llvm": {"name": "labsjdk",   "version": "ee-23+1-jvmci-b01-sulong", "platformspecific": true }
    +    "labsjdk-ce-latest":      {"name": "labsjdk",   "version": "ce-23+2-jvmci-b01-20231219100612-5ebca33d60", "platformspecific": true },
    +    "labsjdk-ce-latestDebug": {"name": "labsjdk",   "version": "ce-23+2-jvmci-b01-20231219100612-5ebca33d60-debug", "platformspecific": true },
    +    "labsjdk-ce-latest-llvm": {"name": "labsjdk",   "version": "ce-23+2-jvmci-b01-20231219100612-5ebca33d60-sulong", "platformspecific": true },
    +    "labsjdk-ee-latest":      {"name": "labsjdk",   "version": "ee-23+2-jvmci-b01-20231219100612-5ebca33d60+4e97b2bfec", "platformspecific": true },
    +    "labsjdk-ee-latestDebug": {"name": "labsjdk",   "version": "ee-23+2-jvmci-b01-20231219100612-5ebca33d60+4e97b2bfec-debug", "platformspecific": true },
    +    "labsjdk-ee-latest-llvm": {"name": "labsjdk",   "version": "ee-23+2-jvmci-b01-20231219100612-5ebca33d60+4e97b2bfec-sulong", "platformspecific": true }
       },
     
       "eclipse": {
    
    From 183e69fe1e4285269cfa13671c4b3437bab009e1 Mon Sep 17 00:00:00 2001
    From: Marouane El Hallaoui 
    Date: Wed, 20 Dec 2023 09:58:51 +0100
    Subject: [PATCH 302/593] update JVMCI version check
    
    ---
     common.json                                                   | 2 +-
     .../src/jdk/graal/compiler/hotspot/JVMCIVersionCheck.java     | 4 ++--
     2 files changed, 3 insertions(+), 3 deletions(-)
    
    diff --git a/common.json b/common.json
    index c16a604da129..94cc85c21248 100644
    --- a/common.json
    +++ b/common.json
    @@ -44,7 +44,7 @@
         "labsjdk-ee-21Debug": {"name": "labsjdk",   "version": "ee-21.0.1+11-jvmci-23.1-b26-debug", "platformspecific": true },
         "labsjdk-ee-21-llvm": {"name": "labsjdk",   "version": "ee-21.0.1+11-jvmci-23.1-b26-sulong", "platformspecific": true },
     
    -    "oraclejdk-latest":       {"name": "jpg-jdk",   "version": "23",      "build_id": "1", "release": true, "platformspecific": true, "extrabundles": ["static-libs"]},
    +    "oraclejdk-latest":       {"name": "jpg-jdk",   "version": "23",      "build_id": "2", "release": true, "platformspecific": true, "extrabundles": ["static-libs"]},
         "labsjdk-ce-latest":      {"name": "labsjdk",   "version": "ce-23+2-jvmci-b01-20231219100612-5ebca33d60", "platformspecific": true },
         "labsjdk-ce-latestDebug": {"name": "labsjdk",   "version": "ce-23+2-jvmci-b01-20231219100612-5ebca33d60-debug", "platformspecific": true },
         "labsjdk-ce-latest-llvm": {"name": "labsjdk",   "version": "ce-23+2-jvmci-b01-20231219100612-5ebca33d60-sulong", "platformspecific": true },
    diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/JVMCIVersionCheck.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/JVMCIVersionCheck.java
    index 096962ee1485..a74becc7ea5d 100644
    --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/JVMCIVersionCheck.java
    +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/JVMCIVersionCheck.java
    @@ -54,8 +54,8 @@ public final class JVMCIVersionCheck {
         private static final Map> JVMCI_MIN_VERSIONS = Map.of(
                         "21", Map.of(DEFAULT_VENDOR_ENTRY, new Version(23, 1, 26)),
                         "23", Map.of(
    -                                    "Oracle Corporation", new Version("23+1", 1),
    -                                    DEFAULT_VENDOR_ENTRY, new Version("23+1", 1)));
    +                                    "Oracle Corporation", new Version("23+2", 1),
    +                                    DEFAULT_VENDOR_ENTRY, new Version("23+2", 1)));
         private static final int NA = 0;
         /**
          * Minimum Java release supported by Graal.
    
    From 56fffc1debf8bc884d03e3c752c1636dc4a39e6a Mon Sep 17 00:00:00 2001
    From: =?UTF-8?q?Aleksandar=20Pejovi=C4=87?= 
    Date: Tue, 19 Dec 2023 23:07:24 +0100
    Subject: [PATCH 303/593] Fix building of microservice benchmark native images
    
    ---
     vm/mx.vm/mx_vm_benchmark.py | 16 +++++++++++-----
     1 file changed, 11 insertions(+), 5 deletions(-)
    
    diff --git a/vm/mx.vm/mx_vm_benchmark.py b/vm/mx.vm/mx_vm_benchmark.py
    index 5825de2bdbc1..529242aed371 100644
    --- a/vm/mx.vm/mx_vm_benchmark.py
    +++ b/vm/mx.vm/mx_vm_benchmark.py
    @@ -237,10 +237,16 @@ def check_runnable(self):
     
             def get_bundle_path_if_present(self):
                 bundle_apply_arg = "--bundle-apply="
    -            bundle_arg = [arg for arg in self.extra_image_build_arguments if arg.startswith(bundle_apply_arg)]
    -            if len(bundle_arg) == 1:
    -                bp = bundle_arg[0][len(bundle_apply_arg):]
    -                return bp
    +            for i in range(len(self.extra_image_build_arguments)):
    +                if self.extra_image_build_arguments[i].startswith(bundle_apply_arg):
    +                    # The bundle output is produced next to the bundle file, which in the case of
    +                    # benchmarks is in the mx cache, so we make a local copy.
    +                    cached_bundle_path = self.extra_image_build_arguments[i][len(bundle_apply_arg):]
    +                    bundle_copy_path = join(self.output_dir, basename(cached_bundle_path))
    +                    mx.ensure_dirname_exists(bundle_copy_path)
    +                    mx.copyfile(cached_bundle_path, bundle_copy_path)
    +                    self.extra_image_build_arguments[i] = bundle_apply_arg + bundle_copy_path
    +                    return bundle_copy_path
     
                 return None
     
    @@ -893,7 +899,7 @@ def rules(self, output, benchmarks, bmSuiteArgs):
         def copy_bundle_output(config):
             """
             Copies all files from the bundle build into the benchmark build location.
    -        By default, the bundle output is produced next to the bundle file. In case of benchmarks, this bundle file is in the mx cache.
    +        By default, the bundle output is produced next to the bundle file.
             """
             bundle_dir = os.path.dirname(config.bundle_path)
             bundle_name = os.path.basename(config.bundle_path)
    
    From 95024c6e6c21f1f4c8e46695eca8a94d4b875b8b Mon Sep 17 00:00:00 2001
    From: Josef Haider 
    Date: Wed, 20 Dec 2023 12:12:27 +0100
    Subject: [PATCH 304/593] Add JDK version check to ported JDK22 intrinsic test
    
    ---
     .../test/StringCompressInflateTest.java       | 39 ++++++++++---------
     1 file changed, 21 insertions(+), 18 deletions(-)
    
    diff --git a/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/replacements/test/StringCompressInflateTest.java b/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/replacements/test/StringCompressInflateTest.java
    index 6d33c868f500..42da8678aebb 100644
    --- a/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/replacements/test/StringCompressInflateTest.java
    +++ b/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/replacements/test/StringCompressInflateTest.java
    @@ -42,6 +42,7 @@
     import jdk.graal.compiler.replacements.StringLatin1InflateNode;
     import jdk.graal.compiler.replacements.StringUTF16CompressNode;
     import jdk.graal.compiler.replacements.amd64.AMD64GraphBuilderPlugins;
    +import jdk.graal.compiler.serviceprovider.JavaVersionUtil;
     import jdk.graal.compiler.test.AddExports;
     import jdk.vm.ci.code.InstalledCode;
     import jdk.vm.ci.code.InvalidInstalledCodeException;
    @@ -299,24 +300,26 @@ public void testStringUTF16CompressCharByte() throws ClassNotFoundException {
                 }
             }
     
    -        // Exhaustively check compress returning the correct index of the non-latin1 char.
    -        final int size = 48;
    -        final byte fillByte = 'R';
    -        char[] chars = new char[size];
    -        final byte[] bytes = new byte[chars.length];
    -        Arrays.fill(bytes, fillByte);
    -        for (int i = 0; i < size; i++) { // Every starting index
    -            for (int j = i; j < size; j++) {  // Every location of non-latin1
    -                Arrays.fill(chars, 'A');
    -                chars[j] = 0xFF21;
    -                byte[] dst = Arrays.copyOf(bytes, bytes.length);
    -                byte[] dst2 = Arrays.copyOf(bytes, bytes.length);
    -                int result = (int) invokeSafe(caller, null, chars, i, dst, 0, chars.length - i);
    -                int result2 = (int) executeVarargsSafe(code, chars, i, dst2, 0, chars.length - i);
    -                Assert.assertEquals(result, result2);
    -                Assert.assertArrayEquals(dst, dst2);
    -                Assert.assertEquals("compress found wrong index", j - i, result);
    -                Assert.assertEquals("extra character stored", fillByte, bytes[j]);
    +        if (JavaVersionUtil.JAVA_SPEC >= 22) {
    +            // Exhaustively check compress returning the correct index of the non-latin1 char.
    +            final int size = 48;
    +            final byte fillByte = 'R';
    +            char[] chars = new char[size];
    +            final byte[] bytes = new byte[chars.length];
    +            Arrays.fill(bytes, fillByte);
    +            for (int i = 0; i < size; i++) { // Every starting index
    +                for (int j = i; j < size; j++) {  // Every location of non-latin1
    +                    Arrays.fill(chars, 'A');
    +                    chars[j] = 0xFF21;
    +                    byte[] dst = Arrays.copyOf(bytes, bytes.length);
    +                    byte[] dst2 = Arrays.copyOf(bytes, bytes.length);
    +                    int result = (int) invokeSafe(caller, null, chars, i, dst, 0, chars.length - i);
    +                    int result2 = (int) executeVarargsSafe(code, chars, i, dst2, 0, chars.length - i);
    +                    Assert.assertEquals(result, result2);
    +                    Assert.assertArrayEquals(dst, dst2);
    +                    Assert.assertEquals("compress found wrong index", j - i, result);
    +                    Assert.assertEquals("extra character stored", fillByte, bytes[j]);
    +                }
                 }
             }
         }
    
    From 27bba3e21aa8a1b59cd220f3e3bc7341e5d4a0d5 Mon Sep 17 00:00:00 2001
    From: Fabio Niephaus 
    Date: Wed, 20 Dec 2023 12:36:39 +0000
    Subject: [PATCH 305/593] Applied suggestion
    
    ---
     docs/reference-manual/embedding/embed-languages.md | 2 +-
     1 file changed, 1 insertion(+), 1 deletion(-)
    
    diff --git a/docs/reference-manual/embedding/embed-languages.md b/docs/reference-manual/embedding/embed-languages.md
    index eb93eab5f6d3..c60fab8df3a1 100644
    --- a/docs/reference-manual/embedding/embed-languages.md
    +++ b/docs/reference-manual/embedding/embed-languages.md
    @@ -72,7 +72,7 @@ To access [polyglot isolate](#polyglot-isolates) artifacts, use the `-isolate` s
     The artifacts `polyglot` and `tools` include all available languages and tools as dependencies. 
     This artifact might grow or shrink between major releases. We recommend selecting only the needed language(s) for a production deployment.
     
    -> The `pom` type is a requirement for a language or tool dependency.
    +> The `pom` type is a requirement for language or tool dependencies.
     
     Additionally, your _module-info.java_ file should require `org.graalvm.polyglot` when using Java modules.
     
    
    From d2c82dff5d303ed69801f5f7f22f00d97348ee7c Mon Sep 17 00:00:00 2001
    From: Christian Haeubl 
    Date: Wed, 20 Dec 2023 14:03:14 +0100
    Subject: [PATCH 306/593] Cleanups.
    
    ---
     .../genscavenge/ChunkedImageHeapLayouter.java | 16 +++++------
     .../ChunkedImageHeapPartition.java            | 28 ++++++++-----------
     .../svm/core/genscavenge/HeapVerifier.java    |  4 +--
     3 files changed, 22 insertions(+), 26 deletions(-)
    
    diff --git a/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/ChunkedImageHeapLayouter.java b/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/ChunkedImageHeapLayouter.java
    index bbb083e3af19..2f249e9f0fbc 100644
    --- a/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/ChunkedImageHeapLayouter.java
    +++ b/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/ChunkedImageHeapLayouter.java
    @@ -232,7 +232,7 @@ private void initializeHeapInfo(int dynamicHubCount, long offsetOfFirstWritableA
                             getReadOnlyHuge().firstObject, getReadOnlyHuge().lastObject, writableAligned, writableUnaligned, dynamicHubCount);
         }
     
    -    protected ImageHeapLayoutInfo createLayoutInfo(long heapStartOffset, long writableBeginOffset) {
    +    private ImageHeapLayoutInfo createLayoutInfo(long heapStartOffset, long writableBeginOffset) {
             long writableEnd = getWritableHuge().getStartOffset() + getWritableHuge().getSize();
             long writableSize = writableEnd - writableBeginOffset;
             long imageHeapSize = getReadOnlyHuge().getStartOffset() + getReadOnlyHuge().getSize() - heapStartOffset;
    @@ -276,30 +276,30 @@ private static void writeHeader(ImageHeapChunkWriter writer, Chunk previous, Chu
         }
     
         private ChunkedImageHeapPartition getReadOnlyPrimitive() {
    -        return getPartitions()[READ_ONLY_PRIMITIVE];
    +        return partitions[READ_ONLY_PRIMITIVE];
         }
     
         private ChunkedImageHeapPartition getReadOnlyReference() {
    -        return getPartitions()[READ_ONLY_REFERENCE];
    +        return partitions[READ_ONLY_REFERENCE];
         }
     
         private ChunkedImageHeapPartition getReadOnlyRelocatable() {
    -        return getPartitions()[READ_ONLY_RELOCATABLE];
    +        return partitions[READ_ONLY_RELOCATABLE];
         }
     
         private ChunkedImageHeapPartition getWritablePrimitive() {
    -        return getPartitions()[WRITABLE_PRIMITIVE];
    +        return partitions[WRITABLE_PRIMITIVE];
         }
     
         private ChunkedImageHeapPartition getWritableReference() {
    -        return getPartitions()[WRITABLE_REFERENCE];
    +        return partitions[WRITABLE_REFERENCE];
         }
     
         private ChunkedImageHeapPartition getWritableHuge() {
    -        return getPartitions()[WRITABLE_HUGE];
    +        return partitions[WRITABLE_HUGE];
         }
     
         private ChunkedImageHeapPartition getReadOnlyHuge() {
    -        return getPartitions()[READ_ONLY_HUGE];
    +        return partitions[READ_ONLY_HUGE];
         }
     }
    diff --git a/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/ChunkedImageHeapPartition.java b/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/ChunkedImageHeapPartition.java
    index 9e636d812940..ee65ca25caa1 100644
    --- a/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/ChunkedImageHeapPartition.java
    +++ b/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/ChunkedImageHeapPartition.java
    @@ -68,7 +68,7 @@ public class ChunkedImageHeapPartition implements ImageHeapPartition {
             this.minimumObjectSize = ConfigurationValues.getObjectLayout().getMinImageHeapObjectSize();
         }
     
    -    public void assign(ImageHeapObject obj) {
    +    void assign(ImageHeapObject obj) {
             assert obj.getPartition() == this : obj;
             objects.add(obj);
         }
    @@ -86,7 +86,7 @@ private void layoutInUnalignedChunks(ChunkedImageHeapAllocator allocator) {
             allocator.alignBetweenChunks(getStartAlignment());
             startOffset = allocator.getPosition();
     
    -        for (ImageHeapObject info : getObjects()) { // No need to sort by size
    +        for (ImageHeapObject info : objects) { // No need to sort by size
                 appendAllocatedObject(info, allocator.allocateUnalignedChunkForObject(info, isWritable()));
             }
     
    @@ -106,9 +106,9 @@ private void layoutInAlignedChunks(ChunkedImageHeapAllocator allocator) {
         }
     
         private void allocateObjectsInAlignedChunks(ChunkedImageHeapAllocator allocator) {
    -        NavigableMap> objects = createSortedObjectsMap(getObjects());
    -        while (!objects.isEmpty()) {
    -            ImageHeapObject info = dequeueBestFit(objects, allocator.getRemainingBytesInAlignedChunk());
    +        NavigableMap> sortedObjects = createSortedObjectsMap();
    +        while (!sortedObjects.isEmpty()) {
    +            ImageHeapObject info = dequeueBestFit(sortedObjects, allocator.getRemainingBytesInAlignedChunk());
                 if (info == null) {
                     allocator.startNewAlignedChunk();
                 } else {
    @@ -133,7 +133,7 @@ private ImageHeapObject dequeueBestFit(NavigableMap
             return info;
         }
     
    -    private static NavigableMap> createSortedObjectsMap(List objects) {
    +    private NavigableMap> createSortedObjectsMap() {
             ImageHeapObject[] sorted = objects.toArray(new ImageHeapObject[0]);
             Arrays.sort(sorted, new SizeComparator());
     
    @@ -180,16 +180,12 @@ private static Object extractObject(ImageHeapObject info) {
             }
         }
     
    -    public List getObjects() {
    -        return objects;
    -    }
    -
         @Override
         public String getName() {
             return name;
         }
     
    -    public boolean isWritable() {
    +    boolean isWritable() {
             return writable;
         }
     
    @@ -197,22 +193,22 @@ boolean usesUnalignedObjects() {
             return hugeObjects;
         }
     
    -    public final int getStartAlignment() {
    +    final int getStartAlignment() {
             assert startAlignment >= 0 : "Start alignment not yet assigned";
             return startAlignment;
         }
     
    -    public void setStartAlignment(int alignment) {
    +    void setStartAlignment(int alignment) {
             assert this.startAlignment == -1 : "Start alignment already assigned: " + this.startAlignment;
             this.startAlignment = alignment;
         }
     
    -    public final int getEndAlignment() {
    +    final int getEndAlignment() {
             assert endAlignment >= 0 : "End alignment not yet assigned";
             return endAlignment;
         }
     
    -    public void setEndAlignment(int endAlignment) {
    +    void setEndAlignment(int endAlignment) {
             assert this.endAlignment == -1 : "End alignment already assigned: " + this.endAlignment;
             this.endAlignment = endAlignment;
         }
    @@ -223,7 +219,7 @@ public long getStartOffset() {
             return startOffset;
         }
     
    -    public long getEndOffset() {
    +    long getEndOffset() {
             assert endOffset >= 0 : "End offset not yet set";
             return endOffset;
         }
    diff --git a/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/HeapVerifier.java b/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/HeapVerifier.java
    index f5356dd150d0..6e098e8497fe 100644
    --- a/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/HeapVerifier.java
    +++ b/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/HeapVerifier.java
    @@ -59,14 +59,14 @@ private HeapVerifier() {
     
         public static boolean verify(Occasion occasion) {
             boolean success = true;
    -        success &= verifyChunkedImageHeap();
    +        success &= verifyImageHeap();
             success &= verifyYoungGeneration(occasion);
             success &= verifyOldGeneration();
             success &= verifyRememberedSets();
             return success;
         }
     
    -    private static boolean verifyChunkedImageHeap() {
    +    private static boolean verifyImageHeap() {
             boolean success = true;
             ImageHeapInfo info = HeapImpl.getImageHeapInfo();
             success &= verifyAlignedChunks(null, info.getFirstWritableAlignedChunk());
    
    From c26f970db68a335b2d7689d0583f05857af1f45a Mon Sep 17 00:00:00 2001
    From: Tom Shull 
    Date: Wed, 8 Nov 2023 16:14:10 +0100
    Subject: [PATCH 307/593] Split DynamicHub and Hybrid Layout.
    
    ---
     .../ChunkedImageHeapPartition.java            |   4 +-
     .../oracle/svm/core/config/ObjectLayout.java  |   3 +
     .../com/oracle/svm/core/hub/DynamicHub.java   |   9 +-
     .../src/com/oracle/svm/core/hub/Hybrid.java   |  44 ++----
     .../oracle/svm/core/hub/LayoutEncoding.java   |   5 +
     .../svm/hosted/HostedConfiguration.java       |  47 +++++-
     .../svm/hosted/config/DynamicHubLayout.java   | 147 ++++++++++++++++++
     .../svm/hosted/config/HybridLayout.java       |  23 +--
     .../hosted/config/HybridLayoutSupport.java    |  52 ++-----
     .../svm/hosted/image/NativeImageHeap.java     |  75 +++++----
     .../hosted/image/NativeImageHeapWriter.java   | 102 +++++++-----
     .../hosted/image/ObjectGroupHistogram.java    |   4 +-
     .../svm/hosted/jni/JNIAccessFeature.java      |  13 +-
     .../svm/hosted/meta/HostedInstanceClass.java  |  14 ++
     .../svm/hosted/meta/KnownOffsetsFeature.java  |  13 +-
     .../svm/hosted/meta/UniverseBuilder.java      |  55 +++++--
     16 files changed, 423 insertions(+), 187 deletions(-)
     create mode 100644 substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/config/DynamicHubLayout.java
    
    diff --git a/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/ChunkedImageHeapPartition.java b/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/ChunkedImageHeapPartition.java
    index 1e23506521d0..618537c34054 100644
    --- a/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/ChunkedImageHeapPartition.java
    +++ b/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/ChunkedImageHeapPartition.java
    @@ -38,6 +38,8 @@
     import com.oracle.svm.core.image.ImageHeapObject;
     import com.oracle.svm.core.meta.SubstrateObjectConstant;
     
    +import jdk.graal.compiler.debug.Assertions;
    +
     /**
      * An unstructured image heap partition that just contains a linear sequence of image heap objects.
      */
    @@ -134,7 +136,7 @@ private static NavigableMap> createSortedObjectsMap
             for (ImageHeapObject obj : sorted) {
                 long objSize = obj.getSize();
                 if (objSize != currentObjectsSize) {
    -                assert objSize > currentObjectsSize && objSize >= ConfigurationValues.getObjectLayout().getMinImageHeapObjectSize();
    +                assert objSize > currentObjectsSize && objSize >= ConfigurationValues.getObjectLayout().getMinImageHeapObjectSize() : Assertions.errorMessage(obj, objSize);
                     currentObjectsSize = objSize;
                     currentQueue = new ArrayDeque<>();
                     map.put(currentObjectsSize, currentQueue);
    diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/config/ObjectLayout.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/config/ObjectLayout.java
    index 9165ea1f2bb0..f0c08123dc11 100644
    --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/config/ObjectLayout.java
    +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/config/ObjectLayout.java
    @@ -54,6 +54,9 @@
      * object needs the field, the object is resized during garbage collection to accommodate the
      * field.
      * 
    + * 
    + * See this classes instantiation sites (such as {@code HostedConfiguration#createObjectLayout}) for
    + * more details on the exact object layout for a given configuration.
      */
     public final class ObjectLayout {
     
    diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/hub/DynamicHub.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/hub/DynamicHub.java
    index 3831707a1691..83de69f9fe13 100644
    --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/hub/DynamicHub.java
    +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/hub/DynamicHub.java
    @@ -132,7 +132,10 @@
     import sun.reflect.generics.factory.GenericsFactory;
     import sun.reflect.generics.repository.ClassRepository;
     
    -@Hybrid
    +/**
    + * Instantiations of this class have a special layout. See {@code DynamicHubLayout} for a
    + * description of how the object is arranged.
    + */
     @Substitute
     @TargetClass(java.lang.Class.class)
     @SuppressWarnings({"static-method", "serial"})
    @@ -344,10 +347,10 @@ public final class DynamicHub implements AnnotatedElement, java.lang.reflect.Typ
          * match the assignee's type.
          */
         @UnknownObjectField(availability = AfterHostedUniverse.class)//
    -    @Hybrid.TypeIDSlots private short[] typeCheckSlots;
    +    private short[] typeCheckSlots;
     
         @UnknownObjectField(availability = AfterHostedUniverse.class)//
    -    @Hybrid.Array private CFunctionPointer[] vtable;
    +    private CFunctionPointer[] vtable;
     
         /** Field used for module information access at run-time. */
         private Module module;
    diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/hub/Hybrid.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/hub/Hybrid.java
    index a5d88f74cdd4..663b91862acd 100644
    --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/hub/Hybrid.java
    +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/hub/Hybrid.java
    @@ -29,21 +29,28 @@
     import java.lang.annotation.RetentionPolicy;
     import java.lang.annotation.Target;
     
    +import com.oracle.svm.core.config.ObjectLayout;
    +import com.oracle.svm.core.monitor.MultiThreadedMonitorSupport;
    +
     /**
      * Defines that the annotated class should have a Hybrid layout. Hybrid layouts are hybrids between
      * instance layouts and array layouts. The contents of a specified member array and (optional)
      * member type id slots are directly placed within the class layout. This saves one indirection when
      * accessing the array or type id slots.
    - * 
    + *
    + * 

    + * The location of the identity hashcode is configuration-dependent and will follow the same + * placement convention as an array. The See {@link ObjectLayout} for more information on where the + * identity hash can be placed. @Hybrid objects are treated the same way as instance classes for + * determining whether (and where) they have a monitor slot; See {@link MultiThreadedMonitorSupport} + * for more information on monitor slot placement. + * *

      *    +--------------------------------------------------+
      *    | object header (same header as for arrays)        |
      *    +--------------------------------------------------+
      *    | array length                                     |
      *    +--------------------------------------------------+
    - *    | type id slots (i.e., optional primitive data)    |
    - *    |     ...                                          |
    - *    +--------------------------------------------------+
      *    | instance fields (i.e., primitive or object data) |
      *    |     ...                                          |
      *    +--------------------------------------------------+
    @@ -64,32 +71,7 @@
     public @interface Hybrid {
     
         /**
    -     * The component type of the array part of the hybrid class. Must be specified if no field
    -     * annotated with @{@link Hybrid.Array} is declared, otherwise that field's type determines the
    -     * type of the array part.
    +     * The component type of the array part of the hybrid class.
          */
    -    Class componentType() default void.class;
    -
    -    /**
    -     * If {@code true}, allow the data in the hybrid fields to be duplicated between the hybrid
    -     * object and a separate object for the array. For image heap objects, a duplication can occur
    -     * if inlining and constant folding result in the internal reference to a hybrid field being
    -     * folded to a constant value, which must be written into the image heap separately from the
    -     * hybrid object.
    -     *
    -     * If {@code false}, a duplication of the hybrid fields must never happen.
    -     */
    -    boolean canHybridFieldsBeDuplicated() default false;
    -
    -    /** Designates at most one field that refers to the array part of the hybrid object. */
    -    @Retention(RetentionPolicy.RUNTIME)
    -    @Target(ElementType.FIELD)
    -    @interface Array {
    -    }
    -
    -    /** Designates at most one field that refers to the type ID slots of the hybrid object. */
    -    @Retention(RetentionPolicy.RUNTIME)
    -    @Target(ElementType.FIELD)
    -    @interface TypeIDSlots {
    -    }
    +    Class componentType();
     }
    diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/hub/LayoutEncoding.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/hub/LayoutEncoding.java
    index 5e66f82ff986..1c487d69bdb9 100644
    --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/hub/LayoutEncoding.java
    +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/hub/LayoutEncoding.java
    @@ -139,6 +139,11 @@ public static int forHybrid(ResolvedJavaType type, boolean objectElements, int a
             return forArrayLike(type, true, objectElements, arrayBaseOffset, arrayIndexShift);
         }
     
    +    @Platforms(Platform.HOSTED_ONLY.class)
    +    public static int forDynamicHub(ResolvedJavaType type, int vtableOffset, int vtableIndexShift) {
    +        return forArrayLike(type, true, false, vtableOffset, vtableIndexShift);
    +    }
    +
         @Platforms(Platform.HOSTED_ONLY.class)
         private static int forArrayLike(ResolvedJavaType type, boolean isHybrid, boolean objectElements, int arrayBaseOffset, int arrayIndexShift) {
             assert isHybrid != type.isArray();
    diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/HostedConfiguration.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/HostedConfiguration.java
    index 25eb7f0b7c0e..d454cfe8c104 100644
    --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/HostedConfiguration.java
    +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/HostedConfiguration.java
    @@ -51,11 +51,13 @@
     import com.oracle.svm.core.config.ObjectLayout.IdentityHashMode;
     import com.oracle.svm.core.graal.code.SubstrateMetaAccessExtensionProvider;
     import com.oracle.svm.core.graal.meta.RuntimeConfiguration;
    +import com.oracle.svm.core.hub.DynamicHub;
     import com.oracle.svm.core.monitor.MultiThreadedMonitorSupport;
     import com.oracle.svm.hosted.analysis.Inflation;
     import com.oracle.svm.hosted.analysis.flow.SVMMethodTypeFlowBuilder;
     import com.oracle.svm.hosted.classinitialization.ClassInitializationSupport;
     import com.oracle.svm.hosted.code.CompileQueue;
    +import com.oracle.svm.hosted.config.DynamicHubLayout;
     import com.oracle.svm.hosted.config.HybridLayout;
     import com.oracle.svm.hosted.config.HybridLayoutSupport;
     import com.oracle.svm.hosted.image.LIRNativeImageCodeCache;
    @@ -66,8 +68,10 @@
     import com.oracle.svm.hosted.meta.HostedField;
     import com.oracle.svm.hosted.meta.HostedInstanceClass;
     import com.oracle.svm.hosted.meta.HostedMetaAccess;
    +import com.oracle.svm.hosted.meta.HostedType;
     import com.oracle.svm.hosted.meta.HostedUniverse;
     import com.oracle.svm.hosted.substitute.AnnotationSubstitutionProcessor;
    +import com.oracle.svm.util.ReflectionUtil;
     
     import jdk.graal.compiler.api.replacements.SnippetReflectionProvider;
     import jdk.graal.compiler.core.common.CompressEncoding;
    @@ -162,6 +166,37 @@ public static ObjectLayout createObjectLayout(JavaKind referenceKind, IdentityHa
             return new ObjectLayout(target, referenceSize, objectAlignment, hubOffset, firstFieldOffset, arrayLengthOffset, arrayBaseOffset, headerIdentityHashOffset, identityHashMode);
         }
     
    +    public static void initializeDynamicHubLayout(HostedMetaAccess hMeta) {
    +        ImageSingletons.add(DynamicHubLayout.class, createDynamicHubLayout(hMeta));
    +    }
    +
    +    private static DynamicHubLayout createDynamicHubLayout(HostedMetaAccess hMetaAccess) {
    +        var dynamicHubType = hMetaAccess.lookupJavaType(Class.class);
    +        var typeIDSlotsField = hMetaAccess.lookupJavaField(ReflectionUtil.lookupField(DynamicHub.class, "typeCheckSlots"));
    +        var vtableField = hMetaAccess.lookupJavaField(ReflectionUtil.lookupField(DynamicHub.class, "vtable"));
    +
    +        ObjectLayout layout = ConfigurationValues.getObjectLayout();
    +        int typeIDSlotsOffset = layout.getArrayLengthOffset() + layout.sizeInBytes(JavaKind.Int);
    +        int typeIDSlotsSize = layout.sizeInBytes(typeIDSlotsField.getType().getComponentType().getStorageKind());
    +
    +        JavaKind vTableSlotStorageKind = vtableField.getType().getComponentType().getStorageKind();
    +        int vTableSlotSize = layout.sizeInBytes(vTableSlotStorageKind);
    +
    +        return new DynamicHubLayout(layout, dynamicHubType, typeIDSlotsField, typeIDSlotsOffset, typeIDSlotsSize, vtableField, vTableSlotStorageKind, vTableSlotSize);
    +    }
    +
    +    public static boolean isArrayLikeLayout(HostedType clazz) {
    +        return HybridLayout.isHybrid(clazz) || DynamicHubLayout.singleton().isDynamicHub(clazz);
    +    }
    +
    +    /**
    +     * The hybrid array field and the type fields of the dynamic hub are directly inlined to the
    +     * object to remove a level of indirection.
    +     */
    +    public static boolean isInlinedField(HostedField field) {
    +        return HybridLayout.isHybridField(field) || DynamicHubLayout.singleton().isInlinedField(field);
    +    }
    +
         public SVMHost createHostVM(OptionValues options, ImageClassLoader loader, ClassInitializationSupport classInitializationSupport, AnnotationSubstitutionProcessor annotationSubstitutions) {
             return new SVMHost(options, loader, classInitializationSupport, annotationSubstitutions);
         }
    @@ -191,16 +226,22 @@ public MetaAccessExtensionProvider createCompilationMetaAccessExtensionProvider(
         public void findAllFieldsForLayout(HostedUniverse universe, @SuppressWarnings("unused") HostedMetaAccess metaAccess,
                         @SuppressWarnings("unused") Map universeFields,
                         ArrayList rawFields, ArrayList allFields, HostedInstanceClass clazz) {
    +        DynamicHubLayout dynamicHubLayout = DynamicHubLayout.singleton();
             for (ResolvedJavaField javaField : clazz.getWrapped().getInstanceFields(false)) {
                 AnalysisField aField = (AnalysisField) javaField;
                 HostedField hField = universe.lookup(aField);
     
                 /* Because of @Alias fields, the field lookup might not be declared in our class. */
                 if (hField.getDeclaringClass().equals(clazz)) {
    -                if (HybridLayout.isHybridField(hField)) {
    +                if (dynamicHubLayout.isInlinedField(hField)) {
    +                    /*
    +                     * The typeid slots and the vtable of the dynamic hub are not materialized, so
    +                     * they need no field offset.
    +                     */
    +                    allFields.add(hField);
    +                } else if (HybridLayout.isHybridField(hField)) {
                         /*
    -                     * The array or bitset field of a hybrid is not materialized, so it needs no
    -                     * field offset.
    +                     * The array field of a hybrid is not materialized, so it needs no field offset.
                          */
                         allFields.add(hField);
                     } else if (hField.isAccessed()) {
    diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/config/DynamicHubLayout.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/config/DynamicHubLayout.java
    new file mode 100644
    index 000000000000..5fcc4290d145
    --- /dev/null
    +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/config/DynamicHubLayout.java
    @@ -0,0 +1,147 @@
    +/*
    + * Copyright (c) 2023, 2023, Oracle and/or its affiliates. All rights reserved.
    + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
    + *
    + * This code is free software; you can redistribute it and/or modify it
    + * under the terms of the GNU General Public License version 2 only, as
    + * published by the Free Software Foundation.  Oracle designates this
    + * particular file as subject to the "Classpath" exception as provided
    + * by Oracle in the LICENSE file that accompanied this code.
    + *
    + * This code is distributed in the hope that it will be useful, but WITHOUT
    + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
    + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
    + * version 2 for more details (a copy is included in the LICENSE file that
    + * accompanied this code).
    + *
    + * You should have received a copy of the GNU General Public License version
    + * 2 along with this work; if not, write to the Free Software Foundation,
    + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
    + *
    + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
    + * or visit www.oracle.com if you need additional information or have any
    + * questions.
    + */
    +package com.oracle.svm.hosted.config;
    +
    +import org.graalvm.nativeimage.ImageSingletons;
    +
    +import com.oracle.svm.core.config.ObjectLayout;
    +import com.oracle.svm.core.hub.DynamicHub;
    +import com.oracle.svm.core.hub.HubType;
    +import com.oracle.svm.core.hub.Hybrid;
    +import com.oracle.svm.core.hub.LayoutEncoding;
    +import com.oracle.svm.core.monitor.MultiThreadedMonitorSupport;
    +import com.oracle.svm.hosted.meta.HostedField;
    +import com.oracle.svm.hosted.meta.HostedInstanceClass;
    +import com.oracle.svm.hosted.meta.HostedType;
    +
    +import jdk.graal.compiler.core.common.NumUtil;
    +import jdk.vm.ci.meta.JavaKind;
    +
    +/**
    + * Provides sizes and offsets of the {@link DynamicHub} class. Like {@link Hybrid} layouts,
    + * DynamicHubs contain both instance fields and a variable length array to hold the virtual dispatch
    + * table. In addition, to save a level of indirection, there is a fixed-length typeid slot directly
    + * placed within the dynamic hub.
    + *
    + * 

    + * The location of the identity hashcode is configuration-dependent and will follow the same + * placement convention as an array. See {@link ObjectLayout} for more information on where the + * identity hash can be placed. DynamicHubs never have a monitor slot; See + * {@link MultiThreadedMonitorSupport} for more information. + * + *

    + *    +--------------------------------------------------+
    + *    | object header (same header as for arrays)        |
    + *    +--------------------------------------------------+
    + *    | vtable length                                    |
    + *    +--------------------------------------------------+
    + *    | type id slots (i.e., primitive data)             |
    + *    |     ...                                          |
    + *    +--------------------------------------------------+
    + *    | instance fields (i.e., primitive or object data) |
    + *    |     ...                                          |
    + *    +--------------------------------------------------+
    + *    | vtable dispatch addresses (i.e., primitive data) |
    + *    |     ...                                          |
    + *    +--------------------------------------------------+
    + * 
    + * + *

    + * Like {@link Hybrid}, DynamicHub objects have an instance {@link HubType}, but a + * {@link LayoutEncoding} like an array. See the javadoc for {@link Hybrid} more details its + * implications. + */ +public class DynamicHubLayout { + + private final ObjectLayout layout; + private final HostedInstanceClass dynamicHubType; + public final HostedField typeIDSlotsField; + public final int typeIDSlotsOffset; + public final int typeIDSlotsSize; + public final HostedField vTableField; + public final int vTableSlotSize; + public final JavaKind vTableSlotStorageKind; + + /* + * This is calculated lazily, as it requires the dynamicHub's instance fields to be finalized + * before being calculated. + */ + private int vTableOffset; + + public DynamicHubLayout(ObjectLayout layout, HostedType dynamicHubType, HostedField typeIDSlotsField, int typeIDSlotsOffset, int typeIDSlotsSize, HostedField vTableField, + JavaKind vTableSlotStorageKind, int vTableSlotSize) { + this.layout = layout; + this.dynamicHubType = (HostedInstanceClass) dynamicHubType; + this.typeIDSlotsField = typeIDSlotsField; + this.typeIDSlotsOffset = typeIDSlotsOffset; + this.typeIDSlotsSize = typeIDSlotsSize; + this.vTableField = vTableField; + this.vTableSlotStorageKind = vTableSlotStorageKind; + this.vTableSlotSize = vTableSlotSize; + } + + public static DynamicHubLayout singleton() { + return ImageSingletons.lookup(DynamicHubLayout.class); + } + + public JavaKind getVTableSlotStorageKind() { + return vTableSlotStorageKind; + } + + public boolean isDynamicHub(HostedType type) { + return type.equals(dynamicHubType); + } + + public boolean isInlinedField(HostedField field) { + return field.equals(typeIDSlotsField) || field.equals(vTableField); + } + + public int getVTableSlotOffset(int index) { + return vTableOffset() + index * vTableSlotSize; + } + + public int getTypeIDSlotsOffset(int index) { + return typeIDSlotsOffset + index * typeIDSlotsSize; + } + + public int getVTableLengthOffset() { + return layout.getArrayLengthOffset(); + } + + public int vTableOffset() { + if (vTableOffset == 0) { + vTableOffset = NumUtil.roundUp(dynamicHubType.getAfterFieldsOffset(), vTableSlotSize); + } + return vTableOffset; + } + + public long getTotalSize(int vtableLength) { + return layout.computeArrayTotalSize(getVTableSlotOffset(vtableLength), true); + } + + public long getIdentityHashOffset(int vTableLength) { + return layout.getArrayIdentityHashOffset(getVTableSlotOffset(vTableLength)); + } +} diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/config/HybridLayout.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/config/HybridLayout.java index d02d446b5c86..0dd90378af74 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/config/HybridLayout.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/config/HybridLayout.java @@ -28,7 +28,6 @@ import com.oracle.svm.core.hub.Hybrid; import com.oracle.svm.hosted.meta.HostedField; import com.oracle.svm.hosted.meta.HostedInstanceClass; -import com.oracle.svm.hosted.meta.HostedMetaAccess; import com.oracle.svm.hosted.meta.HostedType; import jdk.graal.compiler.core.common.NumUtil; @@ -41,7 +40,7 @@ * * @see Hybrid */ -public class HybridLayout { +public class HybridLayout { public static boolean isHybrid(ResolvedJavaType clazz) { return HybridLayoutSupport.singleton().isHybrid(clazz); @@ -51,10 +50,16 @@ public static boolean isHybridField(HostedField field) { return HybridLayoutSupport.singleton().isHybridField(field); } + /** + * See {@link HybridLayoutSupport#canHybridFieldsBeDuplicated(HostedType)} for explanation. + */ public static boolean canHybridFieldsBeDuplicated(HostedType clazz) { return HybridLayoutSupport.singleton().canHybridFieldsBeDuplicated(clazz); } + /** + * See {@link HybridLayoutSupport#canInstantiateAsInstance(HostedType)} for explanation. + */ public static boolean canInstantiateAsInstance(HostedType clazz) { return HybridLayoutSupport.singleton().canInstantiateAsInstance(clazz); } @@ -62,20 +67,14 @@ public static boolean canInstantiateAsInstance(HostedType clazz) { private final ObjectLayout layout; private final HostedType arrayComponentType; private final HostedField arrayField; - private final HostedField typeIDSlotsField; private final int arrayBaseOffset; - public HybridLayout(Class hybridClass, ObjectLayout layout, HostedMetaAccess metaAccess) { - this((HostedInstanceClass) metaAccess.lookupJavaType(hybridClass), layout, metaAccess); - } - @SuppressWarnings("this-escape") public HybridLayout(HostedInstanceClass hybridClass, ObjectLayout layout, MetaAccessProvider metaAccess) { this.layout = layout; HybridLayoutSupport.HybridInfo hybridInfo = HybridLayoutSupport.singleton().inspectHybrid(hybridClass, metaAccess); this.arrayComponentType = hybridInfo.arrayComponentType; this.arrayField = hybridInfo.arrayField; - this.typeIDSlotsField = hybridInfo.typeIDSlotsField; this.arrayBaseOffset = NumUtil.roundUp(hybridClass.getAfterFieldsOffset(), layout.sizeInBytes(getArrayElementStorageKind())); } @@ -106,12 +105,4 @@ public long getIdentityHashOffset(int length) { public HostedField getArrayField() { return arrayField; } - - public HostedField getTypeIDSlotsField() { - return typeIDSlotsField; - } - - public static int getTypeIDSlotsFieldOffset(ObjectLayout layout) { - return layout.getArrayLengthOffset() + layout.sizeInBytes(JavaKind.Int); - } } diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/config/HybridLayoutSupport.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/config/HybridLayoutSupport.java index c03cbe544ef5..ffd5a89a1413 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/config/HybridLayoutSupport.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/config/HybridLayoutSupport.java @@ -26,7 +26,6 @@ import java.lang.reflect.Modifier; -import jdk.graal.compiler.api.replacements.Fold; import org.graalvm.nativeimage.ImageSingletons; import com.oracle.svm.core.hub.Hybrid; @@ -34,6 +33,7 @@ import com.oracle.svm.hosted.meta.HostedInstanceClass; import com.oracle.svm.hosted.meta.HostedType; +import jdk.graal.compiler.api.replacements.Fold; import jdk.vm.ci.meta.MetaAccessProvider; import jdk.vm.ci.meta.ResolvedJavaType; @@ -48,12 +48,21 @@ public boolean isHybrid(ResolvedJavaType clazz) { } public boolean isHybridField(HostedField field) { - return field.getAnnotation(Hybrid.Array.class) != null || field.getAnnotation(Hybrid.TypeIDSlots.class) != null; + return false; } + /** + * If {@code true}, allow the data in the hybrid fields to be duplicated between the hybrid + * object and a separate object for the array. For image heap objects, a duplication can occur + * if inlining and constant folding result in the internal reference to a hybrid field being + * folded to a constant value, which must be written into the image heap separately from the + * hybrid object. + * + * If {@code false}, a duplication of the hybrid fields must never happen. + */ public boolean canHybridFieldsBeDuplicated(HostedType clazz) { assert isHybrid(clazz) : "Can only be called on hybrid types"; - return clazz.getAnnotation(Hybrid.class).canHybridFieldsBeDuplicated(); + return false; } public boolean canInstantiateAsInstance(HostedType clazz) { @@ -63,47 +72,20 @@ public boolean canInstantiateAsInstance(HostedType clazz) { /** Determines characteristics of a hybrid class. */ protected HybridInfo inspectHybrid(HostedInstanceClass hybridClass, MetaAccessProvider metaAccess) { - Hybrid annotation = hybridClass.getAnnotation(Hybrid.class); - assert annotation != null; - assert Modifier.isFinal(hybridClass.getModifiers()); + assert Modifier.isFinal(hybridClass.getModifiers()) : "Hybrid class must be final " + hybridClass; - HostedField foundArrayField = null; - HostedField foundTypeIDSlotsField = null; - for (HostedField field : hybridClass.getInstanceFields(true)) { - if (field.getAnnotation(Hybrid.Array.class) != null) { - assert foundArrayField == null : "must have at most one hybrid array field"; - foundArrayField = field; - } - if (field.getAnnotation(Hybrid.TypeIDSlots.class) != null) { - assert foundTypeIDSlotsField == null : "must have at most one typeid slot field"; - assert field.getType().isArray(); - foundTypeIDSlotsField = field; - } - } - - HostedType arrayComponentType; - boolean arrayTypeIsSet = (annotation.componentType() != void.class); - if (foundArrayField != null) { - arrayComponentType = foundArrayField.getType().getComponentType(); - - assert !arrayTypeIsSet || arrayComponentType.equals(metaAccess.lookupJavaType(annotation.componentType())) : // - "@Hybrid.componentType must match the type of a @Hybrid.Array field when both are present"; - } else { - assert arrayTypeIsSet : "@Hybrid.componentType must be set when no @Hybrid.Array field is present (if present, ensure it is reachable)"; - arrayComponentType = (HostedType) metaAccess.lookupJavaType(annotation.componentType()); - } - return new HybridInfo(arrayComponentType, foundArrayField, foundTypeIDSlotsField); + Class componentType = hybridClass.getAnnotation(Hybrid.class).componentType(); + assert componentType != void.class : "@Hybrid.componentType cannot be void"; + return new HybridInfo((HostedType) metaAccess.lookupJavaType(componentType), null); } public static class HybridInfo { public final HostedType arrayComponentType; public final HostedField arrayField; - public final HostedField typeIDSlotsField; - public HybridInfo(HostedType arrayComponentType, HostedField arrayField, HostedField typeIDSlotsField) { + public HybridInfo(HostedType arrayComponentType, HostedField arrayField) { this.arrayComponentType = arrayComponentType; this.arrayField = arrayField; - this.typeIDSlotsField = typeIDSlotsField; } } } diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/NativeImageHeap.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/NativeImageHeap.java index 3e96712d3c08..dfdeb0a694f1 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/NativeImageHeap.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/NativeImageHeap.java @@ -36,6 +36,7 @@ import java.util.HashMap; import java.util.IdentityHashMap; import java.util.LinkedHashSet; +import java.util.List; import java.util.Map; import java.util.Optional; import java.util.Set; @@ -70,7 +71,9 @@ import com.oracle.svm.core.util.HostedStringDeduplication; import com.oracle.svm.core.util.UserError; import com.oracle.svm.core.util.VMError; +import com.oracle.svm.hosted.HostedConfiguration; import com.oracle.svm.hosted.ameta.AnalysisConstantReflectionProvider; +import com.oracle.svm.hosted.config.DynamicHubLayout; import com.oracle.svm.hosted.config.HybridLayout; import com.oracle.svm.hosted.meta.HostedArrayClass; import com.oracle.svm.hosted.meta.HostedClass; @@ -103,6 +106,7 @@ public final class NativeImageHeap implements ImageHeap { public final HostedMetaAccess hMetaAccess; public final HostedConstantReflectionProvider hConstantReflection; public final ObjectLayout objectLayout; + public final DynamicHubLayout dynamicHubLayout; private final ImageHeapLayouter heapLayouter; private final int minInstanceSize; @@ -122,7 +126,7 @@ public final class NativeImageHeap implements ImageHeap { private final Set blacklist = Collections.newSetFromMap(new IdentityHashMap<>()); /** A map from hosted classes to classes that have hybrid layouts in the native image heap. */ - private final Map> hybridLayouts = new HashMap<>(); + private final Map hybridLayouts = new HashMap<>(); /** A Map to build what will be the String intern map in the native image heap. */ private final Map internedStrings = new HashMap<>(); @@ -153,6 +157,8 @@ public NativeImageHeap(AnalysisUniverse aUniverse, HostedUniverse hUniverse, Hos this.minArraySize = objectLayout.getMinImageHeapArraySize(); assert assertFillerObjectSizes(); + dynamicHubLayout = DynamicHubLayout.singleton(); + if (ImageHeapConnectedComponentsFeature.Options.PrintImageHeapConnectedComponents.getValue()) { this.objectReachabilityInfo = new IdentityHashMap<>(); } @@ -178,7 +184,7 @@ public ObjectInfo getConstantInfo(JavaConstant constant) { return objects.get(CompressibleConstant.uncompress(constant)); } - protected HybridLayout getHybridLayout(HostedClass clazz) { + protected HybridLayout getHybridLayout(HostedClass clazz) { return hybridLayouts.get(clazz); } @@ -248,11 +254,11 @@ public void addTrailingObjects() { } /** - * Bypass shadow heap reading for hybrid fields. These fields are not actually present in the - * image, their value is inlined, and are not present in the shadow heap either. + * Bypass shadow heap reading for inlined fields. These fields are not actually present in the + * image (their value is inlined) and are not present in the shadow heap either. */ - Object readHybridField(HostedField field, JavaConstant receiver) { - VMError.guarantee(HybridLayout.isHybridField(field), "Expected a hybrid field, found %s", field); + Object readInlinedField(HostedField field, JavaConstant receiver) { + VMError.guarantee(HostedConfiguration.isInlinedField(field), "Expected an inlined field, found %s", field); JavaConstant hostedReceiver = ((ImageHeapInstance) receiver).getHostedObject(); /* Use the AnalysisConstantReflectionProvider to get direct access to hosted values. */ AnalysisConstantReflectionProvider analysisConstantReflection = hConstantReflection.getWrappedConstantReflection(); @@ -458,35 +464,44 @@ private void addObjectToImageHeap(final JavaConstant constant, boolean immutable // also not immutable: users of registerAsImmutable() must take precautions } - HostedField hybridTypeIDSlotsField = null; - HostedField hybridArrayField = null; - Object hybridArray = null; + List ignoredFields; + Object hybridArray; final long size; - if (HybridLayout.isHybrid(clazz)) { - HybridLayout hybridLayout = hybridLayouts.get(clazz); + if (dynamicHubLayout.isDynamicHub(clazz)) { + /* + * DynamicHubs' typeIdSlots and vTable fields are written within the object. They + * can never be duplicated, i.e. written as a separate object. We use the blacklist + * to check this. + */ + Object typeIDSlots = readInlinedField(dynamicHubLayout.typeIDSlotsField, constant); + assert typeIDSlots != null : "Cannot read value for field " + dynamicHubLayout.typeIDSlotsField.format("%H.%n"); + blacklist.add(typeIDSlots); + + Object vTable = readInlinedField(dynamicHubLayout.vTableField, constant); + hybridArray = vTable; + assert vTable != null : "Cannot read value for field " + dynamicHubLayout.vTableField.format("%H.%n"); + blacklist.add(vTable); + + size = dynamicHubLayout.getTotalSize(Array.getLength(vTable)); + ignoredFields = List.of(dynamicHubLayout.typeIDSlotsField, dynamicHubLayout.vTableField); + + } else if (HybridLayout.isHybrid(clazz)) { + HybridLayout hybridLayout = hybridLayouts.get(clazz); if (hybridLayout == null) { - hybridLayout = new HybridLayout<>(clazz, objectLayout, hMetaAccess); + hybridLayout = new HybridLayout(clazz, objectLayout, hMetaAccess); hybridLayouts.put(clazz, hybridLayout); } /* - * The hybrid array, bit set, and typeID array are written within the hybrid object. - * If the hybrid object declares that they can never be duplicated, i.e. written as - * a separate object, we ensure that they never are duplicated. We use the blacklist - * to check that. + * The hybrid array is written within the hybrid object. If the hybrid object + * declares that they can never be duplicated, i.e. written as a separate object, we + * ensure that they are never duplicated. We use the blacklist to check that. */ boolean shouldBlacklist = !HybridLayout.canHybridFieldsBeDuplicated(clazz); - hybridTypeIDSlotsField = hybridLayout.getTypeIDSlotsField(); - if (hybridTypeIDSlotsField != null && shouldBlacklist) { - Object typeIDSlots = readHybridField(hybridTypeIDSlotsField, constant); - if (typeIDSlots != null) { - blacklist.add(typeIDSlots); - } - } - - hybridArrayField = hybridLayout.getArrayField(); - hybridArray = readHybridField(hybridArrayField, constant); + HostedField hybridArrayField = hybridLayout.getArrayField(); + hybridArray = readInlinedField(hybridArrayField, constant); + ignoredFields = List.of(hybridArrayField); if (hybridArray != null && shouldBlacklist) { blacklist.add(hybridArray); written = true; @@ -495,6 +510,8 @@ private void addObjectToImageHeap(final JavaConstant constant, boolean immutable assert hybridArray != null : "Cannot read value for field " + hybridArrayField.format("%H.%n"); size = hybridLayout.getTotalSize(Array.getLength(hybridArray), true); } else { + ignoredFields = List.of(); + hybridArray = null; size = LayoutEncoding.getPureInstanceSize(hub, true).rawValue(); } @@ -510,9 +527,7 @@ private void addObjectToImageHeap(final JavaConstant constant, boolean immutable * StringInternSupport.imageInternedStrings and all ImageHeapInfo fields will * not be processed. */ - if (field.isRead() && field.isValueAvailable() && - !field.equals(hybridArrayField) && - !field.equals(hybridTypeIDSlotsField)) { + if (field.isRead() && field.isValueAvailable() && !ignoredFields.contains(field)) { if (field.getJavaKind() == JavaKind.Object) { assert field.hasLocation(); JavaConstant fieldValueConstant = hConstantReflection.readFieldValue(field, constant); @@ -656,7 +671,7 @@ public ObjectInfo addLateToImageHeap(Object object, Object reason) { private long getSize(Object object, HostedType type) { if (type.isInstanceClass()) { HostedInstanceClass clazz = (HostedInstanceClass) type; - assert !HybridLayout.isHybrid(clazz); + assert !HostedConfiguration.isArrayLikeLayout(clazz) : type; return LayoutEncoding.getPureInstanceSize(clazz.getHub(), true).rawValue(); } else if (type.isArray()) { return objectLayout.getArraySize(type.getComponentType().getStorageKind(), Array.getLength(object), true); diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/NativeImageHeapWriter.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/NativeImageHeapWriter.java index 87a5078b4791..aa9fdc11e037 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/NativeImageHeapWriter.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/NativeImageHeapWriter.java @@ -30,6 +30,8 @@ import java.lang.reflect.Array; import java.lang.reflect.Modifier; import java.nio.ByteBuffer; +import java.util.Arrays; +import java.util.stream.Stream; import org.graalvm.nativeimage.ImageSingletons; import org.graalvm.nativeimage.c.function.CFunctionPointer; @@ -52,6 +54,7 @@ import com.oracle.svm.core.meta.MethodPointer; import com.oracle.svm.core.meta.SubstrateObjectConstant; import com.oracle.svm.hosted.code.CEntryPointLiteralFeature; +import com.oracle.svm.hosted.config.DynamicHubLayout; import com.oracle.svm.hosted.config.HybridLayout; import com.oracle.svm.hosted.image.NativeImageHeap.ObjectInfo; import com.oracle.svm.hosted.meta.HostedClass; @@ -63,6 +66,7 @@ import jdk.graal.compiler.api.replacements.SnippetReflectionProvider; import jdk.graal.compiler.core.common.CompressEncoding; import jdk.graal.compiler.core.common.NumUtil; +import jdk.graal.compiler.debug.Assertions; import jdk.graal.compiler.debug.DebugContext; import jdk.graal.compiler.debug.Indent; import jdk.internal.misc.Unsafe; @@ -321,6 +325,7 @@ private void writeObject(ObjectInfo info, RelocatableBuffer buffer) { * the object base. */ ObjectLayout objectLayout = heap.objectLayout; + DynamicHubLayout dynamicHubLayout = heap.dynamicHubLayout; final int indexInBuffer = info.getIndexInBuffer(objectLayout.getHubOffset()); assert objectLayout.isAligned(indexInBuffer); @@ -329,53 +334,52 @@ private void writeObject(ObjectInfo info, RelocatableBuffer buffer) { ByteBuffer bufferBytes = buffer.getByteBuffer(); HostedClass clazz = info.getClazz(); if (clazz.isInstanceClass()) { + /* + * We always write the instance fields and identity hashcode + * + * If the object is a hybrid object, then also the array length and elements will be + * written. + * + * If the object is a dynamic hub, then the typeID and vTable (& length) slots will be + * written. + */ JavaConstant con = info.getConstant(); - HybridLayout hybridLayout = heap.getHybridLayout(clazz); - HostedField hybridArrayField = null; - HostedField hybridTypeIDSlotsField = null; - int maxBitIndex = -1; - int maxTypeIDSlotIndex = -1; - Object hybridArray = null; - if (hybridLayout != null) { - hybridArrayField = hybridLayout.getArrayField(); - hybridArray = heap.readHybridField(hybridArrayField, con); - - hybridTypeIDSlotsField = hybridLayout.getTypeIDSlotsField(); - if (hybridTypeIDSlotsField != null) { - short[] typeIDSlots = (short[]) heap.readHybridField(hybridTypeIDSlotsField, con); - if (typeIDSlots != null) { - int length = typeIDSlots.length; - for (int i = 0; i < length; i++) { - final int index = info.getIndexInBuffer(HybridLayout.getTypeIDSlotsFieldOffset(objectLayout)) + (i * 2); - if (index + 1 > maxTypeIDSlotIndex) { - maxTypeIDSlotIndex = index + 1; // Takes two bytes... - } - short value = typeIDSlots[i]; - bufferBytes.putShort(index, value); - } - } + HostedInstanceClass instanceClazz = (HostedInstanceClass) clazz; + long idHashOffset; + Stream instanceFields = Arrays.stream(clazz.getInstanceFields(true)).filter(HostedField::isRead); + + if (dynamicHubLayout.isDynamicHub(clazz)) { + /* Write typeID slots. */ + short[] typeIDSlots = (short[]) heap.readInlinedField(dynamicHubLayout.typeIDSlotsField, con); + int typeIDSlotsLength = typeIDSlots.length; + for (int i = 0; i < typeIDSlotsLength; i++) { + int index = info.getIndexInBuffer(dynamicHubLayout.getTypeIDSlotsOffset(i)); + short value = typeIDSlots[i]; + bufferBytes.putShort(index, value); } - } - /* - * Write the regular instance fields. - */ - for (HostedField field : clazz.getInstanceFields(true)) { - if (!field.equals(hybridArrayField) && - !field.equals(hybridTypeIDSlotsField) && - field.isRead()) { - assert field.getLocation() >= 0; - assert info.getIndexInBuffer(field.getLocation()) > maxBitIndex; - assert info.getIndexInBuffer(field.getLocation()) > maxTypeIDSlotIndex; - writeField(buffer, info, field, con, info); + /* Write vtable slots and length. */ + Object vTable = heap.readInlinedField(dynamicHubLayout.vTableField, con); + int vtableLength = Array.getLength(vTable); + bufferBytes.putInt(info.getIndexInBuffer(dynamicHubLayout.getVTableLengthOffset()), vtableLength); + final JavaKind elementStorageKind = dynamicHubLayout.getVTableSlotStorageKind(); + for (int i = 0; i < vtableLength; i++) { + Object vtableSlot = Array.get(vTable, i); + int elementIndex = info.getIndexInBuffer(dynamicHubLayout.getVTableSlotOffset(i)); + writeConstant(buffer, elementIndex, elementStorageKind, vtableSlot, info); } - } - long idHashOffset; - if (hybridArray != null) { + + idHashOffset = dynamicHubLayout.getIdentityHashOffset(vtableLength); + instanceFields = instanceFields.filter(field -> !dynamicHubLayout.isInlinedField(field)); + + } else if (heap.getHybridLayout(clazz) != null) { + HybridLayout hybridLayout = heap.getHybridLayout(clazz); /* - * Write the hybrid array length and the array elements. + * write array and its length */ + HostedField hybridArrayField = hybridLayout.getArrayField(); + Object hybridArray = heap.readInlinedField(hybridArrayField, con); int length = Array.getLength(hybridArray); bufferBytes.putInt(info.getIndexInBuffer(objectLayout.getArrayLengthOffset()), length); for (int i = 0; i < length; i++) { @@ -384,10 +388,26 @@ private void writeObject(ObjectInfo info, RelocatableBuffer buffer) { final Object array = Array.get(hybridArray, i); writeConstant(buffer, elementIndex, elementStorageKind, array, info); } + idHashOffset = hybridLayout.getIdentityHashOffset(length); + instanceFields = instanceFields.filter(field -> !field.equals(hybridArrayField)); } else { - idHashOffset = ((HostedInstanceClass) clazz).getIdentityHashOffset(); + + idHashOffset = instanceClazz.getIdentityHashOffset(); } + + /* + * Write the "regular" instance fields. + */ + instanceFields.forEach(field -> { + assert (field.getLocation() >= 0) && + (field.getLocation() >= instanceClazz.getFirstInstanceFieldOffset()) && + (field.getLocation() < instanceClazz.getAfterFieldsOffset()) : Assertions.errorMessage(field, + instanceClazz.getFirstInstanceFieldOffset(), instanceClazz.getAfterFieldsOffset()); + writeField(buffer, info, field, con, info); + }); + + /* Write the identity hashcode */ assert idHashOffset > 0; bufferBytes.putInt(info.getIndexInBuffer(idHashOffset), info.getIdentityHashCode()); diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/ObjectGroupHistogram.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/ObjectGroupHistogram.java index cd496fe6cd05..0265c56d6667 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/ObjectGroupHistogram.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/ObjectGroupHistogram.java @@ -36,7 +36,7 @@ import com.oracle.svm.core.hub.DynamicHub; import com.oracle.svm.core.hub.DynamicHubSupport; import com.oracle.svm.core.meta.SubstrateObjectConstant; -import com.oracle.svm.hosted.config.HybridLayout; +import com.oracle.svm.hosted.HostedConfiguration; import com.oracle.svm.hosted.image.NativeImageHeap.ObjectInfo; import com.oracle.svm.hosted.meta.HostedField; import com.oracle.svm.util.LogUtils; @@ -180,7 +180,7 @@ private void processObject(ObjectInfo info, String group, boolean addObject, int if (info.getClazz().isInstanceClass()) { JavaConstant con = heap.hUniverse.getSnippetReflection().forObject(info.getObject()); for (HostedField field : info.getClazz().getInstanceFields(true)) { - if (field.getType().getStorageKind() == JavaKind.Object && !HybridLayout.isHybridField(field) && field.isAccessed()) { + if (field.getType().getStorageKind() == JavaKind.Object && !HostedConfiguration.isInlinedField(field) && field.isAccessed()) { if (fieldFilter == null || fieldFilter.test(info, field)) { JavaConstant fieldValue = heap.hConstantReflection.readFieldValue(field, con); if (fieldValue.isNonNull()) { diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/jni/JNIAccessFeature.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/jni/JNIAccessFeature.java index b09b2e537aa3..d2ad28b3825e 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/jni/JNIAccessFeature.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/jni/JNIAccessFeature.java @@ -75,6 +75,7 @@ import com.oracle.svm.core.meta.MethodPointer; import com.oracle.svm.core.option.HostedOptionKey; import com.oracle.svm.core.util.UserError; +import com.oracle.svm.core.util.VMError; import com.oracle.svm.hosted.ConditionalConfigurationRegistry; import com.oracle.svm.hosted.FallbackFeature; import com.oracle.svm.hosted.FeatureImpl.AfterRegistrationAccessImpl; @@ -85,6 +86,7 @@ import com.oracle.svm.hosted.code.CEntryPointData; import com.oracle.svm.hosted.code.FactoryMethodSupport; import com.oracle.svm.hosted.config.ConfigurationParserUtils; +import com.oracle.svm.hosted.config.DynamicHubLayout; import com.oracle.svm.hosted.config.HybridLayout; import com.oracle.svm.hosted.meta.HostedField; import com.oracle.svm.hosted.meta.HostedInstanceClass; @@ -474,11 +476,12 @@ public void beforeCompilation(BeforeCompilationAccess a) { } CompilationAccessImpl access = (CompilationAccessImpl) a; + DynamicHubLayout dynamicHubLayout = DynamicHubLayout.singleton(); for (JNIAccessibleClass clazz : JNIReflectionDictionary.singleton().getClasses()) { UnmodifiableMapCursor cursor = clazz.getFields(); while (cursor.advance()) { String name = (String) cursor.getKey(); - finishFieldBeforeCompilation(name, cursor.getValue(), access); + finishFieldBeforeCompilation(name, cursor.getValue(), access, dynamicHubLayout); } } for (JNICallableJavaMethod method : calledJavaMethods) { @@ -588,15 +591,17 @@ private static EconomicSet> findHidingSubclasses0(HostedType type, Pred return map; } - private static void finishFieldBeforeCompilation(String name, JNIAccessibleField field, CompilationAccessImpl access) { + private static void finishFieldBeforeCompilation(String name, JNIAccessibleField field, CompilationAccessImpl access, DynamicHubLayout dynamicHubLayout) { try { Class declaringClass = field.getDeclaringClass().getClassObject(); Field reflField = declaringClass.getDeclaredField(name); HostedField hField = access.getMetaAccess().lookupJavaField(reflField); int offset; - if (HybridLayout.isHybridField(hField)) { + if (dynamicHubLayout.isInlinedField(hField)) { + throw VMError.shouldNotReachHere("DynamicHub inlined fields are not accessible %s", hField); + } else if (HybridLayout.isHybridField(hField)) { assert !hField.hasLocation(); - HybridLayout hybridLayout = new HybridLayout<>((HostedInstanceClass) hField.getDeclaringClass(), + HybridLayout hybridLayout = new HybridLayout((HostedInstanceClass) hField.getDeclaringClass(), ImageSingletons.lookup(ObjectLayout.class), access.getMetaAccess()); assert hField.equals(hybridLayout.getArrayField()) : "JNI access to hybrid objects is implemented only for the array field"; offset = hybridLayout.getArrayBaseOffset(); diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/meta/HostedInstanceClass.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/meta/HostedInstanceClass.java index 2fe8f881b665..86ae80063d48 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/meta/HostedInstanceClass.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/meta/HostedInstanceClass.java @@ -33,6 +33,7 @@ public class HostedInstanceClass extends HostedClass { protected HostedField[] instanceFieldsWithoutSuper; protected HostedField[] instanceFieldsWithSuper; + protected int firstInstanceFieldOffset; protected int afterFieldsOffset; protected int instanceSize; protected boolean monitorFieldNeeded = false; @@ -86,7 +87,20 @@ public ResolvedJavaField findInstanceFieldWithOffset(long offset, JavaKind expec return null; } + public int getFirstInstanceFieldOffset() { + /* + * Each object has at least a header, so the firstInstanceFieldOffset should always be + * positive. + */ + assert firstInstanceFieldOffset > 0 : "Invalid offset " + firstInstanceFieldOffset + " class: " + getName(); + return firstInstanceFieldOffset; + } + public int getAfterFieldsOffset() { + /* + * Each object has at least a header, so the afterFieldsOffset should always be positive. + */ + assert afterFieldsOffset > 0 : "Invalid offset " + afterFieldsOffset + " class: " + getName(); return afterFieldsOffset; } diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/meta/KnownOffsetsFeature.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/meta/KnownOffsetsFeature.java index fe6287a0a1c7..a0c1afe3eeab 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/meta/KnownOffsetsFeature.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/meta/KnownOffsetsFeature.java @@ -33,17 +33,16 @@ import com.oracle.svm.core.SubstrateOptions; import com.oracle.svm.core.code.ImageCodeInfo; -import com.oracle.svm.core.config.ConfigurationValues; +import com.oracle.svm.core.feature.AutomaticallyRegisteredFeature; import com.oracle.svm.core.feature.InternalFeature; import com.oracle.svm.core.graal.meta.KnownOffsets; import com.oracle.svm.core.hub.DynamicHub; import com.oracle.svm.core.stack.JavaFrameAnchor; import com.oracle.svm.core.thread.VMThreads; -import com.oracle.svm.core.feature.AutomaticallyRegisteredFeature; import com.oracle.svm.hosted.FeatureImpl.BeforeCompilationAccessImpl; import com.oracle.svm.hosted.c.info.AccessorInfo; import com.oracle.svm.hosted.c.info.StructFieldInfo; -import com.oracle.svm.hosted.config.HybridLayout; +import com.oracle.svm.hosted.config.DynamicHubLayout; import com.oracle.svm.hosted.thread.VMThreadMTFeature; import com.oracle.svm.util.ReflectionUtil; @@ -68,10 +67,10 @@ public void afterRegistration(AfterRegistrationAccess access) { public void beforeCompilation(BeforeCompilationAccess a) { BeforeCompilationAccessImpl access = (BeforeCompilationAccessImpl) a; - HybridLayout hubLayout = new HybridLayout<>(DynamicHub.class, ConfigurationValues.getObjectLayout(), access.getMetaAccess()); - int vtableBaseOffset = hubLayout.getArrayBaseOffset(); - int vtableEntrySize = ConfigurationValues.getObjectLayout().sizeInBytes(hubLayout.getArrayElementStorageKind()); - int typeIDSlotsOffset = HybridLayout.getTypeIDSlotsFieldOffset(ConfigurationValues.getObjectLayout()); + DynamicHubLayout dynamicHubLayout = DynamicHubLayout.singleton(); + int vtableBaseOffset = dynamicHubLayout.vTableOffset(); + int vtableEntrySize = dynamicHubLayout.vTableSlotSize; + int typeIDSlotsOffset = dynamicHubLayout.typeIDSlotsOffset; int componentHubOffset = findFieldOffset(access, DynamicHub.class, "componentType"); diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/meta/UniverseBuilder.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/meta/UniverseBuilder.java index 1ceab52617d5..bc2ee0cc9ad7 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/meta/UniverseBuilder.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/meta/UniverseBuilder.java @@ -93,6 +93,7 @@ import com.oracle.svm.hosted.NativeImageOptions; import com.oracle.svm.hosted.ameta.FieldValueInterceptionSupport; import com.oracle.svm.hosted.annotation.CustomSubstitutionMethod; +import com.oracle.svm.hosted.config.DynamicHubLayout; import com.oracle.svm.hosted.config.HybridLayout; import com.oracle.svm.hosted.heap.PodSupport; import com.oracle.svm.hosted.substitute.AnnotationSubstitutionProcessor; @@ -173,6 +174,8 @@ public void build(DebugContext debug) { assert previous == null : "Overwriting analysis key"; } + HostedConfiguration.initializeDynamicHubLayout(hMetaAccess); + Collection allTypes = hUniverse.types.values(); HostedType objectType = hUniverse.objectType(); HostedType cloneableType = hUniverse.types.get(aMetaAccess.lookupJavaType(Cloneable.class)); @@ -459,22 +462,42 @@ private void layoutInstanceFields(HostedInstanceClass clazz, HostedField[] super HostedConfiguration.instance().findAllFieldsForLayout(hUniverse, hMetaAccess, hUniverse.fields, rawFields, allFields, clazz); - if (mustReserveArrayFields(clazz)) { + int firstInstanceFieldOffset; + int minimumFirstFieldOffset = layout.getFirstFieldOffset(); + DynamicHubLayout dynamicHubLayout = DynamicHubLayout.singleton(); + if (dynamicHubLayout.isDynamicHub(clazz)) { + /* + * Reserve the vtable and typeslots + */ + int intSize = layout.sizeInBytes(JavaKind.Int); + int afterVtableLengthOffset = dynamicHubLayout.getVTableLengthOffset() + intSize; + + /* + * Reserve the extra memory that DynamicHub fields may use (at least the vtable length + * field). + */ + int fieldBytes = afterVtableLengthOffset - minimumFirstFieldOffset; + assert fieldBytes >= intSize; + reserve(usedBytes, minimumFirstFieldOffset, fieldBytes); + + /* Each type check id slot is 2 bytes. */ + int slotsSize = typeCheckBuilder.getNumTypeCheckSlots() * 2; + reserve(usedBytes, dynamicHubLayout.typeIDSlotsOffset, slotsSize); + firstInstanceFieldOffset = dynamicHubLayout.typeIDSlotsOffset + slotsSize; + + } else if (mustReserveArrayFields(clazz)) { int intSize = layout.sizeInBytes(JavaKind.Int); - int firstFieldOffset = layout.getFirstFieldOffset(); int afterArrayLengthOffset = layout.getArrayLengthOffset() + intSize; + firstInstanceFieldOffset = afterArrayLengthOffset; - /* Reserve the extra memory that array fields may use (at least the array length). */ - int arrayFieldBytes = afterArrayLengthOffset - firstFieldOffset; + /* + * Reserve the extra memory that array fields may use (at least the array length field). + */ + int arrayFieldBytes = afterArrayLengthOffset - minimumFirstFieldOffset; assert arrayFieldBytes >= intSize; - reserve(usedBytes, firstFieldOffset, arrayFieldBytes); - - /* Type check fields in DynamicHub. */ - if (clazz.equals(hMetaAccess.lookupJavaType(DynamicHub.class))) { - /* Each type check id slot is 2 bytes. */ - int slotsSize = typeCheckBuilder.getNumTypeCheckSlots() * 2; - reserve(usedBytes, afterArrayLengthOffset, slotsSize); - } + reserve(usedBytes, minimumFirstFieldOffset, arrayFieldBytes); + } else { + firstInstanceFieldOffset = minimumFirstFieldOffset; } /* @@ -544,7 +567,7 @@ private void layoutInstanceFields(HostedInstanceClass clazz, HostedField[] super /* No identity hash field needed. */ } else if (layout.isIdentityHashFieldInObjectHeader()) { clazz.setIdentityHashOffset(layout.getObjectHeaderIdentityHashOffset()); - } else if (HybridLayout.isHybrid(clazz)) { + } else if (HostedConfiguration.isArrayLikeLayout(clazz)) { if (layout.isIdentityHashFieldAtTypeSpecificOffset()) { clazz.setIdentityHashOffset(layout.getObjectHeaderIdentityHashOffset()); } else { @@ -567,6 +590,7 @@ private void layoutInstanceFields(HostedInstanceClass clazz, HostedField[] super } clazz.instanceFieldsWithoutSuper = allFields.toArray(new HostedField[0]); + clazz.firstInstanceFieldOffset = firstInstanceFieldOffset; clazz.afterFieldsOffset = afterFieldsOffset; clazz.instanceSize = layout.alignUp(afterFieldsOffset); @@ -1035,6 +1059,7 @@ private void buildHubs() { ImageSingletons.lookup(DynamicHubSupport.class).setData(referenceMapEncoder.encodeAll()); ObjectLayout ol = ConfigurationValues.getObjectLayout(); + DynamicHubLayout dynamicHubLayout = DynamicHubLayout.singleton(); for (HostedType type : hUniverse.getTypes()) { hUniverse.hostVM().recordActivity(); @@ -1046,8 +1071,10 @@ private void buildHubs() { HostedInstanceClass instanceClass = (HostedInstanceClass) type; if (instanceClass.isAbstract()) { layoutHelper = LayoutEncoding.forAbstract(); + } else if (dynamicHubLayout.isDynamicHub(type)) { + layoutHelper = LayoutEncoding.forDynamicHub(type, dynamicHubLayout.vTableOffset(), ol.getArrayIndexShift(dynamicHubLayout.getVTableSlotStorageKind())); } else if (HybridLayout.isHybrid(type)) { - HybridLayout hybridLayout = new HybridLayout<>(instanceClass, ol, hMetaAccess); + HybridLayout hybridLayout = new HybridLayout(instanceClass, ol, hMetaAccess); JavaKind storageKind = hybridLayout.getArrayElementStorageKind(); boolean isObject = (storageKind == JavaKind.Object); layoutHelper = LayoutEncoding.forHybrid(type, isObject, hybridLayout.getArrayBaseOffset(), ol.getArrayIndexShift(storageKind)); From 3a00ce650849ab41290b68254684892128f79ce0 Mon Sep 17 00:00:00 2001 From: Fabio Niephaus Date: Wed, 20 Dec 2023 12:31:40 +0100 Subject: [PATCH 308/593] Drop redundant architecture error for Windows. --- .../com/oracle/svm/hosted/c/codegen/CCompilerInvoker.java | 5 ----- 1 file changed, 5 deletions(-) diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/c/codegen/CCompilerInvoker.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/c/codegen/CCompilerInvoker.java index 58f19553d3b8..12aeeb068cc2 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/c/codegen/CCompilerInvoker.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/c/codegen/CCompilerInvoker.java @@ -195,11 +195,6 @@ protected void verify() { UserError.abort("On Windows, GraalVM Native Image for JDK %s requires %s or later (C/C++ Optimizing Compiler Version %s.%s or later).%nCompiler info detected: %s", JavaVersionUtil.JAVA_SPEC, VISUAL_STUDIO_MINIMUM_REQUIRED_VERSION, minimumMajorVersion, minimumMinorVersion, compilerInfo.getShortDescription()); } - if (guessArchitecture(compilerInfo.targetArch) != AMD64.class) { - String targetPrefix = compilerInfo.targetArch.matches("(.*x|i\\d)86$") ? "32-bit architecture " : ""; - UserError.abort("Native-image building on Windows currently only supports target architecture: %s (%s%s unsupported)", - AMD64.class.getSimpleName(), targetPrefix, compilerInfo.targetArch); - } } @Override From bf5194363958289bc55a098a34a70c8103bae339 Mon Sep 17 00:00:00 2001 From: Marouane El Hallaoui Date: Wed, 20 Dec 2023 17:30:10 +0100 Subject: [PATCH 309/593] deploy 23+2-jvmci-b01 --- common.json | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/common.json b/common.json index 94cc85c21248..f415645cf6b2 100644 --- a/common.json +++ b/common.json @@ -45,12 +45,12 @@ "labsjdk-ee-21-llvm": {"name": "labsjdk", "version": "ee-21.0.1+11-jvmci-23.1-b26-sulong", "platformspecific": true }, "oraclejdk-latest": {"name": "jpg-jdk", "version": "23", "build_id": "2", "release": true, "platformspecific": true, "extrabundles": ["static-libs"]}, - "labsjdk-ce-latest": {"name": "labsjdk", "version": "ce-23+2-jvmci-b01-20231219100612-5ebca33d60", "platformspecific": true }, - "labsjdk-ce-latestDebug": {"name": "labsjdk", "version": "ce-23+2-jvmci-b01-20231219100612-5ebca33d60-debug", "platformspecific": true }, - "labsjdk-ce-latest-llvm": {"name": "labsjdk", "version": "ce-23+2-jvmci-b01-20231219100612-5ebca33d60-sulong", "platformspecific": true }, - "labsjdk-ee-latest": {"name": "labsjdk", "version": "ee-23+2-jvmci-b01-20231219100612-5ebca33d60+4e97b2bfec", "platformspecific": true }, - "labsjdk-ee-latestDebug": {"name": "labsjdk", "version": "ee-23+2-jvmci-b01-20231219100612-5ebca33d60+4e97b2bfec-debug", "platformspecific": true }, - "labsjdk-ee-latest-llvm": {"name": "labsjdk", "version": "ee-23+2-jvmci-b01-20231219100612-5ebca33d60+4e97b2bfec-sulong", "platformspecific": true } + "labsjdk-ce-latest": {"name": "labsjdk", "version": "ce-23+2-jvmci-b01", "platformspecific": true }, + "labsjdk-ce-latestDebug": {"name": "labsjdk", "version": "ce-23+2-jvmci-b01-debug", "platformspecific": true }, + "labsjdk-ce-latest-llvm": {"name": "labsjdk", "version": "ce-23+2-jvmci-b01-sulong", "platformspecific": true }, + "labsjdk-ee-latest": {"name": "labsjdk", "version": "ee-23+2-jvmci-b01", "platformspecific": true }, + "labsjdk-ee-latestDebug": {"name": "labsjdk", "version": "ee-23+2-jvmci-b01-debug", "platformspecific": true }, + "labsjdk-ee-latest-llvm": {"name": "labsjdk", "version": "ee-23+2-jvmci-b01-sulong", "platformspecific": true } }, "eclipse": { From 7677eb88e9f509fb03149b567493e2e64fed7776 Mon Sep 17 00:00:00 2001 From: Olya Gupalo Date: Wed, 20 Dec 2023 17:18:32 +0000 Subject: [PATCH 310/593] Applied suggestion --- docs/reference-manual/native-image/Bundles.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/reference-manual/native-image/Bundles.md b/docs/reference-manual/native-image/Bundles.md index 7e93e8c46e9b..cb9188c98795 100644 --- a/docs/reference-manual/native-image/Bundles.md +++ b/docs/reference-manual/native-image/Bundles.md @@ -66,7 +66,7 @@ Then, run the Maven package command: ```shell ./mvnw -Pnative native:compile ``` ->Note: The command to create a native executable with Maven for a Micaonut project is: `./mvnw package -Dpackaging=native-image`. +> Note: The command to create a native executable with Maven for a Micronaut project is: `./mvnw package -Dpackaging=native-image`. You get the following build artifacts: ``` From 0131220db352541aa8d177a3be64db2a08b7e541 Mon Sep 17 00:00:00 2001 From: Jakub Chaloupka Date: Thu, 2 Mar 2023 09:01:02 +0100 Subject: [PATCH 311/593] Allow calling into the host from polyglot isolate's polyglot thread even when the context is not entered. --- .../api/test/polyglot/PolyglotThreadNotificationsTest.java | 3 --- .../com/oracle/truffle/polyglot/PolyglotLanguageContext.java | 4 +++- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/truffle/src/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/polyglot/PolyglotThreadNotificationsTest.java b/truffle/src/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/polyglot/PolyglotThreadNotificationsTest.java index 7d8b400f9296..fc4d5844f3b2 100644 --- a/truffle/src/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/polyglot/PolyglotThreadNotificationsTest.java +++ b/truffle/src/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/polyglot/PolyglotThreadNotificationsTest.java @@ -591,9 +591,6 @@ protected boolean isThreadAccessAllowed(Thread thread, boolean singleThreaded) { @Test public void testThreadNotificationError() throws IOException { - // TODO GR-44560 - TruffleTestAssumptions.assumeWeakEncapsulation(); - try (ByteArrayOutputStream errorOutput = new ByteArrayOutputStream(); Context ctx = Context.newBuilder().allowCreateThread(true).err(errorOutput).build()) { AbstractExecutableTestLanguage.evalTestLanguage(ctx, ThreadNotificationErrorTestLanguage.class, "1", "throwBefore"); AbstractExecutableTestLanguage.evalTestLanguage(ctx, ThreadNotificationErrorTestLanguage.class, "2", "throwAfter"); diff --git a/truffle/src/com.oracle.truffle.polyglot/src/com/oracle/truffle/polyglot/PolyglotLanguageContext.java b/truffle/src/com.oracle.truffle.polyglot/src/com/oracle/truffle/polyglot/PolyglotLanguageContext.java index 4dd8670fc6b6..0947a18c402b 100644 --- a/truffle/src/com.oracle.truffle.polyglot/src/com/oracle/truffle/polyglot/PolyglotLanguageContext.java +++ b/truffle/src/com.oracle.truffle.polyglot/src/com/oracle/truffle/polyglot/PolyglotLanguageContext.java @@ -56,6 +56,7 @@ import java.util.Set; import java.util.logging.Level; +import org.graalvm.polyglot.impl.AbstractPolyglotImpl; import org.graalvm.polyglot.impl.AbstractPolyglotImpl.APIAccess; import com.oracle.truffle.api.CallTarget; @@ -1010,12 +1011,13 @@ public String toString() { private class PolyglotUncaughtExceptionHandler implements Thread.UncaughtExceptionHandler { + @SuppressWarnings({"unused", "try"}) @Override public void uncaughtException(Thread t, Throwable e) { if (!(e instanceof ThreadDeath)) { Env currentEnv = env; if (currentEnv != null) { - try { + try (AbstractPolyglotImpl.ThreadScope scope = PolyglotLanguageContext.this.getImpl().getRootImpl().createThreadScope()) { e.printStackTrace(new PrintStream(currentEnv.err())); } catch (Throwable exc) { // Still show the original error if printing on Env.err() fails for some From 94e65784b3c6a80fc3c3502f6e9928454999e140 Mon Sep 17 00:00:00 2001 From: David Leopoldseder Date: Wed, 20 Dec 2023 10:34:48 +0100 Subject: [PATCH 312/593] debug options: make diagnose dump level a string to set different leves for diagnose retry. also support old numeric mode --- .../jdk/graal/compiler/core/CompilationWrapper.java | 10 +++++++++- .../src/jdk/graal/compiler/debug/DebugOptions.java | 2 +- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/core/CompilationWrapper.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/core/CompilationWrapper.java index 1867731d604e..bbc3761db224 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/core/CompilationWrapper.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/core/CompilationWrapper.java @@ -335,8 +335,16 @@ protected T handleFailure(DebugContext initialDebug, Throwable cause) { TTY.printf("Error writing to %s: %s%n", retryLogFile, ioe); } + String diagnoseLevel = DebugOptions.DiagnoseDumpLevel.getValue(initialOptions); + + // pre GR-51012 this was just a number - we still want to support the old numeric values + boolean isOldLevel = diagnoseLevel.matches("-?\\d+"); + if (isOldLevel) { + diagnoseLevel = ":" + diagnoseLevel; + } + OptionValues retryOptions = new OptionValues(initialOptions, - Dump, ":" + DebugOptions.DiagnoseDumpLevel.getValue(initialOptions), + Dump, diagnoseLevel, MethodFilter, null, Count, "", Time, "", diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/debug/DebugOptions.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/debug/DebugOptions.java index 85a64c82677e..fa2db0513f85 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/debug/DebugOptions.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/debug/DebugOptions.java @@ -147,7 +147,7 @@ public enum OptimizationLogTarget { public static final OptionKey DumpOnError = new OptionKey<>(false); @Option(help = "Specify the dump level if CompilationFailureAction#Diagnose is used." + "See CompilationFailureAction for details. file:doc-files/CompilationFailureActionHelp.txt", type = OptionType.Debug) - public static final OptionKey DiagnoseDumpLevel = new OptionKey<>(DebugContext.VERBOSE_LEVEL); + public static final OptionKey DiagnoseDumpLevel = new OptionKey<>(":" + DebugContext.VERBOSE_LEVEL); @Option(help = "Disable intercepting exceptions in debug scopes.", type = OptionType.Debug) public static final OptionKey DisableIntercept = new OptionKey<>(false); @Option(help = "Intercept also bailout exceptions", type = OptionType.Debug) From 8fa8599fa2083d1a1351c345d64b004bf913b5c3 Mon Sep 17 00:00:00 2001 From: David Leopoldseder Date: Wed, 20 Dec 2023 10:55:01 +0100 Subject: [PATCH 313/593] lowering: add option to dump lowering after every node --- .../src/jdk/graal/compiler/phases/common/LoweringPhase.java | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/phases/common/LoweringPhase.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/phases/common/LoweringPhase.java index 6c5e70f1dd87..130dd42fd6bd 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/phases/common/LoweringPhase.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/phases/common/LoweringPhase.java @@ -117,6 +117,8 @@ public static class Options { //@formatter:off @Option(help = "Print schedule result pre lowering to TTY.", type = OptionType.Expert) public static final OptionKey PrintLoweringScheduleToTTY = new OptionKey<>(false); + @Option(help = "Dump lowering after every node to igv.", type = OptionType.Expert) + public static final OptionKey DumpAfterEveryLowering = new OptionKey<>(false); //@formatter:on } @@ -584,7 +586,6 @@ public void postprocess() { @SuppressWarnings("try") private AnchoringNode process(CoreProviders context, final HIRBlock b, final NodeBitMap activeGuards, final AnchoringNode startAnchor, ScheduleResult schedule) { - FixedWithNextNode lastFixedNode = b.getBeginNode(); if (b.getBeginNode() instanceof LoopExitNode) { /** @@ -693,6 +694,9 @@ private AnchoringNode process(CoreProviders context, final HIRBlock b, final Nod } loweringTool.setLastFixedNode((FixedWithNextNode) nextLastFixed); } + if (Options.DumpAfterEveryLowering.getValue(debug.getOptions())) { + debug.dump(DebugContext.VERY_DETAILED_LEVEL, b.getBeginNode().graph(), "After lowering %s", node); + } } return loweringTool.getCurrentGuardAnchor(); } From 49ca8ea775dfd3e4d05c66c441f722e112ae9b51 Mon Sep 17 00:00:00 2001 From: David Leopoldseder Date: Wed, 20 Dec 2023 11:51:43 +0100 Subject: [PATCH 314/593] array length handling: changes to avoid loosing the stamp when an array length is lowered to a constant (or to a read that can constant fold). to preserve the original pi's position swtich to using value anchors. --- .../nodes/test/ConstantArrayLengthTest.java | 56 +++++++++++ .../compiler/nodes/java/ArrayLengthNode.java | 5 +- .../graal/compiler/nodes/memory/ReadNode.java | 95 +++++++++++++------ .../DefaultJavaLoweringProvider.java | 4 +- 4 files changed, 125 insertions(+), 35 deletions(-) create mode 100644 compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/nodes/test/ConstantArrayLengthTest.java diff --git a/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/nodes/test/ConstantArrayLengthTest.java b/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/nodes/test/ConstantArrayLengthTest.java new file mode 100644 index 000000000000..fdff60ec9f20 --- /dev/null +++ b/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/nodes/test/ConstantArrayLengthTest.java @@ -0,0 +1,56 @@ +/* + * Copyright (c) 2023, 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 jdk.graal.compiler.nodes.test; + +import org.junit.Test; + +import jdk.graal.compiler.core.test.GraalCompilerTest; +import jdk.graal.compiler.options.OptionValues; + +public class ConstantArrayLengthTest extends GraalCompilerTest { + + static int method0(int[] arg, int a, int b) { + int len = 0; + int[] arr = null; + if (a == noBCInline(a)) { + arr = new int[Math.addExact(a, b)]; + } else { + arr = arg; + } + len = arr.length; + return len / a; + } + + @BytecodeParserNeverInline + public static int noBCInline(int i) { + return i; + } + + @Test + public void test0() { + OptionValues opt = getInitialOptions(); + test(opt, "method0", new int[]{}, 100, 10); + } +} diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/nodes/java/ArrayLengthNode.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/nodes/java/ArrayLengthNode.java index 0ef69f766e63..9fe147606ad3 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/nodes/java/ArrayLengthNode.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/nodes/java/ArrayLengthNode.java @@ -38,12 +38,13 @@ import jdk.graal.compiler.nodes.ConstantNode; import jdk.graal.compiler.nodes.DeoptimizeNode; import jdk.graal.compiler.nodes.FixedWithNextNode; +import jdk.graal.compiler.nodes.GraphState.StageFlag; import jdk.graal.compiler.nodes.NamedLocationIdentity; import jdk.graal.compiler.nodes.NodeView; import jdk.graal.compiler.nodes.PiNode; import jdk.graal.compiler.nodes.StructuredGraph; import jdk.graal.compiler.nodes.ValueNode; -import jdk.graal.compiler.nodes.GraphState.StageFlag; +import jdk.graal.compiler.nodes.extended.ValueAnchorNode; import jdk.graal.compiler.nodes.graphbuilderconf.GraphBuilderContext; import jdk.graal.compiler.nodes.memory.MemoryAccess; import jdk.graal.compiler.nodes.spi.ArrayLengthProvider; @@ -171,7 +172,7 @@ public void simplify(SimplifierTool tool) { StructuredGraph graph = graph(); ValueNode replacement = length; if (!length.isConstant() && length.stamp(NodeView.DEFAULT).canBeImprovedWith(StampFactory.positiveInt())) { - BeginNode guard = graph.add(new BeginNode()); + ValueAnchorNode guard = graph.add(new ValueAnchorNode()); graph.addAfterFixed(this, guard); replacement = graph.addWithoutUnique(new PiNode(length, StampFactory.positiveInt(), guard)); } diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/nodes/memory/ReadNode.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/nodes/memory/ReadNode.java index 3386826f1c00..a16db2e91ca6 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/nodes/memory/ReadNode.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/nodes/memory/ReadNode.java @@ -51,10 +51,13 @@ import jdk.graal.compiler.nodes.FixedWithNextNode; import jdk.graal.compiler.nodes.FrameState; import jdk.graal.compiler.nodes.NodeView; +import jdk.graal.compiler.nodes.PiNode; +import jdk.graal.compiler.nodes.StructuredGraph; import jdk.graal.compiler.nodes.ValueNode; import jdk.graal.compiler.nodes.calc.NarrowNode; import jdk.graal.compiler.nodes.calc.ZeroExtendNode; import jdk.graal.compiler.nodes.extended.GuardingNode; +import jdk.graal.compiler.nodes.extended.ValueAnchorNode; import jdk.graal.compiler.nodes.memory.address.AddressNode; import jdk.graal.compiler.nodes.memory.address.OffsetAddressNode; import jdk.graal.compiler.nodes.spi.ArrayLengthProvider; @@ -62,6 +65,8 @@ import jdk.graal.compiler.nodes.spi.CanonicalizerTool; import jdk.graal.compiler.nodes.spi.CoreProviders; import jdk.graal.compiler.nodes.spi.NodeLIRBuilderTool; +import jdk.graal.compiler.nodes.spi.Simplifiable; +import jdk.graal.compiler.nodes.spi.SimplifierTool; import jdk.graal.compiler.nodes.spi.Virtualizable; import jdk.graal.compiler.nodes.spi.VirtualizerTool; import jdk.graal.compiler.nodes.util.ConstantFoldUtil; @@ -76,7 +81,8 @@ * Reads an {@linkplain FixedAccessNode accessed} value. */ @NodeInfo(nameTemplate = "Read#{p#location/s}", cycles = CYCLES_2, size = SIZE_1) -public class ReadNode extends FloatableAccessNode implements LIRLowerableAccess, Canonicalizable, Virtualizable, GuardingNode, OrderedMemoryAccess, SingleMemoryKill, ExtendableMemoryAccess { +public class ReadNode extends FloatableAccessNode + implements LIRLowerableAccess, Canonicalizable, Virtualizable, GuardingNode, OrderedMemoryAccess, SingleMemoryKill, ExtendableMemoryAccess, Simplifiable { public static final NodeClass TYPE = NodeClass.create(ReadNode.class); @@ -126,13 +132,17 @@ public void generate(NodeLIRBuilderTool gen) { } } + private boolean canCanonicalizeRead() { + return !getUsedAsNullCheck() && !extendsAccess(); + } + @Override public Node canonical(CanonicalizerTool tool) { if (tool.allUsagesAvailable() && hasNoUsages()) { // Read without usages or guard can be safely removed. return null; } - if (!getUsedAsNullCheck() && !extendsAccess()) { + if (canCanonicalizeRead()) { return canonicalizeRead(this, getAddress(), getLocationIdentity(), tool); } else { // if this read is a null check, then replacing it with the value is incorrect for @@ -141,6 +151,36 @@ public Node canonical(CanonicalizerTool tool) { } } + @Override + public void simplify(SimplifierTool tool) { + if (!tool.canonicalizeReads() || !canCanonicalizeRead()) { + return; + } + if (address instanceof OffsetAddressNode) { + OffsetAddressNode objAddress = (OffsetAddressNode) address; + ConstantReflectionProvider constantReflection = tool.getConstantReflection(); + // Note: readConstant cannot be used to read the array length, so in order to avoid an + // unnecessary CompilerToVM.readFieldValue call ending in an IllegalArgumentException, + // check if we are reading the array length location first. + if (getLocationIdentity().equals(ARRAY_LENGTH_LOCATION)) { + ValueNode length = GraphUtil.arrayLength(objAddress.getBase(), ArrayLengthProvider.FindLengthMode.CANONICALIZE_READ, constantReflection); + if (length != null) { + StructuredGraph graph = graph(); + ValueNode replacement = length; + if (!length.isConstant() && length.stamp(NodeView.DEFAULT).canBeImprovedWith(StampFactory.positiveInt())) { + ValueAnchorNode g = graph.add(new ValueAnchorNode()); + graph.addAfterFixed(this, g); + replacement = graph.addWithoutUnique(new PiNode(length, StampFactory.positiveInt(), g)); + } + if (!replacement.isAlive()) { + replacement = graph.addOrUnique(replacement); + } + graph.replaceFixedWithFloating(this, replacement); + } + } + } + } + @Override public LocationIdentity getKilledLocationIdentity() { if (ordersMemoryAccesses()) { @@ -199,39 +239,32 @@ private static ValueNode canonicalizeRead(ValueNode read, Stamp accessStamp, Val ConstantReflectionProvider constantReflection = tool.getConstantReflection(); Stamp resultStamp = read.stamp(view); - // Note: readConstant cannot be used to read the array length, so in order to avoid an - // unnecessary CompilerToVM.readFieldValue call ending in an IllegalArgumentException, - // check if we are reading the array length location first. - if (locationIdentity.equals(ARRAY_LENGTH_LOCATION)) { - ValueNode length = GraphUtil.arrayLength(object, ArrayLengthProvider.FindLengthMode.CANONICALIZE_READ, constantReflection); - if (length != null) { - assert length.stamp(view).isCompatible(accessStamp); - return length; - } - } else { - if (metaAccess != null && object.isConstant() && !object.isNullConstant() && offset.isConstant()) { - long displacement = offset.asJavaConstant().asLong(); - int stableDimension = ((ConstantNode) object).getStableDimension(); - - if (locationIdentity.isImmutable() || stableDimension > 0) { - Constant constant = resultStamp.readConstant(constantReflection.getMemoryAccessProvider(), object.asConstant(), displacement, accessStamp); - boolean isDefaultStable = locationIdentity.isImmutable() || ((ConstantNode) object).isDefaultStable(); - if (constant != null && (isDefaultStable || !constant.isDefaultForKind())) { - return ConstantNode.forConstant(resultStamp, constant, Math.max(stableDimension - 1, 0), isDefaultStable, metaAccess); - } + // NOTE: Canonicalizing array lengths are not done here but in simplify since we need to + // preserve the stamp and insert fixed and floating nodes + + if (metaAccess != null && object.isConstant() && !object.isNullConstant() && offset.isConstant()) { + long displacement = offset.asJavaConstant().asLong(); + int stableDimension = ((ConstantNode) object).getStableDimension(); + + if (locationIdentity.isImmutable() || stableDimension > 0) { + Constant constant = resultStamp.readConstant(constantReflection.getMemoryAccessProvider(), object.asConstant(), displacement, accessStamp); + boolean isDefaultStable = locationIdentity.isImmutable() || ((ConstantNode) object).isDefaultStable(); + if (constant != null && (isDefaultStable || !constant.isDefaultForKind())) { + return ConstantNode.forConstant(resultStamp, constant, Math.max(stableDimension - 1, 0), isDefaultStable, metaAccess); } - if (locationIdentity instanceof FieldLocationIdentity && !locationIdentity.isImmutable()) { - // Use ConstantFoldUtil as that properly handles final Java fields which are - // normally not considered immutable. - ResolvedJavaField field = ((FieldLocationIdentity) locationIdentity).getField(); - ConstantNode constantNode = ConstantFoldUtil.tryConstantFold(tool, field, object.asJavaConstant(), displacement, resultStamp, - accessStamp, read.getOptions(), read.getNodeSourcePosition()); - if (constantNode != null) { - return constantNode; - } + } + if (locationIdentity instanceof FieldLocationIdentity && !locationIdentity.isImmutable()) { + // Use ConstantFoldUtil as that properly handles final Java fields which are + // normally not considered immutable. + ResolvedJavaField field = ((FieldLocationIdentity) locationIdentity).getField(); + ConstantNode constantNode = ConstantFoldUtil.tryConstantFold(tool, field, object.asJavaConstant(), displacement, resultStamp, + accessStamp, read.getOptions(), read.getNodeSourcePosition()); + if (constantNode != null) { + return constantNode; } } } + if (locationIdentity instanceof CanonicalizableLocation) { CanonicalizableLocation canonicalize = (CanonicalizableLocation) locationIdentity; ValueNode result = canonicalize.canonicalizeRead(read, object, offset, tool); diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/replacements/DefaultJavaLoweringProvider.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/replacements/DefaultJavaLoweringProvider.java index 62f87e0d1639..96ca4cf29d59 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/replacements/DefaultJavaLoweringProvider.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/replacements/DefaultJavaLoweringProvider.java @@ -625,8 +625,8 @@ public void lowerStoreIndexedNode(StoreIndexedNode storeIndexed, LoweringTool to } protected void lowerArrayLengthNode(ArrayLengthNode arrayLengthNode, LoweringTool tool) { - arrayLengthNode.replaceAtUsages(createReadArrayLength(arrayLengthNode.array(), arrayLengthNode, tool)); StructuredGraph graph = arrayLengthNode.graph(); + arrayLengthNode.replaceAtUsages(createReadArrayLength(arrayLengthNode.array(), arrayLengthNode, tool)); graph.removeFixed(arrayLengthNode); } @@ -635,7 +635,7 @@ protected void lowerArrayLengthNode(ArrayLengthNode arrayLengthNode, LoweringToo * * The created node is placed before {@code before} in the CFG. */ - protected ReadNode createReadArrayLength(ValueNode array, FixedNode before, LoweringTool tool) { + private ReadNode createReadArrayLength(ValueNode array, FixedNode before, LoweringTool tool) { StructuredGraph graph = array.graph(); ValueNode canonicalArray = this.createNullCheckedValue(GraphUtil.skipPiWhileNonNullArray(array), before, tool); AddressNode address = createOffsetAddress(graph, canonicalArray, arrayLengthOffset()); From 2f1d4a7fb8bbe68c75b431ad9ab2bffab242ddbe Mon Sep 17 00:00:00 2001 From: Roland Schatz Date: Thu, 21 Dec 2023 11:44:44 +0100 Subject: [PATCH 315/593] Partial revert "Reduce the frequency of the deployment of JDK21-based artifacts." This reverts parts of commit a2e7e272f27353d0957bd6b686c25c067d9047cf. --- vm/ci/ci_common/common.jsonnet | 2 +- vm/ci/ci_includes/vm.jsonnet | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/vm/ci/ci_common/common.jsonnet b/vm/ci/ci_common/common.jsonnet index be3c970b9063..570b0a889ea4 100644 --- a/vm/ci/ci_common/common.jsonnet +++ b/vm/ci/ci_common/common.jsonnet @@ -653,7 +653,7 @@ local devkits = graal_common.devkits; deploy_vm_base_javaLatest_linux_amd64: vm.vm_java_Latest + self.full_vm_build_linux_amd64 + self.linux_deploy + self.vm_base('linux', 'amd64', 'post-merge', deploy=true) + self.deploy_graalvm_base('latest') + {name: 'post-merge-deploy-vm-base-java-latest-linux-amd64', notify_groups:: ["deploy"]}, deploy_vm_installables_standalones_javaLatest_linux_amd64: vm.vm_java_Latest + self.full_vm_build_linux_amd64 + self.linux_deploy + self.vm_base('linux', 'amd64', 'daily', deploy=true) + self.deploy_graalvm_components('latest', installables=false, standalones=true, record_file_sizes=true) + {name: 'daily-deploy-vm-installables-standalones-java-latest-linux-amd64', notify_groups:: ["deploy"]}, # - JDK21 - deploy_vm_base_java21_linux_amd64: vm.vm_java_21 + self.full_vm_build_linux_amd64 + self.linux_deploy + self.vm_base('linux', 'amd64', 'weekly', deploy=true) + self.deploy_graalvm_base("java21") + {name: 'weekly-deploy-vm-base-java21-linux-amd64', notify_groups:: ["deploy"]}, + deploy_vm_base_java21_linux_amd64: vm.vm_java_21 + self.full_vm_build_linux_amd64 + self.linux_deploy + self.vm_base('linux', 'amd64', 'post-merge', deploy=true) + self.deploy_graalvm_base("java21") + {name: 'post-merge-deploy-vm-base-java21-linux-amd64', notify_groups:: ["deploy"]}, deploy_vm_installables_standalones_java21_linux_amd64: vm.vm_java_21_llvm + self.full_vm_build_linux_amd64 + self.linux_deploy + self.vm_base('linux', 'amd64', 'weekly', deploy=true) + self.deploy_graalvm_components("java21", installables=true, standalones=true, record_file_sizes=true) + {name: 'weekly-deploy-vm-installables-standalones-java21-linux-amd64', notify_groups:: ["deploy"]}, # Linux/AARCH64 diff --git a/vm/ci/ci_includes/vm.jsonnet b/vm/ci/ci_includes/vm.jsonnet index b13a3dfec21c..3ef2711f1f1b 100644 --- a/vm/ci/ci_includes/vm.jsonnet +++ b/vm/ci/ci_includes/vm.jsonnet @@ -55,6 +55,7 @@ local graal_common = import '../../../ci/ci_common/common.jsonnet'; ], runAfter: [ 'post-merge-deploy-vm-base-java-latest-linux-amd64', + 'post-merge-deploy-vm-base-java21-linux-amd64', 'daily-deploy-vm-installables-standalones-java-latest-linux-amd64', 'daily-deploy-vm-base-java-latest-linux-aarch64', 'daily-deploy-vm-installables-standalones-java-latest-linux-aarch64', From cdc813a8fd5cd8b094a8dc6b6d2efe5203a5a095 Mon Sep 17 00:00:00 2001 From: David Leopoldseder Date: Thu, 21 Dec 2023 14:43:41 +0100 Subject: [PATCH 316/593] read node: perform simple length foldings to constants and other precise stamps always --- .../nodes/memory/FloatingReadNode.java | 10 ++-- .../graal/compiler/nodes/memory/ReadNode.java | 52 +++++++++++-------- 2 files changed, 36 insertions(+), 26 deletions(-) diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/nodes/memory/FloatingReadNode.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/nodes/memory/FloatingReadNode.java index 7552c7233878..a69fe8897fff 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/nodes/memory/FloatingReadNode.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/nodes/memory/FloatingReadNode.java @@ -28,6 +28,8 @@ import static jdk.graal.compiler.nodeinfo.NodeCycles.CYCLES_2; import static jdk.graal.compiler.nodeinfo.NodeSize.SIZE_1; +import org.graalvm.word.LocationIdentity; + import jdk.graal.compiler.core.common.LIRKind; import jdk.graal.compiler.core.common.memory.BarrierType; import jdk.graal.compiler.core.common.memory.MemoryExtendKind; @@ -38,14 +40,13 @@ import jdk.graal.compiler.graph.Node; import jdk.graal.compiler.graph.NodeClass; import jdk.graal.compiler.nodeinfo.NodeInfo; +import jdk.graal.compiler.nodes.NodeView; +import jdk.graal.compiler.nodes.ValuePhiNode; import jdk.graal.compiler.nodes.extended.GuardingNode; +import jdk.graal.compiler.nodes.memory.address.AddressNode; import jdk.graal.compiler.nodes.spi.Canonicalizable; import jdk.graal.compiler.nodes.spi.CanonicalizerTool; import jdk.graal.compiler.nodes.spi.NodeLIRBuilderTool; -import jdk.graal.compiler.nodes.NodeView; -import jdk.graal.compiler.nodes.ValuePhiNode; -import jdk.graal.compiler.nodes.memory.address.AddressNode; -import org.graalvm.word.LocationIdentity; /** * A floating read of a value from memory specified in terms of an object base and an object @@ -134,4 +135,5 @@ public boolean verify() { public Stamp getAccessStamp(NodeView view) { return stamp(view); } + } diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/nodes/memory/ReadNode.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/nodes/memory/ReadNode.java index a16db2e91ca6..20f02c13659f 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/nodes/memory/ReadNode.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/nodes/memory/ReadNode.java @@ -239,32 +239,40 @@ private static ValueNode canonicalizeRead(ValueNode read, Stamp accessStamp, Val ConstantReflectionProvider constantReflection = tool.getConstantReflection(); Stamp resultStamp = read.stamp(view); - // NOTE: Canonicalizing array lengths are not done here but in simplify since we need to - // preserve the stamp and insert fixed and floating nodes - - if (metaAccess != null && object.isConstant() && !object.isNullConstant() && offset.isConstant()) { - long displacement = offset.asJavaConstant().asLong(); - int stableDimension = ((ConstantNode) object).getStableDimension(); - - if (locationIdentity.isImmutable() || stableDimension > 0) { - Constant constant = resultStamp.readConstant(constantReflection.getMemoryAccessProvider(), object.asConstant(), displacement, accessStamp); - boolean isDefaultStable = locationIdentity.isImmutable() || ((ConstantNode) object).isDefaultStable(); - if (constant != null && (isDefaultStable || !constant.isDefaultForKind())) { - return ConstantNode.forConstant(resultStamp, constant, Math.max(stableDimension - 1, 0), isDefaultStable, metaAccess); - } + // Note: readConstant cannot be used to read the array length, so in order to avoid an + // unnecessary CompilerToVM.readFieldValue call ending in an IllegalArgumentException, + // check if we are reading the array length location first. + if (locationIdentity.equals(ARRAY_LENGTH_LOCATION)) { + ValueNode length = GraphUtil.arrayLength(object, ArrayLengthProvider.FindLengthMode.CANONICALIZE_READ, constantReflection); + // only use length if we do not drop stamp precision here + if (length != null && !length.stamp(NodeView.DEFAULT).canBeImprovedWith(StampFactory.positiveInt())) { + assert length.stamp(view).isCompatible(accessStamp); + return length; } - if (locationIdentity instanceof FieldLocationIdentity && !locationIdentity.isImmutable()) { - // Use ConstantFoldUtil as that properly handles final Java fields which are - // normally not considered immutable. - ResolvedJavaField field = ((FieldLocationIdentity) locationIdentity).getField(); - ConstantNode constantNode = ConstantFoldUtil.tryConstantFold(tool, field, object.asJavaConstant(), displacement, resultStamp, - accessStamp, read.getOptions(), read.getNodeSourcePosition()); - if (constantNode != null) { - return constantNode; + } else { + if (metaAccess != null && object.isConstant() && !object.isNullConstant() && offset.isConstant()) { + long displacement = offset.asJavaConstant().asLong(); + int stableDimension = ((ConstantNode) object).getStableDimension(); + + if (locationIdentity.isImmutable() || stableDimension > 0) { + Constant constant = resultStamp.readConstant(constantReflection.getMemoryAccessProvider(), object.asConstant(), displacement, accessStamp); + boolean isDefaultStable = locationIdentity.isImmutable() || ((ConstantNode) object).isDefaultStable(); + if (constant != null && (isDefaultStable || !constant.isDefaultForKind())) { + return ConstantNode.forConstant(resultStamp, constant, Math.max(stableDimension - 1, 0), isDefaultStable, metaAccess); + } + } + if (locationIdentity instanceof FieldLocationIdentity && !locationIdentity.isImmutable()) { + // Use ConstantFoldUtil as that properly handles final Java fields which are + // normally not considered immutable. + ResolvedJavaField field = ((FieldLocationIdentity) locationIdentity).getField(); + ConstantNode constantNode = ConstantFoldUtil.tryConstantFold(tool, field, object.asJavaConstant(), displacement, resultStamp, + accessStamp, read.getOptions(), read.getNodeSourcePosition()); + if (constantNode != null) { + return constantNode; + } } } } - if (locationIdentity instanceof CanonicalizableLocation) { CanonicalizableLocation canonicalize = (CanonicalizableLocation) locationIdentity; ValueNode result = canonicalize.canonicalizeRead(read, object, offset, tool); From ab6dbf91333e91be63816563a22fa4e99acf3de6 Mon Sep 17 00:00:00 2001 From: Andreas Woess Date: Wed, 20 Dec 2023 19:24:29 +0100 Subject: [PATCH 317/593] Fix possible language context initialization cycle in Insight instrument. --- .../agentscript/impl/InsightPerSource.java | 58 +++++++++++++++++-- 1 file changed, 54 insertions(+), 4 deletions(-) diff --git a/tools/src/com.oracle.truffle.tools.agentscript/src/com/oracle/truffle/tools/agentscript/impl/InsightPerSource.java b/tools/src/com.oracle.truffle.tools.agentscript/src/com/oracle/truffle/tools/agentscript/impl/InsightPerSource.java index 320be516c8a9..11d848a581df 100644 --- a/tools/src/com.oracle.truffle.tools.agentscript/src/com/oracle/truffle/tools/agentscript/impl/InsightPerSource.java +++ b/tools/src/com.oracle.truffle.tools.agentscript/src/com/oracle/truffle/tools/agentscript/impl/InsightPerSource.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 2023, 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,13 +27,17 @@ import java.lang.reflect.Array; import java.util.ArrayList; import java.util.HashMap; +import java.util.HashSet; import java.util.List; import java.util.Map; +import java.util.Set; import java.util.WeakHashMap; import java.util.function.Consumer; import java.util.function.Function; import java.util.function.Supplier; +import org.graalvm.collections.EconomicMap; + import com.oracle.truffle.api.CallTarget; import com.oracle.truffle.api.CompilerDirectives; import com.oracle.truffle.api.TruffleContext; @@ -56,8 +60,6 @@ import com.oracle.truffle.api.nodes.LanguageInfo; import com.oracle.truffle.api.source.Source; -import org.graalvm.collections.EconomicMap; - final class InsightPerSource implements ContextsListener, AutoCloseable, LoadSourceListener { private final InsightInstrument instrument; private final Supplier src; @@ -75,6 +77,8 @@ final class InsightPerSource implements ContextsListener, AutoCloseable, LoadSou private Map bindings = new HashMap<>(); /* @GuardedBy("this") */ private final Map registeredSource = new WeakHashMap<>(); + /* @GuardedBy("this") */ + private final Map> contextLanguagesInitializing = new WeakHashMap<>(); private final EventBinding onInit; InsightPerSource(Instrumenter instrumenter, InsightInstrument instrument, Supplier src, IgnoreSources ignoredSources) { @@ -120,8 +124,47 @@ void initializeAgent(TruffleContext ctx) { public void onContextCreated(TruffleContext context) { } + private synchronized void pushLanguageContextCreateOrInitialize(TruffleContext context, LanguageInfo language) { + contextLanguagesInitializing.putIfAbsent(context, new HashSet<>()); + contextLanguagesInitializing.get(context).add(language.getId()); + } + + private synchronized boolean popLanguageContextCreateOrInitialize(TruffleContext context, LanguageInfo language) { + boolean currentlyInitializing = false; + var languagesInitializing = contextLanguagesInitializing.get(context); + if (languagesInitializing != null) { + languagesInitializing.remove(language.getId()); + if (languagesInitializing.isEmpty()) { + contextLanguagesInitializing.remove(context); + } else { + currentlyInitializing = true; + } + } + return currentlyInitializing; + } + + @Override + public void onLanguageContextCreate(TruffleContext context, LanguageInfo language) { + if (language.isInternal()) { + return; + } + pushLanguageContextCreateOrInitialize(context, language); + } + @Override public void onLanguageContextCreated(TruffleContext context, LanguageInfo language) { + if (language.isInternal()) { + return; + } + popLanguageContextCreateOrInitialize(context, language); + } + + @Override + public void onLanguageContextInitialize(TruffleContext context, LanguageInfo language) { + if (language.isInternal()) { + return; + } + pushLanguageContextCreateOrInitialize(context, language); } @Override @@ -129,7 +172,14 @@ public void onLanguageContextInitialized(TruffleContext context, LanguageInfo la if (language.isInternal()) { return; } - if (context.isEntered()) { + /* + * Only parse the script eagerly if we're not currently creating or initializing a context; + * otherwise we might introduce an initialization cycle (e.g.: language A (during context + * create or initialize) initializing language B, initializing Insight script, initializing + * language A (via TruffleInstrument.Env#parse). + */ + boolean currentlyInitializing = popLanguageContextCreateOrInitialize(context, language); + if (context.isEntered() && !currentlyInitializing) { EventBinding agentBinding; synchronized (this) { agentBinding = initializeBindings.removeKey(context); From 69b59662261fe62f821e3228596eb6d1aead9429 Mon Sep 17 00:00:00 2001 From: Jirka Marsik Date: Thu, 21 Dec 2023 16:00:23 +0100 Subject: [PATCH 318/593] Use ARRAY_BYTE_BASE_OFFSET when copying memory to byte[] --- .../src/org/graalvm/wasm/memory/NativeWasmMemory.java | 2 +- .../src/org/graalvm/wasm/memory/UnsafeWasmMemory.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/memory/NativeWasmMemory.java b/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/memory/NativeWasmMemory.java index 0e9848f72cf3..2e0f9ca6dd56 100644 --- a/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/memory/NativeWasmMemory.java +++ b/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/memory/NativeWasmMemory.java @@ -246,7 +246,7 @@ public long load_i64_32u(Node node, long address) { public Vector128 load_i128(Node node, long address) { validateAddress(node, address, 16); byte[] bytes = new byte[16]; - unsafe.copyMemory(null, startAddress + address, bytes, 0, 16); + unsafe.copyMemory(null, startAddress + address, bytes, Unsafe.ARRAY_BYTE_BASE_OFFSET, 16); return Vector128.ofBytes(bytes); } diff --git a/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/memory/UnsafeWasmMemory.java b/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/memory/UnsafeWasmMemory.java index 7e68401f2c15..701480dc04a4 100644 --- a/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/memory/UnsafeWasmMemory.java +++ b/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/memory/UnsafeWasmMemory.java @@ -246,7 +246,7 @@ public long load_i64_32u(Node node, long address) { public Vector128 load_i128(Node node, long address) { validateAddress(node, address, 16); byte[] bytes = new byte[16]; - unsafe.copyMemory(null, startAddress + address, bytes, 0, 16); + unsafe.copyMemory(null, startAddress + address, bytes, Unsafe.ARRAY_BYTE_BASE_OFFSET, 16); return Vector128.ofBytes(bytes); } From c2e15cbd1987bef17fe61480bf36ff3ffdcbcafe Mon Sep 17 00:00:00 2001 From: Jirka Marsik Date: Thu, 21 Dec 2023 17:07:00 +0100 Subject: [PATCH 319/593] Make Vector128 class final and a ValueType --- .../src/org/graalvm/wasm/BinaryParser.java | 2 +- .../src/org/graalvm/wasm/BinaryStreamParser.java | 2 +- .../src/org/graalvm/wasm/api/Vector128.java | 14 ++++++++------ 3 files changed, 10 insertions(+), 8 deletions(-) diff --git a/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/BinaryParser.java b/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/BinaryParser.java index bb35f13f84af..61fe18c86338 100644 --- a/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/BinaryParser.java +++ b/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/BinaryParser.java @@ -2804,7 +2804,7 @@ private Vector128 readUnsignedInt128() { for (int i = 0; i < 16; i++) { bytes[i] = read1(); } - return new Vector128(bytes); + return Vector128.ofBytes(bytes); } /** diff --git a/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/BinaryStreamParser.java b/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/BinaryStreamParser.java index b1d2e990525b..9189c0f6f02b 100644 --- a/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/BinaryStreamParser.java +++ b/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/BinaryStreamParser.java @@ -465,7 +465,7 @@ public static void writeI64(byte[] bytecode, int offset, long value) { */ public static Vector128 rawPeekI128(byte[] bytecode, int offset) { byte[] bytes = Arrays.copyOfRange(bytecode, offset, offset + 16); - return new Vector128(bytes); + return Vector128.ofBytes(bytes); } // endregion diff --git a/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/api/Vector128.java b/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/api/Vector128.java index f97fad797565..52240d3fec4f 100644 --- a/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/api/Vector128.java +++ b/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/api/Vector128.java @@ -40,6 +40,7 @@ */ package org.graalvm.wasm.api; +import com.oracle.truffle.api.CompilerDirectives; import com.oracle.truffle.api.interop.InteropLibrary; import com.oracle.truffle.api.interop.InvalidArrayIndexException; import com.oracle.truffle.api.interop.TruffleObject; @@ -49,16 +50,17 @@ import com.oracle.truffle.api.nodes.ExplodeLoop; @ExportLibrary(InteropLibrary.class) -public class Vector128 implements TruffleObject { +@CompilerDirectives.ValueType +public final class Vector128 implements TruffleObject { // v128 component values are stored in little-endian order private static final ByteArraySupport byteArraySupport = ByteArraySupport.littleEndian(); - public static final Vector128 ZERO = new Vector128(new byte[16]); + public static final Vector128 ZERO = Vector128.ofBytes(new byte[16]); private final byte[] bytes; - public Vector128(byte[] bytes) { + private Vector128(byte[] bytes) { assert bytes.length == 16; this.bytes = bytes; } @@ -167,17 +169,17 @@ public static Vector128 ofDoubles(double[] doubles) { } @ExportMessage - protected boolean hasArrayElements() { + protected static boolean hasArrayElements(@SuppressWarnings("unused") Vector128 receiver) { return true; } @ExportMessage - protected int getArraySize() { + protected static int getArraySize(@SuppressWarnings("unused") Vector128 receiver) { return 16; } @ExportMessage - protected boolean isArrayElementReadable(long index) { + protected static boolean isArrayElementReadable(@SuppressWarnings("unused") Vector128 receiver, long index) { return index < 16; } From b9548a35cc97b4f107bd7e608ef8034d237a1b35 Mon Sep 17 00:00:00 2001 From: Sacha Coppey Date: Wed, 11 Oct 2023 17:05:50 +0200 Subject: [PATCH 320/593] Add LayeredBaseImageAnalysis option to enable layered image base layer analysis --- .../pointsto/standalone/PointsToAnalyzer.java | 22 +- .../StandalonePointsToAnalysis.java | 5 +- .../pointsto/AbstractAnalysisEngine.java | 25 ++- .../com/oracle/graal/pointsto/BigBang.java | 4 + .../graal/pointsto/ClassInclusionPolicy.java | 188 ++++++++++++++++++ .../graal/pointsto/PointsToAnalysis.java | 26 ++- .../graal/pointsto/ReachabilityAnalysis.java | 10 + .../graal/pointsto/flow/MethodFlowsGraph.java | 30 +++ .../ReachabilityAnalysisEngine.java | 10 +- .../com/oracle/svm/core/SubstrateOptions.java | 3 + .../svm/hosted/NativeImageGenerator.java | 21 +- .../analysis/NativeImagePointsToAnalysis.java | 6 +- ...NativeImageReachabilityAnalysisEngine.java | 5 +- 13 files changed, 320 insertions(+), 35 deletions(-) create mode 100644 substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/ClassInclusionPolicy.java diff --git a/substratevm/src/com.oracle.graal.pointsto.standalone/src/com/oracle/graal/pointsto/standalone/PointsToAnalyzer.java b/substratevm/src/com.oracle.graal.pointsto.standalone/src/com/oracle/graal/pointsto/standalone/PointsToAnalyzer.java index 2bbbca0263a0..bbb53fa0d632 100644 --- a/substratevm/src/com.oracle.graal.pointsto.standalone/src/com/oracle/graal/pointsto/standalone/PointsToAnalyzer.java +++ b/substratevm/src/com.oracle.graal.pointsto.standalone/src/com/oracle/graal/pointsto/standalone/PointsToAnalyzer.java @@ -38,19 +38,11 @@ import java.util.ArrayList; import java.util.List; -import jdk.graal.compiler.api.replacements.SnippetReflectionProvider; -import jdk.graal.compiler.debug.DebugContext; -import jdk.graal.compiler.debug.Indent; -import jdk.graal.compiler.nodes.graphbuilderconf.GraphBuilderConfiguration; -import jdk.graal.compiler.nodes.graphbuilderconf.InvocationPlugins; -import jdk.graal.compiler.options.OptionValues; -import jdk.graal.compiler.phases.util.Providers; -import jdk.graal.compiler.printer.GraalDebugHandlersFactory; -import jdk.graal.compiler.word.WordTypes; import org.graalvm.nativeimage.hosted.Feature; import com.oracle.graal.pointsto.AnalysisObjectScanningObserver; import com.oracle.graal.pointsto.AnalysisPolicy; +import com.oracle.graal.pointsto.ClassInclusionPolicy; import com.oracle.graal.pointsto.api.PointstoOptions; import com.oracle.graal.pointsto.flow.context.bytecode.BytecodeSensitiveAnalysisPolicy; import com.oracle.graal.pointsto.heap.HeapSnapshotVerifier; @@ -79,6 +71,15 @@ import com.oracle.svm.util.ModuleSupport; import com.oracle.svm.util.ReflectionUtil; +import jdk.graal.compiler.api.replacements.SnippetReflectionProvider; +import jdk.graal.compiler.debug.DebugContext; +import jdk.graal.compiler.debug.Indent; +import jdk.graal.compiler.nodes.graphbuilderconf.GraphBuilderConfiguration; +import jdk.graal.compiler.nodes.graphbuilderconf.InvocationPlugins; +import jdk.graal.compiler.options.OptionValues; +import jdk.graal.compiler.phases.util.Providers; +import jdk.graal.compiler.printer.GraalDebugHandlersFactory; +import jdk.graal.compiler.word.WordTypes; import jdk.vm.ci.amd64.AMD64Kind; import jdk.vm.ci.hotspot.HotSpotJVMCIRuntime; import jdk.vm.ci.meta.JavaKind; @@ -151,8 +152,9 @@ private PointsToAnalyzer(String mainEntryClass, OptionValues options) { originalProviders.getPlatformConfigurationProvider(), aMetaAccessExtensionProvider, originalProviders.getLoopsDataProvider()); standaloneHost.initializeProviders(aProviders); analysisName = getAnalysisName(mainEntryClass); + ClassInclusionPolicy classInclusionPolicy = new ClassInclusionPolicy.DefaultAllInclusionPolicy("Included in the base image"); bigbang = new StandalonePointsToAnalysis(options, aUniverse, standaloneHost, aMetaAccess, snippetReflection, aConstantReflection, aProviders.getWordTypes(), debugContext, - new TimerCollection()); + new TimerCollection(), classInclusionPolicy); standaloneHost.setImageName(analysisName); aUniverse.setBigBang(bigbang); ImageHeap heap = new ImageHeap(); diff --git a/substratevm/src/com.oracle.graal.pointsto.standalone/src/com/oracle/graal/pointsto/standalone/StandalonePointsToAnalysis.java b/substratevm/src/com.oracle.graal.pointsto.standalone/src/com/oracle/graal/pointsto/standalone/StandalonePointsToAnalysis.java index fb985be004ea..1dc26544b7aa 100644 --- a/substratevm/src/com.oracle.graal.pointsto.standalone/src/com/oracle/graal/pointsto/standalone/StandalonePointsToAnalysis.java +++ b/substratevm/src/com.oracle.graal.pointsto.standalone/src/com/oracle/graal/pointsto/standalone/StandalonePointsToAnalysis.java @@ -29,6 +29,7 @@ import java.util.Set; import java.util.concurrent.ConcurrentHashMap; +import com.oracle.graal.pointsto.ClassInclusionPolicy; import com.oracle.graal.pointsto.PointsToAnalysis; import com.oracle.graal.pointsto.api.HostVM; import com.oracle.graal.pointsto.constraints.UnsupportedFeatures; @@ -48,8 +49,8 @@ public class StandalonePointsToAnalysis extends PointsToAnalysis { private final Set addedClinits = ConcurrentHashMap.newKeySet(); public StandalonePointsToAnalysis(OptionValues options, AnalysisUniverse universe, HostVM hostVM, AnalysisMetaAccess metaAccess, SnippetReflectionProvider snippetReflectionProvider, - ConstantReflectionProvider constantReflectionProvider, WordTypes wordTypes, DebugContext debugContext, TimerCollection timerCollection) { - super(options, universe, hostVM, metaAccess, snippetReflectionProvider, constantReflectionProvider, wordTypes, new UnsupportedFeatures(), debugContext, timerCollection); + ConstantReflectionProvider constantReflectionProvider, WordTypes wordTypes, DebugContext debugContext, TimerCollection timerCollection, ClassInclusionPolicy classInclusionPolicy) { + super(options, universe, hostVM, metaAccess, snippetReflectionProvider, constantReflectionProvider, wordTypes, new UnsupportedFeatures(), debugContext, timerCollection, classInclusionPolicy); } @Override diff --git a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/AbstractAnalysisEngine.java b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/AbstractAnalysisEngine.java index 035cb2da64f0..4deb02bf6041 100644 --- a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/AbstractAnalysisEngine.java +++ b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/AbstractAnalysisEngine.java @@ -25,12 +25,15 @@ package com.oracle.graal.pointsto; import java.io.PrintWriter; +import java.util.Arrays; import java.util.Collections; import java.util.List; import java.util.function.Function; +import java.util.stream.Stream; import org.graalvm.nativeimage.hosted.Feature; +import com.oracle.graal.pointsto.ClassInclusionPolicy.LayeredBaseImageInclusionPolicy; import com.oracle.graal.pointsto.api.HostVM; import com.oracle.graal.pointsto.api.PointstoOptions; import com.oracle.graal.pointsto.constraints.UnsupportedFeatures; @@ -97,11 +100,12 @@ public abstract class AbstractAnalysisEngine implements BigBang { protected final Timer processFeaturesTimer; protected final Timer analysisTimer; protected final Timer verifyHeapTimer; + protected final ClassInclusionPolicy classInclusionPolicy; @SuppressWarnings("this-escape") public AbstractAnalysisEngine(OptionValues options, AnalysisUniverse universe, HostVM hostVM, AnalysisMetaAccess metaAccess, SnippetReflectionProvider snippetReflectionProvider, ConstantReflectionProvider constantReflectionProvider, WordTypes wordTypes, UnsupportedFeatures unsupportedFeatures, DebugContext debugContext, - TimerCollection timerCollection) { + TimerCollection timerCollection, ClassInclusionPolicy classInclusionPolicy) { this.options = options; this.universe = universe; this.debugHandlerFactories = Collections.singletonList(new GraalDebugHandlersFactory(snippetReflectionProvider)); @@ -123,6 +127,8 @@ public AbstractAnalysisEngine(OptionValues options, AnalysisUniverse universe, H this.snippetReflectionProvider = snippetReflectionProvider; this.constantReflectionProvider = constantReflectionProvider; this.wordTypes = wordTypes; + classInclusionPolicy.setBigBang(this); + this.classInclusionPolicy = classInclusionPolicy; } /** @@ -257,6 +263,10 @@ public void profileConstantObject(AnalysisType type) { } } + public boolean isBaseLayerAnalysisEnabled() { + return classInclusionPolicy instanceof LayeredBaseImageInclusionPolicy; + } + @Override public OptionValues getOptions() { return options; @@ -346,6 +356,19 @@ public final boolean executorIsStarted() { return executor.isStarted(); } + @Override + public void registerTypeForBaseImage(Class cls) { + if (classInclusionPolicy.isClassIncluded(cls)) { + classInclusionPolicy.includeClass(cls); + Stream.concat(Arrays.stream(cls.getDeclaredConstructors()), Arrays.stream(cls.getDeclaredMethods())) + .filter(classInclusionPolicy::isMethodIncluded) + .forEach(classInclusionPolicy::includeMethod); + Arrays.stream(cls.getDeclaredFields()) + .filter(classInclusionPolicy::isFieldIncluded) + .forEach(classInclusionPolicy::includeField); + } + } + /** * Provide a non-null position. Some flows like newInstance and invoke require a non-null * position, for others is just better. The constructed position is best-effort, i.e., it diff --git a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/BigBang.java b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/BigBang.java index af914b935320..612ad177b792 100644 --- a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/BigBang.java +++ b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/BigBang.java @@ -136,4 +136,8 @@ default void afterAnalysis() { default AnalysisMethod fallbackResolveConcreteMethod(AnalysisType resolvingType, AnalysisMethod method) { return null; } + + default void registerTypeForBaseImage(Class cls) { + + } } diff --git a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/ClassInclusionPolicy.java b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/ClassInclusionPolicy.java new file mode 100644 index 000000000000..81a2b7c42cec --- /dev/null +++ b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/ClassInclusionPolicy.java @@ -0,0 +1,188 @@ +/* + * Copyright (c) 2023, 2023, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.graal.pointsto; + +import java.lang.reflect.Executable; +import java.lang.reflect.Field; +import java.lang.reflect.Member; +import java.lang.reflect.Modifier; + +import org.graalvm.nativeimage.AnnotationAccess; + +import com.oracle.graal.pointsto.meta.AnalysisMethod; + +import jdk.graal.compiler.api.replacements.Fold; + +/** + * Policy used to determine which classes, methods and fields need to be included in the image when + * the {@code IncludeAllFromPath} and/or {@code IncludeAllFromModule} options are specified + * depending on the configuration. + */ +public abstract class ClassInclusionPolicy { + protected BigBang bb; + protected final Object reason; + + public ClassInclusionPolicy(Object reason) { + this.reason = reason; + } + + public void setBigBang(BigBang bb) { + this.bb = bb; + } + + /** + * Determine if the given class needs to be included in the image according to the policy. + */ + public abstract boolean isClassIncluded(Class cls); + + /** + * Determine if the given method needs to be included in the image according to the policy. + */ + public boolean isMethodIncluded(Executable method) { + /* + * Methods annotated with @Fold should not be included in the base image as they must be + * inlined. An extension image would inline the method as well and would not use the method + * from the base image. + */ + return !AnnotationAccess.isAnnotationPresent(bb.getMetaAccess().lookupJavaMethod(method), Fold.class); + } + + /** + * Determine if the given field needs to be included in the image according to the policy. + */ + public boolean isFieldIncluded(Field field) { + return isAccessible(field); + } + + /** + * Includes the given class in the image. + */ + public void includeClass(Class cls) { + /* + * Those classes cannot be registered as allocated as they cannot be instantiated. They are + * instead registered as reachable as they can still have methods or fields that could be + * used by an extension image. + */ + if (Modifier.isAbstract(cls.getModifiers()) || cls.isInterface() || cls.isPrimitive()) { + bb.getMetaAccess().lookupJavaType(cls).registerAsReachable(reason); + } else { + bb.getMetaAccess().lookupJavaType(cls).registerAsAllocated(reason); + } + } + + /** + * Includes the given method in the image. + */ + public abstract void includeMethod(Executable method); + + /** + * Includes the given field in the image. + */ + public void includeField(Field field) { + bb.postTask(debug -> bb.getMetaAccess().lookupJavaField(field).registerAsAccessed(reason)); + } + + /** + * The analysis for the base layer of a layered image assumes that any method or field that is + * reachable using the base java access rules can be an entry point. An upper layer does not + * have access to the packages from a lower layer. Thus, only the public classes with their + * public and protected inner classes, methods and fields can be accessed by an upper layer. + * Protected elements from final or sealed class cannot be accessed as an upper layer cannot + * create a new class that extends the final or sealed class. + */ + public static class LayeredBaseImageInclusionPolicy extends ClassInclusionPolicy { + public LayeredBaseImageInclusionPolicy(Object reason) { + super(reason); + } + + @Override + public boolean isClassIncluded(Class cls) { + Class enclosingClass = cls.getEnclosingClass(); + int classModifiers = cls.getModifiers(); + if (enclosingClass != null) { + return isAccessible(enclosingClass, classModifiers) && isClassIncluded(enclosingClass); + } else { + return Modifier.isPublic(classModifiers); + } + } + + @Override + public boolean isMethodIncluded(Executable method) { + return !Modifier.isAbstract(method.getModifiers()) && isAccessible(method) && super.isMethodIncluded(method); + } + + @Override + public void includeMethod(Executable method) { + bb.postTask(debug -> { + /* + * Non-abstract methods from an abstract class or default methods from an interface + * are not registered as implementation invoked by the analysis because their + * declaring class cannot be marked as instantiated and AnalysisType.getTypeFlow + * only includes instantiated types (see TypeFlow.addObserver). For now, to ensure + * those methods are included in the image, they are manually registered as + * implementation invoked. + */ + Class declaringClass = method.getDeclaringClass(); + if (!Modifier.isAbstract(method.getModifiers()) && (declaringClass.isInterface() || Modifier.isAbstract(declaringClass.getModifiers()))) { + AnalysisMethod analysisMethod = bb.getMetaAccess().lookupJavaMethod(method); + analysisMethod.registerAsDirectRootMethod(reason); + analysisMethod.registerAsImplementationInvoked(reason); + } + bb.forcedAddRootMethod(method, false, reason); + }); + } + } + + /** + * The default inclusion policy. Includes all classes and methods. Including all fields causes + * issues at the moment, so the same rules as for the {@link LayeredBaseImageInclusionPolicy} + * are used. + */ + public static class DefaultAllInclusionPolicy extends ClassInclusionPolicy { + public DefaultAllInclusionPolicy(Object reason) { + super(reason); + } + + @Override + public boolean isClassIncluded(Class cls) { + return true; + } + + @Override + public void includeMethod(Executable method) { + bb.postTask(debug -> bb.addRootMethod(method, false, reason)); + } + } + + protected boolean isAccessible(Member member) { + Class cls = member.getDeclaringClass(); + int modifiers = member.getModifiers(); + return isAccessible(cls, modifiers); + } + + protected boolean isAccessible(Class cls, int modifiers) { + return Modifier.isPublic(modifiers) || (!Modifier.isFinal(cls.getModifiers()) && !cls.isSealed() && Modifier.isProtected(modifiers)); + } +} diff --git a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/PointsToAnalysis.java b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/PointsToAnalysis.java index 5def0656c55f..a52ca2062da4 100644 --- a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/PointsToAnalysis.java +++ b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/PointsToAnalysis.java @@ -52,6 +52,7 @@ import com.oracle.graal.pointsto.flow.InvokeTypeFlow; import com.oracle.graal.pointsto.flow.MethodFlowsGraph; import com.oracle.graal.pointsto.flow.MethodFlowsGraphInfo; +import com.oracle.graal.pointsto.flow.MethodTypeFlow; import com.oracle.graal.pointsto.flow.MethodTypeFlowBuilder; import com.oracle.graal.pointsto.flow.OffsetLoadTypeFlow.AbstractUnsafeLoadTypeFlow; import com.oracle.graal.pointsto.flow.OffsetStoreTypeFlow.AbstractUnsafeStoreTypeFlow; @@ -120,8 +121,9 @@ public abstract class PointsToAnalysis extends AbstractAnalysisEngine { @SuppressWarnings("this-escape") public PointsToAnalysis(OptionValues options, AnalysisUniverse universe, HostVM hostVM, AnalysisMetaAccess metaAccess, SnippetReflectionProvider snippetReflectionProvider, - ConstantReflectionProvider constantReflectionProvider, WordTypes wordTypes, UnsupportedFeatures unsupportedFeatures, DebugContext debugContext, TimerCollection timerCollection) { - super(options, universe, hostVM, metaAccess, snippetReflectionProvider, constantReflectionProvider, wordTypes, unsupportedFeatures, debugContext, timerCollection); + ConstantReflectionProvider constantReflectionProvider, WordTypes wordTypes, UnsupportedFeatures unsupportedFeatures, DebugContext debugContext, TimerCollection timerCollection, + ClassInclusionPolicy classInclusionPolicy) { + super(options, universe, hostVM, metaAccess, snippetReflectionProvider, constantReflectionProvider, wordTypes, unsupportedFeatures, debugContext, timerCollection, classInclusionPolicy); this.typeFlowTimer = timerCollection.createTimer("(typeflow)"); this.trackPrimitiveValues = PointstoOptions.TrackPrimitiveValues.getValue(options); this.anyPrimitiveSourceTypeFlow = new AnyPrimitiveSourceTypeFlow(null, null); @@ -315,6 +317,26 @@ public AnalysisMethod addRootMethod(Executable method, boolean invokeSpecial, Ob return addRootMethod(metaAccess.lookupJavaMethod(method), invokeSpecial, reason, otherRoots); } + @Override + public AnalysisMethod forcedAddRootMethod(Executable method, boolean invokeSpecial, Object reason, MultiMethod.MultiMethodKey... otherRoots) { + AnalysisError.guarantee(isBaseLayerAnalysisEnabled()); + PointsToAnalysisMethod analysisMethod = assertPointsToAnalysisMethod(metaAccess.lookupJavaMethod(method)); + postTask(ignore -> { + MethodTypeFlow typeFlow = analysisMethod.getTypeFlow(); + /* + * Calling MethodTypeFlow#ensureFlowsGraphCreated ensures that the method is not + * optimized away by the analysis. + */ + typeFlow.ensureFlowsGraphCreated(this, null); + /* + * Saturating all the parameters of the method allows to enforce that no optimization is + * performed using the types of the parameters of the methods. + */ + typeFlow.getMethodFlowsGraph().saturateAllParameters(this); + }); + return addRootMethod(analysisMethod, invokeSpecial, reason, otherRoots); + } + @Override @SuppressWarnings("try") public AnalysisMethod addRootMethod(AnalysisMethod aMethod, boolean invokeSpecial, Object reason, MultiMethod.MultiMethodKey... otherRoots) { diff --git a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/ReachabilityAnalysis.java b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/ReachabilityAnalysis.java index 9838508c96cf..d37472b5a006 100644 --- a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/ReachabilityAnalysis.java +++ b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/ReachabilityAnalysis.java @@ -87,6 +87,16 @@ public interface ReachabilityAnalysis { */ AnalysisMethod addRootMethod(Executable method, boolean invokeSpecial, Object reason, MultiMethod.MultiMethodKey... otherRoots); + /** + * In addition to register the method as a root, saturate all the parameters. Meant to be used + * under the {@code LayeredBaseImageAnalysis} option to ensure the invocation is replaced by the + * context-insensitive invoke. + * + * @see ReachabilityAnalysis#addRootMethod(AnalysisMethod, boolean, Object, + * MultiMethod.MultiMethodKey...) + */ + AnalysisMethod forcedAddRootMethod(Executable method, boolean invokeSpecial, Object reason, MultiMethod.MultiMethodKey... otherRoots); + default void registerAsFrozenUnsafeAccessed(AnalysisField field) { field.setUnsafeFrozenTypeState(true); } diff --git a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/flow/MethodFlowsGraph.java b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/flow/MethodFlowsGraph.java index 81ee33673555..f2051b871222 100644 --- a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/flow/MethodFlowsGraph.java +++ b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/flow/MethodFlowsGraph.java @@ -439,4 +439,34 @@ void updateInternalState(GraphKind newGraphKind) { linearizeGraph(true); } } + + /** + * Saturates all the formal parameters of the graph. This is expected to be used by layered base + * image analysis. + */ + public void saturateAllParameters(PointsToAnalysis bb) { + AnalysisError.guarantee(bb.isBaseLayerAnalysisEnabled()); + for (TypeFlow parameter : getParameters()) { + if (parameter != null && parameter.canSaturate()) { + parameter.onSaturated(bb); + } + } + + /* + * Even if saturating only parameters already ensures that all code from the base layer is + * reached, it is still necessary to saturate flows from miscEntryFlows, as the extension + * image can introduce new types and methods. For example, an ActualReturnTypeFlow returning + * from an AbstractVirtualInvokeTypeFlow would not be saturated only by saturating + * parameters, as there is no direct use/observer link between the two flows. While all the + * types returned by the implementations from the base image will be in the TypeState, a + * different type might be returned by an implementation introduced by the extension image. + */ + if (miscEntryFlows != null) { + for (TypeFlow miscEntryFlow : miscEntryFlows) { + if (miscEntryFlow != null && miscEntryFlow.canSaturate()) { + miscEntryFlow.onSaturated(bb); + } + } + } + } } diff --git a/substratevm/src/com.oracle.graal.reachability/src/com/oracle/graal/reachability/ReachabilityAnalysisEngine.java b/substratevm/src/com.oracle.graal.reachability/src/com/oracle/graal/reachability/ReachabilityAnalysisEngine.java index 5ca6ed4c41b7..971065b3de62 100644 --- a/substratevm/src/com.oracle.graal.reachability/src/com/oracle/graal/reachability/ReachabilityAnalysisEngine.java +++ b/substratevm/src/com.oracle.graal.reachability/src/com/oracle/graal/reachability/ReachabilityAnalysisEngine.java @@ -32,6 +32,7 @@ import java.util.Set; import com.oracle.graal.pointsto.AbstractAnalysisEngine; +import com.oracle.graal.pointsto.ClassInclusionPolicy; import com.oracle.graal.pointsto.api.HostVM; import com.oracle.graal.pointsto.constraints.UnsupportedFeatures; import com.oracle.graal.pointsto.meta.AnalysisField; @@ -80,8 +81,8 @@ public abstract class ReachabilityAnalysisEngine extends AbstractAnalysisEngine @SuppressWarnings("this-escape") public ReachabilityAnalysisEngine(OptionValues options, AnalysisUniverse universe, HostVM hostVM, AnalysisMetaAccess metaAccess, SnippetReflectionProvider snippetReflectionProvider, ConstantReflectionProvider constantReflectionProvider, WordTypes wordTypes, UnsupportedFeatures unsupportedFeatures, DebugContext debugContext, TimerCollection timerCollection, - ReachabilityMethodProcessingHandler reachabilityMethodProcessingHandler) { - super(options, universe, hostVM, metaAccess, snippetReflectionProvider, constantReflectionProvider, wordTypes, unsupportedFeatures, debugContext, timerCollection); + ReachabilityMethodProcessingHandler reachabilityMethodProcessingHandler, ClassInclusionPolicy classInclusionPolicy) { + super(options, universe, hostVM, metaAccess, snippetReflectionProvider, constantReflectionProvider, wordTypes, unsupportedFeatures, debugContext, timerCollection, classInclusionPolicy); this.executor.init(getTiming()); this.reachabilityTimer = timerCollection.createTimer("(reachability)"); @@ -109,6 +110,11 @@ public AnalysisMethod addRootMethod(Executable method, boolean invokeSpecial, Ob return addRootMethod(metaAccess.lookupJavaMethod(method), invokeSpecial, reason, otherRoots); } + @Override + public AnalysisMethod forcedAddRootMethod(Executable method, boolean invokeSpecial, Object reason, MultiMethod.MultiMethodKey... otherRoots) { + return addRootMethod(method, invokeSpecial, reason, otherRoots); + } + @SuppressWarnings("try") @Override public AnalysisType addRootClass(AnalysisType type, boolean addFields, boolean addArrayClass) { diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/SubstrateOptions.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/SubstrateOptions.java index 3394043aeebc..240b6fc0733a 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/SubstrateOptions.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/SubstrateOptions.java @@ -1040,6 +1040,9 @@ public enum ReportingMode { @Option(help = "Include all classes, methods, fields, and resources from given paths", type = OptionType.Debug) // public static final HostedOptionKey IncludeAllFromPath = new HostedOptionKey<>(LocatableMultiOptionValue.Strings.build()); + @Option(help = "Run layered image base layer open-world analysis. Includes all public types and methods that can be reached using normal Java access rules.")// + public static final HostedOptionKey LayeredBaseImageAnalysis = new HostedOptionKey<>(false); + @Option(help = "Support for calls via the Java Foreign Function and Memory API", type = Expert) // public static final HostedOptionKey ForeignAPISupport = new HostedOptionKey<>(false); diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/NativeImageGenerator.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/NativeImageGenerator.java index a9e4460375ef..405fed6bc7f9 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/NativeImageGenerator.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/NativeImageGenerator.java @@ -54,7 +54,6 @@ import java.util.Set; import java.util.concurrent.atomic.AtomicBoolean; import java.util.function.BooleanSupplier; -import java.util.stream.Stream; import org.graalvm.collections.EconomicMap; import org.graalvm.collections.EconomicSet; @@ -86,6 +85,7 @@ import com.oracle.graal.pointsto.AnalysisObjectScanningObserver; import com.oracle.graal.pointsto.AnalysisPolicy; import com.oracle.graal.pointsto.BigBang; +import com.oracle.graal.pointsto.ClassInclusionPolicy; import com.oracle.graal.pointsto.ObjectScanningObserver; import com.oracle.graal.pointsto.api.PointstoOptions; import com.oracle.graal.pointsto.constraints.UnsupportedFeatureException; @@ -984,7 +984,7 @@ protected void setupNativeImage(OptionValues options, Map bb.registerTypeForBaseImage(cls)); registerEntryPointStubs(entryPoints); } @@ -993,16 +993,6 @@ protected void setupNativeImage(OptionValues options, Map cls) { - String reason = "Included in the base image"; - if (!(Modifier.isAbstract(cls.getModifiers()) || cls.isInterface() || cls.isPrimitive())) { - bb.getMetaAccess().lookupJavaType(cls).registerAsAllocated(reason); - } - Stream methods = Arrays.stream(cls.getDeclaredMethods()).filter(method -> bb.getMetaAccess().lookupJavaMethod(method).getAnnotation(Fold.class) == null); - Stream.concat(Arrays.stream(cls.getDeclaredConstructors()), methods) - .forEach(mthd -> bb.addRootMethod(mthd, false, reason)); - } - protected void registerEntryPointStubs(Map entryPoints) { entryPoints.forEach((method, entryPointData) -> CEntryPointCallStubSupport.singleton().registerStubForMethod(method, () -> entryPointData)); } @@ -1209,6 +1199,9 @@ private static Inflation createBigBang(DebugContext debug, OptionValues options, SnippetReflectionProvider snippetReflectionProvider = aProviders.getSnippetReflection(); ConstantReflectionProvider constantReflectionProvider = aProviders.getConstantReflection(); WordTypes wordTypes = aProviders.getWordTypes(); + String reason = "Included in the base image"; + ClassInclusionPolicy classInclusionPolicy = SubstrateOptions.LayeredBaseImageAnalysis.getValue(options) ? new ClassInclusionPolicy.LayeredBaseImageInclusionPolicy(reason) + : new ClassInclusionPolicy.DefaultAllInclusionPolicy(reason); if (PointstoOptions.UseExperimentalReachabilityAnalysis.getValue(options)) { ReachabilityMethodProcessingHandler reachabilityMethodProcessingHandler; if (PointstoOptions.UseReachabilityMethodSummaries.getValue(options)) { @@ -1219,10 +1212,10 @@ private static Inflation createBigBang(DebugContext debug, OptionValues options, reachabilityMethodProcessingHandler = new DirectMethodProcessingHandler(); } return new NativeImageReachabilityAnalysisEngine(options, aUniverse, aMetaAccess, snippetReflectionProvider, constantReflectionProvider, wordTypes, annotationSubstitutionProcessor, debug, - ImageSingletons.lookup(TimerCollection.class), reachabilityMethodProcessingHandler); + ImageSingletons.lookup(TimerCollection.class), reachabilityMethodProcessingHandler, classInclusionPolicy); } return new NativeImagePointsToAnalysis(options, aUniverse, aMetaAccess, snippetReflectionProvider, constantReflectionProvider, wordTypes, annotationSubstitutionProcessor, - new SubstrateUnsupportedFeatures(), debug, ImageSingletons.lookup(TimerCollection.class)); + new SubstrateUnsupportedFeatures(), debug, ImageSingletons.lookup(TimerCollection.class), classInclusionPolicy); } @SuppressWarnings("try") diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/analysis/NativeImagePointsToAnalysis.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/analysis/NativeImagePointsToAnalysis.java index f9eb3ae3524d..84de638787ed 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/analysis/NativeImagePointsToAnalysis.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/analysis/NativeImagePointsToAnalysis.java @@ -28,6 +28,7 @@ import java.lang.reflect.Method; import java.lang.reflect.Modifier; +import com.oracle.graal.pointsto.ClassInclusionPolicy; import com.oracle.graal.pointsto.PointsToAnalysis; import com.oracle.graal.pointsto.constraints.UnsupportedFeatures; import com.oracle.graal.pointsto.flow.MethodFlowsGraph; @@ -66,8 +67,9 @@ public NativeImagePointsToAnalysis(OptionValues options, AnalysisUniverse univer AnalysisMetaAccess metaAccess, SnippetReflectionProvider snippetReflectionProvider, ConstantReflectionProvider constantReflectionProvider, WordTypes wordTypes, AnnotationSubstitutionProcessor annotationSubstitutionProcessor, UnsupportedFeatures unsupportedFeatures, - DebugContext debugContext, TimerCollection timerCollection) { - super(options, universe, universe.hostVM(), metaAccess, snippetReflectionProvider, constantReflectionProvider, wordTypes, unsupportedFeatures, debugContext, timerCollection); + DebugContext debugContext, TimerCollection timerCollection, ClassInclusionPolicy classInclusionPolicy) { + super(options, universe, universe.hostVM(), metaAccess, snippetReflectionProvider, constantReflectionProvider, wordTypes, unsupportedFeatures, debugContext, timerCollection, + classInclusionPolicy); this.annotationSubstitutionProcessor = annotationSubstitutionProcessor; dynamicHubInitializer = new DynamicHubInitializer(this); diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/analysis/NativeImageReachabilityAnalysisEngine.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/analysis/NativeImageReachabilityAnalysisEngine.java index be0373bf07b4..8b2dc40e7112 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/analysis/NativeImageReachabilityAnalysisEngine.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/analysis/NativeImageReachabilityAnalysisEngine.java @@ -24,6 +24,7 @@ */ package com.oracle.svm.hosted.analysis; +import com.oracle.graal.pointsto.ClassInclusionPolicy; import com.oracle.graal.pointsto.meta.AnalysisField; import com.oracle.graal.pointsto.meta.AnalysisMetaAccess; import com.oracle.graal.pointsto.meta.AnalysisType; @@ -50,9 +51,9 @@ public class NativeImageReachabilityAnalysisEngine extends ReachabilityAnalysisE @SuppressWarnings("this-escape") public NativeImageReachabilityAnalysisEngine(OptionValues options, AnalysisUniverse universe, AnalysisMetaAccess metaAccess, SnippetReflectionProvider snippetReflectionProvider, ConstantReflectionProvider constantReflectionProvider, WordTypes wordTypes, AnnotationSubstitutionProcessor annotationSubstitutionProcessor, DebugContext debugContext, - TimerCollection timerCollection, ReachabilityMethodProcessingHandler reachabilityMethodProcessingHandler) { + TimerCollection timerCollection, ReachabilityMethodProcessingHandler reachabilityMethodProcessingHandler, ClassInclusionPolicy classInclusionPolicy) { super(options, universe, universe.hostVM(), metaAccess, snippetReflectionProvider, constantReflectionProvider, wordTypes, new SubstrateUnsupportedFeatures(), debugContext, timerCollection, - reachabilityMethodProcessingHandler); + reachabilityMethodProcessingHandler, classInclusionPolicy); this.annotationSubstitutionProcessor = annotationSubstitutionProcessor; this.dynamicHubInitializer = new DynamicHubInitializer(this); this.unknownFieldHandler = new CustomTypeFieldHandler(this, metaAccess) { From b901f5b56072e9a6981f6817568886711d24f1bf Mon Sep 17 00:00:00 2001 From: Sacha Coppey Date: Wed, 15 Nov 2023 10:53:03 +0100 Subject: [PATCH 321/593] Ensure all field flows act as if they have a saturated store as input --- .../graal/pointsto/ClassInclusionPolicy.java | 2 +- .../graal/pointsto/PointsToAnalysis.java | 47 +++++++++++++------ .../graal/pointsto/ReachabilityAnalysis.java | 3 ++ .../ReachabilityAnalysisEngine.java | 8 ++++ 4 files changed, 45 insertions(+), 15 deletions(-) diff --git a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/ClassInclusionPolicy.java b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/ClassInclusionPolicy.java index 81a2b7c42cec..6e6c90c2d609 100644 --- a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/ClassInclusionPolicy.java +++ b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/ClassInclusionPolicy.java @@ -101,7 +101,7 @@ public void includeClass(Class cls) { * Includes the given field in the image. */ public void includeField(Field field) { - bb.postTask(debug -> bb.getMetaAccess().lookupJavaField(field).registerAsAccessed(reason)); + bb.postTask(debug -> bb.addRootField(field)); } /** diff --git a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/PointsToAnalysis.java b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/PointsToAnalysis.java index a52ca2062da4..b73e61f43d62 100644 --- a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/PointsToAnalysis.java +++ b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/PointsToAnalysis.java @@ -477,14 +477,29 @@ public AnalysisType addRootField(Class clazz, String fieldName) { for (ResolvedJavaField javaField : type.getInstanceFields(true)) { AnalysisField field = (AnalysisField) javaField; if (field.getName().equals(fieldName)) { - field.registerAsAccessed("root field"); - processRootField(type, field); - return field.getType(); + return addRootField(type, field); } } throw shouldNotReachHere("field not found: " + fieldName); } + @Override + public AnalysisType addRootField(Field field) { + AnalysisField analysisField = getMetaAccess().lookupJavaField(field); + if (analysisField.isStatic()) { + return addRootStaticField(analysisField); + } else { + AnalysisType analysisType = getMetaAccess().lookupJavaType(field.getDeclaringClass()); + return addRootField(analysisType, analysisField); + } + } + + private AnalysisType addRootField(AnalysisType type, AnalysisField field) { + field.registerAsAccessed("root field"); + processRootField(type, field); + return field.getType(); + } + private void processRootField(AnalysisType type, AnalysisField field) { JavaKind storageKind = field.getStorageKind(); if (isSupportedJavaKind(storageKind)) { @@ -509,23 +524,27 @@ public AnalysisType addRootStaticField(Class clazz, String fieldName) { try { reflectField = clazz.getField(fieldName); AnalysisField field = metaAccess.lookupJavaField(reflectField); - field.registerAsAccessed("static root field"); - JavaKind storageKind = field.getStorageKind(); - if (isSupportedJavaKind(storageKind)) { - if (storageKind.isObject()) { - TypeFlow fieldFlow = field.getType().getTypeFlow(this, true); - fieldFlow.addUse(this, field.getStaticFieldFlow()); - } else { - field.getStaticFieldFlow().addState(this, TypeState.anyPrimitiveState()); - } - } - return field.getType(); + return addRootStaticField(field); } catch (NoSuchFieldException e) { throw shouldNotReachHere("field not found: " + fieldName); } } + private AnalysisType addRootStaticField(AnalysisField field) { + field.registerAsAccessed("static root field"); + JavaKind storageKind = field.getStorageKind(); + if (isSupportedJavaKind(storageKind)) { + if (storageKind.isObject()) { + TypeFlow fieldFlow = field.getType().getTypeFlow(this, true); + fieldFlow.addUse(this, field.getStaticFieldFlow()); + } else { + field.getStaticFieldFlow().addState(this, TypeState.anyPrimitiveState()); + } + } + return field.getType(); + } + @Override public void checkUserLimitations() { } diff --git a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/ReachabilityAnalysis.java b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/ReachabilityAnalysis.java index d37472b5a006..ba0296d28a84 100644 --- a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/ReachabilityAnalysis.java +++ b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/ReachabilityAnalysis.java @@ -25,6 +25,7 @@ package com.oracle.graal.pointsto; import java.lang.reflect.Executable; +import java.lang.reflect.Field; import com.oracle.graal.pointsto.meta.AnalysisField; import com.oracle.graal.pointsto.meta.AnalysisMetaAccess; @@ -58,6 +59,8 @@ public interface ReachabilityAnalysis { */ AnalysisType addRootField(Class clazz, String fieldName); + AnalysisType addRootField(Field field); + /** * Registers the method as root. Must be an {@link MultiMethod#ORIGINAL_METHOD}. * diff --git a/substratevm/src/com.oracle.graal.reachability/src/com/oracle/graal/reachability/ReachabilityAnalysisEngine.java b/substratevm/src/com.oracle.graal.reachability/src/com/oracle/graal/reachability/ReachabilityAnalysisEngine.java index 971065b3de62..60662dc50802 100644 --- a/substratevm/src/com.oracle.graal.reachability/src/com/oracle/graal/reachability/ReachabilityAnalysisEngine.java +++ b/substratevm/src/com.oracle.graal.reachability/src/com/oracle/graal/reachability/ReachabilityAnalysisEngine.java @@ -25,6 +25,7 @@ package com.oracle.graal.reachability; import java.lang.reflect.Executable; +import java.lang.reflect.Field; import java.util.ArrayDeque; import java.util.Collections; import java.util.Deque; @@ -149,6 +150,13 @@ public AnalysisType addRootField(Class clazz, String fieldName) { throw AnalysisError.userError("Field not found: " + fieldName); } + @Override + public AnalysisType addRootField(Field field) { + AnalysisField analysisField = getMetaAccess().lookupJavaField(field); + analysisField.registerAsAccessed("root field"); + return analysisField.getType(); + } + @Override public AnalysisMethod addRootMethod(AnalysisMethod m, boolean invokeSpecial, Object reason, MultiMethod.MultiMethodKey... otherRoots) { assert otherRoots.length == 0 : otherRoots; From f1364533c899bc718f7f868d691a0ebd2161f6a5 Mon Sep 17 00:00:00 2001 From: Sacha Coppey Date: Mon, 20 Nov 2023 15:40:15 +0100 Subject: [PATCH 322/593] Include all fields --- .../graal/pointsto/ClassInclusionPolicy.java | 16 ++++++++++------ .../com/oracle/graal/pointsto/api/HostVM.java | 5 +++++ .../src/com/oracle/svm/core/jdk/JRTSupport.java | 9 ++++++--- .../Target_jdk_internal_perf_PerfCounter.java | 6 ++++++ ...et_java_lang_invoke_MethodHandles_Lookup.java | 6 ++++++ .../src/com/oracle/svm/hosted/SVMHost.java | 12 ++++++++++++ .../svm/hosted/jdk/JDKInitializationFeature.java | 2 ++ .../AnnotationSubstitutionProcessor.java | 10 +++++++++- 8 files changed, 56 insertions(+), 10 deletions(-) diff --git a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/ClassInclusionPolicy.java b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/ClassInclusionPolicy.java index 6e6c90c2d609..bb1d4a5df4f7 100644 --- a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/ClassInclusionPolicy.java +++ b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/ClassInclusionPolicy.java @@ -73,7 +73,7 @@ public boolean isMethodIncluded(Executable method) { * Determine if the given field needs to be included in the image according to the policy. */ public boolean isFieldIncluded(Field field) { - return isAccessible(field); + return bb.getHostVM().isFieldIncluded(bb, field); } /** @@ -105,12 +105,16 @@ public void includeField(Field field) { } /** - * The analysis for the base layer of a layered image assumes that any method or field that is - * reachable using the base java access rules can be an entry point. An upper layer does not - * have access to the packages from a lower layer. Thus, only the public classes with their - * public and protected inner classes, methods and fields can be accessed by an upper layer. - * Protected elements from final or sealed class cannot be accessed as an upper layer cannot + * The analysis for the base layer of a layered image assumes that any method that is reachable + * using the base java access rules can be an entry point. An upper layer does not have access + * to the packages from a lower layer. Thus, only the public classes with their public and + * protected inner classes and methods can be accessed by an upper layer. + *

    + * Protected elements from a final or sealed class cannot be accessed as an upper layer cannot * create a new class that extends the final or sealed class. + *

    + * All the fields are included disregarding access rules as a missing field would cause issues + * in the object layout. */ public static class LayeredBaseImageInclusionPolicy extends ClassInclusionPolicy { public LayeredBaseImageInclusionPolicy(Object reason) { diff --git a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/api/HostVM.java b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/api/HostVM.java index 9ec95cd96b31..da1233406b79 100644 --- a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/api/HostVM.java +++ b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/api/HostVM.java @@ -27,6 +27,7 @@ package com.oracle.graal.pointsto.api; import java.lang.reflect.AnnotatedElement; +import java.lang.reflect.Field; import java.util.ArrayList; import java.util.Collection; import java.util.Comparator; @@ -313,6 +314,10 @@ public HostedProviders getProviders(MultiMethod.MultiMethodKey key) { return providers; } + public boolean isFieldIncluded(BigBang bb, Field field) { + return true; + } + /** * Helpers to determine what analysis actions should be taken for a given Multi-Method version. */ diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/JRTSupport.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/JRTSupport.java index 5ff6a4924994..8757de6e5005 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/JRTSupport.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/JRTSupport.java @@ -37,9 +37,6 @@ import java.util.concurrent.ConcurrentHashMap; import java.util.function.BooleanSupplier; -import jdk.graal.compiler.options.Option; -import jdk.graal.compiler.options.OptionType; - import com.oracle.svm.core.annotate.Alias; import com.oracle.svm.core.annotate.Delete; import com.oracle.svm.core.annotate.RecomputeFieldValue; @@ -52,6 +49,9 @@ import com.oracle.svm.core.option.HostedOptionKey; import com.oracle.svm.core.util.VMError; +import jdk.graal.compiler.options.Option; +import jdk.graal.compiler.options.OptionType; + /** * Support to access system Java modules and the jrt:// file system. * @@ -154,6 +154,9 @@ final class Target_jdk_internal_jimage_ImageReaderFactory_JRTEnabled { */ @TargetClass(className = "jdk.internal.module.SystemModuleFinders", innerClass = "SystemImage", onlyWith = JRTDisabled.class) final class Target_jdk_internal_module_SystemModuleFinders_SystemImage_JRTDisabled { + @Delete // + static Target_jdk_internal_jimage_ImageReader READER; + @Substitute static Target_jdk_internal_jimage_ImageReader reader() { throw VMError.unsupportedFeature("JRT file system is disabled"); diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmstat/Target_jdk_internal_perf_PerfCounter.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmstat/Target_jdk_internal_perf_PerfCounter.java index b0a4f52c059b..e4a5dbca516f 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmstat/Target_jdk_internal_perf_PerfCounter.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmstat/Target_jdk_internal_perf_PerfCounter.java @@ -24,6 +24,9 @@ */ package com.oracle.svm.core.jvmstat; +import java.nio.LongBuffer; + +import com.oracle.svm.core.annotate.Delete; import com.oracle.svm.core.annotate.Substitute; import com.oracle.svm.core.annotate.TargetClass; @@ -34,6 +37,9 @@ */ @TargetClass(className = "jdk.internal.perf.PerfCounter") final class Target_jdk_internal_perf_PerfCounter { + @Delete // + private LongBuffer lb; + @Substitute @SuppressWarnings("static-method") public long get() { diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/methodhandles/Target_java_lang_invoke_MethodHandles_Lookup.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/methodhandles/Target_java_lang_invoke_MethodHandles_Lookup.java index 1b1e2093979e..b9e2e0ed7593 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/methodhandles/Target_java_lang_invoke_MethodHandles_Lookup.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/methodhandles/Target_java_lang_invoke_MethodHandles_Lookup.java @@ -28,6 +28,7 @@ import java.lang.invoke.MethodHandle; import java.lang.invoke.MethodHandles; +import java.util.concurrent.ConcurrentHashMap; import com.oracle.svm.core.SubstrateUtil; import com.oracle.svm.core.annotate.Alias; @@ -40,6 +41,11 @@ @TargetClass(value = MethodHandles.class, innerClass = "Lookup") final class Target_java_lang_invoke_MethodHandles_Lookup { + // Checkstyle: stop + @Delete // + static ConcurrentHashMap LOOKASIDE_TABLE; + // Checkstyle: resume + @SuppressWarnings("static-method") @Substitute public Class defineClass(@SuppressWarnings("unused") byte[] bytes) { diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/SVMHost.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/SVMHost.java index ce07a00c936c..8213286efb54 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/SVMHost.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/SVMHost.java @@ -28,6 +28,7 @@ import java.lang.ref.Reference; import java.lang.ref.SoftReference; import java.lang.reflect.AnnotatedElement; +import java.lang.reflect.Field; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.lang.reflect.Modifier; @@ -73,6 +74,7 @@ import com.oracle.svm.core.RuntimeAssertionsSupport; import com.oracle.svm.core.SubstrateOptions; import com.oracle.svm.core.SubstrateOptions.OptimizationLevel; +import com.oracle.svm.core.annotate.InjectAccessors; import com.oracle.svm.core.classinitialization.EnsureClassInitializedNode; import com.oracle.svm.core.graal.meta.SubstrateForeignCallLinkage; import com.oracle.svm.core.graal.meta.SubstrateForeignCallsProvider; @@ -92,6 +94,7 @@ import com.oracle.svm.core.util.HostedStringDeduplication; import com.oracle.svm.core.util.VMError; import com.oracle.svm.hosted.ameta.FieldValueInterceptionSupport; +import com.oracle.svm.hosted.analysis.NativeImagePointsToAnalysis; import com.oracle.svm.hosted.analysis.SVMParsingSupport; import com.oracle.svm.hosted.classinitialization.ClassInitializationOptions; import com.oracle.svm.hosted.classinitialization.ClassInitializationSupport; @@ -807,6 +810,15 @@ public boolean platformSupported(AnnotatedElement element) { return false; } + @Override + public boolean isFieldIncluded(BigBang bb, Field field) { + if (bb instanceof NativeImagePointsToAnalysis nativeImagePointsToAnalysis) { + AnnotationSubstitutionProcessor annotationSubstitutionProcessor = nativeImagePointsToAnalysis.getAnnotationSubstitutionProcessor(); + return !annotationSubstitutionProcessor.isDeleted(field) && !annotationSubstitutionProcessor.isAnnotationPresent(field, InjectAccessors.class); + } + return super.isFieldIncluded(bb, field); + } + private final List> neverInlineTrivialHandlers = new CopyOnWriteArrayList<>(); public void registerNeverInlineTrivialHandler(BiPredicate handler) { diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/jdk/JDKInitializationFeature.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/jdk/JDKInitializationFeature.java index bb86216030bc..ab69e9166381 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/jdk/JDKInitializationFeature.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/jdk/JDKInitializationFeature.java @@ -196,6 +196,8 @@ public void afterRegistration(AfterRegistrationAccess access) { rci.rerunInitialization("jdk.internal.foreign.SystemLookup$WindowsFallbackSymbols", "Does not work on non-Windows modular images"); + rci.rerunInitialization("jdk.internal.logger.LoggerFinderLoader", "Contains a static field with a FilePermission value"); + /* * The local class Holder in FallbackLinker#getInstance fails the build time initialization * starting JDK 22. There is no way to obtain a list of local classes using reflection. They diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/substitute/AnnotationSubstitutionProcessor.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/substitute/AnnotationSubstitutionProcessor.java index ac5460c17e89..7752e66bf8f3 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/substitute/AnnotationSubstitutionProcessor.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/substitute/AnnotationSubstitutionProcessor.java @@ -197,9 +197,17 @@ public boolean isDeleted(ResolvedJavaField field) { if (deleteAnnotations.get(field) != null) { return true; } + return isAnnotationPresent(field, Delete.class); + } + + public boolean isAnnotationPresent(Field field, Class annotationClass) { + return isAnnotationPresent(metaAccess.lookupJavaField(field), annotationClass); + } + + public boolean isAnnotationPresent(ResolvedJavaField field, Class annotationClass) { ResolvedJavaField substitutionField = fieldSubstitutions.get(field); if (substitutionField != null) { - return AnnotationAccess.isAnnotationPresent(substitutionField, Delete.class); + return AnnotationAccess.isAnnotationPresent(substitutionField, annotationClass); } return false; } From 5ab9db9bab89b86a78057601023bd7fc4b15540d Mon Sep 17 00:00:00 2001 From: Sacha Coppey Date: Fri, 8 Dec 2023 14:25:02 +0100 Subject: [PATCH 323/593] Include all fields for all reachable types --- .../graal/pointsto/ClassInclusionPolicy.java | 3 +++ .../com/oracle/svm/core/SubstrateOptions.java | 4 ++++ .../svm/core/jdk/JVMCISubstitutions.java | 4 ++++ .../svm/core/jdk/JavaLangSubstitutions.java | 4 ++++ .../svm/hosted/NativeImageGenerator.java | 19 ++++++++++------ .../src/com/oracle/svm/hosted/SVMHost.java | 22 +++++++++++++++++++ .../analysis/NativeImagePointsToAnalysis.java | 13 +++++++++-- 7 files changed, 60 insertions(+), 9 deletions(-) diff --git a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/ClassInclusionPolicy.java b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/ClassInclusionPolicy.java index bb1d4a5df4f7..5e1c8bdb0963 100644 --- a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/ClassInclusionPolicy.java +++ b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/ClassInclusionPolicy.java @@ -73,6 +73,9 @@ public boolean isMethodIncluded(Executable method) { * Determine if the given field needs to be included in the image according to the policy. */ public boolean isFieldIncluded(Field field) { + if (!bb.getHostVM().platformSupported(field)) { + return false; + } return bb.getHostVM().isFieldIncluded(bb, field); } diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/SubstrateOptions.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/SubstrateOptions.java index 240b6fc0733a..62f139a15cb3 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/SubstrateOptions.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/SubstrateOptions.java @@ -1040,6 +1040,10 @@ public enum ReportingMode { @Option(help = "Include all classes, methods, fields, and resources from given paths", type = OptionType.Debug) // public static final HostedOptionKey IncludeAllFromPath = new HostedOptionKey<>(LocatableMultiOptionValue.Strings.build()); + public static boolean includeAll() { + return IncludeAllFromPath.hasBeenSet() || IncludeAllFromPath.hasBeenSet(); + } + @Option(help = "Run layered image base layer open-world analysis. Includes all public types and methods that can be reached using normal Java access rules.")// public static final HostedOptionKey LayeredBaseImageAnalysis = new HostedOptionKey<>(false); diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/JVMCISubstitutions.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/JVMCISubstitutions.java index bdd2904b7cc9..efae01988ad5 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/JVMCISubstitutions.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/JVMCISubstitutions.java @@ -32,6 +32,7 @@ import com.oracle.svm.core.SubstrateUtil; import com.oracle.svm.core.annotate.Alias; +import com.oracle.svm.core.annotate.Delete; import com.oracle.svm.core.annotate.Substitute; import com.oracle.svm.core.annotate.TargetClass; @@ -51,6 +52,9 @@ public boolean getAsBoolean() { */ @TargetClass(value = Services.class, onlyWith = IsNotLibgraal.class) final class Target_jdk_vm_ci_services_Services { + @Delete // + static Map savedProperties; + @Substitute public static Map getSavedProperties() { return SystemPropertiesSupport.singleton().getSavedProperties(); diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/JavaLangSubstitutions.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/JavaLangSubstitutions.java index 2c9f7be081cd..a68c7ea8346a 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/JavaLangSubstitutions.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/JavaLangSubstitutions.java @@ -576,6 +576,10 @@ final class Target_jdk_internal_loader_ClassLoaders { @TargetClass(value = jdk.internal.loader.BootLoader.class) final class Target_jdk_internal_loader_BootLoader { + // Checkstyle: stop + @Delete // + static String JAVA_HOME; + // Checkstyle: resume @Substitute static Package getDefinedPackage(String name) { diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/NativeImageGenerator.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/NativeImageGenerator.java index 405fed6bc7f9..31ce3158dc47 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/NativeImageGenerator.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/NativeImageGenerator.java @@ -1709,13 +1709,7 @@ public static void checkName(String name, AnalysisMethod method, BigBang bb) { * The same holds for "hotspot" elements, which come from the hosting HotSpot VM, unless * they are JDK internal types. */ - String lname = name.toLowerCase(); - String message = null; - if (lname.contains("hosted")) { - message = "Hosted element used at run time: " + name; - } else if (!name.startsWith("jdk.internal") && lname.contains("hotspot")) { - message = "HotSpot element used at run time: " + name; - } + String message = checkName(name); if (message != null) { if (bb != null) { @@ -1726,6 +1720,17 @@ public static void checkName(String name, AnalysisMethod method, BigBang bb) { } } + public static String checkName(String name) { + String lname = name.toLowerCase(); + String message = null; + if (lname.contains("hosted")) { + message = "Hosted element used at run time: " + name; + } else if (!name.startsWith("jdk.internal") && lname.contains("hotspot")) { + message = "HotSpot element used at run time: " + name; + } + return message; + } + @SuppressWarnings("try") protected void processNativeLibraryImports(NativeLibraries nativeLibs, MetaAccessProvider metaAccess, ClassInitializationSupport classInitializationSupport) { diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/SVMHost.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/SVMHost.java index 8213286efb54..5a1148b2696a 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/SVMHost.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/SVMHost.java @@ -75,6 +75,7 @@ import com.oracle.svm.core.SubstrateOptions; import com.oracle.svm.core.SubstrateOptions.OptimizationLevel; import com.oracle.svm.core.annotate.InjectAccessors; +import com.oracle.svm.core.c.CGlobalData; import com.oracle.svm.core.classinitialization.EnsureClassInitializedNode; import com.oracle.svm.core.graal.meta.SubstrateForeignCallLinkage; import com.oracle.svm.core.graal.meta.SubstrateForeignCallsProvider; @@ -91,6 +92,7 @@ import com.oracle.svm.core.option.HostedOptionKey; import com.oracle.svm.core.option.SubstrateOptionsParser; import com.oracle.svm.core.thread.ContinuationSupport; +import com.oracle.svm.core.util.Counter; import com.oracle.svm.core.util.HostedStringDeduplication; import com.oracle.svm.core.util.VMError; import com.oracle.svm.hosted.ameta.FieldValueInterceptionSupport; @@ -812,6 +814,26 @@ public boolean platformSupported(AnnotatedElement element) { @Override public boolean isFieldIncluded(BigBang bb, Field field) { + /* + * Fields of type CGlobalData can use a CGlobalDataFactory which must not be reachable at + * run time + */ + if (field.getType().equals(CGlobalData.class)) { + return false; + } + /* This field cannot be written to (see documentation) */ + if (field.equals(ReflectionUtil.lookupField(Counter.Group.class, "enabled"))) { + return false; + } + /* Fields with those names are not allowed in the image */ + if (NativeImageGenerator.checkName(field.getType().getName() + "." + field.getName()) != null) { + return false; + } + /* Fields from this package should not be in the image */ + if (field.getDeclaringClass().getName().startsWith("jdk.graal.compiler")) { + return false; + } + /* Fields that are deleted or substituted should not be in the image */ if (bb instanceof NativeImagePointsToAnalysis nativeImagePointsToAnalysis) { AnnotationSubstitutionProcessor annotationSubstitutionProcessor = nativeImagePointsToAnalysis.getAnnotationSubstitutionProcessor(); return !annotationSubstitutionProcessor.isDeleted(field) && !annotationSubstitutionProcessor.isAnnotationPresent(field, InjectAccessors.class); diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/analysis/NativeImagePointsToAnalysis.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/analysis/NativeImagePointsToAnalysis.java index 84de638787ed..e0eebede8300 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/analysis/NativeImagePointsToAnalysis.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/analysis/NativeImagePointsToAnalysis.java @@ -27,12 +27,14 @@ import java.lang.reflect.Executable; import java.lang.reflect.Method; import java.lang.reflect.Modifier; +import java.util.Arrays; import com.oracle.graal.pointsto.ClassInclusionPolicy; import com.oracle.graal.pointsto.PointsToAnalysis; import com.oracle.graal.pointsto.constraints.UnsupportedFeatures; import com.oracle.graal.pointsto.flow.MethodFlowsGraph; import com.oracle.graal.pointsto.flow.MethodTypeFlowBuilder; +import com.oracle.graal.pointsto.infrastructure.OriginalClassProvider; import com.oracle.graal.pointsto.meta.AnalysisField; import com.oracle.graal.pointsto.meta.AnalysisMetaAccess; import com.oracle.graal.pointsto.meta.AnalysisMethod; @@ -40,6 +42,7 @@ import com.oracle.graal.pointsto.meta.AnalysisUniverse; import com.oracle.graal.pointsto.meta.PointsToAnalysisMethod; import com.oracle.graal.pointsto.util.TimerCollection; +import com.oracle.svm.core.SubstrateOptions; import com.oracle.svm.hosted.HostedConfiguration; import com.oracle.svm.hosted.SVMHost; import com.oracle.svm.hosted.ameta.CustomTypeFieldHandler; @@ -116,7 +119,14 @@ public void onFieldAccessed(AnalysisField field) { @Override public void onTypeReachable(AnalysisType type) { - postTask(d -> type.getInitializeMetaDataTask().ensureDone()); + postTask(d -> { + type.getInitializeMetaDataTask().ensureDone(); + if (SubstrateOptions.includeAll()) { + Arrays.stream(OriginalClassProvider.getJavaClass(type).getDeclaredFields()) + .filter(classInclusionPolicy::isFieldIncluded) + .forEach(classInclusionPolicy::includeField); + } + }); } @Override @@ -213,5 +223,4 @@ private static Class findResolutionError /* Not matching method found at all. */ return AbstractMethodError.class; } - } From 09e500ad1e427c03e0652828daa3fe037781c4f2 Mon Sep 17 00:00:00 2001 From: Tom Shull Date: Thu, 21 Dec 2023 18:28:14 +0100 Subject: [PATCH 324/593] try to use calltree for call traces --- .../runtimecompilation/CallTreeInfo.java | 78 +++++++++++-------- .../RuntimeCompilationFeature.java | 10 ++- .../oracle/svm/truffle/TruffleFeature.java | 6 +- 3 files changed, 59 insertions(+), 35 deletions(-) diff --git a/substratevm/src/com.oracle.svm.graal/src/com/oracle/svm/graal/hosted/runtimecompilation/CallTreeInfo.java b/substratevm/src/com.oracle.svm.graal/src/com/oracle/svm/graal/hosted/runtimecompilation/CallTreeInfo.java index 0ed531bea9bb..9a84a0c8a8ef 100644 --- a/substratevm/src/com.oracle.svm.graal/src/com/oracle/svm/graal/hosted/runtimecompilation/CallTreeInfo.java +++ b/substratevm/src/com.oracle.svm.graal/src/com/oracle/svm/graal/hosted/runtimecompilation/CallTreeInfo.java @@ -53,8 +53,7 @@ public final class CallTreeInfo { private final Map runtimeCompilations; private Map runtimeCandidateMap; private Map analysisMethodMap; - private boolean callTreeInitialized = false; - private boolean callTraceInitialized = false; + private boolean initialized = false; private CallTreeInfo(Map runtimeCompilations) { this.runtimeCompilations = runtimeCompilations; @@ -82,12 +81,7 @@ public static CallTreeInfo create(AnalysisUniverse aUniverse, Map(); runtimeCandidateMap = new HashMap<>(); @@ -131,22 +125,22 @@ private void initializeCallTraceInfo() { } } - public void initializeCallTreeInfo(Set registeredRoots) { - if (callTreeInitialized) { + public void initialize(Set registeredRoots) { + if (initialized) { return; } - initializeCallTraceInfo(); - callTreeInitialized = true; + initializeCallerInfo(); + initialized = true; // ensure invokeInfo calculated Queue worklist = new LinkedList<>(); /* - * First initialize all nodes with no callers. + * First initialize all nodes which are registered roots */ for (var methodNode : analysisMethodMap.values()) { - if (methodNode.getCallers().isEmpty() || registeredRoots.contains(methodNode.method.getMultiMethod(ORIGINAL_METHOD))) { + if (registeredRoots.contains(methodNode.method.getMultiMethod(ORIGINAL_METHOD))) { worklist.add(methodNode); methodNode.trace = new TraceInfo(0, new BytecodePosition(null, methodNode.method, BytecodeFrame.UNKNOWN_BCI), null); } @@ -189,8 +183,8 @@ public void initializeCallTreeInfo(Set registeredRoots) { private static final String[] UNKNOWN_TRACE = new String[]{"Unknown"}; private static final String[] EMPTY_STRING = new String[0]; - public static String[] getCallTrace(CallTreeInfo callTreeInfo, AnalysisMethod method) { - callTreeInfo.initializeCallTraceInfo(); + static String[] getCallTrace(CallTreeInfo callTreeInfo, AnalysisMethod method, Set registeredRuntimeCompilations) { + callTreeInfo.initialize(registeredRuntimeCompilations); MethodNode methodNode = callTreeInfo.analysisMethodMap.get(method); if (methodNode == null) { return UNKNOWN_TRACE; @@ -201,8 +195,8 @@ public static String[] getCallTrace(CallTreeInfo callTreeInfo, AnalysisMethod me return trace.toArray(EMPTY_STRING); } - public static String[] getCallTrace(CallTreeInfo callTreeInfo, RuntimeCompilationCandidate candidate) { - callTreeInfo.initializeCallTraceInfo(); + static String[] getCallTrace(CallTreeInfo callTreeInfo, RuntimeCompilationCandidate candidate, Set registeredRuntimeCompilations) { + callTreeInfo.initialize(registeredRuntimeCompilations); InvokeNode invokeNode = callTreeInfo.runtimeCandidateMap.get(candidate); if (invokeNode == null) { return UNKNOWN_TRACE; @@ -214,26 +208,48 @@ public static String[] getCallTrace(CallTreeInfo callTreeInfo, RuntimeCompilatio } private static void findCallTraceHelper(ArrayList trace, MethodNode first) { - Set covered = new HashSet<>(); - MethodNode current = first; - covered.add(current); - - while (current != null) { - // find parent - MethodNode parent = null; - for (InvokeNode caller : current.getCallers()) { - if (covered.add(caller.method)) { + if (first.trace != null) { + /* + * If there is a known trace from root, then we can return this + */ + MethodNode current = first; + while (current != null) { + MethodNode parent = null; + InvokeNode caller = current.trace.invokeParent; + if (caller != null) { parent = caller.method; trace.add(caller.position.toString()); - break; } + current = parent; + } + trace.add("[Root]"); + + } else { + /* + * Otherwise we will walk an arbitrary caller until there is not a caller or we + * encounter a cycle. + */ + Set covered = new HashSet<>(); + MethodNode current = first; + covered.add(current); + + while (current != null) { + // find parent + MethodNode parent = null; + for (InvokeNode caller : current.getCallers()) { + if (covered.add(caller.method)) { + parent = caller.method; + trace.add(caller.position.toString()); + break; + } + } + current = parent; } - current = parent; } } public static void printCallTree(CallTreeInfo info, Set registeredRuntimeCompilations) { - info.initializeCallTreeInfo(registeredRuntimeCompilations); + info.initialize(registeredRuntimeCompilations); System.out.println("depth;method;invoke position"); for (MethodNode methodNode : info.analysisMethodMap.values()) { @@ -255,7 +271,7 @@ private static void printCallTreeNode(MethodNode node) { } public static void printDeepestPath(CallTreeInfo info, Set registeredRuntimeCompilations) { - info.initializeCallTreeInfo(registeredRuntimeCompilations); + info.initialize(registeredRuntimeCompilations); Optional deepestNode = info.analysisMethodMap.values().stream().max(Comparator.comparingInt(t -> t.trace == null ? -1 : t.trace.level)); diff --git a/substratevm/src/com.oracle.svm.graal/src/com/oracle/svm/graal/hosted/runtimecompilation/RuntimeCompilationFeature.java b/substratevm/src/com.oracle.svm.graal/src/com/oracle/svm/graal/hosted/runtimecompilation/RuntimeCompilationFeature.java index 2ed14e40d39d..e110574e9b3b 100644 --- a/substratevm/src/com.oracle.svm.graal/src/com/oracle/svm/graal/hosted/runtimecompilation/RuntimeCompilationFeature.java +++ b/substratevm/src/com.oracle.svm.graal/src/com/oracle/svm/graal/hosted/runtimecompilation/RuntimeCompilationFeature.java @@ -300,6 +300,14 @@ public void initializeAnalysisProviders(BigBang bb, Function violation : neverPartOfCompilationViolations) { System.out.println("called from"); System.out.println("(inlined call path): " + violation.getRight()); - for (String item : CallTreeInfo.getCallTrace(treeInfo, (AnalysisMethod) violation.getLeft())) { + for (String item : runtimeCompilation.getCallTrace(treeInfo, (AnalysisMethod) violation.getLeft())) { System.out.println(" " + item); } } From 074574ccffbc59228f810b79fc95d626f3c52055 Mon Sep 17 00:00:00 2001 From: Christian Haeubl Date: Tue, 19 Dec 2023 14:29:14 +0100 Subject: [PATCH 325/593] Remove Heap.allowPageSizeMismatch(). --- .../src/com/oracle/svm/core/genscavenge/HeapImpl.java | 6 ------ .../svm/core/graal/snippets/CEntryPointSnippets.java | 4 +--- .../src/com/oracle/svm/core/heap/Heap.java | 9 --------- 3 files changed, 1 insertion(+), 18 deletions(-) diff --git a/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/HeapImpl.java b/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/HeapImpl.java index 9ec3bd2c2b10..21cbe165518b 100644 --- a/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/HeapImpl.java +++ b/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/HeapImpl.java @@ -426,12 +426,6 @@ public int getImageHeapOffsetInAddressSpace() { return 0; } - @Fold - @Override - public boolean allowPageSizeMismatch() { - return true; - } - @Override public boolean walkImageHeapObjects(ObjectVisitor visitor) { VMOperation.guaranteeInProgressAtSafepoint("Must only be called at a safepoint"); diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/graal/snippets/CEntryPointSnippets.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/graal/snippets/CEntryPointSnippets.java index 83129a008571..480183ad2464 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/graal/snippets/CEntryPointSnippets.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/graal/snippets/CEntryPointSnippets.java @@ -72,7 +72,6 @@ import com.oracle.svm.core.graal.nodes.CEntryPointLeaveNode; import com.oracle.svm.core.graal.nodes.CEntryPointUtilityNode; import com.oracle.svm.core.graal.nodes.WriteCurrentVMThreadNode; -import com.oracle.svm.core.heap.Heap; import com.oracle.svm.core.heap.PhysicalMemory; import com.oracle.svm.core.heap.ReferenceHandler; import com.oracle.svm.core.heap.ReferenceHandlerThread; @@ -224,8 +223,7 @@ private static int createIsolate(CEntryPointCreateIsolateParameters providedPara UnsignedWord runtimePageSize = VirtualMemoryProvider.get().getGranularity(); UnsignedWord imagePageSize = WordFactory.unsigned(SubstrateOptions.getPageSize()); - boolean validPageSize = runtimePageSize.equal(imagePageSize) || - (Heap.getHeap().allowPageSizeMismatch() && UnsignedUtils.isAMultiple(imagePageSize, runtimePageSize)); + boolean validPageSize = UnsignedUtils.isAMultiple(imagePageSize, runtimePageSize); if (!validPageSize) { return CEntryPointErrors.PAGE_SIZE_CHECK_FAILED; } diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/heap/Heap.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/heap/Heap.java index 103ee02581c7..f62a7f622371 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/heap/Heap.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/heap/Heap.java @@ -36,7 +36,6 @@ import org.graalvm.word.Pointer; import org.graalvm.word.UnsignedWord; -import com.oracle.svm.core.SubstrateOptions; import com.oracle.svm.core.Uninterruptible; import com.oracle.svm.core.hub.DynamicHub; import com.oracle.svm.core.hub.PredefinedClassesSupport; @@ -157,14 +156,6 @@ public void visitLoadedClasses(Consumer> visitor) { @Fold public abstract int getImageHeapOffsetInAddressSpace(); - /** - * Returns whether the runtime page size doesn't have to match the page size set at image - * creation ({@link SubstrateOptions#getPageSize()}). If there is a mismatch, then the page size - * set at image creation must be a multiple of the runtime page size. - */ - @Fold - public abstract boolean allowPageSizeMismatch(); - /** * Returns true if the given object is located in the image heap. */ From 954deb2367d5ef826a36cc2c049a613ff6c7f8f7 Mon Sep 17 00:00:00 2001 From: Lesia Chaban Date: Thu, 21 Dec 2023 15:51:12 +0200 Subject: [PATCH 326/593] Add info about storing configs in META-INF/native-image/ directory --- docs/reference-manual/native-image/JNI.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/docs/reference-manual/native-image/JNI.md b/docs/reference-manual/native-image/JNI.md index 727b41a70f20..88a1b670664b 100644 --- a/docs/reference-manual/native-image/JNI.md +++ b/docs/reference-manual/native-image/JNI.md @@ -79,6 +79,8 @@ The JNI functions `FromReflectedMethod` and `ToReflectedMethod` can be used to o The functions `FromReflectedField` and `ToReflectedField` convert between `jfieldID` and `java.lang.reflect.Field`. In order to use these functions, [reflection support](Reflection.md) must be enabled and the methods and fields in question must be included in the reflection configuration, which is specified with `-H:ReflectionConfigurationFiles=`. +The generated configuration files can be supplied to the native-image tool by placing them in a META-INF/native-image/ directory on the class path. This directory (or any of its subdirectories) is searched for files with the names jni-config.json, reflect-config.json, proxy-config.json, resource-config.json, predefined-classes-config.json, serialization-config.json which are then automatically included in the build process. Not all of those files must be present. When multiple files with the same name are found, all of them are considered. + ## Object Handles JNI does not permit direct access to Java objects. @@ -195,3 +197,4 @@ For that reason, it can be beneficial to wrap synchronization in Java code. - [Interoperability with Native Code](InteropWithNativeCode.md) - [JNI Invocation API](JNIInvocationAPI.md) - [Reachability Metadata: Java Native Interface](ReachabilityMetadata.md#java-native-interface) +- [Collect Metadata with the Tracing Agent](https://www.graalvm.org/latest/reference-manual/native-image/metadata/AutomaticMetadataCollection/) \ No newline at end of file From bb80d4c3d5ab145dc9e2e80cc61754d663634d41 Mon Sep 17 00:00:00 2001 From: Lesia Chaban Date: Thu, 21 Dec 2023 16:31:57 +0200 Subject: [PATCH 327/593] Fix code boxes rendering --- docs/reference-manual/native-image/JNI.md | 14 ++++++++------ .../native-image/guides/use-system-properties.md | 7 ++++--- 2 files changed, 12 insertions(+), 9 deletions(-) diff --git a/docs/reference-manual/native-image/JNI.md b/docs/reference-manual/native-image/JNI.md index 88a1b670664b..78dcb7e3c116 100644 --- a/docs/reference-manual/native-image/JNI.md +++ b/docs/reference-manual/native-image/JNI.md @@ -33,7 +33,7 @@ The Native Image JNI implementation supports both approaches. ## Loading Native Libraries When loading native libraries using `System.loadLibrary()` (and related APIs), the native image will search the -directory containing the native image before searching the Java library path. So as long as the native libraries +directory containing the native library before searching the Java library path. So as long as the native libraries to be loaded are in the same directory as the native image, no other settings should be necessary. ## Reflection Metadata @@ -41,19 +41,22 @@ to be loaded are in the same directory as the native image, no other settings sh JNI supports looking up classes by their names, and looking up methods and fields by their names and signatures. This requires keeping the necessary metadata for these lookups around. The `native-image` builder must know beforehand which items will be looked up in case they might not be reachable otherwise and therefore would not be included in a native image. -Moreover, `native-image` must generate call wrapper code ahead-of-time for any method that can be called via JNI. +Moreover, `native-image` must generate wrapper code ahead-of-time for any method that can be called via JNI. Therefore, specifying a concise list of items that need to be accessible via JNI guarantees their availability and allows for a smaller footprint. Such a list can be specified with the following image build argument: ```shell -H:JNIConfigurationFiles=/path/to/jniconfig ``` -Here, `jniconfig` is a JSON configuration file. +Here, _jniconfig_ is a JSON configuration file. Check the JSON schema for specifing JNI metadata [here](ReachabilityMetadata.md#specifying-metadata-with-json). The `native-image` builder generates JNI reflection metadata for all classes, methods, and fields referenced in the configuration file. More than one JNI configuration can be used by specifying multiple paths for `JNIConfigurationFiles` and separating them with `,`. Also, `-H:JNIConfigurationResources` can be specified to load one or several configuration files from the image build's class path, such as from a JAR file. +The JNI configuration can be collected automatically using the [Tracing Agent](AutomaticMetadataCollection.md), provided with GraalVM. The agent tracks all usages of dynamic features during application execution on a regular Java VM. When the application completes and the JVM exits, the agent writes configuration to JSON files in the specified output directory. +If you move the generated configuration files from that output directory to _META-INF/native-image/_ on the class path, they are then automatically included at build time. The `native-image` builder searches for _META-INF/native-image/_ and its subdirectories for files named _jni-config.json_, _reflect-config.json_, and others. + Alternatively, a custom `Feature` implementation can register program elements before and during the analysis phase of the image build using the `JNIRuntimeAccess` class. For example: ```java class JNIRegistrationFeature implements Feature { @@ -75,12 +78,11 @@ To activate the custom feature `--features= Date: Fri, 22 Dec 2023 10:36:40 +0100 Subject: [PATCH 328/593] Update Maven project basic structure in docs/reference-manual/native-image/Resources.md --- docs/reference-manual/native-image/Resources.md | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/docs/reference-manual/native-image/Resources.md b/docs/reference-manual/native-image/Resources.md index bdb7fbb4e131..927e14593138 100644 --- a/docs/reference-manual/native-image/Resources.md +++ b/docs/reference-manual/native-image/Resources.md @@ -43,15 +43,12 @@ To see which resources are included in the native executable, use the option `-H Given this project structure: ``` -my-app-root +app-root └── src - ├── main - │   └── com.my.app - │   ├── Resource0.txt - │   └── Resource1.txt - └── resources - ├── Resource2.txt - └── Resource3.txt + └── main + └── resources + ├── Resource0.txt + └── Resource1.txt ``` Then: From 99399552909fe70233126eba28b31a2f335c0aa1 Mon Sep 17 00:00:00 2001 From: Fabio Niephaus Date: Fri, 22 Dec 2023 17:29:27 +0100 Subject: [PATCH 329/593] Generate `List.of()` instead of `Arrays.asList()`. --- .../com/oracle/truffle/dsl/processor/OptionProcessor.java | 4 ++-- .../dsl/processor/generator/FlatNodeGenFactory.java | 2 +- .../truffle/dsl/processor/generator/NodeCodeGenerator.java | 6 +----- .../dsl/processor/generator/NodeFactoryFactory.java | 7 +++---- .../truffle/dsl/processor/library/LibraryGenerator.java | 5 ++--- 5 files changed, 9 insertions(+), 15 deletions(-) diff --git a/truffle/src/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/OptionProcessor.java b/truffle/src/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/OptionProcessor.java index a37fc60d4871..8aa99b2ba4a4 100644 --- a/truffle/src/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/OptionProcessor.java +++ b/truffle/src/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/OptionProcessor.java @@ -505,7 +505,7 @@ private static CodeTypeElement generateDescriptors(ProcessorContext context, Ele if (model.options.isEmpty()) { builder.startStaticCall(context.getType(Collections.class), " emptyList().iterator").end(); } else { - builder.startStaticCall(context.getType(Arrays.class), "asList"); + builder.startStaticCall(context.getType(List.class), "of"); for (OptionInfo info : model.options) { builder.startGroup(); builder.startIndention(); @@ -514,7 +514,7 @@ private static CodeTypeElement generateDescriptors(ProcessorContext context, Ele builder.end(); builder.end(); } - builder.end(); /// asList call + builder.end(); /// of call builder.newLine(); builder.startCall("", "iterator").end(); } diff --git a/truffle/src/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/generator/FlatNodeGenFactory.java b/truffle/src/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/generator/FlatNodeGenFactory.java index 6d78553bf75c..3a3d4972a374 100644 --- a/truffle/src/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/generator/FlatNodeGenFactory.java +++ b/truffle/src/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/generator/FlatNodeGenFactory.java @@ -1803,7 +1803,7 @@ private void generateIntrospectionInfo(CodeTypeElement clazz, boolean inlined) { } builder.startStatement().startCall("cached", "add"); - builder.startStaticCall(context.getType(Arrays.class), "asList"); + builder.startStaticCall(context.getType(List.class), "of"); for (CacheExpression cache : specialization.getCaches()) { if (cache.isAlwaysInitialized()) { continue; diff --git a/truffle/src/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/generator/NodeCodeGenerator.java b/truffle/src/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/generator/NodeCodeGenerator.java index 1e0c29476fbd..f91ddcdb7402 100644 --- a/truffle/src/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/generator/NodeCodeGenerator.java +++ b/truffle/src/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/generator/NodeCodeGenerator.java @@ -367,11 +367,7 @@ private static ExecutableElement createGetFactories(ProcessorContext context, No CodeTreeBuilder builder = method.createBuilder(); builder.startReturn(); - if (factoryList.size() > 1) { - builder.startStaticCall(context.getType(Arrays.class), "asList"); - } else { - builder.startStaticCall(context.getType(Collections.class), "singletonList"); - } + builder.startStaticCall(context.getType(List.class), "of"); for (NodeData child : factoryList) { builder.startGroup(); diff --git a/truffle/src/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/generator/NodeFactoryFactory.java b/truffle/src/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/generator/NodeFactoryFactory.java index e76f7fa8ee96..78ce38cab799 100644 --- a/truffle/src/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/generator/NodeFactoryFactory.java +++ b/truffle/src/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/generator/NodeFactoryFactory.java @@ -47,7 +47,6 @@ import static javax.lang.model.element.Modifier.STATIC; import java.util.ArrayList; -import java.util.Arrays; import java.util.List; import javax.lang.model.element.Element; @@ -143,11 +142,11 @@ private CodeExecutableElement createCreateGetNodeSignatures() { builder.startReturn(); builder.startGroup(); - builder.startStaticCall(context.getType(Arrays.class), "asList"); + builder.startStaticCall(context.getType(List.class), "of"); List constructors = GeneratorUtils.findUserConstructors(createdFactoryElement.asType()); for (ExecutableElement constructor : constructors) { builder.startGroup(); - builder.startStaticCall(context.getType(Arrays.class), "asList"); + builder.startStaticCall(context.getType(List.class), "of"); for (VariableElement var : constructor.getParameters()) { builder.typeLiteral(var.asType()); } @@ -167,7 +166,7 @@ private CodeExecutableElement createCreateGetExecutionSignature() { CodeTreeBuilder builder = method.createBuilder(); builder.startReturn(); - builder.startStaticCall(context.getType(Arrays.class), "asList"); + builder.startStaticCall(context.getType(List.class), "of"); for (NodeExecutionData execution : node.getChildExecutions()) { TypeMirror nodeType = execution.getNodeType(); if (nodeType != null) { diff --git a/truffle/src/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/library/LibraryGenerator.java b/truffle/src/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/library/LibraryGenerator.java index 87e64de19665..b00eafeb7467 100644 --- a/truffle/src/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/library/LibraryGenerator.java +++ b/truffle/src/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/library/LibraryGenerator.java @@ -779,14 +779,13 @@ public List create(ProcessorContext context1, AnnotationProcess builder = implConstructor.createBuilder(); builder.startStatement(); builder.startSuperCall().staticReference(libraryClassLiteral); - builder.startStaticCall(context.getType(Collections.class), "unmodifiableList"); - builder.startStaticCall(context.getType(Arrays.class), "asList"); + builder.startStaticCall(context.getType(List.class), "of"); for (MessageObjects message : methods) { if (message.messageField != null) { builder.field(null, message.messageField); } } - builder.end().end(); // unmodfiiableList, asList + builder.end(); // of builder.end(); // superCall builder.end(); // statement From 09905d40a31e409d7d15b280f0e72c4f169679a7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gerg=C3=B6=20Barany?= Date: Fri, 22 Dec 2023 17:32:42 +0100 Subject: [PATCH 330/593] Don't try to replace node with itself --- .../virtual/phases/ea/GraphEffectList.java | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/virtual/phases/ea/GraphEffectList.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/virtual/phases/ea/GraphEffectList.java index a563eaf42df9..59f2c91f5b8c 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/virtual/phases/ea/GraphEffectList.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/virtual/phases/ea/GraphEffectList.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2023, 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 @@ -382,13 +382,15 @@ public void apply(StructuredGraph graph, ArrayList obsoleteNodes) { if (node.hasUsages() && (replacementNode.stamp(NodeView.DEFAULT).tryImproveWith(node.stamp(NodeView.DEFAULT)) != null)) { replacementNode = graph.unique(new PiNode(replacementNode, node.stamp(NodeView.DEFAULT))); } - node.replaceAtUsages(replacementNode); - if (node instanceof WithExceptionNode) { - GraphUtil.unlinkAndKillExceptionEdge((WithExceptionNode) node); - } else if (node instanceof FixedWithNextNode) { - GraphUtil.unlinkFixedNode((FixedWithNextNode) node); + if (node != replacementNode) { + node.replaceAtUsages(replacementNode); + if (node instanceof WithExceptionNode) { + GraphUtil.unlinkAndKillExceptionEdge((WithExceptionNode) node); + } else if (node instanceof FixedWithNextNode) { + GraphUtil.unlinkFixedNode((FixedWithNextNode) node); + } + obsoleteNodes.add(node); } - obsoleteNodes.add(node); } } From 8206a5779a8785bd7063ab99692d8dc4268bf242 Mon Sep 17 00:00:00 2001 From: Allan Gregersen Date: Fri, 22 Dec 2023 17:43:52 +0100 Subject: [PATCH 331/593] make sure foreign exceptions also check for available type conversions before wrapping them to Espresso ForeignExceptions --- .../espresso/nodes/interop/ToReference.java | 30 +++++++++++++++++-- 1 file changed, 28 insertions(+), 2 deletions(-) diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/nodes/interop/ToReference.java b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/nodes/interop/ToReference.java index c27a27349b6c..90f16dbacbc6 100644 --- a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/nodes/interop/ToReference.java +++ b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/nodes/interop/ToReference.java @@ -1076,18 +1076,40 @@ StaticObject doForeignString(Object value, @Specialization(guards = { "interop.isException(value)", + "!isTypeMappingEnabled(context)", "!isStaticObject(value)", "!interop.isNull(value)", "!isHostString(value)", "!isEspressoException(value)", "!isBoxedPrimitive(value)" }) - StaticObject doForeignException(Object value, + StaticObject doForeignExceptionNoTypeMapping(Object value, @Cached.Shared("value") @CachedLibrary(limit = "LIMIT") InteropLibrary interop, @SuppressWarnings("unused") @Bind("getContext()") EspressoContext context) { return StaticObject.createForeignException(context, value, interop); } + @Specialization(guards = { + "interop.isException(value)", + "isTypeMappingEnabled(context)", + "!isStaticObject(value)", + "!interop.isNull(value)", + "!isHostString(value)", + "!isEspressoException(value)", + "!isBoxedPrimitive(value)" + }) + StaticObject doForeignExceptionTypeMapping(Object value, + @Cached.Shared("value") @CachedLibrary(limit = "LIMIT") InteropLibrary interop, + @SuppressWarnings("unused") @Bind("getContext()") EspressoContext context, + @Cached BranchProfile errorProfile, + @Cached LookupProxyKlassNode lookupProxyKlassNode, + @Cached LookupTypeConverterNode lookupTypeConverterNode, + @Cached LookupInternalTypeConverterNode lookupInternalTypeConverterNode, + @Cached ToReference.DynamicToReference converterToEspresso, + @Bind("getMeta()") Meta meta) throws UnsupportedTypeException { + return tryTypeConversion(value, interop, lookupProxyKlassNode, lookupTypeConverterNode, lookupInternalTypeConverterNode, converterToEspresso, errorProfile, meta); + } + @Specialization(guards = { "interop.hasArrayElements(value)", "!isTypeMappingEnabled(context)", @@ -1225,7 +1247,11 @@ private StaticObject tryTypeConversion(Object value, InteropLibrary interop, Loo } else { PolyglotTypeMappings.TypeConverter converter = lookupTypeConverterNode.execute(metaName); if (converter != null) { - return (StaticObject) converter.convert(StaticObject.createForeign(getLanguage(), meta.java_lang_Object, value, interop)); + if (interop.isException(value)) { + return (StaticObject) converter.convert(StaticObject.createForeignException(getContext(), value, interop)); + } else { + return (StaticObject) converter.convert(StaticObject.createForeign(getLanguage(), meta.java_lang_Object, value, interop)); + } } // check if foreign exception From 7fbb705cb75759571befec5c5b62b511307044ed Mon Sep 17 00:00:00 2001 From: Allan Gregersen Date: Fri, 22 Dec 2023 18:21:55 +0100 Subject: [PATCH 332/593] for foreign exceptions with no meta object, simply wrap into espresso foreign exception --- .../oracle/truffle/espresso/nodes/interop/ToReference.java | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/nodes/interop/ToReference.java b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/nodes/interop/ToReference.java index 90f16dbacbc6..8c9a5cc70a23 100644 --- a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/nodes/interop/ToReference.java +++ b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/nodes/interop/ToReference.java @@ -1107,7 +1107,12 @@ StaticObject doForeignExceptionTypeMapping(Object value, @Cached LookupInternalTypeConverterNode lookupInternalTypeConverterNode, @Cached ToReference.DynamicToReference converterToEspresso, @Bind("getMeta()") Meta meta) throws UnsupportedTypeException { - return tryTypeConversion(value, interop, lookupProxyKlassNode, lookupTypeConverterNode, lookupInternalTypeConverterNode, converterToEspresso, errorProfile, meta); + try { + return tryTypeConversion(value, interop, lookupProxyKlassNode, lookupTypeConverterNode, lookupInternalTypeConverterNode, converterToEspresso, errorProfile, meta); + } catch (@SuppressWarnings("unused") UnsupportedTypeException ex) { + // no meta object available, but we know it's a foreign exception so simply wrap + return StaticObject.createForeignException(context, value, interop); + } } @Specialization(guards = { From 184ac774e0f2759e84e1d8b78b9e1931ad971fe1 Mon Sep 17 00:00:00 2001 From: ol-automation_ww Date: Fri, 22 Dec 2023 21:07:51 +0000 Subject: [PATCH 333/593] Update truffleruby import. --- vm/mx.vm/suite.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vm/mx.vm/suite.py b/vm/mx.vm/suite.py index 6d3a0cb9e348..f5c816d2261b 100644 --- a/vm/mx.vm/suite.py +++ b/vm/mx.vm/suite.py @@ -49,7 +49,7 @@ }, { "name": "truffleruby", - "version": "b7cb7fec62d04436dbba79b1b80a5a76c80a7a1b", + "version": "26f8683a5208566f45fd887453a95471d665603c", "dynamic": True, "urls": [ {"url": "https://github.com/oracle/truffleruby.git", "kind": "git"}, From 90c3b9306ab17ee069446bfeb6a5579df5b46a97 Mon Sep 17 00:00:00 2001 From: Allan Gregersen Date: Fri, 22 Dec 2023 22:42:50 +0100 Subject: [PATCH 334/593] remove throws declaration for not thrown exception --- .../com/oracle/truffle/espresso/nodes/interop/ToReference.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/nodes/interop/ToReference.java b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/nodes/interop/ToReference.java index 8c9a5cc70a23..fe4ac8f26ec9 100644 --- a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/nodes/interop/ToReference.java +++ b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/nodes/interop/ToReference.java @@ -1106,7 +1106,7 @@ StaticObject doForeignExceptionTypeMapping(Object value, @Cached LookupTypeConverterNode lookupTypeConverterNode, @Cached LookupInternalTypeConverterNode lookupInternalTypeConverterNode, @Cached ToReference.DynamicToReference converterToEspresso, - @Bind("getMeta()") Meta meta) throws UnsupportedTypeException { + @Bind("getMeta()") Meta meta) { try { return tryTypeConversion(value, interop, lookupProxyKlassNode, lookupTypeConverterNode, lookupInternalTypeConverterNode, converterToEspresso, errorProfile, meta); } catch (@SuppressWarnings("unused") UnsupportedTypeException ex) { From 3cf5f17fb6018b635117d36df932cfb08ca6ca62 Mon Sep 17 00:00:00 2001 From: Christian Haeubl Date: Fri, 22 Dec 2023 11:32:40 +0100 Subject: [PATCH 335/593] Fix @Uninterruptible on VMThreads.lockThreadMutexInNativeCode(). --- .../src/com/oracle/svm/core/thread/VMThreads.java | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/thread/VMThreads.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/thread/VMThreads.java index 0472be6f89bb..51193fc1f1bb 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/thread/VMThreads.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/thread/VMThreads.java @@ -24,11 +24,6 @@ */ package com.oracle.svm.core.thread; -import com.oracle.svm.core.locks.VMLockSupport; -import jdk.graal.compiler.api.directives.GraalDirectives; -import jdk.graal.compiler.api.replacements.Fold; -import jdk.graal.compiler.replacements.ReplacementsUtil; -import jdk.graal.compiler.replacements.nodes.AssertionNode; import org.graalvm.nativeimage.CurrentIsolate; import org.graalvm.nativeimage.ImageSingletons; import org.graalvm.nativeimage.Isolate; @@ -55,6 +50,7 @@ import com.oracle.svm.core.jdk.UninterruptibleUtils; import com.oracle.svm.core.jdk.UninterruptibleUtils.AtomicWord; import com.oracle.svm.core.locks.VMCondition; +import com.oracle.svm.core.locks.VMLockSupport; import com.oracle.svm.core.locks.VMMutex; import com.oracle.svm.core.log.Log; import com.oracle.svm.core.nodes.CFunctionEpilogueNode; @@ -68,6 +64,11 @@ import com.oracle.svm.core.util.UnsignedUtils; import com.oracle.svm.core.util.VMError; +import jdk.graal.compiler.api.directives.GraalDirectives; +import jdk.graal.compiler.api.replacements.Fold; +import jdk.graal.compiler.replacements.ReplacementsUtil; +import jdk.graal.compiler.replacements.nodes.AssertionNode; + /** * Utility methods for the manipulation and iteration of {@link IsolateThread}s. */ @@ -407,12 +408,12 @@ public static boolean wasStartedByCurrentIsolate(IsolateThread thread) { return StartedByCurrentIsolate.getAddress(thread).readByte(0) != 0; } - @Uninterruptible(reason = "Called from uninterruptible code.", mayBeInlined = true) + @Uninterruptible(reason = "Thread locks/holds the THREAD_MUTEX.", callerMustBe = true) static void lockThreadMutexInNativeCode() { lockThreadMutexInNativeCode(false); } - @Uninterruptible(reason = "Called from uninterruptible code.") + @Uninterruptible(reason = "Thread locks/holds the THREAD_MUTEX.", callerMustBe = true) @NeverInline("Must not be inlined in a caller that has an exception handler: We only support InvokeNode and not InvokeWithExceptionNode between a CFunctionPrologueNode and CFunctionEpilogueNode.") private static void lockThreadMutexInNativeCode(boolean unspecifiedOwner) { CFunctionPrologueNode.cFunctionPrologue(StatusSupport.STATUS_IN_NATIVE); From c824757acb889597079a13cc74d3058bba08b0a8 Mon Sep 17 00:00:00 2001 From: Christian Haeubl Date: Fri, 22 Dec 2023 11:35:34 +0100 Subject: [PATCH 336/593] ImageHeapProvider-related cleanups and simplifications. --- .../posix/linux/LinuxImageHeapProvider.java | 77 +++++-------------- .../os/AbstractCopyingImageHeapProvider.java | 14 ++-- .../core/os/AbstractImageHeapProvider.java | 9 ++- 3 files changed, 33 insertions(+), 67 deletions(-) diff --git a/substratevm/src/com.oracle.svm.core.posix/src/com/oracle/svm/core/posix/linux/LinuxImageHeapProvider.java b/substratevm/src/com.oracle.svm.core.posix/src/com/oracle/svm/core/posix/linux/LinuxImageHeapProvider.java index 163428a33c3f..21101ca87597 100644 --- a/substratevm/src/com.oracle.svm.core.posix/src/com/oracle/svm/core/posix/linux/LinuxImageHeapProvider.java +++ b/substratevm/src/com.oracle.svm.core.posix/src/com/oracle/svm/core/posix/linux/LinuxImageHeapProvider.java @@ -42,7 +42,6 @@ import org.graalvm.nativeimage.c.type.CCharPointer; import org.graalvm.nativeimage.c.type.WordPointer; import org.graalvm.word.ComparableWord; -import org.graalvm.word.LocationIdentity; import org.graalvm.word.Pointer; import org.graalvm.word.PointerBase; import org.graalvm.word.SignedWord; @@ -64,8 +63,8 @@ import com.oracle.svm.core.posix.PosixUtils; import com.oracle.svm.core.posix.headers.Fcntl; import com.oracle.svm.core.posix.headers.Unistd; -import com.oracle.svm.core.util.PointerUtils; +import jdk.graal.compiler.nodes.NamedLocationIdentity; import jdk.graal.compiler.word.Word; /** @@ -88,10 +87,9 @@ public class LinuxImageHeapProvider extends AbstractImageHeapProvider { private static final CGlobalData PROC_SELF_MAPS = CGlobalDataFactory.createCString("/proc/self/maps"); - private static final SignedWord FIRST_ISOLATE_FD = signed(-1); - private static final SignedWord UNASSIGNED_FD = signed(-2); - private static final SignedWord CANNOT_OPEN_FD = signed(-3); - private static final CGlobalData CACHED_IMAGE_FD = CGlobalDataFactory.createWord(FIRST_ISOLATE_FD); + private static final SignedWord UNASSIGNED_FD = signed(-1); + private static final SignedWord CANNOT_OPEN_FD = signed(-2); + private static final CGlobalData CACHED_IMAGE_FD = CGlobalDataFactory.createWord(UNASSIGNED_FD); private static final CGlobalData CACHED_IMAGE_HEAP_OFFSET = CGlobalDataFactory.createWord(); private static final int MAX_PATHLEN = 4096; @@ -106,29 +104,15 @@ public boolean guaranteesHeapPreferredAddressSpaceAlignment() { @Override @Uninterruptible(reason = "Called during isolate initialization.") public int initialize(Pointer reservedAddressSpace, UnsignedWord reservedSize, WordPointer basePointer, WordPointer endPointer) { - // If we are the first isolate, we might be able to use the existing image heap (see below) - SignedWord fd = CACHED_IMAGE_FD.get().read(); - boolean firstIsolate = false; - if (fd.equal(FIRST_ISOLATE_FD)) { - SignedWord previous = ((Pointer) CACHED_IMAGE_FD.get()).compareAndSwapWord(0, FIRST_ISOLATE_FD, UNASSIGNED_FD, LocationIdentity.ANY_LOCATION); - firstIsolate = previous.equal(FIRST_ISOLATE_FD); - fd = firstIsolate ? UNASSIGNED_FD : previous; - } - /* - * If we haven't already, find and open the image file. Even if we are the first isolate, - * this is necessary because if we fail, we need to leave the loaded image heap in pristine - * condition so we can use it to spawn isolates by copying it. - * - * We cache the file descriptor and the determined offset in the file for subsequent isolate - * initializations. We intentionally allow racing in this step to avoid stalling threads. + * Find and open the image file. We cache the file descriptor and the determined offset in + * the file for subsequent isolate initializations. We intentionally allow racing in this + * step to avoid stalling threads. */ - if (fd.equal(UNASSIGNED_FD) || firstIsolate) { + SignedWord fd = CACHED_IMAGE_FD.get().read(); + if (fd.equal(UNASSIGNED_FD)) { int opened = openImageFile(); - /* - * Pointer cas operations are volatile accesses and prevent code reorderings. - */ - SignedWord previous = ((Pointer) CACHED_IMAGE_FD.get()).compareAndSwapWord(0, fd, signed(opened), LocationIdentity.ANY_LOCATION); + SignedWord previous = ((Pointer) CACHED_IMAGE_FD.get()).compareAndSwapWord(0, fd, signed(opened), NamedLocationIdentity.OFF_HEAP_LOCATION); if (previous.equal(fd)) { fd = signed(opened); } else { @@ -139,13 +123,15 @@ public int initialize(Pointer reservedAddressSpace, UnsignedWord reservedSize, W } } - // If we cannot find or open the image file, fall back to copy it from memory. + /* + * If we cannot find or open the image file, fall back to copy it from memory (the image + * heap must be in pristine condition for that). + */ if (fd.equal(CANNOT_OPEN_FD)) { return fallbackCopyingProvider.initialize(reservedAddressSpace, reservedSize, basePointer, endPointer); } boolean haveDynamicMethodResolution = DynamicMethodAddressResolutionHeapSupport.isEnabled(); - if (haveDynamicMethodResolution) { int res = DynamicMethodAddressResolutionHeapSupport.get().initialize(); if (res != CEntryPointErrors.NO_ERROR) { @@ -153,31 +139,8 @@ public int initialize(Pointer reservedAddressSpace, UnsignedWord reservedSize, W } } - // If we are the first isolate and can use the existing image heap, do it. UnsignedWord pageSize = VirtualMemoryProvider.get().getGranularity(); - Word imageHeapBegin = IMAGE_HEAP_BEGIN.get(); UnsignedWord imageHeapSizeInFile = getImageHeapSizeInFile(); - int imageHeapOffsetInAddressSpace = Heap.getHeap().getImageHeapOffsetInAddressSpace(); - UnsignedWord alignment = WordFactory.unsigned(Heap.getHeap().getPreferredAddressSpaceAlignment()); - if (firstIsolate && reservedAddressSpace.isNull() && PointerUtils.isAMultiple(imageHeapBegin, alignment) && imageHeapOffsetInAddressSpace == 0 && !haveDynamicMethodResolution) { - // Mark the whole image heap as read only. - if (VirtualMemoryProvider.get().protect(imageHeapBegin, imageHeapSizeInFile, Access.READ) != 0) { - return CEntryPointErrors.PROTECT_HEAP_FAILED; - } - - // Unprotect writable pages. - Pointer writableBegin = IMAGE_HEAP_WRITABLE_BEGIN.get(); - UnsignedWord writableSize = IMAGE_HEAP_WRITABLE_END.get().subtract(writableBegin); - if (VirtualMemoryProvider.get().protect(writableBegin, writableSize, Access.READ | Access.WRITE) != 0) { - return CEntryPointErrors.PROTECT_HEAP_FAILED; - } - - basePointer.write(imageHeapBegin); - if (endPointer.isNonNull()) { - endPointer.write(IMAGE_HEAP_END.get()); - } - return CEntryPointErrors.NO_ERROR; - } UnsignedWord preHeapRequiredBytes = WordFactory.zero(); if (haveDynamicMethodResolution) { @@ -191,6 +154,7 @@ public int initialize(Pointer reservedAddressSpace, UnsignedWord reservedSize, W Pointer heapBase; Pointer allocatedMemory = WordFactory.nullPointer(); if (reservedAddressSpace.isNull()) { + UnsignedWord alignment = WordFactory.unsigned(Heap.getHeap().getPreferredAddressSpaceAlignment()); heapBase = allocatedMemory = VirtualMemoryProvider.get().reserve(totalAddressSpaceSize, alignment, false); if (allocatedMemory.isNull()) { return CEntryPointErrors.RESERVE_ADDRESS_SPACE_FAILED; @@ -218,22 +182,21 @@ public int initialize(Pointer reservedAddressSpace, UnsignedWord reservedSize, W // Create memory mappings from the image file. UnsignedWord fileOffset = CACHED_IMAGE_HEAP_OFFSET.get().read(); - Pointer imageHeap = heapBase.add(imageHeapOffsetInAddressSpace); + Pointer imageHeap = getImageHeapBegin(heapBase); imageHeap = VirtualMemoryProvider.get().mapFile(imageHeap, imageHeapSizeInFile, fd, fileOffset, Access.READ); if (imageHeap.isNull()) { freeImageHeap(allocatedMemory); return CEntryPointErrors.MAP_HEAP_FAILED; } - Pointer relocPointer = IMAGE_HEAP_A_RELOCATABLE_POINTER.get(); - ComparableWord relocatedValue = relocPointer.readWord(0); - ComparableWord mappedValue = imageHeap.readWord(relocPointer.subtract(imageHeapBegin)); + Pointer relocsBegin = imageHeap.add(IMAGE_HEAP_RELOCATABLE_BEGIN.get().subtract(IMAGE_HEAP_BEGIN.get())); + ComparableWord relocatedValue = IMAGE_HEAP_A_RELOCATABLE_POINTER.get().readWord(0); + ComparableWord mappedValue = relocsBegin.readWord(0); if (relocatedValue.notEqual(mappedValue)) { /* * Addresses were relocated by dynamic linker, so copy them, but first remap the pages * to avoid swapping them in from disk. */ - Pointer relocsBegin = imageHeap.add(IMAGE_HEAP_RELOCATABLE_BEGIN.get().subtract(imageHeapBegin)); UnsignedWord relocsSize = IMAGE_HEAP_RELOCATABLE_END.get().subtract(IMAGE_HEAP_RELOCATABLE_BEGIN.get()); if (!isAMultiple(relocsSize, pageSize)) { freeImageHeap(allocatedMemory); @@ -252,7 +215,7 @@ public int initialize(Pointer reservedAddressSpace, UnsignedWord reservedSize, W } // Unprotect writable pages. - Pointer writableBegin = imageHeap.add(IMAGE_HEAP_WRITABLE_BEGIN.get().subtract(imageHeapBegin)); + Pointer writableBegin = imageHeap.add(IMAGE_HEAP_WRITABLE_BEGIN.get().subtract(IMAGE_HEAP_BEGIN.get())); UnsignedWord writableSize = IMAGE_HEAP_WRITABLE_END.get().subtract(IMAGE_HEAP_WRITABLE_BEGIN.get()); if (VirtualMemoryProvider.get().protect(writableBegin, writableSize, Access.READ | Access.WRITE) != 0) { freeImageHeap(allocatedMemory); diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/os/AbstractCopyingImageHeapProvider.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/os/AbstractCopyingImageHeapProvider.java index 1bca6c7217ef..d9ad6a514744 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/os/AbstractCopyingImageHeapProvider.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/os/AbstractCopyingImageHeapProvider.java @@ -42,8 +42,6 @@ import com.oracle.svm.core.os.VirtualMemoryProvider.Access; import com.oracle.svm.core.util.UnsignedUtils; -import jdk.graal.compiler.word.Word; - public abstract class AbstractCopyingImageHeapProvider extends AbstractImageHeapProvider { @Override public boolean guaranteesHeapPreferredAddressSpaceAlignment() { @@ -98,10 +96,9 @@ public int initialize(Pointer reservedAddressSpace, UnsignedWord reservedSize, W } // Copy the memory to the reserved address space. - Word imageHeapBegin = IMAGE_HEAP_BEGIN.get(); UnsignedWord imageHeapSizeInFile = getImageHeapSizeInFile(); - Pointer imageHeap = heapBase.add(Heap.getHeap().getImageHeapOffsetInAddressSpace()); - int result = commitAndCopyMemory(imageHeapBegin, imageHeapSizeInFile, imageHeap); + Pointer imageHeap = getImageHeapBegin(heapBase); + int result = commitAndCopyMemory(IMAGE_HEAP_BEGIN.get(), imageHeapSizeInFile, imageHeap); if (result != CEntryPointErrors.NO_ERROR) { freeImageHeap(allocatedMemory); return result; @@ -109,17 +106,16 @@ public int initialize(Pointer reservedAddressSpace, UnsignedWord reservedSize, W // Protect the read-only parts at the start of the image heap. UnsignedWord pageSize = VirtualMemoryProvider.get().getGranularity(); - Pointer firstPartOfReadOnlyImageHeap = imageHeap; - UnsignedWord writableBeginPageOffset = UnsignedUtils.roundDown(IMAGE_HEAP_WRITABLE_BEGIN.get().subtract(imageHeapBegin), pageSize); + UnsignedWord writableBeginPageOffset = UnsignedUtils.roundDown(IMAGE_HEAP_WRITABLE_BEGIN.get().subtract(IMAGE_HEAP_BEGIN.get()), pageSize); if (writableBeginPageOffset.aboveThan(0)) { - if (VirtualMemoryProvider.get().protect(firstPartOfReadOnlyImageHeap, writableBeginPageOffset, Access.READ) != 0) { + if (VirtualMemoryProvider.get().protect(imageHeap, writableBeginPageOffset, Access.READ) != 0) { freeImageHeap(allocatedMemory); return CEntryPointErrors.PROTECT_HEAP_FAILED; } } // Protect the read-only parts at the end of the image heap. - UnsignedWord writableEndPageOffset = UnsignedUtils.roundUp(IMAGE_HEAP_WRITABLE_END.get().subtract(imageHeapBegin), pageSize); + UnsignedWord writableEndPageOffset = UnsignedUtils.roundUp(IMAGE_HEAP_WRITABLE_END.get().subtract(IMAGE_HEAP_BEGIN.get()), pageSize); if (writableEndPageOffset.belowThan(imageHeapSizeInFile)) { Pointer afterWritableBoundary = imageHeap.add(writableEndPageOffset); UnsignedWord afterWritableSize = imageHeapSizeInFile.subtract(writableEndPageOffset); diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/os/AbstractImageHeapProvider.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/os/AbstractImageHeapProvider.java index 906a55e92f67..e89f419d15b6 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/os/AbstractImageHeapProvider.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/os/AbstractImageHeapProvider.java @@ -27,12 +27,14 @@ import static com.oracle.svm.core.Isolates.IMAGE_HEAP_BEGIN; import static com.oracle.svm.core.Isolates.IMAGE_HEAP_END; -import jdk.graal.compiler.word.Word; +import org.graalvm.word.Pointer; import org.graalvm.word.UnsignedWord; import com.oracle.svm.core.Uninterruptible; import com.oracle.svm.core.heap.Heap; +import jdk.graal.compiler.word.Word; + public abstract class AbstractImageHeapProvider implements ImageHeapProvider { @Uninterruptible(reason = "Called from uninterruptible code.", mayBeInlined = true) protected static UnsignedWord getImageHeapAddressSpaceSize() { @@ -45,4 +47,9 @@ protected static UnsignedWord getImageHeapSizeInFile() { Word imageHeapBegin = IMAGE_HEAP_BEGIN.get(); return IMAGE_HEAP_END.get().subtract(imageHeapBegin); } + + @Uninterruptible(reason = "Called from uninterruptible code.", mayBeInlined = true) + protected static Pointer getImageHeapBegin(Pointer heapBase) { + return heapBase.add(Heap.getHeap().getImageHeapOffsetInAddressSpace()); + } } From 62765c2411422f96120967e969e3f98b3898bbd0 Mon Sep 17 00:00:00 2001 From: ol-automation_ww Date: Sat, 23 Dec 2023 12:42:03 +0000 Subject: [PATCH 337/593] [GR-23997] Periodic update of the graal import (2023-12-22). PullRequest: js/3016 --- vm/mx.vm/suite.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/vm/mx.vm/suite.py b/vm/mx.vm/suite.py index 6d3a0cb9e348..ff34d418e632 100644 --- a/vm/mx.vm/suite.py +++ b/vm/mx.vm/suite.py @@ -33,7 +33,7 @@ "name": "graal-nodejs", "subdir": True, "dynamic": True, - "version": "9bde3a5564b1bf1968e0f38be51dad2df7b2a33d", + "version": "b7e93e4cb0fb2cc3050aa384746c9e2e2cb0d0cd", "urls" : [ {"url" : "https://github.com/graalvm/graaljs.git", "kind" : "git"}, ] @@ -42,7 +42,7 @@ "name": "graal-js", "subdir": True, "dynamic": True, - "version": "9bde3a5564b1bf1968e0f38be51dad2df7b2a33d", + "version": "b7e93e4cb0fb2cc3050aa384746c9e2e2cb0d0cd", "urls": [ {"url": "https://github.com/graalvm/graaljs.git", "kind" : "git"}, ] From 95e1247743594351baf16703cef6b40ecbfb5fde Mon Sep 17 00:00:00 2001 From: arvyy Date: Sat, 23 Dec 2023 15:41:27 +0200 Subject: [PATCH 338/593] Add truffle-islisp entry to Languages.md --- truffle/docs/Languages.md | 1 + 1 file changed, 1 insertion(+) diff --git a/truffle/docs/Languages.md b/truffle/docs/Languages.md index 298685bb4c9d..73ef7e8ab53e 100644 --- a/truffle/docs/Languages.md +++ b/truffle/docs/Languages.md @@ -35,6 +35,7 @@ The following language implementations exist already: * [DynSem](https://github.com/metaborg/dynsem), a DSL for declarative specification of dynamic semantics of languages. * [Heap Language](https://github.com/jaroslavtulach/heapdump), a tutorial showing the embedding of Truffle languages via interoperability. * [hextruffe](https://bitbucket.org/hexafraction/truffles), an implementation of Hex. +* [islisp-truffle](https://github.com/arvyy/islisp-truffle), an implemention of the ISLISP 2007 standard. * [LuaTruffle](https://github.com/lucasallan/LuaTruffle), an implementation of the Lua language. * [Mozart-Graal](https://github.com/eregon/mozart-graal), an implementation of the Oz programming language. * [Mumbler](https://github.com/cesquivias/mumbler), an experimental Lisp programming language. From b9765c4b90a16babff693368affedeb4b9bf11f1 Mon Sep 17 00:00:00 2001 From: ol-automation_ww Date: Tue, 26 Dec 2023 15:53:29 +0000 Subject: [PATCH 339/593] update JVMCI to 23+3-jvmci-b01 --- common.json | 14 +++++++------- .../graal/compiler/hotspot/JVMCIVersionCheck.java | 4 ++-- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/common.json b/common.json index f415645cf6b2..c2ffce6cbbbb 100644 --- a/common.json +++ b/common.json @@ -44,13 +44,13 @@ "labsjdk-ee-21Debug": {"name": "labsjdk", "version": "ee-21.0.1+11-jvmci-23.1-b26-debug", "platformspecific": true }, "labsjdk-ee-21-llvm": {"name": "labsjdk", "version": "ee-21.0.1+11-jvmci-23.1-b26-sulong", "platformspecific": true }, - "oraclejdk-latest": {"name": "jpg-jdk", "version": "23", "build_id": "2", "release": true, "platformspecific": true, "extrabundles": ["static-libs"]}, - "labsjdk-ce-latest": {"name": "labsjdk", "version": "ce-23+2-jvmci-b01", "platformspecific": true }, - "labsjdk-ce-latestDebug": {"name": "labsjdk", "version": "ce-23+2-jvmci-b01-debug", "platformspecific": true }, - "labsjdk-ce-latest-llvm": {"name": "labsjdk", "version": "ce-23+2-jvmci-b01-sulong", "platformspecific": true }, - "labsjdk-ee-latest": {"name": "labsjdk", "version": "ee-23+2-jvmci-b01", "platformspecific": true }, - "labsjdk-ee-latestDebug": {"name": "labsjdk", "version": "ee-23+2-jvmci-b01-debug", "platformspecific": true }, - "labsjdk-ee-latest-llvm": {"name": "labsjdk", "version": "ee-23+2-jvmci-b01-sulong", "platformspecific": true } + "oraclejdk-latest": {"name": "jpg-jdk", "version": "23", "build_id": "3", "release": true, "platformspecific": true, "extrabundles": ["static-libs"]}, + "labsjdk-ce-latest": {"name": "labsjdk", "version": "ce-23+3-jvmci-b01-20231222172622-47cbd747ea", "platformspecific": true }, + "labsjdk-ce-latestDebug": {"name": "labsjdk", "version": "ce-23+3-jvmci-b01-20231222172622-47cbd747ea-debug", "platformspecific": true }, + "labsjdk-ce-latest-llvm": {"name": "labsjdk", "version": "ce-23+3-jvmci-b01-20231222172622-47cbd747ea-sulong", "platformspecific": true }, + "labsjdk-ee-latest": {"name": "labsjdk", "version": "ee-23+3-jvmci-b01-20231222172622-47cbd747ea+40f899c1b9", "platformspecific": true }, + "labsjdk-ee-latestDebug": {"name": "labsjdk", "version": "ee-23+3-jvmci-b01-20231222172622-47cbd747ea+40f899c1b9-debug", "platformspecific": true }, + "labsjdk-ee-latest-llvm": {"name": "labsjdk", "version": "ee-23+3-jvmci-b01-20231222172622-47cbd747ea+40f899c1b9-sulong", "platformspecific": true } }, "eclipse": { diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/JVMCIVersionCheck.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/JVMCIVersionCheck.java index a74becc7ea5d..5d019e28d2b9 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/JVMCIVersionCheck.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/JVMCIVersionCheck.java @@ -54,8 +54,8 @@ public final class JVMCIVersionCheck { private static final Map> JVMCI_MIN_VERSIONS = Map.of( "21", Map.of(DEFAULT_VENDOR_ENTRY, new Version(23, 1, 26)), "23", Map.of( - "Oracle Corporation", new Version("23+2", 1), - DEFAULT_VENDOR_ENTRY, new Version("23+2", 1))); + "Oracle Corporation", new Version("23+3", 1), + DEFAULT_VENDOR_ENTRY, new Version("23+3", 1))); private static final int NA = 0; /** * Minimum Java release supported by Graal. From 4d1211a71351e074b6afd072ef415cf91c8ce110 Mon Sep 17 00:00:00 2001 From: Florian Angerer Date: Thu, 28 Dec 2023 13:35:46 +0000 Subject: [PATCH 340/593] [GR-21590] Update Python imports. PullRequest: graalpython/3137 --- vm/mx.vm/suite.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vm/mx.vm/suite.py b/vm/mx.vm/suite.py index ff34d418e632..e0f7cc41acc5 100644 --- a/vm/mx.vm/suite.py +++ b/vm/mx.vm/suite.py @@ -65,7 +65,7 @@ }, { "name": "graalpython", - "version": "d80162246f7b03bf2d71647316033df8ed9e1550", + "version": "93f10ca7253d04cb0f7e33c6f6523a6169a65667", "dynamic": True, "urls": [ {"url": "https://github.com/graalvm/graalpython.git", "kind": "git"}, From ae397d98d2e3836e32f7a9a1243049f8ba951110 Mon Sep 17 00:00:00 2001 From: Mohaned Qunaibit Date: Mon, 1 Jan 2024 09:10:42 +0000 Subject: [PATCH 341/593] [GR-21590] Update imports PullRequest: graalpython/3139 --- vm/mx.vm/suite.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vm/mx.vm/suite.py b/vm/mx.vm/suite.py index e0f7cc41acc5..93d25016ffe4 100644 --- a/vm/mx.vm/suite.py +++ b/vm/mx.vm/suite.py @@ -65,7 +65,7 @@ }, { "name": "graalpython", - "version": "93f10ca7253d04cb0f7e33c6f6523a6169a65667", + "version": "1b0fe2ddd0bb4e02b867a0b90380ecd719da89b0", "dynamic": True, "urls": [ {"url": "https://github.com/graalvm/graalpython.git", "kind": "git"}, From dcc9e089a756308338ef9786ac45dd73f0334d8e Mon Sep 17 00:00:00 2001 From: Tomas Zezula Date: Thu, 14 Dec 2023 10:47:12 +0100 Subject: [PATCH 342/593] [GR-50945] Fixed missing RuntimeCompileMethods option. --- .../native-image/org.graalvm.sl/native-image.properties | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/truffle/src/com.oracle.truffle.sl/src/META-INF/native-image/org.graalvm.sl/native-image.properties b/truffle/src/com.oracle.truffle.sl/src/META-INF/native-image/org.graalvm.sl/native-image.properties index df152223f131..5bbb2eb60389 100644 --- a/truffle/src/com.oracle.truffle.sl/src/META-INF/native-image/org.graalvm.sl/native-image.properties +++ b/truffle/src/com.oracle.truffle.sl/src/META-INF/native-image/org.graalvm.sl/native-image.properties @@ -1,2 +1,2 @@ -Args = --initialize-at-build-time=com.oracle.truffle.sl,org.antlr.v4 - +Args = --initialize-at-build-time=com.oracle.truffle.sl,org.antlr.v4 \ + -H:MaxRuntimeCompileMethods=250 From 03d8714e60d3f2ba2e08c195127da0b4087a9225 Mon Sep 17 00:00:00 2001 From: Tomas Zezula Date: Thu, 14 Dec 2023 18:40:41 +0100 Subject: [PATCH 343/593] Added use-enterprise-polyglot unittest argument. When set the enterprise polyglot is added to unittest dependencies. --- truffle/mx.truffle/mx_truffle.py | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/truffle/mx.truffle/mx_truffle.py b/truffle/mx.truffle/mx_truffle.py index 5348780ca458..5f25063c8be5 100644 --- a/truffle/mx.truffle/mx_truffle.py +++ b/truffle/mx.truffle/mx_truffle.py @@ -188,9 +188,16 @@ def _open_module_exports_args(): class TruffleUnittestConfig(mx_unittest.MxUnittestConfig): + _use_enterprise_polyglot = False + def __init__(self): super(TruffleUnittestConfig, self).__init__('truffle') + def processDeps(self, deps): + if TruffleUnittestConfig._use_enterprise_polyglot: + mx.logv('Adding Enterprise Polyglot to unittest dependencies due to the `--use-enterprise-polyglot` unittest argument being set.') + deps.add(mx.distribution('graal-enterprise:TRUFFLE_ENTERPRISE')) + def apply(self, config): vmArgs, mainClass, mainClassArgs = config @@ -210,6 +217,19 @@ def apply(self, config): mx_unittest.register_unittest_config(TruffleUnittestConfig()) +class _UseEnterprisePolyglotAction(Action): + def __init__(self, **kwargs): + kwargs['required'] = False + kwargs['nargs'] = 0 + super(_UseEnterprisePolyglotAction, self).__init__(**kwargs) + + def __call__(self, parser, namespace, values, option_string=None): + TruffleUnittestConfig._use_enterprise_polyglot = True + + +mx_unittest.add_unittest_argument('--use-enterprise-polyglot', default=False, help='Adds Truffle enterprise polyglot to unittest depdendencies.', action=_UseEnterprisePolyglotAction) + + class NFITestConfig: def __init__(self, name, runtime_deps): From 46c6212831f9a971c3cde07eaf5dd62f9a2edff4 Mon Sep 17 00:00:00 2001 From: David Leopoldseder Date: Thu, 21 Dec 2023 13:37:14 +0100 Subject: [PATCH 344/593] add loop speculation overflow test verifying integrity of the speculation log during a compile --- .../HotSpotLoopOverflowSpeculationTest.java | 166 ++++++++++++++++++ 1 file changed, 166 insertions(+) create mode 100644 compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/hotspot/test/HotSpotLoopOverflowSpeculationTest.java diff --git a/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/hotspot/test/HotSpotLoopOverflowSpeculationTest.java b/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/hotspot/test/HotSpotLoopOverflowSpeculationTest.java new file mode 100644 index 000000000000..6e515a7e3188 --- /dev/null +++ b/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/hotspot/test/HotSpotLoopOverflowSpeculationTest.java @@ -0,0 +1,166 @@ +/* + * Copyright (c) 2015, 2020, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.graal.compiler.hotspot.test; + +import java.util.List; +import java.util.Optional; +import java.util.concurrent.atomic.AtomicInteger; + +import org.junit.Test; + +import jdk.graal.compiler.api.directives.GraalDirectives; +import jdk.graal.compiler.core.test.GraalCompilerTest; +import jdk.graal.compiler.debug.GraalError; +import jdk.graal.compiler.debug.TTY; +import jdk.graal.compiler.nodes.GraphState; +import jdk.graal.compiler.nodes.StructuredGraph; +import jdk.graal.compiler.nodes.loop.CountedLoopInfo; +import jdk.graal.compiler.nodes.loop.LoopEx; +import jdk.graal.compiler.nodes.loop.LoopsData; +import jdk.graal.compiler.options.OptionValues; +import jdk.graal.compiler.phases.BasePhase; +import jdk.graal.compiler.phases.OptimisticOptimizations; +import jdk.graal.compiler.phases.tiers.HighTierContext; +import jdk.graal.compiler.phases.tiers.Suites; +import jdk.vm.ci.hotspot.HotSpotSpeculationLog; + +public class HotSpotLoopOverflowSpeculationTest extends GraalCompilerTest { + + // loop that can overflow + public static void snippetUp(int start, int end, int stride) { + int i = start; + int step = ((stride - 1) & 0xFFFF) + 1; // make sure this value is always strictly positive + while (true) { + // TTY.printf("I=%s end=%s%n", i, end); + if (i >= end) { + break; + } + GraalDirectives.sideEffect(); + if (GraalDirectives.sideEffect(i) < 0) { + TTY.printf("Overflow happened with values %s %s %s %n", start, end, stride); + return; + } + i += step; + } + } + + @Override + protected OptimisticOptimizations getOptimisticOptimizations() { + return OptimisticOptimizations.ALL; + } + + static volatile boolean loopCompileUntilErrorHit; + static volatile boolean loopingStarted; + + public void startThreadAndWaitUntilLoopingStarted() { + new Thread(new Runnable() { + + @Override + public void run() { + TTY.printf("[OverflowThread] Starting waiting until compiler is at the right position...%n"); + while (!loopingStarted) { + try { + Thread.sleep(100); + } catch (InterruptedException e) { + throw GraalError.shouldNotReachHere(e); + } + } + TTY.printf("[OverflowThread] Sleeping over, starting overflow trigger%n"); + snippetUp(Integer.MAX_VALUE - 100, Integer.MAX_VALUE - 1, 7); + TTY.printf("[OverflowThread] Sleeping over, overflow happened now - speculation can be asked again%n"); + loopCompileUntilErrorHit = false; + } + }).start(); + } + + static AtomicInteger compiles = new AtomicInteger(); + + @Override + protected Suites createSuites(OptionValues opts) { + Suites s = super.createSuites(opts); + s = s.copy(); + + s.getHighTier().appendPhase(new BasePhase() { + + static CountedLoopInfo queryOverflowGuardCounted(StructuredGraph graph, HighTierContext context) { + LoopsData ld = context.getLoopsDataProvider().getLoopsData(graph); + ld.detectCountedLoops(); + List countedLoops = ld.countedLoops(); + GraalError.guarantee(countedLoops.size() == 1, "Must have one counted loop " + countedLoops); + return countedLoops.get(0).counted(); + } + + @Override + protected void run(StructuredGraph graph, HighTierContext context) { + compiles.incrementAndGet(); + HotSpotSpeculationLog hsLog = (HotSpotSpeculationLog) graph.getSpeculationLog(); + TTY.printf("[Compiler Thread compileId=%s] Initial failed speculation adr %s and data %s%n", compiles.get(), hsLog.getFailedSpeculationsAddress(), + UNSAFE.getLong(hsLog.getFailedSpeculationsAddress())); + if (!loopCompileUntilErrorHit) { + return; + } + // the fact that the counted loop info below exists is enough proof that passing did + // not find any overflow guards that failed for that loop + CountedLoopInfo cli = queryOverflowGuardCounted(graph, context); + TTY.printf("[Compiler Thread compileId=%s] Asking for the overflow guard - not a problem, starting looping and waiting %n", compiles.get()); + loopingStarted = true; + while (loopCompileUntilErrorHit) { + try { + Thread.sleep(100); + } catch (InterruptedException e) { + throw GraalError.shouldNotReachHere(e); + } + } + TTY.printf("[Compiler Thread compileId=%s] Looping over, asking again %n", compiles.get()); + TTY.printf("[Compiler Thread compileId=%s] Failed speculation adr %s and data %s%n", compiles.get(), hsLog.getFailedSpeculationsAddress(), + UNSAFE.getLong(hsLog.getFailedSpeculationsAddress())); + // ask again - this time we should fail + cli.createOverFlowGuard(); + } + + @Override + public Optional notApplicableTo(GraphState graphState) { + return ALWAYS_APPLICABLE; + } + + }); + + return s; + } + + @Test + public void testUpOverflow() { + // install code + getCode(getResolvedJavaMethod("snippetUp"), null, true, true, getInitialOptions()); + // run the code + snippetUp(0, 1000, 3); + // start the thread that waits until the compiler thread fails + loopCompileUntilErrorHit = true; + startThreadAndWaitUntilLoopingStarted(); + // force compile again, for some reason another compile is enqueued and the exisitng one is + // not yet deopted + getCode(getResolvedJavaMethod("snippetUp"), null, true, true, getInitialOptions()); + } +} From 2397d60e74d9ff7cb937a4003c72940b55812834 Mon Sep 17 00:00:00 2001 From: David Leopoldseder Date: Tue, 2 Jan 2024 14:23:50 +0100 Subject: [PATCH 345/593] consistent speculation log test: do not log per default to stdout --- .../HotSpotLoopOverflowSpeculationTest.java | 48 +++++++++++++------ 1 file changed, 34 insertions(+), 14 deletions(-) diff --git a/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/hotspot/test/HotSpotLoopOverflowSpeculationTest.java b/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/hotspot/test/HotSpotLoopOverflowSpeculationTest.java index 6e515a7e3188..eabc2338c8c5 100644 --- a/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/hotspot/test/HotSpotLoopOverflowSpeculationTest.java +++ b/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/hotspot/test/HotSpotLoopOverflowSpeculationTest.java @@ -42,24 +42,33 @@ import jdk.graal.compiler.options.OptionValues; import jdk.graal.compiler.phases.BasePhase; import jdk.graal.compiler.phases.OptimisticOptimizations; +import jdk.graal.compiler.phases.common.DisableOverflownCountedLoopsPhase; import jdk.graal.compiler.phases.tiers.HighTierContext; import jdk.graal.compiler.phases.tiers.Suites; import jdk.vm.ci.hotspot.HotSpotSpeculationLog; +/** + * Test to ensure that {@code HotSpotSpeculationLog} yields consistent results with respect to + * failed speculations during the course of a compilation. This is necessary for overflow + * speculations used by Graal in {@link DisableOverflownCountedLoopsPhase}. + */ public class HotSpotLoopOverflowSpeculationTest extends GraalCompilerTest { - // loop that can overflow + public static final boolean LOG_STDOUT = false; + + // Snippet with a loop that can easily overflow public static void snippetUp(int start, int end, int stride) { int i = start; int step = ((stride - 1) & 0xFFFF) + 1; // make sure this value is always strictly positive while (true) { - // TTY.printf("I=%s end=%s%n", i, end); if (i >= end) { break; } GraalDirectives.sideEffect(); if (GraalDirectives.sideEffect(i) < 0) { - TTY.printf("Overflow happened with values %s %s %s %n", start, end, stride); + if (LOG_STDOUT) { + TTY.printf("Overflow happened with values %s %s %s %n", start, end, stride); + } return; } i += step; @@ -79,7 +88,9 @@ public void startThreadAndWaitUntilLoopingStarted() { @Override public void run() { - TTY.printf("[OverflowThread] Starting waiting until compiler is at the right position...%n"); + if (LOG_STDOUT) { + TTY.printf("[OverflowThread] Starting waiting until compiler is at the right position...%n"); + } while (!loopingStarted) { try { Thread.sleep(100); @@ -87,9 +98,13 @@ public void run() { throw GraalError.shouldNotReachHere(e); } } - TTY.printf("[OverflowThread] Sleeping over, starting overflow trigger%n"); + if (LOG_STDOUT) { + TTY.printf("[OverflowThread] Sleeping over, starting overflow trigger%n"); + } snippetUp(Integer.MAX_VALUE - 100, Integer.MAX_VALUE - 1, 7); - TTY.printf("[OverflowThread] Sleeping over, overflow happened now - speculation can be asked again%n"); + if (LOG_STDOUT) { + TTY.printf("[OverflowThread] Sleeping over, overflow happened now - speculation can be asked again%n"); + } loopCompileUntilErrorHit = false; } }).start(); @@ -101,7 +116,6 @@ public void run() { protected Suites createSuites(OptionValues opts) { Suites s = super.createSuites(opts); s = s.copy(); - s.getHighTier().appendPhase(new BasePhase() { static CountedLoopInfo queryOverflowGuardCounted(StructuredGraph graph, HighTierContext context) { @@ -116,15 +130,19 @@ static CountedLoopInfo queryOverflowGuardCounted(StructuredGraph graph, HighTier protected void run(StructuredGraph graph, HighTierContext context) { compiles.incrementAndGet(); HotSpotSpeculationLog hsLog = (HotSpotSpeculationLog) graph.getSpeculationLog(); - TTY.printf("[Compiler Thread compileId=%s] Initial failed speculation adr %s and data %s%n", compiles.get(), hsLog.getFailedSpeculationsAddress(), - UNSAFE.getLong(hsLog.getFailedSpeculationsAddress())); + if (LOG_STDOUT) { + TTY.printf("[Compiler Thread compileId=%s] Initial failed speculation adr %s and data %s%n", compiles.get(), hsLog.getFailedSpeculationsAddress(), + UNSAFE.getLong(hsLog.getFailedSpeculationsAddress())); + } if (!loopCompileUntilErrorHit) { return; } // the fact that the counted loop info below exists is enough proof that passing did // not find any overflow guards that failed for that loop CountedLoopInfo cli = queryOverflowGuardCounted(graph, context); - TTY.printf("[Compiler Thread compileId=%s] Asking for the overflow guard - not a problem, starting looping and waiting %n", compiles.get()); + if (LOG_STDOUT) { + TTY.printf("[Compiler Thread compileId=%s] Asking for the overflow guard - not a problem, starting looping and waiting %n", compiles.get()); + } loopingStarted = true; while (loopCompileUntilErrorHit) { try { @@ -133,9 +151,11 @@ protected void run(StructuredGraph graph, HighTierContext context) { throw GraalError.shouldNotReachHere(e); } } - TTY.printf("[Compiler Thread compileId=%s] Looping over, asking again %n", compiles.get()); - TTY.printf("[Compiler Thread compileId=%s] Failed speculation adr %s and data %s%n", compiles.get(), hsLog.getFailedSpeculationsAddress(), - UNSAFE.getLong(hsLog.getFailedSpeculationsAddress())); + if (LOG_STDOUT) { + TTY.printf("[Compiler Thread compileId=%s] Looping over, asking again %n", compiles.get()); + TTY.printf("[Compiler Thread compileId=%s] Failed speculation adr %s and data %s%n", compiles.get(), hsLog.getFailedSpeculationsAddress(), + UNSAFE.getLong(hsLog.getFailedSpeculationsAddress())); + } // ask again - this time we should fail cli.createOverFlowGuard(); } @@ -159,7 +179,7 @@ public void testUpOverflow() { // start the thread that waits until the compiler thread fails loopCompileUntilErrorHit = true; startThreadAndWaitUntilLoopingStarted(); - // force compile again, for some reason another compile is enqueued and the exisitng one is + // force compile again, for some reason another compile is enqueued and the existing one is // not yet deopted getCode(getResolvedJavaMethod("snippetUp"), null, true, true, getInitialOptions()); } From a31e2a5341b09b5cfd3a943772e3b44efbfe986b Mon Sep 17 00:00:00 2001 From: Imane Mamri Date: Mon, 18 Dec 2023 11:27:48 +0100 Subject: [PATCH 346/593] next dev cycle 24.1.0 --- compiler/mx.compiler/suite.py | 2 +- espresso/mx.espresso/suite.py | 2 +- regex/mx.regex/suite.py | 2 +- sdk/mx.sdk/suite.py | 2 +- substratevm/mx.substratevm/suite.py | 2 +- tools/mx.tools/suite.py | 2 +- truffle/external_repos/simplelanguage/pom.xml | 2 +- truffle/external_repos/simpletool/pom.xml | 2 +- truffle/mx.truffle/suite.py | 2 +- vm/mx.vm/suite.py | 2 +- wasm/mx.wasm/suite.py | 2 +- 11 files changed, 11 insertions(+), 11 deletions(-) diff --git a/compiler/mx.compiler/suite.py b/compiler/mx.compiler/suite.py index 96870bee17e2..334cc3141594 100644 --- a/compiler/mx.compiler/suite.py +++ b/compiler/mx.compiler/suite.py @@ -4,7 +4,7 @@ "sourceinprojectwhitelist" : [], "groupId" : "org.graalvm.compiler", - "version" : "24.0.0", + "version" : "24.1.0", "release" : False, "url" : "http://www.graalvm.org/", "developer" : { diff --git a/espresso/mx.espresso/suite.py b/espresso/mx.espresso/suite.py index 502bb1a25eac..0dbec84b0664 100644 --- a/espresso/mx.espresso/suite.py +++ b/espresso/mx.espresso/suite.py @@ -24,7 +24,7 @@ suite = { "mxversion": "6.44.0", "name": "espresso", - "version" : "24.0.0", + "version" : "24.1.0", "release" : False, "groupId" : "org.graalvm.espresso", "url" : "https://www.graalvm.org/reference-manual/java-on-truffle/", diff --git a/regex/mx.regex/suite.py b/regex/mx.regex/suite.py index 37d082672f05..070043a9b28d 100644 --- a/regex/mx.regex/suite.py +++ b/regex/mx.regex/suite.py @@ -43,7 +43,7 @@ "name" : "regex", - "version" : "24.0.0", + "version" : "24.1.0", "release" : False, "groupId" : "org.graalvm.regex", "url" : "http://www.graalvm.org/", diff --git a/sdk/mx.sdk/suite.py b/sdk/mx.sdk/suite.py index a7ceded8071e..126223f09038 100644 --- a/sdk/mx.sdk/suite.py +++ b/sdk/mx.sdk/suite.py @@ -41,7 +41,7 @@ suite = { "mxversion": "6.53.2", "name" : "sdk", - "version" : "24.0.0", + "version" : "24.1.0", "release" : False, "sourceinprojectwhitelist" : [], "url" : "https://github.com/oracle/graal", diff --git a/substratevm/mx.substratevm/suite.py b/substratevm/mx.substratevm/suite.py index ff63e6e642c9..596a9fe5743c 100644 --- a/substratevm/mx.substratevm/suite.py +++ b/substratevm/mx.substratevm/suite.py @@ -2,7 +2,7 @@ suite = { "mxversion": "6.27.1", "name": "substratevm", - "version" : "24.0.0", + "version" : "24.1.0", "release" : False, "url" : "https://github.com/oracle/graal/tree/master/substratevm", diff --git a/tools/mx.tools/suite.py b/tools/mx.tools/suite.py index d95e556bf9f5..822e3f095391 100644 --- a/tools/mx.tools/suite.py +++ b/tools/mx.tools/suite.py @@ -26,7 +26,7 @@ "defaultLicense" : "GPLv2-CPE", "groupId" : "org.graalvm.tools", - "version" : "24.0.0", + "version" : "24.1.0", "release" : False, "url" : "http://openjdk.java.net/projects/graal", "developer" : { diff --git a/truffle/external_repos/simplelanguage/pom.xml b/truffle/external_repos/simplelanguage/pom.xml index e33816257dc6..65259103ef24 100644 --- a/truffle/external_repos/simplelanguage/pom.xml +++ b/truffle/external_repos/simplelanguage/pom.xml @@ -47,7 +47,7 @@ UTF-8 jdt_apt - 24.0.0-dev + 24.1.0-dev 17 17 org.graalvm.sl.launcher/com.oracle.truffle.sl.launcher.SLMain diff --git a/truffle/external_repos/simpletool/pom.xml b/truffle/external_repos/simpletool/pom.xml index afde0af17a67..26385c8cf881 100644 --- a/truffle/external_repos/simpletool/pom.xml +++ b/truffle/external_repos/simpletool/pom.xml @@ -48,7 +48,7 @@ ${graalvm.version} simpletool - 24.0.0-dev + 24.1.0-dev UTF-8 17 17 diff --git a/truffle/mx.truffle/suite.py b/truffle/mx.truffle/suite.py index 5371a5b2ac6c..9e71e6230976 100644 --- a/truffle/mx.truffle/suite.py +++ b/truffle/mx.truffle/suite.py @@ -41,7 +41,7 @@ suite = { "mxversion": "7.0.3", "name" : "truffle", - "version" : "24.0.0", + "version" : "24.1.0", "release" : False, "groupId" : "org.graalvm.truffle", "sourceinprojectwhitelist" : [], diff --git a/vm/mx.vm/suite.py b/vm/mx.vm/suite.py index 93d25016ffe4..55616953e61f 100644 --- a/vm/mx.vm/suite.py +++ b/vm/mx.vm/suite.py @@ -1,6 +1,6 @@ suite = { "name": "vm", - "version" : "24.0.0", + "version" : "24.1.0", "mxversion": "6.41.0", "release" : False, "groupId" : "org.graalvm", diff --git a/wasm/mx.wasm/suite.py b/wasm/mx.wasm/suite.py index bdd955f76f32..3c6d3e7f15b7 100644 --- a/wasm/mx.wasm/suite.py +++ b/wasm/mx.wasm/suite.py @@ -42,7 +42,7 @@ "mxversion": "6.41.0", "name" : "wasm", "groupId" : "org.graalvm.wasm", - "version" : "24.0.0", + "version" : "24.1.0", "versionConflictResolution" : "latest", "url" : "http://graalvm.org/", "developer" : { From 7f092802b13714c896ed8e73ff58c811e23d3326 Mon Sep 17 00:00:00 2001 From: Fabio Niephaus Date: Wed, 3 Jan 2024 10:56:02 +0100 Subject: [PATCH 347/593] Inform about invalid `--exclude-config` regexes. --- .../svm/driver/CmdLineOptionHandler.java | 35 ++++++++++++++----- 1 file changed, 26 insertions(+), 9 deletions(-) diff --git a/substratevm/src/com.oracle.svm.driver/src/com/oracle/svm/driver/CmdLineOptionHandler.java b/substratevm/src/com.oracle.svm.driver/src/com/oracle/svm/driver/CmdLineOptionHandler.java index c2b1ca7d5cb2..0a6af33f52dd 100644 --- a/substratevm/src/com.oracle.svm.driver/src/com/oracle/svm/driver/CmdLineOptionHandler.java +++ b/substratevm/src/com.oracle.svm.driver/src/com/oracle/svm/driver/CmdLineOptionHandler.java @@ -29,6 +29,7 @@ import java.util.List; import java.util.Optional; import java.util.regex.Pattern; +import java.util.regex.PatternSyntaxException; import com.oracle.svm.core.VM; import com.oracle.svm.core.option.OptionOrigin; @@ -114,15 +115,7 @@ private boolean consume(ArgumentQueue args, String headArg) { return true; case "--exclude-config": args.poll(); - String excludeJar = args.poll(); - if (excludeJar == null) { - NativeImage.showError(headArg + " requires two arguments: a jar regular expression and a resource regular expression"); - } - String excludeConfig = args.poll(); - if (excludeConfig == null) { - NativeImage.showError(headArg + " requires resource regular expression"); - } - nativeImage.addExcludeConfig(Pattern.compile(excludeJar), Pattern.compile(excludeConfig)); + handleExcludeConfigOption(headArg, args); return true; case VERBOSE_OPTION: args.poll(); @@ -188,6 +181,30 @@ private boolean consume(ArgumentQueue args, String headArg) { return false; } + private void handleExcludeConfigOption(String headArg, ArgumentQueue args) { + String excludeJar = args.poll(); + if (excludeJar == null) { + NativeImage.showError(headArg + " requires two arguments: a jar regular expression and a resource regular expression"); + } + Pattern jarPattern; + try { + jarPattern = Pattern.compile(excludeJar); + } catch (final PatternSyntaxException pse) { + throw NativeImage.showError(headArg + " was used with an invalid jar regular expression: %s", pse); + } + String excludeConfig = args.poll(); + if (excludeConfig == null) { + NativeImage.showError(headArg + " requires resource regular expression"); + } + Pattern excludeConfigPattern; + try { + excludeConfigPattern = Pattern.compile(excludeConfig); + } catch (final PatternSyntaxException pse) { + throw NativeImage.showError(headArg + " was used with an invalid resource regular expression: %s", pse); + } + nativeImage.addExcludeConfig(jarPattern, excludeConfigPattern); + } + /** * Prints version output following * "src/java.base/share/classes/java/lang/VersionProps.java.template#print(boolean)". From a7792fc46532450802017cc7d46bb7eee8e2fff3 Mon Sep 17 00:00:00 2001 From: Andrija Kolic Date: Mon, 11 Dec 2023 16:17:43 +0100 Subject: [PATCH 348/593] Use both time -v and custom rss percentile tracker for benchmarking. --- compiler/ci/ci_common/compiler-common.libsonnet | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/ci/ci_common/compiler-common.libsonnet b/compiler/ci/ci_common/compiler-common.libsonnet index 7f97e498a3d8..4a2088a86eb2 100644 --- a/compiler/ci/ci_common/compiler-common.libsonnet +++ b/compiler/ci/ci_common/compiler-common.libsonnet @@ -66,7 +66,7 @@ "--results-file", "${BENCH_RESULTS_FILE_PATH}", "--machine-name=${MACHINE_NAME}"] + - (if std.objectHasAll(self.environment, 'MX_TRACKER') then ["--tracker=" + self.environment['MX_TRACKER']] else ["--tracker=rss"]), + (if std.objectHasAll(self.environment, 'MX_TRACKER') then ["--tracker=" + self.environment['MX_TRACKER']] else ["--tracker=rsspercentiles+maxrss"]), benchmark_cmd:: bench_common.hwlocIfNuma(self.should_use_hwloc, self.plain_benchmark_cmd, node=self.default_numa_node), min_heap_size:: if std.objectHasAll(self.environment, 'XMS') then ["-Xms${XMS}"] else [], max_heap_size:: if std.objectHasAll(self.environment, 'XMX') then ["-Xmx${XMX}"] else [], From 0031642f62770be5ebb2c367a6e6e9e0fa87e2a8 Mon Sep 17 00:00:00 2001 From: Andrija Kolic Date: Tue, 12 Dec 2023 17:20:47 +0100 Subject: [PATCH 349/593] Bump mx version to GR-50424 branch for testing purposes. --- common.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/common.json b/common.json index f415645cf6b2..72e7b54d4af0 100644 --- a/common.json +++ b/common.json @@ -4,7 +4,7 @@ "Jsonnet files should not include this file directly but use ci/common.jsonnet instead." ], - "mx_version": "7.4.1", + "mx_version": "akolic/GR-50424-track-rss-percentiles", "COMMENT.jdks": "When adding or removing JDKs keep in sync with JDKs in ci/common.jsonnet", "jdks": { From 9322aa79ef2dfaad0b29d63b4202b96cb07915a5 Mon Sep 17 00:00:00 2001 From: Andrija Kolic Date: Wed, 3 Jan 2024 10:55:53 +0100 Subject: [PATCH 350/593] Bump required mx version. --- common.json | 2 +- compiler/mx.compiler/suite.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/common.json b/common.json index 72e7b54d4af0..9757335d1d1c 100644 --- a/common.json +++ b/common.json @@ -4,7 +4,7 @@ "Jsonnet files should not include this file directly but use ci/common.jsonnet instead." ], - "mx_version": "akolic/GR-50424-track-rss-percentiles", + "mx_version": "7.5.2", "COMMENT.jdks": "When adding or removing JDKs keep in sync with JDKs in ci/common.jsonnet", "jdks": { diff --git a/compiler/mx.compiler/suite.py b/compiler/mx.compiler/suite.py index 96870bee17e2..2dcd78db683b 100644 --- a/compiler/mx.compiler/suite.py +++ b/compiler/mx.compiler/suite.py @@ -1,5 +1,5 @@ suite = { - "mxversion": "6.49.1", + "mxversion": "7.5.2", "name" : "compiler", "sourceinprojectwhitelist" : [], From 1122504a3473ebdfec1ae5922d29e4ceba1d4c13 Mon Sep 17 00:00:00 2001 From: Jirka Marsik Date: Wed, 3 Jan 2024 14:42:04 +0100 Subject: [PATCH 351/593] Check bounds in ByteArrayWasmMemory#load_i128 --- .../src/org/graalvm/wasm/memory/ByteArrayWasmMemory.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/memory/ByteArrayWasmMemory.java b/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/memory/ByteArrayWasmMemory.java index 5d7423e0b247..950d5eacbd33 100644 --- a/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/memory/ByteArrayWasmMemory.java +++ b/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/memory/ByteArrayWasmMemory.java @@ -238,9 +238,9 @@ public long load_i64_32u(Node node, long address) { @Override public Vector128 load_i128(Node node, long address) { - try { + if (ByteArraySupport.littleEndian().inBounds(byteArrayBuffer.buffer(), address, 16)) { return Vector128.ofBytes(Arrays.copyOfRange(byteArrayBuffer.buffer(), (int) address, (int) address + 16)); - } catch (final IndexOutOfBoundsException e) { + } else { throw trapOutOfBounds(node, address, 16); } } From df3f90eab81e3e70a7545dfde00e876aee23c6b1 Mon Sep 17 00:00:00 2001 From: Danilo Ansaloni Date: Wed, 3 Jan 2024 15:17:22 +0100 Subject: [PATCH 352/593] Publish nightly dev builds based on JDK23. --- vm/ce-release-artifacts.json | 46 ++++++++++++++++++------------------ 1 file changed, 23 insertions(+), 23 deletions(-) diff --git a/vm/ce-release-artifacts.json b/vm/ce-release-artifacts.json index 14a29a02e1c1..3a3d2b463b30 100644 --- a/vm/ce-release-artifacts.json +++ b/vm/ce-release-artifacts.json @@ -1,8 +1,8 @@ [ { - "name": "graalvm-community-java22", + "name": "graalvm-community-java23", "core": true, - "jdk": "jdk_22", + "jdk": "jdk_23", "artifacts": [ { "os": "linux", @@ -29,7 +29,7 @@ { "name": "maven-bundle-ce", "core": true, - "jdk": "jdk_22", + "jdk": "jdk_23", "override_name":"maven-resource-bundle", "artifacts": [ { @@ -40,9 +40,9 @@ ] }, { - "name": "js-native-standalone-svm-java22", + "name": "js-native-standalone-svm-java23", "core": true, - "jdk": "jdk_22", + "jdk": "jdk_23", "override_name":"graaljs", "artifacts": [ { @@ -73,9 +73,9 @@ ] }, { - "name": "js-java-standalone-svm-java22", + "name": "js-java-standalone-svm-java23", "core": true, - "jdk": "jdk_22", + "jdk": "jdk_23", "override_name":"graaljs", "artifacts": [ { @@ -106,9 +106,9 @@ ] }, { - "name": "nodejs-native-standalone-svm-java22", + "name": "nodejs-native-standalone-svm-java23", "core": true, - "jdk": "jdk_22", + "jdk": "jdk_23", "override_name":"graalnodejs", "artifacts": [ { @@ -139,9 +139,9 @@ ] }, { - "name": "nodejs-java-standalone-svm-java22", + "name": "nodejs-java-standalone-svm-java23", "core": true, - "jdk": "jdk_22", + "jdk": "jdk_23", "override_name":"graalnodejs", "artifacts": [ { @@ -172,9 +172,9 @@ ] }, { - "name": "ruby-native-standalone-svm-java22", + "name": "ruby-native-standalone-svm-java23", "core": true, - "jdk": "jdk_22", + "jdk": "jdk_23", "override_name":"truffleruby", "artifacts": [ { @@ -200,9 +200,9 @@ ] }, { - "name": "ruby-java-standalone-svm-java22", + "name": "ruby-java-standalone-svm-java23", "core": true, - "jdk": "jdk_22", + "jdk": "jdk_23", "override_name":"truffleruby", "artifacts": [ { @@ -228,9 +228,9 @@ ] }, { - "name": "python-native-standalone-svm-java22", + "name": "python-native-standalone-svm-java23", "core": true, - "jdk": "jdk_22", + "jdk": "jdk_23", "override_name":"graalpy", "artifacts": [ { @@ -261,9 +261,9 @@ ] }, { - "name": "python-java-standalone-svm-java22", + "name": "python-java-standalone-svm-java23", "core": true, - "jdk": "jdk_22", + "jdk": "jdk_23", "override_name":"graalpy", "artifacts": [ { @@ -294,9 +294,9 @@ ] }, { - "name": "wasm-native-standalone-svm-java22", + "name": "wasm-native-standalone-svm-java23", "core": true, - "jdk": "jdk_22", + "jdk": "jdk_23", "override_name": "graalwasm", "artifacts": [ { @@ -327,9 +327,9 @@ ] }, { - "name": "wasm-java-standalone-svm-java22", + "name": "wasm-java-standalone-svm-java23", "core": true, - "jdk": "jdk_22", + "jdk": "jdk_23", "override_name": "graalwasm", "artifacts": [ { From 883a571a6a3d3f6f7d6f241a0da32ddcc39706db Mon Sep 17 00:00:00 2001 From: Jirka Marsik Date: Wed, 3 Jan 2024 15:39:22 +0100 Subject: [PATCH 353/593] Hide SIMD support behind a flag --- .../src/org/graalvm/wasm/BinaryParser.java | 25 ++++++++++++------- .../org/graalvm/wasm/BinaryStreamParser.java | 15 ++++++++--- .../org/graalvm/wasm/WasmContextOptions.java | 10 ++++++++ .../src/org/graalvm/wasm/WasmOptions.java | 4 +++ 4 files changed, 41 insertions(+), 13 deletions(-) diff --git a/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/BinaryParser.java b/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/BinaryParser.java index 61fe18c86338..b0c113a11cab 100644 --- a/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/BinaryParser.java +++ b/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/BinaryParser.java @@ -115,6 +115,7 @@ public class BinaryParser extends BinaryStreamParser { private final boolean memory64; private final boolean multiMemory; private final boolean threads; + private final boolean simd; private final boolean unsafeMemory; @@ -131,6 +132,7 @@ public BinaryParser(WasmModule module, WasmContext context, byte[] data) { this.memory64 = context.getContextOptions().supportMemory64(); this.multiMemory = context.getContextOptions().supportMultiMemory(); this.threads = context.getContextOptions().supportThreads(); + this.simd = context.getContextOptions().supportSIMD(); this.unsafeMemory = context.getContextOptions().useUnsafeMemory(); } @@ -420,7 +422,7 @@ private void readImportSection() { break; } case ImportIdentifier.GLOBAL: { - byte type = readValueType(bulkMemoryAndRefTypes); + byte type = readValueType(bulkMemoryAndRefTypes, simd); byte mutability = readMutability(); int index = module.symbolTable().numGlobals(); module.symbolTable().importGlobal(moduleName, memberName, index, type, mutability); @@ -520,7 +522,7 @@ private ByteArrayList readCodeEntryLocals() { final int groupLength = readUnsignedInt32(); localsLength += groupLength; module.limits().checkLocalCount(localsLength); - final byte t = readValueType(bulkMemoryAndRefTypes); + final byte t = readValueType(bulkMemoryAndRefTypes, simd); for (int i = 0; i != groupLength; ++i) { localTypes.add(t); } @@ -597,7 +599,7 @@ private CodeEntry readFunction(int functionIndex, byte[] locals, byte[] resultTy case Instructions.BLOCK: { final byte[] blockParamTypes; final byte[] blockResultTypes; - readBlockType(multiResult, bulkMemoryAndRefTypes); + readBlockType(multiResult, bulkMemoryAndRefTypes, simd); // Extract value based on result arity. if (multiResult[1] == SINGLE_RESULT_VALUE) { blockParamTypes = WasmType.VOID_TYPE_ARRAY; @@ -616,7 +618,7 @@ private CodeEntry readFunction(int functionIndex, byte[] locals, byte[] resultTy // Jumps are targeting the loop instruction for OSR. final byte[] loopParamTypes; final byte[] loopResultTypes; - readBlockType(multiResult, bulkMemoryAndRefTypes); + readBlockType(multiResult, bulkMemoryAndRefTypes, simd); // Extract value based on result arity. if (multiResult[1] == SINGLE_RESULT_VALUE) { loopParamTypes = WasmType.VOID_TYPE_ARRAY; @@ -635,7 +637,7 @@ private CodeEntry readFunction(int functionIndex, byte[] locals, byte[] resultTy state.popChecked(I32_TYPE); // condition final byte[] ifParamTypes; final byte[] ifResultTypes; - readBlockType(multiResult, bulkMemoryAndRefTypes); + readBlockType(multiResult, bulkMemoryAndRefTypes, simd); // Extract value based on result arity. if (multiResult[1] == SINGLE_RESULT_VALUE) { ifParamTypes = WasmType.VOID_TYPE_ARRAY; @@ -763,7 +765,7 @@ private CodeEntry readFunction(int functionIndex, byte[] locals, byte[] resultTy checkBulkMemoryAndRefTypesSupport(opcode); final int length = readLength(); assertIntEqual(length, 1, Failure.INVALID_RESULT_ARITY); - final byte t = readValueType(bulkMemoryAndRefTypes); + final byte t = readValueType(bulkMemoryAndRefTypes, simd); state.popChecked(I32_TYPE); state.popChecked(t); state.popChecked(t); @@ -1798,6 +1800,7 @@ private void readNumericInstructions(ParserState state, int opcode) { } break; case Instructions.VECTOR: + checkSIMDSupport(); int vectorOpcode = read1() & 0xFF; state.addVectorFlag(); switch (vectorOpcode) { @@ -1881,6 +1884,10 @@ private void checkThreadsSupport(int opcode) { checkContextOption(wasmContext.getContextOptions().supportThreads(), "Threads and atomics are not enabled (opcode: 0x%02x)", opcode); } + private void checkSIMDSupport() { + checkContextOption(wasmContext.getContextOptions().supportSIMD(), "Vector instructions are not enabled (opcode: 0x%02x)", Instructions.VECTOR); + } + private void store(ParserState state, byte type, int n, long[] result) { int alignHint = readAlignHint(n); final int memoryIndex = readMemoryIndexFromAlignHint(alignHint); @@ -2381,7 +2388,7 @@ private void readGlobalSection() { final int startingGlobalIndex = module.symbolTable().numGlobals(); for (int globalIndex = startingGlobalIndex; globalIndex != startingGlobalIndex + globalCount; globalIndex++) { assertTrue(!isEOF(), Failure.LENGTH_OUT_OF_BOUNDS); - final byte type = readValueType(bulkMemoryAndRefTypes); + final byte type = readValueType(bulkMemoryAndRefTypes, simd); // 0x00 means const, 0x01 means var final byte mutability = readMutability(); // Global initialization expressions must be constant expressions: @@ -2516,14 +2523,14 @@ private void readFunctionType() { private void readParameterList(int funcTypeIdx, int paramCount) { for (int paramIdx = 0; paramIdx != paramCount; ++paramIdx) { - byte type = readValueType(bulkMemoryAndRefTypes); + byte type = readValueType(bulkMemoryAndRefTypes, simd); module.symbolTable().registerFunctionTypeParameterType(funcTypeIdx, paramIdx, type); } } private void readResultList(int funcTypeIdx, int resultCount) { for (int resultIdx = 0; resultIdx != resultCount; resultIdx++) { - byte type = readValueType(bulkMemoryAndRefTypes); + byte type = readValueType(bulkMemoryAndRefTypes, simd); module.symbolTable().registerFunctionTypeResultType(funcTypeIdx, resultIdx, type); } } diff --git a/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/BinaryStreamParser.java b/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/BinaryStreamParser.java index 9189c0f6f02b..9e419df1e73c 100644 --- a/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/BinaryStreamParser.java +++ b/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/BinaryStreamParser.java @@ -276,7 +276,7 @@ protected int offset() { * @param result The array used for returning the result. * */ - protected void readBlockType(int[] result, boolean allowRefTypes) { + protected void readBlockType(int[] result, boolean allowRefTypes, boolean allowVecType) { byte type = peek1(data, offset); switch (type) { case WasmType.VOID_TYPE: @@ -284,7 +284,12 @@ protected void readBlockType(int[] result, boolean allowRefTypes) { case WasmType.I64_TYPE: case WasmType.F32_TYPE: case WasmType.F64_TYPE: + offset++; + result[0] = type; + result[1] = SINGLE_RESULT_VALUE; + break; case WasmType.V128_TYPE: + Assert.assertTrue(allowVecType, Failure.MALFORMED_VALUE_TYPE); offset++; result[0] = type; result[1] = SINGLE_RESULT_VALUE; @@ -305,14 +310,16 @@ protected void readBlockType(int[] result, boolean allowRefTypes) { } } - protected static byte peekValueType(byte[] data, int offset, boolean allowRefTypes) { + protected static byte peekValueType(byte[] data, int offset, boolean allowRefTypes, boolean allowVecType) { byte b = peek1(data, offset); switch (b) { case WasmType.I32_TYPE: case WasmType.I64_TYPE: case WasmType.F32_TYPE: case WasmType.F64_TYPE: + break; case WasmType.V128_TYPE: + Assert.assertTrue(allowVecType, Failure.MALFORMED_VALUE_TYPE); break; case WasmType.FUNCREF_TYPE: case WasmType.EXTERNREF_TYPE: @@ -324,8 +331,8 @@ protected static byte peekValueType(byte[] data, int offset, boolean allowRefTyp return b; } - protected byte readValueType(boolean allowRefTypes) { - byte b = peekValueType(data, offset, allowRefTypes); + protected byte readValueType(boolean allowRefTypes, boolean allowVecType) { + byte b = peekValueType(data, offset, allowRefTypes, allowVecType); offset++; return b; } diff --git a/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/WasmContextOptions.java b/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/WasmContextOptions.java index d0f1a468c955..87df2fb729e5 100644 --- a/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/WasmContextOptions.java +++ b/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/WasmContextOptions.java @@ -57,6 +57,7 @@ public class WasmContextOptions { @CompilationFinal private boolean multiMemory; @CompilationFinal private boolean unsafeMemory; @CompilationFinal private boolean threads; + @CompilationFinal private boolean simd; @CompilationFinal private boolean memoryOverheadMode; @CompilationFinal private boolean constantRandomGet; @@ -84,6 +85,7 @@ private void setOptionValues() { this.multiMemory = readBooleanOption(WasmOptions.MultiMemory); this.threads = readBooleanOption(WasmOptions.Threads); this.unsafeMemory = readBooleanOption(WasmOptions.UseUnsafeMemory); + this.simd = readBooleanOption(WasmOptions.SIMD); this.memoryOverheadMode = readBooleanOption(WasmOptions.MemoryOverheadMode); this.constantRandomGet = readBooleanOption(WasmOptions.WasiConstantRandomGet); this.debugCompDirectory = readStringOption(WasmOptions.DebugCompDirectory); @@ -143,6 +145,10 @@ public boolean useUnsafeMemory() { return unsafeMemory; } + public boolean supportSIMD() { + return simd; + } + public boolean memoryOverheadMode() { return memoryOverheadMode; } @@ -166,6 +172,7 @@ public int hashCode() { hash = 54 * hash + (this.extendedConstExpressions ? 1 : 0); hash = 53 * hash + (this.multiMemory ? 1 : 0); hash = 53 * hash + (this.unsafeMemory ? 1 : 0); + hash = 53 * hash + (this.simd ? 1 : 0); hash = 53 * hash + (this.memoryOverheadMode ? 1 : 0); hash = 53 * hash + (this.constantRandomGet ? 1 : 0); hash = 53 * hash + (this.debugCompDirectory.hashCode()); @@ -211,6 +218,9 @@ public boolean equals(Object obj) { if (this.unsafeMemory != other.unsafeMemory) { return false; } + if (this.simd != other.simd) { + return false; + } if (this.memoryOverheadMode != other.memoryOverheadMode) { return false; } diff --git a/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/WasmOptions.java b/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/WasmOptions.java index b4206f477393..b50c1add4d80 100644 --- a/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/WasmOptions.java +++ b/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/WasmOptions.java @@ -103,6 +103,10 @@ public enum ConstantsStorePolicy { category = OptionCategory.EXPERT, stability = OptionStability.EXPERIMENTAL, usageSyntax = "false|true") // public static final OptionKey ExtendedConstExpressions = new OptionKey<>(false); + @Option(help = "Enable support for the v128 type and vector instructions", // + category = OptionCategory.EXPERT, stability = OptionStability.EXPERIMENTAL, usageSyntax = "false|true") // + public static final OptionKey SIMD = new OptionKey<>(false); + @Option(help = "In this mode memories and tables are not initialized.", category = OptionCategory.INTERNAL, stability = OptionStability.EXPERIMENTAL, usageSyntax = "false|true") // public static final OptionKey MemoryOverheadMode = new OptionKey<>(false); From 6be80470451914889e9888622429559967a95c38 Mon Sep 17 00:00:00 2001 From: Tomas Zezula Date: Wed, 3 Jan 2024 18:37:56 +0100 Subject: [PATCH 354/593] [GR-51149] Wrong error message when polyglot implementation is missing. --- .../src/org/graalvm/polyglot/Engine.java | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/sdk/src/org.graalvm.polyglot/src/org/graalvm/polyglot/Engine.java b/sdk/src/org.graalvm.polyglot/src/org/graalvm/polyglot/Engine.java index bfd161abe887..9fcf2bc86037 100644 --- a/sdk/src/org.graalvm.polyglot/src/org/graalvm/polyglot/Engine.java +++ b/sdk/src/org.graalvm.polyglot/src/org/graalvm/polyglot/Engine.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * The Universal Permissive License (UPL), Version 1.0 @@ -2252,6 +2252,10 @@ public String findLanguage(String mimeType) { return null; } + @Override + public String getTruffleVersion() { + return getPolyglotVersion().toString(); + } } private static final class EngineShutDownHook implements Runnable { From 955de4d94acf019c44c2455abe55a65b53b48c1f Mon Sep 17 00:00:00 2001 From: Tom Shull Date: Wed, 8 Nov 2023 09:45:46 +0100 Subject: [PATCH 355/593] introduce ReportFatalErroronOutOfMemoryError --- .../com/oracle/svm/core/SubstrateGCOptions.java | 3 +++ .../com/oracle/svm/core/heap/OutOfMemoryUtil.java | 15 +++++++++++++++ 2 files changed, 18 insertions(+) diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/SubstrateGCOptions.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/SubstrateGCOptions.java index 88b3d02101a7..f302e0a11452 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/SubstrateGCOptions.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/SubstrateGCOptions.java @@ -84,6 +84,9 @@ protected void onValueUpdate(EconomicMap, Object> values, Long oldV @Option(help = "Exit on the first occurrence of an out-of-memory error that is thrown because the Java heap is out of memory.", type = OptionType.Expert)// public static final RuntimeOptionKey ExitOnOutOfMemoryError = new NotifyGCRuntimeOptionKey<>(false); + @Option(help = "Report a fatal error on the first occurrence of an out-of-memory error that is thrown because the Java heap is out of memory.", type = OptionType.Expert)// + public static final RuntimeOptionKey ReportFatalErrorOnOutOfMemoryError = new RuntimeOptionKey<>(false); + @Option(help = "Ignore calls to System.gc().", type = OptionType.Expert)// public static final RuntimeOptionKey DisableExplicitGC = new NotifyGCRuntimeOptionKey<>(false); diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/heap/OutOfMemoryUtil.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/heap/OutOfMemoryUtil.java index 5ab7d43ebeb5..21b8448fab59 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/heap/OutOfMemoryUtil.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/heap/OutOfMemoryUtil.java @@ -24,6 +24,11 @@ */ package com.oracle.svm.core.heap; +import org.graalvm.nativeimage.ImageSingletons; +import org.graalvm.nativeimage.LogHandler; +import org.graalvm.nativeimage.Platform; +import org.graalvm.nativeimage.impl.InternalPlatform; + import com.oracle.svm.core.SubstrateGCOptions; import com.oracle.svm.core.SubstrateOptions; import com.oracle.svm.core.Uninterruptible; @@ -68,6 +73,16 @@ public static OutOfMemoryError reportOutOfMemoryError(OutOfMemoryError error) { VMError.shouldNotReachHere("ExitOnOutOfMemoryError can only be used if the LibC support is present."); } } + + if (SubstrateGCOptions.ReportFatalErrorOnOutOfMemoryError.getValue()) { + if (Platform.includedIn(InternalPlatform.NATIVE_ONLY.class)) { + Log.log().string("Reporting Fatal Error due to java.lang.OutOfMemoryError: ").exception(error); + } else { + Log.log().string("Reporting Fatal Error due to java.lang.OutOfMemoryError").newline(); + } + ImageSingletons.lookup(LogHandler.class).fatalError(); + } + throw error; } } From 600c75aadbca5a59d8e8700af3af0299566dc1b1 Mon Sep 17 00:00:00 2001 From: Tomas Zezula Date: Thu, 4 Jan 2024 09:55:25 +0100 Subject: [PATCH 356/593] [GR-51153] PEGraphDecoder#handleInvokeWithCallTarget check for a method from an unlinked class is no more valid. --- .../src/jdk/graal/compiler/replacements/PEGraphDecoder.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/replacements/PEGraphDecoder.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/replacements/PEGraphDecoder.java index d61d3d0690e1..ee6be27268f3 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/replacements/PEGraphDecoder.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/replacements/PEGraphDecoder.java @@ -999,7 +999,7 @@ protected LoopScope handleInvokeWithCallTarget(PEMethodScope methodScope, LoopSc } callTarget = trySimplifyCallTarget(methodScope, invokeData, methodCall); ResolvedJavaMethod targetMethod = callTarget.targetMethod(); - if (forceLink && targetMethod.hasBytecodes() && targetMethod.getCode() == null && !targetMethod.getDeclaringClass().isLinked()) { + if (forceLink && targetMethod.getCodeSize() == -1) { targetMethod.getDeclaringClass().link(); } LoopScope inlineLoopScope = trySimplifyInvoke(methodScope, loopScope, invokeData, (MethodCallTargetNode) callTarget); From af764cf5cd747d94489d6bbbe28f8f77dc73dba0 Mon Sep 17 00:00:00 2001 From: David Leopoldseder Date: Thu, 4 Jan 2024 11:48:12 +0100 Subject: [PATCH 357/593] move new VirtualThread.notifyJvmtiDisabledSuspend intrinsic to toBeInvestigated until GR-51158 is fixed --- .../compiler/hotspot/meta/UnimplementedGraalIntrinsics.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/meta/UnimplementedGraalIntrinsics.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/meta/UnimplementedGraalIntrinsics.java index 6f1c57d11738..af5306ff9259 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/meta/UnimplementedGraalIntrinsics.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/meta/UnimplementedGraalIntrinsics.java @@ -117,6 +117,8 @@ public UnimplementedGraalIntrinsics() { "jdk/jfr/internal/JVM.getEventWriter()Ljdk/jfr/internal/event/EventWriter;"); add(toBeInvestigated, // @formatter:off + // JDK-8311218 + "java/lang/VirtualThread.notifyJvmtiDisableSuspend(Z)V", // JDK-8309130: x86_64 AVX512 intrinsics for Arrays.sort methods (GR-48679) "java/util/DualPivotQuicksort.partition(Ljava/lang/Class;Ljava/lang/Object;JIIIILjava/util/DualPivotQuicksort$PartitionOperation;)[I", "java/util/DualPivotQuicksort.sort(Ljava/lang/Class;Ljava/lang/Object;JIILjava/util/DualPivotQuicksort$SortOperation;)V", From 944f5d1d89719a08fa50565a005fc528efa7894f Mon Sep 17 00:00:00 2001 From: David Leopoldseder Date: Thu, 4 Jan 2024 11:48:55 +0100 Subject: [PATCH 358/593] svm: disable the new VirtualThread.notifyJvmtiDisableSuspend intrinsic until JVMTI is supported on svm --- .../com/oracle/svm/core/jdk/JDK23OrLater.java | 36 +++++++++++++++++++ .../Target_java_lang_VirtualThread.java | 8 +++++ 2 files changed, 44 insertions(+) create mode 100644 substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/JDK23OrLater.java diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/JDK23OrLater.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/JDK23OrLater.java new file mode 100644 index 000000000000..dce1a40dae78 --- /dev/null +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/JDK23OrLater.java @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2024, 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.svm.core.jdk; + +import java.util.function.BooleanSupplier; + +import jdk.graal.compiler.serviceprovider.JavaVersionUtil; + +public class JDK23OrLater implements BooleanSupplier { + @Override + public boolean getAsBoolean() { + return JavaVersionUtil.JAVA_SPEC >= 23; + } +} diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/thread/Target_java_lang_VirtualThread.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/thread/Target_java_lang_VirtualThread.java index b1e050cb558b..5927a8b8054b 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/thread/Target_java_lang_VirtualThread.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/thread/Target_java_lang_VirtualThread.java @@ -47,6 +47,7 @@ import com.oracle.svm.core.annotate.TargetElement; import com.oracle.svm.core.jdk.JDK21OrEarlier; import com.oracle.svm.core.jdk.JDK22OrLater; +import com.oracle.svm.core.jdk.JDK23OrLater; import com.oracle.svm.core.jfr.HasJfrSupport; import com.oracle.svm.core.jfr.SubstrateJVM; import com.oracle.svm.core.monitor.MonitorInflationCause; @@ -216,6 +217,13 @@ private void notifyJvmtiHideFrames(boolean hide) { // unimplemented (GR-45392) } + @Substitute + @SuppressWarnings({"static-method", "unused"}) + @TargetElement(onlyWith = JDK23OrLater.class) + private void notifyJvmtiDisableSuspend(boolean hide) { + // unimplemented (GR-51158) + } + @Alias volatile Thread carrierThread; @Alias volatile Target_sun_nio_ch_Interruptible nioBlocker; From 7e72e78b43bb0f1e862e11ec68e31cf78d6981f4 Mon Sep 17 00:00:00 2001 From: David Leopoldseder Date: Thu, 4 Jan 2024 14:44:44 +0100 Subject: [PATCH 359/593] add jdk22 or earlier for verious substitutions --- .../oracle/svm/core/jdk/JDK22OrEarlier.java | 36 +++++++++++++++++++ 1 file changed, 36 insertions(+) create mode 100644 substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/JDK22OrEarlier.java diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/JDK22OrEarlier.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/JDK22OrEarlier.java new file mode 100644 index 000000000000..7c5b240aaeb1 --- /dev/null +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/JDK22OrEarlier.java @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2024, 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.svm.core.jdk; + +import java.util.function.BooleanSupplier; + +import jdk.graal.compiler.serviceprovider.JavaVersionUtil; + +public class JDK22OrEarlier implements BooleanSupplier { + @Override + public boolean getAsBoolean() { + return JavaVersionUtil.JAVA_SPEC <= 22; + } +} From 7727397f1186c1e96a33f72f291cca58360eaf2c Mon Sep 17 00:00:00 2001 From: David Leopoldseder Date: Thu, 4 Jan 2024 15:34:35 +0100 Subject: [PATCH 360/593] fix naming --- .../oracle/svm/core/thread/Target_java_lang_VirtualThread.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/thread/Target_java_lang_VirtualThread.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/thread/Target_java_lang_VirtualThread.java index 5927a8b8054b..d8de56243df6 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/thread/Target_java_lang_VirtualThread.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/thread/Target_java_lang_VirtualThread.java @@ -220,7 +220,7 @@ private void notifyJvmtiHideFrames(boolean hide) { @Substitute @SuppressWarnings({"static-method", "unused"}) @TargetElement(onlyWith = JDK23OrLater.class) - private void notifyJvmtiDisableSuspend(boolean hide) { + private void notifyJvmtiDisableSuspend(boolean enter) { // unimplemented (GR-51158) } From de8636d62a9a87ec3de334584e8cebc3bdc4310a Mon Sep 17 00:00:00 2001 From: Fabio Niephaus Date: Wed, 3 Jan 2024 13:11:27 +0100 Subject: [PATCH 361/593] Put additional JDK libs into bin/ dir on Windows. --- sdk/mx.sdk/mx_sdk_vm_impl.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/sdk/mx.sdk/mx_sdk_vm_impl.py b/sdk/mx.sdk/mx_sdk_vm_impl.py index 4df39802976e..9a9c8a437ab3 100644 --- a/sdk/mx.sdk/mx_sdk_vm_impl.py +++ b/sdk/mx.sdk/mx_sdk_vm_impl.py @@ -2890,7 +2890,8 @@ def add_files_from_component(comp, path_prefix, excluded_paths): 'path': None, }) # additional JDK libraries need to be in the launcher's directory - layout.setdefault(dirname(launcher_dest) + '/', []).append({ + destination = path_prefix + '/bin/' if mx.is_windows() else dirname(launcher_dest) + '/' + layout.setdefault(destination, []).append({ 'source_type': 'dependency', 'dependency': dependency, 'exclude': [], @@ -2938,7 +2939,8 @@ def add_files_from_component(comp, path_prefix, excluded_paths): }) if not _skip_libraries(library_config): # additional JDK libraries need to be in the library's directory - layout.setdefault(dirname(library_dest) + '/', []).append({ + destination = path_prefix + '/bin/' if mx.is_windows() else dirname(library_dest) + '/' + layout.setdefault(destination, []).append({ 'source_type': 'dependency', 'dependency': dependency, 'exclude': [], From 7e22c17766fa21ba292afad540ee72ec2cc4cb9e Mon Sep 17 00:00:00 2001 From: Christian Haeubl Date: Fri, 5 Jan 2024 12:16:57 +0100 Subject: [PATCH 362/593] Provide a method to set the physical memory size. --- .../src/com/oracle/svm/core/heap/PhysicalMemory.java | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/heap/PhysicalMemory.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/heap/PhysicalMemory.java index ddbcf533339b..2f234bcd8548 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/heap/PhysicalMemory.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/heap/PhysicalMemory.java @@ -63,6 +63,12 @@ public static boolean isInitializationInProgress() { return LOCK.isHeldByCurrentThread(); } + @Uninterruptible(reason = "May only be called during early startup.") + public static void setSize(UnsignedWord value) { + VMError.guarantee(!isInitialized(), "PhysicalMemorySize must not be initialized yet."); + cachedSize = value; + } + /** * Returns the size of physical memory in bytes, querying it from the OS if it has not been * initialized yet. From a2bfdaea9f9ce3657bc2de8c635bb9679f656ede Mon Sep 17 00:00:00 2001 From: Jirka Marsik Date: Fri, 5 Jan 2024 17:32:27 +0100 Subject: [PATCH 363/593] Use ExplodeLoop kind FULL_UNROLL in all vector ops --- .../src/org/graalvm/wasm/nodes/WasmFunctionNode.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/nodes/WasmFunctionNode.java b/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/nodes/WasmFunctionNode.java index 7b18a1eda1db..61089b26a5f3 100644 --- a/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/nodes/WasmFunctionNode.java +++ b/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/nodes/WasmFunctionNode.java @@ -3928,7 +3928,7 @@ private static void i32x4_all_true(VirtualFrame frame, int stackPointer) { pushInt(frame, stackPointer - 1, result); } - @ExplodeLoop + @ExplodeLoop(kind = ExplodeLoop.LoopExplosionKind.FULL_UNROLL) private static void i32x4_binop(VirtualFrame frame, int stackPointer, int vectorOpcode) { int[] x = popVector128(frame, stackPointer - 1).asInts(); int[] y = popVector128(frame, stackPointer - 2).asInts(); @@ -3947,7 +3947,7 @@ private static void i32x4_binop(VirtualFrame frame, int stackPointer, int vector pushVector128(frame, stackPointer - 2, Vector128.ofInts(result)); } - @ExplodeLoop + @ExplodeLoop(kind = ExplodeLoop.LoopExplosionKind.FULL_UNROLL) private static void f64x2_relop(VirtualFrame frame, int stackPointer, int vectorOpcode) { double[] x = popVector128(frame, stackPointer - 1).asDoubles(); double[] y = popVector128(frame, stackPointer - 2).asDoubles(); @@ -3969,7 +3969,7 @@ private static void f64x2_relop(VirtualFrame frame, int stackPointer, int vector pushVector128(frame, stackPointer - 2, Vector128.ofLongs(result)); } - @ExplodeLoop + @ExplodeLoop(kind = ExplodeLoop.LoopExplosionKind.FULL_UNROLL) private static void f64x2_unop(VirtualFrame frame, int stackPointer, int vectorOpcode) { double[] x = popVector128(frame, stackPointer - 1).asDoubles(); double[] result = new double[2]; @@ -3990,7 +3990,7 @@ private static void f64x2_unop(VirtualFrame frame, int stackPointer, int vectorO pushVector128(frame, stackPointer - 1, Vector128.ofDoubles(result)); } - @ExplodeLoop + @ExplodeLoop(kind = ExplodeLoop.LoopExplosionKind.FULL_UNROLL) private static void f64x2_binop(VirtualFrame frame, int stackPointer, int vectorOpcode) { double[] x = popVector128(frame, stackPointer - 1).asDoubles(); double[] y = popVector128(frame, stackPointer - 2).asDoubles(); From 75a83b9339b437eb5389f503db11e98df1fc9184 Mon Sep 17 00:00:00 2001 From: Marouane El Hallaoui Date: Fri, 5 Jan 2024 21:52:08 +0100 Subject: [PATCH 364/593] deploy snapshots --- common.json | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/common.json b/common.json index c2ffce6cbbbb..66a5069d713a 100644 --- a/common.json +++ b/common.json @@ -45,12 +45,12 @@ "labsjdk-ee-21-llvm": {"name": "labsjdk", "version": "ee-21.0.1+11-jvmci-23.1-b26-sulong", "platformspecific": true }, "oraclejdk-latest": {"name": "jpg-jdk", "version": "23", "build_id": "3", "release": true, "platformspecific": true, "extrabundles": ["static-libs"]}, - "labsjdk-ce-latest": {"name": "labsjdk", "version": "ce-23+3-jvmci-b01-20231222172622-47cbd747ea", "platformspecific": true }, - "labsjdk-ce-latestDebug": {"name": "labsjdk", "version": "ce-23+3-jvmci-b01-20231222172622-47cbd747ea-debug", "platformspecific": true }, - "labsjdk-ce-latest-llvm": {"name": "labsjdk", "version": "ce-23+3-jvmci-b01-20231222172622-47cbd747ea-sulong", "platformspecific": true }, - "labsjdk-ee-latest": {"name": "labsjdk", "version": "ee-23+3-jvmci-b01-20231222172622-47cbd747ea+40f899c1b9", "platformspecific": true }, - "labsjdk-ee-latestDebug": {"name": "labsjdk", "version": "ee-23+3-jvmci-b01-20231222172622-47cbd747ea+40f899c1b9-debug", "platformspecific": true }, - "labsjdk-ee-latest-llvm": {"name": "labsjdk", "version": "ee-23+3-jvmci-b01-20231222172622-47cbd747ea+40f899c1b9-sulong", "platformspecific": true } + "labsjdk-ce-latest": {"name": "labsjdk", "version": "ce-23+3-jvmci-b01", "platformspecific": true }, + "labsjdk-ce-latestDebug": {"name": "labsjdk", "version": "ce-23+3-jvmci-b01-debug", "platformspecific": true }, + "labsjdk-ce-latest-llvm": {"name": "labsjdk", "version": "ce-23+3-jvmci-b01-sulong", "platformspecific": true }, + "labsjdk-ee-latest": {"name": "labsjdk", "version": "ee-23+3-jvmci-b01", "platformspecific": true }, + "labsjdk-ee-latestDebug": {"name": "labsjdk", "version": "ee-23+3-jvmci-b01-debug", "platformspecific": true }, + "labsjdk-ee-latest-llvm": {"name": "labsjdk", "version": "ee-23+3-jvmci-b01-sulong", "platformspecific": true } }, "eclipse": { From 65112f1291002e564e8214c626e6be1ff0b61698 Mon Sep 17 00:00:00 2001 From: ol-automation_ww Date: Fri, 5 Jan 2024 21:09:30 +0000 Subject: [PATCH 365/593] Update truffleruby import. --- vm/mx.vm/suite.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vm/mx.vm/suite.py b/vm/mx.vm/suite.py index 6f1f6c1d714d..5108097c3f21 100644 --- a/vm/mx.vm/suite.py +++ b/vm/mx.vm/suite.py @@ -49,7 +49,7 @@ }, { "name": "truffleruby", - "version": "26f8683a5208566f45fd887453a95471d665603c", + "version": "7c5bef1358b704a5cfa67ff17c4c763d567ff9e0", "dynamic": True, "urls": [ {"url": "https://github.com/oracle/truffleruby.git", "kind": "git"}, From 9761497ea57a58478abed0614b7cb278ee203933 Mon Sep 17 00:00:00 2001 From: ol-automation_ww Date: Sat, 6 Jan 2024 02:30:50 +0000 Subject: [PATCH 366/593] [GR-23997] Periodic update of the graal import (2024-01-05). PullRequest: js/3021 --- vm/mx.vm/suite.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/vm/mx.vm/suite.py b/vm/mx.vm/suite.py index 6f1f6c1d714d..2f4386148939 100644 --- a/vm/mx.vm/suite.py +++ b/vm/mx.vm/suite.py @@ -33,7 +33,7 @@ "name": "graal-nodejs", "subdir": True, "dynamic": True, - "version": "b7e93e4cb0fb2cc3050aa384746c9e2e2cb0d0cd", + "version": "999f4ab64ed6978692183f24bc836d2eed76046f", "urls" : [ {"url" : "https://github.com/graalvm/graaljs.git", "kind" : "git"}, ] @@ -42,7 +42,7 @@ "name": "graal-js", "subdir": True, "dynamic": True, - "version": "b7e93e4cb0fb2cc3050aa384746c9e2e2cb0d0cd", + "version": "999f4ab64ed6978692183f24bc836d2eed76046f", "urls": [ {"url": "https://github.com/graalvm/graaljs.git", "kind" : "git"}, ] From 96b100ea5a3cbcd2e0847c6722b003dd21585afe Mon Sep 17 00:00:00 2001 From: Tomas Zezula Date: Fri, 5 Jan 2024 12:35:21 +0100 Subject: [PATCH 367/593] [GR-50843] Executing some bootstrap methods cause permissions issues in Truffle. --- .../svm/truffle/tck/PermissionsFeature.java | 39 ++++++++++--------- 1 file changed, 21 insertions(+), 18 deletions(-) diff --git a/substratevm/src/com.oracle.svm.truffle.tck/src/com/oracle/svm/truffle/tck/PermissionsFeature.java b/substratevm/src/com.oracle.svm.truffle.tck/src/com/oracle/svm/truffle/tck/PermissionsFeature.java index 592f90e285dd..5f6750329264 100644 --- a/substratevm/src/com.oracle.svm.truffle.tck/src/com/oracle/svm/truffle/tck/PermissionsFeature.java +++ b/substratevm/src/com.oracle.svm.truffle.tck/src/com/oracle/svm/truffle/tck/PermissionsFeature.java @@ -41,7 +41,6 @@ import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; -import java.util.LinkedHashSet; import java.util.LinkedList; import java.util.List; import java.util.Map; @@ -279,10 +278,9 @@ public void afterAnalysis(AfterAnalysisAccess access) { for (BaseMethodNode deniedMethod : deniedMethods) { if (cg.containsKey(deniedMethod)) { collectViolations(report, deniedMethod, - maxStackDepth, - Options.TruffleTCKPermissionsMaxErrors.getValue(), + maxStackDepth, Options.TruffleTCKPermissionsMaxErrors.getValue(), cg, contextFilters, - new LinkedHashSet<>(), 1, 0); + new LinkedList<>(), new HashSet<>(), 1, 0); } } if (!report.isEmpty()) { @@ -447,7 +445,9 @@ private static boolean isBackTraceOverLanguageMethod(AnalysisMethodNode method, * @param callGraph call graph obtained from * {@link PermissionsFeature#callGraph(BigBang, Set, DebugContext, SVMHost)} * @param contextFilters filters removing known valid calls - * @param visited visited methods + * @param currentPath current path from a privileged method in a call graph + * @param visited set of already visited methods, these methods are already part of an existing + * report or do not lead to language class * @param depth current depth */ private int collectViolations( @@ -457,7 +457,8 @@ private int collectViolations( int maxReports, Map> callGraph, Set contextFilters, - LinkedHashSet visited, + List currentPath, + Set visited, int depth, int initialNumReports) { int numReports = initialNumReports; @@ -476,25 +477,27 @@ private int collectViolations( } if (!visited.contains(mNode)) { visited.add(mNode); + currentPath.add(mNode); try { Set callers = callGraph.get(mNode); if (depth > maxDepth) { if (!callers.isEmpty()) { - numReports = collectViolations(report, callers.iterator().next(), maxDepth, maxReports, callGraph, contextFilters, visited, depth + 1, numReports); + numReports = collectViolations(report, callers.iterator().next(), maxDepth, maxReports, callGraph, contextFilters, currentPath, visited, depth + 1, numReports); } } else if (!isSystemClass(mNode)) { - List callPath = new ArrayList<>(visited); + List callPath = new ArrayList<>(currentPath); report.add(callPath); numReports++; } else { for (BaseMethodNode caller : callers) { - if (contextFilters.stream().noneMatch((f) -> f.test(mNode, caller, visited))) { - numReports = collectViolations(report, caller, maxDepth, maxReports, callGraph, contextFilters, visited, depth + 1, numReports); + if (contextFilters.stream().noneMatch((f) -> f.test(mNode, caller, currentPath))) { + numReports = collectViolations(report, caller, maxDepth, maxReports, callGraph, contextFilters, currentPath, visited, depth + 1, numReports); } } } } finally { - visited.remove(mNode); + BaseMethodNode last = currentPath.removeLast(); + assert last == mNode; } } return numReports; @@ -625,7 +628,7 @@ private interface CallGraphFilter { /** * @return whether this methodNode should not be considered a violation */ - boolean test(BaseMethodNode methodNode, BaseMethodNode callerNode, LinkedHashSet trace); + boolean test(BaseMethodNode methodNode, BaseMethodNode callerNode, List trace); Collection getInspectedMethods(); } @@ -655,7 +658,7 @@ private static final class SafeInterruptRecognizer implements CallGraphFilter { } @Override - public boolean test(BaseMethodNode methodNode, BaseMethodNode callerNode, LinkedHashSet trace) { + public boolean test(BaseMethodNode methodNode, BaseMethodNode callerNode, List trace) { Boolean res = null; if (threadInterrupt.equals(methodNode)) { AnalysisMethod caller = callerNode.getMethod(); @@ -696,7 +699,7 @@ private static final class SafePrivilegedRecognizer implements CallGraphFilter { } @Override - public boolean test(BaseMethodNode methodNode, BaseMethodNode callerNode, LinkedHashSet trace) { + public boolean test(BaseMethodNode methodNode, BaseMethodNode callerNode, List trace) { if (!doPrivileged.contains(methodNode)) { return false; } @@ -732,7 +735,7 @@ public boolean test(BaseMethodNode methodNode, BaseMethodNode callerNode, Linked /** * Finds an entry point to {@code PrivilegedAction} called by {@code doPrivilegedMethod}. */ - private ResolvedJavaMethod findPrivilegedEntryPoint(ResolvedJavaMethod doPrivilegedMethod, LinkedHashSet trace) { + private ResolvedJavaMethod findPrivilegedEntryPoint(ResolvedJavaMethod doPrivilegedMethod, List trace) { ResolvedJavaMethod ep = null; for (BaseMethodNode mNode : trace) { AnalysisMethod m = mNode.getMethod(); @@ -766,7 +769,7 @@ private static final class SafeServiceLoaderRecognizer implements CallGraphFilte } @Override - public boolean test(BaseMethodNode methodNode, BaseMethodNode callerNode, LinkedHashSet trace) { + public boolean test(BaseMethodNode methodNode, BaseMethodNode callerNode, List trace) { if (providerImplGet.equals(methodNode)) { ResolvedJavaType instantiatedType = findInstantiatedType(trace); return instantiatedType != null && !isRegisteredInServiceLoader(instantiatedType); @@ -777,7 +780,7 @@ public boolean test(BaseMethodNode methodNode, BaseMethodNode callerNode, Linked /** * Finds last constructor invocation. */ - private static ResolvedJavaType findInstantiatedType(LinkedHashSet trace) { + private static ResolvedJavaType findInstantiatedType(List trace) { ResolvedJavaType res = null; for (BaseMethodNode mNode : trace) { AnalysisMethod m = mNode.getMethod(); @@ -839,7 +842,7 @@ private static final class SafeSetThreadNameRecognizer implements CallGraphFilte } @Override - public boolean test(BaseMethodNode methodNode, BaseMethodNode callerNode, LinkedHashSet trace) { + public boolean test(BaseMethodNode methodNode, BaseMethodNode callerNode, List trace) { if (!threadSetName.equals(methodNode)) { return false; } From 19fe00039da8672e5b48c093e3bde7c258a49b7e Mon Sep 17 00:00:00 2001 From: Tomas Zezula Date: Fri, 5 Jan 2024 17:45:12 +0100 Subject: [PATCH 368/593] [GR-50843] Added record and switch bootstrap methods into allows list. --- .../oracle/svm/truffle/tck/resources/jre.json | 22 +++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/substratevm/src/com.oracle.svm.truffle.tck/src/com/oracle/svm/truffle/tck/resources/jre.json b/substratevm/src/com.oracle.svm.truffle.tck/src/com/oracle/svm/truffle/tck/resources/jre.json index 9e5bdf92a21a..cbd731ad5a85 100644 --- a/substratevm/src/com.oracle.svm.truffle.tck/src/com/oracle/svm/truffle/tck/resources/jre.json +++ b/substratevm/src/com.oracle.svm.truffle.tck/src/com/oracle/svm/truffle/tck/resources/jre.json @@ -221,6 +221,28 @@ } ] }, + { + "name": "java.lang.runtime.ObjectMethods", + "methods":[ + { + "name": "bootstrap", + "justification": "Bootstrap method for record's toString, hashCode and equals methods." + } + ] + }, + { + "name": "java.lang.runtime.SwitchBootstraps", + "methods":[ + { + "name": "typeSwitch", + "justification": "Bootstrap method for switch on a reference type." + }, + { + "name": "enumSwitch", + "justification": "Bootstrap method for switch on enum constants." + } + ] + }, { "name": "java.math.BigInteger", "methods": [ From 25150f623b5d2f04e55ab21afef277ff4183c365 Mon Sep 17 00:00:00 2001 From: Fabio Niephaus Date: Mon, 8 Jan 2024 09:49:57 +0100 Subject: [PATCH 369/593] Ensure all pip dependencies are installed. --- .github/workflows/main.yml | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 79e3185baea3..acd09050c514 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -199,9 +199,7 @@ jobs: if: ${{ env.MX_RUNS_STYLE == 'true' }} run: | sudo apt install python3-pip python-setuptools - sudo pip install ninja_syntax$(jq -r '.pip.ninja_syntax' common.json) - sudo pip install lazy-object-proxy$(jq -r '.pip["lazy-object-proxy"]' common.json) - sudo pip install pylint$(jq -r '.pip.pylint' common.json) + sudo pip install $(jq -r '[.pip | to_entries[] | join("")] | join(" ")' common.json) - name: Install additional pip packages if: ${{ matrix.env.PIP_PACKAGES != '' }} run: ${MX_PYTHON} -m pip install ${{ matrix.env.PIP_PACKAGES }} From a6e7d3416214422a9d1fc35a683114515b2f1e83 Mon Sep 17 00:00:00 2001 From: Fengyun Liu Date: Mon, 27 Nov 2023 11:41:18 +0100 Subject: [PATCH 370/593] [GR-50357] Remove iterated instrumentation --- sdk/mx.sdk/mx_sdk_benchmark.py | 7 ------ vm/mx.vm/mx_vm_benchmark.py | 46 ++++++++++------------------------ 2 files changed, 13 insertions(+), 40 deletions(-) diff --git a/sdk/mx.sdk/mx_sdk_benchmark.py b/sdk/mx.sdk/mx_sdk_benchmark.py index 8b20b1d84558..dd9425bc410e 100644 --- a/sdk/mx.sdk/mx_sdk_benchmark.py +++ b/sdk/mx.sdk/mx_sdk_benchmark.py @@ -250,13 +250,6 @@ def benchmark_output_dir(self, _, args): else: return None - def pgo_iteration_num(self, _, args): - parsed_args = parse_prefixed_args('-Dnative-image.benchmark.pgo-iteration-num=', args) - if parsed_args: - return int(parsed_args[0]) - else: - return None - def stages(self, args): parsed_arg = parse_prefixed_arg('-Dnative-image.benchmark.stages=', args, 'Native Image benchmark stages should only be specified once.') return parsed_arg.split(',') if parsed_arg else ['agent', 'instrument-image', 'instrument-run', 'image', 'run'] diff --git a/vm/mx.vm/mx_vm_benchmark.py b/vm/mx.vm/mx_vm_benchmark.py index b0ac2d2d1636..dfaccd8e8834 100644 --- a/vm/mx.vm/mx_vm_benchmark.py +++ b/vm/mx.vm/mx_vm_benchmark.py @@ -148,7 +148,6 @@ def __init__(self, vm, bm_suite, args): self.extra_profile_run_args = bm_suite.extra_profile_run_arg(self.benchmark_name, args, list(image_run_args), not vm.safepoint_sampler) self.extra_agent_profile_run_args = bm_suite.extra_agent_profile_run_arg(self.benchmark_name, args, list(image_run_args)) self.benchmark_output_dir = bm_suite.benchmark_output_dir(self.benchmark_name, args) - self.pgo_iteration_num = bm_suite.pgo_iteration_num(self.benchmark_name, args) self.params = ['extra-image-build-argument', 'extra-jvm-arg', 'extra-run-arg', 'extra-agent-run-arg', 'extra-profile-run-arg', 'extra-agent-profile-run-arg', 'benchmark-output-dir', 'stages', 'skip-agent-assertions'] @@ -265,7 +264,6 @@ def __init__(self, name, config_name, extra_java_args=None, extra_launcher_args= mx.warn(f"Ignoring: {kwargs}") self.vm_args = None - self.pgo_instrumented_iterations = 0 self.pgo_context_sensitive = True self.is_gate = False self.is_quickbuild = False @@ -348,24 +346,18 @@ def _configure_from_name(self, config_name): pgo_mode = matching.group("pgo")[:-1] if pgo_mode == "pgo": mx.logv(f"'pgo' is enabled for {config_name}") - self.pgo_instrumented_iterations = 1 elif pgo_mode == "pgo-ctx-insens": mx.logv(f"'pgo-ctx-insens' is enabled for {config_name}") - self.pgo_instrumented_iterations = 1 self.pgo_context_sensitive = False else: mx.abort(f"Unknown pgo mode: {pgo_mode}") if matching.group("inliner") is not None: inliner = matching.group("inliner")[:-1] - if self.pgo_instrumented_iterations < 1: - mx.abort(f"The selected inliner require PGO! Invalid configuration: {config_name}") - elif inliner == "iterative": + if inliner == "iterative": mx.logv(f"'iterative' inliner is enabled for {config_name}") - self.pgo_instrumented_iterations = 3 elif inliner == "inline-explored": mx.logv(f"'inline-explored' is enabled for {config_name}") - self.pgo_instrumented_iterations = 3 else: mx.abort(f"Unknown inliner configuration: {inliner}") @@ -373,7 +365,6 @@ def _configure_from_name(self, config_name): config = matching.group("jdk_profiles")[:-1] if config == 'jdk-profiles-collect': self.jdk_profiles_collect = True - self.pgo_instrumented_iterations = 1 def generate_profiling_package_prefixes(): # run the native-image-configure tool to gather the jdk package prefixes @@ -407,7 +398,6 @@ def generate_profiling_package_prefixes(): profile_inference_config = matching.group("profile_inference")[:-1] if profile_inference_config == 'profile-inference-feature-extraction': self.profile_inference_feature_extraction = True - self.pgo_instrumented_iterations = 1 # extract code features else: mx.abort('Unknown profile inference configuration: {}.'.format(profile_inference_config)) @@ -415,7 +405,6 @@ def generate_profiling_package_prefixes(): config = matching.group("sampler")[:-1] if config == 'safepoint-sampler': self.safepoint_sampler = True - self.pgo_instrumented_iterations = 1 elif config == 'async-sampler': self.async_sampler = True else: @@ -933,11 +922,11 @@ def run_stage_agent(self, config, stages): if file.endswith(".json"): zipf.write(os.path.join(root, file), os.path.relpath(os.path.join(root, file), os.path.join(path, '..'))) - def run_stage_instrument_image(self, config, stages, out, i, instrumentation_image_name, image_path, image_path_latest, instrumented_iterations, profile_path): + def run_stage_instrument_image(self, config, stages, out, instrumentation_image_name, image_path, profile_path): executable_name_args = ['-o', instrumentation_image_name] pgo_args = ['--pgo=' + config.latest_profile_path] pgo_args += svm_experimental_options(['-H:' + ('+' if self.pgo_context_sensitive else '-') + 'PGOContextSensitivityEnabled']) - instrument_args = ['--pgo-instrument', '-R:ProfilesDumpFile=' + profile_path] + ([] if i == 0 else pgo_args) + instrument_args = ['--pgo-instrument', '-R:ProfilesDumpFile=' + profile_path] + pgo_args if self.jdk_profiles_collect: instrument_args += svm_experimental_options(['-H:+AOTPriorityInline', '-H:-SamplingCollect', f'-H:ProfilingPackagePrefixes={self.generate_profiling_package_prefixes()}']) @@ -946,8 +935,6 @@ def run_stage_instrument_image(self, config, stages, out, i, instrumentation_ima if config.bundle_path is not None: NativeImageVM.copy_bundle_output(config) if s.exit_code == 0: - mx.copyfile(image_path, image_path_latest) - if i + 1 == instrumented_iterations and s.exit_code == 0: image_size = os.stat(image_path).st_size out('Instrumented image size: ' + str(image_size) + ' B') @@ -992,7 +979,6 @@ def run_stage_image(self, config, stages, out): executable_name_args = ['-o', config.final_image_name] pgo_args = ['--pgo=' + config.latest_profile_path] pgo_args += svm_experimental_options(['-H:' + ('+' if self.pgo_context_sensitive else '-') + 'PGOContextSensitivityEnabled']) - instrumented_iterations = self.pgo_instrumented_iterations if config.pgo_iteration_num is None else int(config.pgo_iteration_num) if self.adopted_jdk_pgo: # choose appropriate profiles jdk_version = mx.get_jdk().javaCompliance @@ -1014,7 +1000,7 @@ def run_stage_image(self, config, stages, out): mx.warn("To dump the profile inference features to a specific location, please set the '{}' flag.".format(dump_file_flag)) else: ml_args = [] - final_image_command = config.base_image_build_args + executable_name_args + (pgo_args if instrumented_iterations > 0 else []) + jdk_profiles_args + ml_args + final_image_command = config.base_image_build_args + executable_name_args + pgo_args + jdk_profiles_args + ml_args with stages.set_command(final_image_command) as s: s.execute_command() if config.bundle_path is not None: @@ -1060,7 +1046,6 @@ def run_java(self, args, out=None, err=None, cwd=None, nonZeroIsFatal=False): self.config = config stages = NativeImageVM.Stages(config, out, err, self.is_gate, True if self.is_gate else nonZeroIsFatal, os.path.abspath(cwd if cwd else os.getcwd())) self.stages = stages - instrumented_iterations = self.pgo_instrumented_iterations if config.pgo_iteration_num is None else int(config.pgo_iteration_num) if not os.path.exists(config.output_dir): os.makedirs(config.output_dir) @@ -1069,23 +1054,18 @@ def run_java(self, args, out=None, err=None, cwd=None, nonZeroIsFatal=False): os.makedirs(config.config_dir) if stages.change_stage('agent'): - if instrumented_iterations == 0 and config.last_stage.startswith('instrument-'): - config.last_stage = 'agent' self.run_stage_agent(config, stages) # Native Image profile collection - for i in range(instrumented_iterations): - profile_path = config.profile_path_no_extension + '-' + str(i) + config.profile_file_extension - instrumentation_image_name = config.executable_name + '-instrument-' + str(i) - instrumentation_image_latest = config.executable_name + '-instrument-latest' - - image_path = os.path.join(config.output_dir, instrumentation_image_name) - image_path_latest = os.path.join(config.output_dir, instrumentation_image_latest) - if stages.change_stage('instrument-image', str(i)): - self.run_stage_instrument_image(config, stages, out, i, instrumentation_image_name, image_path, image_path_latest, instrumented_iterations, profile_path) - - if stages.change_stage('instrument-run', str(i)): - self.run_stage_instrument_run(config, stages, image_path, profile_path) + profile_path = config.profile_path_no_extension + config.profile_file_extension + instrumentation_image_name = config.executable_name + '-instrument' + + image_path = os.path.join(config.output_dir, instrumentation_image_name) + if stages.change_stage('instrument-image'): + self.run_stage_instrument_image(config, stages, out, instrumentation_image_name, image_path, profile_path) + + if stages.change_stage('instrument-run'): + self.run_stage_instrument_run(config, stages, image_path, profile_path) # Build the final image if stages.change_stage('image'): From 26f860bdf9e02bc841ed1f2b3ad6d256f4355b3b Mon Sep 17 00:00:00 2001 From: Fengyun Liu Date: Tue, 19 Dec 2023 14:52:00 +0100 Subject: [PATCH 371/593] Remove invalid options during instrumented image build We cannot pass `-pgo=...` during instrumented image build, because the option will set `-H:Opitimize=O3`, while the instrumentation build disallow setting the option. --- vm/mx.vm/mx_vm_benchmark.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/vm/mx.vm/mx_vm_benchmark.py b/vm/mx.vm/mx_vm_benchmark.py index dfaccd8e8834..e2855c7bc305 100644 --- a/vm/mx.vm/mx_vm_benchmark.py +++ b/vm/mx.vm/mx_vm_benchmark.py @@ -924,9 +924,7 @@ def run_stage_agent(self, config, stages): def run_stage_instrument_image(self, config, stages, out, instrumentation_image_name, image_path, profile_path): executable_name_args = ['-o', instrumentation_image_name] - pgo_args = ['--pgo=' + config.latest_profile_path] - pgo_args += svm_experimental_options(['-H:' + ('+' if self.pgo_context_sensitive else '-') + 'PGOContextSensitivityEnabled']) - instrument_args = ['--pgo-instrument', '-R:ProfilesDumpFile=' + profile_path] + pgo_args + instrument_args = ['--pgo-instrument', '-R:ProfilesDumpFile=' + profile_path] if self.jdk_profiles_collect: instrument_args += svm_experimental_options(['-H:+AOTPriorityInline', '-H:-SamplingCollect', f'-H:ProfilingPackagePrefixes={self.generate_profiling_package_prefixes()}']) From 29a0d42f1363a15b374f10b605f39fe9f67da91f Mon Sep 17 00:00:00 2001 From: Fengyun Liu Date: Mon, 8 Jan 2024 10:09:08 +0100 Subject: [PATCH 372/593] Don't run instrumentation on CE benchmarks --- vm/mx.vm/mx_vm_benchmark.py | 21 +++++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-) diff --git a/vm/mx.vm/mx_vm_benchmark.py b/vm/mx.vm/mx_vm_benchmark.py index e2855c7bc305..91e623c3fd07 100644 --- a/vm/mx.vm/mx_vm_benchmark.py +++ b/vm/mx.vm/mx_vm_benchmark.py @@ -264,6 +264,7 @@ def __init__(self, name, config_name, extra_java_args=None, extra_launcher_args= mx.warn(f"Ignoring: {kwargs}") self.vm_args = None + self.pgo_instrumentation = False self.pgo_context_sensitive = True self.is_gate = False self.is_quickbuild = False @@ -346,8 +347,10 @@ def _configure_from_name(self, config_name): pgo_mode = matching.group("pgo")[:-1] if pgo_mode == "pgo": mx.logv(f"'pgo' is enabled for {config_name}") + self.pgo_instrumentation = True elif pgo_mode == "pgo-ctx-insens": mx.logv(f"'pgo-ctx-insens' is enabled for {config_name}") + self.pgo_instrumentation = True self.pgo_context_sensitive = False else: mx.abort(f"Unknown pgo mode: {pgo_mode}") @@ -356,8 +359,10 @@ def _configure_from_name(self, config_name): inliner = matching.group("inliner")[:-1] if inliner == "iterative": mx.logv(f"'iterative' inliner is enabled for {config_name}") + self.pgo_instrumentation = True elif inliner == "inline-explored": mx.logv(f"'inline-explored' is enabled for {config_name}") + self.pgo_instrumentation = True else: mx.abort(f"Unknown inliner configuration: {inliner}") @@ -365,6 +370,7 @@ def _configure_from_name(self, config_name): config = matching.group("jdk_profiles")[:-1] if config == 'jdk-profiles-collect': self.jdk_profiles_collect = True + self.pgo_instrumentation = True def generate_profiling_package_prefixes(): # run the native-image-configure tool to gather the jdk package prefixes @@ -398,6 +404,7 @@ def generate_profiling_package_prefixes(): profile_inference_config = matching.group("profile_inference")[:-1] if profile_inference_config == 'profile-inference-feature-extraction': self.profile_inference_feature_extraction = True + self.pgo_instrumentation = True # extract code features else: mx.abort('Unknown profile inference configuration: {}.'.format(profile_inference_config)) @@ -405,6 +412,7 @@ def generate_profiling_package_prefixes(): config = matching.group("sampler")[:-1] if config == 'safepoint-sampler': self.safepoint_sampler = True + self.pgo_instrumentation = True elif config == 'async-sampler': self.async_sampler = True else: @@ -998,7 +1006,7 @@ def run_stage_image(self, config, stages, out): mx.warn("To dump the profile inference features to a specific location, please set the '{}' flag.".format(dump_file_flag)) else: ml_args = [] - final_image_command = config.base_image_build_args + executable_name_args + pgo_args + jdk_profiles_args + ml_args + final_image_command = config.base_image_build_args + executable_name_args + (pgo_args if self.pgo_instrumentation else []) + jdk_profiles_args + ml_args with stages.set_command(final_image_command) as s: s.execute_command() if config.bundle_path is not None: @@ -1058,12 +1066,13 @@ def run_java(self, args, out=None, err=None, cwd=None, nonZeroIsFatal=False): profile_path = config.profile_path_no_extension + config.profile_file_extension instrumentation_image_name = config.executable_name + '-instrument' - image_path = os.path.join(config.output_dir, instrumentation_image_name) - if stages.change_stage('instrument-image'): - self.run_stage_instrument_image(config, stages, out, instrumentation_image_name, image_path, profile_path) + if self.pgo_instrumentation: + image_path = os.path.join(config.output_dir, instrumentation_image_name) + if stages.change_stage('instrument-image'): + self.run_stage_instrument_image(config, stages, out, instrumentation_image_name, image_path, profile_path) - if stages.change_stage('instrument-run'): - self.run_stage_instrument_run(config, stages, image_path, profile_path) + if stages.change_stage('instrument-run'): + self.run_stage_instrument_run(config, stages, image_path, profile_path) # Build the final image if stages.change_stage('image'): From a79c196b8d01aac256afd63856dff7a5bcd4c0ee Mon Sep 17 00:00:00 2001 From: Fengyun Liu Date: Mon, 8 Jan 2024 11:17:57 +0100 Subject: [PATCH 373/593] Remove obsolete iterative inliner and inline-explored (Thanks Patrick) --- vm/mx.vm/mx_vm_benchmark.py | 13 +------------ 1 file changed, 1 insertion(+), 12 deletions(-) diff --git a/vm/mx.vm/mx_vm_benchmark.py b/vm/mx.vm/mx_vm_benchmark.py index 91e623c3fd07..26a99694e3d6 100644 --- a/vm/mx.vm/mx_vm_benchmark.py +++ b/vm/mx.vm/mx_vm_benchmark.py @@ -301,7 +301,7 @@ def _configure_from_name(self, config_name): return # This defines the allowed config names for NativeImageVM. The ones registered will be available via --jvm-config - rule = r'^(?Pnative-architecture-)?(?Pstring-inlining-)?(?Pgate-)?(?Pupx-)?(?Pquickbuild-)?(?Pg1gc-)?(?Pllvm-)?(?Ppgo-|pgo-ctx-insens-)?(?Pinline-|iterative-|inline-explored-)?' \ + rule = r'^(?Pnative-architecture-)?(?Pstring-inlining-)?(?Pgate-)?(?Pupx-)?(?Pquickbuild-)?(?Pg1gc-)?(?Pllvm-)?(?Ppgo-|pgo-ctx-insens-)?(?Pinline-)?' \ r'(?Pinsens-|allocsens-|1obj-|2obj1h-|3obj2h-|4obj3h-)?(?Pno-inline-)?(?Pjdk-profiles-collect-|adopted-jdk-pgo-)?' \ r'(?Pprofile-inference-feature-extraction-)?(?Psafepoint-sampler-|async-sampler-)?(?PO0-|O1-|O2-|O3-)?(?Pce-|ee-)?$' @@ -355,17 +355,6 @@ def _configure_from_name(self, config_name): else: mx.abort(f"Unknown pgo mode: {pgo_mode}") - if matching.group("inliner") is not None: - inliner = matching.group("inliner")[:-1] - if inliner == "iterative": - mx.logv(f"'iterative' inliner is enabled for {config_name}") - self.pgo_instrumentation = True - elif inliner == "inline-explored": - mx.logv(f"'inline-explored' is enabled for {config_name}") - self.pgo_instrumentation = True - else: - mx.abort(f"Unknown inliner configuration: {inliner}") - if matching.group("jdk_profiles") is not None: config = matching.group("jdk_profiles")[:-1] if config == 'jdk-profiles-collect': From 983e2777d0b1574bcc5ef91fd962d61a25899c39 Mon Sep 17 00:00:00 2001 From: Peter Hofer Date: Fri, 5 Jan 2024 18:18:18 +0100 Subject: [PATCH 374/593] Avoid needlessly rescanning objects. --- .../svm/core/genscavenge/AlignedHeapChunk.java | 4 ++-- .../svm/core/genscavenge/GreyObjectsWalker.java | 6 +++++- .../com/oracle/svm/core/genscavenge/HeapChunk.java | 14 +++++++------- 3 files changed, 14 insertions(+), 10 deletions(-) diff --git a/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/AlignedHeapChunk.java b/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/AlignedHeapChunk.java index e45c244257d0..8e45dbc58ced 100644 --- a/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/AlignedHeapChunk.java +++ b/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/AlignedHeapChunk.java @@ -149,8 +149,8 @@ static boolean walkObjects(AlignedHeader that, ObjectVisitor visitor) { @AlwaysInline("GC performance") @Uninterruptible(reason = "Called from uninterruptible code.", mayBeInlined = true) - static boolean walkObjectsInline(AlignedHeader that, ObjectVisitor visitor) { - return HeapChunk.walkObjectsFromInline(that, getObjectsStart(that), visitor); + static boolean walkObjectsFromInline(AlignedHeader that, Pointer start, ObjectVisitor visitor) { + return HeapChunk.walkObjectsFromInline(that, start, visitor); } @Fold diff --git a/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/GreyObjectsWalker.java b/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/GreyObjectsWalker.java index 09ad12fd3568..c0d70a40f52b 100644 --- a/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/GreyObjectsWalker.java +++ b/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/GreyObjectsWalker.java @@ -87,12 +87,15 @@ void walkGreyObjects() { @Uninterruptible(reason = "Called from uninterruptible code.", mayBeInlined = true) private void walkAlignedGreyObjects() { AlignedHeapChunk.AlignedHeader aChunk; + Pointer aStart; if (alignedHeapChunk.isNull() && alignedTop.isNull()) { /* If the snapshot is empty, then I have to walk from the beginning of the Space. */ aChunk = space.getFirstAlignedHeapChunk(); + aStart = (aChunk.isNonNull() ? AlignedHeapChunk.getObjectsStart(aChunk) : WordFactory.nullPointer()); } else { /* Otherwise walk Objects that arrived after the snapshot. */ aChunk = alignedHeapChunk; + aStart = alignedTop; } /* Visit Objects in the AlignedChunks. */ GreyToBlackObjectVisitor visitor = GCImpl.getGCImpl().getGreyToBlackObjectVisitor(); @@ -100,10 +103,11 @@ private void walkAlignedGreyObjects() { AlignedHeapChunk.AlignedHeader lastChunk; do { lastChunk = aChunk; - if (!AlignedHeapChunk.walkObjectsInline(aChunk, visitor)) { + if (!AlignedHeapChunk.walkObjectsFromInline(aChunk, aStart, visitor)) { throw VMError.shouldNotReachHereAtRuntime(); } aChunk = HeapChunk.getNext(aChunk); + aStart = (aChunk.isNonNull() ? AlignedHeapChunk.getObjectsStart(aChunk) : WordFactory.nullPointer()); } while (aChunk.isNonNull()); /* Move the scan point. */ diff --git a/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/HeapChunk.java b/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/HeapChunk.java index 33d7acb9f0b6..84406410daf5 100644 --- a/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/HeapChunk.java +++ b/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/HeapChunk.java @@ -297,20 +297,20 @@ private static SignedWord offsetFromPointer(Header that, PointerBase pointer) } @NeverInline("Not performance critical") - public static boolean walkObjectsFrom(Header that, Pointer offset, ObjectVisitor visitor) { - return walkObjectsFromInline(that, offset, visitor); + public static boolean walkObjectsFrom(Header that, Pointer start, ObjectVisitor visitor) { + return walkObjectsFromInline(that, start, visitor); } @AlwaysInline("GC performance") @Uninterruptible(reason = "Called from uninterruptible code.", mayBeInlined = true) - public static boolean walkObjectsFromInline(Header that, Pointer startOffset, ObjectVisitor visitor) { - Pointer offset = startOffset; - while (offset.belowThan(getTopPointer(that))) { // crucial: top can move, so always re-read - Object obj = offset.toObject(); + public static boolean walkObjectsFromInline(Header that, Pointer start, ObjectVisitor visitor) { + Pointer p = start; + while (p.belowThan(getTopPointer(that))) { // crucial: top can move, so always re-read + Object obj = p.toObject(); if (!callVisitor(visitor, obj)) { return false; } - offset = offset.add(LayoutEncoding.getSizeFromObjectInlineInGC(obj)); + p = p.add(LayoutEncoding.getSizeFromObjectInlineInGC(obj)); } return true; } From 41bae6679c0ff50a15feb0dc5d325162a2d159ab Mon Sep 17 00:00:00 2001 From: ol-automation_ww Date: Mon, 8 Jan 2024 14:54:29 +0000 Subject: [PATCH 375/593] update JVMCI to 23+4-jvmci-b01 --- common.json | 14 +++++++------- .../graal/compiler/hotspot/JVMCIVersionCheck.java | 4 ++-- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/common.json b/common.json index e9e919c4c50f..d2b5a8e886f2 100644 --- a/common.json +++ b/common.json @@ -44,13 +44,13 @@ "labsjdk-ee-21Debug": {"name": "labsjdk", "version": "ee-21.0.1+11-jvmci-23.1-b26-debug", "platformspecific": true }, "labsjdk-ee-21-llvm": {"name": "labsjdk", "version": "ee-21.0.1+11-jvmci-23.1-b26-sulong", "platformspecific": true }, - "oraclejdk-latest": {"name": "jpg-jdk", "version": "23", "build_id": "3", "release": true, "platformspecific": true, "extrabundles": ["static-libs"]}, - "labsjdk-ce-latest": {"name": "labsjdk", "version": "ce-23+3-jvmci-b01", "platformspecific": true }, - "labsjdk-ce-latestDebug": {"name": "labsjdk", "version": "ce-23+3-jvmci-b01-debug", "platformspecific": true }, - "labsjdk-ce-latest-llvm": {"name": "labsjdk", "version": "ce-23+3-jvmci-b01-sulong", "platformspecific": true }, - "labsjdk-ee-latest": {"name": "labsjdk", "version": "ee-23+3-jvmci-b01", "platformspecific": true }, - "labsjdk-ee-latestDebug": {"name": "labsjdk", "version": "ee-23+3-jvmci-b01-debug", "platformspecific": true }, - "labsjdk-ee-latest-llvm": {"name": "labsjdk", "version": "ee-23+3-jvmci-b01-sulong", "platformspecific": true } + "oraclejdk-latest": {"name": "jpg-jdk", "version": "23", "build_id": "4", "release": true, "platformspecific": true, "extrabundles": ["static-libs"]}, + "labsjdk-ce-latest": {"name": "labsjdk", "version": "ce-23+4-jvmci-b01-20240105210900-50fd6eca51", "platformspecific": true }, + "labsjdk-ce-latestDebug": {"name": "labsjdk", "version": "ce-23+4-jvmci-b01-20240105210900-50fd6eca51-debug", "platformspecific": true }, + "labsjdk-ce-latest-llvm": {"name": "labsjdk", "version": "ce-23+4-jvmci-b01-20240105210900-50fd6eca51-sulong", "platformspecific": true }, + "labsjdk-ee-latest": {"name": "labsjdk", "version": "ee-23+4-jvmci-b01-20240105210900-50fd6eca51+3e47329d85", "platformspecific": true }, + "labsjdk-ee-latestDebug": {"name": "labsjdk", "version": "ee-23+4-jvmci-b01-20240105210900-50fd6eca51+3e47329d85-debug", "platformspecific": true }, + "labsjdk-ee-latest-llvm": {"name": "labsjdk", "version": "ee-23+4-jvmci-b01-20240105210900-50fd6eca51+3e47329d85-sulong", "platformspecific": true } }, "eclipse": { diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/JVMCIVersionCheck.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/JVMCIVersionCheck.java index 5d019e28d2b9..ed7c992ba231 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/JVMCIVersionCheck.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/JVMCIVersionCheck.java @@ -54,8 +54,8 @@ public final class JVMCIVersionCheck { private static final Map> JVMCI_MIN_VERSIONS = Map.of( "21", Map.of(DEFAULT_VENDOR_ENTRY, new Version(23, 1, 26)), "23", Map.of( - "Oracle Corporation", new Version("23+3", 1), - DEFAULT_VENDOR_ENTRY, new Version("23+3", 1))); + "Oracle Corporation", new Version("23+4", 1), + DEFAULT_VENDOR_ENTRY, new Version("23+4", 1))); private static final int NA = 0; /** * Minimum Java release supported by Graal. From acdd38d106858ae7c985606cea4c9267cd5f380a Mon Sep 17 00:00:00 2001 From: Fabio Niephaus Date: Mon, 8 Jan 2024 16:53:33 +0100 Subject: [PATCH 376/593] Use Oracle JDK 17 to build Quarkus. --- .github/workflows/quarkus.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/quarkus.yml b/.github/workflows/quarkus.yml index aa249a96fb37..37049aebc15e 100644 --- a/.github/workflows/quarkus.yml +++ b/.github/workflows/quarkus.yml @@ -131,7 +131,7 @@ jobs: # Use Java 17 to build Quarkus as that's the lowest supported JDK version currently - uses: actions/setup-java@v4 with: - distribution: 'temurin' + distribution: 'oracle' java-version: '17' - name: Build Quarkus run: | @@ -196,7 +196,7 @@ jobs: run: tar -xzf maven-repo.tgz -C ~ - uses: actions/setup-java@v4 with: - distribution: 'temurin' + distribution: 'oracle' java-version: '17' - name: Build with Maven if: startsWith(matrix.os-name, 'ubuntu') From a73d61c60280eb69d840d79df5efffba37fae581 Mon Sep 17 00:00:00 2001 From: Fabio Niephaus Date: Mon, 8 Jan 2024 16:56:43 +0100 Subject: [PATCH 377/593] Update several actions. --- .github/workflows/main.yml | 6 +++--- .github/workflows/quarkus.yml | 16 ++++++++-------- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 79e3185baea3..2e262e43d8f9 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -161,21 +161,21 @@ jobs: MX_RUNS_STYLE: ${{ contains(matrix.env.GATE_TAGS, 'style') || matrix.env.GATE_TAGS == '' }} steps: - name: Checkout oracle/graal - uses: actions/checkout@v3 + uses: actions/checkout@v4 with: ref: ${{ github.ref }} # Lock ref to current branch to avoid fetching others fetch-depth: "${{ env.MX_RUNS_STYLE && '0' || '1' }}" # The style gate needs the full commit history for checking copyright years - name: Determine mx version run: echo "MX_VERSION=$(jq -r '.mx_version' common.json)" >> ${GITHUB_ENV} - name: Checkout graalvm/mx - uses: actions/checkout@v3 + uses: actions/checkout@v4 with: repository: graalvm/mx.git ref: ${{ env.MX_VERSION }} fetch-depth: 1 path: ${{ env.MX_PATH }} - name: Set up Python - uses: actions/setup-python@v4 + uses: actions/setup-python@v5 with: python-version: '3.8' - name: Update mx cache diff --git a/.github/workflows/quarkus.yml b/.github/workflows/quarkus.yml index 37049aebc15e..91e4633c6eb4 100644 --- a/.github/workflows/quarkus.yml +++ b/.github/workflows/quarkus.yml @@ -76,18 +76,18 @@ jobs: matrix: ${{ steps.read.outputs.matrix }} steps: - name: Checkout oracle/graal - uses: actions/checkout@v3 + uses: actions/checkout@v4 with: fetch-depth: 1 - name: Checkout graalvm/mx - uses: actions/checkout@v3 + uses: actions/checkout@v4 with: repository: graalvm/mx.git fetch-depth: 1 ref: master path: ${{ env.MX_PATH }} - name: Set up Python - uses: actions/setup-python@v4 + uses: actions/setup-python@v5 with: python-version: '3.8' - name: Get latest Quarkus release @@ -124,7 +124,7 @@ jobs: shell: bash run: tar -czvf graalvm.tgz -C $(dirname ${GRAALVM_HOME}) $(basename ${GRAALVM_HOME}) - name: Persist GraalVM build - uses: actions/upload-artifact@v1 + uses: actions/upload-artifact@v4 with: name: graalvm path: graalvm.tgz @@ -147,7 +147,7 @@ jobs: shell: bash run: tar -czvf maven-repo.tgz -C ~ .m2/repository - name: Persist Maven Repo - uses: actions/upload-artifact@v1 + uses: actions/upload-artifact@v4 with: name: maven-repo path: maven-repo.tgz @@ -165,7 +165,7 @@ jobs: steps: - name: Download GraalVM build if: startsWith(matrix.os-name, 'ubuntu') - uses: actions/download-artifact@v1 + uses: actions/download-artifact@v4 with: name: graalvm path: . @@ -186,7 +186,7 @@ jobs: run: ${QUARKUS_PATH}/.github/ci-prerequisites.sh - name: Download Maven Repo if: startsWith(matrix.os-name, 'ubuntu') - uses: actions/download-artifact@v1 + uses: actions/download-artifact@v4 with: name: maven-repo path: . @@ -212,7 +212,7 @@ jobs: shell: bash run: find . -type d -name '*-reports' -o -wholename '*/build/reports/tests/functionalTest' | tar -czf test-reports.tgz -T - - name: Upload failure Archive (if maven failed) - uses: actions/upload-artifact@v1 + uses: actions/upload-artifact@v4 if: failure() with: name: test-reports-native-${{matrix.category}} From bcec8a9e59126db648bae558b9b7a70d9bd68b47 Mon Sep 17 00:00:00 2001 From: Mike Hearn Date: Fri, 5 Jan 2024 16:02:24 +0100 Subject: [PATCH 378/593] Espresso: clean up README and add some internal docs. --- espresso/README.md | 111 ++------ espresso/docs/hacking.md | 93 +++++++ espresso/docs/how-espresso-works.md | 243 ++++++++++++++++++ .../espresso/launcher/EspressoLauncher.java | 5 + .../espresso/runtime/EspressoException.java | 4 + 5 files changed, 362 insertions(+), 94 deletions(-) create mode 100644 espresso/docs/hacking.md create mode 100644 espresso/docs/how-espresso-works.md diff --git a/espresso/README.md b/espresso/README.md index 335e75fcc0b7..68799e19c7fd 100644 --- a/espresso/README.md +++ b/espresso/README.md @@ -1,105 +1,28 @@ -# Espresso :coffee: -A meta-circular Java bytecode interpreter for the [GraalVM](https://github.com/oracle/graal). -Espresso is a fully meta-circular implementation of *The Java Virtual Machine Specification, Java SE [8](https://docs.oracle.com/javase/specs/jvms/se8/html/index.html) and [11](https://docs.oracle.com/javase/specs/jvms/se11/html/index.html) Edition*, written in Java, capable of running non-trivial programs at speed. -A Java bytecode interpreter at its core, turned Just-In-Time (JIT) compiler by leveraging [Truffle](https://github.com/oracle/graal/tree/master/truffle) and the Graal compiler on the GraalVM. -It highlights the sublime potential of the GraalVM as a platform for implementing high-performance languages and runtimes. +# Java On Truffle :coffee: -## Status -Espresso is still an early prototype, but it already passes the *Java Compatibility Kit* (a.k.a. the JCK or TCK for Java SE) 8c and 11 runtime suite. -Espresso can compile itself with both `javac` and (the Eclipse Java Compiler) `ecj`. -It features complete meta-circularity: it can run itself any amount of layers deep, preserving all the capabilities (Unsafe, JNI, Reflection...) of the base layer. Running HelloWorld on three nested layers of Espresso takes **~15 minutes**. - -Espresso is similar to *HotSpot Express*, the same codebase can run either an 8 or 11 guest JVM, on either an 8 or 11 host JVM. - -The development of Espresso happens mostly on HotSpot, but this configuration (Espresso on HotSpot) is only supported on Linux, see [Limitations](#1--limitations.) -. -**Espresso's native image runs on Linux, MacOS and Windows.** - -### Building _Espresso_ - -Set your (JVMCI-enabled) JDK via `mx` argument e.g. `mx --java-home /path/to/java/home ...` or via `export JAVA_HOME=/path/to/java/home`. - -`mx build`-ing Espresso creates a GraalVM with Espresso included. +Espresso is a full JVM capable of dynamic bytecode loading, written in Java using the Truffle framework. It can provide competitive performance when run on [GraalVM](https://github.com/oracle/graal). -To build the default configuration (interpreter-only), on the `espresso` repository: -```bash -$ mx build -``` +It has some unique features: -Other configurations are provided: -```bash -$ mx --env jvm build # GraalVM CE + Espresso jars (interpreter only) -$ mx --env jvm-ce build # GraalVM CE + Espresso jars (JIT) -$ mx --env native-ce build # GraalVM CE + Espresso native (JIT) +- Run Java code inside a sandboxed, isolated context using [GraalVM's sandboxing features](https://www.graalvm.org/latest/security-guide/polyglot-sandbox/). +- More comprehensive hotswap support than HotSpot, enabling you to easily patch code whilst the app is running by just recompiling your project in your IDE whilst attached with the debugger. Your app can react to HotSwap events in order to fix up internal state when needed. +- Can be used to dynamically load and run Java from inside an ahead of time compiled _native image_. +- Can be used to isolate and call code that requires an older Java version on a newer host JVM. -# Use the same --env argument used to build. -$ export ESPRESSO=`mx --env native-ce graalvm-home`/bin/espresso -``` +Why implement a JVM in Java? -Configuration files: `mx.espresso/{jvm,jvm-ce,native-ce}` and `mx.espresso/native-image.properties` +- It's easy to understand and work on. Adding features is easy. See [How Espresso Works](docs/how-espresso-works.md). +- Full self-hosting (meta-circularity) is a common goal for programming languages, as it proves they are fully general enough to implement themselves. +- It highlights the sublime potential of the GraalVM as a platform for implementing high-performance languages and runtimes. -### Running Espresso -`mx espresso` runs Espresso (from jars or native) from within a GraalVM. It mimics the `java` (8|11) command. Bare `mx espresso` runs Espresso on interpreter-only mode. - -```bash -$ mx --env jvm-ce build # Always build first -$ mx --env jvm-ce espresso -cp my.jar HelloWorld -``` - -To build and run Espresso native image: -```bash -$ mx --env native-ce build # Always build first -$ mx --env native-ce espresso -cp my.jar HelloWorld -``` - -The `mx espresso` launcher adds some overhead, to execute Espresso native image directly use: -```bash -$ mx --env native-ce build # Always build first -$ export ESPRESSO=`mx --env native-ce graalvm-home`/bin/espresso -$ time $ESPRESSO -cp my.jar HelloWorld -``` - -### `mx espresso-standalone ...` -To run Espresso on a vanilla JDK (8|11) and/or not within a GraalVM use `mx espresso-standalone ...`, it mimics the `java` (8|11) command. The launcher adds all jars and properties required to run Espresso on any vanilla JDK (8|11). - -To debug Espresso: -```bash -$ mx build -$ mx -d espresso-standalone -cp mxbuild/dists/jdk1.8/espresso-playground.jar com.oracle.truffle.espresso.playground.HelloWorld -``` +## Status -It can also run on a GraalVM with JIT compilation: -```bash -$ mx build -$ mx --dy /compiler espresso-standalone -cp my.jar HelloWorld -``` +Espresso is a fully supported implementation of the Java platform that ships in Oracle products and which is kept up to date with the latest Java versions. When the VM is compiled to a native image it runs on Windows, macOS and Linux. -### Dumping IGV graphs -```bash -$ mx -v --dy /compiler -J"-Djdk.graal.Dump=:4 -Djdk.graal.TraceTruffleCompilation=true -Djdk.graal.TruffleBackgroundCompilation=false" espresso-standalone -cp mxbuild/dists/jdk1.8/espresso-playground.jar com.oracle.truffle.espresso.playground.TestMain -``` +It features complete meta-circularity: it can run itself any amount of layers deep, preserving all the capabilities (Unsafe, JNI, Reflection...) of the base layer. Running HelloWorld on three nested layers of Espresso takes **~15 minutes**. -### Running Espresso cross-versions -By default, Espresso runs within a GraalVM and it reuses the jars and native libraries shipped with GraalVM. But it's possible to specify a different Java home, even with a different version; Espresso will automatically switch versions regardless of the host JVM. -```bash -$ mx build -$ mx espresso -version -$ mx espresso --java.JavaHome=/path/to/java/8/home -version -$ mx espresso --java.JavaHome=/path/to/java/11/home -version -``` +The development of Espresso happens mostly on HotSpot, but this configuration (Espresso on HotSpot) is only supported on Linux, see [Limitations](docs/hacking.md#limitations). -### Limitations -Espresso relies on glibc's [dlmopen](https://man7.org/linux/man-pages/man3/dlopen.3.html) to run on HotSpot, but this approach has limitations that lead to crashes e.g. `libnio.so: undefined symbol: fstatat64` . Some of these limitations can be by avoided by defining `LD_DEBUG=unused` e.g. -```bash -$ LD_DEBUG=unused mx espresso -cp mxbuild/dists/jdk1.8/espresso-playground.jar com.oracle.truffle.espresso.playground.Tetris -``` +## Working on Espresso -## _Espressoⁿ_ Java-ception -**Self-hosting requires a Linux distribution with an up-to-date glibc.** -Use `mx espresso-meta` to run programs on Espresso². Ensure to prepend `LD_DEBUG=unused` to overcome a known **glibc** bug. -To run HelloWorld on Espresso² execute the following: -```bash -$ mx build -$ LD_DEBUG=unused mx --dy /compiler espresso-meta -cp my.jar HelloWorld -``` -It takes some time for both (nested) VMs to boot, only the base layer is blessed with JIT compilation. Enjoy! +See the [hacking notes](docs/hacking.md). diff --git a/espresso/docs/hacking.md b/espresso/docs/hacking.md new file mode 100644 index 000000000000..d66842c98233 --- /dev/null +++ b/espresso/docs/hacking.md @@ -0,0 +1,93 @@ +# How to work on Espresso + +## Building + +Set your (JVMCI-enabled) JDK via `mx` argument e.g. `mx --java-home /path/to/java/home ...` or via `export JAVA_HOME=/path/to/java/home`. + +`mx build`-ing Espresso creates a GraalVM with Espresso included. + +To build the default configuration (interpreter-only), on the `espresso` repository: + +```bash +$ mx build +``` + +Other configurations are provided: +```bash +$ mx --env jvm build # GraalVM CE + Espresso jars (interpreter only) +$ mx --env jvm-ce build # GraalVM CE + Espresso jars (JIT) +$ mx --env native-ce build # GraalVM CE + Espresso native (JIT) + +# Use the same --env argument used to build. +$ export ESPRESSO=`mx --env native-ce graalvm-home`/bin/espresso +``` + +Configuration files: `mx.espresso/{jvm,jvm-ce,native-ce}` and `mx.espresso/native-image.properties` + +## Running Espresso +`mx espresso` runs Espresso (from jars or native) from within a GraalVM. It mimics the `java` (8|11) command. Bare `mx espresso` runs Espresso on interpreter-only mode. + +```bash +$ mx --env jvm-ce build # Always build first +$ mx --env jvm-ce espresso -cp my.jar HelloWorld +``` + +To build and run Espresso native image: +```bash +$ mx --env native-ce build # Always build first +$ mx --env native-ce espresso -cp my.jar HelloWorld +``` + +The `mx espresso` launcher adds some overhead, to execute Espresso native image directly use: +```bash +$ mx --env native-ce build # Always build first +$ export ESPRESSO=`mx --env native-ce graalvm-home`/bin/espresso +$ time $ESPRESSO -cp my.jar HelloWorld +``` + +## `mx espresso-standalone ...` +To run Espresso on a vanilla JDK (8|11) and/or not within a GraalVM use `mx espresso-standalone ...`, it mimics the `java` (8|11) command. The launcher adds all jars and properties required to run Espresso on any vanilla JDK (8|11). + +To debug Espresso: +```bash +$ mx build +$ mx -d espresso-standalone -cp mxbuild/dists/jdk1.8/espresso-playground.jar com.oracle.truffle.espresso.playground.HelloWorld +``` + +It can also run on a GraalVM with JIT compilation: +```bash +$ mx build +$ mx --dy /compiler espresso-standalone -cp my.jar HelloWorld +``` + +## Dumping IGV graphs +```bash +$ mx -v --dy /compiler -J"-Djdk.graal.Dump=:4 -Djdk.graal.TraceTruffleCompilation=true -Djdk.graal.TruffleBackgroundCompilation=false" espresso-standalone -cp mxbuild/dists/jdk1.8/espresso-playground.jar com.oracle.truffle.espresso.playground.TestMain +``` + +## Running Espresso cross-versions +By default, Espresso runs within a GraalVM and it reuses the jars and native libraries shipped with GraalVM. But it's possible to specify a different Java home, even with a different version; Espresso will automatically switch versions regardless of the host JVM. +```bash +$ mx build +$ mx espresso -version +$ mx espresso --java.JavaHome=/path/to/java/8/home -version +$ mx espresso --java.JavaHome=/path/to/java/11/home -version +``` + +## Limitations + +Espresso relies on glibc's [dlmopen](https://man7.org/linux/man-pages/man3/dlopen.3.html) to run on HotSpot, but this approach has limitations that lead to crashes e.g. `libnio.so: undefined symbol: fstatat64` . Some of these limitations can be by avoided by defining `LD_DEBUG=unused` e.g. + +```bash +$ LD_DEBUG=unused mx espresso -cp mxbuild/dists/jdk1.8/espresso-playground.jar com.oracle.truffle.espresso.playground.Tetris +``` + +## _Espressoⁿ_ Java-ception +**Self-hosting requires a Linux distribution with an up-to-date glibc.** +Use `mx espresso-meta` to run programs on Espresso². Ensure to prepend `LD_DEBUG=unused` to overcome a known **glibc** bug. +To run HelloWorld on Espresso² execute the following: +```bash +$ mx build +$ LD_DEBUG=unused mx --dy /compiler espresso-meta -cp my.jar HelloWorld +``` +It takes some time for both (nested) VMs to boot, only the base layer is blessed with JIT compilation. Enjoy! diff --git a/espresso/docs/how-espresso-works.md b/espresso/docs/how-espresso-works.md new file mode 100644 index 000000000000..59127195744a --- /dev/null +++ b/espresso/docs/how-espresso-works.md @@ -0,0 +1,243 @@ +# How Espresso works + +## Introduction + +_(All package paths are relative to `com.oracle.truffle.espresso`)_ + +Espresso is an implementation of a Java Virtual Machine that itself runs on a host JVM. This can make what's going on a +little confusing. To begin understanding the Espresso internals you should first learn about the Graal compiler and the +Truffle language implementation framework. Espresso does not contain components you might expect from a JVM like a +garbage collector, JIT compiler or operating system abstraction because they are already provided by lower levels of the +stack. Instead Espresso provides runtime services like: + +* Bytecode parsing, validation and interpretation. +* Debugging. +* HotSwap (changing code whilst it's running). +* JNI. +* A `java` launcher command. +* The "native" components of the standard library like `libjava` (in quotes because what native means can vary). + [See below](#native-components). +* Sandboxing. + +## How to attach a debugger + +A good way to start Espresso when working fully in JVM mode (Espresso isn't a native image), is to run: + +``` +mx --env jvm-ce espresso --log.file=/tmp/truffle-log '--vm.agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=*:8000' -cp .... hello.World +``` + +Espresso will pause at startup until you attach your IDE's debugger to it. + +## Modes of operation + +Espresso can be used in different configurations with differing tradeoffs. + +The **host VM** can be OpenJDK, GraalVM HotSpot or GraalVM Native Image. On OpenJDK Espresso will only execute in the +interpreter and is thus slow. With a regular GraalVM it executes faster, because the Graal compiler will be used which +knows how to accelerate Truffle languages, and with a Native Image host it is the fastest due to not needing the +Espresso VM itself to warm up. Additionally, virtual threads currently only work with a native image host. + +The **native components** that implement the JNI side of the standard library can be genuine operating system +specific machine code, in which case the host OS must be Linux and Java code cannot be sandboxed, or LLVM bitcode +executed via Sulong in which case it can in theory run on any OS and Java code can be sandboxed. + +## Startup sequence + +There are three ways that Espresso can be started up: + +1. Embedded in another program that uses the Truffle Polyglot API to create a context, e.g. for sandboxing. +2. By the user running `java -truffle -cp ...`. This requires that Espresso be compiled with native image and is the + normal way for users to interact with Espresso if they just want to treat it as a regular JVM. +3. By an Espresso developer (you) running `mx espresso`. This is the way to start Espresso as a JVM library and passes + control to `launcher.EspressoLauncher`, a simple Java program that somewhat unconvincingly pretends to be the `java` + launcher. It parses the flags and then uses the Polyglot API to create an Espresso context. + +No matter what path is used the first time Espresso gets control is in `EspressoLanguage`, which is instantiated +by Truffle when it's asked for a Java context. You can't actually evaluate Java sources with this language, only a few +commands in a control language that point Espresso at a classpath. `EspressoLanguage` in turn creates `EspressoContext`s +which contain the VM state for a Java world. + +When a user runs `java -truffle` execution starts at the regular native C `java` launcher from OpenJDK, which passes +control to `libjli` (the Java Launch Infrastructure). That looks up and instantiates the Espresso JVM when the +`-truffle` flag is passed. The launcher/`libjli` isn't patched to do this, instead a generic OpenJDK mechanism is used +in which the `-truffle` flag is mapped via the `jvm.cfg` file in the JVM `lib` directory to the file +`lib/truffle/libjvm.dylib`. This is a small native code library that in the source is called Mokapot. + +Mokapot exports both the JNI interface for creating a JVM and also the internal `JVM_*` methods that the OpenJDK +standard library modules sometimes call into from their own native code. It makes Espresso look like a regular JVM. +Mokapot doesn't contain Espresso itself. It's just a binding layer. Espresso will be found in +`lib/languages/libjavavm.{so,dylib,dll}`. This is a native image that exports some C APIs via the native image C +interface. In `libjavavm.LibEspresso` a C entry point is exported which creates a Polyglot context for the Espresso +engine, 'casts' it to the JNI interface and then returns it. + +So adding it all together the startup sequence for end users goes like this: + +`java -truffle ...` -> `libjli` -> `lib/truffle/libjvm` (mokapot) -> `libjavavm` (`LibEspresso`) -> Polyglot API -> `EspressoLauncher` -> `EspressoContext`. + +## Execution loop + +The core of the interpreter is in `nodes.BytecodeNode`, which is a Truffle node representing all the bytecodes in a +single regular guest method. It's a big `while (true)` loop. When a guest method becomes hot enough to be compiled by +Truffle the loop will be unrolled and partially evaluated, which is how the method gets translated to native code. + +### Quickening + +Most bytecodes are handled in the obvious way. Some are _quickened_. + +Truffle started as an AST interpreter and thus is very oriented around the concept of nodes (as in, AST nodes). It has +a lot of features that require nodes, and in particular nodes can be _specialized_ based on how they are actually used +whereas a bytecode generally cannot. Quickening bridges the two worlds. A bytecode that is quickened is replaced with +a special internal bytecode, `QUICK` or `SLIM_QUICK`, and a Truffle node is created for it then stored in the +`BytecodeNode`'s child node array. The quick opcode passes control to the right child node. + +Some examples of quickened opcodes include `instanceof`, and all the method invocation opcodes. Quickening trades off +extra memory for faster runtime, so some bytecodes are always quickened but others only sometimes. + +### Special methods + +Some methods are special and have to be implemented by the JVM itself. How these work depend on how they are reached. A +method in the standard library may appear to be a normal Java method but is actually replaced by a different +implementation (an intrinsic), usually one that's doing more optimal things that can't be expressed in regular Java. +Espresso implements these using _substitutions_, which are explained below. + +When the interpreter reaches a JNI method, control will be pass to either native code or into Sulong. The two +possibilities are abstracted by the (not Espresso specific) Truffle NFI "language", which acts as a generic FFI, so +native calls look like polyglot/interop calls. + +The OpenJDK version of the Java standard library has native methods, some of which call into HotSpot via +private APIs. Espresso implements these APIs in a library called `mokapot`, which is compiled to a `libjvm.so`/`jvm.dll` +file. The operating system links the stdlib native components to this library, and when code execution reaches +mokapot control is transferred back into the Java world via a thread local variable storing a struct of function +pointers, where it emerges in the static methods in `vm.VM`. + +### Liveness analysis + +The garbage collector looks at local variables on the stack to find objects that are still live. An edge case is +where a method puts a reference into a local variable that roots a large object graph, uses it briefly and then +enters a hot loop in which that local is never used again. The object graph could be collected but because it's still +referenced from the stack, it won't be. + +The solution is to do an analysis on the method to figure out when it's safe to automatically null out locals that +aren't being used anymore. The analysis has a cost, so it's only done for JIT compiled code and by default only when +there are a lot of locals. + +## Things in the guest world + +### The heap + +Objects allocated by guest code are all represented in the host heap as instances of +`runtime.staticobject.StaticObject`, including arrays and even `null`! The JVM executing the _host_ (Espresso) +provides garbage collection services. + +You may notice that this class has only a lock word and a pointer to the class of the object, and wonder where the +actual data is stored. The answer depends on what host JVM is being used. On HotSpot the Truffle framework synthesizes +bytecode to create and load subclasses of `StaticObject` with the right number of fields to store the guest data. This +lets guest code use the host garbage collector. On SubstrateVM (native image) you can't dynamically load classes, so an +alternative is required. SubstrateVM exposes APIs that let you define new class layouts at runtime (called "pods") which +the garbage collector then becomes aware of. Behind the scenes field accesses may be carefully checked, or they may have +their checks compiled out. That's useful for Espresso where the bytecode is statically verified ahead of time, so it's +known to be safe at the time it executes. To learn more about how object storage works, read about the [Truffle Static +Object Model](https://www.graalvm.org/latest/graalvm-as-a-platform/language-implementation-framework/StaticObjectModel/). + +### Reflecting guest heap objects + +The `meta.Meta` and `descriptors.Symbol` classes are boilerplate that makes reflecting guest classes more type safe and +convenient. It's especially convenient for navigating in the IDE, as it lets you do "Find Usages" to locate where a +guest symbol is being manipulated by the VM, without being distracted by all the places the host code is also using the +same symbol. + +Accessing guest objects is relatively straightforward. An `impl.Klass` is similar to (but not the same as) a `Class` in +the guest world. Once you've obtained one you can use it to read fields, call methods etc. If you want to access +_static_ fields, then you'll need to look up the field using `impl.Klass#lookupField()`, then use `getObject` on the +field passing in the result of `Klass#tryInitializeAndGetStatics()`. Static fields are stored in a separate +`StaticObject` and this will ensure the guest code `` runs to set up the static fields of the class you're +trying to access. The guest world `java.lang.reflect.Class` that matches a host `impl.ObjectKlass` can be obtained by +calling `ObjectKlass#mirror()`. + +Guest-world reflection objects are tied back to host-world objects using _hidden fields_. These are special kinds of +fields added to objects. Their names start with `0` making them illegal identifiers, ensuring there can never be +conflicts, and they are hidden from guest-world reflection. + +### The stack + +Guest threads are run on host threads 1:1. That means guest stacks use host stacks, and for virtual threads to work the +hosting JVM must support the combination of virtual threads and Truffle, which as of December 2023 HotSpot does not. +Likewise guest exceptions are wrapped in `EspressoException` and then thrown, so the JVM running Espresso provides +stack unwinding services and similar. + +Truffle provides stack frame management. A `nodes.BytecodeNode` receives a Truffle `VirtualFrame` object, which manages +a series of slots stored on the host stack, or when _materialized_, the frame is stored on the heap. In dynamic Truffle +languages these slots are strongly typed and correspond to the base Java type system with ints, booleans, longs and +object references etc. Espresso however uses Truffle's _static slots_, which are (somewhat confusingly) both typed and +untyped at the same time. The Truffle `Frame` interface has an API for reading and writing to static slots which +distinguishes betwen primitive types (`get/setObjectStatic`, `get/setLongStatic` etc), but the actual primitive type of +a static slot is tracked only when assertions are enabled i.e. in debug mode. You can see some of this code in Truffle's +`FrameWithoutBoxing` class. In normal execution the slot types are marked only as being "static". This is OK because +Java bytecode implicitly types stack slots. The types aren't recorded in the bytecode itself, but can be recovered using +an analysis algorithm. During bytecode verification the types of slots are computed to ensure that (even when they +change) they are never being used inconsistently. Behind the scenes then we only need to store object references +separately from everything else so the GC can find them, and thus other types of stack slot are just stored in +uninterpreted longs. + +## Substitutions and extension modules + +Espresso specific features may need guest-exposed APIs to control them. For example Espresso exposes a HotSwap control +API that lets apps register for callbacks that run when the program code is mutated. + +To add one of these: + +1. Add a new module in the `com.oracle.truffle.espresso` namespace by creating the directories and then adding it to + `suite.py`. Use the way `HOTSWAP` is defined as a template. +2. In `substitutions.ModuleExtension` add a new entry to the `ESPRESSO_EXTENSION_MODULES` array. +3. In `meta.Meta` and `descriptors.Symbol`, add entries for any parts of the new module that you need to access from + the VM. Watch out! In `meta.Meta` your new fields should be `@CompilationFinal public static ....` and not `final`. + You'll need to look them up in `postSystemInit` as otherwise you'll load classes into the wrong module. + +Extension modules can't directly call into Espresso code - they are effectively just normal Java libraries, and should +be able to gracefully degrade or report failure on non-Espresso JVMs. To hook the extension into Espresso requires +the substitution mechanism. + +How to register substitutions is explained clearly in the JavaDoc for `substitutions.Substitutions`. An annotation +processor generates boilerplate to help with invoking the substitution-containing classes. Generally, each method has +a Truffle node object created for it, but you can also define a node directly in a substitutions class which is helpful +if you need to optimize it with Truffle specializations. + +## Guest code metadata + +Espresso divides metadata about the guest program into three layers: parser (data), linked (structural) and runtime. + +### Parser (data) + +The parser layer is whatever comes out from the .class parser. +In the parser (data) layer, Espresso could already do some pre-processing of the (method) bytecodes: + +- Pre-quicken bytecodes. +- Pre-allocate/count how many nodes are needed. +- Answer questions like: does a method use monitors, does it call AccessController.doPrivileged, is it a getter/setter ... + +### Linked (structural) + +The linked layer (LinkedKlass, LinkedMethod, LinkedField) defines an immutable, structural representation of the class hierarchy. +At structural layer, the super class and super interfaces are also linked, the class hierarchy is known. +In the linked (structural) layer, Espresso can compute useful information: + +- vtables +- itables +- Class layout: field offsets, object size... +- Mark the class as finalizable (or not) + +### Runtime + +Finally the runtime layer associates a linked class with the runtime data: a class loader instance, static fields, +initialization and verification status, guest Class instance. The runtime layer can squeeze even more information, +via assumptions, based on classes loaded at runtime: + +- (Effectively) leaf methods +- (Effectively) leaf classes +- Single interface/abstract class implementor +- All of the above AKA class hierarchy analysis (CHA). + +These layers were designed to make metadata as shareable as possible via a strict separation between metadata and +runtime data. The idea is to share up to the linked (structural) layer between contexts e.g. a second context doesn't +need to reparse and recompute vtable, itables etc. diff --git a/espresso/src/com.oracle.truffle.espresso.launcher/src/com/oracle/truffle/espresso/launcher/EspressoLauncher.java b/espresso/src/com.oracle.truffle.espresso.launcher/src/com/oracle/truffle/espresso/launcher/EspressoLauncher.java index 7519a68b7bab..bdf2d24b49d6 100644 --- a/espresso/src/com.oracle.truffle.espresso.launcher/src/com/oracle/truffle/espresso/launcher/EspressoLauncher.java +++ b/espresso/src/com.oracle.truffle.espresso.launcher/src/com/oracle/truffle/espresso/launcher/EspressoLauncher.java @@ -40,6 +40,11 @@ import org.graalvm.polyglot.PolyglotException; import org.graalvm.polyglot.Value; +/** + * A simple emulation of the {@code java} launcher that parses the command line flags and builds and Espresso context + * based on them. This code isn't used by anyone except Espresso developers, because in a shipped Espresso the VM + * is started via {@code mokapot} instead (see {@code hacking.md} for details). + */ public final class EspressoLauncher extends AbstractLanguageLauncher { private static final String AGENT_LIB = "java.AgentLib."; private static final String AGENT_PATH = "java.AgentPath."; diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/runtime/EspressoException.java b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/runtime/EspressoException.java index edc77f67ae01..b41d198111ea 100644 --- a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/runtime/EspressoException.java +++ b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/runtime/EspressoException.java @@ -31,6 +31,10 @@ import com.oracle.truffle.espresso.vm.InterpreterToVM; import com.oracle.truffle.espresso.vm.VM; +/** + * A wrapped guest exception. Espresso uses host exceptions to unwind the stack when the guest throws, so we have to + * wrap guest with host here. + */ @ExportLibrary(value = InteropLibrary.class, delegateTo = "exception") @SuppressWarnings("serial") public final class EspressoException extends AbstractTruffleException { From fb00f14cd1f1e33649a568f9118ce019eb08f42b Mon Sep 17 00:00:00 2001 From: Christian Wimmer Date: Wed, 27 Dec 2023 15:13:15 -0800 Subject: [PATCH 379/593] Disable profiling of guard-with-test method handles --- .../src/com/oracle/svm/driver/NativeImage.java | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/substratevm/src/com.oracle.svm.driver/src/com/oracle/svm/driver/NativeImage.java b/substratevm/src/com.oracle.svm.driver/src/com/oracle/svm/driver/NativeImage.java index c230b49e1cde..772752493d6c 100644 --- a/substratevm/src/com.oracle.svm.driver/src/com/oracle/svm/driver/NativeImage.java +++ b/substratevm/src/com.oracle.svm.driver/src/com/oracle/svm/driver/NativeImage.java @@ -1115,12 +1115,21 @@ private int completeImageBuild() { imageBuilderJavaArgs.add("-Djava.lang.invoke.InnerClassLambdaMetafactory.initializeLambdas=false"); /* * DONT_INLINE_THRESHOLD is used to set a profiling threshold for certain method handles and - * only allow inlining after n invocations. This is used for example in the implementation - * of record equals methods. We disable this behavior in the image builder because it can - * prevent optimizing the method handles for AOT compilation if the threshold is not - * reached. + * only allow inlining when JIT compiling after n invocations. PROFILE_GWT is used to + * profile "guard with test" method handles and speculate on a constant guard value, making + * the other branch statically unreachable for JIT compilation. + * + * Both are used for example in the implementation of record hashCode/equals methods. We + * disable this behavior in the image builder because for AOT compilation, profiling and + * speculation are never useful. Instead, it prevents optimizing the method handles for AOT + * compilation if the threshold is not already reached at image build time. + * + * As a side effect, the profiling is also disabled when using such method handles in the + * image generator itself. If that turns out to be a performance problem, we need to + * investigate at different solution that disables the profiling only for AOT compilation. */ imageBuilderJavaArgs.add("-Djava.lang.invoke.MethodHandle.DONT_INLINE_THRESHOLD=-1"); + imageBuilderJavaArgs.add("-Djava.lang.invoke.MethodHandle.PROFILE_GWT=false"); /* After JavaArgs consolidation add the user provided JavaArgs */ boolean afterOption = false; From 2ee164de1b1670b0526f0954116337d427415118 Mon Sep 17 00:00:00 2001 From: Christian Wimmer Date: Wed, 27 Dec 2023 21:19:28 -0800 Subject: [PATCH 380/593] Eagerly initialize VarHandle objects before method handle intrinsification --- .../oracle/svm/core/jdk/VarHandleFeature.java | 64 +++++++++++++++++++ ...trinsifyMethodHandlesInvocationPlugin.java | 61 +----------------- 2 files changed, 65 insertions(+), 60 deletions(-) diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/VarHandleFeature.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/VarHandleFeature.java index 9e74855377c7..effc5aa5c858 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/VarHandleFeature.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/VarHandleFeature.java @@ -27,6 +27,7 @@ import java.lang.invoke.MethodHandle; import java.lang.invoke.VarHandle; import java.lang.reflect.Field; +import java.lang.reflect.Method; import java.lang.reflect.Modifier; import java.util.HashMap; import java.util.Map; @@ -99,6 +100,69 @@ public class VarHandleFeature implements InternalFeature { private final ConcurrentMap processedVarHandles = new ConcurrentHashMap<>(); private Consumer markAsUnsafeAccessed; + @Override + public void duringSetup(DuringSetupAccess access) { + /* + * Initialize fiels of VarHandle instances that are @Stable eagerly, so that during method + * handle intrinsification loads of those fields and array elements can be constant-folded. + * + * Note that we do this on purpose here in an object replacer, and not in an object + * reachability handler: intrinsification happens before the VarHandle object itself is + * marked as reachable, and the goal of intrinsification is to actually avoid making the + * VarHandle object itself reachable. + */ + access.registerObjectReplacer(VarHandleFeature::eagerlyInitializeVarHandle); + } + + private static Object eagerlyInitializeVarHandle(Object obj) { + if (obj instanceof VarHandle varHandle) { + eagerlyInitializeVarHandle(varHandle); + } + return obj; + } + + private static final Field varHandleVFormField = ReflectionUtil.lookupField(VarHandle.class, "vform"); + private static final Method varFormInitMethod = ReflectionUtil.lookupMethod(ReflectionUtil.lookupClass(false, "java.lang.invoke.VarForm"), "getMethodType_V", int.class); + private static final Method varHandleGetMethodHandleMethod = ReflectionUtil.lookupMethod(VarHandle.class, "getMethodHandle", int.class); + + public static void eagerlyInitializeVarHandle(VarHandle varHandle) { + try { + /* + * The field VarHandle.vform.methodType_V_table is a @Stable field but initialized + * lazily on first access. Therefore, constant folding can happen only after + * initialization has happened. We force initialization by invoking the method + * VarHandle.vform.getMethodType_V(0). + */ + Object varForm = varHandleVFormField.get(varHandle); + varFormInitMethod.invoke(varForm, 0); + + /* + * The AccessMode used for the access that we are going to intrinsify is hidden in a + * AccessDescriptor object that is also passed in as a parameter to the intrinsified + * method. Initializing all AccessMode enum values is easier than trying to extract the + * actual AccessMode. + */ + for (VarHandle.AccessMode accessMode : VarHandle.AccessMode.values()) { + /* + * Force initialization of the @Stable field VarHandle.vform.memberName_table. + */ + boolean isAccessModeSupported = varHandle.isAccessModeSupported(accessMode); + /* + * Force initialization of the @Stable field + * VarHandle.typesAndInvokers.methodType_table. + */ + varHandle.accessModeType(accessMode); + + if (isAccessModeSupported) { + /* Force initialization of the @Stable field VarHandle.methodHandleTable. */ + varHandleGetMethodHandleMethod.invoke(varHandle, accessMode.ordinal()); + } + } + } catch (ReflectiveOperationException ex) { + throw VMError.shouldNotReachHere(ex); + } + } + @Override public void afterRegistration(AfterRegistrationAccess access) { try { diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/phases/IntrinsifyMethodHandlesInvocationPlugin.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/phases/IntrinsifyMethodHandlesInvocationPlugin.java index 242acbc508eb..be055c089ecc 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/phases/IntrinsifyMethodHandlesInvocationPlugin.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/phases/IntrinsifyMethodHandlesInvocationPlugin.java @@ -30,8 +30,6 @@ import java.lang.invoke.MethodType; import java.lang.invoke.VarHandle; import java.lang.invoke.WrongMethodTypeException; -import java.lang.reflect.Field; -import java.lang.reflect.Method; import java.util.Arrays; import java.util.Collections; import java.util.List; @@ -59,7 +57,6 @@ import com.oracle.svm.hosted.meta.HostedSnippetReflectionProvider; import com.oracle.svm.hosted.meta.HostedType; import com.oracle.svm.hosted.meta.HostedUniverse; -import com.oracle.svm.util.ReflectionUtil; import jdk.graal.compiler.api.replacements.SnippetReflectionProvider; import jdk.graal.compiler.core.common.spi.MetaAccessExtensionProvider; @@ -175,21 +172,6 @@ */ public class IntrinsifyMethodHandlesInvocationPlugin implements NodePlugin { - private static final Field varHandleVFormField; - private static final Method varFormInitMethod; - private static final Method varHandleGetMethodHandleMethod; - - static { - varHandleVFormField = ReflectionUtil.lookupField(VarHandle.class, "vform"); - try { - Class varFormClass = Class.forName("java.lang.invoke.VarForm"); - varFormInitMethod = ReflectionUtil.lookupMethod(varFormClass, "getMethodType_V", int.class); - varHandleGetMethodHandleMethod = ReflectionUtil.lookupMethod(VarHandle.class, "getMethodHandle", int.class); - } catch (ClassNotFoundException ex) { - throw VMError.shouldNotReachHere(ex); - } - } - private final ParsingReason reason; private final Providers parsingProviders; private final HostedProviders universeProviders; @@ -317,48 +299,7 @@ private boolean isVarHandleMethod(ResolvedJavaMethod method, ValueNode[] args) { if (args.length < 1 || !args[0].isJavaConstant() || !isVarHandle(args[0])) { return false; } - - try { - /* - * The field VarHandle.vform.methodType_V_table is a @Stable field but initialized - * lazily on first access. Therefore, constant folding can happen only after - * initialization has happened. We force initialization by invoking the method - * VarHandle.vform.getMethodType_V(0). - */ - VarHandle varHandle = hostedSnippetReflection.asObject(VarHandle.class, args[0].asJavaConstant()); - Object varForm = varHandleVFormField.get(varHandle); - varFormInitMethod.invoke(varForm, 0); - - /* - * The AccessMode used for the access that we are going to intrinsify is hidden in a - * AccessDescriptor object that is also passed in as a parameter to the intrinsified - * method. Initializing all AccessMode enum values is easier than trying to extract - * the actual AccessMode. - */ - for (VarHandle.AccessMode accessMode : VarHandle.AccessMode.values()) { - /* - * Force initialization of the @Stable field VarHandle.vform.memberName_table. - * Starting with JDK 17, this field is lazily initialized. - */ - boolean isAccessModeSupported = varHandle.isAccessModeSupported(accessMode); - /* - * Force initialization of the @Stable field - * VarHandle.typesAndInvokers.methodType_table. - */ - varHandle.accessModeType(accessMode); - - if (isAccessModeSupported) { - /* - * Force initialization of the @Stable field VarHandle.methodHandleTable (or - * VarHandle.typesAndInvokers.methodHandle_tabel on JDK <= 17) . - */ - varHandleGetMethodHandleMethod.invoke(varHandle, accessMode.ordinal()); - } - } - } catch (ReflectiveOperationException ex) { - throw VMError.shouldNotReachHere(ex); - } - + VarHandleFeature.eagerlyInitializeVarHandle(hostedSnippetReflection.asObject(VarHandle.class, args[0].asJavaConstant())); return true; } else { return false; From 9d0d15610c0ffaab396d6b798185ed49ad43e039 Mon Sep 17 00:00:00 2001 From: Christian Wimmer Date: Mon, 8 Jan 2024 11:26:46 -0800 Subject: [PATCH 381/593] Allow recursive inlining during method handle intrinsification --- .../compiler/replacements/PEGraphDecoder.java | 2 +- .../InlineBeforeAnalysisGraphDecoder.java | 42 ++- ...nlineBeforeAnalysisInlineInvokePlugin.java | 51 ---- .../phases/InlineBeforeAnalysisPolicy.java | 14 +- .../oracle/svm/core/jdk/VarHandleFeature.java | 7 +- .../RuntimeCompilationFeature.java | 50 ++-- .../SimulateClassInitializerPolicy.java | 12 +- .../InlineBeforeAnalysisPolicyImpl.java | 38 +-- .../InlineBeforeAnalysisPolicyUtils.java | 282 +++++++++++------- 9 files changed, 258 insertions(+), 240 deletions(-) delete mode 100644 substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/phases/InlineBeforeAnalysisInlineInvokePlugin.java diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/replacements/PEGraphDecoder.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/replacements/PEGraphDecoder.java index d61d3d0690e1..78115d9eb3f3 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/replacements/PEGraphDecoder.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/replacements/PEGraphDecoder.java @@ -344,7 +344,7 @@ public String getNodeClassName() { } protected class PENonAppendGraphBuilderContext extends CoreProvidersDelegate implements GraphBuilderContext { - protected final PEMethodScope methodScope; + public final PEMethodScope methodScope; protected final Invoke invoke; @Override diff --git a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/phases/InlineBeforeAnalysisGraphDecoder.java b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/phases/InlineBeforeAnalysisGraphDecoder.java index 308b33edc49c..9857f6fbcf44 100644 --- a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/phases/InlineBeforeAnalysisGraphDecoder.java +++ b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/phases/InlineBeforeAnalysisGraphDecoder.java @@ -38,6 +38,7 @@ import com.oracle.graal.pointsto.meta.AnalysisField; import com.oracle.graal.pointsto.meta.AnalysisMethod; import com.oracle.graal.pointsto.meta.HostedProviders; +import com.oracle.graal.pointsto.phases.InlineBeforeAnalysisPolicy.AbstractPolicyScope; import com.oracle.graal.pointsto.util.AnalysisError; import com.oracle.graal.pointsto.util.GraalAccess; import com.oracle.svm.util.ReflectionUtil; @@ -60,6 +61,7 @@ import jdk.graal.compiler.nodes.ValueNode; import jdk.graal.compiler.nodes.calc.IsNullNode; import jdk.graal.compiler.nodes.extended.UnsafeAccessNode; +import jdk.graal.compiler.nodes.graphbuilderconf.GraphBuilderContext; import jdk.graal.compiler.nodes.graphbuilderconf.InlineInvokePlugin; import jdk.graal.compiler.nodes.graphbuilderconf.InvocationPlugin; import jdk.graal.compiler.nodes.graphbuilderconf.LoopExplosionPlugin; @@ -78,7 +80,7 @@ public class InlineBeforeAnalysisGraphDecoder extends PEGraphDecoder { public class InlineBeforeAnalysisMethodScope extends PEMethodScope { - public final InlineBeforeAnalysisPolicy.AbstractPolicyScope policyScope; + public final AbstractPolicyScope policyScope; private boolean inliningAborted; @@ -103,7 +105,7 @@ public class InlineBeforeAnalysisMethodScope extends PEMethodScope { for (int i = 0; i < arguments.length; i++) { constArgsWithReceiver[i] = arguments[i].isConstant(); } - policyScope = policy.openCalleeScope(cast(caller).policyScope, bb.getMetaAccess(), method, constArgsWithReceiver, invokeData.intrinsifiedMethodHandle); + policyScope = policy.openCalleeScope(cast(caller).policyScope, method); if (graph.getDebug().isLogEnabled()) { graph.getDebug().logv(" ".repeat(inliningDepth) + "openCalleeScope for " + method.format("%H.%n(%p)") + ": " + policyScope); } @@ -121,6 +123,27 @@ static void recordInlined(InlineBeforeAnalysisMethodScope callerScope, InlineBef } } + static final class InlineBeforeAnalysisInlineInvokePlugin implements InlineInvokePlugin { + + private final InlineBeforeAnalysisPolicy policy; + + InlineBeforeAnalysisInlineInvokePlugin(InlineBeforeAnalysisPolicy policy) { + this.policy = policy; + } + + @Override + public InlineInfo shouldInlineInvoke(GraphBuilderContext b, ResolvedJavaMethod m, ValueNode[] args) { + AnalysisMethod method = (AnalysisMethod) m; + + AbstractPolicyScope policyScope = cast(((PENonAppendGraphBuilderContext) b).methodScope).policyScope; + if (policy.shouldInlineInvoke(b, policyScope, method, args)) { + return policy.createInvokeInfo(method); + } else { + return InlineInfo.DO_NOT_INLINE_WITH_EXCEPTION; + } + } + } + private Field dmhStaticAccessorOffsetField; private Field dmhStaticAccessorBaseField; private AnalysisField dmhStaticAccessorOffsetAnalysisField; @@ -301,8 +324,19 @@ private void ensureDMHStaticAccessorFieldsInitialized() { } @Override - protected void handleNonInlinedInvoke(MethodScope methodScope, LoopScope loopScope, InvokeData invokeData) { + protected void handleNonInlinedInvoke(MethodScope ms, LoopScope loopScope, InvokeData invokeData) { + InlineBeforeAnalysisMethodScope methodScope = cast(ms); maybeAbortInlining(methodScope, loopScope, invokeData.invoke.asNode()); + + if (!methodScope.inliningAborted && methodScope.isInlinedMethod()) { + if (graph.getDebug().isLogEnabled()) { + graph.getDebug().logv(" ".repeat(methodScope.inliningDepth) + " nonInlinedInvoke " + invokeData.callTarget.targetMethod() + ": " + methodScope.policyScope); + } + if (!methodScope.policyScope.processNonInlinedInvoke(providers, invokeData.callTarget)) { + abortInlining(methodScope); + } + } + super.handleNonInlinedInvoke(methodScope, loopScope, invokeData); } @@ -494,7 +528,7 @@ private void killControlFlowNodes(PEMethodScope inlineScope, FixedNode start) { * at the cost of this ugly cast. */ @SuppressWarnings("unchecked") - protected InlineBeforeAnalysisMethodScope cast(MethodScope methodScope) { + protected static InlineBeforeAnalysisMethodScope cast(MethodScope methodScope) { return (InlineBeforeAnalysisMethodScope) methodScope; } diff --git a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/phases/InlineBeforeAnalysisInlineInvokePlugin.java b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/phases/InlineBeforeAnalysisInlineInvokePlugin.java deleted file mode 100644 index d24fe0429d9e..000000000000 --- a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/phases/InlineBeforeAnalysisInlineInvokePlugin.java +++ /dev/null @@ -1,51 +0,0 @@ -/* - * Copyright (c) 2021, 2022, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.oracle.graal.pointsto.phases; - -import com.oracle.graal.pointsto.meta.AnalysisMethod; - -import jdk.graal.compiler.nodes.ValueNode; -import jdk.graal.compiler.nodes.graphbuilderconf.GraphBuilderContext; -import jdk.graal.compiler.nodes.graphbuilderconf.InlineInvokePlugin; -import jdk.vm.ci.meta.ResolvedJavaMethod; - -final class InlineBeforeAnalysisInlineInvokePlugin implements InlineInvokePlugin { - - private final InlineBeforeAnalysisPolicy policy; - - InlineBeforeAnalysisInlineInvokePlugin(InlineBeforeAnalysisPolicy policy) { - this.policy = policy; - } - - @Override - public InlineInfo shouldInlineInvoke(GraphBuilderContext b, ResolvedJavaMethod m, ValueNode[] args) { - AnalysisMethod method = (AnalysisMethod) m; - if (policy.shouldInlineInvoke(b, method, args)) { - return policy.createInvokeInfo(method); - } else { - return InlineInfo.DO_NOT_INLINE_WITH_EXCEPTION; - } - } -} diff --git a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/phases/InlineBeforeAnalysisPolicy.java b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/phases/InlineBeforeAnalysisPolicy.java index c13fad407ee2..4d17a00af129 100644 --- a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/phases/InlineBeforeAnalysisPolicy.java +++ b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/phases/InlineBeforeAnalysisPolicy.java @@ -30,11 +30,13 @@ import jdk.graal.compiler.graph.Node; import jdk.graal.compiler.graph.NodeSourcePosition; +import jdk.graal.compiler.nodes.CallTargetNode; import jdk.graal.compiler.nodes.FixedWithNextNode; import jdk.graal.compiler.nodes.ValueNode; import jdk.graal.compiler.nodes.graphbuilderconf.GraphBuilderContext; import jdk.graal.compiler.nodes.graphbuilderconf.InlineInvokePlugin.InlineInfo; import jdk.graal.compiler.nodes.graphbuilderconf.NodePlugin; +import jdk.graal.compiler.nodes.spi.CoreProviders; /** * Provides the policy which methods are inlined by {@link InlineBeforeAnalysis}. If @@ -77,6 +79,8 @@ protected AbstractPolicyScope(int inliningDepth) { * decision on the current list of usages. The list of usages is often but not always empty. */ public abstract boolean processNode(AnalysisMetaAccess metaAccess, AnalysisMethod method, Node node); + + public abstract boolean processNonInlinedInvoke(CoreProviders providers, CallTargetNode node); } protected final NodePlugin[] nodePlugins; @@ -85,7 +89,7 @@ protected InlineBeforeAnalysisPolicy(NodePlugin[] nodePlugins) { this.nodePlugins = nodePlugins; } - protected abstract boolean shouldInlineInvoke(GraphBuilderContext b, AnalysisMethod method, ValueNode[] args); + protected abstract boolean shouldInlineInvoke(GraphBuilderContext b, AbstractPolicyScope policyScope, AnalysisMethod method, ValueNode[] args); protected abstract InlineInfo createInvokeInfo(AnalysisMethod method); @@ -97,8 +101,7 @@ protected InlineBeforeAnalysisPolicy(NodePlugin[] nodePlugins) { protected abstract AbstractPolicyScope createRootScope(); - protected abstract AbstractPolicyScope openCalleeScope(AbstractPolicyScope outer, AnalysisMetaAccess metaAccess, - AnalysisMethod method, boolean[] constArgsWithReceiver, boolean intrinsifiedMethodHandle); + protected abstract AbstractPolicyScope openCalleeScope(AbstractPolicyScope outer, AnalysisMethod method); /** @see InlineBeforeAnalysisGraphDecoder#shouldOmitIntermediateMethodInStates */ protected boolean shouldOmitIntermediateMethodInState(AnalysisMethod method) { @@ -108,7 +111,7 @@ protected boolean shouldOmitIntermediateMethodInState(AnalysisMethod method) { public static final InlineBeforeAnalysisPolicy NO_INLINING = new InlineBeforeAnalysisPolicy(new NodePlugin[0]) { @Override - protected boolean shouldInlineInvoke(GraphBuilderContext b, AnalysisMethod method, ValueNode[] args) { + protected boolean shouldInlineInvoke(GraphBuilderContext b, AbstractPolicyScope policyScope, AnalysisMethod method, ValueNode[] args) { return false; } @@ -143,8 +146,7 @@ protected AbstractPolicyScope createRootScope() { } @Override - protected AbstractPolicyScope openCalleeScope(AbstractPolicyScope outer, AnalysisMetaAccess metaAccess, - AnalysisMethod method, boolean[] constArgsWithReceiver, boolean intrinsifiedMethodHandle) { + protected AbstractPolicyScope openCalleeScope(AbstractPolicyScope outer, AnalysisMethod method) { throw AnalysisError.shouldNotReachHere("NO_INLINING policy should not try to inline"); } }; diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/VarHandleFeature.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/VarHandleFeature.java index effc5aa5c858..c79167ebf497 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/VarHandleFeature.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/VarHandleFeature.java @@ -103,12 +103,13 @@ public class VarHandleFeature implements InternalFeature { @Override public void duringSetup(DuringSetupAccess access) { /* - * Initialize fiels of VarHandle instances that are @Stable eagerly, so that during method + * Initialize fields of VarHandle instances that are @Stable eagerly, so that during method * handle intrinsification loads of those fields and array elements can be constant-folded. * * Note that we do this on purpose here in an object replacer, and not in an object - * reachability handler: intrinsification happens before the VarHandle object itself is - * marked as reachable, and the goal of intrinsification is to actually avoid making the + * reachability handler: Intrinsification happens as part of method inlining before + * analysis, i.e., before the static analysis, i.e., before the VarHandle object itself is + * marked as reachable. The goal of intrinsification is to actually avoid making the * VarHandle object itself reachable. */ access.registerObjectReplacer(VarHandleFeature::eagerlyInitializeVarHandle); diff --git a/substratevm/src/com.oracle.svm.graal/src/com/oracle/svm/graal/hosted/runtimecompilation/RuntimeCompilationFeature.java b/substratevm/src/com.oracle.svm.graal/src/com/oracle/svm/graal/hosted/runtimecompilation/RuntimeCompilationFeature.java index 2ed14e40d39d..993f34f62eb1 100644 --- a/substratevm/src/com.oracle.svm.graal/src/com/oracle/svm/graal/hosted/runtimecompilation/RuntimeCompilationFeature.java +++ b/substratevm/src/com.oracle.svm.graal/src/com/oracle/svm/graal/hosted/runtimecompilation/RuntimeCompilationFeature.java @@ -28,7 +28,6 @@ import static com.oracle.svm.common.meta.MultiMethod.ORIGINAL_METHOD; import static com.oracle.svm.core.util.VMError.guarantee; import static com.oracle.svm.hosted.code.SubstrateCompilationDirectives.RUNTIME_COMPILED_METHOD; -import static com.oracle.svm.hosted.phases.InlineBeforeAnalysisPolicyUtils.Options.InlineBeforeAnalysisAllowedDepth; import static jdk.graal.compiler.java.BytecodeParserOptions.InlineDuringParsingMaxDepth; import java.lang.reflect.Executable; @@ -45,6 +44,7 @@ import java.util.function.Supplier; import java.util.stream.Stream; +import org.graalvm.nativeimage.AnnotationAccess; import org.graalvm.nativeimage.ImageSingletons; import org.graalvm.nativeimage.hosted.Feature; @@ -799,7 +799,6 @@ public Function getStrengthenGraphsToTargetFunct * {@code RUNTIME_COMPILED_METHOD}s. */ private class RuntimeCompilationInlineBeforeAnalysisPolicy extends InlineBeforeAnalysisPolicy { - private final int accumulativeAllowedInliningDepth = InlineBeforeAnalysisAllowedDepth.getValue(); private final int trivialAllowingInliningDepth = InlineDuringParsingMaxDepth.getValue(HostedOptionValues.singleton()); final SVMHost hostVM; @@ -831,26 +830,22 @@ protected FixedWithNextNode processInvokeArgs(AnalysisMethod targetMethod, Fixed } @Override - protected boolean shouldInlineInvoke(GraphBuilderContext b, AnalysisMethod method, ValueNode[] args) { - if (inliningUtils.alwaysInlineInvoke((AnalysisMetaAccess) b.getMetaAccess(), method)) { - return true; - } - // worse case depth is max trivial, and then max accumulative - if (b.getDepth() > trivialAllowingInliningDepth + accumulativeAllowedInliningDepth) { - return false; - } - if (b.recursiveInliningDepth(method) > 0) { - /* Prevent recursive inlining. */ + protected boolean shouldInlineInvoke(GraphBuilderContext b, AbstractPolicyScope policyScope, AnalysisMethod method, ValueNode[] args) { + if (allowInliningPredicate.allowInlining(b, method) != AllowInliningPredicate.InlineDecision.INLINE) { return false; } - if (!InlineBeforeAnalysisPolicyUtils.inliningAllowed(hostVM, b, method)) { - return false; + InlineBeforeAnalysisPolicyUtils.AccumulativeInlineScope accScope; + if (policyScope instanceof InlineBeforeAnalysisPolicyUtils.AlwaysInlineScope) { + /* + * If we are in "trivial inlining" mode, we make inlining decisions as if we are + * still the root (= null) accumulative inlining scope. + */ + accScope = null; + } else { + accScope = (InlineBeforeAnalysisPolicyUtils.AccumulativeInlineScope) policyScope; } - - AllowInliningPredicate.InlineDecision result = allowInliningPredicate.allowInlining(b, method); - - return result == AllowInliningPredicate.InlineDecision.INLINE; + return inliningUtils.shouldInlineInvoke(b, hostVM, accScope, method); } @Override @@ -871,26 +866,33 @@ protected AbstractPolicyScope createRootScope() { } @Override - protected AbstractPolicyScope openCalleeScope(AbstractPolicyScope outer, AnalysisMetaAccess metaAccess, - AnalysisMethod method, boolean[] constArgsWithReceiver, boolean intrinsifiedMethodHandle) { + protected AbstractPolicyScope openCalleeScope(AbstractPolicyScope outer, AnalysisMethod method) { if (outer instanceof InlineBeforeAnalysisPolicyUtils.AccumulativeInlineScope accOuter) { /* * once the accumulative policy is activated, then we cannot return to the trivial * policy */ - return inliningUtils.createAccumulativeInlineScope(accOuter, metaAccess, method, constArgsWithReceiver, intrinsifiedMethodHandle); + return inliningUtils.createAccumulativeInlineScope(accOuter, method); } assert outer == null || outer instanceof InlineBeforeAnalysisPolicyUtils.AlwaysInlineScope : "unexpected outer scope: " + outer; - // check if trivial is possible - boolean trivialInlineAllowed = hostVM.isAnalysisTrivialMethod(method); + /* + * Check if trivial is possible. We use the graph size as the main criteria, similar to + * the trivial inlining for AOT compilation. + * + * In addition, we do not allow method handle internals to be processed by the trivial + * inlining. The regular accumulative inlining scope has a special mode for method + * handle intrinsification with larger thresholds in order to fully inline the method + * handle. + */ + boolean trivialInlineAllowed = hostVM.isAnalysisTrivialMethod(method) && !AnnotationAccess.isAnnotationPresent(method, InlineBeforeAnalysisPolicyUtils.COMPILED_LAMBDA_FORM_ANNOTATION); int inliningDepth = outer == null ? 1 : outer.inliningDepth + 1; if (trivialInlineAllowed && inliningDepth <= trivialAllowingInliningDepth) { return new InlineBeforeAnalysisPolicyUtils.AlwaysInlineScope(inliningDepth); } else { // start with a new accumulative inline scope - return inliningUtils.createAccumulativeInlineScope(null, metaAccess, method, constArgsWithReceiver, intrinsifiedMethodHandle); + return inliningUtils.createAccumulativeInlineScope(null, method); } } } diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/classinitialization/SimulateClassInitializerPolicy.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/classinitialization/SimulateClassInitializerPolicy.java index e697a824b451..69d32dc917e5 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/classinitialization/SimulateClassInitializerPolicy.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/classinitialization/SimulateClassInitializerPolicy.java @@ -38,11 +38,13 @@ import jdk.graal.compiler.graph.Node; import jdk.graal.compiler.graph.NodeSourcePosition; +import jdk.graal.compiler.nodes.CallTargetNode; import jdk.graal.compiler.nodes.FixedWithNextNode; import jdk.graal.compiler.nodes.ValueNode; import jdk.graal.compiler.nodes.graphbuilderconf.GraphBuilderContext; import jdk.graal.compiler.nodes.graphbuilderconf.InlineInvokePlugin; import jdk.graal.compiler.nodes.graphbuilderconf.NodePlugin; +import jdk.graal.compiler.nodes.spi.CoreProviders; /** * This class is necessary because simulation of class initializer is based on @@ -91,6 +93,11 @@ public boolean processNode(AnalysisMetaAccess metaAccess, AnalysisMethod method, return true; } + @Override + public boolean processNonInlinedInvoke(CoreProviders providers, CallTargetNode node) { + return true; + } + @Override public String toString() { return "allocatedBytes: " + allocatedBytes + " (" + accumulativeCounters.allocatedBytes + ")"; @@ -108,7 +115,7 @@ public String toString() { } @Override - protected boolean shouldInlineInvoke(GraphBuilderContext b, AnalysisMethod method, ValueNode[] args) { + protected boolean shouldInlineInvoke(GraphBuilderContext b, AbstractPolicyScope policyScope, AnalysisMethod method, ValueNode[] args) { if (b.getDepth() > support.maxInlineDepth) { /* Safeguard against excessive inlining, for example endless recursion. */ return false; @@ -154,8 +161,7 @@ protected AbstractPolicyScope createRootScope() { } @Override - protected AbstractPolicyScope openCalleeScope(AbstractPolicyScope o, AnalysisMetaAccess metaAccess, - AnalysisMethod method, boolean[] constArgsWithReceiver, boolean intrinsifiedMethodHandle) { + protected AbstractPolicyScope openCalleeScope(AbstractPolicyScope o, AnalysisMethod method) { var outer = (SimulateClassInitializerInlineScope) o; return new SimulateClassInitializerInlineScope(outer.accumulativeCounters, outer.inliningDepth + 1); } diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/phases/InlineBeforeAnalysisPolicyImpl.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/phases/InlineBeforeAnalysisPolicyImpl.java index 85f5563d6b47..a85ac193cfef 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/phases/InlineBeforeAnalysisPolicyImpl.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/phases/InlineBeforeAnalysisPolicyImpl.java @@ -24,11 +24,11 @@ */ package com.oracle.svm.hosted.phases; -import com.oracle.graal.pointsto.meta.AnalysisMetaAccess; import com.oracle.graal.pointsto.meta.AnalysisMethod; import com.oracle.graal.pointsto.phases.InlineBeforeAnalysisPolicy; import com.oracle.svm.core.ParsingReason; import com.oracle.svm.hosted.SVMHost; +import com.oracle.svm.hosted.phases.InlineBeforeAnalysisPolicyUtils.AccumulativeInlineScope; import jdk.graal.compiler.graph.NodeSourcePosition; import jdk.graal.compiler.nodes.FixedWithNextNode; @@ -37,23 +37,7 @@ import jdk.graal.compiler.nodes.graphbuilderconf.InlineInvokePlugin.InlineInfo; import jdk.graal.compiler.nodes.graphbuilderconf.NodePlugin; -/** - * The defaults for node limits are very conservative. Only small methods should be inlined. The - * only exception are constants - an arbitrary number of constants is always allowed. Limiting to 1 - * node (which can be also 1 invoke) means that field accessors can be inlined and forwarding - * methods can be inlined. But null checks and class initialization checks are already putting a - * method above the limit. On the other hand, the inlining depth is generous because we do do not - * need to limit it. Note that more experimentation is necessary to come up with the optimal - * configuration. - * - * Important: the implementation details of this class are publicly observable API. Since - * {@link java.lang.reflect.Method} constants can be produced by inlining lookup methods with - * constant arguments, reducing inlining can break customer code. This means we can never reduce the - * amount of inlining in a future version without breaking compatibility. This also means that we - * must be conservative and only inline what is necessary for known use cases. - */ public class InlineBeforeAnalysisPolicyImpl extends InlineBeforeAnalysisPolicy { - private final int maxInliningDepth = InlineBeforeAnalysisPolicyUtils.Options.InlineBeforeAnalysisAllowedDepth.getValue(); private final SVMHost hostVM; private final InlineBeforeAnalysisPolicyUtils inliningUtils; @@ -65,19 +49,8 @@ public InlineBeforeAnalysisPolicyImpl(SVMHost hostVM, InlineBeforeAnalysisPolicy } @Override - protected boolean shouldInlineInvoke(GraphBuilderContext b, AnalysisMethod method, ValueNode[] args) { - if (inliningUtils.alwaysInlineInvoke((AnalysisMetaAccess) b.getMetaAccess(), method)) { - return true; - } - if (b.getDepth() >= maxInliningDepth) { - return false; - } - if (b.recursiveInliningDepth(method) > 0) { - /* Prevent recursive inlining. */ - return false; - } - - return InlineBeforeAnalysisPolicyUtils.inliningAllowed(hostVM, b, method); + protected boolean shouldInlineInvoke(GraphBuilderContext b, AbstractPolicyScope policyScope, AnalysisMethod method, ValueNode[] args) { + return inliningUtils.shouldInlineInvoke(b, hostVM, (AccumulativeInlineScope) policyScope, method); } @Override @@ -106,9 +79,8 @@ protected AbstractPolicyScope createRootScope() { } @Override - protected AbstractPolicyScope openCalleeScope(AbstractPolicyScope outer, AnalysisMetaAccess metaAccess, - AnalysisMethod method, boolean[] constArgsWithReceiver, boolean intrinsifiedMethodHandle) { - return inliningUtils.createAccumulativeInlineScope((InlineBeforeAnalysisPolicyUtils.AccumulativeInlineScope) outer, metaAccess, method, constArgsWithReceiver, intrinsifiedMethodHandle); + protected AbstractPolicyScope openCalleeScope(AbstractPolicyScope outer, AnalysisMethod method) { + return inliningUtils.createAccumulativeInlineScope((InlineBeforeAnalysisPolicyUtils.AccumulativeInlineScope) outer, method); } @Override diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/phases/InlineBeforeAnalysisPolicyUtils.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/phases/InlineBeforeAnalysisPolicyUtils.java index 3fe948fee521..9a8df7d0428d 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/phases/InlineBeforeAnalysisPolicyUtils.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/phases/InlineBeforeAnalysisPolicyUtils.java @@ -25,21 +25,16 @@ package com.oracle.svm.hosted.phases; import java.lang.annotation.Annotation; -import java.lang.invoke.MethodHandle; -import java.lang.invoke.MethodHandles; -import java.util.Map; +import java.lang.reflect.Executable; import java.util.Set; import org.graalvm.nativeimage.AnnotationAccess; -import com.oracle.graal.pointsto.infrastructure.OriginalClassProvider; import com.oracle.graal.pointsto.meta.AnalysisMetaAccess; import com.oracle.graal.pointsto.meta.AnalysisMethod; -import com.oracle.graal.pointsto.meta.AnalysisType; import com.oracle.graal.pointsto.phases.InlineBeforeAnalysisPolicy; import com.oracle.svm.core.Uninterruptible; import com.oracle.svm.core.heap.RestrictHeapAccess; -import com.oracle.svm.core.jdk.VarHandleFeature; import com.oracle.svm.core.option.HostedOptionKey; import com.oracle.svm.core.util.VMError; import com.oracle.svm.hosted.ReachabilityRegistrationNode; @@ -62,10 +57,12 @@ import jdk.graal.compiler.nodes.StartNode; import jdk.graal.compiler.nodes.UnwindNode; import jdk.graal.compiler.nodes.ValueNode; +import jdk.graal.compiler.nodes.calc.ConditionalNode; import jdk.graal.compiler.nodes.extended.ValueAnchorNode; import jdk.graal.compiler.nodes.graphbuilderconf.GraphBuilderContext; import jdk.graal.compiler.nodes.java.AbstractNewObjectNode; import jdk.graal.compiler.nodes.java.NewArrayNode; +import jdk.graal.compiler.nodes.spi.CoreProviders; import jdk.graal.compiler.nodes.spi.ValueProxy; import jdk.graal.compiler.nodes.virtual.AllocatedObjectNode; import jdk.graal.compiler.nodes.virtual.CommitAllocationNode; @@ -73,7 +70,23 @@ import jdk.graal.compiler.nodes.virtual.VirtualObjectNode; import jdk.graal.compiler.options.Option; import jdk.graal.compiler.replacements.nodes.MethodHandleWithExceptionNode; - +import jdk.internal.vm.annotation.ForceInline; + +/** + * The defaults for node limits are very conservative. Only small methods should be inlined. The + * only exception are constants - an arbitrary number of constants is always allowed. Limiting to 1 + * node (which can be also 1 invoke) means that field accessors can be inlined and forwarding + * methods can be inlined. But null checks and class initialization checks are already putting a + * method above the limit. On the other hand, the inlining depth is generous because we do do not + * need to limit it. Note that more experimentation is necessary to come up with the optimal + * configuration. + * + * Important: the implementation details of this class are publicly observable API. Since + * {@link java.lang.reflect.Method} constants can be produced by inlining lookup methods with + * constant arguments, reducing inlining can break customer code. This means we can never reduce the + * amount of inlining in a future version without breaking compatibility. This also means that we + * must be conservative and only inline what is necessary for known use cases. + */ public class InlineBeforeAnalysisPolicyUtils { public static class Options { @Option(help = "Maximum number of computation nodes for method inlined before static analysis")// @@ -85,26 +98,100 @@ public static class Options { @Option(help = "Maximum call depth for method inlined before static analysis")// public static final HostedOptionKey InlineBeforeAnalysisAllowedDepth = new HostedOptionKey<>(20); + @Option(help = "Maximum number of methods inlined for method inlined before static analysis")// + public static final HostedOptionKey InlineBeforeAnalysisAllowedInlinings = new HostedOptionKey<>(10_000); + @Option(help = "Maximum number of computation nodes for method handle internals inlined before static analysis")// - public static final HostedOptionKey InlineBeforeAnalysisMethodHandleAllowedNodes = new HostedOptionKey<>(100); + public static final HostedOptionKey InlineBeforeAnalysisMethodHandleAllowedNodes = new HostedOptionKey<>(10_000); @Option(help = "Maximum number of invokes for method handle internals inlined before static analysis")// - public static final HostedOptionKey InlineBeforeAnalysisMethodHandleAllowedInvokes = new HostedOptionKey<>(20); + public static final HostedOptionKey InlineBeforeAnalysisMethodHandleAllowedInvokes = new HostedOptionKey<>(1_000); + + @Option(help = "Maximum call depth for method handle internals inlined before static analysis")// + public static final HostedOptionKey InlineBeforeAnalysisMethodHandleAllowedDepth = new HostedOptionKey<>(1_000); + + @Option(help = "Maximum number of methods inlined for method handle internals before static analysis")// + public static final HostedOptionKey InlineBeforeAnalysisMethodHandleAllowedInlinings = new HostedOptionKey<>(10_000); } + /* Cached values of options, to avoid repeated option lookup. */ + public final int optionAllowedNodes = Options.InlineBeforeAnalysisAllowedNodes.getValue(); + public final int optionAllowedInvokes = Options.InlineBeforeAnalysisAllowedInvokes.getValue(); + public final int optionAllowedDepth = Options.InlineBeforeAnalysisAllowedDepth.getValue(); + public final int optionAllowedInlinings = Options.InlineBeforeAnalysisAllowedInlinings.getValue(); + public final int optionMethodHandleAllowedNodes = Options.InlineBeforeAnalysisMethodHandleAllowedNodes.getValue(); + public final int optionMethodHandleAllowedInvokes = Options.InlineBeforeAnalysisMethodHandleAllowedInvokes.getValue(); + public final int optionMethodHandleAllowedDepth = Options.InlineBeforeAnalysisMethodHandleAllowedDepth.getValue(); + public final int optionMethodHandleAllowedInlinings = Options.InlineBeforeAnalysisMethodHandleAllowedInlinings.getValue(); + @SuppressWarnings("unchecked") // - private static final Class COMPILED_LAMBDA_FORM_ANNOTATION = // + public static final Class COMPILED_LAMBDA_FORM_ANNOTATION = // (Class) ReflectionUtil.lookupClass(false, "java.lang.invoke.LambdaForm$Compiled"); - private static final Class INVOKERS_CLASS = ReflectionUtil.lookupClass(false, "java.lang.invoke.Invokers"); + public boolean shouldInlineInvoke(GraphBuilderContext b, SVMHost hostVM, AccumulativeInlineScope policyScope, AnalysisMethod method) { + boolean result = shouldInlineInvoke0(b, hostVM, policyScope, method); + if (result && policyScope != null) { + policyScope.accumulativeCounters.totalInlinedMethods++; + } + return result; + } + + private boolean shouldInlineInvoke0(GraphBuilderContext b, SVMHost hostVM, AccumulativeInlineScope policyScope, AnalysisMethod method) { + if (!inliningAllowed(hostVM, b, method)) { + /* + * Inlining this method can lead to incorrect code, so this condition must always be + * checked first. + */ + return false; + } else if (alwaysInlineInvoke((AnalysisMetaAccess) b.getMetaAccess(), method)) { + /* Manual override of the regular inlining depth checks. */ + return true; + } + + boolean inMethodHandleIntrinsification = policyScope != null && policyScope.accumulativeCounters.inMethodHandleIntrinsification; + int allowedInlinings = inMethodHandleIntrinsification ? optionMethodHandleAllowedInlinings : optionAllowedInlinings; + if (policyScope != null && policyScope.accumulativeCounters.totalInlinedMethods >= allowedInlinings) { + return false; + } - private static final Map, Set> IGNORED_METHOD_HANDLE_METHODS = Map.of( - MethodHandle.class, Set.of("bindTo"), - MethodHandles.class, Set.of("dropArguments", "filterReturnValue", "foldArguments", "insertArguments"), - INVOKERS_CLASS, Set.of("spreadInvoker")); + int allowedDepth = inMethodHandleIntrinsification ? optionMethodHandleAllowedDepth : optionAllowedDepth; + /* + * Note that we do not use the inlining depth from the GraphBuilderContext: If we are in a + * regular inlining scope, but nested into a deep method handle intrinsification, then the + * total inlining depth is high but our local depth for the scope can still be low enough to + * do inlining. + */ + int actualDepth = policyScope == null ? 0 : policyScope.inliningDepth; + if (actualDepth >= allowedDepth) { + return false; + } - private AnalysisType methodHandleType; - private AnalysisType varHandleGuardsType; + if (!inMethodHandleIntrinsification) { + if (b.recursiveInliningDepth(method) > 0) { + /* + * There is no need to make recursive inlining configurable via an option for now, + * it is always just disallowed. Except when we are in a method handle + * intrinsification, because method handles are often deeply recursive. The + * "total inlined methods" check above prevents excessive recursive inlining during + * method handle intrinsification. + */ + return false; + } + if (policyScope != null && AnnotationAccess.isAnnotationPresent(method, COMPILED_LAMBDA_FORM_ANNOTATION)) { + /* + * We are not in a method handle intrinsification i.e., the method handle was not + * the root inlining context. Do not inline compiled lambda forms at all. Since the + * inlining limits are low, this could lead to partially inlined method handle + * chains, which leads to slow code because the non-inlined part is executed in the + * method handle interpreter. It is likely that the method handle is fully inlined + * when processing the callee, where the method handle is then the root inlining + * context. + */ + return false; + } + } + return true; + } public static boolean inliningAllowed(SVMHost hostVM, GraphBuilderContext b, AnalysisMethod callee) { AnalysisMethod caller = (AnalysisMethod) b.getMethod(); @@ -175,6 +262,11 @@ public boolean processNode(AnalysisMetaAccess metaAccess, AnalysisMethod method, return true; } + @Override + public boolean processNonInlinedInvoke(CoreProviders providers, CallTargetNode node) { + return true; + } + @Override public String toString() { return "AlwaysInlineScope"; @@ -182,33 +274,17 @@ public String toString() { } static final class AccumulativeCounters { - static AccumulativeCounters create(AccumulativeCounters outer) { - int maxDepth = (outer != null) ? outer.maxInliningDepth : Options.InlineBeforeAnalysisAllowedDepth.getValue(); - return new AccumulativeCounters(Options.InlineBeforeAnalysisAllowedNodes.getValue(), - Options.InlineBeforeAnalysisAllowedInvokes.getValue(), - maxDepth, - false); - } - - static AccumulativeCounters createForMethodHandleIntrinsification(AccumulativeCounters outer) { - return new AccumulativeCounters(Options.InlineBeforeAnalysisMethodHandleAllowedNodes.getValue(), - Options.InlineBeforeAnalysisMethodHandleAllowedInvokes.getValue(), - outer.maxInliningDepth, - true); - } - int maxNodes; int maxInvokes; - final int maxInliningDepth; final boolean inMethodHandleIntrinsification; - int numNodes = 0; - int numInvokes = 0; + int numNodes; + int numInvokes; + int totalInlinedMethods; - private AccumulativeCounters(int maxNodes, int maxInvokes, int maxInliningDepth, boolean inMethodHandleIntrinsification) { + private AccumulativeCounters(int maxNodes, int maxInvokes, boolean inMethodHandleIntrinsification) { this.maxNodes = maxNodes; this.maxInvokes = maxInvokes; - this.maxInliningDepth = maxInliningDepth; this.inMethodHandleIntrinsification = inMethodHandleIntrinsification; } } @@ -218,8 +294,7 @@ private AccumulativeCounters(int maxNodes, int maxInvokes, int maxInliningDepth, * has exceeded a specified count, or an illegal node is inlined, then the process will be * aborted. */ - public AccumulativeInlineScope createAccumulativeInlineScope(AccumulativeInlineScope outer, AnalysisMetaAccess metaAccess, - AnalysisMethod method, boolean[] constArgsWithReceiver, boolean intrinsifiedMethodHandle) { + public AccumulativeInlineScope createAccumulativeInlineScope(AccumulativeInlineScope outer, AnalysisMethod method) { AccumulativeCounters accumulativeCounters; int depth; if (outer == null) { @@ -228,16 +303,17 @@ public AccumulativeInlineScope createAccumulativeInlineScope(AccumulativeInlineS * point of view. */ depth = 1; - accumulativeCounters = AccumulativeCounters.create(null); - } else if (!outer.accumulativeCounters.inMethodHandleIntrinsification && (intrinsifiedMethodHandle || isMethodHandleIntrinsificationRoot(metaAccess, method, constArgsWithReceiver))) { - /* - * Method handle intrinsification root: create counters with relaxed limits and permit - * more types of nodes, but not recursively, i.e., not if we are already in a method - * handle intrinsification context. - */ - depth = outer.inliningDepth + 1; - accumulativeCounters = AccumulativeCounters.createForMethodHandleIntrinsification(outer.accumulativeCounters); + if (AnnotationAccess.isAnnotationPresent(method, COMPILED_LAMBDA_FORM_ANNOTATION)) { + /* + * Method handle intrinsification root: create counters with relaxed limits and + * permit more types of nodes, but not recursively, i.e., not if we are already in a + * method handle intrinsification context. + */ + accumulativeCounters = new AccumulativeCounters(optionMethodHandleAllowedNodes, optionMethodHandleAllowedInvokes, true); + } else { + accumulativeCounters = new AccumulativeCounters(optionAllowedNodes, optionAllowedInvokes, false); + } } else if (outer.accumulativeCounters.inMethodHandleIntrinsification && !inlineForMethodHandleIntrinsification(method)) { /* @@ -249,9 +325,12 @@ public AccumulativeInlineScope createAccumulativeInlineScope(AccumulativeInlineS * This assumes that the regular limits are strict enough to prevent excessive inlining * triggered by method handles. We could also use alternative fixed values or the option * defaults instead of any set option values. + * + * We start again with an inlining depth of 1, i.e., we behave as if that method is the + * inlining root. */ - depth = outer.inliningDepth + 1; - accumulativeCounters = AccumulativeCounters.create(outer.accumulativeCounters); + depth = 1; + accumulativeCounters = new AccumulativeCounters(optionAllowedNodes, optionAllowedInvokes, false); } else { /* Nested inlining (potentially during method handle intrinsification). */ @@ -261,54 +340,6 @@ public AccumulativeInlineScope createAccumulativeInlineScope(AccumulativeInlineS return new AccumulativeInlineScope(accumulativeCounters, depth); } - private boolean isMethodHandleIntrinsificationRoot(AnalysisMetaAccess metaAccess, AnalysisMethod method, boolean[] constArgsWithReceiver) { - return (isVarHandleMethod(metaAccess, method) || hasConstantMethodHandleParameter(metaAccess, method, constArgsWithReceiver)) && !isIgnoredMethodHandleMethod(method); - } - - private boolean hasConstantMethodHandleParameter(AnalysisMetaAccess metaAccess, AnalysisMethod method, boolean[] constArgsWithReceiver) { - if (methodHandleType == null) { - methodHandleType = metaAccess.lookupJavaType(MethodHandle.class); - } - for (int i = 0; i < constArgsWithReceiver.length; i++) { - if (constArgsWithReceiver[i] && methodHandleType.isAssignableFrom(getParameterType(method, i))) { - return true; - } - } - return false; - } - - private static AnalysisType getParameterType(AnalysisMethod method, int index) { - int i = index; - if (!method.isStatic()) { - if (i == 0) { // receiver - return method.getDeclaringClass(); - } - i--; - } - return method.getSignature().getParameterType(i); - } - - /** - * Checks if the method is the intrinsification root for a VarHandle. In the current VarHandle - * implementation, all guards are in the automatically generated class VarHandleGuards. All - * methods do have a VarHandle argument, and we expect it to be a compile-time constant. - *

    - * See the documentation in {@link VarHandleFeature} for more information on the overall - * VarHandle support. - */ - private boolean isVarHandleMethod(AnalysisMetaAccess metaAccess, AnalysisMethod method) { - if (varHandleGuardsType == null) { - varHandleGuardsType = metaAccess.lookupJavaType(ReflectionUtil.lookupClass(false, "java.lang.invoke.VarHandleGuards")); - } - return method.getDeclaringClass().equals(varHandleGuardsType); - } - - private static boolean isIgnoredMethodHandleMethod(AnalysisMethod method) { - Class declaringClass = OriginalClassProvider.getJavaClass(method.getDeclaringClass()); - Set ignoredMethods = IGNORED_METHOD_HANDLE_METHODS.get(declaringClass); - return ignoredMethods != null && ignoredMethods.contains(method.getName()); - } - public final class AccumulativeInlineScope extends InlineBeforeAnalysisPolicy.AbstractPolicyScope { final AccumulativeCounters accumulativeCounters; @@ -374,11 +405,6 @@ public boolean processNode(AnalysisMetaAccess metaAccess, AnalysisMethod method, return true; } - if (inliningDepth > accumulativeCounters.maxInliningDepth) { - // too deep to continue inlining - return false; - } - if (node instanceof FullInfopointNode || node instanceof ValueProxy || node instanceof ValueAnchorNode || node instanceof FrameState || node instanceof AbstractBeginNode || node instanceof AbstractEndNode) { /* @@ -395,6 +421,14 @@ public boolean processNode(AnalysisMetaAccess metaAccess, AnalysisMethod method, return true; } + if (node instanceof ConditionalNode) { + /* + * A ConditionalNode is used to "materialize" a prior logic node when returning a + * condition in a boolean method. We do not want to count it separately. + */ + return true; + } + if (node instanceof ReachabilityRegistrationNode) { /* * These nodes do not affect compilation and are only used to execute handlers @@ -462,25 +496,43 @@ public boolean processNode(AnalysisMetaAccess metaAccess, AnalysisMethod method, return allow || accumulativeCounters.inMethodHandleIntrinsification; } + @Override + public boolean processNonInlinedInvoke(CoreProviders providers, CallTargetNode node) { + if (node.targetMethod() != null && AnnotationAccess.isAnnotationPresent(node.targetMethod(), COMPILED_LAMBDA_FORM_ANNOTATION)) { + /* + * Prevent partial inlining of method handle code, both with and without + * "intrinsification of method handles". We rather want to keep a top-level call to + * the original method handle. + */ + return false; + } + return true; + } + @Override public String toString() { return "AccumulativeInlineScope: " + numNodes + "/" + numInvokes + " (" + accumulativeCounters.numNodes + "/" + accumulativeCounters.numInvokes + ")"; } } + private static final Set> INLINE_METHOD_HANDLE_CLASSES = Set.of( + /* Inline trivial helper methods for value conversion. */ + sun.invoke.util.ValueConversions.class); + + private static final Set INLINE_METHOD_HANDLE_METHODS = Set.of( + /* + * Important methods in the method handle implementation that do not have + * a @ForceInline annotation. + */ + ReflectionUtil.lookupMethod(ReflectionUtil.lookupClass(false, "java.lang.invoke.DirectMethodHandle"), "allocateInstance", Object.class), + ReflectionUtil.lookupMethod(ReflectionUtil.lookupClass(false, "java.lang.invoke.DirectMethodHandle$Accessor"), "checkCast", Object.class), + ReflectionUtil.lookupMethod(ReflectionUtil.lookupClass(false, "java.lang.invoke.DirectMethodHandle$StaticAccessor"), "checkCast", Object.class)); + private static boolean inlineForMethodHandleIntrinsification(AnalysisMethod method) { - String className = method.getDeclaringClass().toJavaName(true); - if (className.startsWith("java.lang.invoke") && !className.contains("InvokerBytecodeGenerator")) { - /* - * Inline all helper methods used by method handles. We do not know exactly which ones - * they are, but they are all from the same package. - */ - return true; - } else if (className.equals("sun.invoke.util.ValueConversions")) { - /* Inline trivial helper methods for value conversion. */ - return true; - } - return false; + return AnnotationAccess.isAnnotationPresent(method, ForceInline.class) || + AnnotationAccess.isAnnotationPresent(method, COMPILED_LAMBDA_FORM_ANNOTATION) || + INLINE_METHOD_HANDLE_CLASSES.contains(method.getDeclaringClass().getJavaClass()) || + INLINE_METHOD_HANDLE_METHODS.contains(method.getJavaMethod()); } /** From cfb6cfa37acbb88c97d39ea4e6ca01fcfa2de7dc Mon Sep 17 00:00:00 2001 From: Christian Wimmer Date: Wed, 27 Dec 2023 18:21:37 -0800 Subject: [PATCH 382/593] Better reporting for late shadow heap errors --- .../com/oracle/graal/pointsto/ObjectScanner.java | 14 +++++++------- .../oracle/svm/hosted/NativeImageGenerator.java | 2 ++ 2 files changed, 9 insertions(+), 7 deletions(-) diff --git a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/ObjectScanner.java b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/ObjectScanner.java index 7ed9916b5c32..7e09be8fa42f 100644 --- a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/ObjectScanner.java +++ b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/ObjectScanner.java @@ -145,7 +145,7 @@ protected void scanEmbeddedRoot(JavaConstant root, Object position) { try { scanningObserver.forEmbeddedRoot(root, reason); scanConstant(root, reason); - } catch (UnsupportedFeatureException ex) { + } catch (UnsupportedFeatureException | AnalysisError.TypeNotFoundError ex) { bb.getUnsupportedFeatures().addMessage(reason.toString(), reason.getMethod(), ex.getMessage(), null, ex); } } @@ -205,7 +205,7 @@ protected void scanField(AnalysisField field, JavaConstant receiver, ScanReason scanningObserver.forPrimitiveFieldValue(receiver, field, fieldValue, reason); } - } catch (UnsupportedFeatureException ex) { + } catch (UnsupportedFeatureException | AnalysisError.TypeNotFoundError ex) { unsupportedFeatureDuringFieldScan(bb, field, receiver, ex, reason); } } @@ -268,7 +268,7 @@ protected final void scanArray(JavaConstant array, ScanReason prevReason) { try { JavaConstant element = bb.getUniverse().getSnippetReflection().forObject(bb.getUniverse().replaceObject(e)); scanArrayElement(array, arrayType, reason, idx, element); - } catch (UnsupportedFeatureException ex) { /* Object replacement can throw. */ + } catch (UnsupportedFeatureException | AnalysisError.TypeNotFoundError ex) { unsupportedFeatureDuringConstantScan(bb, bb.getUniverse().getSnippetReflection().forObject(e), ex, reason); } } @@ -313,7 +313,7 @@ public void scanConstant(JavaConstant value, ScanReason reason) { * Use the constant hashCode as a key for the unsupported feature to register only one error * message if the constant is reachable from multiple places. */ - public static void unsupportedFeatureDuringConstantScan(BigBang bb, JavaConstant constant, UnsupportedFeatureException e, ScanReason reason) { + public static void unsupportedFeatureDuringConstantScan(BigBang bb, JavaConstant constant, Throwable e, ScanReason reason) { unsupportedFeature(bb, String.valueOf(receiverHashCode(constant)), e.getMessage(), reason); } @@ -322,11 +322,11 @@ public static void unsupportedFeatureDuringConstantScan(BigBang bb, JavaConstant * only one error message if the value is reachable from multiple places. For example both the * heap scanning and the heap verification would scan a field that contains an illegal value. */ - public static void unsupportedFeatureDuringFieldScan(BigBang bb, AnalysisField field, JavaConstant receiver, UnsupportedFeatureException e, ScanReason reason) { + public static void unsupportedFeatureDuringFieldScan(BigBang bb, AnalysisField field, JavaConstant receiver, Throwable e, ScanReason reason) { unsupportedFeature(bb, (receiver != null ? receiverHashCode(receiver) + "_" : "") + field.format("%H.%n"), e.getMessage(), reason); } - public static void unsupportedFeatureDuringFieldFolding(BigBang bb, AnalysisField field, JavaConstant receiver, UnsupportedFeatureException e, AnalysisMethod parsedMethod, int bci) { + public static void unsupportedFeatureDuringFieldFolding(BigBang bb, AnalysisField field, JavaConstant receiver, Throwable e, AnalysisMethod parsedMethod, int bci) { ScanReason reason = new FieldConstantFold(field, parsedMethod, bci, receiver, new MethodParsing(parsedMethod)); unsupportedFeature(bb, (receiver != null ? receiverHashCode(receiver) + "_" : "") + field.format("%H.%n"), e.getMessage(), reason); } @@ -448,7 +448,7 @@ private void doScan(WorklistEntry entry) { /* Scan the array elements. */ scanArray(entry.constant, entry.reason); } - } catch (UnsupportedFeatureException ex) { + } catch (UnsupportedFeatureException | AnalysisError.TypeNotFoundError ex) { unsupportedFeatureDuringConstantScan(bb, entry.constant, ex, entry.reason); } } diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/NativeImageGenerator.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/NativeImageGenerator.java index a9e4460375ef..6752dc122c6c 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/NativeImageGenerator.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/NativeImageGenerator.java @@ -670,6 +670,7 @@ protected void doRun(Map entryPoints, JavaMainSupport j /* Re-run shadow heap verification after compilation. */ aUniverse.getHeapVerifier().checkHeapSnapshot(debug, hMetaAccess, "after compilation", bb.getUniverse().getEmbeddedRoots()); + bb.getUnsupportedFeatures().report(bb); CodeCacheProvider codeCacheProvider = runtimeConfiguration.getBackendForNormalMethod().getProviders().getCodeCache(); reporter.printCreationStart(); @@ -751,6 +752,7 @@ private void verifyAndSealShadowHeap(NativeImageCodeCache codeCache, DebugContex */ Map embeddedConstants = codeCache.initAndGetEmbeddedConstants(); bb.getUniverse().getHeapVerifier().checkHeapSnapshot(debug, heap.hMetaAccess, "before heap layout", embeddedConstants); + bb.getUnsupportedFeatures().report(bb); /* * Seal shadow heap after final verification. Any modification to the shadow heap after this * point, i.e., registering a new ImageHeapConstant or materializing the hosted values From 901c81c5e795cc876bb037e6552d4c0c09c195bf Mon Sep 17 00:00:00 2001 From: Christian Wimmer Date: Thu, 28 Dec 2023 08:51:45 -0800 Subject: [PATCH 383/593] Only rescan fields that are reachable --- .../src/com/oracle/graal/pointsto/heap/ImageHeapScanner.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/heap/ImageHeapScanner.java b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/heap/ImageHeapScanner.java index b71030577aa5..939849b0368c 100644 --- a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/heap/ImageHeapScanner.java +++ b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/heap/ImageHeapScanner.java @@ -595,6 +595,9 @@ public void rescanField(Object receiver, Field reflectionField, ScanReason reaso if (type.isReachable()) { AnalysisField field = metaAccess.lookupJavaField(reflectionField); assert !field.isStatic() : field; + if (!field.isReachable()) { + return; + } JavaConstant receiverConstant = asConstant(receiver); Optional replaced = maybeReplace(receiverConstant, reason); if (replaced.isPresent()) { From f08ef1a97a03cb8913aa8ee2f6b7bbe4e798ce1d Mon Sep 17 00:00:00 2001 From: Christian Wimmer Date: Thu, 28 Dec 2023 09:30:18 -0800 Subject: [PATCH 384/593] Allow concrete subtypes of MethodHandle and VarHandle as parameters when folding reflection methods --- .../oracle/svm/hosted/snippets/ReflectionPlugins.java | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/snippets/ReflectionPlugins.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/snippets/ReflectionPlugins.java index 719033927eb5..b7a0ed3474a2 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/snippets/ReflectionPlugins.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/snippets/ReflectionPlugins.java @@ -635,12 +635,21 @@ private Object unboxObjectConstant(GraphBuilderContext b, JavaConstant argConsta /* Any other object that is not a Class. */ Object result = snippetReflection.asObject(Object.class, argConstant); - if (result != null && ALLOWED_CONSTANT_CLASSES.contains(result.getClass())) { + if (result != null && isAllowedConstant(result.getClass())) { return result; } return null; } + private boolean isAllowedConstant(Class clazz) { + for (var allowed : ALLOWED_CONSTANT_CLASSES) { + if (allowed.isAssignableFrom(clazz)) { + return true; + } + } + return false; + } + /** * This method checks if the element should be intrinsified and returns the cached intrinsic * element if found. Caching intrinsic elements during analysis and reusing the same element From 6e52619e1f742dd79d598ddbe6d51577a0601301 Mon Sep 17 00:00:00 2001 From: Christian Wimmer Date: Thu, 28 Dec 2023 18:57:49 -0800 Subject: [PATCH 385/593] Ensure all Module objects are seen by the ModuleLayerFeature --- .../src/com/oracle/svm/hosted/ModuleLayerFeature.java | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/ModuleLayerFeature.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/ModuleLayerFeature.java index 13edc84ff9f7..2ef1b608213d 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/ModuleLayerFeature.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/ModuleLayerFeature.java @@ -66,6 +66,7 @@ import com.oracle.svm.core.feature.AutomaticallyRegisteredFeature; import com.oracle.svm.core.feature.InternalFeature; import com.oracle.svm.core.heap.UnknownObjectField; +import com.oracle.svm.core.hub.DynamicHub; import com.oracle.svm.core.jdk.Resources; import com.oracle.svm.core.jdk.RuntimeModuleSupport; import com.oracle.svm.core.util.VMError; @@ -139,6 +140,14 @@ public void duringSetup(DuringSetupAccess access) { private Object replaceHostedModules(Object source) { if (source instanceof Module module) { return moduleLayerFeatureUtils.getOrCreateRuntimeModuleForHostedModule(module); + } else if (source instanceof Class clazz) { + /* + * If the field Class(=DynamicHub).module is not reachable, we do not see all Module + * instances directly. So we also need to scan the module in Class/DynamicHub objects. + */ + moduleLayerFeatureUtils.getOrCreateRuntimeModuleForHostedModule(clazz.getModule()); + } else if (source instanceof DynamicHub hub) { + moduleLayerFeatureUtils.getOrCreateRuntimeModuleForHostedModule(hub.getModule()); } return source; } From 6e0c0513509e9f7fe4cd6daaba08c64a28abfcd6 Mon Sep 17 00:00:00 2001 From: Christian Wimmer Date: Sun, 31 Dec 2023 13:32:39 -0800 Subject: [PATCH 386/593] Changelog entry --- substratevm/CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/substratevm/CHANGELOG.md b/substratevm/CHANGELOG.md index 9542ed34d5be..9560988d0e20 100644 --- a/substratevm/CHANGELOG.md +++ b/substratevm/CHANGELOG.md @@ -18,6 +18,7 @@ This changelog summarizes major changes to GraalVM Native Image. * (GR-30433) Disallow the deprecated environment variable USE_NATIVE_IMAGE_JAVA_PLATFORM_MODULE_SYSTEM=false. * (GR-49655) Experimental support for parts of the [Foreign Function & Memory API](https://github.com/oracle/graal/blob/master/docs/reference-manual/native-image/ForeignInterface.md) (part of "Project Panama", [JEP 454](https://openjdk.org/jeps/454)) on AMD64. Must be enabled with `-H:+ForeignAPISupport` (requiring `-H:+UnlockExperimentalVMOptions`). * (GR-46407) Correctly rethrow build-time linkage errors at run-time for registered reflection queries. +* (GR-51002) Improve intrinsification of method handles. This especially improves the performance of `equals` and `hashCode` methods for records, which use method handles that are now intrinsified. ## GraalVM for JDK 21 (Internal Version 23.1.0) * (GR-35746) Lower the default aligned chunk size from 1 MB to 512 KB for the serial and epsilon GCs, reducing memory usage and image size in many cases. From 3ea048f2d97c70fbbdb414ff74872066ad31f69c Mon Sep 17 00:00:00 2001 From: Christian Wimmer Date: Wed, 27 Dec 2023 09:08:39 -0800 Subject: [PATCH 387/593] Fix method override reachability handler notification --- .../graal/pointsto/meta/AnalysisField.java | 21 ++++++++++------- .../graal/pointsto/meta/AnalysisType.java | 23 +++++++++++-------- 2 files changed, 26 insertions(+), 18 deletions(-) diff --git a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/meta/AnalysisField.java b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/meta/AnalysisField.java index e8ed9ab33b56..d9feb2ba3ee8 100644 --- a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/meta/AnalysisField.java +++ b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/meta/AnalysisField.java @@ -544,16 +544,21 @@ public JavaConstant getConstantValue() { */ public void beforeFieldValueAccess() { declaringClass.registerAsReachable(this); - declaringClass.ensureOnTypeReachableTaskDone(); - List> notifications = declaringClass.scheduledTypeReachableNotifications; - if (notifications != null) { - for (var notification : notifications) { - notification.ensureDone(); + declaringClass.forAllSuperTypes(type -> { + type.ensureOnTypeReachableTaskDone(); + + List> notifications = type.scheduledTypeReachableNotifications; + if (notifications != null) { + for (var notification : notifications) { + notification.ensureDone(); + } + /* + * Now we know all the handlers have been executed, no checks are necessary anymore. + */ + type.scheduledTypeReachableNotifications = null; } - /* Now we know all the handlers have been executed, no checks are necessary anymore. */ - declaringClass.scheduledTypeReachableNotifications = null; - } + }); } public void addAnalysisFieldObserver(AnalysisFieldObserver observer) { diff --git a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/meta/AnalysisType.java b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/meta/AnalysisType.java index e87a907f9d3f..4cc54061690e 100644 --- a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/meta/AnalysisType.java +++ b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/meta/AnalysisType.java @@ -576,8 +576,16 @@ public void registerAsAssignable(BigBang bb) { public boolean registerAsReachable(Object reason) { assert isValidReason(reason) : "Registering a type as reachable needs to provide a valid reason."; if (!AtomicUtils.isSet(this, isReachableUpdater)) { - /* Mark this type and all its super types as reachable. */ - forAllSuperTypes(type -> AtomicUtils.atomicSetAndRun(type, reason, isReachableUpdater, type::onReachable)); + /* First mark all super types as reachable. */ + forAllSuperTypes(type -> type.registerAsReachable(reason), false); + /* + * Only mark this type itself as reachable after marking all supertypes. This ensures + * that, e.g., a type is never seen as reachable by another thread before all of its + * supertypes are already marked as reachable too. Note that this does *not* guarantee + * that the onReachable hook for all supertypes is already finished, because they can + * still be running in another thread. + */ + AtomicUtils.atomicSetAndRun(this, reason, isReachableUpdater, this::onReachable); return true; } return false; @@ -705,18 +713,13 @@ private static void forAllSuperTypes(AnalysisType elementType, int arrayDimensio if (elementType == null) { return; } + if (processType) { + superTypeConsumer.accept(elementType.getArrayClass(arrayDimension)); + } for (AnalysisType interf : elementType.getInterfaces()) { forAllSuperTypes(interf, arrayDimension, true, superTypeConsumer); } forAllSuperTypes(elementType.getSuperclass(), arrayDimension, true, superTypeConsumer); - /* - * Process the type itself only after visiting all supertypes. This ensures that, e.g., a - * type is never seen as reachable by another thread before all of its supertypes are - * already marked as reachable too. - */ - if (processType) { - superTypeConsumer.accept(elementType.getArrayClass(arrayDimension)); - } } protected synchronized void addAssignableType(BigBang bb, TypeState typeState) { From ff2f1eac315609e6e61790cc86ecd8c8e06ac308 Mon Sep 17 00:00:00 2001 From: Marouane El Hallaoui Date: Mon, 8 Jan 2024 23:37:56 +0100 Subject: [PATCH 388/593] deploy labsjdk snapshots --- common.json | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/common.json b/common.json index d2b5a8e886f2..3de3235179e8 100644 --- a/common.json +++ b/common.json @@ -45,12 +45,12 @@ "labsjdk-ee-21-llvm": {"name": "labsjdk", "version": "ee-21.0.1+11-jvmci-23.1-b26-sulong", "platformspecific": true }, "oraclejdk-latest": {"name": "jpg-jdk", "version": "23", "build_id": "4", "release": true, "platformspecific": true, "extrabundles": ["static-libs"]}, - "labsjdk-ce-latest": {"name": "labsjdk", "version": "ce-23+4-jvmci-b01-20240105210900-50fd6eca51", "platformspecific": true }, - "labsjdk-ce-latestDebug": {"name": "labsjdk", "version": "ce-23+4-jvmci-b01-20240105210900-50fd6eca51-debug", "platformspecific": true }, - "labsjdk-ce-latest-llvm": {"name": "labsjdk", "version": "ce-23+4-jvmci-b01-20240105210900-50fd6eca51-sulong", "platformspecific": true }, - "labsjdk-ee-latest": {"name": "labsjdk", "version": "ee-23+4-jvmci-b01-20240105210900-50fd6eca51+3e47329d85", "platformspecific": true }, - "labsjdk-ee-latestDebug": {"name": "labsjdk", "version": "ee-23+4-jvmci-b01-20240105210900-50fd6eca51+3e47329d85-debug", "platformspecific": true }, - "labsjdk-ee-latest-llvm": {"name": "labsjdk", "version": "ee-23+4-jvmci-b01-20240105210900-50fd6eca51+3e47329d85-sulong", "platformspecific": true } + "labsjdk-ce-latest": {"name": "labsjdk", "version": "ce-23+4-jvmci-b01", "platformspecific": true }, + "labsjdk-ce-latestDebug": {"name": "labsjdk", "version": "ce-23+4-jvmci-b01-debug", "platformspecific": true }, + "labsjdk-ce-latest-llvm": {"name": "labsjdk", "version": "ce-23+4-jvmci-b01-sulong", "platformspecific": true }, + "labsjdk-ee-latest": {"name": "labsjdk", "version": "ee-23+4-jvmci-b01", "platformspecific": true }, + "labsjdk-ee-latestDebug": {"name": "labsjdk", "version": "ee-23+4-jvmci-b01-debug", "platformspecific": true }, + "labsjdk-ee-latest-llvm": {"name": "labsjdk", "version": "ee-23+4-jvmci-b01-sulong", "platformspecific": true } }, "eclipse": { From 56f2a82cc4cc56aa27a86818bf834e9f0dd4de45 Mon Sep 17 00:00:00 2001 From: Michael Simacek Date: Tue, 9 Jan 2024 08:22:04 +0000 Subject: [PATCH 389/593] [GR-51045] Move intrinsified _pickle module PullRequest: graalpython/3142 --- vm/mx.vm/suite.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vm/mx.vm/suite.py b/vm/mx.vm/suite.py index 2f4386148939..d6b80ccac7e1 100644 --- a/vm/mx.vm/suite.py +++ b/vm/mx.vm/suite.py @@ -65,7 +65,7 @@ }, { "name": "graalpython", - "version": "1b0fe2ddd0bb4e02b867a0b90380ecd719da89b0", + "version": "cf3c107181f2375f4241eba4bc49751b43f5bd88", "dynamic": True, "urls": [ {"url": "https://github.com/graalvm/graalpython.git", "kind": "git"}, From 9a0453bf8ddfad3a7bd5296c230b545e08ac7004 Mon Sep 17 00:00:00 2001 From: Roland Schatz Date: Thu, 23 Nov 2023 13:53:20 +0100 Subject: [PATCH 390/593] Use multi-target support in mx to Build separate support libraries for musl cross-compilation. --- sdk/mx.sdk/suite.py | 75 +++++++++++++++++++++++++++++ substratevm/mx.substratevm/suite.py | 68 +++++++++++++++----------- 2 files changed, 116 insertions(+), 27 deletions(-) diff --git a/sdk/mx.sdk/suite.py b/sdk/mx.sdk/suite.py index a7ceded8071e..eacc33a5e0ba 100644 --- a/sdk/mx.sdk/suite.py +++ b/sdk/mx.sdk/suite.py @@ -215,6 +215,26 @@ "digest" : "sha512:1bb2f66cc123bb9f0263cd186a8ab7948939f181001e57a7171466534bc89c0ebb17863e90c487f48083f202745ea3d90275a3fa26d793fd2b9f1b62d7e1eabd", "license" : "Apache-2.0-LLVM", }, + "MUSL_GCC_TOOLCHAIN" : { + "packedResource": True, + "os_arch": { + "linux": { + "amd64": { + "urls" : ["https://lafo.ssw.uni-linz.ac.at/pub/toolchain-gcc-musl/toolchain-gcc-10.2.1-musl-1.2.2-linux-amd64.tar.gz"], + "digest" : "sha512:8f49b04d4826c560c791e5223f504046fa0daa6b79e581ea1781a2d01f4efe2de4a0fb6771dc1b07318ab0109a61ea3b04255eadf36191a76687f873931eb283", + }, + "aarch64": { + "urls" : ["https://lafo.ssw.uni-linz.ac.at/pub/toolchain-gcc-musl/toolchain-gcc-10.2.1-musl-1.2.2-linux-aarch64.tar.gz"], + "digest" : "sha512:f5545f6b36c2306861c026895d437a57357515e8dfefb0e8419413f61b146f42dc072f8a8a7a9f4885d6448396d656f59264e61e3f5eedd278486228aa58904e", + }, + }, + "": { + "": { + "optional": True, + } + } + }, + }, }, "projects" : { "org.graalvm.options" : { @@ -1175,5 +1195,60 @@ class UniversalDetector { ], "graalCompilerSourceEdition": "ignore", }, + "MUSL_NINJA_TOOLCHAIN" : { + "native" : True, + "platformDependent" : True, + "native_toolchain" : { + "kind": "ninja", + "target": { + # host os/arch + "libc": "musl", + }, + }, + "os_arch": { + "linux": { + "amd64": { + "layout" : { + "toolchain.ninja" : { + "source_type": "string", + "value": ''' +include +CC=/x86_64-linux-musl-native/bin/gcc +CXX=/x86_64-linux-musl-native/bin/g++ +AR=/x86_64-linux-musl-native/bin/ar +''' + }, + }, + "dependencies": [ + "MUSL_GCC_TOOLCHAIN", + "mx:GCC_NINJA_TOOLCHAIN", + ], + }, + "aarch64": { + "layout" : { + "toolchain.ninja" : { + "source_type": "string", + "value": ''' +include +CC=/aarch64-linux-musl-native/bin/gcc +CXX=/aarch64-linux-musl-native/bin/g++ +AR=/aarch64-linux-musl-native/bin/ar +''' + }, + }, + "dependencies": [ + "MUSL_GCC_TOOLCHAIN", + "mx:GCC_NINJA_TOOLCHAIN", + ], + }, + }, + "": { + "": { + "optional": True, + } + }, + }, + "maven" : False, + }, }, } diff --git a/substratevm/mx.substratevm/suite.py b/substratevm/mx.substratevm/suite.py index ff63e6e642c9..f1f9edad30b6 100644 --- a/substratevm/mx.substratevm/suite.py +++ b/substratevm/mx.substratevm/suite.py @@ -736,21 +736,21 @@ "com.oracle.svm.native.libchelper": { "subDir": "src", "native": "static_lib", - "os_arch": { + "multitarget": { + "libc": ["glibc", "musl", "default"], + }, + "os": { "solaris": { - "": { - "ignore": "solaris is not supported", - }, + "ignore": "solaris is not supported", }, "windows": { - "": { - "cflags": ["-Zi", "-O2", "-D_LITTLE_ENDIAN"], - }, + "cflags": ["-Zi", "-O2", "-D_LITTLE_ENDIAN"], + }, + "linux": { + "cflags": ["-g", "-gdwarf-4", "-fPIC", "-O2", "-D_LITTLE_ENDIAN", "-ffunction-sections", "-fdata-sections", "-fvisibility=hidden", "-D_FORTIFY_SOURCE=0"], }, "": { - "": { - "cflags": ["-g", "-gdwarf-4", "-fPIC", "-O2", "-D_LITTLE_ENDIAN", "-ffunction-sections", "-fdata-sections", "-fvisibility=hidden", "-D_FORTIFY_SOURCE=0"], - }, + "cflags": ["-g", "-gdwarf-4", "-fPIC", "-O2", "-D_LITTLE_ENDIAN", "-ffunction-sections", "-fdata-sections", "-fvisibility=hidden", "-D_FORTIFY_SOURCE=0"], }, }, "jacoco" : "exclude", @@ -800,21 +800,18 @@ "native": "static_lib", "deliverable" : "jvm", "use_jdk_headers" : True, - "os_arch" : { + "multitarget": { + "libc": ["glibc", "musl", "default"], + }, + "os" : { "darwin": { - "" : { - "cflags": ["-g", "-fPIC", "-O2", "-ffunction-sections", "-fdata-sections", "-fvisibility=hidden"], - }, + "cflags": ["-g", "-fPIC", "-O2", "-ffunction-sections", "-fdata-sections", "-fvisibility=hidden"], }, "linux": { - "" : { - "cflags": ["-g", "-gdwarf-4", "-fPIC", "-O2", "-ffunction-sections", "-fdata-sections", "-fvisibility=hidden", "-D_FORTIFY_SOURCE=0", "-D_GNU_SOURCE"], - }, + "cflags": ["-g", "-gdwarf-4", "-fPIC", "-O2", "-ffunction-sections", "-fdata-sections", "-fvisibility=hidden", "-D_FORTIFY_SOURCE=0", "-D_GNU_SOURCE"], }, "": { - "": { - "ignore": "only darwin and linux are supported", - }, + "ignore": "only darwin and linux are supported", }, }, "dependencies": [ @@ -1752,13 +1749,30 @@ "darwin-amd64", "windows-amd64", ], - "layout": { - "-/": [ - "dependency:com.oracle.svm.native.libchelper/*", - "dependency:com.oracle.svm.native.darwin/*", - "dependency:com.oracle.svm.native.jvm.posix/*", - "dependency:com.oracle.svm.native.jvm.windows/*", - ], + "os": { + "linux": { + "layout": { + # on linux we want os-arch/libc directory structure + "./": [ + "dependency:com.oracle.svm.native.libchelper/*", + "dependency:com.oracle.svm.native.jvm.posix/*", + ], + }, + }, + "": { + "layout": { + # on all other os's we don't want libc specific subdirectories + "include/": [ + "dependency:com.oracle.svm.native.libchelper/include/*", + ], + "-/": [ + "dependency:com.oracle.svm.native.libchelper/-/default/*", + "dependency:com.oracle.svm.native.jvm.posix/-/default/*", + "dependency:com.oracle.svm.native.darwin/*", + "dependency:com.oracle.svm.native.jvm.windows/*", + ], + }, + }, }, "description" : "SubstrateVM image builder native components", "noMavenJavadoc": True, From 91321e370d3fbb8629ccd5e711e55de646f2233e Mon Sep 17 00:00:00 2001 From: Roland Schatz Date: Fri, 15 Dec 2023 15:24:12 +0100 Subject: [PATCH 391/593] Set correct library paths for libc variants in native-image launcher. --- .../com/oracle/svm/driver/BundleSupport.java | 2 +- .../com/oracle/svm/driver/NativeImage.java | 22 +++++++++++++++---- 2 files changed, 19 insertions(+), 5 deletions(-) diff --git a/substratevm/src/com.oracle.svm.driver/src/com/oracle/svm/driver/BundleSupport.java b/substratevm/src/com.oracle.svm.driver/src/com/oracle/svm/driver/BundleSupport.java index dba05ac7d47f..18be7c322c57 100644 --- a/substratevm/src/com.oracle.svm.driver/src/com/oracle/svm/driver/BundleSupport.java +++ b/substratevm/src/com.oracle.svm.driver/src/com/oracle/svm/driver/BundleSupport.java @@ -228,7 +228,7 @@ static BundleSupport create(NativeImage nativeImage, String bundleArg, NativeIma void createDockerfile(Path dockerfile) { nativeImage.showVerboseMessage(nativeImage.isVerbose(), BUNDLE_INFO_MESSAGE_PREFIX + "Creating default Dockerfile for native-image bundle."); String dockerfileText = DEFAULT_DOCKERFILE; - if (nativeImage.staticExecutable && nativeImage.libC.equals("musl")) { + if (nativeImage.staticExecutable && "musl".equals(nativeImage.targetLibC)) { dockerfileText += System.lineSeparator() + DEFAULT_DOCKERFILE_MUSLIB; } try { diff --git a/substratevm/src/com.oracle.svm.driver/src/com/oracle/svm/driver/NativeImage.java b/substratevm/src/com.oracle.svm.driver/src/com/oracle/svm/driver/NativeImage.java index c230b49e1cde..ce165065d2d2 100644 --- a/substratevm/src/com.oracle.svm.driver/src/com/oracle/svm/driver/NativeImage.java +++ b/substratevm/src/com.oracle.svm.driver/src/com/oracle/svm/driver/NativeImage.java @@ -1057,6 +1057,18 @@ private void handleModuleExports(String modulesValues, OptionKey option) { } } + private Stream resolveTargetSpecificPaths(Path base) { + Stream.Builder builder = Stream.builder(); + String clibrariesPath = (targetPlatform != null) ? targetPlatform : platform; + Path osArch = base.resolve(clibrariesPath); + if (targetLibC != null) { + builder.add(osArch.resolve(targetLibC)); + } + builder.add(osArch); + builder.add(base); + return builder.build(); + } + private int completeImageBuild() { List leftoverArgs = processNativeImageArgs(); apiOptionHandler.validateExperimentalOptions(); @@ -1078,9 +1090,12 @@ private int completeImageBuild() { completeOptionArgs(); addTargetArguments(); - String clibrariesPath = (targetPlatform != null) ? targetPlatform : platform; + String defaultLibC = OS.getCurrent() == OS.LINUX ? "glibc" : null; + targetLibC = getHostedOptionFinalArgument(imageBuilderArgs, oHUseLibC).map(ArgumentEntry::value).orElse(System.getProperty("substratevm.HostLibC", defaultLibC)); + String clibrariesBuilderArg = config.getBuilderCLibrariesPaths().stream() - .map(path -> canonicalize(path.resolve(clibrariesPath)).toString()) + .flatMap(this::resolveTargetSpecificPaths) + .map(Path::toString) .collect(Collectors.joining(",", oHCLibraryPath, "")); imageBuilderArgs.add(0, clibrariesBuilderArg); @@ -1145,7 +1160,6 @@ private int completeImageBuild() { mainClass = getHostedOptionFinalArgumentValue(imageBuilderArgs, oHClass); buildExecutable = imageBuilderArgs.stream().noneMatch(arg -> arg.startsWith(oHEnableSharedLibraryFlagPrefix)); staticExecutable = imageBuilderArgs.stream().anyMatch(arg -> arg.contains(oHEnableStaticExecutable)); - libC = getHostedOptionFinalArgumentValue(imageBuilderArgs, oHUseLibC); boolean listModules = imageBuilderArgs.stream().anyMatch(arg -> arg.contains(oH + "+" + "ListModules")); printFlags |= imageBuilderArgs.stream().anyMatch(arg -> arg.matches("-H:MicroArchitecture(@[^=]*)?=list")); @@ -1440,7 +1454,7 @@ private void addTargetArguments() { boolean buildExecutable; boolean staticExecutable; - String libC; + String targetLibC; String mainClass; String mainClassModule; String imageName; From 052b0e30e86ec357a6eb5f358718f5c6460665c0 Mon Sep 17 00:00:00 2001 From: Roland Schatz Date: Mon, 18 Dec 2023 12:58:19 +0100 Subject: [PATCH 392/593] Specify extra targets in GraalVM components, add musl support libs. --- sdk/mx.sdk/mx_sdk_vm.py | 5 ++++- sdk/mx.sdk/mx_sdk_vm_impl.py | 7 +++++++ substratevm/mx.substratevm/mx_substratevm.py | 1 + 3 files changed, 12 insertions(+), 1 deletion(-) diff --git a/sdk/mx.sdk/mx_sdk_vm.py b/sdk/mx.sdk/mx_sdk_vm.py index 29ea7cbdeca1..c66bccc05ddc 100644 --- a/sdk/mx.sdk/mx_sdk_vm.py +++ b/sdk/mx.sdk/mx_sdk_vm.py @@ -263,7 +263,8 @@ def __init__(self, stability=None, extra_installable_qualifiers=None, has_relative_home=True, - jvm_configs=None): + jvm_configs=None, + extra_native_targets=None): """ :param suite mx.Suite: the suite this component belongs to :type name: str @@ -280,6 +281,7 @@ def __init__(self, 'configs': ['-truffle KNOWN'], 'priority': -1, # 0 is invalid; < 0 prepends to the default configs; > 0 appends } + :param extra_native_targets: list of str, enables extra targets in multi-target projects. :type license_files: list[str] :type third_party_license_files: list[str] :type polyglot_lib_build_args: list[str] @@ -341,6 +343,7 @@ def __init__(self, self.extra_installable_qualifiers = extra_installable_qualifiers or [] self.has_relative_home = has_relative_home self.jvm_configs = jvm_configs or [] + self.extra_native_targets = extra_native_targets if supported is not None or early_adopter: if stability is not None: diff --git a/sdk/mx.sdk/mx_sdk_vm_impl.py b/sdk/mx.sdk/mx_sdk_vm_impl.py index 9a9c8a437ab3..85237c793d8f 100644 --- a/sdk/mx.sdk/mx_sdk_vm_impl.py +++ b/sdk/mx.sdk/mx_sdk_vm_impl.py @@ -3601,6 +3601,13 @@ def register_main_dist(dist, label): _final_graalvm_distribution = get_final_graalvm_distribution() + from mx_native import TargetSelection + for c in _final_graalvm_distribution.components: + if c.extra_native_targets: + for t in c.extra_native_targets: + mx.logv(f"Selecting extra target '{t}' from GraalVM component '{c.short_name}'.") + TargetSelection.add_extra(t) + # Add the macros if SubstrateVM is in stage1, as images could be created later with an installable Native Image with_svm = has_component('svm', stage1=True) libpolyglot_component = mx_sdk_vm.graalvm_component_by_name('libpoly', fatalIfMissing=False) if with_svm else None diff --git a/substratevm/mx.substratevm/mx_substratevm.py b/substratevm/mx.substratevm/mx_substratevm.py index 4229fc6608a4..fa896c41fdd9 100644 --- a/substratevm/mx.substratevm/mx_substratevm.py +++ b/substratevm/mx.substratevm/mx_substratevm.py @@ -1006,6 +1006,7 @@ def native_image_context_run(func, func_args=None, config=None, build_if_missing 'substratevm:NATIVE_IMAGE_BASE', ] + (['substratevm:SVM_FOREIGN'] if mx_sdk_vm.base_jdk().javaCompliance >= '22' else []), support_distributions=['substratevm:SVM_GRAALVM_SUPPORT'], + extra_native_targets=['linux-default-glibc', 'linux-default-musl'] if mx.is_linux() else None, stability="earlyadopter", jlink=False, installable=False, From aec3d51d7dc61c89789acc5fd1279c2c97d7aef6 Mon Sep 17 00:00:00 2001 From: Danilo Ansaloni Date: Wed, 20 Dec 2023 15:53:01 +0100 Subject: [PATCH 393/593] The `MUSL_NINJA_TOOLCHAIN` distribution is not part of the Graal compiler source edition. --- sdk/mx.sdk/suite.py | 1 + 1 file changed, 1 insertion(+) diff --git a/sdk/mx.sdk/suite.py b/sdk/mx.sdk/suite.py index eacc33a5e0ba..e132cc441941 100644 --- a/sdk/mx.sdk/suite.py +++ b/sdk/mx.sdk/suite.py @@ -1249,6 +1249,7 @@ class UniversalDetector { }, }, "maven" : False, + "graalCompilerSourceEdition": "ignore", }, }, } From 004dfd6c98e9b76fa7fdb2d3f991f5a056ae8210 Mon Sep 17 00:00:00 2001 From: Roland Schatz Date: Tue, 28 Nov 2023 16:33:40 +0100 Subject: [PATCH 394/593] Update mx version. --- sdk/mx.sdk/suite.py | 2 +- substratevm/mx.substratevm/suite.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/sdk/mx.sdk/suite.py b/sdk/mx.sdk/suite.py index e132cc441941..5fd46d186c3f 100644 --- a/sdk/mx.sdk/suite.py +++ b/sdk/mx.sdk/suite.py @@ -39,7 +39,7 @@ # SOFTWARE. # suite = { - "mxversion": "6.53.2", + "mxversion": "7.5.0", "name" : "sdk", "version" : "24.0.0", "release" : False, diff --git a/substratevm/mx.substratevm/suite.py b/substratevm/mx.substratevm/suite.py index f1f9edad30b6..e286da1c0835 100644 --- a/substratevm/mx.substratevm/suite.py +++ b/substratevm/mx.substratevm/suite.py @@ -1,6 +1,6 @@ # pylint: disable=line-too-long suite = { - "mxversion": "6.27.1", + "mxversion": "7.5.0", "name": "substratevm", "version" : "24.0.0", "release" : False, From 3834e5ac1cae29b3e15c3cc76fa5ade1eb49926e Mon Sep 17 00:00:00 2001 From: Fabio Niephaus Date: Thu, 4 Jan 2024 07:58:50 +0000 Subject: [PATCH 395/593] Update Native Image JNI documentation --- docs/reference-manual/native-image/JNI.md | 23 +++++++++++++---------- 1 file changed, 13 insertions(+), 10 deletions(-) diff --git a/docs/reference-manual/native-image/JNI.md b/docs/reference-manual/native-image/JNI.md index 78dcb7e3c116..542f3e10af68 100644 --- a/docs/reference-manual/native-image/JNI.md +++ b/docs/reference-manual/native-image/JNI.md @@ -11,10 +11,11 @@ redirect_from: /reference-manual/native-image/JNI/ Java Native Interface (JNI) is a native API that enables Java code to interact with native code and vice versa. This page gives an overview of the JNI implementation in Native Image. -JNI support is enabled by default and built into Native Image. Individual classes, methods, and fields that should be accessible via JNI must be specified at image build time in a configuration file (read below). +JNI support is enabled by default and built into Native Image. +Individual classes, methods, and fields that should be accessible via JNI must be specified at image build time in a configuration file (read below). Java code can load native code from a shared object with `System.loadLibrary()`. -Alternatively, native code can load the JVM's native library and attach to its Java environment using JNI's Invocation API. +Alternatively, native code can load the JVM's native library and attach to its Java environment using the Invocation API. The Native Image JNI implementation supports both approaches. ### Table of Contents @@ -32,9 +33,8 @@ The Native Image JNI implementation supports both approaches. ## Loading Native Libraries -When loading native libraries using `System.loadLibrary()` (and related APIs), the native image will search the -directory containing the native library before searching the Java library path. So as long as the native libraries -to be loaded are in the same directory as the native image, no other settings should be necessary. +When loading native libraries using `System.loadLibrary()` (and related APIs), the native image will search the directory containing the native library before searching the Java library path. +So as long as the native libraries to be loaded are in the same directory as the native image, no other settings should be necessary. ## Reflection Metadata @@ -45,17 +45,20 @@ Moreover, `native-image` must generate wrapper code ahead-of-time for any method Therefore, specifying a concise list of items that need to be accessible via JNI guarantees their availability and allows for a smaller footprint. Such a list can be specified with the following image build argument: ```shell --H:JNIConfigurationFiles=/path/to/jniconfig +-H:JNIConfigurationFiles=/path/to/jni-config.json ``` -Here, _jniconfig_ is a JSON configuration file. +Here, _jni-config.json_ is a JSON configuration file. Check the JSON schema for specifing JNI metadata [here](ReachabilityMetadata.md#specifying-metadata-with-json). The `native-image` builder generates JNI reflection metadata for all classes, methods, and fields referenced in the configuration file. More than one JNI configuration can be used by specifying multiple paths for `JNIConfigurationFiles` and separating them with `,`. Also, `-H:JNIConfigurationResources` can be specified to load one or several configuration files from the image build's class path, such as from a JAR file. -The JNI configuration can be collected automatically using the [Tracing Agent](AutomaticMetadataCollection.md), provided with GraalVM. The agent tracks all usages of dynamic features during application execution on a regular Java VM. When the application completes and the JVM exits, the agent writes configuration to JSON files in the specified output directory. -If you move the generated configuration files from that output directory to _META-INF/native-image/_ on the class path, they are then automatically included at build time. The `native-image` builder searches for _META-INF/native-image/_ and its subdirectories for files named _jni-config.json_, _reflect-config.json_, and others. +The JNI configuration can be collected automatically using the [Tracing Agent](AutomaticMetadataCollection.md), provided with GraalVM. +The agent tracks all usages of dynamic features during application execution on a regular Java VM. +When the application completes and the JVM exits, the agent writes configuration to JSON files in the specified output directory. +If you move the generated configuration files from that output directory to _META-INF/native-image/_ on the class path, they are then automatically used at build time. +The `native-image` builder searches for _META-INF/native-image/_ and its subdirectories for files named _jni-config.json_, _reflect-config.json_, and others. Alternatively, a custom `Feature` implementation can register program elements before and during the analysis phase of the image build using the `JNIRuntimeAccess` class. For example: ```java @@ -74,7 +77,7 @@ class JNIRegistrationFeature implements Feature { } } ``` -To activate the custom feature `--features=` needs to be passed to native-image. +To activate the custom feature, pass `--features=` to the `native-image` builder. [Native Image Build Configuration](BuildConfiguration.md#embed-a-configuration-file) explains how this can be automated with a `native-image.properties` file in `META-INF/native-image`. ### java.lang.reflect Support From 1d075b5c307cfbcf3b4496ccecd09cdf935e7faa Mon Sep 17 00:00:00 2001 From: ol-automation_ww Date: Tue, 9 Jan 2024 15:47:52 +0000 Subject: [PATCH 396/593] [GR-5369] Periodic update of the Graal import. PullRequest: fastr/2879 --- vm/mx.vm/suite.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vm/mx.vm/suite.py b/vm/mx.vm/suite.py index d6b80ccac7e1..cafd90e17f64 100644 --- a/vm/mx.vm/suite.py +++ b/vm/mx.vm/suite.py @@ -57,7 +57,7 @@ }, { "name": "fastr", - "version": "e67d35460eb33d47cfe1a2d535b64524eacfed81", + "version": "ea083f09c707b48b25d58fda6cb290187726d9f6", "dynamic": True, "urls": [ {"url": "https://github.com/oracle/fastr.git", "kind": "git"}, From b99d44e5a5b38706155c982bcaaec664553243d0 Mon Sep 17 00:00:00 2001 From: Tomas Zezula Date: Tue, 9 Jan 2024 12:19:08 +0100 Subject: [PATCH 397/593] [GR-51012] The LibGraal Truffle gate fails on host compilation error. --- .../truffle/test/ExceptionActionTest.java | 29 +++---- .../test/GraalTruffleRuntimeListenerTest.java | 76 ++++++++++--------- truffle/mx.truffle/mx_truffle.py | 1 + .../oracle/truffle/runtime/EngineData.java | 2 + vm/mx.vm/mx_vm_gate.py | 1 + 5 files changed, 59 insertions(+), 50 deletions(-) diff --git a/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/truffle/test/ExceptionActionTest.java b/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/truffle/test/ExceptionActionTest.java index 3945b5dc1e58..c66001211a15 100644 --- a/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/truffle/test/ExceptionActionTest.java +++ b/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/truffle/test/ExceptionActionTest.java @@ -44,7 +44,6 @@ import jdk.graal.compiler.truffle.test.nodes.RootTestNode; import org.graalvm.polyglot.Context; import org.junit.Assert; -import org.junit.BeforeClass; import org.junit.Test; import com.oracle.truffle.api.CompilerAsserts; @@ -63,17 +62,6 @@ public class ExceptionActionTest extends TestWithPolyglotOptions { static Object nonConstant; - @BeforeClass - public static void setUp() { - // All ExceptionActionTest's tests are executed in the spawned subprocess. The - // PermanentBailoutNode is used only by the code running in the subprocess. Needless - // PermanentBailoutNode initialization in the parent process will cause ExceptionActionTest - // failure when running with the engine.ExceptionAction=Throw. - if (SubprocessTestUtils.isSubprocess()) { - createPermanentBailoutNode().getCallTarget().call(); - } - } - @Test public void testDefault() throws Exception { BiConsumer verifier = (log, output) -> { @@ -126,6 +114,21 @@ public void testPermanentBailoutThrow() throws Exception { executeInSubProcess(verifier, "engine.CompilationFailureAction", "Throw"); } + @Test + public void testPermanentBailoutThrowWithGraalExitVM() throws Exception { + BiConsumer verifier = (log, output) -> { + Assert.assertFalse(formatMessage("Unexpected bailout.", log, output), hasBailout(log)); + Assert.assertFalse(formatMessage("Unexpected exit.", log, output), hasExit(log)); + Assert.assertTrue(formatMessage("Expected OptimizationFailedException.", log, output), hasOptFailedException(log)); + }; + executeInSubProcess(verifier, ExceptionActionTest::createPermanentBailoutNode, + new String[]{ + "-Djdk.graal.CompilationFailureAction=ExitVM", + "-Djdk.graal.CompilationBailoutAsFailure=true", + }, + "engine.CompilationFailureAction", "Throw"); + } + @Test public void testNonPermanentBailout() throws Exception { BiConsumer verifier = (log, output) -> { @@ -164,7 +167,7 @@ private void executeInSubProcess(BiConsumer verifier, Supplier { setupContext(contextOptions); OptimizedCallTarget target = (OptimizedCallTarget) rootNodeFactory.get().getCallTarget(); diff --git a/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/truffle/test/GraalTruffleRuntimeListenerTest.java b/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/truffle/test/GraalTruffleRuntimeListenerTest.java index 52e5e8df53e4..d9ab42612aab 100644 --- a/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/truffle/test/GraalTruffleRuntimeListenerTest.java +++ b/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/truffle/test/GraalTruffleRuntimeListenerTest.java @@ -205,49 +205,51 @@ public void testBlockCompilationLargeBlocks() { } @Test - public void testBlockCompilationMaximumGraalGraphSize() { - int blockSize = 100; - int nodeCount = 1000; - setupContext("engine.CompileImmediately", "true", - "engine.BackgroundCompilation", "false", - "engine.PartialBlockCompilationSize", String.valueOf(blockSize), - "compiler.MaximumGraalGraphSize", "20000"); - OptimizedTruffleRuntime runtime = OptimizedTruffleRuntime.getRuntime(); - AbstractTestNode[] children = new AbstractTestNode[nodeCount]; - for (int i = 0; i < children.length; i++) { - children[i] = new ExpensiveTestNode(); - } - BlockNode block = BlockNode.create(children, new NodeExecutor()); - OptimizedCallTarget compilable = (OptimizedCallTarget) new TestRootNode(block).getCallTarget(); - TestListener listener = new TestListener(compilable); - try { - runtime.addListener(listener); - compilable.compile(!compilable.engine.multiTier); - List expectedEvents = new ArrayList<>(); - // Main CallTarget - expectedEvents.add(EventType.ENQUEUED); - expectedEvents.add(EventType.COMPILATION_STARTED); - expectedEvents.add(EventType.COMPILATION_FAILURE); - expectedEvents.add(EventType.DEQUEUED); - // Main CallTarget enqueued for re-compilation - expectedEvents.add(EventType.ENQUEUED); - // New partial blocks CallTargets - for (int i = 0; i < nodeCount / blockSize; i++) { + public void testBlockCompilationMaximumGraalGraphSize() throws Exception { + executeInSubprocess(() -> { + int blockSize = 100; + int nodeCount = 1000; + setupContext("engine.CompileImmediately", "true", + "engine.BackgroundCompilation", "false", + "engine.PartialBlockCompilationSize", String.valueOf(blockSize), + "compiler.MaximumGraalGraphSize", "20000"); + OptimizedTruffleRuntime runtime = OptimizedTruffleRuntime.getRuntime(); + AbstractTestNode[] children = new AbstractTestNode[nodeCount]; + for (int i = 0; i < children.length; i++) { + children[i] = new ExpensiveTestNode(); + } + BlockNode block = BlockNode.create(children, new NodeExecutor()); + OptimizedCallTarget compilable = (OptimizedCallTarget) new TestRootNode(block).getCallTarget(); + TestListener listener = new TestListener(compilable); + try { + runtime.addListener(listener); + compilable.compile(!compilable.engine.multiTier); + List expectedEvents = new ArrayList<>(); + // Main CallTarget expectedEvents.add(EventType.ENQUEUED); expectedEvents.add(EventType.COMPILATION_STARTED); + expectedEvents.add(EventType.COMPILATION_FAILURE); + expectedEvents.add(EventType.DEQUEUED); + // Main CallTarget enqueued for re-compilation + expectedEvents.add(EventType.ENQUEUED); + // New partial blocks CallTargets + for (int i = 0; i < nodeCount / blockSize; i++) { + expectedEvents.add(EventType.ENQUEUED); + expectedEvents.add(EventType.COMPILATION_STARTED); + expectedEvents.add(EventType.TRUFFLE_TIER_FINISHED); + expectedEvents.add(EventType.GRAAL_TIER_FINISHED); + expectedEvents.add(EventType.COMPILATION_SUCCESS); + } + // Main CallTarget re-compilation + expectedEvents.add(EventType.COMPILATION_STARTED); expectedEvents.add(EventType.TRUFFLE_TIER_FINISHED); expectedEvents.add(EventType.GRAAL_TIER_FINISHED); expectedEvents.add(EventType.COMPILATION_SUCCESS); + listener.assertEvents(expectedEvents.toArray(new EventType[expectedEvents.size()])); + } finally { + runtime.removeListener(listener); } - // Main CallTarget re-compilation - expectedEvents.add(EventType.COMPILATION_STARTED); - expectedEvents.add(EventType.TRUFFLE_TIER_FINISHED); - expectedEvents.add(EventType.GRAAL_TIER_FINISHED); - expectedEvents.add(EventType.COMPILATION_SUCCESS); - listener.assertEvents(expectedEvents.toArray(new EventType[expectedEvents.size()])); - } finally { - runtime.removeListener(listener); - } + }); } private static RootNode createFailureNode() { diff --git a/truffle/mx.truffle/mx_truffle.py b/truffle/mx.truffle/mx_truffle.py index 5348780ca458..b052a127dde0 100644 --- a/truffle/mx.truffle/mx_truffle.py +++ b/truffle/mx.truffle/mx_truffle.py @@ -824,6 +824,7 @@ def tck(args): "-Dpolyglot.engine.AllowExperimentalOptions=true", "-Dpolyglot.engine.Mode=latency", # "-Dpolyglot.engine.CompilationFailureAction=Throw", GR-49399 + "-Djdk.graal.CompilationFailureAction=ExitVM", "-Dpolyglot.engine.CompileImmediately=true", "-Dpolyglot.engine.BackgroundCompilation=false", "-Dtck.inlineVerifierInstrument=false", diff --git a/truffle/src/com.oracle.truffle.runtime/src/com/oracle/truffle/runtime/EngineData.java b/truffle/src/com.oracle.truffle.runtime/src/com/oracle/truffle/runtime/EngineData.java index 71bc2f81bc4a..bacdcc57a3a1 100644 --- a/truffle/src/com.oracle.truffle.runtime/src/com/oracle/truffle/runtime/EngineData.java +++ b/truffle/src/com.oracle.truffle.runtime/src/com/oracle/truffle/runtime/EngineData.java @@ -326,6 +326,8 @@ private void updateCompilerOptions(Map options) { options.put("compiler.DiagnoseFailure", "true"); } else if (compilationFailureAction == ExceptionAction.Diagnose) { options.put("compiler.DiagnoseFailure", "true"); + } else if (compilationFailureAction == ExceptionAction.Throw) { + options.put("compiler.DiagnoseFailure", "true"); } if (TruffleOptions.AOT && traceTransferToInterpreter) { options.put("compiler.NodeSourcePositions", "true"); diff --git a/vm/mx.vm/mx_vm_gate.py b/vm/mx.vm/mx_vm_gate.py index e6a8d0a1f2b0..98844a058905 100644 --- a/vm/mx.vm/mx_vm_gate.py +++ b/vm/mx.vm/mx_vm_gate.py @@ -490,6 +490,7 @@ def is_truffle_fallback(arg): "-Dpolyglot.engine.CompileImmediately=true", "-Dpolyglot.engine.BackgroundCompilation=false", "-Dpolyglot.engine.CompilationFailureAction=Throw", + "-Djdk.graal.CompilationFailureAction=ExitVM", "-Dgraalvm.locatorDisabled=true", "truffle", "LibGraalCompilerTest"]) From 0369fb87ae0033e315840c2aaa4cf9ecee4e2177 Mon Sep 17 00:00:00 2001 From: Josef Eisl Date: Tue, 9 Jan 2024 12:19:36 +0100 Subject: [PATCH 398/593] ci: use galahad overlay file --- ci-branch-config.jsonnet | 6 +++--- common.json | 2 +- graal-common.json | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/ci-branch-config.jsonnet b/ci-branch-config.jsonnet index c95f04314c1d..30f626e7d1dd 100644 --- a/ci-branch-config.jsonnet +++ b/ci-branch-config.jsonnet @@ -1,14 +1,14 @@ { "galahad.*": { "config_file": "galahad.jsonnet", - "overlay_file": null + "overlay_file": "galahad-graal.jsonnet", }, "release/galahad/.*": { "config_file": "galahad.jsonnet", - "overlay_file": null + "overlay_file": "galahad-graal.jsonnet", }, "cpu/galahad/.*": { "config_file": "galahad.jsonnet", - "overlay_file": null + "overlay_file": "galahad-graal.jsonnet", }, } diff --git a/common.json b/common.json index 3de3235179e8..fc82bbd6b031 100644 --- a/common.json +++ b/common.json @@ -8,7 +8,7 @@ "COMMENT.jdks": "When adding or removing JDKs keep in sync with JDKs in ci/common.jsonnet", "jdks": { - "galahad-jdk": {"name": "jpg-jdk", "version": "22", "build_id": "jdk-22+25", "platformspecific": true, "extrabundles": ["static-libs"]}, + "galahad-jdk": {"name": "jpg-jdk", "version": "23", "build_id": "jdk-23+4", "platformspecific": true, "extrabundles": ["static-libs"]}, "oraclejdk11": {"name": "jpg-jdk", "version": "11.0.11", "build_id": "9", "release": true, "platformspecific": true, "extrabundles": ["static-libs"] }, diff --git a/graal-common.json b/graal-common.json index 4a13a395c72c..cafe1f9650fb 100644 --- a/graal-common.json +++ b/graal-common.json @@ -1,6 +1,6 @@ { "README": "This file contains definitions that are useful for the jsonnet CI files of the graal and graal-enterprise repositories.", "ci": { - "overlay": "2dd50c6b85991f42f6e20f05bf33da84b1e1610c" + "overlay": "a3a0f1c506dc9974814a49de1cd24504c25c56f3" } } From fc91d239bb31ec27aec4b715d106b5e945699527 Mon Sep 17 00:00:00 2001 From: Christian Haeubl Date: Tue, 2 Jan 2024 18:02:52 +0100 Subject: [PATCH 399/593] Cleanups. --- .../svm/core/genscavenge/SerialGCOptions.java | 3 - .../genscavenge/graal/BarrierSnippets.java | 85 +++---------------- .../src/com/oracle/svm/core/heap/Heap.java | 6 -- .../SubstrateGraphBuilderPlugins.java | 2 +- 4 files changed, 13 insertions(+), 83 deletions(-) diff --git a/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/SerialGCOptions.java b/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/SerialGCOptions.java index d40da9693bb7..1301903073e8 100644 --- a/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/SerialGCOptions.java +++ b/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/SerialGCOptions.java @@ -80,9 +80,6 @@ public Integer getValue(OptionValues values) { @Option(help = "Print the time for each of the phases of each collection, if +VerboseGC. Serial GC only.", type = OptionType.Debug)// public static final RuntimeOptionKey PrintGCTimes = new RuntimeOptionKey<>(false, SerialGCOptions::serialGCOnly); - @Option(help = "Instrument write barriers with counters. Serial GC only.", type = OptionType.Debug)// - public static final HostedOptionKey CountWriteBarriers = new HostedOptionKey<>(false, SerialGCOptions::serialGCOnly); - @Option(help = "Verify the heap before doing a garbage collection if VerifyHeap is enabled. Serial GC only.", type = OptionType.Debug)// public static final HostedOptionKey VerifyBeforeGC = new HostedOptionKey<>(true, SerialGCOptions::serialGCOnly); diff --git a/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/graal/BarrierSnippets.java b/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/graal/BarrierSnippets.java index 8541c58bdfb2..e00d43cb8f42 100644 --- a/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/graal/BarrierSnippets.java +++ b/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/graal/BarrierSnippets.java @@ -24,11 +24,19 @@ */ package com.oracle.svm.core.genscavenge.graal; -import java.util.Collections; -import java.util.List; import java.util.Map; -import jdk.graal.compiler.api.replacements.Fold; +import org.graalvm.word.LocationIdentity; +import org.graalvm.word.UnsignedWord; + +import com.oracle.svm.core.genscavenge.ObjectHeaderImpl; +import com.oracle.svm.core.genscavenge.SerialGCOptions; +import com.oracle.svm.core.genscavenge.remset.RememberedSet; +import com.oracle.svm.core.graal.snippets.NodeLoweringProvider; +import com.oracle.svm.core.graal.snippets.SubstrateTemplates; +import com.oracle.svm.core.heap.ObjectHeader; +import com.oracle.svm.core.heap.StoredContinuation; + import jdk.graal.compiler.api.replacements.Snippet; import jdk.graal.compiler.api.replacements.Snippet.ConstantParameter; import jdk.graal.compiler.graph.Node; @@ -48,24 +56,6 @@ import jdk.graal.compiler.replacements.SnippetTemplate.Arguments; import jdk.graal.compiler.replacements.SnippetTemplate.SnippetInfo; import jdk.graal.compiler.replacements.Snippets; -import org.graalvm.nativeimage.ImageSingletons; -import org.graalvm.nativeimage.hosted.Feature; -import org.graalvm.word.LocationIdentity; -import org.graalvm.word.UnsignedWord; - -import com.oracle.svm.core.SubstrateOptions; -import com.oracle.svm.core.feature.AutomaticallyRegisteredFeature; -import com.oracle.svm.core.feature.InternalFeature; -import com.oracle.svm.core.genscavenge.ObjectHeaderImpl; -import com.oracle.svm.core.genscavenge.SerialGCOptions; -import com.oracle.svm.core.genscavenge.remset.RememberedSet; -import com.oracle.svm.core.graal.snippets.NodeLoweringProvider; -import com.oracle.svm.core.graal.snippets.SubstrateTemplates; -import com.oracle.svm.core.heap.ObjectHeader; -import com.oracle.svm.core.heap.StoredContinuation; -import com.oracle.svm.core.util.Counter; -import com.oracle.svm.core.util.CounterFeature; - import jdk.vm.ci.meta.MetaAccessProvider; import jdk.vm.ci.meta.ResolvedJavaType; @@ -73,11 +63,6 @@ public class BarrierSnippets extends SubstrateTemplates implements Snippets { /** A LocationIdentity to distinguish card locations from other locations. */ public static final LocationIdentity CARD_REMEMBERED_SET_LOCATION = NamedLocationIdentity.mutable("CardRememberedSet"); - @Fold - static BarrierSnippetCounters counters() { - return ImageSingletons.lookup(BarrierSnippetCounters.class); - } - private final SnippetInfo postWriteBarrierSnippet; BarrierSnippets(OptionValues options, Providers providers) { @@ -95,8 +80,6 @@ public void registerLowerings(MetaAccessProvider metaAccess, Map> getRequiredFeatures() { - return Collections.singletonList(CounterFeature.class); - } - - @Override - public void afterRegistration(AfterRegistrationAccess access) { - ImageSingletons.add(BarrierSnippetCounters.class, new BarrierSnippetCounters()); - } } diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/heap/Heap.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/heap/Heap.java index f62a7f622371..0ff251b63ab4 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/heap/Heap.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/heap/Heap.java @@ -121,12 +121,6 @@ public void visitLoadedClasses(Consumer> visitor) { /** * Get the ObjectHeader implementation that this Heap uses. - * - * TODO: This is used during native image generation to put appropriate headers on Objects in - * the native image heap. Is there any reason to expose the whole ObjectHeader interface, since - * only setBootImageOnLong(0L) is used then, to get the native image object header bits? - * - * TODO: Would an "Unsigned getBootImageObjectHeaderBits()" method be sufficient? */ @Uninterruptible(reason = "Called from uninterruptible code.", mayBeInlined = true) public abstract ObjectHeader getObjectHeader(); diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/snippets/SubstrateGraphBuilderPlugins.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/snippets/SubstrateGraphBuilderPlugins.java index ce8d1b897abf..707e884ea199 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/snippets/SubstrateGraphBuilderPlugins.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/snippets/SubstrateGraphBuilderPlugins.java @@ -1037,7 +1037,7 @@ public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Rec private static void checkNeverInline(GraphBuilderContext b) { if (!AnnotationAccess.isAnnotationPresent(b.getMethod(), NeverInline.class)) { throw VMError.shouldNotReachHere("Accessing the stack pointer or instruction pointer of the caller frame is only safe and deterministic if the method is not inlined. " + - "Therefore, the method " + b.getMethod().format("%H.%n(%p)") + " must be annoated with @" + NeverInline.class.getSimpleName()); + "Therefore, the method " + b.getMethod().format("%H.%n(%p)") + " must be annotated with @" + NeverInline.class.getSimpleName()); } } From 6f06817882f854a41c93b276e197fc3e5a1649ed Mon Sep 17 00:00:00 2001 From: Tomas Zezula Date: Mon, 8 Jan 2024 12:39:43 +0100 Subject: [PATCH 400/593] [GR-49589] False Truffle TCK negative for DebugJSAgent.terminate. --- .../svm/truffle/tck/PermissionsFeature.java | 4 ++- .../tests/language/TCKSmokeTestLanguage.java | 26 +++++++++++++++---- vm/mx.vm/mx_vm_gate.py | 14 +++++----- 3 files changed, 32 insertions(+), 12 deletions(-) diff --git a/substratevm/src/com.oracle.svm.truffle.tck/src/com/oracle/svm/truffle/tck/PermissionsFeature.java b/substratevm/src/com.oracle.svm.truffle.tck/src/com/oracle/svm/truffle/tck/PermissionsFeature.java index 5f6750329264..5479c7a25471 100644 --- a/substratevm/src/com.oracle.svm.truffle.tck/src/com/oracle/svm/truffle/tck/PermissionsFeature.java +++ b/substratevm/src/com.oracle.svm.truffle.tck/src/com/oracle/svm/truffle/tck/PermissionsFeature.java @@ -665,14 +665,16 @@ public boolean test(BaseMethodNode methodNode, BaseMethodNode callerNode, List { + })), new UnsafeCallNode()); return root.getCallTarget(); } @@ -106,10 +107,17 @@ private abstract static class BaseNode extends Node { private static final class PrivilegedCallNode extends BaseNode { + private final Thread otherThread; + + PrivilegedCallNode(Thread thread) { + this.otherThread = thread; + } + @Override void execute(VirtualFrame frame) { doPrivilegedCall(); - doPrivilegedCallBehindBoundary(); + doBehindBoundaryPrivilegedCall(); + doInterrupt(); } @SuppressWarnings("deprecation" /* JEP-411 */) @@ -118,9 +126,17 @@ static void doPrivilegedCall() { } @TruffleBoundary - static void doPrivilegedCallBehindBoundary() { + static void doBehindBoundaryPrivilegedCall() { Thread.currentThread().setName("Thread-2"); } + + @TruffleBoundary + void doInterrupt() { + if (this.otherThread != null) { + this.otherThread.interrupt(); + } + Thread.currentThread().interrupt(); + } } private static final class UnsafeCallNode extends BaseNode { @@ -146,7 +162,7 @@ private static long getFieldOffset(Field filed) { @Override void execute(VirtualFrame frame) { doUnsafeAccess(); - doUnsafeAccessBehindBoundary(); + doBehindBoundaryUnsafeAccess(); } static void doUnsafeAccess() { @@ -156,7 +172,7 @@ static void doUnsafeAccess() { } @TruffleBoundary - static void doUnsafeAccessBehindBoundary() { + static void doBehindBoundaryUnsafeAccess() { int i = 23; int result = UNSAFE.getInt(i, VALUE_OFFSET); assert i == result; diff --git a/vm/mx.vm/mx_vm_gate.py b/vm/mx.vm/mx_vm_gate.py index e6a8d0a1f2b0..1873f63b13f3 100644 --- a/vm/mx.vm/mx_vm_gate.py +++ b/vm/mx.vm/mx_vm_gate.py @@ -720,12 +720,14 @@ def gate_svm_truffle_tck_smoke_test(tasks): mx.abort("Expected failure, log:\n" + result) if not 'UnsafeCallNode.doUnsafeAccess' in result: mx.abort("Missing UnsafeCallNode.doUnsafeAccess call in the log, log:\n" + result) - if not 'UnsafeCallNode.doUnsafeAccessBehindBoundary' in result: - mx.abort("Missing UnsafeCallNode.doUnsafeAccessBehindBoundary call in the log, log:\n" + result) - if not 'PrivilegedCallNode.doPrivilegedCall' in result: - mx.abort("Missing PrivilegedCallNode.doPrivilegedCall call in the log, log:\n" + result) - if not 'PrivilegedCallNode.doPrivilegedCallBehindBoundary' in result: - mx.abort("Missing PrivilegedCallNode.doPrivilegedCallBehindBoundary call in the log, log:\n" + result) + if not 'UnsafeCallNode.doBehindBoundaryUnsafeAccess' in result: + mx.abort("Missing UnsafeCallNode.doBehindBoundaryUnsafeAccess call in the log, log:\n" + result) + if not 'PrivilegedCallNode.execute' in result: + mx.abort("Missing PrivilegedCallNode.execute call in the log, log:\n" + result) + if not 'PrivilegedCallNode.doBehindBoundaryPrivilegedCall' in result: + mx.abort("Missing PrivilegedCallNode.doBehindBoundaryPrivilegedCall call in the log, log:\n" + result) + if not 'PrivilegedCallNode.doInterrupt' in result: + mx.abort("Missing PrivilegedCallNode.doInterrupt call in the log, log:\n" + result) def gate_svm_truffle_tck_js(tasks): From 87125b7419db4f4690a0f370c120538ed2dcd9f5 Mon Sep 17 00:00:00 2001 From: Tomas Zezula Date: Wed, 10 Jan 2024 09:44:32 +0100 Subject: [PATCH 401/593] Fixed wrong condition in ContextLookupCompilationTest. --- .../compiler/truffle/test/ContextLookupCompilationTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/truffle/test/ContextLookupCompilationTest.java b/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/truffle/test/ContextLookupCompilationTest.java index 4fd0031e4f68..40893f784d7f 100644 --- a/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/truffle/test/ContextLookupCompilationTest.java +++ b/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/truffle/test/ContextLookupCompilationTest.java @@ -430,7 +430,7 @@ private static int countMagicFieldReads(StructuredGraph graph, Field field) { LocationIdentity location = readNode.getLocationIdentity(); if (location instanceof FieldLocationIdentity) { ResolvedJavaField locationField = ((FieldLocationIdentity) location).getField(); - if (locationField.getName().equals(locationField.getName()) && locationField.getDeclaringClass().toJavaName().equals(field.getDeclaringClass().getName())) { + if (locationField.getName().equals(field.getName()) && locationField.getDeclaringClass().toJavaName().equals(field.getDeclaringClass().getName())) { count++; } } From 200b5443f5ceb0ae8e51a34186d374d34f4868ce Mon Sep 17 00:00:00 2001 From: Tomas Zezula Date: Thu, 4 Jan 2024 14:02:29 +0100 Subject: [PATCH 402/593] [GR-51162] Update TCK.md to use maven to run the TCK test. --- truffle/docs/TCK.md | 102 +++++++++++++----- .../external_repos/simplelanguage/tck/pom.xml | 21 ---- 2 files changed, 74 insertions(+), 49 deletions(-) diff --git a/truffle/docs/TCK.md b/truffle/docs/TCK.md index 84402fd0eef4..c2371eab9129 100644 --- a/truffle/docs/TCK.md +++ b/truffle/docs/TCK.md @@ -61,32 +61,78 @@ You can also disable output and error output for all tests but one: `mx tck -Dtck.verbose=false -Dtck.ErrorTypeTest.verbose=true` -## Running TCK Tests without `mx` - -The Python [TCK runner](https://github.com/oracle/graal/blob/master/truffle/mx.truffle/tck.py) can be used to execute the Truffle TCK on top of GraalVM. The script requires Maven for downloading the TCK artifacts. - -To execute TCK tests on GraalVM use: - -`python tck.py -g ` - -To include your own language and TCK provider use: - -`python tck.py -g -cp -lp ` - -To restrict tests to a certain language, use the language ID as a first unnamed option. -The following example executes tests only for the JavaScript language: - -`python tck.py -g js` - -To execute the tests under debugger use the `-d` or `--dbg ` option: - -`python tck.py -d -g ` - -The TCK tests can be filtered by test names. To execute just the `ScriptTest` for the JavaScript TCK provider use: - -`python tck.py -g js default ScriptTest` - -The TCK tests can be executed in `compile` mode in which all calltargets are compiled before they are executed. -To execute JavaScript tests in `compile` mode use: +## Running TCK Tests with Apache Maven +The Apache Maven can be used to execute Truffle TCK tests. First, create a Maven module (project) containing the language +TCK provider. Ensure that this module has a test dependency on the language being tested and TCK tests `org.graalvm.truffle:truffle-tck-tests`. +Configure the `maven-surefire-plugin` to identify tests in the `org.graalvm.truffle:truffle-tck-tests` artifact. +This can be achieved using the following snippet within the section of your project's pom.xml: +``` + + + [...] + + org.apache.maven.plugins + maven-surefire-plugin + 3.1.2 + + + org.graalvm.truffle:truffle-tck-tests + + + + [...] + + +``` +To include additional languages in the TCK execution add their TCK providers as test dependencies. For example, adding `org.graalvm.js:js-truffle-tck` will include JavaScript in the testing process. +You can utilize the SimpleLanguage TCK provider [pom.xml](https://github.com/oracle/graal/blob/master/truffle/external_repos/simplelanguage/tck/pom.xml) as a template to get started. +To test the runtime optimizations set the `JAVA_HOME` environment variable to the GraalVM location before running `mvn package`. + +### Customize TCK Tests +To restrict the TCK tests to test a certain language, use the `tck.language` property. +The following example tests JavaScript with data types from all available languages. +``` + + + [...] + + org.apache.maven.plugins + maven-surefire-plugin + 3.1.2 + + + -Dtck.language=js + + [...] + + + [...] + + +``` -`python tck.py -g js compile` +To restrict the data types to a certain language, use the `tck.values` property. +The following example tests JavaScript with Java types. +``` + + + [...] + + org.apache.maven.plugins + maven-surefire-plugin + 3.1.2 + + + -Dtck.values=java-host + -Dtck.language=js + + [...] + + + [...] + + +``` + +To execute a specific TCK test you can use the test parameter along with the `-Dtest` option. +For example: `mvn test -Dtest=ScriptTest` diff --git a/truffle/external_repos/simplelanguage/tck/pom.xml b/truffle/external_repos/simplelanguage/tck/pom.xml index d8f0aa3f65b5..4b7f3061a74d 100644 --- a/truffle/external_repos/simplelanguage/tck/pom.xml +++ b/truffle/external_repos/simplelanguage/tck/pom.xml @@ -65,17 +65,9 @@ maven-surefire-plugin 3.1.2 - - -Dtck.values=java-host,sl - -Dtck.language=sl - org.graalvm.truffle:truffle-tck-tests - - **/*TestSuite.java - **/*Test.java - @@ -91,7 +83,6 @@ - simplelanguage @@ -111,23 +102,11 @@ ${graalvm.version} test - - org.graalvm.truffle - truffle-tck-common - ${graalvm.version} - test - junit junit 4.13.2 test - - org.graalvm.truffle - truffle-tck-instrumentation - ${graalvm.version} - test - From 2e75a4cb351c4a61011033225600c26ebf92de5c Mon Sep 17 00:00:00 2001 From: Olya Gupalo Date: Thu, 4 Jan 2024 14:15:06 +0100 Subject: [PATCH 403/593] Improve Native Image PGO guide --- docs/reference-manual/native-image/JNI.md | 4 ++-- .../optimize-native-executable-with-pgo.md | 23 +++++++++++-------- 2 files changed, 15 insertions(+), 12 deletions(-) diff --git a/docs/reference-manual/native-image/JNI.md b/docs/reference-manual/native-image/JNI.md index 542f3e10af68..8e69eff25941 100644 --- a/docs/reference-manual/native-image/JNI.md +++ b/docs/reference-manual/native-image/JNI.md @@ -33,7 +33,7 @@ The Native Image JNI implementation supports both approaches. ## Loading Native Libraries -When loading native libraries using `System.loadLibrary()` (and related APIs), the native image will search the directory containing the native library before searching the Java library path. +When loading native libraries using `System.loadLibrary()` (and related APIs), the native image will search the directory containing the native image before searching the Java library path. So as long as the native libraries to be loaded are in the same directory as the native image, no other settings should be necessary. ## Reflection Metadata @@ -54,7 +54,7 @@ The `native-image` builder generates JNI reflection metadata for all classes, me More than one JNI configuration can be used by specifying multiple paths for `JNIConfigurationFiles` and separating them with `,`. Also, `-H:JNIConfigurationResources` can be specified to load one or several configuration files from the image build's class path, such as from a JAR file. -The JNI configuration can be collected automatically using the [Tracing Agent](AutomaticMetadataCollection.md), provided with GraalVM. +The JNI configuration can be collected automatically using the [Tracing Agent](AutomaticMetadataCollection.md) from the GraalVM JDK. The agent tracks all usages of dynamic features during application execution on a regular Java VM. When the application completes and the JVM exits, the agent writes configuration to JSON files in the specified output directory. If you move the generated configuration files from that output directory to _META-INF/native-image/_ on the class path, they are then automatically used at build time. diff --git a/docs/reference-manual/native-image/guides/optimize-native-executable-with-pgo.md b/docs/reference-manual/native-image/guides/optimize-native-executable-with-pgo.md index 506930c7885f..07c839617f69 100644 --- a/docs/reference-manual/native-image/guides/optimize-native-executable-with-pgo.md +++ b/docs/reference-manual/native-image/guides/optimize-native-executable-with-pgo.md @@ -11,11 +11,18 @@ redirect_from: /reference-manual/native-image/PGO/ GraalVM Native Image offers quick startup and less memory consumption for a Java application, running as a native executable, by default. You can optimize this native executable even more for additional performance gain and higher throughput by applying Profile-Guided Optimizations (PGO). -With PGO you can collect the profiling data in advance and then feed it to the `native-image` tool, which will use this information to optimize the performance of the resulting binary. +With PGO you can collect the profiling data in advance, and then feed it to the `native-image` tool, which will use this information to optimize the performance of a native application. +The general workflow is: +1. Build an instrumented native executable by passing the `--pgo-instrument` option to `native-image`. +2. Run the instrumented executable to generate a profile file. By default, the _default.iprof_ file is generated in the current working directory and on application shutdown. +3. Build an optimized executable. The profile file with the default name and location will be picked up automatically. Alternatively, you can pass it to the `native-image` builder by specifying the file path: `--pgo=myprofile.iprof`. -> Note: PGO is not available in GraalVM Community Edition. +You can specify where to collect the profiles when running an instrumented native executable by passing the `-XX:ProfilesDumpFile=YourFileName` option at run time. +You can also collect multiple profile files by specifying different filenames, and pass them to `native-image` at build time. + +Note that executing all relevant application code paths and giving the application enough time to collect profiles are essential for having complete profiling information and therefore the best performance. -This guide shows how to apply PGO and transform your Java application into an optimized native executable. +> Note: PGO is not available in GraalVM Community Edition. ### Run a Demo @@ -152,7 +159,6 @@ Follow these steps to build an optimized native executable using PGO. ./streams 100000 200 ``` This version of the program is expected to run slower than on GraalVM's or any regular JDK. - 4. Build an instrumented native executable by passing the `--pgo-instrument` option to `native-image`: @@ -168,16 +174,13 @@ Follow these steps to build an optimized native executable using PGO. Notice that you can profile with a much smaller data size. Profiles collected from this run are stored by default in the _default.iprof_ file. - > Note: You can specify where to collect the profiles when running an instrumented native executable by passing the `-XX:ProfilesDumpFile=YourFileName` option at run time. - -6. Finally, build an optimized native executable by specifying the path to the collected profiles: +6. Finally, build an optimized native executable. The profile file has the default name and location, so it will be picked up automatically: ```shell - $JAVA_HOME/bin/native-image --pgo=default.iprof Streams + $JAVA_HOME/bin/native-image --pgo Streams ``` - > Note: You can also collect multiple profile files, by specifying different filenames, and pass them to the `native-image` tool at build time. - Run this optimized native executable timing the execution to see the system resources and CPU usage: +7. Run this optimized native executable timing the execution to see the system resources and CPU usage: ``` time ./streams 100000 200 ``` From ad3e12e7495ef5b85bcd06ddf85761a4a27e8516 Mon Sep 17 00:00:00 2001 From: David Leopoldseder Date: Mon, 18 Sep 2023 11:20:36 +0200 Subject: [PATCH 404/593] GR-48643: verify phases do not use direct recursion and exclude list some that are exceptions. --- .../src/jdk/graal/compiler/core/test/CheckGraalInvariants.java | 1 + .../compiler/loop/phases/ConvertDeoptimizeToGuardPhase.java | 2 +- .../src/jdk/graal/compiler/phases/common/FloatingReadPhase.java | 2 +- 3 files changed, 3 insertions(+), 2 deletions(-) diff --git a/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/core/test/CheckGraalInvariants.java b/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/core/test/CheckGraalInvariants.java index e3607af87e7d..6e14b37dcb26 100644 --- a/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/core/test/CheckGraalInvariants.java +++ b/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/core/test/CheckGraalInvariants.java @@ -344,6 +344,7 @@ public static void runTest(InvariantsTool tool) { verifiers.add(new VerifyPluginFrameState()); verifiers.add(new VerifyGraphUniqueUsages()); verifiers.add(new VerifyEndlessLoops()); + verifiers.add(new VerifyPhaseNoDirectRecursion()); VerifyAssertionUsage assertionUsages = null; boolean checkAssertions = tool.checkAssertions(); diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/loop/phases/ConvertDeoptimizeToGuardPhase.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/loop/phases/ConvertDeoptimizeToGuardPhase.java index b1e81f4a4fc2..7c80d80f15c3 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/loop/phases/ConvertDeoptimizeToGuardPhase.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/loop/phases/ConvertDeoptimizeToGuardPhase.java @@ -89,7 +89,7 @@ * branch starting at an other kind of {@link ControlSplitNode}, it will only bring the * {@link DeoptimizeNode} as close to the {@link ControlSplitNode} as possible. */ -public class ConvertDeoptimizeToGuardPhase extends PostRunCanonicalizationPhase { +public class ConvertDeoptimizeToGuardPhase extends PostRunCanonicalizationPhase implements RecursivePhase { public ConvertDeoptimizeToGuardPhase(CanonicalizerPhase canonicalizer) { super(canonicalizer); diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/phases/common/FloatingReadPhase.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/phases/common/FloatingReadPhase.java index 710366c9f415..98c45d323269 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/phases/common/FloatingReadPhase.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/phases/common/FloatingReadPhase.java @@ -82,7 +82,7 @@ import jdk.graal.compiler.phases.common.util.EconomicSetNodeEventListener; import jdk.graal.compiler.phases.graph.ReentrantNodeIterator; -public class FloatingReadPhase extends PostRunCanonicalizationPhase { +public class FloatingReadPhase extends PostRunCanonicalizationPhase implements RecursivePhase { private final boolean createMemoryMapNodes; From 80b46da69e474e06155ae28f2da9cc290bc337cd Mon Sep 17 00:00:00 2001 From: David Leopoldseder Date: Mon, 18 Sep 2023 11:23:01 +0200 Subject: [PATCH 405/593] GR-48643: rewrite expand logic phase to use iteration --- .../phases/common/ExpandLogicPhase.java | 38 ++++++++++++------- 1 file changed, 25 insertions(+), 13 deletions(-) diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/phases/common/ExpandLogicPhase.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/phases/common/ExpandLogicPhase.java index 42ac44cca430..42393fccd415 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/phases/common/ExpandLogicPhase.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/phases/common/ExpandLogicPhase.java @@ -102,23 +102,35 @@ private static void processNormalizeCompareNode(AbstractNormalizeCompareNode nor normalize.replaceAtUsagesAndDelete(value); } + @SuppressWarnings("try") - private static void expandBinary(ShortCircuitOrNode binary) { - while (binary.usages().isNotEmpty()) { - Node usage = binary.usages().first(); - try (DebugCloseable nsp = usage.withNodeSourcePosition()) { - if (usage instanceof ShortCircuitOrNode) { - expandBinary((ShortCircuitOrNode) usage); - } else if (usage instanceof IfNode) { - processIf(binary.getX(), binary.isXNegated(), binary.getY(), binary.isYNegated(), (IfNode) usage, binary.getShortCircuitProbability().getDesignatedSuccessorProbability()); - } else if (usage instanceof ConditionalNode) { - processConditional(binary.getX(), binary.isXNegated(), binary.getY(), binary.isYNegated(), (ConditionalNode) usage); - } else { - throw GraalError.shouldNotReachHereUnexpectedValue(usage); // ExcludeFromJacocoGeneratedReport + private static void expandBinary(ShortCircuitOrNode s) { + NodeStack toProcess = new NodeStack(); + toProcess.push(s); + + outer: while (!toProcess.isEmpty()) { + ShortCircuitOrNode binary = (ShortCircuitOrNode) toProcess.pop(); + + while (binary.usages().isNotEmpty()) { + Node usage = binary.usages().first(); + try (DebugCloseable nsp = usage.withNodeSourcePosition()) { + if (usage instanceof ShortCircuitOrNode) { + toProcess.push(binary); + toProcess.push(usage); + continue outer; + } else if (usage instanceof IfNode) { + processIf(binary.getX(), binary.isXNegated(), binary.getY(), binary.isYNegated(), (IfNode) usage, binary.getShortCircuitProbability().getDesignatedSuccessorProbability()); + } else if (usage instanceof ConditionalNode) { + processConditional(binary.getX(), binary.isXNegated(), binary.getY(), binary.isYNegated(), (ConditionalNode) usage); + } else { + throw GraalError.shouldNotReachHereUnexpectedValue(usage); // ExcludeFromJacocoGeneratedReport + } } } + binary.safeDelete(); + } - binary.safeDelete(); + } private static void processIf(LogicNode x, boolean xNegated, LogicNode y, boolean yNegated, IfNode ifNode, double shortCircuitProbability) { From db721cd7b66738e32a87135687e7555d24e51b4b Mon Sep 17 00:00:00 2001 From: Christian Wimmer Date: Fri, 6 Oct 2023 10:20:08 -0700 Subject: [PATCH 406/593] Remove recursion in RemoveUnwindPhase --- .../core/graal/phases/RemoveUnwindPhase.java | 95 ++++++++++++------- 1 file changed, 61 insertions(+), 34 deletions(-) diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/graal/phases/RemoveUnwindPhase.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/graal/phases/RemoveUnwindPhase.java index 4d9ea0a60ca2..79841cede939 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/graal/phases/RemoveUnwindPhase.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/graal/phases/RemoveUnwindPhase.java @@ -70,7 +70,7 @@ protected void run(StructuredGraph graph) { List withExceptionNodes = new ArrayList<>(); List bytecodeExceptionNodes = new ArrayList<>(); for (UnwindNode node : graph.getNodes(UnwindNode.TYPE)) { - walkBack(node.predecessor(), node, withExceptionNodes, bytecodeExceptionNodes, GraphUtil.unproxify(node.exception()), graph); + walkBack(node.predecessor(), node, GraphUtil.unproxify(node.exception()), withExceptionNodes, bytecodeExceptionNodes); } /* @@ -91,47 +91,74 @@ protected void run(StructuredGraph graph) { } } + private record WorklistEntry(Node current, Node successor, ValueNode expectedException) { + } + /** * We walk back from the {@link UnwindNode} to a {@link WithExceptionNode}. If the control flow - * path only contains nodes white-listed in this method, then we know that we have a node that - * just forwards the exception to the {@link UnwindNode}. Such nodes are rewritten to a variant - * without an exception edge, i.e., no exception handler entry is created for such invokes. + * path only contains nodes explicitly allowed in this method, then we know that we have a node + * that just forwards the exception to the {@link UnwindNode}. Such nodes are rewritten to a + * variant without an exception edge, i.e., no exception handler entry is created for such + * invokes. */ - protected static void walkBack(Node n, Node successor, List withExceptionNodes, List bytecodeExceptionNodes, ValueNode expectedExceptionNode, - StructuredGraph graph) { - if (n instanceof WithExceptionNode) { - WithExceptionNode node = (WithExceptionNode) n; - if (node.exceptionEdge() == successor) { - withExceptionNodes.add(node); - } - } else if (n instanceof BytecodeExceptionNode || n instanceof ExceptionObjectNode) { - if (n == expectedExceptionNode) { - if (n instanceof BytecodeExceptionNode) { - BytecodeExceptionNode node = (BytecodeExceptionNode) n; + protected static void walkBack(Node initialNode, Node initialSuccessor, ValueNode initialExpectedException, + List withExceptionNodes, List bytecodeExceptionNodes) { + Node current = initialNode; + Node successor = initialSuccessor; + ValueNode expectedException = initialExpectedException; + + /* + * The worklist is used when a node has multiple predecessors. The inner loop walks back + * single-predecessor nodes to avoid allocating unnecessary worklist entries. + */ + List worklist = new ArrayList<>(); + while (true) { + while (true) { + if (current instanceof WithExceptionNode node) { + if (node.exceptionEdge() == successor) { + withExceptionNodes.add(node); + } + break; + + } else if (current == expectedException && current instanceof BytecodeExceptionNode node) { bytecodeExceptionNodes.add(node); + break; + + } else if (current == expectedException && current instanceof ExceptionObjectNode) { + successor = current; + current = current.predecessor(); + + } else if (current instanceof MergeNode merge) { + if (merge.isPhiAtMerge(expectedException)) { + /* Propagate expected exception on each control path leading to the merge */ + PhiNode expectedExceptionForInput = (PhiNode) expectedException; + for (int input = 0; input < merge.forwardEndCount(); input++) { + Node predecessor = merge.forwardEndAt(input); + worklist.add(new WorklistEntry(predecessor, merge, GraphUtil.unproxify(expectedExceptionForInput.valueAt(input)))); + } + } else { + for (ValueNode predecessor : merge.cfgPredecessors()) { + worklist.add(new WorklistEntry(predecessor, merge, expectedException)); + } + } + break; + + } else if (current instanceof AbstractBeginNode || current instanceof AbstractEndNode) { + successor = current; + current = current.predecessor(); + } else { - walkBack(n.predecessor(), n, withExceptionNodes, bytecodeExceptionNodes, expectedExceptionNode, graph); - } - } else { - graph.getDebug().log(DebugContext.VERY_DETAILED_LEVEL, "Node %s does not flow to the corresponding Unwind. Bailing out.", n); - } - } else if (n instanceof MergeNode) { - MergeNode merge = (MergeNode) n; - if (merge.isPhiAtMerge(expectedExceptionNode)) { - /* Propagate expected exception on each control path leading to the merge */ - PhiNode expectedExceptionForInput = (PhiNode) expectedExceptionNode; - for (int input = 0; input < merge.forwardEndCount(); input++) { - Node predecessor = merge.forwardEndAt(input); - walkBack(predecessor, merge, withExceptionNodes, bytecodeExceptionNodes, GraphUtil.unproxify(expectedExceptionForInput.valueAt(input)), graph); - } - } else { - for (ValueNode predecessor : merge.cfgPredecessors()) { - walkBack(predecessor, merge, withExceptionNodes, bytecodeExceptionNodes, expectedExceptionNode, graph); + break; } } - } else if (n instanceof AbstractBeginNode || n instanceof AbstractEndNode) { - walkBack(n.predecessor(), n, withExceptionNodes, bytecodeExceptionNodes, expectedExceptionNode, graph); + if (worklist.isEmpty()) { + break; + } + var entry = worklist.removeLast(); + current = entry.current; + successor = entry.successor; + expectedException = entry.expectedException; } } From 143f96f19728b3af066f8ad2642c072f9fe33438 Mon Sep 17 00:00:00 2001 From: David Leopoldseder Date: Fri, 24 Nov 2023 11:55:16 +0100 Subject: [PATCH 407/593] fixes after rebase --- .../core/test/CheckGraalInvariants.java | 2 +- .../test/VerifyPhaseNoDirectRecursion.java | 83 +++++++++++++++++++ .../phases/ConvertDeoptimizeToGuardPhase.java | 1 + .../graal/compiler/phases/RecursivePhase.java | 32 +++++++ .../phases/common/ExpandLogicPhase.java | 2 +- .../phases/common/FloatingReadPhase.java | 1 + 6 files changed, 119 insertions(+), 2 deletions(-) create mode 100644 compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/core/test/VerifyPhaseNoDirectRecursion.java create mode 100644 compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/phases/RecursivePhase.java diff --git a/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/core/test/CheckGraalInvariants.java b/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/core/test/CheckGraalInvariants.java index 6e14b37dcb26..bd9e96415e78 100644 --- a/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/core/test/CheckGraalInvariants.java +++ b/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/core/test/CheckGraalInvariants.java @@ -344,7 +344,7 @@ public static void runTest(InvariantsTool tool) { verifiers.add(new VerifyPluginFrameState()); verifiers.add(new VerifyGraphUniqueUsages()); verifiers.add(new VerifyEndlessLoops()); - verifiers.add(new VerifyPhaseNoDirectRecursion()); + verifiers.add(new VerifyPhaseNoDirectRecursion()); VerifyAssertionUsage assertionUsages = null; boolean checkAssertions = tool.checkAssertions(); diff --git a/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/core/test/VerifyPhaseNoDirectRecursion.java b/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/core/test/VerifyPhaseNoDirectRecursion.java new file mode 100644 index 000000000000..6d42528cd52a --- /dev/null +++ b/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/core/test/VerifyPhaseNoDirectRecursion.java @@ -0,0 +1,83 @@ +/* + * Copyright (c) 2023, 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 jdk.graal.compiler.core.test; + +import jdk.graal.compiler.nodes.StructuredGraph; +import jdk.graal.compiler.nodes.java.MethodCallTargetNode; +import jdk.graal.compiler.nodes.spi.CoreProviders; +import jdk.graal.compiler.phases.BasePhase; +import jdk.graal.compiler.phases.PhaseSuite; +import jdk.graal.compiler.phases.RecursivePhase; +import jdk.graal.compiler.phases.VerifyPhase; +import jdk.vm.ci.meta.ResolvedJavaMethod; +import jdk.vm.ci.meta.ResolvedJavaType; + +/** + * Verify that no subclass of {@link BasePhase} uses direct recursion in its implementation. Direct + * recursion can easily cause stack overflows, endless recursions, etc. The graal optimizer code + * base must use iteration instead. + */ +public class VerifyPhaseNoDirectRecursion extends VerifyPhase { + + @Override + public boolean checkContract() { + return false; + } + + @Override + protected void verify(StructuredGraph graph, CoreProviders context) { + final ResolvedJavaType basePhaseType = context.getMetaAccess().lookupJavaType(BasePhase.class); + final ResolvedJavaType phaseSuiteType = context.getMetaAccess().lookupJavaType(PhaseSuite.class); + final ResolvedJavaType recursivePhaseType = context.getMetaAccess().lookupJavaType(RecursivePhase.class); + final ResolvedJavaMethod graphMethod = graph.method(); + final ResolvedJavaType graphMethodType = graph.method().getDeclaringClass(); + + if (graphMethod.getDeclaringClass().getName().contains("truffle")) { + // We only enforce this code requirement for core compiler code and ignore truffle. + return; + } + if (!basePhaseType.isAssignableFrom(graphMethodType)) { + // Not a compiler phase. + return; + } + if (phaseSuiteType.equals(graphMethodType)) { + // PhaseSuite has some understood recursion. + return; + } + if (recursivePhaseType.isAssignableFrom(graphMethodType)) { + // Some exclude listed phases. + return; + } + for (MethodCallTargetNode m : graph.getNodes(MethodCallTargetNode.TYPE)) { + ResolvedJavaMethod callee = m.targetMethod(); + if (callee.equals(graphMethod)) { + throw new VerificationError( + "Call %s in %s is a self recursive call in a phase subclass. This is prohibited for performance and safety reasons. Replace with iteration. " + + "(Exceptions can be made for very stable well understood code, consider whitlisting in VerifyPhaseNoDirectRecursion.java).", + m.invoke(), m.invoke().asNode().getNodeSourcePosition()); + } + } + } +} diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/loop/phases/ConvertDeoptimizeToGuardPhase.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/loop/phases/ConvertDeoptimizeToGuardPhase.java index 7c80d80f15c3..875c9253f7fc 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/loop/phases/ConvertDeoptimizeToGuardPhase.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/loop/phases/ConvertDeoptimizeToGuardPhase.java @@ -71,6 +71,7 @@ import jdk.graal.compiler.nodes.spi.Simplifiable; import jdk.graal.compiler.nodes.spi.SimplifierTool; import jdk.graal.compiler.nodes.util.GraphUtil; +import jdk.graal.compiler.phases.RecursivePhase; import jdk.graal.compiler.phases.common.CanonicalizerPhase; import jdk.graal.compiler.phases.common.DeadCodeEliminationPhase; import jdk.graal.compiler.phases.common.LazyValue; diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/phases/RecursivePhase.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/phases/RecursivePhase.java new file mode 100644 index 000000000000..fe09e654c91e --- /dev/null +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/phases/RecursivePhase.java @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2022, 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 jdk.graal.compiler.phases; + +/** + * Marker interface for phases that use recursion during processing. + */ +public interface RecursivePhase { + +} diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/phases/common/ExpandLogicPhase.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/phases/common/ExpandLogicPhase.java index 42393fccd415..9ef2ff7bf831 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/phases/common/ExpandLogicPhase.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/phases/common/ExpandLogicPhase.java @@ -32,6 +32,7 @@ import jdk.graal.compiler.debug.GraalError; import jdk.graal.compiler.graph.Graph; import jdk.graal.compiler.graph.Node; +import jdk.graal.compiler.graph.NodeStack; import jdk.graal.compiler.nodes.AbstractBeginNode; import jdk.graal.compiler.nodes.AbstractMergeNode; import jdk.graal.compiler.nodes.BeginNode; @@ -102,7 +103,6 @@ private static void processNormalizeCompareNode(AbstractNormalizeCompareNode nor normalize.replaceAtUsagesAndDelete(value); } - @SuppressWarnings("try") private static void expandBinary(ShortCircuitOrNode s) { NodeStack toProcess = new NodeStack(); diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/phases/common/FloatingReadPhase.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/phases/common/FloatingReadPhase.java index 98c45d323269..588bdb7d3cc8 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/phases/common/FloatingReadPhase.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/phases/common/FloatingReadPhase.java @@ -79,6 +79,7 @@ import jdk.graal.compiler.nodes.memory.address.AddressNode; import jdk.graal.compiler.nodes.spi.CoreProviders; import jdk.graal.compiler.nodes.util.GraphUtil; +import jdk.graal.compiler.phases.RecursivePhase; import jdk.graal.compiler.phases.common.util.EconomicSetNodeEventListener; import jdk.graal.compiler.phases.graph.ReentrantNodeIterator; From 001a2d1258d7676b8e50a3e630d2d0b1c7d88ac4 Mon Sep 17 00:00:00 2001 From: David Leopoldseder Date: Wed, 3 Jan 2024 13:33:01 +0100 Subject: [PATCH 408/593] remove unwind phase: iterative version: properly break if we are going over an exception object where the exception is not feeding an unwind --- .../core/graal/phases/RemoveUnwindPhase.java | 22 ++++++++++++------- 1 file changed, 14 insertions(+), 8 deletions(-) diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/graal/phases/RemoveUnwindPhase.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/graal/phases/RemoveUnwindPhase.java index 79841cede939..9d9e92ff5dd4 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/graal/phases/RemoveUnwindPhase.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/graal/phases/RemoveUnwindPhase.java @@ -113,21 +113,27 @@ protected static void walkBack(Node initialNode, Node initialSuccessor, ValueNod */ List worklist = new ArrayList<>(); while (true) { - while (true) { + nodeWalk: while (true) { if (current instanceof WithExceptionNode node) { if (node.exceptionEdge() == successor) { withExceptionNodes.add(node); } break; - } else if (current == expectedException && current instanceof BytecodeExceptionNode node) { - bytecodeExceptionNodes.add(node); + } else if (current instanceof BytecodeExceptionNode || current instanceof ExceptionObjectNode) { + if (current == expectedException) { + if (current instanceof BytecodeExceptionNode) { + BytecodeExceptionNode node = (BytecodeExceptionNode) current; + bytecodeExceptionNodes.add(node); + } else { + successor = current; + current = current.predecessor(); + continue nodeWalk; + } + } + // bailout here, the node does not flow into the corresponding unwind, its a + // unrelated exception, but a different one than the unwind one break; - - } else if (current == expectedException && current instanceof ExceptionObjectNode) { - successor = current; - current = current.predecessor(); - } else if (current instanceof MergeNode merge) { if (merge.isPhiAtMerge(expectedException)) { /* Propagate expected exception on each control path leading to the merge */ From 54bc2ce5648341a3eef06575a36f472a90b8c09d Mon Sep 17 00:00:00 2001 From: David Leopoldseder Date: Tue, 9 Jan 2024 12:32:45 +0100 Subject: [PATCH 409/593] address review comments --- .../compiler/core/test/VerifyPhaseNoDirectRecursion.java | 6 ------ .../src/jdk/graal/compiler/phases/PhaseSuite.java | 2 +- .../src/jdk/graal/compiler/phases/RecursivePhase.java | 2 +- 3 files changed, 2 insertions(+), 8 deletions(-) diff --git a/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/core/test/VerifyPhaseNoDirectRecursion.java b/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/core/test/VerifyPhaseNoDirectRecursion.java index 6d42528cd52a..986ba14f4d08 100644 --- a/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/core/test/VerifyPhaseNoDirectRecursion.java +++ b/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/core/test/VerifyPhaseNoDirectRecursion.java @@ -28,7 +28,6 @@ import jdk.graal.compiler.nodes.java.MethodCallTargetNode; import jdk.graal.compiler.nodes.spi.CoreProviders; import jdk.graal.compiler.phases.BasePhase; -import jdk.graal.compiler.phases.PhaseSuite; import jdk.graal.compiler.phases.RecursivePhase; import jdk.graal.compiler.phases.VerifyPhase; import jdk.vm.ci.meta.ResolvedJavaMethod; @@ -49,7 +48,6 @@ public boolean checkContract() { @Override protected void verify(StructuredGraph graph, CoreProviders context) { final ResolvedJavaType basePhaseType = context.getMetaAccess().lookupJavaType(BasePhase.class); - final ResolvedJavaType phaseSuiteType = context.getMetaAccess().lookupJavaType(PhaseSuite.class); final ResolvedJavaType recursivePhaseType = context.getMetaAccess().lookupJavaType(RecursivePhase.class); final ResolvedJavaMethod graphMethod = graph.method(); final ResolvedJavaType graphMethodType = graph.method().getDeclaringClass(); @@ -62,10 +60,6 @@ protected void verify(StructuredGraph graph, CoreProviders context) { // Not a compiler phase. return; } - if (phaseSuiteType.equals(graphMethodType)) { - // PhaseSuite has some understood recursion. - return; - } if (recursivePhaseType.isAssignableFrom(graphMethodType)) { // Some exclude listed phases. return; diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/phases/PhaseSuite.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/phases/PhaseSuite.java index a82edd16ef60..87b90ef8f64e 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/phases/PhaseSuite.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/phases/PhaseSuite.java @@ -46,7 +46,7 @@ /** * A compiler phase that can apply an ordered collection of phases to a graph. */ -public class PhaseSuite extends BasePhase implements PhasePlan> { +public class PhaseSuite extends BasePhase implements PhasePlan>, RecursivePhase { public static class Options { @Option(help = "Prints the difference in the graph state caused by each phase of the suite.") // diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/phases/RecursivePhase.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/phases/RecursivePhase.java index fe09e654c91e..272042610ac5 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/phases/RecursivePhase.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/phases/RecursivePhase.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2024, 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 From cb0113a5dfc882b6f7d946d7aecebaead23871a2 Mon Sep 17 00:00:00 2001 From: Mike Hearn Date: Wed, 10 Jan 2024 14:26:16 +0100 Subject: [PATCH 410/593] Espresso: Address code review comments. --- espresso/README.md | 2 +- espresso/docs/how-espresso-works.md | 16 +++++++++------- 2 files changed, 10 insertions(+), 8 deletions(-) diff --git a/espresso/README.md b/espresso/README.md index 68799e19c7fd..b43fa54c0411 100644 --- a/espresso/README.md +++ b/espresso/README.md @@ -17,7 +17,7 @@ Why implement a JVM in Java? ## Status -Espresso is a fully supported implementation of the Java platform that ships in Oracle products and which is kept up to date with the latest Java versions. When the VM is compiled to a native image it runs on Windows, macOS and Linux. +Espresso is a complete Java implementation which is kept up to date with the latest LTS JDK versions. When the VM is compiled to a native image it runs on Windows, macOS and Linux. It features complete meta-circularity: it can run itself any amount of layers deep, preserving all the capabilities (Unsafe, JNI, Reflection...) of the base layer. Running HelloWorld on three nested layers of Espresso takes **~15 minutes**. diff --git a/espresso/docs/how-espresso-works.md b/espresso/docs/how-espresso-works.md index 59127195744a..5f7b061b67cf 100644 --- a/espresso/docs/how-espresso-works.md +++ b/espresso/docs/how-espresso-works.md @@ -14,7 +14,7 @@ stack. Instead Espresso provides runtime services like: * Debugging. * HotSwap (changing code whilst it's running). * JNI. -* A `java` launcher command. +* A development/debug java launcher command based on the polyglot API. * The "native" components of the standard library like `libjava` (in quotes because what native means can vary). [See below](#native-components). * Sandboxing. @@ -36,7 +36,7 @@ Espresso can be used in different configurations with differing tradeoffs. The **host VM** can be OpenJDK, GraalVM HotSpot or GraalVM Native Image. On OpenJDK Espresso will only execute in the interpreter and is thus slow. With a regular GraalVM it executes faster, because the Graal compiler will be used which knows how to accelerate Truffle languages, and with a Native Image host it is the fastest due to not needing the -Espresso VM itself to warm up. Additionally, virtual threads currently only work with a native image host. +Espresso VM itself to warm up. The **native components** that implement the JNI side of the standard library can be genuine operating system specific machine code, in which case the host OS must be Linux and Java code cannot be sandboxed, or LLVM bitcode @@ -134,11 +134,13 @@ You may notice that this class has only a lock word and a pointer to the class o actual data is stored. The answer depends on what host JVM is being used. On HotSpot the Truffle framework synthesizes bytecode to create and load subclasses of `StaticObject` with the right number of fields to store the guest data. This lets guest code use the host garbage collector. On SubstrateVM (native image) you can't dynamically load classes, so an -alternative is required. SubstrateVM exposes APIs that let you define new class layouts at runtime (called "pods") which -the garbage collector then becomes aware of. Behind the scenes field accesses may be carefully checked, or they may have -their checks compiled out. That's useful for Espresso where the bytecode is statically verified ahead of time, so it's -known to be safe at the time it executes. To learn more about how object storage works, read about the [Truffle Static -Object Model](https://www.graalvm.org/latest/graalvm-as-a-platform/language-implementation-framework/StaticObjectModel/). +alternative is required. There are two available: array based and "pod" based. The goal is to migrate to "pods", in +which Truffle communicates object layouts directly to the SubstrateVM runtime and GC, but as of January 2024 +the array based method is faster. + +Behind the scenes field accesses may be carefully checked, or they may have their checks compiled out. That's useful for +Espresso where the bytecode is statically verified ahead of time, so it's known to be safe at the time it executes. To +learn more about how object storage works, read about the [Truffle Static Object Model](https://www.graalvm.org/latest/graalvm-as-a-platform/language-implementation-framework/StaticObjectModel/). ### Reflecting guest heap objects From 85fdc5e56d17a242bb54e0bc10fdd238696b8405 Mon Sep 17 00:00:00 2001 From: Carlo Refice Date: Mon, 27 Nov 2023 15:23:10 +0100 Subject: [PATCH 411/593] Fix missing break statements in stackifier from out-of-order switch default case --- .../irwalk/StackifierIRWalker.java | 87 +++++++------------ 1 file changed, 30 insertions(+), 57 deletions(-) diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hightiercodegen/irwalk/StackifierIRWalker.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hightiercodegen/irwalk/StackifierIRWalker.java index 81f802f5161d..a6bb2fdf8f21 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hightiercodegen/irwalk/StackifierIRWalker.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hightiercodegen/irwalk/StackifierIRWalker.java @@ -633,40 +633,34 @@ protected void lowerSwitchDefaultCase(IntegerSwitchNode switchNode) { * @param switchNode node to be lowered */ protected void lowerSwitch(IntegerSwitchNode switchNode) { - codeGenTool.genSwitchHeader(switchNode.value()); - boolean hasdefault = switchNode.defaultSuccessor() != null; - SwitchScopeContainer switchScopeEntry = (SwitchScopeContainer) stackifierData.getScopeEntry(switchNode); Scope[] caseScopes = switchScopeEntry.getCaseScopes(); assert caseScopes != null; for (int i = 0; i < switchNode.blockSuccessorCount(); i++) { - // one successor AbstractBeginNode succ = switchNode.blockSuccessor(i); - // the default case must be lowered at the end - if (hasdefault) { - if (succ.equals(switchNode.defaultSuccessor())) { - continue; + if (succ.equals(switchNode.defaultSuccessor())) { + lowerSwitchDefaultCase(switchNode); + } else { + ArrayList succKeys = new ArrayList<>(); + // query all keys that have the succ as block succ + for (int keyIndex = 0; keyIndex < switchNode.keyCount(); keyIndex++) { + // the key + int key = switchNode.intKeyAt(keyIndex); + AbstractBeginNode keySucc = switchNode.keySuccessor(keyIndex); + if (succ.equals(keySucc)) { + succKeys.add(key); + } } - } - ArrayList succKeys = new ArrayList<>(); - // query all keys that have the succ as block succ - for (int keyIndex = 0; keyIndex < switchNode.keyCount(); keyIndex++) { - // the key - int key = switchNode.intKeyAt(keyIndex); - AbstractBeginNode keySucc = switchNode.keySuccessor(keyIndex); - if (succ.equals(keySucc)) { - succKeys.add(key); + assert succKeys.size() > 0 : "no keys of " + switchNode + " have " + succ + " as block successor"; + int[] succk = new int[succKeys.size()]; + for (int s = 0; s < succKeys.size(); s++) { + succk[s] = succKeys.get(s); } + lowerSwitchCase(switchNode, succ, succk); } - assert succKeys.size() > 0 : "no keys of " + switchNode + " have " + succ + " as block successor"; - int[] succk = new int[succKeys.size()]; - for (int s = 0; s < succKeys.size(); s++) { - succk[s] = succKeys.get(s); - } - lowerSwitchCase(switchNode, succ, succk); if (caseScopes[i] != null) { lowerBlocks(caseScopes[i].getSortedBlocks()); } else { @@ -675,17 +669,6 @@ protected void lowerSwitch(IntegerSwitchNode switchNode) { codeGenTool.genBlockEndBreak(); codeGenTool.genScopeEnd(); } - if (hasdefault) { - lowerSwitchDefaultCase(switchNode); - int defaultIndex = switchNode.defaultSuccessorIndex(); - if (caseScopes[defaultIndex] != null) { - lowerBlocks(caseScopes[defaultIndex].getSortedBlocks()); - } else { - generateForwardJump(cfg.blockFor(switchNode), cfg.blockFor(switchNode.defaultSuccessor())); - } - codeGenTool.genBlockEndBreak(); - codeGenTool.genScopeEnd(); - } codeGenTool.genScopeEnd(); } @@ -778,37 +761,27 @@ protected void lowerTypeSwitchDefaultCase(TypeSwitchNode switchNode) { * @param switchNode node to be lowered */ protected void lowerTypeSwitch(TypeSwitchNode switchNode) { - boolean hasdefault = switchNode.defaultSuccessor() != null; for (int i = 0; i < switchNode.blockSuccessorCount(); i++) { - // one successor AbstractBeginNode succ = switchNode.blockSuccessor(i); - // the default case must be lowered at the end - if (hasdefault) { - if (succ.equals(switchNode.defaultSuccessor())) { - continue; - } - } - ArrayList succKeys = new ArrayList<>(); - // query all keys that have the succ as block succ - for (int keyIndex = 0; keyIndex < switchNode.keyCount(); keyIndex++) { - ResolvedJavaType key = switchNode.typeAt(keyIndex); - AbstractBeginNode keySucc = switchNode.keySuccessor(keyIndex); - if (succ.equals(keySucc)) { - succKeys.add(key); + if (succ.equals(switchNode.defaultSuccessor())) { + lowerTypeSwitchDefaultCase(switchNode); + } else { + ArrayList succKeys = new ArrayList<>(); + // query all keys that have the succ as block succ + for (int keyIndex = 0; keyIndex < switchNode.keyCount(); keyIndex++) { + ResolvedJavaType key = switchNode.typeAt(keyIndex); + AbstractBeginNode keySucc = switchNode.keySuccessor(keyIndex); + if (succ.equals(keySucc)) { + succKeys.add(key); + } } + assert succKeys.size() > 0 : "no keys of " + switchNode + " have " + succ + " as block successor"; + lowerTypeSwitchCase(switchNode, succ, i, succKeys); } - assert succKeys.size() > 0 : "no keys of " + switchNode + " have " + succ + " as block successor"; - lowerTypeSwitchCase(switchNode, succ, i, succKeys); generateForwardJump(cfg.blockFor(switchNode), cfg.blockFor(succ)); codeGenTool.genBlockEndBreak(); codeGenTool.genScopeEnd(); } - if (hasdefault) { - lowerTypeSwitchDefaultCase(switchNode); - generateForwardJump(cfg.blockFor(switchNode), cfg.blockFor(switchNode.defaultSuccessor())); - codeGenTool.genBlockEndBreak(); - codeGenTool.genScopeEnd(); - } } protected void genLabeledBlockHeader(LabeledBlock labeledBlock) { From 7eb2d29a28006edf0dd12827fda3c66a431d6de9 Mon Sep 17 00:00:00 2001 From: Carlo Refice Date: Tue, 28 Nov 2023 15:04:38 +0100 Subject: [PATCH 412/593] Remove unreachable break statement at end of switch cases --- .../compiler/hightiercodegen/irwalk/StackifierIRWalker.java | 1 - 1 file changed, 1 deletion(-) diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hightiercodegen/irwalk/StackifierIRWalker.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hightiercodegen/irwalk/StackifierIRWalker.java index a6bb2fdf8f21..76bea9cef28a 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hightiercodegen/irwalk/StackifierIRWalker.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hightiercodegen/irwalk/StackifierIRWalker.java @@ -666,7 +666,6 @@ protected void lowerSwitch(IntegerSwitchNode switchNode) { } else { generateForwardJump(cfg.blockFor(switchNode), cfg.blockFor(succ)); } - codeGenTool.genBlockEndBreak(); codeGenTool.genScopeEnd(); } codeGenTool.genScopeEnd(); From 1802aefd837ba9f3fff36b9ef9e9f0360f9ff1b9 Mon Sep 17 00:00:00 2001 From: Tomas Stupka Date: Wed, 10 Jan 2024 14:27:16 +0000 Subject: [PATCH 413/593] [GR-21590] Update imports. PullRequest: graalpython/3146 --- vm/mx.vm/suite.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vm/mx.vm/suite.py b/vm/mx.vm/suite.py index 75af6e21a9a8..9a7b4ddea8d8 100644 --- a/vm/mx.vm/suite.py +++ b/vm/mx.vm/suite.py @@ -65,7 +65,7 @@ }, { "name": "graalpython", - "version": "10ee90e185b0ecdc5ad6b7313b146faaf8dc51f9", + "version": "67b5c3646f888b05825a6b36701f6294cc76d818", "dynamic": True, "urls": [ {"url": "https://github.com/graalvm/graalpython.git", "kind": "git"}, From c48be0211c24424b7b9e848739801e37987f0fb6 Mon Sep 17 00:00:00 2001 From: Mike Hearn Date: Wed, 10 Jan 2024 15:30:08 +0100 Subject: [PATCH 414/593] Espresso: Address code review comments. --- espresso/docs/how-espresso-works.md | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/espresso/docs/how-espresso-works.md b/espresso/docs/how-espresso-works.md index 5f7b061b67cf..84e2e8d7dbc8 100644 --- a/espresso/docs/how-espresso-works.md +++ b/espresso/docs/how-espresso-works.md @@ -16,7 +16,6 @@ stack. Instead Espresso provides runtime services like: * JNI. * A development/debug java launcher command based on the polyglot API. * The "native" components of the standard library like `libjava` (in quotes because what native means can vary). - [See below](#native-components). * Sandboxing. ## How to attach a debugger @@ -73,7 +72,11 @@ engine, 'casts' it to the JNI interface and then returns it. So adding it all together the startup sequence for end users goes like this: -`java -truffle ...` -> `libjli` -> `lib/truffle/libjvm` (mokapot) -> `libjavavm` (`LibEspresso`) -> Polyglot API -> `EspressoLauncher` -> `EspressoContext`. +`java -truffle ...` ➜ `libjli` ➜ `lib/truffle/libjvm` (mokapot) ➜ `libjavavm` (`LibEspresso`) ➜ Polyglot API ➜ `EspressoLanguage` ➜ `EspressoContext` + +The launcher uses this code path to obtain a JNI reference to the class `sun.launcher.LauncherHelper` which +loads the user's main class from inside Java, and then invokes it. There are other launcher helper classes for +alternative launch modes like when using `java` with a source file. ## Execution loop @@ -85,7 +88,7 @@ Truffle the loop will be unrolled and partially evaluated, which is how the meth Most bytecodes are handled in the obvious way. Some are _quickened_. -Truffle started as an AST interpreter and thus is very oriented around the concept of nodes (as in, AST nodes). It has +Truffle started as an AST interpreter and thus is very oriented around the concept of tree nodes. It has a lot of features that require nodes, and in particular nodes can be _specialized_ based on how they are actually used whereas a bytecode generally cannot. Quickening bridges the two worlds. A bytecode that is quickened is replaced with a special internal bytecode, `QUICK` or `SLIM_QUICK`, and a Truffle node is created for it then stored in the @@ -149,13 +152,14 @@ convenient. It's especially convenient for navigating in the IDE, as it lets you guest symbol is being manipulated by the VM, without being distracted by all the places the host code is also using the same symbol. -Accessing guest objects is relatively straightforward. An `impl.Klass` is similar to (but not the same as) a `Class` in +Accessing guest objects is relatively straightforward. Add new names, signatures and fields to the `Meta` and `Symbol` +classes using the existing entries as a guide. This will get you an `impl.ObjectKlass`, which is similar to (but not the same as) a `Class` in the guest world. Once you've obtained one you can use it to read fields, call methods etc. If you want to access _static_ fields, then you'll need to look up the field using `impl.Klass#lookupField()`, then use `getObject` on the field passing in the result of `Klass#tryInitializeAndGetStatics()`. Static fields are stored in a separate `StaticObject` and this will ensure the guest code `` runs to set up the static fields of the class you're trying to access. The guest world `java.lang.reflect.Class` that matches a host `impl.ObjectKlass` can be obtained by -calling `ObjectKlass#mirror()`. +calling `ObjectKlass#mirror()`. Guest-world reflection objects are tied back to host-world objects using _hidden fields_. These are special kinds of fields added to objects. Their names start with `0` making them illegal identifiers, ensuring there can never be From 4ec3d4416a5bb089870cb348a845cb5e72fe9efb Mon Sep 17 00:00:00 2001 From: Mike Hearn Date: Wed, 10 Jan 2024 15:32:14 +0100 Subject: [PATCH 415/593] Espresso: Fix code style gate. --- .../truffle/espresso/launcher/EspressoLauncher.java | 11 ++++++----- .../truffle/espresso/runtime/EspressoException.java | 4 ++-- 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/espresso/src/com.oracle.truffle.espresso.launcher/src/com/oracle/truffle/espresso/launcher/EspressoLauncher.java b/espresso/src/com.oracle.truffle.espresso.launcher/src/com/oracle/truffle/espresso/launcher/EspressoLauncher.java index bdf2d24b49d6..319676c116d1 100644 --- a/espresso/src/com.oracle.truffle.espresso.launcher/src/com/oracle/truffle/espresso/launcher/EspressoLauncher.java +++ b/espresso/src/com.oracle.truffle.espresso.launcher/src/com/oracle/truffle/espresso/launcher/EspressoLauncher.java @@ -41,9 +41,10 @@ import org.graalvm.polyglot.Value; /** - * A simple emulation of the {@code java} launcher that parses the command line flags and builds and Espresso context - * based on them. This code isn't used by anyone except Espresso developers, because in a shipped Espresso the VM - * is started via {@code mokapot} instead (see {@code hacking.md} for details). + * A simple emulation of the {@code java} launcher that parses the command line flags and builds and + * Espresso context based on them. This code isn't used by anyone except Espresso developers, + * because in a shipped Espresso the VM is started via {@code mokapot} instead (see + * {@code hacking.md} for details). */ public final class EspressoLauncher extends AbstractLanguageLauncher { private static final String AGENT_LIB = "java.AgentLib."; @@ -137,7 +138,7 @@ String getValue(String arg, String type) { /** * Advances the position, skipping over the value associated with an option if needed. - * + * * @return true if there are still arguments to process, false otherwise. */ boolean next() { @@ -417,7 +418,7 @@ private void buildJvmArgs(List arguments, int toBuild) { * world. It is actually expected that the vm arguments list is populated with arguments * which have been pre-formatted by the regular Java launcher when passed to the VM, ie: the * arguments if the VM was created through a call to JNI_CreateJavaVM. - * + * * In particular, it expects all kay-value pairs to be equals-separated and not * space-separated. Furthermore, it does not expect syntactic-sugared some arguments such as * '-m' or '--modules', that would have been replaced by the regular java launcher as diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/runtime/EspressoException.java b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/runtime/EspressoException.java index b41d198111ea..87caca6c35ae 100644 --- a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/runtime/EspressoException.java +++ b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/runtime/EspressoException.java @@ -32,8 +32,8 @@ import com.oracle.truffle.espresso.vm.VM; /** - * A wrapped guest exception. Espresso uses host exceptions to unwind the stack when the guest throws, so we have to - * wrap guest with host here. + * A wrapped guest exception. Espresso uses host exceptions to unwind the stack when the guest + * throws, so we have to wrap guest with host here. */ @ExportLibrary(value = InteropLibrary.class, delegateTo = "exception") @SuppressWarnings("serial") From c2a7b23b5e0cd47e9b1e2b2d843b99223bf9db8a Mon Sep 17 00:00:00 2001 From: Yudi Zheng Date: Wed, 10 Jan 2024 15:43:29 +0100 Subject: [PATCH 416/593] Implement VirtualThread.notifyJvmtiDisableSuspend intrinsic. --- .../core/test/jfr/TestGetEventWriter.java | 13 +- .../replacements/test/HalfFloatTest.java | 7 +- .../hotspot/GraalHotSpotVMConfig.java | 1 + .../meta/HotSpotGraphBuilderPlugins.java | 116 ++++++++++-------- .../meta/UnimplementedGraalIntrinsics.java | 2 - .../replacements/HotSpotReplacementsUtil.java | 18 ++- .../StandardGraphBuilderPlugins.java | 22 ++-- .../aarch64/AArch64GraphBuilderPlugins.java | 40 +++--- .../amd64/AMD64GraphBuilderPlugins.java | 63 +++++----- 9 files changed, 134 insertions(+), 148 deletions(-) diff --git a/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/core/test/jfr/TestGetEventWriter.java b/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/core/test/jfr/TestGetEventWriter.java index 27cca77802f2..404acc4f2cfb 100644 --- a/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/core/test/jfr/TestGetEventWriter.java +++ b/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/core/test/jfr/TestGetEventWriter.java @@ -28,12 +28,6 @@ import java.lang.reflect.Constructor; import java.lang.reflect.InvocationTargetException; -import jdk.graal.compiler.core.common.PermanentBailoutException; -import jdk.graal.compiler.core.test.SubprocessTest; -import jdk.graal.compiler.serviceprovider.GraalServices; -import jdk.graal.compiler.serviceprovider.JavaVersionUtil; -import jdk.graal.compiler.test.AddExports; -import jdk.graal.compiler.test.SubprocessUtil; import org.junit.Assert; import org.junit.Assume; import org.junit.Test; @@ -42,6 +36,11 @@ import org.objectweb.asm.MethodVisitor; import org.objectweb.asm.Opcodes; +import jdk.graal.compiler.core.common.PermanentBailoutException; +import jdk.graal.compiler.core.test.SubprocessTest; +import jdk.graal.compiler.serviceprovider.GraalServices; +import jdk.graal.compiler.test.AddExports; +import jdk.graal.compiler.test.SubprocessUtil; import jdk.jfr.Event; import jdk.jfr.Recording; import jdk.vm.ci.meta.ResolvedJavaMethod; @@ -61,7 +60,6 @@ public class TestGetEventWriter extends SubprocessTest { private static void initializeJFR() { - Assume.assumeTrue("JDK-8282420 came in JDK 19", JavaVersionUtil.JAVA_SPEC >= 19); Assume.assumeTrue("Requires JDK-8290075", GraalServices.hasLookupMethodWithCaller()); try (Recording r = new Recording()) { r.start(); @@ -82,7 +80,6 @@ static class InitializationEvent extends Event { @Test public void test() throws IOException, InterruptedException { - Assume.assumeTrue("JDK-8282420 came in JDK 19", JavaVersionUtil.JAVA_SPEC >= 19); launchSubprocess(() -> { try { initializeJFR(); diff --git a/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/replacements/test/HalfFloatTest.java b/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/replacements/test/HalfFloatTest.java index b5b6a454f6e4..c345f3a2e536 100644 --- a/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/replacements/test/HalfFloatTest.java +++ b/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/replacements/test/HalfFloatTest.java @@ -24,12 +24,9 @@ */ package jdk.graal.compiler.replacements.test; -import static jdk.graal.compiler.serviceprovider.JavaVersionUtil.JAVA_SPEC; -import static org.junit.Assume.assumeTrue; - -import jdk.graal.compiler.jtt.JTTTest; import org.junit.Test; +import jdk.graal.compiler.jtt.JTTTest; import jdk.vm.ci.code.InstalledCode; import jdk.vm.ci.code.InvalidInstalledCodeException; @@ -49,7 +46,6 @@ public static short floatToFloat16(float f) { */ @Test public void binary16RoundTrip() { - assumeTrue("Interpreter returns different result for silent NaNs prior to JDK-8302976", JAVA_SPEC >= 21); for (int i = Short.MIN_VALUE; i < Short.MAX_VALUE; i++) { short s = (short) i; Result result = test("float16ToFloat", s); @@ -248,7 +244,6 @@ public void roundFloatToBinary16FullBinade() throws InvalidInstalledCodeExceptio */ @Test public void binary16NaNRoundTrip() { - assumeTrue("Interpreter returns different result for silent NaNs prior to JDK-8302976", JAVA_SPEC >= 21); // A NaN has a nonzero significand for (int i = 1; i <= 0x3ff; i++) { short binary16NaN = (short) (NAN_EXPONENT | i); diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/GraalHotSpotVMConfig.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/GraalHotSpotVMConfig.java index e3fcd487cd36..04e88585e01c 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/GraalHotSpotVMConfig.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/GraalHotSpotVMConfig.java @@ -270,6 +270,7 @@ public final int arrayOopDescLengthOffset() { public final int threadIsInVTMSTransitionOffset = getFieldOffset("JavaThread::_is_in_VTMS_transition", Integer.class, "bool"); public final int threadIsInTmpVTMSTransitionOffset = getFieldOffset("JavaThread::_is_in_tmp_VTMS_transition", Integer.class, "bool"); + public final int threadIsDisableSuspendOffset = getFieldOffset("JavaThread::_is_disable_suspend", Integer.class, "bool", -1, JDK >= 22); public final int javaLangThreadJFREpochOffset = getFieldValue("java_lang_Thread::_jfr_epoch_offset", Integer.class, "int"); public final int javaLangThreadTIDOffset = getFieldValue("java_lang_Thread::_tid_offset", Integer.class, "int"); diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/meta/HotSpotGraphBuilderPlugins.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/meta/HotSpotGraphBuilderPlugins.java index 94b304b37a9c..50564e33e2c5 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/meta/HotSpotGraphBuilderPlugins.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/meta/HotSpotGraphBuilderPlugins.java @@ -622,52 +622,48 @@ public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Rec } }); - if (JavaVersionUtil.JAVA_SPEC >= 19) { - r.register(new InvocationPlugin("currentCarrierThread") { - @Override - public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver) { - try (HotSpotInvocationPluginHelper helper = new HotSpotInvocationPluginHelper(b, targetMethod, config)) { - ValueNode value = helper.readCurrentThreadObject(false); - b.push(JavaKind.Object, value); - } - return true; + r.register(new InvocationPlugin("currentCarrierThread") { + @Override + public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver) { + try (HotSpotInvocationPluginHelper helper = new HotSpotInvocationPluginHelper(b, targetMethod, config)) { + ValueNode value = helper.readCurrentThreadObject(false); + b.push(JavaKind.Object, value); } - }); + return true; + } + }); - r.register(new InlineOnlyInvocationPlugin("setCurrentThread", Receiver.class, Thread.class) { - @Override - public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode thread) { - GraalError.guarantee(Services.IS_IN_NATIVE_IMAGE || isAnnotatedByChangesCurrentThread(b.getMethod()), "method changes current Thread but is not annotated ChangesCurrentThread"); - try (HotSpotInvocationPluginHelper helper = new HotSpotInvocationPluginHelper(b, targetMethod, config)) { - receiver.get(); - helper.setCurrentThread(thread); - } - return true; + r.register(new InlineOnlyInvocationPlugin("setCurrentThread", Receiver.class, Thread.class) { + @Override + public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode thread) { + GraalError.guarantee(Services.IS_IN_NATIVE_IMAGE || isAnnotatedByChangesCurrentThread(b.getMethod()), "method changes current Thread but is not annotated ChangesCurrentThread"); + try (HotSpotInvocationPluginHelper helper = new HotSpotInvocationPluginHelper(b, targetMethod, config)) { + receiver.get(); + helper.setCurrentThread(thread); } - }); - } + return true; + } + }); - if (JavaVersionUtil.JAVA_SPEC >= 20) { - r.registerConditional(config.threadScopedValueCacheOffset != -1, new InvocationPlugin("scopedValueCache") { - @Override - public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver) { - try (HotSpotInvocationPluginHelper helper = new HotSpotInvocationPluginHelper(b, targetMethod, config)) { - b.push(JavaKind.Object, helper.readThreadScopedValueCache()); - } - return true; + r.registerConditional(config.threadScopedValueCacheOffset != -1, new InvocationPlugin("scopedValueCache") { + @Override + public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver) { + try (HotSpotInvocationPluginHelper helper = new HotSpotInvocationPluginHelper(b, targetMethod, config)) { + b.push(JavaKind.Object, helper.readThreadScopedValueCache()); } - }); + return true; + } + }); - r.registerConditional(config.threadScopedValueCacheOffset != -1, new InvocationPlugin("setScopedValueCache", Object[].class) { - @Override - public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode cache) { - try (HotSpotInvocationPluginHelper helper = new HotSpotInvocationPluginHelper(b, targetMethod, config)) { - helper.setThreadScopedValueCache(cache); - } - return true; + r.registerConditional(config.threadScopedValueCacheOffset != -1, new InvocationPlugin("setScopedValueCache", Object[].class) { + @Override + public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode cache) { + try (HotSpotInvocationPluginHelper helper = new HotSpotInvocationPluginHelper(b, targetMethod, config)) { + helper.setThreadScopedValueCache(cache); } - }); - } + return true; + } + }); } // @formatter:off @@ -721,8 +717,8 @@ private static void inlineNativeNotifyJvmtiFunctions(GraalHotSpotVMConfig config } private static void registerVirtualThreadPlugins(InvocationPlugins plugins, GraalHotSpotVMConfig config, Replacements replacements) { - if (JavaVersionUtil.JAVA_SPEC >= 21 && config.supportJVMTIVThreadNotification()) { - Registration r = new Registration(plugins, "java.lang.VirtualThread", replacements); + Registration r = new Registration(plugins, "java.lang.VirtualThread", replacements); + if (config.supportJVMTIVThreadNotification()) { r.register(new InvocationPlugin("notifyJvmtiStart", Receiver.class) { @Override public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver) { @@ -763,18 +759,38 @@ public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Rec return true; } }); - r.register(new InvocationPlugin("notifyJvmtiHideFrames", Receiver.class, boolean.class) { + } + r.register(new InvocationPlugin("notifyJvmtiHideFrames", Receiver.class, boolean.class) { + @Override + public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode hide) { + if (config.doJVMTIVirtualThreadTransitions) { + try (HotSpotInvocationPluginHelper helper = new HotSpotInvocationPluginHelper(b, targetMethod, config)) { + receiver.get(); + // unconditionally update the temporary VTMS transition bit in current + // JavaThread + GraalError.guarantee(config.threadIsInTmpVTMSTransitionOffset != -1, "JavaThread::_is_in_tmp_VTMS_transition is not exported"); + CurrentJavaThreadNode javaThread = b.add(new CurrentJavaThreadNode(helper.getWordKind())); + OffsetAddressNode address = b.add(new OffsetAddressNode(javaThread, helper.asWord(config.threadIsInTmpVTMSTransitionOffset))); + b.add(new JavaWriteNode(JavaKind.Boolean, address, HotSpotReplacementsUtil.HOTSPOT_JAVA_THREAD_IS_IN_TMP_VTMS_TRANSITION, hide, BarrierType.NONE, false)); + } + } + return true; + } + }); + + if (JavaVersionUtil.JAVA_SPEC >= 22) { + r.register(new InvocationPlugin("notifyJvmtiDisableSuspend", Receiver.class, boolean.class) { @Override - public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode hide) { + public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode enter) { if (config.doJVMTIVirtualThreadTransitions) { try (HotSpotInvocationPluginHelper helper = new HotSpotInvocationPluginHelper(b, targetMethod, config)) { receiver.get(); - // unconditionally update the temporary VTMS transition bit in current + // unconditionally update the is_disable_suspend bit in current // JavaThread - GraalError.guarantee(config.threadIsInTmpVTMSTransitionOffset != -1L, "JavaThread::_is_in_tmp_VTMS_transition is not exported"); + GraalError.guarantee(config.threadIsDisableSuspendOffset != -1, "JavaThread::_is_disable_suspend is not exported"); CurrentJavaThreadNode javaThread = b.add(new CurrentJavaThreadNode(helper.getWordKind())); - OffsetAddressNode address = b.add(new OffsetAddressNode(javaThread, helper.asWord(config.threadIsInTmpVTMSTransitionOffset))); - b.add(new JavaWriteNode(JavaKind.Boolean, address, HotSpotReplacementsUtil.HOTSPOT_JAVA_THREAD_IS_IN_TMP_VTMS_TRANSITION, hide, BarrierType.NONE, false)); + OffsetAddressNode address = b.add(new OffsetAddressNode(javaThread, helper.asWord(config.threadIsDisableSuspendOffset))); + b.add(new JavaWriteNode(JavaKind.Boolean, address, HotSpotReplacementsUtil.HOTSPOT_JAVA_THREAD_IS_DISABLE_SUSPEND, enter, BarrierType.NONE, false)); } } return true; @@ -898,10 +914,8 @@ private static void registerAESPlugins(InvocationPlugins plugins, GraalHotSpotVM r.registerConditional(config.electronicCodeBookEncrypt != 0L, new ElectronicCodeBookCryptPlugin(CryptMode.ENCRYPT)); r.registerConditional(config.electronicCodeBookDecrypt != 0L, new ElectronicCodeBookCryptPlugin(CryptMode.DECRYPT)); - if (JavaVersionUtil.JAVA_SPEC >= 18) { - r = new Registration(plugins, "com.sun.crypto.provider.GaloisCounterMode", replacements); - r.registerConditional(config.galoisCounterModeCrypt != 0L, new GaloisCounterModeCryptPlugin()); - } + r = new Registration(plugins, "com.sun.crypto.provider.GaloisCounterMode", replacements); + r.registerConditional(config.galoisCounterModeCrypt != 0L, new GaloisCounterModeCryptPlugin()); r = new Registration(plugins, "com.sun.crypto.provider.CounterMode", replacements); r.registerConditional(CounterModeAESNode.isSupported(arch), new CounterModeCryptPlugin() { diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/meta/UnimplementedGraalIntrinsics.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/meta/UnimplementedGraalIntrinsics.java index af5306ff9259..6f1c57d11738 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/meta/UnimplementedGraalIntrinsics.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/meta/UnimplementedGraalIntrinsics.java @@ -117,8 +117,6 @@ public UnimplementedGraalIntrinsics() { "jdk/jfr/internal/JVM.getEventWriter()Ljdk/jfr/internal/event/EventWriter;"); add(toBeInvestigated, // @formatter:off - // JDK-8311218 - "java/lang/VirtualThread.notifyJvmtiDisableSuspend(Z)V", // JDK-8309130: x86_64 AVX512 intrinsics for Arrays.sort methods (GR-48679) "java/util/DualPivotQuicksort.partition(Ljava/lang/Class;Ljava/lang/Object;JIIIILjava/util/DualPivotQuicksort$PartitionOperation;)[I", "java/util/DualPivotQuicksort.sort(Ljava/lang/Class;Ljava/lang/Object;JIILjava/util/DualPivotQuicksort$SortOperation;)V", diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/replacements/HotSpotReplacementsUtil.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/replacements/HotSpotReplacementsUtil.java index e125d8120d6a..a3e87c56255d 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/replacements/HotSpotReplacementsUtil.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/replacements/HotSpotReplacementsUtil.java @@ -29,6 +29,8 @@ import java.lang.ref.Reference; +import org.graalvm.word.LocationIdentity; + import jdk.graal.compiler.api.replacements.Fold; import jdk.graal.compiler.api.replacements.Fold.InjectedParameter; import jdk.graal.compiler.core.common.SuppressFBWarnings; @@ -58,10 +60,7 @@ import jdk.graal.compiler.nodes.type.StampTool; import jdk.graal.compiler.replacements.ReplacementsUtil; import jdk.graal.compiler.replacements.nodes.ReadRegisterNode; -import jdk.graal.compiler.serviceprovider.JavaVersionUtil; import jdk.graal.compiler.word.Word; -import org.graalvm.word.LocationIdentity; - import jdk.vm.ci.code.Register; import jdk.vm.ci.hotspot.HotSpotJVMCIRuntime; import jdk.vm.ci.hotspot.HotSpotMetaspaceConstant; @@ -293,11 +292,9 @@ public static Object getPendingException(Word thread) { * After that, it is never changed. In the presence of virtual threads from JDK 19 onwards, this * value can change when a virtual thread is unmounted and then mounted again. */ - public static final LocationIdentity JAVA_THREAD_CURRENT_THREAD_OBJECT_LOCATION = JavaVersionUtil.JAVA_SPEC < 19 ? NamedLocationIdentity.immutable("JavaThread::_threadObj") - : NamedLocationIdentity.mutable("JavaThread::_vthread"); + public static final LocationIdentity JAVA_THREAD_CURRENT_THREAD_OBJECT_LOCATION = NamedLocationIdentity.mutable("JavaThread::_vthread"); - public static final LocationIdentity JAVA_THREAD_CARRIER_THREAD_OBJECT_LOCATION = JavaVersionUtil.JAVA_SPEC < 19 ? JAVA_THREAD_CURRENT_THREAD_OBJECT_LOCATION - : NamedLocationIdentity.mutable("JavaThread::_threadObj"); + public static final LocationIdentity JAVA_THREAD_CARRIER_THREAD_OBJECT_LOCATION = NamedLocationIdentity.mutable("JavaThread::_threadObj"); public static final LocationIdentity JAVA_THREAD_OSTHREAD_LOCATION = NamedLocationIdentity.mutable("JavaThread::_osthread"); @@ -884,17 +881,16 @@ public static NamedLocationIdentity mutable(String name) { * This represents the contents of the OopHandle used to store the current thread. Virtual * thread support makes this mutable. */ - public static final LocationIdentity HOTSPOT_CURRENT_THREAD_OOP_HANDLE_LOCATION = JavaVersionUtil.JAVA_SPEC < 19 ? HOTSPOT_OOP_HANDLE_LOCATION - : OopHandleLocationIdentity.mutable("_vthread OopHandle contents"); + public static final LocationIdentity HOTSPOT_CURRENT_THREAD_OOP_HANDLE_LOCATION = OopHandleLocationIdentity.mutable("_vthread OopHandle contents"); - public static final LocationIdentity HOTSPOT_CARRIER_THREAD_OOP_HANDLE_LOCATION = JavaVersionUtil.JAVA_SPEC < 19 ? HOTSPOT_OOP_HANDLE_LOCATION - : OopHandleLocationIdentity.mutable("_threadObj OopHandle contents"); + public static final LocationIdentity HOTSPOT_CARRIER_THREAD_OOP_HANDLE_LOCATION = OopHandleLocationIdentity.mutable("_threadObj OopHandle contents"); public static final LocationIdentity HOTSPOT_JAVA_THREAD_SCOPED_VALUE_CACHE_HANDLE_LOCATION = OopHandleLocationIdentity.mutable("_scopedValueCache OopHandle contents"); public static final LocationIdentity HOTSPOT_VTMS_NOTIFY_JVMTI_EVENTS = NamedLocationIdentity.mutable("JvmtiVTMSTransitionDisabler::_VTMS_notify_jvmti_events"); public static final LocationIdentity HOTSPOT_JAVA_THREAD_IS_IN_VTMS_TRANSITION = NamedLocationIdentity.mutable("JavaThread::_is_in_VTMS_transition"); public static final LocationIdentity HOTSPOT_JAVA_THREAD_IS_IN_TMP_VTMS_TRANSITION = NamedLocationIdentity.mutable("JavaThread::_is_in_tmp_VTMS_transition"); + public static final LocationIdentity HOTSPOT_JAVA_THREAD_IS_DISABLE_SUSPEND = NamedLocationIdentity.mutable("JavaThread::_is_disable_suspend"); public static final LocationIdentity HOTSPOT_JAVA_LANG_THREAD_IS_IN_VTMS_TRANSITION = NamedLocationIdentity.mutable("Thread::_is_in_VTMS_transition"); @Fold diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/replacements/StandardGraphBuilderPlugins.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/replacements/StandardGraphBuilderPlugins.java index f9ff00bf993c..e5cc5baef940 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/replacements/StandardGraphBuilderPlugins.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/replacements/StandardGraphBuilderPlugins.java @@ -211,7 +211,6 @@ import jdk.graal.compiler.replacements.nodes.arithmetic.IntegerSubExactOverflowNode; import jdk.graal.compiler.replacements.nodes.arithmetic.IntegerSubExactSplitNode; import jdk.graal.compiler.replacements.nodes.arithmetic.UnsignedMulHighNode; -import jdk.graal.compiler.serviceprovider.JavaVersionUtil; import jdk.graal.compiler.serviceprovider.SpeculationReasonGroup; import jdk.vm.ci.code.Architecture; import jdk.vm.ci.code.BytecodePosition; @@ -749,10 +748,7 @@ private static void registerUnsafePlugins0(Registration r, boolean sunMiscUnsafe r.register(new CacheWritebackPlugin(false, "writeback0", Receiver.class, long.class)); r.register(new CacheWritebackPlugin(true, "writebackPreSync0", Receiver.class)); r.register(new CacheWritebackPlugin(false, "writebackPostSync0", Receiver.class)); - - if (JavaVersionUtil.JAVA_SPEC >= 18) { - r.register(new UnsafeFencePlugin(MembarNode.FenceKind.STORE_STORE, "storeStoreFence")); - } + r.register(new UnsafeFencePlugin(MembarNode.FenceKind.STORE_STORE, "storeStoreFence")); } r.register(new InvocationPlugin("arrayBaseOffset", Receiver.class, Class.class) { @@ -1128,15 +1124,13 @@ public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Rec return true; } }); - if (JavaVersionUtil.JAVA_SPEC >= 18) { - r.register(new InvocationPlugin("unsignedMultiplyHigh", long.class, long.class) { - @Override - public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode x, ValueNode y) { - b.addPush(JavaKind.Long, new UnsignedMulHighNode(x, y)); - return true; - } - }); - } + r.register(new InvocationPlugin("unsignedMultiplyHigh", long.class, long.class) { + @Override + public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode x, ValueNode y) { + b.addPush(JavaKind.Long, new UnsignedMulHighNode(x, y)); + return true; + } + }); } private static void registerRound(boolean supportsRound, Registration r, String name, RoundingMode mode) { diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/replacements/aarch64/AArch64GraphBuilderPlugins.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/replacements/aarch64/AArch64GraphBuilderPlugins.java index 98bce10eb0f9..997384016f4d 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/replacements/aarch64/AArch64GraphBuilderPlugins.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/replacements/aarch64/AArch64GraphBuilderPlugins.java @@ -61,18 +61,16 @@ import jdk.graal.compiler.replacements.StringUTF16CompressNode; import jdk.graal.compiler.replacements.StringUTF16Snippets; import jdk.graal.compiler.replacements.TargetGraphBuilderPlugins; +import jdk.graal.compiler.replacements.nodes.ArrayCompareToNode; +import jdk.graal.compiler.replacements.nodes.ArrayIndexOfNode; import jdk.graal.compiler.replacements.nodes.BinaryMathIntrinsicNode; +import jdk.graal.compiler.replacements.nodes.CountLeadingZerosNode; import jdk.graal.compiler.replacements.nodes.CountTrailingZerosNode; import jdk.graal.compiler.replacements.nodes.FloatToHalfFloatNode; import jdk.graal.compiler.replacements.nodes.FusedMultiplyAddNode; -import jdk.graal.compiler.replacements.nodes.UnaryMathIntrinsicNode; -import jdk.graal.compiler.replacements.nodes.ArrayCompareToNode; -import jdk.graal.compiler.replacements.nodes.ArrayIndexOfNode; -import jdk.graal.compiler.replacements.nodes.CountLeadingZerosNode; import jdk.graal.compiler.replacements.nodes.HalfFloatToFloatNode; import jdk.graal.compiler.replacements.nodes.MessageDigestNode; -import jdk.graal.compiler.serviceprovider.JavaVersionUtil; - +import jdk.graal.compiler.replacements.nodes.UnaryMathIntrinsicNode; import jdk.vm.ci.aarch64.AArch64; import jdk.vm.ci.code.Architecture; import jdk.vm.ci.meta.JavaKind; @@ -135,22 +133,20 @@ public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Rec private static void registerFloatPlugins(InvocationPlugins plugins, Replacements replacements) { Registration r = new Registration(plugins, Float.class, replacements); - if (JavaVersionUtil.JAVA_SPEC >= 20) { - r.register(new InvocationPlugin("float16ToFloat", short.class) { - @Override - public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode value) { - b.push(JavaKind.Float, b.append(new HalfFloatToFloatNode(value))); - return true; - } - }); - r.register(new InvocationPlugin("floatToFloat16", float.class) { - @Override - public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode value) { - b.push(JavaKind.Short, b.append(new FloatToHalfFloatNode(value))); - return true; - } - }); - } + r.register(new InvocationPlugin("float16ToFloat", short.class) { + @Override + public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode value) { + b.push(JavaKind.Float, b.append(new HalfFloatToFloatNode(value))); + return true; + } + }); + r.register(new InvocationPlugin("floatToFloat16", float.class) { + @Override + public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode value) { + b.push(JavaKind.Short, b.append(new FloatToHalfFloatNode(value))); + return true; + } + }); } private static void registerMathPlugins(InvocationPlugins plugins, boolean registerForeignCallMath) { diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/replacements/amd64/AMD64GraphBuilderPlugins.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/replacements/amd64/AMD64GraphBuilderPlugins.java index 41e6aceb6fc2..5e5b9a209b76 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/replacements/amd64/AMD64GraphBuilderPlugins.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/replacements/amd64/AMD64GraphBuilderPlugins.java @@ -84,7 +84,6 @@ import jdk.graal.compiler.replacements.nodes.HalfFloatToFloatNode; import jdk.graal.compiler.replacements.nodes.UnaryMathIntrinsicNode; import jdk.graal.compiler.replacements.nodes.UnaryMathIntrinsicNode.UnaryOperation; -import jdk.graal.compiler.serviceprovider.JavaVersionUtil; import jdk.vm.ci.amd64.AMD64; import jdk.vm.ci.amd64.AMD64.CPUFeature; import jdk.vm.ci.code.Architecture; @@ -146,22 +145,20 @@ public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Rec } }); - if (JavaVersionUtil.JAVA_SPEC >= 20) { - r.registerConditional(arch.getFeatures().contains(CPUFeature.BMI2), new InvocationPlugin("compress", type, type) { - @Override - public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode value, ValueNode mask) { - b.push(kind, b.append(new CompressBitsNode(value, mask))); - return true; - } - }); - r.registerConditional(arch.getFeatures().contains(CPUFeature.BMI2), new InvocationPlugin("expand", type, type) { - @Override - public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode value, ValueNode mask) { - b.push(kind, b.append(new ExpandBitsNode(value, mask))); - return true; - } - }); - } + r.registerConditional(arch.getFeatures().contains(CPUFeature.BMI2), new InvocationPlugin("compress", type, type) { + @Override + public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode value, ValueNode mask) { + b.push(kind, b.append(new CompressBitsNode(value, mask))); + return true; + } + }); + r.registerConditional(arch.getFeatures().contains(CPUFeature.BMI2), new InvocationPlugin("expand", type, type) { + @Override + public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode value, ValueNode mask) { + b.push(kind, b.append(new ExpandBitsNode(value, mask))); + return true; + } + }); } private static boolean supportsFeature(AMD64 arch, String feature) { @@ -175,24 +172,22 @@ private static boolean supportsFeature(AMD64 arch, String feature) { private static void registerFloatPlugins(InvocationPlugins plugins, AMD64 arch, Replacements replacements) { Registration r = new Registration(plugins, Float.class, replacements); - if (JavaVersionUtil.JAVA_SPEC >= 20) { - boolean supportsF16C = supportsFeature(arch, "F16C"); + boolean supportsF16C = supportsFeature(arch, "F16C"); - r.registerConditional(supportsF16C, new InvocationPlugin("float16ToFloat", short.class) { - @Override - public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode value) { - b.push(JavaKind.Float, b.append(new HalfFloatToFloatNode(value))); - return true; - } - }); - r.registerConditional(supportsF16C, new InvocationPlugin("floatToFloat16", float.class) { - @Override - public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode value) { - b.push(JavaKind.Short, b.append(new FloatToHalfFloatNode(value))); - return true; - } - }); - } + r.registerConditional(supportsF16C, new InvocationPlugin("float16ToFloat", short.class) { + @Override + public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode value) { + b.push(JavaKind.Float, b.append(new HalfFloatToFloatNode(value))); + return true; + } + }); + r.registerConditional(supportsF16C, new InvocationPlugin("floatToFloat16", float.class) { + @Override + public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode value) { + b.push(JavaKind.Short, b.append(new FloatToHalfFloatNode(value))); + return true; + } + }); } private static void registerFloatDoublePlugins(InvocationPlugins plugins, JavaKind kind, AMD64 arch, Replacements replacements) { From 44ea24dad9939dc59d3b83e17060ed984b4dd1eb Mon Sep 17 00:00:00 2001 From: Tomas Zezula Date: Wed, 10 Jan 2024 21:36:16 +0100 Subject: [PATCH 417/593] [GR-50945] Resolved review comments. --- truffle/mx.truffle/mx_truffle.py | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/truffle/mx.truffle/mx_truffle.py b/truffle/mx.truffle/mx_truffle.py index 5f25063c8be5..4b17c1298fdd 100644 --- a/truffle/mx.truffle/mx_truffle.py +++ b/truffle/mx.truffle/mx_truffle.py @@ -188,15 +188,17 @@ def _open_module_exports_args(): class TruffleUnittestConfig(mx_unittest.MxUnittestConfig): - _use_enterprise_polyglot = False + _use_enterprise_polyglot = True def __init__(self): super(TruffleUnittestConfig, self).__init__('truffle') def processDeps(self, deps): if TruffleUnittestConfig._use_enterprise_polyglot: - mx.logv('Adding Enterprise Polyglot to unittest dependencies due to the `--use-enterprise-polyglot` unittest argument being set.') - deps.add(mx.distribution('graal-enterprise:TRUFFLE_ENTERPRISE')) + dist_names = resolve_truffle_dist_names() + mx.logv(f'Adding Truffle runtime distributions {", ".join(dist_names)} to unittest dependencies.') + for dist_name in dist_names: + deps.add(mx.distribution(dist_name)) def apply(self, config): vmArgs, mainClass, mainClassArgs = config @@ -217,17 +219,17 @@ def apply(self, config): mx_unittest.register_unittest_config(TruffleUnittestConfig()) -class _UseEnterprisePolyglotAction(Action): +class _DisableEnterpriseTruffleAction(Action): def __init__(self, **kwargs): kwargs['required'] = False kwargs['nargs'] = 0 - super(_UseEnterprisePolyglotAction, self).__init__(**kwargs) + super(_DisableEnterpriseTruffleAction, self).__init__(**kwargs) def __call__(self, parser, namespace, values, option_string=None): - TruffleUnittestConfig._use_enterprise_polyglot = True + TruffleUnittestConfig._use_enterprise_polyglot = False -mx_unittest.add_unittest_argument('--use-enterprise-polyglot', default=False, help='Adds Truffle enterprise polyglot to unittest depdendencies.', action=_UseEnterprisePolyglotAction) +mx_unittest.add_unittest_argument('--disable-truffle-enterprise', default=False, help='Disables the automatic inclusion of Enterprise Truffle in unittest dependencies.', action=_DisableEnterpriseTruffleAction) class NFITestConfig: From 2bd2b2c4185b9e86ff439b9c5ba7940bdc23a725 Mon Sep 17 00:00:00 2001 From: Olya Gupalo Date: Tue, 9 Jan 2024 18:42:37 +0100 Subject: [PATCH 418/593] Update Source.Builder.buildLiteral() method description --- .../src/org/graalvm/polyglot/Source.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/sdk/src/org.graalvm.polyglot/src/org/graalvm/polyglot/Source.java b/sdk/src/org.graalvm.polyglot/src/org/graalvm/polyglot/Source.java index 78b9dd7da5da..11c79b4ed2bb 100644 --- a/sdk/src/org.graalvm.polyglot/src/org/graalvm/polyglot/Source.java +++ b/sdk/src/org.graalvm.polyglot/src/org/graalvm/polyglot/Source.java @@ -931,10 +931,10 @@ public Source build() throws IOException { } /** - * Uses configuration of this builder to create new {@link Source} object. This method can - * only be used if the builder was created as - * {@link Source#newBuilder(String, CharSequence, String) string literal} builder and - * otherwise throws an {@link UnsupportedOperationException}. + * Uses configuration of this builder to create a new {@link Source} object. This method + * suppresses any {@link IOException} as {@link AssertionError} and should only be used if + * the builder was created using {@link Source#newBuilder(String, CharSequence, String) or + * Source#newBuilder(String, ByteSequence, String) byte sequence literal}. * * @return the source object * @since 19.0 From dfeb3e3d6312f09a285b03db72c8b4ed789934e5 Mon Sep 17 00:00:00 2001 From: Foivos Zakkak Date: Thu, 11 Jan 2024 11:16:34 +0200 Subject: [PATCH 419/593] Use latest labsjdk in Quarkus github workflow Quarkus integration tests expect a JDK-23-based build of GraalVM `master`. --- .github/workflows/quarkus.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/quarkus.yml b/.github/workflows/quarkus.yml index 91e4633c6eb4..db0ba6a86d41 100644 --- a/.github/workflows/quarkus.yml +++ b/.github/workflows/quarkus.yml @@ -1,5 +1,5 @@ # -# Copyright (c) 2020, 2023, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2020, 2024, Oracle and/or its affiliates. All rights reserved. # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. # # The Universal Permissive License (UPL), Version 1.0 @@ -112,7 +112,7 @@ jobs: - name: Fetch LabsJDK run: | mkdir jdk-dl - ${MX_PATH}/mx --java-home= fetch-jdk --jdk-id labsjdk-ce-21 --to jdk-dl --alias ${LABSJDK_HOME} + ${MX_PATH}/mx --java-home= fetch-jdk --jdk-id labsjdk-ce-latest --to jdk-dl --alias ${LABSJDK_HOME} - name: Build graalvm native-image run: | export JAVA_HOME=${LABSJDK_HOME} From 572491e4d68702db16130a0306b7397250478eac Mon Sep 17 00:00:00 2001 From: David Leopoldseder Date: Wed, 3 Jan 2024 16:53:01 +0100 Subject: [PATCH 420/593] integer test: fold conditional constants introduced on ni inlining --- .../test/IntegerTestCanonicalizationTest.java | 120 ++++++++++++++++++ .../compiler/nodes/calc/IntegerTestNode.java | 26 +++- 2 files changed, 145 insertions(+), 1 deletion(-) create mode 100644 compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/core/test/IntegerTestCanonicalizationTest.java diff --git a/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/core/test/IntegerTestCanonicalizationTest.java b/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/core/test/IntegerTestCanonicalizationTest.java new file mode 100644 index 000000000000..3b8d1f8ca9d6 --- /dev/null +++ b/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/core/test/IntegerTestCanonicalizationTest.java @@ -0,0 +1,120 @@ +/* + * Copyright (c) 2024, 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 jdk.graal.compiler.core.test; + +import org.junit.Assert; +import org.junit.Test; + +import jdk.graal.compiler.api.directives.GraalDirectives; +import jdk.graal.compiler.nodes.StructuredGraph; +import jdk.graal.compiler.nodes.calc.IntegerTestNode; +import jdk.graal.compiler.nodes.extended.OpaqueNode; +import jdk.graal.compiler.nodes.extended.OpaqueValueNode; + +public class IntegerTestCanonicalizationTest extends GraalCompilerTest { + + @BytecodeParserNeverInline + static int integerTest(int a, int b) { + return (a & b); + } + + /* + * In order to avoid canonicalization of other parts of the expression we wrap the x in an + * opaque node and later remove it during checkHighTier graph. + */ + @BytecodeParserNeverInline + static int hideBehindCall(Object p0, Object p1) { + return GraalDirectives.opaque(p0 == p1 ? 1 : 0); + } + + static int snippet(Object p0, Object p1) { + if (integerTest(hideBehindCall(p0, p1), 1) == 0) { + GraalDirectives.sideEffect(123); + return 12; + } else { + GraalDirectives.sideEffect(111); + return 13; + } + } + + /* + * In order to avoid canonicalization of other parts of the expression we wrap the x in an + * opaque node and later remove it during checkHighTier graph. + */ + @BytecodeParserNeverInline + static int hideBehindCall2(Object p0, Object p1) { + return GraalDirectives.opaque(p0 == p1 ? 0 : 1); + } + + static int snippet2(Object p0, Object p1) { + if (integerTest(hideBehindCall2(p0, p1), 1) == 0) { + GraalDirectives.sideEffect(123); + return 12; + } else { + GraalDirectives.sideEffect(111); + return 13; + } + } + + @Override + protected void checkHighTierGraph(StructuredGraph graph) { + super.checkHighTierGraph(graph); + Assert.assertEquals(1, graph.getNodes().filter(IntegerTestNode.class).count()); + for (OpaqueNode opaque : graph.getNodes().filter(OpaqueValueNode.class).snapshot()) { + opaque.remove(); + } + } + + @Override + protected void checkMidTierGraph(StructuredGraph graph) { + super.checkMidTierGraph(graph); + Assert.assertEquals(0, graph.getNodes().filter(IntegerTestNode.class).count()); + } + + @Test + public void test01() { + test("snippet", "abc", 123); + test("snippet", "abc", null); + test("snippet", null, 123); + Object o = new Object(); + test("snippet", o, o); + test("snippet", o, null); + test("snippet", null, o); + test("snippet", null, null); + } + + @Test + public void test02() { + test("snippet2", "abc", 123); + test("snippet2", "abc", null); + test("snippet2", null, 123); + Object o = new Object(); + test("snippet2", o, o); + test("snippet2", o, null); + test("snippet2", null, o); + test("snippet2", null, null); + } + +} diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/nodes/calc/IntegerTestNode.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/nodes/calc/IntegerTestNode.java index 016dca0beb63..dbf72612df7d 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/nodes/calc/IntegerTestNode.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/nodes/calc/IntegerTestNode.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, 2024, 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 @@ -29,10 +29,12 @@ import jdk.graal.compiler.core.common.type.IntegerStamp; import jdk.graal.compiler.core.common.type.Stamp; +import jdk.graal.compiler.debug.GraalError; import jdk.graal.compiler.graph.NodeClass; import jdk.graal.compiler.nodeinfo.NodeInfo; import jdk.graal.compiler.nodes.BinaryOpLogicNode; import jdk.graal.compiler.nodes.LogicConstantNode; +import jdk.graal.compiler.nodes.LogicNegationNode; import jdk.graal.compiler.nodes.LogicNode; import jdk.graal.compiler.nodes.NodeView; import jdk.graal.compiler.nodes.ValueNode; @@ -86,6 +88,28 @@ private static LogicNode canonical(ValueNode forX, ValueNode forY, NodeView view if (newRHS != null) { return new IntegerTestNode(forX, newRHS); } + + if (forX.isConstant() && forX.asJavaConstant().asLong() == 1 || forY.isConstant() && forY.asJavaConstant().asLong() == 1) { + + ValueNode nonConstantInput = forX.isConstant() ? forY : forX; + GraalError.guarantee(!nonConstantInput.isConstant(), "Must not be constant %s", nonConstantInput); + if (nonConstantInput instanceof ConditionalNode conditional) { + ValueNode condX = conditional.trueValue(); + ValueNode condY = conditional.falseValue(); + + // fold the following condition ((c ? 1:0 ) & 1 == 0) to !c + if (condX.isConstant() && condX.asJavaConstant().asLong() == 1 && condY.isConstant() && condY.asJavaConstant().asLong() == 0) { + return LogicNegationNode.create(conditional.condition()); + } + + // fold the following condition ((c ? 0 : 1 ) & 1 == 0) to c + if (condX.isConstant() && condX.asJavaConstant().asLong() == 0 && condY.isConstant() && condY.asJavaConstant().asLong() == 1) { + return conditional.condition(); + } + } + + } + } return null; } From 38a4e138ae722f0630a08bf95f00a781e6e03f2f Mon Sep 17 00:00:00 2001 From: David Leopoldseder Date: Fri, 5 Jan 2024 16:48:47 +0100 Subject: [PATCH 421/593] binary op logic node: generalize constant logic from integer test to non constant pattern --- .../compiler/nodes/BinaryOpLogicNode.java | 26 ++++++++++++++++ .../compiler/nodes/calc/FloatEqualsNode.java | 2 +- .../nodes/calc/FloatLessThanNode.java | 2 +- .../nodes/calc/IntegerEqualsNode.java | 2 +- .../compiler/nodes/calc/IntegerTestNode.java | 30 ++----------------- .../compiler/nodes/calc/OpMaskOrTestNode.java | 5 ---- .../compiler/nodes/calc/OpMaskTestNode.java | 5 ---- .../nodes/calc/PointerEqualsNode.java | 2 +- .../nodes/java/ClassIsAssignableFromNode.java | 2 +- .../nodes/java/InstanceOfDynamicNode.java | 10 +++---- 10 files changed, 39 insertions(+), 47 deletions(-) diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/nodes/BinaryOpLogicNode.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/nodes/BinaryOpLogicNode.java index f88a0078b5a1..76647cc43aae 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/nodes/BinaryOpLogicNode.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/nodes/BinaryOpLogicNode.java @@ -30,7 +30,9 @@ import jdk.graal.compiler.graph.Node; import jdk.graal.compiler.graph.NodeClass; import jdk.graal.compiler.nodeinfo.NodeInfo; +import jdk.graal.compiler.nodes.calc.ConditionalNode; import jdk.graal.compiler.nodes.spi.Canonicalizable; +import jdk.graal.compiler.nodes.spi.CanonicalizerTool; import jdk.vm.ci.meta.TriState; @NodeInfo @@ -105,4 +107,28 @@ public LogicNode maybeCommuteInputs() { public abstract Stamp getSucceedingStampForY(boolean negated, Stamp xStamp, Stamp yStamp); public abstract TriState tryFold(Stamp xStamp, Stamp yStamp); + + @Override + public Node canonical(CanonicalizerTool tool, ValueNode forX, ValueNode forY) { + // fold conditions of the form forX op forY where forX=(c ? condTrueVal : condFalseVal) + // for example for integer test of (c ? 0 : 1 ) & 1 == 0) to c + if (forX instanceof ConditionalNode conditional) { + final ValueNode condTrueVal = conditional.trueValue(); + final ValueNode condFalseVal = conditional.falseValue(); + // evaluate the conditional true and false value against the forY of this condition, if + // they are both known, i.e., both evaluate to a clear result use the input of the + // conditional in its respective form instead + final TriState trueValCond = tryFold(condTrueVal.stamp(NodeView.DEFAULT), forY.stamp(NodeView.DEFAULT)); + final TriState falseValCond = tryFold(condFalseVal.stamp(NodeView.DEFAULT), forY.stamp(NodeView.DEFAULT)); + if (trueValCond.isUnknown() || falseValCond.isUnknown()) { + return null; + } + if (trueValCond == falseValCond) { + return LogicConstantNode.forBoolean(trueValCond.toBoolean()); + } else { + return trueValCond.toBoolean() ? conditional.condition() : LogicNegationNode.create(conditional.condition()); + } + } + return this; + } } diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/nodes/calc/FloatEqualsNode.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/nodes/calc/FloatEqualsNode.java index 3d41a1740107..332e15298224 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/nodes/calc/FloatEqualsNode.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/nodes/calc/FloatEqualsNode.java @@ -103,7 +103,7 @@ public Node canonical(CanonicalizerTool tool, ValueNode forX, ValueNode forY) { if (value != null) { return value; } - return this; + return super.canonical(tool, forX, forY); } public static class FloatEqualsOp extends CompareOp { diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/nodes/calc/FloatLessThanNode.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/nodes/calc/FloatLessThanNode.java index c235ada55925..5608c14d2aa1 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/nodes/calc/FloatLessThanNode.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/nodes/calc/FloatLessThanNode.java @@ -84,7 +84,7 @@ public Node canonical(CanonicalizerTool tool, ValueNode forX, ValueNode forY) { if (value != null) { return value; } - return this; + return super.canonical(tool, forX, forY); } public static class FloatLessThanOp extends CompareOp { diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/nodes/calc/IntegerEqualsNode.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/nodes/calc/IntegerEqualsNode.java index 8b613993f77b..2cbd658ff0a9 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/nodes/calc/IntegerEqualsNode.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/nodes/calc/IntegerEqualsNode.java @@ -89,7 +89,7 @@ public Node canonical(CanonicalizerTool tool, ValueNode forX, ValueNode forY) { if (value != null) { return value; } - return this; + return super.canonical(tool, forX, forY); } public static class IntegerEqualsOp extends CompareOp { diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/nodes/calc/IntegerTestNode.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/nodes/calc/IntegerTestNode.java index dbf72612df7d..7a2e2177ff0d 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/nodes/calc/IntegerTestNode.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/nodes/calc/IntegerTestNode.java @@ -29,18 +29,16 @@ import jdk.graal.compiler.core.common.type.IntegerStamp; import jdk.graal.compiler.core.common.type.Stamp; -import jdk.graal.compiler.debug.GraalError; +import jdk.graal.compiler.graph.Node; import jdk.graal.compiler.graph.NodeClass; import jdk.graal.compiler.nodeinfo.NodeInfo; import jdk.graal.compiler.nodes.BinaryOpLogicNode; import jdk.graal.compiler.nodes.LogicConstantNode; -import jdk.graal.compiler.nodes.LogicNegationNode; import jdk.graal.compiler.nodes.LogicNode; import jdk.graal.compiler.nodes.NodeView; import jdk.graal.compiler.nodes.ValueNode; import jdk.graal.compiler.nodes.spi.Canonicalizable; import jdk.graal.compiler.nodes.spi.CanonicalizerTool; - import jdk.vm.ci.meta.TriState; /** @@ -88,36 +86,14 @@ private static LogicNode canonical(ValueNode forX, ValueNode forY, NodeView view if (newRHS != null) { return new IntegerTestNode(forX, newRHS); } - - if (forX.isConstant() && forX.asJavaConstant().asLong() == 1 || forY.isConstant() && forY.asJavaConstant().asLong() == 1) { - - ValueNode nonConstantInput = forX.isConstant() ? forY : forX; - GraalError.guarantee(!nonConstantInput.isConstant(), "Must not be constant %s", nonConstantInput); - if (nonConstantInput instanceof ConditionalNode conditional) { - ValueNode condX = conditional.trueValue(); - ValueNode condY = conditional.falseValue(); - - // fold the following condition ((c ? 1:0 ) & 1 == 0) to !c - if (condX.isConstant() && condX.asJavaConstant().asLong() == 1 && condY.isConstant() && condY.asJavaConstant().asLong() == 0) { - return LogicNegationNode.create(conditional.condition()); - } - - // fold the following condition ((c ? 0 : 1 ) & 1 == 0) to c - if (condX.isConstant() && condX.asJavaConstant().asLong() == 0 && condY.isConstant() && condY.asJavaConstant().asLong() == 1) { - return conditional.condition(); - } - } - - } - } return null; } @Override - public ValueNode canonical(CanonicalizerTool tool, ValueNode forX, ValueNode forY) { + public Node canonical(CanonicalizerTool tool, ValueNode forX, ValueNode forY) { ValueNode value = canonical(forX, forY, NodeView.from(tool)); - return value != null ? value : this; + return value != null ? value : super.canonical(tool, forX, forY); } @Override diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/nodes/calc/OpMaskOrTestNode.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/nodes/calc/OpMaskOrTestNode.java index f10e9128ea6e..07c91c67274c 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/nodes/calc/OpMaskOrTestNode.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/nodes/calc/OpMaskOrTestNode.java @@ -32,7 +32,6 @@ import jdk.graal.compiler.nodeinfo.NodeInfo; import jdk.graal.compiler.nodes.BinaryOpLogicNode; import jdk.graal.compiler.nodes.ValueNode; -import jdk.graal.compiler.nodes.spi.CanonicalizerTool; import jdk.vm.ci.meta.TriState; /** @@ -71,8 +70,4 @@ public TriState tryFold(Stamp xStamp, Stamp yStamp) { return TriState.UNKNOWN; } - @Override - public ValueNode canonical(CanonicalizerTool tool, ValueNode forX, ValueNode forY) { - return this; - } } diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/nodes/calc/OpMaskTestNode.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/nodes/calc/OpMaskTestNode.java index 74f99f8cba2f..b29077212d8f 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/nodes/calc/OpMaskTestNode.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/nodes/calc/OpMaskTestNode.java @@ -32,7 +32,6 @@ import jdk.graal.compiler.nodeinfo.NodeInfo; import jdk.graal.compiler.nodes.BinaryOpLogicNode; import jdk.graal.compiler.nodes.ValueNode; -import jdk.graal.compiler.nodes.spi.CanonicalizerTool; import jdk.vm.ci.meta.TriState; /** @@ -78,8 +77,4 @@ public TriState tryFold(Stamp xStamp, Stamp yStamp) { return TriState.UNKNOWN; } - @Override - public ValueNode canonical(CanonicalizerTool tool, ValueNode forX, ValueNode forY) { - return this; - } } diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/nodes/calc/PointerEqualsNode.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/nodes/calc/PointerEqualsNode.java index d598b862b0fa..a7a0532b80e3 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/nodes/calc/PointerEqualsNode.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/nodes/calc/PointerEqualsNode.java @@ -85,7 +85,7 @@ public Node canonical(CanonicalizerTool tool, ValueNode forX, ValueNode forY) { if (value != null) { return value; } - return this; + return super.canonical(tool, forX, forY); } public static class PointerEqualsOp extends CompareOp { diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/nodes/java/ClassIsAssignableFromNode.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/nodes/java/ClassIsAssignableFromNode.java index b39a8e5d13db..23b0b248a58c 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/nodes/java/ClassIsAssignableFromNode.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/nodes/java/ClassIsAssignableFromNode.java @@ -91,7 +91,7 @@ public Node canonical(CanonicalizerTool tool, ValueNode forX, ValueNode forY) { return LogicConstantNode.forBoolean(thisType.isAssignableFrom(otherType)); } } - return this; + return super.canonical(tool, forX, forY); } @Override diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/nodes/java/InstanceOfDynamicNode.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/nodes/java/InstanceOfDynamicNode.java index 836ab290ea73..0f2285adf588 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/nodes/java/InstanceOfDynamicNode.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/nodes/java/InstanceOfDynamicNode.java @@ -29,17 +29,17 @@ import jdk.graal.compiler.core.common.type.Stamp; import jdk.graal.compiler.core.common.type.TypeReference; +import jdk.graal.compiler.graph.Node; import jdk.graal.compiler.graph.NodeClass; -import jdk.graal.compiler.nodes.spi.Canonicalizable; -import jdk.graal.compiler.nodes.spi.CanonicalizerTool; import jdk.graal.compiler.nodeinfo.NodeInfo; import jdk.graal.compiler.nodes.BinaryOpLogicNode; import jdk.graal.compiler.nodes.LogicConstantNode; import jdk.graal.compiler.nodes.LogicNode; import jdk.graal.compiler.nodes.ValueNode; import jdk.graal.compiler.nodes.calc.IsNullNode; +import jdk.graal.compiler.nodes.spi.Canonicalizable; +import jdk.graal.compiler.nodes.spi.CanonicalizerTool; import jdk.graal.compiler.nodes.spi.Lowerable; - import jdk.vm.ci.meta.Assumptions; import jdk.vm.ci.meta.ConstantReflectionProvider; import jdk.vm.ci.meta.JavaKind; @@ -113,12 +113,12 @@ public ValueNode getObject() { } @Override - public LogicNode canonical(CanonicalizerTool tool, ValueNode forMirror, ValueNode forObject) { + public Node canonical(CanonicalizerTool tool, ValueNode forMirror, ValueNode forObject) { LogicNode result = findSynonym(tool.getAssumptions(), tool.getConstantReflection(), forMirror, forObject, allowNull, exact); if (result != null) { return result; } - return this; + return super.canonical(tool, forMirror, forObject); } public void setMirror(ValueNode newObject) { From b3a92d090354042165aa61d1a5a56e3aec73b3be Mon Sep 17 00:00:00 2001 From: David Leopoldseder Date: Fri, 5 Jan 2024 17:01:33 +0100 Subject: [PATCH 422/593] canon must only return null for deletion --- .../src/jdk/graal/compiler/nodes/BinaryOpLogicNode.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/nodes/BinaryOpLogicNode.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/nodes/BinaryOpLogicNode.java index 76647cc43aae..524a8c258be2 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/nodes/BinaryOpLogicNode.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/nodes/BinaryOpLogicNode.java @@ -121,7 +121,7 @@ public Node canonical(CanonicalizerTool tool, ValueNode forX, ValueNode forY) { final TriState trueValCond = tryFold(condTrueVal.stamp(NodeView.DEFAULT), forY.stamp(NodeView.DEFAULT)); final TriState falseValCond = tryFold(condFalseVal.stamp(NodeView.DEFAULT), forY.stamp(NodeView.DEFAULT)); if (trueValCond.isUnknown() || falseValCond.isUnknown()) { - return null; + return this; } if (trueValCond == falseValCond) { return LogicConstantNode.forBoolean(trueValCond.toBoolean()); From 8eb1529cfc9b452d153c3ba4e3e6a3bd907a9acc Mon Sep 17 00:00:00 2001 From: David Leopoldseder Date: Thu, 11 Jan 2024 12:31:28 +0100 Subject: [PATCH 423/593] array length: fix missing arg for canon search constant length --- .../jdk/graal/compiler/nodes/java/ArrayLengthNode.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/nodes/java/ArrayLengthNode.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/nodes/java/ArrayLengthNode.java index 9fe147606ad3..86862a9895d2 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/nodes/java/ArrayLengthNode.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/nodes/java/ArrayLengthNode.java @@ -114,15 +114,15 @@ public ValueNode canonical(CanonicalizerTool tool, ValueNode forValue) { * explode loop we run a limited form for constants before. This is needed for unrolling for * example that uses #canonical instead of #simplify to not recompute the cfg all the time. */ - ValueNode len = searchForConstantLength(tool.getConstantReflection()); + ValueNode len = searchForConstantLength(tool.getConstantReflection(), forValue); if (len != null) { return len; } return this; } - private ValueNode searchForConstantLength(ConstantReflectionProvider constantReflection) { - ValueNode len = GraphUtil.arrayLength(getValue(), ArrayLengthProvider.FindLengthMode.SEARCH_ONLY, constantReflection); + private static ValueNode searchForConstantLength(ConstantReflectionProvider constantReflection, ValueNode forValue) { + ValueNode len = GraphUtil.arrayLength(forValue, ArrayLengthProvider.FindLengthMode.SEARCH_ONLY, constantReflection); return len != null && len.isConstant() ? len : null; } @@ -133,7 +133,7 @@ public void simplify(SimplifierTool tool) { * guarded pi can be done in multiple places and we only want to do it once for all users, * so we let it be done after lowering to catch all users at once. */ - ValueNode constantLength = searchForConstantLength(tool.getConstantReflection()); + ValueNode constantLength = searchForConstantLength(tool.getConstantReflection(), getValue()); if (constantLength == null && !graph().isAfterStage(StageFlag.HIGH_TIER_LOWERING)) { return; } From 7ee35d481032cdf5f29b11a8a0ef79908369b486 Mon Sep 17 00:00:00 2001 From: Gilles Duboscq Date: Fri, 20 Oct 2023 15:01:52 +0200 Subject: [PATCH 424/593] Decouple ESPRESSO_JAVA_HOME from JAVA_HOME ESPRESSO_JAVA_HOME is used to provide the runtime files for the guest. ESPRESSO_LLVM_JAVA_HOME is also supported for consistency. --- espresso/mx.espresso/mx_espresso.py | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/espresso/mx.espresso/mx_espresso.py b/espresso/mx.espresso/mx_espresso.py index fed448a282d8..831a8382d2f3 100644 --- a/espresso/mx.espresso/mx_espresso.py +++ b/espresso/mx.espresso/mx_espresso.py @@ -36,7 +36,7 @@ _suite = mx.suite('espresso') # JDK compiled with the Sulong toolchain. -LLVM_JAVA_HOME = mx.get_env('LLVM_JAVA_HOME') +ESPRESSO_LLVM_JAVA_HOME = mx.get_env('ESPRESSO_LLVM_JAVA_HOME') or mx.get_env('LLVM_JAVA_HOME') def _espresso_command(launcher, args): bin_dir = join(mx_sdk_vm.graalvm_home(fatalIfMissing=True), 'bin') @@ -242,7 +242,7 @@ def _espresso_gate_runner(args, tasks): standalone=False, )) -if LLVM_JAVA_HOME: +if ESPRESSO_LLVM_JAVA_HOME: mx_sdk_vm.register_graalvm_component(mx_sdk_vm.GraalVmLanguage( suite=_suite, name='Java on Truffle LLVM Java libraries', @@ -252,7 +252,7 @@ def _espresso_gate_runner(args, tasks): truffle_jars=[], dir_name='java', installable_id='espresso-llvm', - extra_installable_qualifiers=mx_sdk_vm.extra_installable_qualifiers(jdk_home=LLVM_JAVA_HOME, ce_edition=['ce'], oracle_edition=['ee']), + extra_installable_qualifiers=mx_sdk_vm.extra_installable_qualifiers(jdk_home=ESPRESSO_LLVM_JAVA_HOME, ce_edition=['ce'], oracle_edition=['ee']), installable=True, dependencies=['Java on Truffle', 'LLVM Runtime Native'], support_distributions=['espresso:ESPRESSO_LLVM_SUPPORT'], @@ -274,27 +274,27 @@ def mx_register_dynamic_suite_constituents(register_project, register_distributi :type register_distribution: (mx.Distribution) -> None """ - if LLVM_JAVA_HOME: + if ESPRESSO_LLVM_JAVA_HOME: # Conditionally creates the ESPRESSO_LLVM_SUPPORT distribution if a Java home with LLVM bitcode is provided. lib_prefix = mx.add_lib_prefix('') lib_suffix = mx.add_lib_suffix('') - lib_path = join(LLVM_JAVA_HOME, 'lib') - libraries = [join(lib_path, name) for name in os.listdir(lib_path) if name.startswith(lib_prefix) and name.endswith(lib_suffix)] register_distribution(mx.LayoutTARDistribution(_suite, 'ESPRESSO_LLVM_SUPPORT', [], { - "lib/llvm/default/": - ["file:" + lib for lib in libraries] + - ["file:{}/release".format(LLVM_JAVA_HOME)], - }, None, True, _jdk_license(LLVM_JAVA_HOME))) + "lib/llvm/default/": [ + f"dependency:LLVM_JAVA_HOME/lib/{lib_prefix}*{lib_suffix}", + "dependency:LLVM_JAVA_HOME/release" + ], + }, None, True, _jdk_license(ESPRESSO_LLVM_JAVA_HOME))) llvm_runtime_dir = { "source_type": "dependency", "dependency": "LLVM_JAVA_HOME", "path": "lib/", } - register_project(JavaHomeDependency(_suite, "LLVM_JAVA_HOME", LLVM_JAVA_HOME)) + register_project(JavaHomeDependency(_suite, "LLVM_JAVA_HOME", ESPRESSO_LLVM_JAVA_HOME)) else: llvm_runtime_dir = [] - register_project(JavaHomeDependency(_suite, "JAVA_HOME", mx_sdk_vm.base_jdk().home)) + ESPRESSO_JAVA_HOME = mx.get_env('ESPRESSO_JAVA_HOME') or mx_sdk_vm.base_jdk().home + register_project(JavaHomeDependency(_suite, "JAVA_HOME", ESPRESSO_JAVA_HOME)) if mx.is_windows(): platform_specific_excludes = [ "bin/", @@ -436,7 +436,7 @@ def register_espresso_envs(suite): # pylint: disable=line-too-long tools = ['cov', 'dap', 'ins', 'insight', 'insightheap', 'lsp', 'pro', 'truffle-json'] _llvm_toolchain_wrappers = ['bgraalvm-native-clang', 'bgraalvm-native-clang-cl', 'bgraalvm-native-clang++', 'bgraalvm-native-flang', 'bgraalvm-native-ld', 'bgraalvm-native-binutil'] - if LLVM_JAVA_HOME: + if ESPRESSO_LLVM_JAVA_HOME: mx_sdk_vm.register_vm_config('espresso-jvm', ['java', 'ejvm' , 'ellvm', 'libpoly', 'nfi-libffi', 'nfi', 'sdk', 'sdkni', 'sdkc', 'sdkl', 'tfl', 'tfla', 'tflc' , 'cmp', 'antlr4', 'llrc', 'llrlf', 'llrn' , 'elau' ] + tools, suite, env_file='jvm-llvm') mx_sdk_vm.register_vm_config('espresso-jvm-ce', ['java', 'ejvm' , 'ellvm', 'libpoly', 'nfi-libffi', 'nfi', 'sdk', 'sdkni', 'sdkc', 'sdkl', 'tfl', 'tfla', 'tflc' , 'cmp', 'antlr4', 'llrc', 'llrlf', 'llrn' , 'svm', 'svmt' , 'svmsl' , 'tflm', 'elau', 'lg', 'bespresso', 'sjavavm', 'spolyglot'] + _llvm_toolchain_wrappers + tools, suite, env_file='jvm-ce-llvm') mx_sdk_vm.register_vm_config('espresso-jvm-ee', ['java', 'ejvm' , 'ellvm', 'libpoly', 'nfi-libffi', 'nfi', 'sdk', 'sdkni', 'sdkc', 'sdkl', 'tfl', 'tfla', 'tflc', 'tfle', 'cmp', 'antlr4', 'llrc', 'llrlf', 'llrn', 'cmpee', 'svm', 'svmt', 'svmee', 'svmte', 'svmsl', 'tflllm', 'tflm', 'elau', 'lg', 'bespresso', 'sjavavm', 'spolyglot'] + _llvm_toolchain_wrappers + tools, suite, env_file='jvm-ee-llvm') From 58f66b19daaf2553b65df598016ed9b825e9460a Mon Sep 17 00:00:00 2001 From: Jakub Chaloupka Date: Thu, 11 Jan 2024 14:07:53 +0100 Subject: [PATCH 425/593] Make ContextPolicyTest#testOptionDescriptorContextReuse more robust. --- .../api/test/polyglot/ContextPolicyTest.java | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/truffle/src/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/polyglot/ContextPolicyTest.java b/truffle/src/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/polyglot/ContextPolicyTest.java index 233046980799..32d648d5cb32 100644 --- a/truffle/src/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/polyglot/ContextPolicyTest.java +++ b/truffle/src/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/polyglot/ContextPolicyTest.java @@ -316,11 +316,19 @@ public void testOptionDescriptorContextReuse() { remoteAssert(engine, AssertType.LANGUAGE_INSTANCES_COUNT, 1); context0.close(); - Context.newBuilder().engine(engine).build().initialize(REUSE0); - remoteAssert(engine, AssertType.LANGUAGE_INSTANCES_COUNT, 1); + try (Context ctx1 = Context.newBuilder().engine(engine).build()) { + ctx1.initialize(REUSE0); + remoteAssert(engine, AssertType.LANGUAGE_INSTANCES_COUNT, 1); - Context.newBuilder().engine(engine).build().initialize(REUSE0); - remoteAssert(engine, AssertType.LANGUAGE_INSTANCES_COUNT, 2); + /* + * Nesting the try-with-resources makes sure ctx1 is not collected by the garbage + * collector before ctx2 is created. + */ + try (Context ctx2 = Context.newBuilder().engine(engine).build()) { + ctx2.initialize(REUSE0); + remoteAssert(engine, AssertType.LANGUAGE_INSTANCES_COUNT, 2); + } + } engine.close(); From 7ff095a8446c03dfa363c996fdf10d5e8f69193a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gerg=C3=B6=20Barany?= Date: Thu, 11 Jan 2024 14:24:32 +0100 Subject: [PATCH 426/593] Fix bounds computation for floating point conversion --- .../replacements/amd64/AMD64FloatConvertNode.java | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/replacements/amd64/AMD64FloatConvertNode.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/replacements/amd64/AMD64FloatConvertNode.java index a4cecf4f4652..e6f4f877c1c3 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/replacements/amd64/AMD64FloatConvertNode.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/replacements/amd64/AMD64FloatConvertNode.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2024, 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 @@ -108,10 +108,10 @@ public Stamp foldStamp(Stamp newStamp) { * * We must ensure during stamp folding the special cases are considered and accounted for. */ - if (resultStamp instanceof IntegerStamp && newStamp instanceof FloatStamp inputStamp) { + if (resultStamp instanceof IntegerStamp integerStamp && newStamp instanceof FloatStamp inputStamp) { final boolean canBeNan = inputStamp.canBeNaN(); final boolean canBeInfinity = Double.isInfinite(inputStamp.lowerBound()) || Double.isInfinite(inputStamp.upperBound()); - final boolean conversionCanOverflow = integralPartLargerMaxValue(inputStamp) || integralPartSmallerMinValue(inputStamp); + final boolean conversionCanOverflow = integralPartLargerMaxValue(inputStamp, integerStamp) || integralPartSmallerMinValue(inputStamp, integerStamp); final boolean canGenerateSpecialValue = canBeNan || canBeInfinity || conversionCanOverflow; if (canGenerateSpecialValue) { return resultStamp.meet(createInexactCaseStamp()); @@ -123,12 +123,12 @@ public Stamp foldStamp(Stamp newStamp) { } } - private static boolean integralPartLargerMaxValue(FloatStamp stamp) { + private static boolean integralPartLargerMaxValue(FloatStamp stamp, IntegerStamp integerStamp) { double upperBound = stamp.upperBound(); if (Double.isInfinite(upperBound) || Double.isNaN(upperBound)) { return true; } - int bits = stamp.getBits(); + int bits = integerStamp.getBits(); assert bits == 32 || bits == 64 : "Must be int or long " + Assertions.errorMessage(stamp, upperBound); long maxValue = NumUtil.maxValue(bits); /* @@ -146,12 +146,12 @@ private static boolean integralPartLargerMaxValue(FloatStamp stamp) { return upperBound >= maxValue; } - private static boolean integralPartSmallerMinValue(FloatStamp stamp) { + private static boolean integralPartSmallerMinValue(FloatStamp stamp, IntegerStamp integerStamp) { double lowerBound = stamp.lowerBound(); if (Double.isInfinite(lowerBound) || Double.isNaN(lowerBound)) { return true; } - int bits = stamp.getBits(); + int bits = integerStamp.getBits(); assert bits == 32 || bits == 64 : "Must be int or long " + Assertions.errorMessage(stamp, lowerBound); long minValue = NumUtil.minValue(bits); return lowerBound <= minValue; From 8a4b31ddf4a6afe9bcb0271483aa49f8179bc139 Mon Sep 17 00:00:00 2001 From: Christian Humer Date: Thu, 11 Jan 2024 17:50:54 +0100 Subject: [PATCH 427/593] Fix corner case where cached fields should not be generated for createCachedFields to avoid compiler warnings. --- .../truffle/api/dsl/test/GR51148Test.java | 126 ++++++++++++++++++ .../generator/FlatNodeGenFactory.java | 28 ++-- 2 files changed, 144 insertions(+), 10 deletions(-) create mode 100644 truffle/src/com.oracle.truffle.api.dsl.test/src/com/oracle/truffle/api/dsl/test/GR51148Test.java diff --git a/truffle/src/com.oracle.truffle.api.dsl.test/src/com/oracle/truffle/api/dsl/test/GR51148Test.java b/truffle/src/com.oracle.truffle.api.dsl.test/src/com/oracle/truffle/api/dsl/test/GR51148Test.java new file mode 100644 index 000000000000..05924ea4af73 --- /dev/null +++ b/truffle/src/com.oracle.truffle.api.dsl.test/src/com/oracle/truffle/api/dsl/test/GR51148Test.java @@ -0,0 +1,126 @@ +/* + * Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * The Universal Permissive License (UPL), Version 1.0 + * + * Subject to the condition set forth below, permission is hereby granted to any + * person obtaining a copy of this software, associated documentation and/or + * data (collectively the "Software"), free of charge and under any and all + * copyright rights in the Software, and any and all patent rights owned or + * freely licensable by each licensor hereunder covering either (i) the + * unmodified Software as contributed to or provided by such licensor, or (ii) + * the Larger Works (as defined below), to deal in both + * + * (a) the Software, and + * + * (b) any piece of software and/or hardware listed in the lrgrwrks.txt file if + * one is included with the Software each a "Larger Work" to which the Software + * is contributed by such licensors), + * + * without restriction, including without limitation the rights to copy, create + * derivative works of, display, perform, and distribute the Software and make, + * use, sell, offer for sale, import, export, have made, and have sold the + * Software and the Larger Work(s), and to sublicense the foregoing rights on + * either these or other terms. + * + * This license is subject to the following condition: + * + * The above copyright notice and either this complete permission notice or at a + * minimum a reference to the UPL must be included in all copies or substantial + * portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.oracle.truffle.api.dsl.test; + +import com.oracle.truffle.api.dsl.Bind; +import com.oracle.truffle.api.dsl.Cached; +import com.oracle.truffle.api.dsl.Cached.Exclusive; +import com.oracle.truffle.api.dsl.Cached.Shared; +import com.oracle.truffle.api.dsl.Specialization; +import com.oracle.truffle.api.nodes.Node; +import com.oracle.truffle.api.profiles.ConditionProfile; +import com.oracle.truffle.api.profiles.InlinedConditionProfile; + +/* + * This test fails by emitting a warning in the generated code. + * It passes if no warning is emitted. + */ +public class GR51148Test { + + @SuppressWarnings({"truffle", "unused"}) + abstract static class TestNode extends Node { + + abstract Object execute(Object arg); + + @Specialization(guards = "arg0 == 0") + Object s0(int arg0, + @Bind("this") Node node, + @Cached @Shared InlinedConditionProfile profile0, + @Cached @Exclusive InlinedConditionProfile cachedProfile0, + // use a number of cached profiles to force trigger a specialization data + // class + @Cached @Exclusive ConditionProfile cachedProfile1, + @Cached @Exclusive ConditionProfile cachedProfile2, + @Cached @Exclusive ConditionProfile cachedProfile3, + @Cached @Exclusive ConditionProfile cachedProfile4, + @Cached @Exclusive ConditionProfile cachedProfile5, + @Cached @Exclusive ConditionProfile cachedProfile6, + @Cached @Exclusive ConditionProfile cachedProfile7, + @Cached @Exclusive ConditionProfile cachedProfile8, + @Cached @Exclusive ConditionProfile cachedProfile9, + @Cached @Exclusive ConditionProfile cachedProfile10, + @Cached @Exclusive ConditionProfile cachedProfile11) { + profile0.profile(this, arg0 == 0); + return arg0; + } + + /* + * This specialization triggers a data class, before the fix this was emitting an error + * requiring @Bind("this") to bind the inlining target. But in this case "this" can safely + * be used. + */ + @SuppressWarnings("truffle-interpreted-performance") + @Specialization(guards = "arg0 == 1") + Object s1(int arg0, + @Bind("this") Node node, + @Cached @Shared InlinedConditionProfile profile0, + @Cached @Exclusive InlinedConditionProfile cachedProfile0, + @Cached @Exclusive ConditionProfile cachedProfile1, + @Cached @Exclusive ConditionProfile cachedProfile2, + @Cached @Exclusive ConditionProfile cachedProfile3, + @Cached @Exclusive ConditionProfile cachedProfile4, + @Cached @Exclusive ConditionProfile cachedProfile5) { + profile0.profile(this, arg0 == 1); + return arg0; + } + + /* + * This specialization triggers a data class, before the fix this was emitting an error + * requiring @Bind("this") to bind the inlining target. But in this case "this" can safely + * be used. + */ + @SuppressWarnings("truffle-interpreted-performance") + @Specialization(guards = "arg0 == 2") + Object s2(int arg0, + @Bind("this") Node node, + @Cached @Shared InlinedConditionProfile profile0, + @Cached @Exclusive InlinedConditionProfile cachedProfile0, + @Cached @Exclusive ConditionProfile cachedProfile1, + @Cached @Exclusive ConditionProfile cachedProfile2, + @Cached @Exclusive ConditionProfile cachedProfile3, + @Cached @Exclusive ConditionProfile cachedProfile4, + @Cached @Exclusive ConditionProfile cachedProfile5) { + profile0.profile(this, arg0 == 1); + return arg0; + } + } + +} diff --git a/truffle/src/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/generator/FlatNodeGenFactory.java b/truffle/src/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/generator/FlatNodeGenFactory.java index 3a3d4972a374..db0f9dc56f34 100644 --- a/truffle/src/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/generator/FlatNodeGenFactory.java +++ b/truffle/src/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/generator/FlatNodeGenFactory.java @@ -1883,7 +1883,6 @@ private List createCachedFields(CodeTypeElement baseType) { continue; } expressions.add(fieldName); - createCachedFieldsImpl(nodeElements, nodeElements, null, null, cache, true); } } @@ -2180,6 +2179,11 @@ private void createCachedFieldsImpl( } CacheExpression sharedCache = lookupSharedCacheKey(cache); InlinedNodeData inline = sharedCache.getInlinedNode(); + /* + * Handles corner case where we try to avoid generating shared cached fields if we are + * always using parent access cache for a shared cache. + */ + boolean generateCachedFields = specialization != null || !hasCacheParentAccess(cache) || hasSharedCacheDirectAccess(lookupSharedCacheKey(cache)); if (inline != null) { Parameter parameter = cache.getParameter(); @@ -2194,14 +2198,16 @@ private void createCachedFieldsImpl( for (InlineFieldData field : inline.getFields()) { builder.startGroup(); if (field.isState()) { - BitSet specializationBitSet = findInlinedState(specializationState, field); - CodeVariableElement updaterField = createStateUpdaterField(specialization, specializationState, field, specializationClassElements); - String updaterFieldName = updaterField.getName(); - builder.startCall(updaterFieldName, "subUpdater"); - BitRange range = specializationBitSet.getStates().queryRange(StateQuery.create(InlinedNodeState.class, field)); - builder.string(String.valueOf(range.offset)); - builder.string(String.valueOf(range.length)); - builder.end(); + if (generateCachedFields) { + BitSet specializationBitSet = findInlinedState(specializationState, field); + CodeVariableElement updaterField = createStateUpdaterField(specialization, specializationState, field, specializationClassElements); + String updaterFieldName = updaterField.getName(); + builder.startCall(updaterFieldName, "subUpdater"); + BitRange range = specializationBitSet.getStates().queryRange(StateQuery.create(InlinedNodeState.class, field)); + builder.string(String.valueOf(range.offset)); + builder.string(String.valueOf(range.length)); + builder.end(); + } } else { /* * All other fields need fields to get inlined. We do not support specialization @@ -2265,7 +2271,9 @@ private void createCachedFieldsImpl( addSourceDoc(javadoc, specialization, cache, null); javadoc.end(); - nodeElements.add(cachedField); + if (generateCachedFields) { + nodeElements.add(cachedField); + } } else { Parameter parameter = cache.getParameter(); String fieldName = createFieldName(specialization, cache); From f43fa96d5730b3a8efb4a620044dbe89dcc6b5b4 Mon Sep 17 00:00:00 2001 From: Raphael Mosaner Date: Thu, 11 Jan 2024 09:00:18 +0100 Subject: [PATCH 428/593] [GR-51027] Aarch: Add means for post-processing code after emitting from LIR. --- .../graal/compiler/lir/asm/CompilationResultBuilder.java | 8 ++++++++ .../svm/core/graal/aarch64/SubstrateAArch64Backend.java | 7 +++++++ 2 files changed, 15 insertions(+) diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/asm/CompilationResultBuilder.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/asm/CompilationResultBuilder.java index bd3c9f4da803..b2928d745636 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/asm/CompilationResultBuilder.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/asm/CompilationResultBuilder.java @@ -705,6 +705,14 @@ public void setConservativeLabelRanges() { this.conservativeLabelOffsets = true; } + /** + * Query, whether this {@link CompilationResultBuilder} uses conservative label ranges. This + * allows for larger jump distances at the cost of increased code size. + */ + public boolean usesConservativeLabelRanges() { + return this.conservativeLabelOffsets; + } + public final boolean needsClearUpperVectorRegisters() { for (int blockId : lir.getBlocks()) { if (LIR.isBlockDeleted(blockId)) { diff --git a/substratevm/src/com.oracle.svm.core.graal.aarch64/src/com/oracle/svm/core/graal/aarch64/SubstrateAArch64Backend.java b/substratevm/src/com.oracle.svm.core.graal.aarch64/src/com/oracle/svm/core/graal/aarch64/SubstrateAArch64Backend.java index d237fb640257..1665ea46e290 100755 --- a/substratevm/src/com.oracle.svm.core.graal.aarch64/src/com/oracle/svm/core/graal/aarch64/SubstrateAArch64Backend.java +++ b/substratevm/src/com.oracle.svm.core.graal.aarch64/src/com/oracle/svm/core/graal/aarch64/SubstrateAArch64Backend.java @@ -1325,6 +1325,7 @@ public void emitCode(CompilationResultBuilder crb, ResolvedJavaMethod installedC try { crb.buildLabelOffsets(); crb.emitLIR(); + finalizeCode(crb); } catch (BranchTargetOutOfBoundsException e) { // A branch estimation was wrong, now retry with conservative label ranges, this // should always work @@ -1332,9 +1333,15 @@ public void emitCode(CompilationResultBuilder crb, ResolvedJavaMethod installedC crb.setConservativeLabelRanges(); crb.resetForEmittingCode(); crb.emitLIR(); + finalizeCode(crb); } } + @SuppressWarnings("unused") + protected void finalizeCode(CompilationResultBuilder crb) { + + } + @SuppressWarnings("unused") protected void resetForEmittingCode(CompilationResultBuilder crb) { From a8d8921fd786bac790625a7497c419d32bf1b4f4 Mon Sep 17 00:00:00 2001 From: Danilo Ansaloni Date: Mon, 8 Jan 2024 15:28:25 +0100 Subject: [PATCH 429/593] Update mx import. --- common.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/common.json b/common.json index 9757335d1d1c..b182a7c4844d 100644 --- a/common.json +++ b/common.json @@ -4,7 +4,7 @@ "Jsonnet files should not include this file directly but use ci/common.jsonnet instead." ], - "mx_version": "7.5.2", + "mx_version": "7.6.1", "COMMENT.jdks": "When adding or removing JDKs keep in sync with JDKs in ci/common.jsonnet", "jdks": { From 672e0674c22b82a9b615892e35e0922ceedc23b3 Mon Sep 17 00:00:00 2001 From: Codrut Stancu Date: Fri, 5 Jan 2024 15:18:14 +0100 Subject: [PATCH 430/593] Update scanning trace message. --- .../oracle/graal/pointsto/ObjectScanner.java | 37 ++++++++++++++----- .../graal/pointsto/heap/ImageHeapScanner.java | 9 +++-- 2 files changed, 32 insertions(+), 14 deletions(-) diff --git a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/ObjectScanner.java b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/ObjectScanner.java index 7e09be8fa42f..7122eeb5ca9e 100644 --- a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/ObjectScanner.java +++ b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/ObjectScanner.java @@ -552,20 +552,37 @@ public String toString() { public static class FieldScan extends ScanReason { final AnalysisField field; - private static ScanReason previous(AnalysisField field) { - Object readBy = field.getReadBy(); - if (readBy instanceof BytecodePosition) { - ResolvedJavaMethod readingMethod = ((BytecodePosition) readBy).getMethod(); - return new MethodParsing((AnalysisMethod) readingMethod); - } else if (readBy instanceof AnalysisMethod) { - return new MethodParsing((AnalysisMethod) readBy); + private static ScanReason previous(AnalysisField field, JavaConstant receiver) { + /* + * Since there is no previous reason we try to infer one either from the receiver + * constant or from the field read-by reason. + */ + Object reason; + if (receiver instanceof ImageHeapConstant heapConstant) { + AnalysisError.guarantee(heapConstant.isReachable()); + reason = heapConstant.getReachableReason(); } else { - return new OtherReason("registered as read because: " + readBy); + reason = field.getReadBy(); + } + if (reason instanceof ScanReason scanReason) { + return scanReason; + } else if (reason instanceof BytecodePosition position) { + ResolvedJavaMethod readingMethod = position.getMethod(); + return new MethodParsing((AnalysisMethod) readingMethod); + } else if (reason instanceof AnalysisMethod method) { + return new MethodParsing(method); + } else if (reason != null) { + return new OtherReason("registered as read because: " + reason); } + return null; } public FieldScan(AnalysisField field) { - this(field, null, previous(field)); + this(field, null, previous(field, null)); + } + + public FieldScan(AnalysisField field, JavaConstant receiver) { + this(field, receiver, previous(field, receiver)); } public FieldScan(AnalysisField field, JavaConstant receiver, ScanReason previous) { @@ -718,7 +735,7 @@ public AnalysisMethod getMethod() { @Override public String toString(BigBang bb) { - return "scanning root " + asString(bb, constant) + " embedded in " + System.lineSeparator() + INDENTATION_AFTER_NEWLINE + asStackTraceElement(); + return "scanning root " + asString(bb, constant) + " embedded in" + System.lineSeparator() + INDENTATION_AFTER_NEWLINE + asStackTraceElement(); } @Override diff --git a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/heap/ImageHeapScanner.java b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/heap/ImageHeapScanner.java index 939849b0368c..5c415109cd59 100644 --- a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/heap/ImageHeapScanner.java +++ b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/heap/ImageHeapScanner.java @@ -122,9 +122,9 @@ public void scanEmbeddedRoot(JavaConstant root, BytecodePosition position) { public void onFieldRead(AnalysisField field) { assert field.isRead() : field; /* Check if the value is available before accessing it. */ - FieldScan reason = new FieldScan(field); AnalysisType declaringClass = field.getDeclaringClass(); if (field.isStatic()) { + FieldScan reason = new FieldScan(field); if (isValueAvailable(field)) { JavaConstant fieldValue = readStaticFieldValue(field); markReachable(fieldValue, reason); @@ -134,19 +134,20 @@ public void onFieldRead(AnalysisField field) { } } else { /* Trigger field scanning for the already processed objects. */ - postTask(() -> onInstanceFieldRead(field, declaringClass, reason)); + postTask(() -> onInstanceFieldRead(field, declaringClass)); } } - private void onInstanceFieldRead(AnalysisField field, AnalysisType type, FieldScan reason) { + private void onInstanceFieldRead(AnalysisField field, AnalysisType type) { for (AnalysisType subtype : type.getSubTypes()) { for (ImageHeapConstant imageHeapConstant : imageHeap.getReachableObjects(subtype)) { + FieldScan reason = new FieldScan(field, imageHeapConstant); ImageHeapInstance imageHeapInstance = (ImageHeapInstance) imageHeapConstant; updateInstanceField(field, imageHeapInstance, reason, null); } /* Subtypes include this type itself. */ if (!subtype.equals(type)) { - onInstanceFieldRead(field, subtype, reason); + onInstanceFieldRead(field, subtype); } } } From 938112365b455fcc11fd31412e0ddd728f0a70b0 Mon Sep 17 00:00:00 2001 From: Christian Wimmer Date: Wed, 10 Jan 2024 14:44:44 -0800 Subject: [PATCH 431/593] Cleanup registerAsUnsafeAccessed --- .../StandaloneAnalysisFeatureImpl.java | 13 +++-------- .../graal/pointsto/PointsToAnalysis.java | 8 ++++++- .../graal/pointsto/ReachabilityAnalysis.java | 22 ------------------- .../graal/pointsto/meta/AnalysisField.java | 4 ++-- .../pointsto/meta/PointsToAnalysisField.java | 1 + .../ReachabilityAnalysisEngine.java | 4 ---- .../com/oracle/svm/hosted/FeatureImpl.java | 4 ++-- .../SubstrateGraphBuilderPlugins.java | 9 ++++---- .../AnnotationSubstitutionProcessor.java | 1 - .../AutomaticUnsafeTransformationSupport.java | 3 +-- 10 files changed, 20 insertions(+), 49 deletions(-) diff --git a/substratevm/src/com.oracle.graal.pointsto.standalone/src/com/oracle/graal/pointsto/standalone/features/StandaloneAnalysisFeatureImpl.java b/substratevm/src/com.oracle.graal.pointsto.standalone/src/com/oracle/graal/pointsto/standalone/features/StandaloneAnalysisFeatureImpl.java index c4edb1cec953..479811444ec3 100644 --- a/substratevm/src/com.oracle.graal.pointsto.standalone/src/com/oracle/graal/pointsto/standalone/features/StandaloneAnalysisFeatureImpl.java +++ b/substratevm/src/com.oracle.graal.pointsto.standalone/src/com/oracle/graal/pointsto/standalone/features/StandaloneAnalysisFeatureImpl.java @@ -38,7 +38,6 @@ import java.util.function.Consumer; import java.util.stream.Collectors; -import jdk.graal.compiler.debug.DebugContext; import org.graalvm.nativeimage.hosted.Feature; import org.graalvm.nativeimage.hosted.FieldValueTransformer; @@ -51,6 +50,8 @@ import com.oracle.graal.pointsto.standalone.StandaloneHost; import com.oracle.svm.util.UnsafePartitionKind; +import jdk.graal.compiler.debug.DebugContext; + public class StandaloneAnalysisFeatureImpl { public abstract static class FeatureAccessImpl implements Feature.FeatureAccess { @@ -207,11 +208,7 @@ public void registerAsUnsafeAccessed(Field field) { public boolean registerAsUnsafeAccessed(AnalysisField aField, Object reason) { if (!aField.isUnsafeAccessed()) { - /* Register the field as unsafe accessed. */ - aField.registerAsAccessed(reason); aField.registerAsUnsafeAccessed(reason); - /* Force the update of registered unsafe loads and stores. */ - bb.forceUnsafeUpdate(aField); return true; } return false; @@ -222,7 +219,7 @@ public void registerAsFrozenUnsafeAccessed(Field field) { } public void registerAsFrozenUnsafeAccessed(AnalysisField aField) { - aField.setUnsafeFrozenTypeState(true); + aField.registerAsFrozenUnsafeAccessed(); registerAsUnsafeAccessed(aField, "registered from standalone feature"); } @@ -232,11 +229,7 @@ public void registerAsUnsafeAccessed(Field field, UnsafePartitionKind partitionK public void registerAsUnsafeAccessed(AnalysisField aField, UnsafePartitionKind partitionKind, Object reason) { if (!aField.isUnsafeAccessed()) { - /* Register the field as unsafe accessed. */ - aField.registerAsAccessed(reason); aField.registerAsUnsafeAccessed(partitionKind, reason); - /* Force the update of registered unsafe loads and stores. */ - bb.forceUnsafeUpdate(aField); } } diff --git a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/PointsToAnalysis.java b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/PointsToAnalysis.java index b73e61f43d62..9a3e534064e1 100644 --- a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/PointsToAnalysis.java +++ b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/PointsToAnalysis.java @@ -184,7 +184,13 @@ public void registerUnsafeStore(AbstractUnsafeStoreTypeFlow unsafeStore) { unsafeStores.putIfAbsent(unsafeStore, true); } - @Override + /** + * Force update of the unsafe loads and unsafe store type flows when a field is registered as + * unsafe accessed 'on the fly', i.e., during the analysis. + * + * @param field the newly unsafe registered field. We use its declaring type to filter the + * unsafe access flows that need to be updated. + */ public void forceUnsafeUpdate(AnalysisField field) { /* * It is cheaper to post the flows of all loads and stores even if they are not related to diff --git a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/ReachabilityAnalysis.java b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/ReachabilityAnalysis.java index ba0296d28a84..2575560d1604 100644 --- a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/ReachabilityAnalysis.java +++ b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/ReachabilityAnalysis.java @@ -33,7 +33,6 @@ import com.oracle.graal.pointsto.meta.AnalysisType; import com.oracle.graal.pointsto.meta.AnalysisUniverse; import com.oracle.svm.common.meta.MultiMethod; -import com.oracle.svm.util.UnsafePartitionKind; /** * Interface to be used to query and change the state of the static analysis in Native Image. @@ -100,18 +99,6 @@ public interface ReachabilityAnalysis { */ AnalysisMethod forcedAddRootMethod(Executable method, boolean invokeSpecial, Object reason, MultiMethod.MultiMethodKey... otherRoots); - default void registerAsFrozenUnsafeAccessed(AnalysisField field) { - field.setUnsafeFrozenTypeState(true); - } - - default boolean registerAsUnsafeAccessed(AnalysisField field, UnsafePartitionKind partitionKind, Object reason) { - if (field.registerAsUnsafeAccessed(partitionKind, reason)) { - forceUnsafeUpdate(field); - return true; - } - return false; - } - default boolean registerTypeAsReachable(AnalysisType type, Object reason) { return type.registerAsReachable(reason); } @@ -146,15 +133,6 @@ default void markFieldWritten(AnalysisField field, Object reason) { */ void cleanupAfterAnalysis(); - /** - * Force update of the unsafe loads and unsafe store type flows when a field is registered as - * unsafe accessed 'on the fly', i.e., during the analysis. - * - * @param field the newly unsafe registered field. We use its declaring type to filter the - * unsafe access flows that need to be updated. - */ - void forceUnsafeUpdate(AnalysisField field); - /** * Performs any necessary additional steps required by the analysis to handle JNI accessed * fields. diff --git a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/meta/AnalysisField.java b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/meta/AnalysisField.java index d9feb2ba3ee8..1d01ba061882 100644 --- a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/meta/AnalysisField.java +++ b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/meta/AnalysisField.java @@ -379,8 +379,8 @@ public boolean isJNIAccessed() { return isJNIAccessed; } - public void setUnsafeFrozenTypeState(boolean value) { - unsafeFrozenTypeStateUpdater.set(this, value ? 1 : 0); + public void registerAsFrozenUnsafeAccessed() { + unsafeFrozenTypeStateUpdater.set(this, 1); } public boolean hasUnsafeFrozenTypeState() { diff --git a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/meta/PointsToAnalysisField.java b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/meta/PointsToAnalysisField.java index cc3ae97f8775..042bd2743d58 100644 --- a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/meta/PointsToAnalysisField.java +++ b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/meta/PointsToAnalysisField.java @@ -91,6 +91,7 @@ public boolean registerAsUnsafeAccessed(UnsafePartitionKind partitionKind, Objec */ saturatePrimitiveField(); } + ((PointsToAnalysis) getUniverse().getBigbang()).forceUnsafeUpdate(this); return true; } return false; diff --git a/substratevm/src/com.oracle.graal.reachability/src/com/oracle/graal/reachability/ReachabilityAnalysisEngine.java b/substratevm/src/com.oracle.graal.reachability/src/com/oracle/graal/reachability/ReachabilityAnalysisEngine.java index 60662dc50802..2be520237399 100644 --- a/substratevm/src/com.oracle.graal.reachability/src/com/oracle/graal/reachability/ReachabilityAnalysisEngine.java +++ b/substratevm/src/com.oracle.graal.reachability/src/com/oracle/graal/reachability/ReachabilityAnalysisEngine.java @@ -353,10 +353,6 @@ private void computeCallers() { } - @Override - public void forceUnsafeUpdate(AnalysisField field) { - } - @Override public void registerAsJNIAccessed(AnalysisField field, boolean writable) { } diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/FeatureImpl.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/FeatureImpl.java index 102d0b5fec39..0cc128522760 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/FeatureImpl.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/FeatureImpl.java @@ -405,7 +405,7 @@ public void registerAsUnsafeAccessed(Field field, UnsafePartitionKind partitionK public boolean registerAsUnsafeAccessed(AnalysisField aField, UnsafePartitionKind partitionKind, Object reason) { assert !AnnotationAccess.isAnnotationPresent(aField, Delete.class); - return bb.registerAsUnsafeAccessed(aField, partitionKind, reason); + return aField.registerAsUnsafeAccessed(partitionKind, reason); } public void registerAsFrozenUnsafeAccessed(Field field, Object reason) { @@ -413,7 +413,7 @@ public void registerAsFrozenUnsafeAccessed(Field field, Object reason) { } public void registerAsFrozenUnsafeAccessed(AnalysisField aField, Object reason) { - bb.registerAsFrozenUnsafeAccessed(aField); + aField.registerAsFrozenUnsafeAccessed(); registerAsUnsafeAccessed(aField, reason); } diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/snippets/SubstrateGraphBuilderPlugins.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/snippets/SubstrateGraphBuilderPlugins.java index ce8d1b897abf..cc56e9bcf2b6 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/snippets/SubstrateGraphBuilderPlugins.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/snippets/SubstrateGraphBuilderPlugins.java @@ -714,12 +714,12 @@ private static void interceptUpdaterInvoke(GraphBuilderContext b, SnippetReflect String fieldName = snippetReflection.asObject(String.class, fieldNameNode.asJavaConstant()); try { Field field = tclass.getDeclaredField(fieldName); - // register the holder class and the field for reflection + /* + * Register the holder class and the field for reflection. This also registers the + * field for unsafe access. + */ RuntimeReflection.register(tclass); RuntimeReflection.register(field); - - // register the field for unsafe access - registerAsUnsafeAccessed(b, field); } catch (NoSuchFieldException e) { /* * Ignore the exception. If the field does not exist, there will be an error at run @@ -735,7 +735,6 @@ private static void interceptUpdaterInvoke(GraphBuilderContext b, SnippetReflect private static void registerAsUnsafeAccessed(GraphBuilderContext b, Field field) { AnalysisField targetField = (AnalysisField) b.getMetaAccess().lookupJavaField(field); Object reason = nonNullReason(b.getGraph().currentNodeSourcePosition()); - targetField.registerAsAccessed(reason); targetField.registerAsUnsafeAccessed(reason); } diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/substitute/AnnotationSubstitutionProcessor.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/substitute/AnnotationSubstitutionProcessor.java index 7752e66bf8f3..816c55b9262e 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/substitute/AnnotationSubstitutionProcessor.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/substitute/AnnotationSubstitutionProcessor.java @@ -313,7 +313,6 @@ public void processComputedValueFields(BigBang bb) { switch (cvField.getRecomputeValueKind()) { case FieldOffset: AnalysisField targetField = bb.getMetaAccess().lookupJavaField(cvField.getTargetField()); - targetField.registerAsAccessed(cvField); assert !AnnotationAccess.isAnnotationPresent(targetField, Delete.class); targetField.registerAsUnsafeAccessed(cvField); break; diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/substitute/AutomaticUnsafeTransformationSupport.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/substitute/AutomaticUnsafeTransformationSupport.java index 088511b32352..047b7029ca8e 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/substitute/AutomaticUnsafeTransformationSupport.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/substitute/AutomaticUnsafeTransformationSupport.java @@ -45,7 +45,6 @@ import org.graalvm.nativeimage.hosted.FieldValueTransformer; import com.oracle.graal.pointsto.BigBang; -import com.oracle.graal.pointsto.api.DefaultUnsafePartition; import com.oracle.graal.pointsto.phases.NoClassInitializationPlugin; import com.oracle.graal.pointsto.util.GraalAccess; import com.oracle.svm.core.ParsingReason; @@ -292,7 +291,7 @@ private void addTransformation(BigBang bb, ResolvedJavaField original, ComputedV } private static FieldOffsetFieldValueTransformer createFieldOffsetFieldValueTransformer(BigBang bb, ResolvedJavaField original, Field targetField) { - bb.postTask(debugContext -> bb.registerAsUnsafeAccessed(bb.getMetaAccess().lookupJavaField(targetField), DefaultUnsafePartition.get(), original)); + bb.postTask(debugContext -> bb.getMetaAccess().lookupJavaField(targetField).registerAsUnsafeAccessed(original)); return new FieldOffsetFieldValueTransformer(targetField, original.getType().getJavaKind().toJavaClass()); } From 3994e9b5d323e3cf908ba5f8cc1564d508c2591f Mon Sep 17 00:00:00 2001 From: Christian Wimmer Date: Mon, 8 Jan 2024 16:23:13 -0800 Subject: [PATCH 432/593] Introduce ImageHeapList --- .../core/posix/PosixVMSemaphoreSupport.java | 44 --- ...eFeature.java => DarwinVMLockSupport.java} | 56 +--- ...reFeature.java => LinuxVMLockSupport.java} | 56 +--- .../posix/pthread/PthreadVMLockSupport.java | 93 +------ .../core/windows/WindowsVMLockSupport.java | 98 +------ .../svm/core/locks/ClassInstanceReplacer.java | 22 +- .../locks/SingleThreadedVMLockSupport.java | 256 ------------------ .../oracle/svm/core/locks/VMLockSupport.java | 107 +++++--- .../com/oracle/svm/core/thread/VMThreads.java | 2 + .../oracle/svm/core/util/ImageHeapList.java | 150 ++++++++++ ...e.java => ImageHeapCollectionFeature.java} | 50 +++- .../svm/hosted/heap/SVMImageHeapVerifier.java | 6 +- 12 files changed, 308 insertions(+), 632 deletions(-) delete mode 100644 substratevm/src/com.oracle.svm.core.posix/src/com/oracle/svm/core/posix/PosixVMSemaphoreSupport.java rename substratevm/src/com.oracle.svm.core.posix/src/com/oracle/svm/core/posix/darwin/{DarwinVMSemaphoreFeature.java => DarwinVMLockSupport.java} (61%) rename substratevm/src/com.oracle.svm.core.posix/src/com/oracle/svm/core/posix/linux/{LinuxVMSemaphoreFeature.java => LinuxVMLockSupport.java} (58%) delete mode 100644 substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/locks/SingleThreadedVMLockSupport.java create mode 100644 substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/util/ImageHeapList.java rename substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/heap/{ImageHeapMapFeature.java => ImageHeapCollectionFeature.java} (65%) diff --git a/substratevm/src/com.oracle.svm.core.posix/src/com/oracle/svm/core/posix/PosixVMSemaphoreSupport.java b/substratevm/src/com.oracle.svm.core.posix/src/com/oracle/svm/core/posix/PosixVMSemaphoreSupport.java deleted file mode 100644 index cc1209d9545f..000000000000 --- a/substratevm/src/com.oracle.svm.core.posix/src/com/oracle/svm/core/posix/PosixVMSemaphoreSupport.java +++ /dev/null @@ -1,44 +0,0 @@ -/* - * Copyright (c) 2022, 2023, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -package com.oracle.svm.core.posix; - -import jdk.graal.compiler.api.replacements.Fold; -import org.graalvm.nativeimage.ImageSingletons; - -import com.oracle.svm.core.locks.VMSemaphore; - -/** - * Support of {@link VMSemaphore} in multithreaded environments. - */ -public abstract class PosixVMSemaphoreSupport { - - @Fold - public static PosixVMSemaphoreSupport singleton() { - return ImageSingletons.lookup(PosixVMSemaphoreSupport.class); - } - - public abstract VMSemaphore[] getSemaphores(); -} diff --git a/substratevm/src/com.oracle.svm.core.posix/src/com/oracle/svm/core/posix/darwin/DarwinVMSemaphoreFeature.java b/substratevm/src/com.oracle.svm.core.posix/src/com/oracle/svm/core/posix/darwin/DarwinVMLockSupport.java similarity index 61% rename from substratevm/src/com.oracle.svm.core.posix/src/com/oracle/svm/core/posix/darwin/DarwinVMSemaphoreFeature.java rename to substratevm/src/com.oracle.svm.core.posix/src/com/oracle/svm/core/posix/darwin/DarwinVMLockSupport.java index a8486fe713bd..00af899059df 100644 --- a/substratevm/src/com.oracle.svm.core.posix/src/com/oracle/svm/core/posix/darwin/DarwinVMSemaphoreFeature.java +++ b/substratevm/src/com.oracle.svm.core.posix/src/com/oracle/svm/core/posix/darwin/DarwinVMLockSupport.java @@ -27,66 +27,24 @@ import static com.oracle.svm.core.Uninterruptible.CALLED_FROM_UNINTERRUPTIBLE_CODE; -import org.graalvm.nativeimage.ImageSingletons; import org.graalvm.nativeimage.Platform; import org.graalvm.nativeimage.Platforms; import org.graalvm.nativeimage.StackValue; -import com.oracle.svm.core.BuildPhaseProvider.ReadyForCompilation; -import com.oracle.svm.core.SubstrateOptions; import com.oracle.svm.core.Uninterruptible; -import com.oracle.svm.core.feature.AutomaticallyRegisteredFeature; -import com.oracle.svm.core.feature.InternalFeature; -import com.oracle.svm.core.heap.UnknownObjectField; -import com.oracle.svm.core.locks.ClassInstanceReplacer; +import com.oracle.svm.core.feature.AutomaticallyRegisteredImageSingleton; +import com.oracle.svm.core.locks.VMLockSupport; import com.oracle.svm.core.locks.VMSemaphore; -import com.oracle.svm.core.posix.PosixVMSemaphoreSupport; import com.oracle.svm.core.posix.headers.darwin.DarwinVirtualMemory; import com.oracle.svm.core.posix.pthread.PthreadVMLockSupport; -/** - * Support of unnamed {@link VMSemaphore} in multithreaded environments on Darwin. Please note that - * POSIX unnamed semaphores are not supported on Darwin, so we need to use Darwin-specific - * implementations. - */ -@AutomaticallyRegisteredFeature -final class DarwinVMSemaphoreFeature implements InternalFeature { - - private final ClassInstanceReplacer semaphoreReplacer = new ClassInstanceReplacer<>(VMSemaphore.class) { - @Override - protected VMSemaphore createReplacement(VMSemaphore source) { - return new DarwinVMSemaphore(source.getName()); - } - }; - - @Override - public boolean isInConfiguration(IsInConfigurationAccess access) { - return SubstrateOptions.MultiThreaded.getValue(); - } - - @Override - public void duringSetup(DuringSetupAccess access) { - ImageSingletons.add(PosixVMSemaphoreSupport.class, new DarwinVMSemaphoreSupport()); - access.registerObjectReplacer(semaphoreReplacer); - } +@AutomaticallyRegisteredImageSingleton(VMLockSupport.class) +final class DarwinVMLockSupport extends PthreadVMLockSupport { @Override - public void beforeCompilation(BeforeCompilationAccess access) { - DarwinVMSemaphoreSupport semaphoreSupport = (DarwinVMSemaphoreSupport) PosixVMSemaphoreSupport.singleton(); - semaphoreSupport.semaphores = semaphoreReplacer.getReplacements().toArray(new DarwinVMSemaphore[0]); - } -} - -final class DarwinVMSemaphoreSupport extends PosixVMSemaphoreSupport { - - /** All semaphores, so that we can initialize them at run time when the VM starts. */ - @UnknownObjectField(availability = ReadyForCompilation.class) // - DarwinVMSemaphore[] semaphores; - - @Override - @Uninterruptible(reason = CALLED_FROM_UNINTERRUPTIBLE_CODE, mayBeInlined = true) - public VMSemaphore[] getSemaphores() { - return semaphores; + @Platforms(Platform.HOSTED_ONLY.class) + protected VMSemaphore replaceSemaphore(VMSemaphore source) { + return new DarwinVMSemaphore(source.getName()); } } diff --git a/substratevm/src/com.oracle.svm.core.posix/src/com/oracle/svm/core/posix/linux/LinuxVMSemaphoreFeature.java b/substratevm/src/com.oracle.svm.core.posix/src/com/oracle/svm/core/posix/linux/LinuxVMLockSupport.java similarity index 58% rename from substratevm/src/com.oracle.svm.core.posix/src/com/oracle/svm/core/posix/linux/LinuxVMSemaphoreFeature.java rename to substratevm/src/com.oracle.svm.core.posix/src/com/oracle/svm/core/posix/linux/LinuxVMLockSupport.java index 7d41981a48ec..c7acba7cd6dc 100644 --- a/substratevm/src/com.oracle.svm.core.posix/src/com/oracle/svm/core/posix/linux/LinuxVMSemaphoreFeature.java +++ b/substratevm/src/com.oracle.svm.core.posix/src/com/oracle/svm/core/posix/linux/LinuxVMLockSupport.java @@ -24,68 +24,26 @@ */ package com.oracle.svm.core.posix.linux; -import static com.oracle.svm.core.Uninterruptible.CALLED_FROM_UNINTERRUPTIBLE_CODE; - -import org.graalvm.nativeimage.ImageSingletons; import org.graalvm.nativeimage.Platform; import org.graalvm.nativeimage.Platforms; import org.graalvm.word.WordFactory; -import com.oracle.svm.core.BuildPhaseProvider.ReadyForCompilation; -import com.oracle.svm.core.SubstrateOptions; import com.oracle.svm.core.Uninterruptible; import com.oracle.svm.core.c.CIsolateData; import com.oracle.svm.core.c.CIsolateDataFactory; -import com.oracle.svm.core.feature.AutomaticallyRegisteredFeature; -import com.oracle.svm.core.feature.InternalFeature; -import com.oracle.svm.core.heap.UnknownObjectField; -import com.oracle.svm.core.locks.ClassInstanceReplacer; +import com.oracle.svm.core.feature.AutomaticallyRegisteredImageSingleton; +import com.oracle.svm.core.locks.VMLockSupport; import com.oracle.svm.core.locks.VMSemaphore; -import com.oracle.svm.core.posix.PosixVMSemaphoreSupport; import com.oracle.svm.core.posix.headers.Semaphore; import com.oracle.svm.core.posix.pthread.PthreadVMLockSupport; -/** - * Support of unnamed {@link VMSemaphore} in multithreaded environments on LINUX. - */ -@AutomaticallyRegisteredFeature -final class LinuxVMSemaphoreFeature implements InternalFeature { - - private final ClassInstanceReplacer semaphoreReplacer = new ClassInstanceReplacer<>(VMSemaphore.class) { - @Override - protected VMSemaphore createReplacement(VMSemaphore source) { - return new LinuxVMSemaphore(source.getName()); - } - }; - - @Override - public boolean isInConfiguration(IsInConfigurationAccess access) { - return SubstrateOptions.MultiThreaded.getValue(); - } - - @Override - public void duringSetup(DuringSetupAccess access) { - ImageSingletons.add(PosixVMSemaphoreSupport.class, new LinuxVMSemaphoreSupport()); - access.registerObjectReplacer(semaphoreReplacer); - } - - @Override - public void beforeCompilation(BeforeCompilationAccess access) { - LinuxVMSemaphoreSupport semaphoreSupport = (LinuxVMSemaphoreSupport) PosixVMSemaphoreSupport.singleton(); - semaphoreSupport.semaphores = semaphoreReplacer.getReplacements().toArray(new LinuxVMSemaphore[0]); - } -} - -final class LinuxVMSemaphoreSupport extends PosixVMSemaphoreSupport { - - /** All semaphores, so that we can initialize them at run time when the VM starts. */ - @UnknownObjectField(availability = ReadyForCompilation.class) // - LinuxVMSemaphore[] semaphores; +@AutomaticallyRegisteredImageSingleton(VMLockSupport.class) +final class LinuxVMLockSupport extends PthreadVMLockSupport { @Override - @Uninterruptible(reason = CALLED_FROM_UNINTERRUPTIBLE_CODE, mayBeInlined = true) - public VMSemaphore[] getSemaphores() { - return semaphores; + @Platforms(Platform.HOSTED_ONLY.class) + protected VMSemaphore replaceSemaphore(VMSemaphore source) { + return new LinuxVMSemaphore(source.getName()); } } diff --git a/substratevm/src/com.oracle.svm.core.posix/src/com/oracle/svm/core/posix/pthread/PthreadVMLockSupport.java b/substratevm/src/com.oracle.svm.core.posix/src/com/oracle/svm/core/posix/pthread/PthreadVMLockSupport.java index dd15e021d8b6..deff0643b8fd 100644 --- a/substratevm/src/com.oracle.svm.core.posix/src/com/oracle/svm/core/posix/pthread/PthreadVMLockSupport.java +++ b/substratevm/src/com.oracle.svm.core.posix/src/com/oracle/svm/core/posix/pthread/PthreadVMLockSupport.java @@ -24,103 +24,42 @@ */ package com.oracle.svm.core.posix.pthread; -import static com.oracle.svm.core.Uninterruptible.CALLED_FROM_UNINTERRUPTIBLE_CODE; import static com.oracle.svm.core.heap.RestrictHeapAccess.Access.NO_ALLOCATION; -import java.util.Arrays; -import java.util.Comparator; - import org.graalvm.nativeimage.ImageSingletons; import org.graalvm.nativeimage.LogHandler; import org.graalvm.nativeimage.Platform; import org.graalvm.nativeimage.Platforms; import org.graalvm.word.WordFactory; -import com.oracle.svm.core.BuildPhaseProvider.ReadyForCompilation; -import com.oracle.svm.core.SubstrateOptions; import com.oracle.svm.core.Uninterruptible; import com.oracle.svm.core.c.CIsolateData; import com.oracle.svm.core.c.CIsolateDataFactory; -import com.oracle.svm.core.feature.AutomaticallyRegisteredFeature; -import com.oracle.svm.core.feature.InternalFeature; import com.oracle.svm.core.graal.stackvalue.UnsafeStackValue; import com.oracle.svm.core.heap.RestrictHeapAccess; -import com.oracle.svm.core.heap.UnknownObjectField; import com.oracle.svm.core.jdk.UninterruptibleUtils; -import com.oracle.svm.core.locks.ClassInstanceReplacer; import com.oracle.svm.core.locks.VMCondition; import com.oracle.svm.core.locks.VMLockSupport; import com.oracle.svm.core.locks.VMMutex; -import com.oracle.svm.core.locks.VMSemaphore; import com.oracle.svm.core.log.Log; -import com.oracle.svm.core.posix.PosixVMSemaphoreSupport; import com.oracle.svm.core.posix.headers.Errno; import com.oracle.svm.core.posix.headers.Pthread; import com.oracle.svm.core.posix.headers.Time; import com.oracle.svm.core.stack.StackOverflowCheck; import com.oracle.svm.core.thread.VMThreads.SafepointBehavior; -import jdk.graal.compiler.api.replacements.Fold; - -/** - * Support of {@link VMMutex} and {@link VMCondition} in multi-threaded environments. Locking is - * implemented via pthreads. - */ -@AutomaticallyRegisteredFeature -final class PthreadVMLockFeature implements InternalFeature { - - private final ClassInstanceReplacer mutexReplacer = new ClassInstanceReplacer<>(VMMutex.class) { - @Override - protected VMMutex createReplacement(VMMutex source) { - return new PthreadVMMutex(source.getName()); - } - }; - - private final ClassInstanceReplacer conditionReplacer = new ClassInstanceReplacer<>(VMCondition.class) { - @Override - protected VMCondition createReplacement(VMCondition source) { - return new PthreadVMCondition((PthreadVMMutex) mutexReplacer.apply(source.getMutex()), source.getConditionName()); - } - }; +public abstract class PthreadVMLockSupport extends VMLockSupport { @Override - public boolean isInConfiguration(IsInConfigurationAccess access) { - return SubstrateOptions.MultiThreaded.getValue(); - } - - @Override - public void duringSetup(DuringSetupAccess access) { - PthreadVMLockSupport support = new PthreadVMLockSupport(); - ImageSingletons.add(VMLockSupport.class, support); - access.registerObjectReplacer(mutexReplacer); - access.registerObjectReplacer(conditionReplacer); + @Platforms(Platform.HOSTED_ONLY.class) + protected VMMutex replaceVMMutex(VMMutex source) { + return new PthreadVMMutex(source.getName()); } @Override - public void beforeCompilation(BeforeCompilationAccess access) { - PthreadVMMutex[] mutexes = mutexReplacer.getReplacements().toArray(new PthreadVMMutex[0]); - PthreadVMCondition[] conditions = conditionReplacer.getReplacements().toArray(new PthreadVMCondition[0]); - Arrays.sort(mutexes, Comparator.comparing(PthreadVMMutex::getName)); - Arrays.sort(conditions, Comparator.comparing(c -> c.getMutex().getName())); - - PthreadVMLockSupport lockSupport = PthreadVMLockSupport.singleton(); - lockSupport.mutexes = mutexes; - lockSupport.conditions = conditions; - } -} - -public final class PthreadVMLockSupport extends VMLockSupport { - /** All mutexes, so that we can initialize them at run time when the VM starts. */ - @UnknownObjectField(availability = ReadyForCompilation.class) // - PthreadVMMutex[] mutexes; - - /** All conditions, so that we can initialize them at run time when the VM starts. */ - @UnknownObjectField(availability = ReadyForCompilation.class) // - PthreadVMCondition[] conditions; - - @Fold - public static PthreadVMLockSupport singleton() { - return (PthreadVMLockSupport) ImageSingletons.lookup(VMLockSupport.class); + @Platforms(Platform.HOSTED_ONLY.class) + protected VMCondition replaceVMCondition(VMCondition source) { + return new PthreadVMCondition((PthreadVMMutex) mutexReplacer.apply(source.getMutex()), source.getConditionName()); } @Uninterruptible(reason = "Called from uninterruptible code.", mayBeInlined = true) @@ -143,24 +82,6 @@ private static void fatalError(int result, String functionName) { Log.log().string(functionName).string(" returned ").signed(result).newline(); ImageSingletons.lookup(LogHandler.class).fatalError(); } - - @Override - @Uninterruptible(reason = CALLED_FROM_UNINTERRUPTIBLE_CODE, mayBeInlined = true) - public VMMutex[] getMutexes() { - return mutexes; - } - - @Override - @Uninterruptible(reason = CALLED_FROM_UNINTERRUPTIBLE_CODE, mayBeInlined = true) - public VMCondition[] getConditions() { - return conditions; - } - - @Override - @Uninterruptible(reason = CALLED_FROM_UNINTERRUPTIBLE_CODE, mayBeInlined = true) - public VMSemaphore[] getSemaphores() { - return PosixVMSemaphoreSupport.singleton().getSemaphores(); - } } final class PthreadVMMutex extends VMMutex { diff --git a/substratevm/src/com.oracle.svm.core.windows/src/com/oracle/svm/core/windows/WindowsVMLockSupport.java b/substratevm/src/com.oracle.svm.core.windows/src/com/oracle/svm/core/windows/WindowsVMLockSupport.java index 0892f2284985..07b8fef0f76d 100644 --- a/substratevm/src/com.oracle.svm.core.windows/src/com/oracle/svm/core/windows/WindowsVMLockSupport.java +++ b/substratevm/src/com.oracle.svm.core.windows/src/com/oracle/svm/core/windows/WindowsVMLockSupport.java @@ -24,7 +24,6 @@ */ package com.oracle.svm.core.windows; -import static com.oracle.svm.core.Uninterruptible.CALLED_FROM_UNINTERRUPTIBLE_CODE; import static com.oracle.svm.core.heap.RestrictHeapAccess.Access.NO_ALLOCATION; import org.graalvm.nativeimage.ImageSingletons; @@ -33,16 +32,11 @@ import org.graalvm.nativeimage.Platforms; import org.graalvm.word.WordFactory; -import com.oracle.svm.core.BuildPhaseProvider.ReadyForCompilation; -import com.oracle.svm.core.SubstrateOptions; import com.oracle.svm.core.Uninterruptible; import com.oracle.svm.core.c.CIsolateData; import com.oracle.svm.core.c.CIsolateDataFactory; -import com.oracle.svm.core.feature.AutomaticallyRegisteredFeature; -import com.oracle.svm.core.feature.InternalFeature; +import com.oracle.svm.core.feature.AutomaticallyRegisteredImageSingleton; import com.oracle.svm.core.heap.RestrictHeapAccess; -import com.oracle.svm.core.heap.UnknownObjectField; -import com.oracle.svm.core.locks.ClassInstanceReplacer; import com.oracle.svm.core.locks.VMCondition; import com.oracle.svm.core.locks.VMLockSupport; import com.oracle.svm.core.locks.VMMutex; @@ -54,75 +48,25 @@ import com.oracle.svm.core.windows.headers.SynchAPI; import com.oracle.svm.core.windows.headers.WinBase; -import jdk.graal.compiler.api.replacements.Fold; - -/** - * Support of {@link VMMutex}, {@link VMCondition} and {@link VMSemaphore} in multithreaded - * environments. Locking is implemented via Windows locking primitives. - */ -@AutomaticallyRegisteredFeature -@Platforms(Platform.WINDOWS.class) -final class WindowsVMLockFeature implements InternalFeature { - - private final ClassInstanceReplacer mutexReplacer = new ClassInstanceReplacer<>(VMMutex.class) { - @Override - protected WindowsVMMutex createReplacement(VMMutex source) { - return new WindowsVMMutex(source.getName()); - } - }; - - private final ClassInstanceReplacer conditionReplacer = new ClassInstanceReplacer<>(VMCondition.class) { - @Override - protected WindowsVMCondition createReplacement(VMCondition source) { - return new WindowsVMCondition((WindowsVMMutex) mutexReplacer.apply(source.getMutex())); - } - }; - - private final ClassInstanceReplacer semaphoreReplacer = new ClassInstanceReplacer<>(VMSemaphore.class) { - @Override - protected VMSemaphore createReplacement(VMSemaphore source) { - return new WindowsVMSemaphore(source.getName()); - } - }; +@AutomaticallyRegisteredImageSingleton(VMLockSupport.class) +public final class WindowsVMLockSupport extends VMLockSupport { @Override - public boolean isInConfiguration(IsInConfigurationAccess access) { - return SubstrateOptions.MultiThreaded.getValue(); + @Platforms(Platform.HOSTED_ONLY.class) + protected VMMutex replaceVMMutex(VMMutex source) { + return new WindowsVMMutex(source.getName()); } @Override - public void duringSetup(DuringSetupAccess access) { - ImageSingletons.add(VMLockSupport.class, new WindowsVMLockSupport()); - access.registerObjectReplacer(mutexReplacer); - access.registerObjectReplacer(conditionReplacer); - access.registerObjectReplacer(semaphoreReplacer); + @Platforms(Platform.HOSTED_ONLY.class) + protected VMCondition replaceVMCondition(VMCondition source) { + return new WindowsVMCondition((WindowsVMMutex) mutexReplacer.apply(source.getMutex())); } @Override - public void beforeCompilation(BeforeCompilationAccess access) { - WindowsVMMutex[] mutexes = mutexReplacer.getReplacements().toArray(new WindowsVMMutex[0]); - WindowsVMCondition[] conditions = conditionReplacer.getReplacements().toArray(new WindowsVMCondition[0]); - - WindowsVMLockSupport lockSupport = WindowsVMLockSupport.singleton(); - lockSupport.mutexes = mutexes; - lockSupport.conditions = conditions; - lockSupport.semaphores = semaphoreReplacer.getReplacements().toArray(new WindowsVMSemaphore[0]); - } -} - -public final class WindowsVMLockSupport extends VMLockSupport { - /** All mutexes, so that we can initialize them at run time when the VM starts. */ - @UnknownObjectField(availability = ReadyForCompilation.class) WindowsVMMutex[] mutexes; - - /** All conditions, so that we can initialize them at run time when the VM starts. */ - @UnknownObjectField(availability = ReadyForCompilation.class) WindowsVMCondition[] conditions; - - /** All semaphores, so that we can initialize them at run time when the VM starts. */ - @UnknownObjectField(availability = ReadyForCompilation.class) WindowsVMSemaphore[] semaphores; - - @Fold - public static WindowsVMLockSupport singleton() { - return (WindowsVMLockSupport) ImageSingletons.lookup(VMLockSupport.class); + @Platforms(Platform.HOSTED_ONLY.class) + protected VMSemaphore replaceSemaphore(VMSemaphore source) { + return new WindowsVMSemaphore(source.getName()); } @Uninterruptible(reason = "Called from uninterruptible code.", mayBeInlined = true) @@ -146,24 +90,6 @@ private static void fatalError(String functionName) { Log.log().string(functionName).string(" failed with error ").hex(lastError).newline(); ImageSingletons.lookup(LogHandler.class).fatalError(); } - - @Override - @Uninterruptible(reason = CALLED_FROM_UNINTERRUPTIBLE_CODE, mayBeInlined = true) - public VMMutex[] getMutexes() { - return mutexes; - } - - @Override - @Uninterruptible(reason = CALLED_FROM_UNINTERRUPTIBLE_CODE, mayBeInlined = true) - public VMCondition[] getConditions() { - return conditions; - } - - @Override - @Uninterruptible(reason = CALLED_FROM_UNINTERRUPTIBLE_CODE, mayBeInlined = true) - public VMSemaphore[] getSemaphores() { - return semaphores; - } } final class WindowsVMMutex extends VMMutex { diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/locks/ClassInstanceReplacer.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/locks/ClassInstanceReplacer.java index 60a531f7c5f1..844f477a01fe 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/locks/ClassInstanceReplacer.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/locks/ClassInstanceReplacer.java @@ -24,9 +24,9 @@ */ package com.oracle.svm.core.locks; -import java.util.Collection; import java.util.Collections; import java.util.IdentityHashMap; +import java.util.List; import java.util.Map; import java.util.function.Function; @@ -36,14 +36,18 @@ import com.oracle.svm.core.util.VMError; @Platforms(Platform.HOSTED_ONLY.class) -public abstract class ClassInstanceReplacer implements Function { +public final class ClassInstanceReplacer implements Function { private final Class sourceClass; + private final List imageHeapList; + private final Function createReplacement; private final Map replacements = Collections.synchronizedMap(new IdentityHashMap<>()); private boolean sealed; - protected ClassInstanceReplacer(Class sourceClass) { + public ClassInstanceReplacer(Class sourceClass, List imageHeapList, Function createReplacement) { this.sourceClass = sourceClass; + this.imageHeapList = imageHeapList; + this.createReplacement = createReplacement; } @Override @@ -56,15 +60,11 @@ public Object apply(Object object) { private T doReplace(S object) { VMError.guarantee(!sealed, "new object introduced after static analysis"); - T replacement = createReplacement(object); + T replacement = createReplacement.apply(object); assert replacement.getClass() != sourceClass : "leads to recursive replacement"; + if (imageHeapList != null) { + imageHeapList.add(replacement); + } return replacement; } - - public Collection getReplacements() { - sealed = true; - return replacements.values(); - } - - protected abstract T createReplacement(S source); } diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/locks/SingleThreadedVMLockSupport.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/locks/SingleThreadedVMLockSupport.java deleted file mode 100644 index a855b63de8b6..000000000000 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/locks/SingleThreadedVMLockSupport.java +++ /dev/null @@ -1,256 +0,0 @@ -/* - * Copyright (c) 2015, 2017, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.oracle.svm.core.locks; - -import org.graalvm.nativeimage.ImageSingletons; -import org.graalvm.nativeimage.Platform; -import org.graalvm.nativeimage.Platforms; - -import com.oracle.svm.core.SubstrateOptions; -import com.oracle.svm.core.Uninterruptible; -import com.oracle.svm.core.feature.AutomaticallyRegisteredFeature; -import com.oracle.svm.core.feature.InternalFeature; -import com.oracle.svm.core.util.VMError; - -import static com.oracle.svm.core.Uninterruptible.CALLED_FROM_UNINTERRUPTIBLE_CODE; - -/** - * Support of {@link VMMutex}, {@link VMCondition} and {@link VMSemaphore} in single-threaded - * environments. No real locking is necessary. - */ -final class SingleThreadedVMLockSupport extends VMLockSupport { - @Override - @Uninterruptible(reason = CALLED_FROM_UNINTERRUPTIBLE_CODE, mayBeInlined = true) - public VMMutex[] getMutexes() { - return null; - } - - @Override - @Uninterruptible(reason = CALLED_FROM_UNINTERRUPTIBLE_CODE, mayBeInlined = true) - public VMCondition[] getConditions() { - return null; - } - - @Override - @Uninterruptible(reason = CALLED_FROM_UNINTERRUPTIBLE_CODE, mayBeInlined = true) - public VMSemaphore[] getSemaphores() { - return null; - } -} - -@AutomaticallyRegisteredFeature -final class SingleThreadedVMLockFeature implements InternalFeature { - - private final ClassInstanceReplacer mutexReplacer = new ClassInstanceReplacer<>(VMMutex.class) { - @Override - protected VMMutex createReplacement(VMMutex source) { - return new SingleThreadedVMMutex(source.getName()); - } - }; - - private final ClassInstanceReplacer conditionReplacer = new ClassInstanceReplacer<>(VMCondition.class) { - @Override - protected VMCondition createReplacement(VMCondition source) { - return new SingleThreadedVMCondition((SingleThreadedVMMutex) mutexReplacer.apply(source.getMutex())); - } - }; - - private final ClassInstanceReplacer semaphoreReplacer = new ClassInstanceReplacer<>(VMSemaphore.class) { - @Override - protected VMSemaphore createReplacement(VMSemaphore source) { - return new SingleThreadedVMSemaphore(source.getName()); - } - }; - - @Override - public boolean isInConfiguration(IsInConfigurationAccess access) { - return !SubstrateOptions.MultiThreaded.getValue(); - } - - @Override - public void duringSetup(DuringSetupAccess access) { - ImageSingletons.add(VMLockSupport.class, new SingleThreadedVMLockSupport()); - access.registerObjectReplacer(mutexReplacer); - access.registerObjectReplacer(conditionReplacer); - access.registerObjectReplacer(semaphoreReplacer); - } - - @Override - public void beforeCompilation(BeforeCompilationAccess access) { - /* Seal the lists. */ - mutexReplacer.getReplacements(); - conditionReplacer.getReplacements(); - semaphoreReplacer.getReplacements(); - } -} - -final class SingleThreadedVMMutex extends VMMutex { - @Platforms(Platform.HOSTED_ONLY.class) - SingleThreadedVMMutex(String name) { - super(name); - } - - @Override - @Uninterruptible(reason = "Too early for safepoints.") - public int initialize() { - /* Nothing to do here. */ - return 0; - } - - @Override - @Uninterruptible(reason = "The isolate teardown is in progress.") - public int destroy() { - /* Nothing to do here. */ - return 0; - } - - @Override - public VMMutex lock() { - assert !isOwner() : "Recursive locking is not supported"; - setOwnerToCurrentThread(); - return this; - } - - @Override - @Uninterruptible(reason = "Whole critical section needs to be uninterruptible.", callerMustBe = true) - public void lockNoTransition() { - assert !isOwner() : "Recursive locking is not supported"; - setOwnerToCurrentThread(); - } - - @Override - @Uninterruptible(reason = "Whole critical section needs to be uninterruptible.", callerMustBe = true) - public void lockNoTransitionUnspecifiedOwner() { - setOwnerToUnspecified(); - } - - @Override - @Uninterruptible(reason = "Called from uninterruptible code.", mayBeInlined = true) - public void unlock() { - clearCurrentThreadOwner(); - } - - @Override - @Uninterruptible(reason = "Whole critical section needs to be uninterruptible.") - public void unlockNoTransitionUnspecifiedOwner() { - clearUnspecifiedOwner(); - } -} - -final class SingleThreadedVMCondition extends VMCondition { - - SingleThreadedVMCondition(SingleThreadedVMMutex mutex) { - super(mutex); - } - - @Override - @Uninterruptible(reason = "Too early for safepoints.") - public int initialize() { - /* Nothing to do here. */ - return 0; - } - - @Override - @Uninterruptible(reason = "The isolate teardown is in progress.") - public int destroy() { - /* Nothing to do here. */ - return 0; - } - - @Override - public void block() { - VMError.shouldNotReachHere("Cannot block in a single-threaded environment, because there is no other thread that could signal"); - } - - @Uninterruptible(reason = "Should only be called if the thread did an explicit transition to native earlier.", callerMustBe = true) - @Override - public void blockNoTransition() { - VMError.shouldNotReachHere("Cannot block in a single-threaded environment, because there is no other thread that could signal"); - } - - @Uninterruptible(reason = "Should only be called if the thread did an explicit transition to native earlier.", callerMustBe = true) - @Override - public void blockNoTransitionUnspecifiedOwner() { - VMError.shouldNotReachHere("Cannot block in a single-threaded environment, because there is no other thread that could signal"); - } - - @Override - public long block(long nanos) { - VMError.shouldNotReachHere("Cannot block in a single-threaded environment, because there is no other thread that could signal"); - return 0; - } - - @Uninterruptible(reason = "Should only be called if the thread did an explicit transition to native earlier.", callerMustBe = true) - @Override - public long blockNoTransition(long nanos) { - VMError.shouldNotReachHere("Cannot block in a single-threaded environment, because there is no other thread that could signal"); - return 0; - } - - @Override - @Uninterruptible(reason = "Called from uninterruptible code.", mayBeInlined = true) - public void signal() { - /* Nothing to do. */ - } - - @Override - @Uninterruptible(reason = "Called from uninterruptible code.", mayBeInlined = true) - public void broadcast() { - /* Nothing to do. */ - } -} - -final class SingleThreadedVMSemaphore extends VMSemaphore { - - @Platforms(Platform.HOSTED_ONLY.class) - SingleThreadedVMSemaphore(String name) { - super(name); - } - - @Override - @Uninterruptible(reason = "Too early for safepoints.") - public int initialize() { - /* Nothing to do here. */ - return 0; - } - - @Override - @Uninterruptible(reason = "The isolate teardown is in progress.") - public int destroy() { - /* Nothing to do here. */ - return 0; - } - - @Override - public void await() { - VMError.shouldNotReachHere("Cannot wait in a single-threaded environment, because there is no other thread that could signal."); - } - - @Override - @Uninterruptible(reason = "Called from uninterruptible code.", mayBeInlined = true) - public void signal() { - /* Nothing to do here. */ - } -} diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/locks/VMLockSupport.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/locks/VMLockSupport.java index 33135546d0d7..c61495b2e915 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/locks/VMLockSupport.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/locks/VMLockSupport.java @@ -24,17 +24,52 @@ */ package com.oracle.svm.core.locks; +import java.util.Comparator; +import java.util.List; + import org.graalvm.nativeimage.ImageSingletons; import org.graalvm.nativeimage.IsolateThread; +import org.graalvm.nativeimage.Platform; +import org.graalvm.nativeimage.Platforms; import com.oracle.svm.core.SubstrateDiagnostics.DiagnosticThunk; import com.oracle.svm.core.SubstrateDiagnostics.ErrorContext; +import com.oracle.svm.core.SubstrateOptions; import com.oracle.svm.core.Uninterruptible; +import com.oracle.svm.core.feature.AutomaticallyRegisteredFeature; +import com.oracle.svm.core.feature.InternalFeature; import com.oracle.svm.core.heap.RestrictHeapAccess; import com.oracle.svm.core.log.Log; +import com.oracle.svm.core.util.ImageHeapList; import jdk.graal.compiler.api.replacements.Fold; +@AutomaticallyRegisteredFeature +final class VMLockFeature implements InternalFeature { + + @Override + public boolean isInConfiguration(IsInConfigurationAccess access) { + return SubstrateOptions.MultiThreaded.getValue(); + } + + @Override + public void duringSetup(DuringSetupAccess access) { + if (!ImageSingletons.contains(VMLockSupport.class)) { + /* The platform uses a VMThreads implementation that does not rely on VMLockSupport. */ + return; + } + VMLockSupport support = ImageSingletons.lookup(VMLockSupport.class); + + support.mutexReplacer = new ClassInstanceReplacer<>(VMMutex.class, support.mutexes, support::replaceVMMutex); + support.conditionReplacer = new ClassInstanceReplacer<>(VMCondition.class, support.conditions, support::replaceVMCondition); + support.semaphoreReplacer = new ClassInstanceReplacer<>(VMSemaphore.class, support.semaphores, support::replaceSemaphore); + + access.registerObjectReplacer(support.mutexReplacer); + access.registerObjectReplacer(support.conditionReplacer); + access.registerObjectReplacer(support.semaphoreReplacer); + } +} + public abstract class VMLockSupport { @Fold @@ -42,23 +77,28 @@ public static VMLockSupport singleton() { return ImageSingletons.lookup(VMLockSupport.class); } - /** - * Returns an array that contains all {@link VMMutex} objects that are present in the image or - * null if that information is not available. - */ - public abstract VMMutex[] getMutexes(); + /** All mutexes, so that we can initialize them at run time when the VM starts. */ + protected final List mutexes = ImageHeapList.create(VMMutex.class, Comparator.comparing(VMMutex::getName)); + /** All conditions, so that we can initialize them at run time when the VM starts. */ + protected final List conditions = ImageHeapList.create(VMCondition.class, Comparator.comparing(VMCondition::getName)); + /** All semaphores, so that we can initialize them at run time when the VM starts. */ + protected final List semaphores = ImageHeapList.create(VMSemaphore.class, Comparator.comparing(VMSemaphore::getName)); - /** - * Returns an array that contains all {@link VMCondition} objects that are present in the image - * or null if that information is not available. - */ - public abstract VMCondition[] getConditions(); + @Platforms(Platform.HOSTED_ONLY.class) // + protected ClassInstanceReplacer mutexReplacer; + @Platforms(Platform.HOSTED_ONLY.class) // + protected ClassInstanceReplacer conditionReplacer; + @Platforms(Platform.HOSTED_ONLY.class) // + protected ClassInstanceReplacer semaphoreReplacer; - /** - * Returns an array that contains all {@link VMSemaphore} objects that are present in the image - * or null if that information is not available. - */ - public abstract VMSemaphore[] getSemaphores(); + @Platforms(Platform.HOSTED_ONLY.class) + protected abstract VMMutex replaceVMMutex(VMMutex source); + + @Platforms(Platform.HOSTED_ONLY.class) + protected abstract VMCondition replaceVMCondition(VMCondition source); + + @Platforms(Platform.HOSTED_ONLY.class) + protected abstract VMSemaphore replaceSemaphore(VMSemaphore source); /** * Initializes all {@link VMMutex}, {@link VMCondition}, and {@link VMSemaphore} objects. @@ -68,25 +108,21 @@ public static VMLockSupport singleton() { */ @Uninterruptible(reason = "Too early for safepoints.") public final boolean initialize() { - VMLockSupport support = VMLockSupport.singleton(); - for (VMMutex mutex : support.getMutexes()) { - if (mutex.initialize() != 0) { + for (int i = 0; i < mutexes.size(); i++) { + if (mutexes.get(i).initialize() != 0) { return false; } } - - for (VMCondition condition : support.getConditions()) { - if (condition.initialize() != 0) { + for (int i = 0; i < conditions.size(); i++) { + if (conditions.get(i).initialize() != 0) { return false; } } - - for (VMSemaphore semaphore : support.getSemaphores()) { - if (semaphore.initialize() != 0) { + for (int i = 0; i < semaphores.size(); i++) { + if (semaphores.get(i).initialize() != 0) { return false; } } - return true; } @@ -97,25 +133,21 @@ public final boolean initialize() { */ @Uninterruptible(reason = "The isolate teardown is in progress.") public final boolean destroy() { - VMLockSupport support = VMLockSupport.singleton(); - for (VMSemaphore semaphore : support.getSemaphores()) { - if (semaphore.destroy() != 0) { + for (int i = 0; i < semaphores.size(); i++) { + if (semaphores.get(i).destroy() != 0) { return false; } } - - for (VMCondition condition : support.getConditions()) { - if (condition.destroy() != 0) { + for (int i = 0; i < conditions.size(); i++) { + if (conditions.get(i).destroy() != 0) { return false; } } - - for (VMMutex mutex : support.getMutexes()) { - if (mutex.destroy() != 0) { + for (int i = 0; i < mutexes.size(); i++) { + if (mutexes.get(i).destroy() != 0) { return false; } } - return true; } @@ -135,10 +167,11 @@ public void printDiagnostics(Log log, ErrorContext context, int maxDiagnosticLev support = ImageSingletons.lookup(VMLockSupport.class); } - if (support == null || support.getMutexes() == null) { + if (support == null || support.mutexes == null) { log.string("No mutex information is available.").newline(); } else { - for (VMMutex mutex : support.getMutexes()) { + for (int i = 0; i < support.mutexes.size(); i++) { + VMMutex mutex = support.mutexes.get(i); IsolateThread owner = mutex.owner; log.string("mutex \"").string(mutex.getName()).string("\" "); if (owner.isNull()) { diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/thread/VMThreads.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/thread/VMThreads.java index 51193fc1f1bb..6606fc0f7c62 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/thread/VMThreads.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/thread/VMThreads.java @@ -66,6 +66,7 @@ import jdk.graal.compiler.api.directives.GraalDirectives; import jdk.graal.compiler.api.replacements.Fold; +import jdk.graal.compiler.core.common.SuppressFBWarnings; import jdk.graal.compiler.replacements.ReplacementsUtil; import jdk.graal.compiler.replacements.nodes.AssertionNode; @@ -600,6 +601,7 @@ public boolean verifyIsCurrentThread(IsolateThread thread) { } @Uninterruptible(reason = "Called from uninterruptible code.", mayBeInlined = true) + @SuppressFBWarnings(value = "UC", justification = "FB does not know that VMMutex objects are replaced, i.e., that the lock/unlock methods do not throw an error at run time.") public IsolateThread findIsolateThreadForCurrentOSThread(boolean inCrashHandler) { ThreadLookup threadLookup = ImageSingletons.lookup(ThreadLookup.class); ComparableWord identifier = threadLookup.getThreadIdentifier(); diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/util/ImageHeapList.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/util/ImageHeapList.java new file mode 100644 index 000000000000..0648e8fbc923 --- /dev/null +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/util/ImageHeapList.java @@ -0,0 +1,150 @@ +/* + * Copyright (c) 2024, 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.svm.core.util; + +import java.lang.reflect.Array; +import java.util.AbstractList; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Comparator; +import java.util.List; + +import org.graalvm.nativeimage.Platform; +import org.graalvm.nativeimage.Platforms; + +import com.oracle.svm.core.BuildPhaseProvider; +import com.oracle.svm.core.Uninterruptible; + +/** + * At list that is filled at image build time while the static analysis running, and then read at + * run time. + * + * Filling the list at image build time is thread safe. Every object to the list is properly added + * to the shadow heap. + * + * The list is immutable at run time. The run-time list can optionally be sorted, to make code at + * run time deterministic regardless of the order in which elements are discovered and added at + * image build time. + */ +@Platforms(Platform.HOSTED_ONLY.class) // +public final class ImageHeapList { + + @Platforms(Platform.HOSTED_ONLY.class) // + public static List create(Class elementClass, Comparator comparator) { + VMError.guarantee(!BuildPhaseProvider.isAnalysisFinished(), "Trying to create an ImageHeapList after analysis."); + return new HostedImageHeapList<>(elementClass, comparator); + } + + private ImageHeapList() { + } + + @Platforms(Platform.HOSTED_ONLY.class) // + public static final class HostedImageHeapList extends AbstractList { + private final Comparator comparator; + private final List hostedList; + public final RuntimeImageHeapList runtimeList; + private boolean modified; + + @SuppressWarnings("unchecked") + private HostedImageHeapList(Class elementClass, Comparator comparator) { + this.comparator = comparator; + this.hostedList = new ArrayList<>(); + this.runtimeList = new RuntimeImageHeapList<>((E[]) Array.newInstance(elementClass, 0)); + } + + public synchronized boolean needsUpdate() { + return modified; + } + + public synchronized void update() { + /* + * It is important that the runtime list object does not change because it can be + * already constant folded into graphs. So we only replace the backing array of the + * runtime list. + */ + runtimeList.elementData = hostedList.toArray(runtimeList.elementData); + if (comparator != null) { + Arrays.sort(runtimeList.elementData, comparator); + } + modified = false; + } + + @Override + public synchronized boolean add(E e) { + modified = true; + return hostedList.add(e); + } + + @Override + public synchronized void add(int index, E element) { + modified = true; + hostedList.add(index, element); + } + + @Override + public synchronized E remove(int index) { + modified = true; + return hostedList.remove(index); + } + + @Override + public synchronized E get(int index) { + return hostedList.get(index); + } + + @Override + public synchronized E set(int index, E element) { + modified = true; + return hostedList.set(index, element); + } + + @Override + public synchronized int size() { + return hostedList.size(); + } + } +} + +final class RuntimeImageHeapList extends AbstractList { + + E[] elementData; + + @Platforms(Platform.HOSTED_ONLY.class) + RuntimeImageHeapList(E[] elementData) { + this.elementData = elementData; + } + + @Uninterruptible(reason = "Called from uninterruptible code.", mayBeInlined = true) + @Override + public E get(int index) { + return elementData[index]; + } + + @Uninterruptible(reason = "Called from uninterruptible code.", mayBeInlined = true) + @Override + public int size() { + return elementData.length; + } +} diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/heap/ImageHeapMapFeature.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/heap/ImageHeapCollectionFeature.java similarity index 65% rename from substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/heap/ImageHeapMapFeature.java rename to substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/heap/ImageHeapCollectionFeature.java index 7963d985a53d..c06c23ccccee 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/heap/ImageHeapMapFeature.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/heap/ImageHeapCollectionFeature.java @@ -32,31 +32,40 @@ import org.graalvm.collections.MapCursor; import com.oracle.svm.core.BuildPhaseProvider; -import com.oracle.svm.core.feature.InternalFeature; import com.oracle.svm.core.feature.AutomaticallyRegisteredFeature; +import com.oracle.svm.core.feature.InternalFeature; +import com.oracle.svm.core.util.ImageHeapList.HostedImageHeapList; import com.oracle.svm.core.util.ImageHeapMap.HostedImageHeapMap; import com.oracle.svm.core.util.VMError; import com.oracle.svm.hosted.FeatureImpl.DuringAnalysisAccessImpl; @AutomaticallyRegisteredFeature -final class ImageHeapMapFeature implements InternalFeature { +final class ImageHeapCollectionFeature implements InternalFeature { - private final Set> allInstances = ConcurrentHashMap.newKeySet(); + private final Set> allMaps = ConcurrentHashMap.newKeySet(); + private final Set> allLists = ConcurrentHashMap.newKeySet(); @Override public void duringSetup(DuringSetupAccess config) { - config.registerObjectReplacer(this::imageHeapMapTransformer); + config.registerObjectReplacer(this::replaceHostedWithRuntime); } - private Object imageHeapMapTransformer(Object obj) { + private Object replaceHostedWithRuntime(Object obj) { if (obj instanceof HostedImageHeapMap) { HostedImageHeapMap hostedImageHeapMap = (HostedImageHeapMap) obj; if (BuildPhaseProvider.isAnalysisFinished()) { - VMError.guarantee(allInstances.contains(hostedImageHeapMap), "ImageHeapMap reachable after analysis that was not seen during analysis"); + VMError.guarantee(allMaps.contains(hostedImageHeapMap), "ImageHeapMap reachable after analysis that was not seen during analysis"); } else { - allInstances.add(hostedImageHeapMap); + allMaps.add(hostedImageHeapMap); } return hostedImageHeapMap.runtimeMap; + } else if (obj instanceof HostedImageHeapList hostedImageHeapList) { + if (BuildPhaseProvider.isAnalysisFinished()) { + VMError.guarantee(allLists.contains(hostedImageHeapList), "ImageHeapList reachable after analysis that was not seen during analysis"); + } else { + allLists.add(hostedImageHeapList); + } + return hostedImageHeapList.runtimeList; } return obj; } @@ -64,32 +73,51 @@ private Object imageHeapMapTransformer(Object obj) { @Override public void duringAnalysis(DuringAnalysisAccess a) { DuringAnalysisAccessImpl access = (DuringAnalysisAccessImpl) a; - for (HostedImageHeapMap hostedImageHeapMap : allInstances) { + for (var hostedImageHeapMap : allMaps) { if (needsUpdate(hostedImageHeapMap)) { update(hostedImageHeapMap); access.rescanObject(hostedImageHeapMap.runtimeMap); access.requireAnalysisIteration(); } } + for (var hostedImageHeapList : allLists) { + if (hostedImageHeapList.needsUpdate()) { + hostedImageHeapList.update(); + access.rescanObject(hostedImageHeapList.runtimeList); + access.requireAnalysisIteration(); + } + } } - public boolean imageHeapMapNeedsUpdate() { - for (HostedImageHeapMap hostedImageHeapMap : allInstances) { + public boolean needsUpdate() { + for (var hostedImageHeapMap : allMaps) { if (needsUpdate(hostedImageHeapMap)) { return true; } } + for (var hostedImageHeapList : allLists) { + if (hostedImageHeapList.needsUpdate()) { + return true; + } + } return false; } @Override public void afterImageWrite(AfterImageWriteAccess access) { - for (HostedImageHeapMap hostedImageHeapMap : allInstances) { + for (var hostedImageHeapMap : allMaps) { if (needsUpdate(hostedImageHeapMap)) { throw VMError.shouldNotReachHere("ImageHeapMap modified after static analysis:%n%s%n%s", hostedImageHeapMap, hostedImageHeapMap.runtimeMap); } } + for (var hostedImageHeapList : allLists) { + if (hostedImageHeapList.needsUpdate()) { + throw VMError.shouldNotReachHere("ImageHeapList modified after static analysis:%n%s%n%s", + hostedImageHeapList, hostedImageHeapList.runtimeList); + + } + } } private static boolean needsUpdate(HostedImageHeapMap hostedMap) { diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/heap/SVMImageHeapVerifier.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/heap/SVMImageHeapVerifier.java index d52145742a44..a152d8c57097 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/heap/SVMImageHeapVerifier.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/heap/SVMImageHeapVerifier.java @@ -62,14 +62,14 @@ public boolean checkHeapSnapshot(UniverseMetaAccess metaAccess, CompletionExecut * - an image heap map, e.g., via an object replacer like * com.oracle.svm.enterprise.core.stringformat.StringFormatFeature.collectZeroDigits(). Signal * this by returning true to make sure that - * com.oracle.graal.pointsto.heap.ImageHeapMapFeature.duringAnalysis() is run to properly patch - * all ImageHeapMaps. + * com.oracle.graal.pointsto.heap.ImageHeapCollectionFeature.duringAnalysis() is run to properly + * patch all ImageHeapMaps. * * - runtime reflection registration. * */ private static boolean imageStateModified() { - return ImageSingletons.lookup(ImageHeapMapFeature.class).imageHeapMapNeedsUpdate(); + return ImageSingletons.lookup(ImageHeapCollectionFeature.class).needsUpdate(); } @Override From 9d52cb92bf441c2c9ab0a2c628667dcd52985986 Mon Sep 17 00:00:00 2001 From: Codrut Stancu Date: Thu, 11 Jan 2024 19:54:16 +0100 Subject: [PATCH 433/593] Catch disallowed objects in object reachable callback. Previously this was using an object replacer. --- .../graal/pointsto/heap/ImageHeapScanner.java | 12 +- .../image/DisallowedImageHeapObjects.java | 201 +++++++++++------- .../DisallowedImageHeapObjectFeature.java | 71 +++++-- 3 files changed, 187 insertions(+), 97 deletions(-) diff --git a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/heap/ImageHeapScanner.java b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/heap/ImageHeapScanner.java index 5c415109cd59..f0f850cebdfe 100644 --- a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/heap/ImageHeapScanner.java +++ b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/heap/ImageHeapScanner.java @@ -518,7 +518,17 @@ protected void onObjectReachable(ImageHeapConstant imageHeapConstant, ScanReason AnalysisType type = imageHeapConstant.getType(metaAccess); Object object = bb.getSnippetReflectionProvider().asObject(Object.class, imageHeapConstant); - type.notifyObjectReachable(universe.getConcurrentAnalysisAccess(), object); + try { + /* Simulated constants don't have a backing object and don't need to be processed. */ + if (object != null) { + type.notifyObjectReachable(universe.getConcurrentAnalysisAccess(), object); + } + } catch (UnsupportedFeatureException e) { + /* Enhance the unsupported feature message with the object trace and rethrow. */ + StringBuilder backtrace = new StringBuilder(); + ObjectScanner.buildObjectBacktrace(bb, reason, backtrace); + throw new UnsupportedFeatureException(e.getMessage() + System.lineSeparator() + backtrace); + } markTypeInstantiated(objectType, reason); if (imageHeapConstant instanceof ImageHeapObjectArray imageHeapArray) { diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/image/DisallowedImageHeapObjects.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/image/DisallowedImageHeapObjects.java index b6ccc67d8976..25fd73988d23 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/image/DisallowedImageHeapObjects.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/image/DisallowedImageHeapObjects.java @@ -35,6 +35,8 @@ import java.util.Random; import java.util.SplittableRandom; import java.util.concurrent.ThreadLocalRandom; +import java.util.random.RandomGenerator; +import java.util.zip.ZipFile; import com.oracle.svm.core.SubstrateUtil; import com.oracle.svm.core.util.VMError; @@ -51,115 +53,168 @@ public interface DisallowedObjectReporter { RuntimeException raise(String msg, Object obj, String initializerAction); } - private static final Class CANCELLABLE_CLASS = ReflectionUtil.lookupClass(false, "sun.nio.fs.Cancellable"); + public static final Class CANCELLABLE_CLASS = ReflectionUtil.lookupClass(false, "sun.nio.fs.Cancellable"); private static final Class VIRTUAL_THREAD_CLASS = ReflectionUtil.lookupClass(false, "java.lang.VirtualThread"); - private static final Class CONTINUATION_CLASS = ReflectionUtil.lookupClass(false, "jdk.internal.vm.Continuation"); + public static final Class CONTINUATION_CLASS = ReflectionUtil.lookupClass(false, "jdk.internal.vm.Continuation"); private static final Method CONTINUATION_IS_STARTED_METHOD = ReflectionUtil.lookupMethod(CONTINUATION_CLASS, "isStarted"); private static final Class CLEANER_CLEANABLE_CLASS = ReflectionUtil.lookupClass(false, "jdk.internal.ref.CleanerImpl$CleanerCleanable"); - private static final Class LEGACY_CLEANER_CLASS = ReflectionUtil.lookupClass(false, "jdk.internal.ref.Cleaner"); + public static final Class LEGACY_CLEANER_CLASS = ReflectionUtil.lookupClass(false, "jdk.internal.ref.Cleaner"); public static void check(Object obj, DisallowedObjectReporter reporter) { - if (((obj instanceof Random) && !(obj instanceof ThreadLocalRandom)) || obj instanceof SplittableRandom) { - throw reporter.raise("Detected an instance of Random/SplittableRandom class in the image heap. " + - "Instances created during image generation have cached seed values and don't behave as expected.", - obj, "Try avoiding to initialize the class that caused initialization of the object."); + if (obj instanceof SplittableRandom random) { + onSplittableRandomReachable(random, reporter); + } else if (obj instanceof Random random) { + onRandomReachable(random, reporter); } /* Started platform threads */ if (obj instanceof Thread asThread) { - if (VIRTUAL_THREAD_CLASS.isInstance(asThread)) { - // allowed unless the thread is mounted, in which case it references its carrier - // thread and fails - } else if (asThread.getState() != Thread.State.NEW && asThread.getState() != Thread.State.TERMINATED) { - throw reporter.raise("Detected a started Thread in the image heap. Thread name: " + asThread.getName() + - ". Threads running in the image generator are no longer running at image runtime.", - asThread, "Prevent threads from starting during image generation, or a started thread from being included in the image."); - } + onThreadReachable(asThread, reporter); } if (SubstrateUtil.HOSTED && CONTINUATION_CLASS.isInstance(obj)) { - boolean isStarted; - try { - isStarted = (Boolean) CONTINUATION_IS_STARTED_METHOD.invoke(obj); - } catch (IllegalAccessException | InvocationTargetException ignored) { - isStarted = false; - } - if (isStarted) { - throw reporter.raise("Detected a started Continuation in the image heap. " + - "Continuation state from the image generator cannot be used at image runtime.", - obj, "Prevent continuations from starting during image generation, or started continuations from being included in the image."); - } + onContinuationReachable(obj, reporter); } if (obj instanceof FileDescriptor) { - final FileDescriptor asFileDescriptor = (FileDescriptor) obj; - /* Exemptions for well-known FileDescriptors. */ - if (!((asFileDescriptor == FileDescriptor.in) || (asFileDescriptor == FileDescriptor.out) || (asFileDescriptor == FileDescriptor.err) || (!asFileDescriptor.valid()))) { - throw reporter.raise("Detected a FileDescriptor in the image heap. " + - "File descriptors opened during image generation are no longer open at image runtime, and the files might not even be present anymore at image runtime.", - asFileDescriptor, "Try avoiding to initialize the class that caused initialization of the FileDescriptor."); - } + onFileDescriptorReachable((FileDescriptor) obj, reporter); + } + + if (obj instanceof Buffer buffer) { + onBufferReachable(buffer, reporter); + } + + if (obj instanceof Cleaner.Cleanable || LEGACY_CLEANER_CLASS.isInstance(obj)) { + onCleanableReachable(obj, reporter); + } + + if (obj instanceof Cleaner cleaner) { + onCleanerReachable(cleaner, reporter); + } + + if (obj instanceof ZipFile zipFile) { + onZipFileReachable(zipFile, reporter); + } + + if (CANCELLABLE_CLASS.isInstance(obj)) { + onCancellableReachable(obj, reporter); + } + } + + public static void onRandomReachable(Random random, DisallowedObjectReporter reporter) { + if (!(random instanceof ThreadLocalRandom)) { + onRandomGeneratorReachable(random, reporter); } + } + + public static void onSplittableRandomReachable(SplittableRandom random, DisallowedObjectReporter reporter) { + onRandomGeneratorReachable(random, reporter); + } + + private static void onRandomGeneratorReachable(RandomGenerator random, DisallowedObjectReporter reporter) { + throw reporter.raise("Detected an instance of Random/SplittableRandom class in the image heap. " + + "Instances created during image generation have cached seed values and don't behave as expected.", + random, "Try avoiding to initialize the class that caused initialization of the object."); + } - if (obj instanceof MappedByteBuffer) { - MappedByteBuffer buffer = (MappedByteBuffer) obj; + public static void onThreadReachable(Thread thread, DisallowedObjectReporter reporter) { + if (VIRTUAL_THREAD_CLASS.isInstance(thread)) { + // allowed unless the thread is mounted, in which case it references its carrier + // thread and fails + } else if (thread.getState() != Thread.State.NEW && thread.getState() != Thread.State.TERMINATED) { + throw reporter.raise("Detected a started Thread in the image heap. Thread name: " + thread.getName() + + ". Threads running in the image generator are no longer running at image runtime.", + thread, "Prevent threads from starting during image generation, or a started thread from being included in the image."); + } + } + + public static void onContinuationReachable(Object continuation, DisallowedObjectReporter reporter) { + VMError.guarantee(CONTINUATION_CLASS.isInstance(continuation)); + boolean isStarted; + try { + isStarted = (Boolean) CONTINUATION_IS_STARTED_METHOD.invoke(continuation); + } catch (IllegalAccessException | InvocationTargetException ignored) { + isStarted = false; + } + if (isStarted) { + throw reporter.raise("Detected a started Continuation in the image heap. " + + "Continuation state from the image generator cannot be used at image runtime.", + continuation, "Prevent continuations from starting during image generation, or started continuations from being included in the image."); + } + } + + public static void onFileDescriptorReachable(FileDescriptor descriptor, DisallowedObjectReporter reporter) { + /* Exemptions for well-known FileDescriptors. */ + if (!((descriptor == FileDescriptor.in) || (descriptor == FileDescriptor.out) || (descriptor == FileDescriptor.err) || (!descriptor.valid()))) { + throw reporter.raise("Detected a FileDescriptor in the image heap. " + + "File descriptors opened during image generation are no longer open at image runtime, and the files might not even be present anymore at image runtime.", + descriptor, "Try avoiding to initialize the class that caused initialization of the FileDescriptor."); + } + } + + public static void onBufferReachable(Buffer buffer, DisallowedObjectReporter reporter) { + if (buffer instanceof MappedByteBuffer mappedBuffer) { /* * We allow 0-length non-file-based direct buffers, see comment on * Target_java_nio_DirectByteBuffer. */ - if (buffer.capacity() != 0 || getFileDescriptor(buffer) != null) { + if (mappedBuffer.capacity() != 0 || getFileDescriptor(mappedBuffer) != null) { throw reporter.raise("Detected a direct/mapped ByteBuffer in the image heap. " + "A direct ByteBuffer has a pointer to unmanaged C memory, and C memory from the image generator is not available at image runtime. " + "A mapped ByteBuffer references a file descriptor, which is no longer open and mapped at run time.", - buffer, "Try avoiding to initialize the class that caused initialization of the MappedByteBuffer."); + mappedBuffer, "Try avoiding to initialize the class that caused initialization of the MappedByteBuffer."); } - } else if (obj instanceof Buffer && ((Buffer) obj).isDirect()) { + } else if (buffer.isDirect()) { throw reporter.raise("Detected a direct Buffer in the image heap. " + "A direct Buffer has a pointer to unmanaged C memory, and C memory from the image generator is not available at image runtime.", - obj, "Try avoiding to initialize the class that caused initialization of the direct Buffer."); + buffer, "Try avoiding to initialize the class that caused initialization of the direct Buffer."); } + } - if (obj instanceof Cleaner.Cleanable || LEGACY_CLEANER_CLASS.isInstance(obj)) { - /* - * Cleanable and jdk.internal.ref.Cleaner are used to release various resources such as - * native memory, file descriptors, or timers, which are not available at image runtime. - * By disallowing these objects, we detect when such resources are reachable. - * - * If a Cleanable is a nulled (Phantom)Reference, its problematic resource is already - * unreachable, so we tolerate it. - * - * A CleanerCleanable serves only to keep a cleaner thread alive (without referencing - * the Thread) and does nothing, so we also tolerate it. We should encounter at least - * one such object for jdk.internal.ref.CleanerFactory.commonCleaner. - * - * Legacy jdk.internal.ref.Cleaner objects (formerly in sun.misc) should be used only by - * DirectByteBuffer, which we already cover above, but other code could also use them. - * If they have been nulled, we tolerate them, too. - */ - if (!(obj instanceof Reference && ((Reference) obj).refersTo(null)) && !CLEANER_CLEANABLE_CLASS.isInstance(obj)) { - throw reporter.raise("Detected an active instance of Cleanable or jdk.internal.ref.Cleaner in the image heap. This usually means that a resource " + - "such as a Timer, native memory, a file descriptor or another resource is reachable which is not available at image runtime.", - obj, "Prevent such objects being used during image generation, including by class initializers."); - } + public static void onCleanableReachable(Object cleanable, DisallowedObjectReporter reporter) { + VMError.guarantee(cleanable instanceof Cleaner.Cleanable || LEGACY_CLEANER_CLASS.isInstance(cleanable)); + /* + * Cleanable and jdk.internal.ref.Cleaner are used to release various resources such as + * native memory, file descriptors, or timers, which are not available at image runtime. By + * disallowing these objects, we detect when such resources are reachable. + * + * If a Cleanable is a nulled (Phantom)Reference, its problematic resource is already + * unreachable, so we tolerate it. + * + * A CleanerCleanable serves only to keep a cleaner thread alive (without referencing the + * Thread) and does nothing, so we also tolerate it. We should encounter at least one such + * object for jdk.internal.ref.CleanerFactory.commonCleaner. + * + * Legacy jdk.internal.ref.Cleaner objects (formerly in sun.misc) should be used only by + * DirectByteBuffer, which we already cover above, but other code could also use them. If + * they have been nulled, we tolerate them, too. + */ + if (!(cleanable instanceof Reference && ((Reference) cleanable).refersTo(null)) && !CLEANER_CLEANABLE_CLASS.isInstance(cleanable)) { + throw reporter.raise("Detected an active instance of Cleanable or jdk.internal.ref.Cleaner in the image heap. This usually means that a resource " + + "such as a Timer, native memory, a file descriptor or another resource is reachable which is not available at image runtime.", + cleanable, "Prevent such objects being used during image generation, including by class initializers."); } + } - if (obj instanceof Cleaner && obj != CleanerFactory.cleaner()) { + public static void onCleanerReachable(Cleaner cleaner, DisallowedObjectReporter reporter) { + if (cleaner != CleanerFactory.cleaner()) { /* We handle the "common cleaner", CleanerFactory.cleaner(), in reference handling. */ throw reporter.raise("Detected a java.lang.ref.Cleaner object in the image heap which uses a daemon thread that invokes " + "cleaning actions, but threads running in the image generator are no longer running at image runtime.", - obj, "Prevent such objects being used during image generation, including by class initializers."); + cleaner, "Prevent such objects being used during image generation, including by class initializers."); } + } - if (obj instanceof java.util.zip.ZipFile) { - throw reporter.raise("Detected a ZipFile object in the image heap. " + - "A ZipFile object contains pointers to unmanaged C memory and file descriptors, and these resources are no longer available at image runtime.", - obj, "Try avoiding to initialize the class that caused initialization of the ZipFile."); - } + public static void onZipFileReachable(java.util.zip.ZipFile zipFile, DisallowedObjectReporter reporter) { + throw reporter.raise("Detected a ZipFile object in the image heap. " + + "A ZipFile object contains pointers to unmanaged C memory and file descriptors, and these resources are no longer available at image runtime.", + zipFile, "Try avoiding to initialize the class that caused initialization of the ZipFile."); + } - if (CANCELLABLE_CLASS.isInstance(obj)) { - throw reporter.raise("Detected an instance of a class that extends " + CANCELLABLE_CLASS.getTypeName() + ": " + obj.getClass().getTypeName() + ". " + - "It contains a pointer to unmanaged C memory, which is no longer available at image runtime.", obj, - "Try avoiding to initialize the class that caused initialization of the object."); - } + public static void onCancellableReachable(Object cancellable, DisallowedObjectReporter reporter) { + VMError.guarantee(CANCELLABLE_CLASS.isInstance(cancellable)); + throw reporter.raise("Detected an instance of a class that extends " + CANCELLABLE_CLASS.getTypeName() + ": " + cancellable.getClass().getTypeName() + ". " + + "It contains a pointer to unmanaged C memory, which is no longer available at image runtime.", cancellable, + "Try avoiding to initialize the class that caused initialization of the object."); } private static final Field FILE_DESCRIPTOR_FIELD = ReflectionUtil.lookupField(MappedByteBuffer.class, "fd"); diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/DisallowedImageHeapObjectFeature.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/DisallowedImageHeapObjectFeature.java index 959bd979b12c..da33d69a6f90 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/DisallowedImageHeapObjectFeature.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/DisallowedImageHeapObjectFeature.java @@ -24,8 +24,14 @@ */ package com.oracle.svm.hosted.image; +import static com.oracle.svm.core.image.DisallowedImageHeapObjects.CANCELLABLE_CLASS; +import static com.oracle.svm.core.image.DisallowedImageHeapObjects.LEGACY_CLEANER_CLASS; + import java.io.File; +import java.io.FileDescriptor; import java.lang.management.PlatformManagedObject; +import java.lang.ref.Cleaner; +import java.nio.Buffer; import java.nio.charset.Charset; import java.nio.charset.StandardCharsets; import java.util.Arrays; @@ -33,7 +39,10 @@ import java.util.IdentityHashMap; import java.util.List; import java.util.Map; +import java.util.Random; import java.util.Set; +import java.util.SplittableRandom; +import java.util.zip.ZipFile; import javax.management.MBeanServerConnection; @@ -72,9 +81,24 @@ public List> getRequiredFeatures() { } @Override - public void duringSetup(DuringSetupAccess access) { - classInitialization = ((FeatureImpl.DuringSetupAccessImpl) access).getHostVM().getClassInitializationSupport(); - access.registerObjectReplacer(this::replacer); + public void duringSetup(DuringSetupAccess a) { + FeatureImpl.DuringSetupAccessImpl access = (FeatureImpl.DuringSetupAccessImpl) a; + classInitialization = access.getHostVM().getClassInitializationSupport(); + access.registerObjectReachableCallback(String.class, this::onStringReachable); + access.registerObjectReachableCallback(byte[].class, this::onByteArrayReachable); + access.registerObjectReachableCallback(MBeanServerConnection.class, this::onMBeanServerConnectionReachable); + access.registerObjectReachableCallback(PlatformManagedObject.class, this::onPlatformManagedObjectReachable); + access.registerObjectReachableCallback(Random.class, (a1, obj) -> DisallowedImageHeapObjects.onRandomReachable(obj, this::error)); + access.registerObjectReachableCallback(SplittableRandom.class, (a1, obj) -> DisallowedImageHeapObjects.onSplittableRandomReachable(obj, this::error)); + access.registerObjectReachableCallback(Thread.class, (a1, obj) -> DisallowedImageHeapObjects.onThreadReachable(obj, this::error)); + access.registerObjectReachableCallback(DisallowedImageHeapObjects.CONTINUATION_CLASS, (a1, obj) -> DisallowedImageHeapObjects.onContinuationReachable(obj, this::error)); + access.registerObjectReachableCallback(FileDescriptor.class, (a1, obj) -> DisallowedImageHeapObjects.onFileDescriptorReachable(obj, this::error)); + access.registerObjectReachableCallback(Buffer.class, (a1, obj) -> DisallowedImageHeapObjects.onBufferReachable(obj, this::error)); + access.registerObjectReachableCallback(Cleaner.Cleanable.class, (a1, obj) -> DisallowedImageHeapObjects.onCleanableReachable(obj, this::error)); + access.registerObjectReachableCallback(LEGACY_CLEANER_CLASS, (a1, obj) -> DisallowedImageHeapObjects.onCleanableReachable(obj, this::error)); + access.registerObjectReachableCallback(Cleaner.class, (a1, obj) -> DisallowedImageHeapObjects.onCleanerReachable(obj, this::error)); + access.registerObjectReachableCallback(ZipFile.class, (a1, obj) -> DisallowedImageHeapObjects.onZipFileReachable(obj, this::error)); + access.registerObjectReachableCallback(CANCELLABLE_CLASS, (a1, obj) -> DisallowedImageHeapObjects.onCancellableReachable(obj, this::error)); if (SubstrateOptions.DetectUserDirectoriesInImageHeap.getValue()) { /* @@ -111,11 +135,8 @@ private static String[] getDisallowedSubstrings(String... substrings) { }).toArray(String[]::new); } - private Object replacer(Object original) { - checkDisallowedMBeanObjects(original); - - if (original instanceof String && disallowedSubstrings != null) { - String string = (String) original; + private void onStringReachable(DuringAnalysisAccess a, String string) { + if (disallowedSubstrings != null) { for (String disallowedSubstring : disallowedSubstrings) { if (string.contains(disallowedSubstring)) { throw new UnsupportedFeatureException("Detected a string in the image heap that contains a user directory. " + @@ -126,9 +147,10 @@ private Object replacer(Object original) { } } } + } - if (original instanceof byte[] && disallowedByteSubstrings != null) { - byte[] bytes = (byte[]) original; + private void onByteArrayReachable(DuringAnalysisAccess a, byte[] bytes) { + if (disallowedByteSubstrings != null) { for (Map.Entry entry : disallowedByteSubstrings.entrySet()) { byte[] disallowedSubstring = entry.getKey(); if (search(bytes, disallowedSubstring)) { @@ -141,24 +163,27 @@ private Object replacer(Object original) { } } } - - DisallowedImageHeapObjects.check(original, this::error); - return original; } - /** See {@link ManagementSupport} for details why these objects are not allowed. */ - private void checkDisallowedMBeanObjects(Object original) { - if (original instanceof MBeanServerConnection) { - throw error("Detected a MBean server in the image heap. This is currently not supported, but could be changed in the future. " + - "Management beans are registered in many global caches that would need to be cleared and properly re-built at image build time. " + - "Class of disallowed object: " + original.getClass().getTypeName(), - original, "Try to avoid initializing the class that stores a MBean server or a MBean in a static field"); + /** + * See {@link ManagementSupport} for details why these objects are not allowed. + */ + private void onMBeanServerConnectionReachable(DuringAnalysisAccess a, MBeanServerConnection serverConnection) { + throw error("Detected a MBean server in the image heap. This is currently not supported, but could be changed in the future. " + + "Management beans are registered in many global caches that would need to be cleared and properly re-built at image build time. " + + "Class of disallowed object: " + serverConnection.getClass().getTypeName(), + serverConnection, "Try to avoid initializing the class that stores a MBean server or a MBean in a static field"); + } - } else if (original instanceof PlatformManagedObject && !ManagementSupport.getSingleton().isAllowedPlatformManagedObject((PlatformManagedObject) original)) { + /** + * See {@link ManagementSupport} for details why these objects are not allowed. + */ + private void onPlatformManagedObjectReachable(DuringAnalysisAccess a, PlatformManagedObject platformManagedObject) { + if (!ManagementSupport.getSingleton().isAllowedPlatformManagedObject(platformManagedObject)) { throw error("Detected a PlatformManagedObject (a MXBean defined by the virtual machine) in the image heap. " + "This bean is introspecting the VM that runs the image builder, i.e., a VM instance that is no longer available at image runtime. " + - "Class of disallowed object: " + original.getClass().getTypeName(), - original, "Try to avoid initializing the class that stores the object in a static field"); + "Class of disallowed object: " + platformManagedObject.getClass().getTypeName(), + platformManagedObject, "Try to avoid initializing the class that stores the object in a static field"); } } From dd8fc916524fb3e0f9dbe27e9901e67bce929eab Mon Sep 17 00:00:00 2001 From: Fabio Niephaus Date: Fri, 12 Jan 2024 11:08:47 +0100 Subject: [PATCH 434/593] Add ole32.lib as AWT linking dependency on Windows. --- .../com/oracle/svm/hosted/jdk/JNIRegistrationAWTSupport.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/jdk/JNIRegistrationAWTSupport.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/jdk/JNIRegistrationAWTSupport.java index 569b4690e0fa..3705e8f70fc1 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/jdk/JNIRegistrationAWTSupport.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/jdk/JNIRegistrationAWTSupport.java @@ -103,10 +103,11 @@ public void beforeImageWrite(BeforeImageWriteAccess access) { if (isWindows() && JNIRegistrationSupport.singleton().isRegisteredLibrary("awt")) { ((BeforeImageWriteAccessImpl) access).registerLinkerInvocationTransformer(linkerInvocation -> { /* - * Add a Windows library that is pulled in as a side effect of exporting the + * Add Windows libraries that are pulled in as a side effect of exporting the * `getEncodingFromLangID` and `getJavaIDFromLangID` symbols. */ linkerInvocation.addNativeLinkerOption("shell32.lib"); + linkerInvocation.addNativeLinkerOption("ole32.lib"); return linkerInvocation; }); } From bb8582b32432b955f84777b15ba6a7f6e593c1ed Mon Sep 17 00:00:00 2001 From: ol-automation_ww Date: Fri, 12 Jan 2024 10:49:54 +0000 Subject: [PATCH 435/593] update JVMCI to 23+5-jvmci-b01 --- common.json | 14 +++++++------- .../graal/compiler/hotspot/JVMCIVersionCheck.java | 4 ++-- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/common.json b/common.json index 3de3235179e8..d66895606c42 100644 --- a/common.json +++ b/common.json @@ -44,13 +44,13 @@ "labsjdk-ee-21Debug": {"name": "labsjdk", "version": "ee-21.0.1+11-jvmci-23.1-b26-debug", "platformspecific": true }, "labsjdk-ee-21-llvm": {"name": "labsjdk", "version": "ee-21.0.1+11-jvmci-23.1-b26-sulong", "platformspecific": true }, - "oraclejdk-latest": {"name": "jpg-jdk", "version": "23", "build_id": "4", "release": true, "platformspecific": true, "extrabundles": ["static-libs"]}, - "labsjdk-ce-latest": {"name": "labsjdk", "version": "ce-23+4-jvmci-b01", "platformspecific": true }, - "labsjdk-ce-latestDebug": {"name": "labsjdk", "version": "ce-23+4-jvmci-b01-debug", "platformspecific": true }, - "labsjdk-ce-latest-llvm": {"name": "labsjdk", "version": "ce-23+4-jvmci-b01-sulong", "platformspecific": true }, - "labsjdk-ee-latest": {"name": "labsjdk", "version": "ee-23+4-jvmci-b01", "platformspecific": true }, - "labsjdk-ee-latestDebug": {"name": "labsjdk", "version": "ee-23+4-jvmci-b01-debug", "platformspecific": true }, - "labsjdk-ee-latest-llvm": {"name": "labsjdk", "version": "ee-23+4-jvmci-b01-sulong", "platformspecific": true } + "oraclejdk-latest": {"name": "jpg-jdk", "version": "23", "build_id": "5", "release": true, "platformspecific": true, "extrabundles": ["static-libs"]}, + "labsjdk-ce-latest": {"name": "labsjdk", "version": "ce-23+5-jvmci-b01-20240112101422-340c6f0aca", "platformspecific": true }, + "labsjdk-ce-latestDebug": {"name": "labsjdk", "version": "ce-23+5-jvmci-b01-20240112101422-340c6f0aca-debug", "platformspecific": true }, + "labsjdk-ce-latest-llvm": {"name": "labsjdk", "version": "ce-23+5-jvmci-b01-20240112101422-340c6f0aca-sulong", "platformspecific": true }, + "labsjdk-ee-latest": {"name": "labsjdk", "version": "ee-23+5-jvmci-b01-20240112101422-340c6f0aca+8a910e360e", "platformspecific": true }, + "labsjdk-ee-latestDebug": {"name": "labsjdk", "version": "ee-23+5-jvmci-b01-20240112101422-340c6f0aca+8a910e360e-debug", "platformspecific": true }, + "labsjdk-ee-latest-llvm": {"name": "labsjdk", "version": "ee-23+5-jvmci-b01-20240112101422-340c6f0aca+8a910e360e-sulong", "platformspecific": true } }, "eclipse": { diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/JVMCIVersionCheck.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/JVMCIVersionCheck.java index ed7c992ba231..790aaa7808ec 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/JVMCIVersionCheck.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/JVMCIVersionCheck.java @@ -54,8 +54,8 @@ public final class JVMCIVersionCheck { private static final Map> JVMCI_MIN_VERSIONS = Map.of( "21", Map.of(DEFAULT_VENDOR_ENTRY, new Version(23, 1, 26)), "23", Map.of( - "Oracle Corporation", new Version("23+4", 1), - DEFAULT_VENDOR_ENTRY, new Version("23+4", 1))); + "Oracle Corporation", new Version("23+5", 1), + DEFAULT_VENDOR_ENTRY, new Version("23+5", 1))); private static final int NA = 0; /** * Minimum Java release supported by Graal. From 3b96a9a587f28f496eb98f192b37874f8f62bd52 Mon Sep 17 00:00:00 2001 From: Gilles Duboscq Date: Fri, 12 Jan 2024 14:27:09 +0100 Subject: [PATCH 436/593] Allow any host java version --- .../com/oracle/truffle/espresso/runtime/EspressoContext.java | 3 +++ .../src/com/oracle/truffle/espresso/runtime/JavaVersion.java | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/runtime/EspressoContext.java b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/runtime/EspressoContext.java index 88ed90416a32..724ee8e30292 100644 --- a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/runtime/EspressoContext.java +++ b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/runtime/EspressoContext.java @@ -388,6 +388,9 @@ private void spawnVM() throws ContextPatchingException { vmProperties.javaHome(), vmProperties.bootLibraryPath(), JavaVersion.latestSupported())); } } + if (contextJavaVersion.compareTo(JavaVersion.latestSupported()) > 0) { + throw EspressoError.fatal("Unsupported Java version: " + contextJavaVersion); + } this.downcallStubs = new DowncallStubs(Platform.getHostPlatform()); this.upcallStubs = new UpcallStubs(Platform.getHostPlatform(), nativeAccess, language); diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/runtime/JavaVersion.java b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/runtime/JavaVersion.java index ebb2a26e2cdf..e790d19c5dbd 100644 --- a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/runtime/JavaVersion.java +++ b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/runtime/JavaVersion.java @@ -70,7 +70,7 @@ public boolean contains(JavaVersion version) { } public static JavaVersion forVersion(int version) { - if (version < 1 || version > LATEST_SUPPORTED) { + if (version < 1) { throw new IllegalArgumentException("Unsupported java version: " + version); } return new JavaVersion(version); From d87076d1a3b9b253aface167f696f8c26234d010 Mon Sep 17 00:00:00 2001 From: Roland Schatz Date: Thu, 16 Nov 2023 16:49:52 +0100 Subject: [PATCH 437/593] Use correct assembler for JNI trampoline methods, and add endbranch if CFI is enabled. --- .../jdk/graal/compiler/asm/amd64/AMD64Assembler.java | 2 +- .../svm/core/graal/amd64/SubstrateAMD64Backend.java | 11 ++++++++++- 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/asm/amd64/AMD64Assembler.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/asm/amd64/AMD64Assembler.java index 42468b96b5f0..2427d2cc5453 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/asm/amd64/AMD64Assembler.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/asm/amd64/AMD64Assembler.java @@ -4985,7 +4985,7 @@ public final void call(Register src) { emitModRM(2, src); } - protected final void endbranch() { + public final void endbranch() { emitByte(0xf3); emitByte(0x0f); emitByte(0x1e); diff --git a/substratevm/src/com.oracle.svm.core.graal.amd64/src/com/oracle/svm/core/graal/amd64/SubstrateAMD64Backend.java b/substratevm/src/com.oracle.svm.core.graal.amd64/src/com/oracle/svm/core/graal/amd64/SubstrateAMD64Backend.java index b9969cbb5cc0..8eecaddfb577 100644 --- a/substratevm/src/com.oracle.svm.core.graal.amd64/src/com/oracle/svm/core/graal/amd64/SubstrateAMD64Backend.java +++ b/substratevm/src/com.oracle.svm.core.graal.amd64/src/com/oracle/svm/core/graal/amd64/SubstrateAMD64Backend.java @@ -43,6 +43,7 @@ import java.util.EnumSet; import java.util.function.BiConsumer; +import org.graalvm.collections.EconomicMap; import org.graalvm.nativeimage.ImageSingletons; import com.oracle.svm.core.CPUFeatureAccess; @@ -1530,12 +1531,20 @@ public void emitCode(CompilationResultBuilder crb, ResolvedJavaMethod installedC crb.emitLIR(); } + private AMD64Assembler createAssemblerNoOptions() { + OptionValues o = new OptionValues(EconomicMap.create()); + return createAssembler(o); + } + @Override public CompilationResult createJNITrampolineMethod(ResolvedJavaMethod method, CompilationIdentifier identifier, RegisterValue threadArg, int threadIsolateOffset, RegisterValue methodIdArg, int methodObjEntryPointOffset) { CompilationResult result = new CompilationResult(identifier); - AMD64Assembler asm = new AMD64Assembler(getTarget()); + AMD64Assembler asm = createAssemblerNoOptions(); + if (SubstrateControlFlowIntegrity.enabled()) { + asm.endbranch(); + } if (SubstrateOptions.SpawnIsolates.getValue()) { // method id is offset from heap base asm.movq(rax, new AMD64Address(threadArg.getRegister(), threadIsolateOffset)); /* From e58c55e71021c8cfd5d2b6a4ba347f67cc24b2b5 Mon Sep 17 00:00:00 2001 From: Roland Schatz Date: Tue, 19 Dec 2023 17:26:33 +0100 Subject: [PATCH 438/593] Export package. --- substratevm/mx.substratevm/suite.py | 1 + 1 file changed, 1 insertion(+) diff --git a/substratevm/mx.substratevm/suite.py b/substratevm/mx.substratevm/suite.py index 588ffc63d50f..509f42ce1483 100644 --- a/substratevm/mx.substratevm/suite.py +++ b/substratevm/mx.substratevm/suite.py @@ -1455,6 +1455,7 @@ org.graalvm.nativeimage.foreign, org.graalvm.truffle.runtime.svm, com.oracle.truffle.enterprise.svm""", + "com.oracle.svm.hosted.c.libc to com.oracle.graal.sandbox", ], "opens" : [ "com.oracle.svm.core to jdk.graal.compiler", From 59351aae01b3f70da6087585fea581f1e81cf768 Mon Sep 17 00:00:00 2001 From: Doug Simon Date: Thu, 11 Jan 2024 10:42:02 +0100 Subject: [PATCH 439/593] add PrintPropertiesAll for printing all Graal options --- compiler/CHANGELOG.md | 3 +++ .../compiler/hotspot/test/CompileTheWorld.java | 2 +- .../test/HotSpotGraalOptionValuesTest.java | 10 ++++++---- .../compiler/options/test/TestOptionKey.java | 13 ++++++++++++- .../hotspot/HotSpotGraalCompilerFactory.java | 15 ++++++++++++++- .../jdk/graal/compiler/options/OptionValues.java | 11 +++++------ 6 files changed, 41 insertions(+), 13 deletions(-) diff --git a/compiler/CHANGELOG.md b/compiler/CHANGELOG.md index cc49d855f02d..bf34c6c73a15 100644 --- a/compiler/CHANGELOG.md +++ b/compiler/CHANGELOG.md @@ -2,6 +2,9 @@ This changelog summarizes newly introduced optimizations and other compiler related changes. +## GraalVM for JDK 23 (Internal Version 24.1.0) +* (GR-50352): Added `-Djdk.graal.PrintPropertiesAll` to make `-XX:+JVMCIPrintProperties` show all Graal options. + ## GraalVM for JDK 22 (Internal Version 24.0.0) * (GR-49876): Added `-Dgraal.PrintIntrinsics=true` to log the intrinsics used by Graal in the current runtime. * (GR-49960): The Graal options now use the `jdk.graal.` prefix (e.g. `-Djdk.graal.PrintCompilation=true`). diff --git a/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/hotspot/test/CompileTheWorld.java b/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/hotspot/test/CompileTheWorld.java index 148ba982229d..0b1eb8a4cbb2 100644 --- a/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/hotspot/test/CompileTheWorld.java +++ b/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/hotspot/test/CompileTheWorld.java @@ -1500,7 +1500,7 @@ public static OptionValues loadHarnessOptions() { OptionsParser.parseOptions(extractEntries(System.getProperties(), "CompileTheWorld.", true), values, loader); OptionValues options = new OptionValues(values); if (Options.Help.getValue(options)) { - options.printHelp(loader, System.out, "CompileTheWorld."); + options.printHelp(loader, System.out, "CompileTheWorld.", true); System.exit(0); } return options; diff --git a/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/hotspot/test/HotSpotGraalOptionValuesTest.java b/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/hotspot/test/HotSpotGraalOptionValuesTest.java index ad9ed9f22f80..8edeb5124b95 100644 --- a/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/hotspot/test/HotSpotGraalOptionValuesTest.java +++ b/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/hotspot/test/HotSpotGraalOptionValuesTest.java @@ -41,10 +41,12 @@ public class HotSpotGraalOptionValuesTest extends HotSpotGraalCompilerTest { @Test public void testPrintHelp() throws IOException { OptionValues options = getInitialOptions(); - try (ByteArrayOutputStream baos = new ByteArrayOutputStream()) { - PrintStream out = new PrintStream(baos); - options.printHelp(OptionsParser.getOptionsLoader(), out, GRAAL_OPTION_PROPERTY_PREFIX); - Assert.assertNotEquals(baos.size(), 0); + for (boolean all : new boolean[]{true, false}) { + try (ByteArrayOutputStream baos = new ByteArrayOutputStream()) { + PrintStream out = new PrintStream(baos); + options.printHelp(OptionsParser.getOptionsLoader(), out, GRAAL_OPTION_PROPERTY_PREFIX, all); + Assert.assertNotEquals(baos.size(), 0); + } } } } diff --git a/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/options/test/TestOptionKey.java b/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/options/test/TestOptionKey.java index a687f06b8a85..e0560e10e070 100644 --- a/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/options/test/TestOptionKey.java +++ b/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/options/test/TestOptionKey.java @@ -28,6 +28,7 @@ import static jdk.graal.compiler.options.OptionValues.newOptionMap; import static jdk.graal.compiler.options.OptionsParser.parseOptionValue; import static jdk.graal.compiler.options.test.TestOptionKey.Options.MyBooleanOption; +import static jdk.graal.compiler.options.test.TestOptionKey.Options.MyDebugOption; import static jdk.graal.compiler.options.test.TestOptionKey.Options.MyDeprecatedOption; import static jdk.graal.compiler.options.test.TestOptionKey.Options.MyDoubleOption; import static jdk.graal.compiler.options.test.TestOptionKey.Options.MyFloatOption; @@ -90,12 +91,14 @@ public static class Options { public static final OptionKey MyOtherOption = new OptionKey<>("original"); public static final EnumMultiOptionKey MyMultiEnumOption = new EnumMultiOptionKey<>(TestEnum.class, null); public static final OptionKey MyDeprecatedOption = new OptionKey<>("deprecated"); + public static final OptionKey MyDebugOption = new OptionKey<>("debug"); } private static final OptionDescriptors OPTION_DESCRIPTORS; static { EconomicMap map = EconomicMap.create(); map.put("MyOption", OptionDescriptor.create("MyOption", OptionType.User, String.class, "", Options.class, "MyOption", MyOption)); + map.put("MyDebugOption", OptionDescriptor.create("MyDebugOption", OptionType.Debug, String.class, "", Options.class, "MyDebugOption", MyDebugOption)); map.put("MyIntegerOption", OptionDescriptor.create("MyIntegerOption", OptionType.User, Integer.class, "", Options.class, "MyIntegerOption", MyIntegerOption)); map.put("MyLongOption", OptionDescriptor.create("MyLongOption", OptionType.User, Long.class, "", Options.class, "MyLongOption", MyLongOption)); map.put("MyBooleanOption", OptionDescriptor.create("MyBooleanOption", OptionType.User, Boolean.class, "", Options.class, "MyBooleanOption", MyBooleanOption)); @@ -141,11 +144,19 @@ public void testToString() throws IOException { try (ByteArrayOutputStream baos = new ByteArrayOutputStream()) { Iterable loader = List.of(OPTION_DESCRIPTORS); - optionsValues.printHelp(loader, new PrintStream(baos), "prefix."); + optionsValues.printHelp(loader, new PrintStream(baos), "prefix.", false); String help = baos.toString(); Assert.assertNotEquals(help.length(), 0); Assert.assertTrue(help, help.contains("prefix.MyDeprecatedOption = \"deprecated\"")); } + + try (ByteArrayOutputStream baos = new ByteArrayOutputStream()) { + Iterable loader = List.of(OPTION_DESCRIPTORS); + optionsValues.printHelp(loader, new PrintStream(baos), "prefix.", true); + String help = baos.toString(); + Assert.assertNotEquals(help.length(), 0); + Assert.assertTrue(help, help.contains("prefix.MyDebugOption = \"debug\"")); + } } @Test diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/HotSpotGraalCompilerFactory.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/HotSpotGraalCompilerFactory.java index 299225cfe61e..f780fb386b32 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/HotSpotGraalCompilerFactory.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/HotSpotGraalCompilerFactory.java @@ -34,6 +34,7 @@ import jdk.graal.compiler.api.runtime.GraalRuntime; import jdk.graal.compiler.debug.MethodFilter; +import jdk.graal.compiler.debug.TTY; import jdk.graal.compiler.options.Option; import jdk.graal.compiler.options.OptionKey; import jdk.graal.compiler.options.OptionType; @@ -44,6 +45,7 @@ import jdk.vm.ci.hotspot.HotSpotJVMCICompilerFactory; import jdk.vm.ci.hotspot.HotSpotJVMCIRuntime; import jdk.vm.ci.hotspot.HotSpotResolvedJavaMethod; +import jdk.vm.ci.hotspot.HotSpotVMConfigAccess; import jdk.vm.ci.meta.Signature; import jdk.vm.ci.runtime.JVMCICompilerFactory; import jdk.vm.ci.runtime.JVMCIRuntime; @@ -157,7 +159,8 @@ public void printProperties(PrintStream out) { System.err.printf("Error parsing Graal options: %s%n", optionsFailure.getMessage()); return; } - options.printHelp(OptionsParser.getOptionsLoader(), out, GRAAL_OPTION_PROPERTY_PREFIX); + boolean all = Options.PrintPropertiesAll.getValue(options); + options.printHelp(OptionsParser.getOptionsLoader(), out, GRAAL_OPTION_PROPERTY_PREFIX, all); } static class Options { @@ -170,6 +173,8 @@ static class Options { "A method not matching the filter is redirected to a lower tier compiler. " + "The filter format is the same as for the MethodFilter option.", type = OptionType.Expert) public static final OptionKey GraalCompileOnly = new OptionKey<>(null); + @Option(help = "Make JVMCIPrintProperties show all Graal options, including debug and internal options.", type = OptionType.Debug) + public static final OptionKey PrintPropertiesAll = new OptionKey<>(false); // @formatter:on } @@ -182,6 +187,14 @@ public HotSpotGraalCompiler createCompiler(JVMCIRuntime runtime) { System.err.printf("Error parsing Graal options: %s%nError: A fatal exception has occurred. Program will exit.%n", optionsFailure.getMessage()); HotSpotGraalServices.exit(1, hsRuntime); } + + if (Options.PrintPropertiesAll.getValue(options)) { + HotSpotVMConfigAccess config = new HotSpotVMConfigAccess(hsRuntime.getConfigStore()); + if (!config.getFlag("JVMCIPrintProperties", Boolean.class)) { + TTY.printf("Warning: Ignoring %s since JVMCIPrintProperties is false%n", Options.PrintPropertiesAll.getName()); + } + } + CompilerConfigurationFactory factory = CompilerConfigurationFactory.selectFactory(null, options, hsRuntime); if (isGraalPredicate != null) { isGraalPredicate.onCompilerConfigurationFactorySelection(hsRuntime, factory); diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/options/OptionValues.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/options/OptionValues.java index f6b9723c3021..70ba07e17712 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/options/OptionValues.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/options/OptionValues.java @@ -188,15 +188,14 @@ private static List wrap(String text, int width) { } /** - * Prints a help message to {@code out} describing all options available via {@code loader}. The + * Prints a help message to {@code out} describing the options available via {@code loader}. The * key/value for each option is separated by {@code :=} if the option has an entry in this * object otherwise {@code =} is used as the separator. * - * @param loader - * @param out - * @param namePrefix + * @param all if true, all options are printed otherwise only {@linkplain #excludeOptionFromHelp + * non-excluded} options are printed. */ - public void printHelp(Iterable loader, PrintStream out, String namePrefix) { + public void printHelp(Iterable loader, PrintStream out, String namePrefix, boolean all) { SortedMap sortedOptions = new TreeMap<>(); for (OptionDescriptors opts : loader) { for (OptionDescriptor desc : opts) { @@ -208,7 +207,7 @@ public void printHelp(Iterable loader, PrintStream out, Strin for (Map.Entry e : sortedOptions.entrySet()) { String key = e.getKey(); OptionDescriptor desc = e.getValue(); - if (!excludeOptionFromHelp(key, desc)) { + if (all || !excludeOptionFromHelp(key, desc)) { printHelp(out, namePrefix, key, desc); } } From 985cc326d56f063226b26ea57d6ecb50b97cbacf Mon Sep 17 00:00:00 2001 From: Fabio Niephaus Date: Fri, 12 Jan 2024 15:22:06 +0100 Subject: [PATCH 440/593] showOutOfMemoryWarning if builder is OOMKilled. --- .../src/com/oracle/svm/core/util/ExitStatus.java | 2 ++ .../src/com/oracle/svm/driver/NativeImage.java | 4 ++-- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/util/ExitStatus.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/util/ExitStatus.java index 0b56b0d8e6ef..3f7aa369b670 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/util/ExitStatus.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/util/ExitStatus.java @@ -32,6 +32,8 @@ public enum ExitStatus { // 3 used by `-XX:+ExitOnOutOfMemoryError` (see src/hotspot/share/utilities/debug.cpp) OUT_OF_MEMORY(3), + // Used by OOMKilled in containers + OUT_OF_MEMORY_KILLED(137), BUILDER_INTERRUPT_WITHOUT_REASON(4), DRIVER_ERROR(20), diff --git a/substratevm/src/com.oracle.svm.driver/src/com/oracle/svm/driver/NativeImage.java b/substratevm/src/com.oracle.svm.driver/src/com/oracle/svm/driver/NativeImage.java index 7c03164d2a3d..aa087d4b783e 100644 --- a/substratevm/src/com.oracle.svm.driver/src/com/oracle/svm/driver/NativeImage.java +++ b/substratevm/src/com.oracle.svm.driver/src/com/oracle/svm/driver/NativeImage.java @@ -1634,7 +1634,7 @@ protected int buildImage(List javaArgs, LinkedHashSet cp, LinkedHa /* Exit, builder has handled error reporting. */ throw NativeImage.showError(null, null, exitStatusCode); } - case OUT_OF_MEMORY -> { + case OUT_OF_MEMORY, OUT_OF_MEMORY_KILLED -> { showOutOfMemoryWarning(); throw NativeImage.showError(null, null, exitStatusCode); } @@ -1882,7 +1882,7 @@ private static void build(BuildConfiguration config, Function Date: Fri, 12 Jan 2024 16:34:55 +0100 Subject: [PATCH 441/593] Update copyright year to pass mx checkcopyrights --- .../org.graalvm.polyglot/src/org/graalvm/polyglot/Source.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sdk/src/org.graalvm.polyglot/src/org/graalvm/polyglot/Source.java b/sdk/src/org.graalvm.polyglot/src/org/graalvm/polyglot/Source.java index 11c79b4ed2bb..a3609f853028 100644 --- a/sdk/src/org.graalvm.polyglot/src/org/graalvm/polyglot/Source.java +++ b/sdk/src/org.graalvm.polyglot/src/org/graalvm/polyglot/Source.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * The Universal Permissive License (UPL), Version 1.0 From 64d9520e1e6a6ea1e92de2cb130806bfc9629acf Mon Sep 17 00:00:00 2001 From: Tomas Zezula Date: Fri, 12 Jan 2024 17:02:31 +0100 Subject: [PATCH 442/593] [GR-51318] The _test_libgraal_truffle contains an unused code. --- vm/mx.vm/mx_vm_gate.py | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/vm/mx.vm/mx_vm_gate.py b/vm/mx.vm/mx_vm_gate.py index e6a8d0a1f2b0..c7af88058231 100644 --- a/vm/mx.vm/mx_vm_gate.py +++ b/vm/mx.vm/mx_vm_gate.py @@ -466,17 +466,6 @@ def _test_libgraal_ctw(extra_vm_arguments): ], extra_vm_arguments) def _test_libgraal_truffle(extra_vm_arguments): - def _unittest_config_participant(config): - vmArgs, mainClass, mainClassArgs = config - def is_truffle_fallback(arg): - fallback_args = [ - "-Dtruffle.TruffleRuntime=com.oracle.truffle.api.impl.DefaultTruffleRuntime", - "-Dgraalvm.ForcePolyglotInvalid=true" - ] - return arg in fallback_args - newVmArgs = [arg for arg in vmArgs if not is_truffle_fallback(arg)] - return (newVmArgs, mainClass, mainClassArgs) - mx_unittest.add_config_participant(_unittest_config_participant) excluded_tests = environ.get("TEST_LIBGRAAL_EXCLUDE") if excluded_tests: with NamedTemporaryFile(prefix='blacklist.', mode='w', delete=False) as fp: From 4aad6b3014680503d28809bd3c6d4e4ab34e4d0f Mon Sep 17 00:00:00 2001 From: Gilles Duboscq Date: Fri, 12 Jan 2024 14:31:35 +0100 Subject: [PATCH 443/593] Initialize java version earlier Drop guest java version detection using JDK_GetVersionInfo0, always use release file --- .../espresso/runtime/EspressoContext.java | 60 +++++++++++-------- .../com/oracle/truffle/espresso/vm/VM.java | 31 +--------- .../espresso/vm/structs/StructWrapper.java | 22 ------- 3 files changed, 36 insertions(+), 77 deletions(-) diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/runtime/EspressoContext.java b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/runtime/EspressoContext.java index 724ee8e30292..3f7f7d5671da 100644 --- a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/runtime/EspressoContext.java +++ b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/runtime/EspressoContext.java @@ -373,38 +373,36 @@ private void spawnVM() throws ContextPatchingException { this.nativeAccess = spawnNativeAccess(); initVmProperties(); + // Find guest java version + JavaVersion contextJavaVersion = javaVersionFromReleaseFile(vmProperties.javaHome()); + if (contextJavaVersion == null) { + contextJavaVersion = JavaVersion.latestSupported(); + getLogger().warning(() -> "Couldn't find Java version for %s / %s: defaulting to %s".formatted( + vmProperties.javaHome(), vmProperties.bootLibraryPath(), JavaVersion.latestSupported())); + } else if (contextJavaVersion.compareTo(JavaVersion.latestSupported()) > 0) { + throw EspressoError.fatal("Unsupported Java version: " + contextJavaVersion); + } + + // Ensure that the extracted Java version equals the language's Java version, if it + // is set + JavaVersion languageJavaVersion = getLanguage().getJavaVersion(); + if (languageJavaVersion != null) { + if (!contextJavaVersion.equals(languageJavaVersion)) { + throw ContextPatchingException.javaVersionMismatch(languageJavaVersion, contextJavaVersion); + } + } else { + getLanguage().tryInitializeJavaVersion(contextJavaVersion); + } + // Spawn JNI first, then the VM. try (DebugCloseable vmInit = VM_INIT.scope(espressoEnv.getTimers())) { this.jniEnv = JniEnv.create(this); // libnespresso this.vm = VM.create(this.jniEnv); // libjvm vm.attachThread(Thread.currentThread()); - // The Java version is extracted from libjava and is available after this line. - JavaVersion contextJavaVersion = vm.loadJavaLibrary(vmProperties.bootLibraryPath()); // libjava - if (contextJavaVersion == null) { - contextJavaVersion = javaVersionFromReleaseFile(vmProperties.javaHome()); - if (contextJavaVersion == null) { - contextJavaVersion = JavaVersion.latestSupported(); - getLogger().warning(() -> "Couldn't find Java version for %s / %s: defaulting to %s".formatted( - vmProperties.javaHome(), vmProperties.bootLibraryPath(), JavaVersion.latestSupported())); - } - } - if (contextJavaVersion.compareTo(JavaVersion.latestSupported()) > 0) { - throw EspressoError.fatal("Unsupported Java version: " + contextJavaVersion); - } + vm.loadJavaLibrary(vmProperties.bootLibraryPath()); // libjava this.downcallStubs = new DowncallStubs(Platform.getHostPlatform()); this.upcallStubs = new UpcallStubs(Platform.getHostPlatform(), nativeAccess, language); - // Ensure that the extracted Java version equals the language's Java version, if it - // is set - JavaVersion languageJavaVersion = getLanguage().getJavaVersion(); - if (languageJavaVersion != null) { - if (!contextJavaVersion.equals(languageJavaVersion)) { - throw ContextPatchingException.javaVersionMismatch(languageJavaVersion, contextJavaVersion); - } - } else { - getLanguage().tryInitializeJavaVersion(contextJavaVersion); - } - vm.initializeJavaLibrary(); EspressoError.guarantee(getJavaVersion() != null, "Java version"); } @@ -540,7 +538,19 @@ private void spawnVM() throws ContextPatchingException { private JavaVersion javaVersionFromReleaseFile(Path javaHome) { Path releaseFilePath = javaHome.resolve("release"); if (!Files.isRegularFile(releaseFilePath)) { - return null; + Path maybeJre = javaHome.getFileName(); + if (maybeJre == null || !"jre".equals(maybeJre.toString())) { + return null; + } + Path parent = javaHome.getParent(); + if (parent == null) { + return null; + } + // pre-jdk9 layout + releaseFilePath = parent.resolve("release"); + if (!Files.isRegularFile(releaseFilePath)) { + return null; + } } try { for (String line : Files.readAllLines(releaseFilePath)) { diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/vm/VM.java b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/vm/VM.java index 0c6168c361d0..96409aff4e82 100644 --- a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/vm/VM.java +++ b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/vm/VM.java @@ -138,7 +138,6 @@ import com.oracle.truffle.espresso.runtime.EspressoException; import com.oracle.truffle.espresso.runtime.EspressoExitException; import com.oracle.truffle.espresso.runtime.EspressoProperties; -import com.oracle.truffle.espresso.runtime.JavaVersion; import com.oracle.truffle.espresso.runtime.MethodHandleIntrinsics; import com.oracle.truffle.espresso.runtime.OS; import com.oracle.truffle.espresso.runtime.staticobject.StaticObject; @@ -155,7 +154,6 @@ import com.oracle.truffle.espresso.threads.Transition; import com.oracle.truffle.espresso.vm.npe.ExtendedNPEMessage; import com.oracle.truffle.espresso.vm.structs.JavaVMAttachArgs; -import com.oracle.truffle.espresso.vm.structs.JdkVersionInfo; import com.oracle.truffle.espresso.vm.structs.Structs; import com.oracle.truffle.espresso.vm.structs.StructsAccess; @@ -249,36 +247,9 @@ public static long getID() { return getNativeAccess().loadLibrary(bootLibraryPath, "java", true); } - private JavaVersion findJavaVersion(TruffleObject libJava) { - // void JDK_GetVersionInfo0(jdk_version_info* info, size_t info_size); - TruffleObject jdkGetVersionInfo = getNativeAccess().lookupAndBindSymbol(libJava, "JDK_GetVersionInfo0", NativeSignature.create(NativeType.VOID, NativeType.POINTER, NativeType.LONG)); - if (jdkGetVersionInfo == null) { - return null; - } - JdkVersionInfo.JdkVersionInfoWrapper wrapper = getStructs().jdkVersionInfo.allocate(getNativeAccess(), jni()); - try { - getUncached().execute(jdkGetVersionInfo, wrapper.pointer(), getStructs().jdkVersionInfo.structSize()); - } catch (UnsupportedTypeException | UnsupportedMessageException | ArityException e) { - throw EspressoError.shouldNotReachHere(e); - } - int versionInfo = wrapper.jdkVersion(); - wrapper.free(getNativeAccess()); - - int major = (versionInfo & 0xFF000000) >> 24; - if (major == 1) { - // Version 1.X - int minor = (versionInfo & 0x00FF0000) >> 16; - return JavaVersion.forVersion(minor); - } else { - // Version X.Y - return JavaVersion.forVersion(major); - } - } - - public JavaVersion loadJavaLibrary(List searchPaths) { + public void loadJavaLibrary(List searchPaths) { assert javaLibrary == null : "java library already initialized"; this.javaLibrary = loadJavaLibraryImpl(searchPaths); - return findJavaVersion(this.javaLibrary); } public void initializeJavaLibrary() { diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/vm/structs/StructWrapper.java b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/vm/structs/StructWrapper.java index 3422dd0dfa98..8eacc45cbd53 100644 --- a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/vm/structs/StructWrapper.java +++ b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/vm/structs/StructWrapper.java @@ -83,28 +83,6 @@ POINTER, OBJECT, }), - /*- - * struct jdk_version_info { - * unsigned int jdk_version; // <- The only one we are interested in. - * unsigned int update_version : 8; - * unsigned int special_update_version : 8; - * unsigned int reserved1 : 16; - * unsigned int reserved2; - * unsigned int thread_park_blocker : 1; - * unsigned int post_vm_init_hook_enabled : 1; - * unsigned int pending_list_uses_discovered_field : 1; - * unsigned int : 29; - * unsigned int : 32; - * unsigned int : 32; - * }; - */ - @KnownStruct(structName = "jdk_version_info", // - memberNames = { - "jdk_version", - }, // - types = { - INT, - }), /*- * struct member_info { * char* id; From 1e84c1fa8bb9352e5ff5c1854d7978d90e013106 Mon Sep 17 00:00:00 2001 From: Gilles Duboscq Date: Fri, 12 Jan 2024 15:30:39 +0100 Subject: [PATCH 444/593] Set ESPRESSO_(LLVM_)?JAVA_HOME --- vm/ci/ci_common/common.jsonnet | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/vm/ci/ci_common/common.jsonnet b/vm/ci/ci_common/common.jsonnet index c84478a34d35..9e31beafec88 100644 --- a/vm/ci/ci_common/common.jsonnet +++ b/vm/ci/ci_common/common.jsonnet @@ -255,9 +255,10 @@ local devkits = graal_common.devkits; local java_deps(edition) = { downloads+: { JAVA_HOME: graal_common.jdks_data['labsjdk-' + edition + '-' + java_version], + ESPRESSO_JAVA_HOME: graal_common.jdks_data['labsjdk-' + edition + '-21'], } + ( - if (os == 'linux' || os == 'darwin') && (arch == 'amd64') && (java_version != 'latest') then { - LLVM_JAVA_HOME: graal_common.jdks_data['labsjdk-' + edition + '-' + java_version + '-llvm'], + if (os == 'linux' || os == 'darwin') && (arch == 'amd64') then { + ESPRESSO_LLVM_JAVA_HOME: graal_common.jdks_data['labsjdk-' + edition + '-21-llvm'], } else { } ) + ( From e6d4c50fda2d7264693f39bc43ed054fe8046adb Mon Sep 17 00:00:00 2001 From: Gilles Duboscq Date: Fri, 12 Jan 2024 16:04:17 +0100 Subject: [PATCH 445/593] Use lower-case variable name --- espresso/mx.espresso/mx_espresso.py | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/espresso/mx.espresso/mx_espresso.py b/espresso/mx.espresso/mx_espresso.py index 831a8382d2f3..fbcf6e3fbf69 100644 --- a/espresso/mx.espresso/mx_espresso.py +++ b/espresso/mx.espresso/mx_espresso.py @@ -36,7 +36,7 @@ _suite = mx.suite('espresso') # JDK compiled with the Sulong toolchain. -ESPRESSO_LLVM_JAVA_HOME = mx.get_env('ESPRESSO_LLVM_JAVA_HOME') or mx.get_env('LLVM_JAVA_HOME') +espresso_llvm_java_home = mx.get_env('ESPRESSO_LLVM_JAVA_HOME') or mx.get_env('LLVM_JAVA_HOME') def _espresso_command(launcher, args): bin_dir = join(mx_sdk_vm.graalvm_home(fatalIfMissing=True), 'bin') @@ -242,7 +242,7 @@ def _espresso_gate_runner(args, tasks): standalone=False, )) -if ESPRESSO_LLVM_JAVA_HOME: +if espresso_llvm_java_home: mx_sdk_vm.register_graalvm_component(mx_sdk_vm.GraalVmLanguage( suite=_suite, name='Java on Truffle LLVM Java libraries', @@ -252,7 +252,7 @@ def _espresso_gate_runner(args, tasks): truffle_jars=[], dir_name='java', installable_id='espresso-llvm', - extra_installable_qualifiers=mx_sdk_vm.extra_installable_qualifiers(jdk_home=ESPRESSO_LLVM_JAVA_HOME, ce_edition=['ce'], oracle_edition=['ee']), + extra_installable_qualifiers=mx_sdk_vm.extra_installable_qualifiers(jdk_home=espresso_llvm_java_home, ce_edition=['ce'], oracle_edition=['ee']), installable=True, dependencies=['Java on Truffle', 'LLVM Runtime Native'], support_distributions=['espresso:ESPRESSO_LLVM_SUPPORT'], @@ -268,13 +268,14 @@ def _jdk_license(home): else: return "GPLv2-CPE" + def mx_register_dynamic_suite_constituents(register_project, register_distribution): """ :type register_project: (mx.Project) -> None :type register_distribution: (mx.Distribution) -> None """ - if ESPRESSO_LLVM_JAVA_HOME: + if espresso_llvm_java_home: # Conditionally creates the ESPRESSO_LLVM_SUPPORT distribution if a Java home with LLVM bitcode is provided. lib_prefix = mx.add_lib_prefix('') lib_suffix = mx.add_lib_suffix('') @@ -283,18 +284,18 @@ def mx_register_dynamic_suite_constituents(register_project, register_distributi f"dependency:LLVM_JAVA_HOME/lib/{lib_prefix}*{lib_suffix}", "dependency:LLVM_JAVA_HOME/release" ], - }, None, True, _jdk_license(ESPRESSO_LLVM_JAVA_HOME))) + }, None, True, _jdk_license(espresso_llvm_java_home))) llvm_runtime_dir = { "source_type": "dependency", "dependency": "LLVM_JAVA_HOME", "path": "lib/", } - register_project(JavaHomeDependency(_suite, "LLVM_JAVA_HOME", ESPRESSO_LLVM_JAVA_HOME)) + register_project(JavaHomeDependency(_suite, "LLVM_JAVA_HOME", espresso_llvm_java_home)) else: llvm_runtime_dir = [] - ESPRESSO_JAVA_HOME = mx.get_env('ESPRESSO_JAVA_HOME') or mx_sdk_vm.base_jdk().home - register_project(JavaHomeDependency(_suite, "JAVA_HOME", ESPRESSO_JAVA_HOME)) + espresso_java_home = mx.get_env('ESPRESSO_JAVA_HOME') or mx_sdk_vm.base_jdk().home + register_project(JavaHomeDependency(_suite, "JAVA_HOME", espresso_java_home)) if mx.is_windows(): platform_specific_excludes = [ "bin/", @@ -436,7 +437,7 @@ def register_espresso_envs(suite): # pylint: disable=line-too-long tools = ['cov', 'dap', 'ins', 'insight', 'insightheap', 'lsp', 'pro', 'truffle-json'] _llvm_toolchain_wrappers = ['bgraalvm-native-clang', 'bgraalvm-native-clang-cl', 'bgraalvm-native-clang++', 'bgraalvm-native-flang', 'bgraalvm-native-ld', 'bgraalvm-native-binutil'] - if ESPRESSO_LLVM_JAVA_HOME: + if espresso_llvm_java_home: mx_sdk_vm.register_vm_config('espresso-jvm', ['java', 'ejvm' , 'ellvm', 'libpoly', 'nfi-libffi', 'nfi', 'sdk', 'sdkni', 'sdkc', 'sdkl', 'tfl', 'tfla', 'tflc' , 'cmp', 'antlr4', 'llrc', 'llrlf', 'llrn' , 'elau' ] + tools, suite, env_file='jvm-llvm') mx_sdk_vm.register_vm_config('espresso-jvm-ce', ['java', 'ejvm' , 'ellvm', 'libpoly', 'nfi-libffi', 'nfi', 'sdk', 'sdkni', 'sdkc', 'sdkl', 'tfl', 'tfla', 'tflc' , 'cmp', 'antlr4', 'llrc', 'llrlf', 'llrn' , 'svm', 'svmt' , 'svmsl' , 'tflm', 'elau', 'lg', 'bespresso', 'sjavavm', 'spolyglot'] + _llvm_toolchain_wrappers + tools, suite, env_file='jvm-ce-llvm') mx_sdk_vm.register_vm_config('espresso-jvm-ee', ['java', 'ejvm' , 'ellvm', 'libpoly', 'nfi-libffi', 'nfi', 'sdk', 'sdkni', 'sdkc', 'sdkl', 'tfl', 'tfla', 'tflc', 'tfle', 'cmp', 'antlr4', 'llrc', 'llrlf', 'llrn', 'cmpee', 'svm', 'svmt', 'svmee', 'svmte', 'svmsl', 'tflllm', 'tflm', 'elau', 'lg', 'bespresso', 'sjavavm', 'spolyglot'] + _llvm_toolchain_wrappers + tools, suite, env_file='jvm-ee-llvm') From 8747ff1364b96df45b736195a305f63d97a514eb Mon Sep 17 00:00:00 2001 From: Andreas Woess Date: Fri, 12 Jan 2024 17:33:52 +0100 Subject: [PATCH 446/593] Extend allowed DynamicObject shape flags to 16 bits. --- .../src/com/oracle/truffle/api/object/Shape.java | 10 +++++----- .../src/com/oracle/truffle/object/ShapeImpl.java | 4 ++-- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/truffle/src/com.oracle.truffle.api.object/src/com/oracle/truffle/api/object/Shape.java b/truffle/src/com.oracle.truffle.api.object/src/com/oracle/truffle/api/object/Shape.java index c37b42e1179a..2faff4e0162c 100644 --- a/truffle/src/com.oracle.truffle.api.object/src/com/oracle/truffle/api/object/Shape.java +++ b/truffle/src/com.oracle.truffle.api.object/src/com/oracle/truffle/api/object/Shape.java @@ -78,7 +78,7 @@ * @since 0.8 or earlier */ public abstract class Shape { - static final int OBJECT_FLAGS_MASK = 0x0000_00ff; + static final int OBJECT_FLAGS_MASK = 0x0000_ffff; static final int OBJECT_FLAGS_SHIFT = 0; static final int OBJECT_SHARED = 1 << 16; static final int OBJECT_PROPERTY_ASSUMPTIONS = 1 << 17; @@ -116,11 +116,11 @@ abstract static class AbstractBuilder> { public abstract T dynamicType(Object dynamicType); /** - * Sets initial shape flags (default: 0). Currently limited to 8 bits. + * Sets initial shape flags (default: 0). Currently limited to 16 bits. * * See {@link DynamicObjectLibrary#setShapeFlags(DynamicObject, int)} for more information. * - * @param flags an int value in the range from 0 to 255 (inclusive) + * @param flags an int value in the range from 0 to 65535 (inclusive) * @throws IllegalArgumentException if the flags value is not in the supported range * @since 20.2.0 */ @@ -147,7 +147,7 @@ static Object checkDynamicType(Object dynamicType) { static int checkShapeFlags(int flags) { if ((flags & ~OBJECT_FLAGS_MASK) != 0) { - throw new IllegalArgumentException("flags must be in the range (0, 255)"); + throw new IllegalArgumentException("flags must be in the range [0, 0xffff]"); } return flags; } @@ -694,7 +694,7 @@ public int getFlags() { /** * Returns a copy of the shape, with the shape flags set to {@code newFlags}. * - * @param newFlags the new shape flags; an int value in the range from 0 to 255 (inclusive) + * @param newFlags the new shape flags; an int value in the range from 0 to 65535 (inclusive) * @throws IllegalArgumentException if the flags value is not in the supported range * @see Shape.Builder#shapeFlags(int) * @since 20.2.0 diff --git a/truffle/src/com.oracle.truffle.object/src/com/oracle/truffle/object/ShapeImpl.java b/truffle/src/com.oracle.truffle.object/src/com/oracle/truffle/object/ShapeImpl.java index 66af6aa2db09..f1632473e66f 100644 --- a/truffle/src/com.oracle.truffle.object/src/com/oracle/truffle/object/ShapeImpl.java +++ b/truffle/src/com.oracle.truffle.object/src/com/oracle/truffle/object/ShapeImpl.java @@ -1126,7 +1126,7 @@ public Shape makeSharedShape() { } /** Bits available to API users. */ - protected static final int OBJECT_FLAGS_MASK = 0x0000_00ff; + protected static final int OBJECT_FLAGS_MASK = 0x0000_ffff; protected static final int OBJECT_FLAGS_SHIFT = 0; protected static int getObjectFlags(int flags) { @@ -1135,7 +1135,7 @@ protected static int getObjectFlags(int flags) { protected static int checkObjectFlags(int flags) { if ((flags & ~OBJECT_FLAGS_MASK) != 0) { - throw new IllegalArgumentException("flags must be in the range [0, 255]"); + throw new IllegalArgumentException("flags must be in the range [0, 0xffff]"); } return flags; } From 58c8af536e344d54552091d00e12d962c39c28ff Mon Sep 17 00:00:00 2001 From: Andreas Woess Date: Fri, 12 Jan 2024 17:36:47 +0100 Subject: [PATCH 447/593] Update truffle changelog. --- truffle/CHANGELOG.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/truffle/CHANGELOG.md b/truffle/CHANGELOG.md index 27188be870a1..7dadce19272c 100644 --- a/truffle/CHANGELOG.md +++ b/truffle/CHANGELOG.md @@ -2,6 +2,9 @@ This changelog summarizes major changes between Truffle versions relevant to languages implementors building upon the Truffle framework. The main focus is on APIs exported by Truffle. +## Version 24.1.0 +* GR-51253 Extend allowed DynamicObject shape flags from 8 to 16 bits. + ## Version 24.0.0 * GR-45863 Yield and resume events added to the instrumentation: From 8f1d77abedeac0f6da15c335b070e413dd4eb414 Mon Sep 17 00:00:00 2001 From: Tomas Zezula Date: Thu, 11 Jan 2024 13:16:14 +0100 Subject: [PATCH 448/593] Copying compresses the heap file. --- .../com/oracle/truffle/api/test/GCUtils.java | 38 +++++++++++++++---- 1 file changed, 30 insertions(+), 8 deletions(-) diff --git a/truffle/src/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/GCUtils.java b/truffle/src/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/GCUtils.java index 5ad6bb52a61d..e4ef781a97f4 100644 --- a/truffle/src/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/GCUtils.java +++ b/truffle/src/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/GCUtils.java @@ -40,6 +40,8 @@ */ package com.oracle.truffle.api.test; +import java.io.BufferedInputStream; +import java.io.BufferedOutputStream; import java.io.IOException; import java.lang.management.ManagementFactory; import java.lang.ref.Reference; @@ -48,7 +50,6 @@ import java.nio.file.Files; import java.nio.file.LinkOption; import java.nio.file.Path; -import java.nio.file.StandardCopyOption; import java.nio.file.attribute.FileAttribute; import java.util.ArrayList; import java.util.Arrays; @@ -58,6 +59,7 @@ import java.util.List; import java.util.Map; import java.util.function.Function; +import java.util.zip.GZIPOutputStream; import com.sun.management.HotSpotDiagnosticMXBean; @@ -442,29 +444,35 @@ Result analyse(Collection> references, boolean force, boo try { Result result = null; Path tmpDirectory = Files.createTempDirectory(GCUtils.class.getSimpleName().toLowerCase()); + Path heapDumpFile = tmpDirectory.resolve("heapdump.hprof"); + Path targetFile = null; + boolean copyHeapDump = false; try { - Path heapDumpFile = tmpDirectory.resolve("heapdump.hprof"); System.gc(); // Perform GC to minimize heap size and speed up heap queries. Map, Integer> todoIndexes = prepareTodoAndTakeHeapDump(references, heapDumpFile); Heap heap = HeapFactory.createHeap(heapDumpFile.toFile()); JavaClass trackableReferenceClass = heap.getJavaClassByName(HeapDumpAnalyser.class.getName()); ObjectArrayInstance todoArray = (ObjectArrayInstance) trackableReferenceClass.getValueOfStaticField("todo"); List instances = todoArray.getValues(); - Path targetFile = null; if (preserveHeapDumpIfNonCollectable) { if (SAVE_HEAP_DUMP_TO != null) { Path targetFolder = Path.of(SAVE_HEAP_DUMP_TO); - targetFile = Files.createTempFile(targetFolder, "gcutils_heapdump_", ".hprof"); + targetFile = Files.createTempFile(targetFolder, "gcutils_heapdump_", ".hprof.gz"); + copyHeapDump = true; } else { targetFile = heapDumpFile; } } result = testCollected.apply(new State(collectGCRootPath, targetFile, heap, instances, todoIndexes)); - if (targetFile != null && !targetFile.equals(heapDumpFile)) { - Files.move(heapDumpFile, targetFile, StandardCopyOption.REPLACE_EXISTING); - } } finally { - if (result == null || result.isCollected() || !preserveHeapDumpIfNonCollectable || SAVE_HEAP_DUMP_TO != null) { + if (targetFile == null) { + delete(tmpDirectory); + } else if (result == null || result.isCollected()) { + delete(targetFile); + delete(tmpDirectory); + } else if (copyHeapDump) { + compress(heapDumpFile, targetFile); + System.out.println("[DEBUG] HEAP DUMP STORED: " + targetFile); delete(tmpDirectory); } } @@ -474,6 +482,20 @@ Result analyse(Collection> references, boolean force, boo } } + private static void compress(Path src, Path target) throws IOException { + try (BufferedInputStream in = new BufferedInputStream(Files.newInputStream(src)); + GZIPOutputStream out = new GZIPOutputStream(new BufferedOutputStream(Files.newOutputStream(target)))) { + byte[] buffer = new byte[16384]; + while (true) { + int count = in.read(buffer, 0, buffer.length); + if (count < 0) { + break; + } + out.write(buffer, 0, count); + } + } + } + @Override Result isCollected(Reference reference, State context) { int index = context.todoIndexes.get(reference); From a603283048b77a0ee1b38f2733be16498b2e0a25 Mon Sep 17 00:00:00 2001 From: Tomas Zezula Date: Thu, 11 Jan 2024 14:02:20 +0100 Subject: [PATCH 449/593] Truffle libgraal gate preserves GCUtils heap dumps. --- compiler/ci/ci_common/gate.jsonnet | 2 +- vm/ci/ci_common/libgraal.jsonnet | 5 +++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/compiler/ci/ci_common/gate.jsonnet b/compiler/ci/ci_common/gate.jsonnet index 337e7c238307..836cbce39c03 100644 --- a/compiler/ci/ci_common/gate.jsonnet +++ b/compiler/ci/ci_common/gate.jsonnet @@ -57,7 +57,7 @@ JVM_CONFIG: jvm_config + jvm_config_suffix } else {}, logs+: [ - "*/gcutils_heapdump_*.hprof", + "*/gcutils_heapdump_*.hprof.gz", ], targets: ["gate"], python_version: "3" diff --git a/vm/ci/ci_common/libgraal.jsonnet b/vm/ci/ci_common/libgraal.jsonnet index e783f1643380..bbaccee9f5e3 100644 --- a/vm/ci/ci_common/libgraal.jsonnet +++ b/vm/ci/ci_common/libgraal.jsonnet @@ -49,11 +49,12 @@ local utils = import '../../../ci/ci_common/common-utils.libsonnet'; }, run+: [ ['mx', '--env', vm.libgraal_env, 'gate', '--task', 'LibGraal Truffle'] + if coverage then g.jacoco_gate_args else [] + - if extra_vm_args != [] then ['--extra-vm-argument=' + std.join(" ", extra_vm_args)] else [], + ['--extra-vm-argument=' + std.join(" ", ['-DGCUtils.saveHeapDumpTo=.'] + extra_vm_args)], ], logs+: [ '*/graal-compiler.log', - '*/graal-compiler-ctw.log' + '*/graal-compiler-ctw.log', + '*/gcutils_heapdump_*.hprof.gz' ], timelimit: '1:00:00', teardown+: if coverage then [ From 36ebb3a6a00ee75c4e9d005842e65e0a21dcd6a5 Mon Sep 17 00:00:00 2001 From: Christian Wimmer Date: Fri, 5 Jan 2024 11:26:27 -0800 Subject: [PATCH 450/593] Do not mark objects as reachable that are only used in FrameState --- .../pointsto/flow/MethodTypeFlowBuilder.java | 40 ++++++++---------- .../pointsto/results/StrengthenGraphs.java | 11 +++-- .../oracle/svm/core/util/ImageHeapList.java | 9 ++-- .../svm/hosted/HostedConfiguration.java | 5 --- .../svm/hosted/NativeImageGenerator.java | 3 +- .../flow/SVMMethodTypeFlowBuilder.java | 42 ------------------- 6 files changed, 30 insertions(+), 80 deletions(-) diff --git a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/flow/MethodTypeFlowBuilder.java b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/flow/MethodTypeFlowBuilder.java index c5c67b3d951f..4776a5ae45ff 100644 --- a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/flow/MethodTypeFlowBuilder.java +++ b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/flow/MethodTypeFlowBuilder.java @@ -235,7 +235,7 @@ private boolean parse(Object reason, boolean forceReparse) { } } - protected static void registerUsedElements(PointsToAnalysis bb, StructuredGraph graph) { + public static void registerUsedElements(PointsToAnalysis bb, StructuredGraph graph) { PointsToAnalysisMethod method = (PointsToAnalysisMethod) graph.method(); HostedProviders providers = bb.getProviders(method); for (Node n : graph.getNodes()) { @@ -307,9 +307,9 @@ protected static void registerUsedElements(PointsToAnalysis bb, StructuredGraph JavaConstant root = cn.asJavaConstant(); if (cn.hasUsages() && cn.isJavaConstant() && root.getJavaKind() == JavaKind.Object && root.isNonNull()) { assert StampTool.isExactType(cn) : cn; - AnalysisType type = (AnalysisType) StampTool.typeOrNull(cn, bb.getMetaAccess()); - type.registerAsInHeap(new EmbeddedRootScan(AbstractAnalysisEngine.sourcePosition(cn), root)); - if (!ignoreConstant(bb, cn)) { + if (!ignoreConstant(cn)) { + AnalysisType type = (AnalysisType) StampTool.typeOrNull(cn, bb.getMetaAccess()); + type.registerAsInHeap(new EmbeddedRootScan(AbstractAnalysisEngine.sourcePosition(cn), root)); registerEmbeddedRoot(bb, cn); } } @@ -356,27 +356,28 @@ protected static void registerUsedElements(PointsToAnalysis bb, StructuredGraph * to the error message of a {@link ClassCastException}. In {@link StrengthenGraphs} we can * re-write the Class constant to a String constant, i.e., only embed the class name and not the * full java.lang.Class object in the image. + * + * {@link FrameState} are only used for debugging. We do not want to have larger images just so + * that users can see a constant value in the debugger. */ - protected static boolean ignoreConstant(PointsToAnalysis bb, ConstantNode cn) { - if (!ignoreInstanceOfType(bb, (AnalysisType) bb.getConstantReflectionProvider().asJavaType(cn.asConstant()))) { - return false; - } - for (var usage : cn.usages()) { - if (usage instanceof ClassIsAssignableFromNode) { - if (((ClassIsAssignableFromNode) usage).getThisClass() != cn) { + protected static boolean ignoreConstant(ConstantNode node) { + for (var u : node.usages()) { + if (u instanceof ClassIsAssignableFromNode usage) { + if (usage.getOtherClass() == node || usage.getThisClass() != node) { return false; } - } else if (usage instanceof BytecodeExceptionNode) { - if (((BytecodeExceptionNode) usage).getExceptionKind() != BytecodeExceptionKind.CLASS_CAST) { + } else if (u instanceof BytecodeExceptionNode usage) { + /* The checked type is the second argument for a CLASS_CAST. */ + if (usage.getExceptionKind() != BytecodeExceptionKind.CLASS_CAST || usage.getArguments().size() != 2 || usage.getArguments().get(0) == node || usage.getArguments().get(1) != node) { return false; } - } else if (usage instanceof FrameState) { + } else if (u instanceof FrameState) { /* FrameState usages are only for debugging and not necessary for correctness. */ } else { return false; } } - /* Success, the ConstantNode do not need to be seen as reachable. */ + /* Success, the ConstantNode does not need to be seen as reachable. */ return true; } @@ -541,15 +542,10 @@ private void createTypeFlow() { }); typeFlows.add(node, sourceBuilder); } else if (node.asJavaConstant().getJavaKind() == JavaKind.Object) { - /* - * TODO a SubstrateObjectConstant wrapping a PrimitiveConstant has kind - * equals to Object. Do we care about the effective value of these primitive - * constants in the analysis? - */ assert StampTool.isExactType(node) : node; - AnalysisType type = (AnalysisType) StampTool.typeOrNull(node, bb.getMetaAccess()); - assert type.isInstantiated() : type; TypeFlowBuilder sourceBuilder = TypeFlowBuilder.create(bb, node, ConstantTypeFlow.class, () -> { + AnalysisType type = (AnalysisType) StampTool.typeOrNull(node, bb.getMetaAccess()); + assert type.isInstantiated() : type; JavaConstant constantValue = node.asJavaConstant(); BytecodePosition position = AbstractAnalysisEngine.sourcePosition(node); JavaConstant heapConstant = bb.getUniverse().getHeapScanner().toImageHeapObject(constantValue, new EmbeddedRootScan(position, constantValue)); diff --git a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/results/StrengthenGraphs.java b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/results/StrengthenGraphs.java index e56b163e5e8a..e04e8a7f5b9a 100644 --- a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/results/StrengthenGraphs.java +++ b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/results/StrengthenGraphs.java @@ -45,6 +45,7 @@ import com.oracle.graal.pointsto.flow.MethodFlowsGraph; import com.oracle.graal.pointsto.flow.MethodTypeFlow; import com.oracle.graal.pointsto.flow.TypeFlow; +import com.oracle.graal.pointsto.heap.ImageHeapConstant; import com.oracle.graal.pointsto.infrastructure.Universe; import com.oracle.graal.pointsto.meta.AnalysisMethod; import com.oracle.graal.pointsto.meta.AnalysisType; @@ -450,15 +451,13 @@ public void simplify(Node n, SimplifierTool tool) { } else if (n instanceof FrameState) { /* - * We do not want a type to be reachable only to be used for debugging purposes in a - * FrameState. We could just null out the frame slot, but to leave as much - * information as possible we replace the java.lang.Class with the type name. + * We do not want a constant to be reachable only to be used for debugging purposes + * in a FrameState. */ FrameState node = (FrameState) n; for (int i = 0; i < node.values().size(); i++) { - AnalysisType nonReachableType = asConstantNonReachableType(node.values().get(i), tool); - if (nonReachableType != null) { - node.values().set(i, ConstantNode.forConstant(tool.getConstantReflection().forString(getTypeName(nonReachableType)), tool.getMetaAccess(), graph)); + if (node.values().get(i) instanceof ConstantNode constantNode && constantNode.getValue() instanceof ImageHeapConstant imageHeapConstant && !imageHeapConstant.isReachable()) { + node.values().set(i, ConstantNode.defaultForKind(JavaKind.Object, graph)); } } diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/util/ImageHeapList.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/util/ImageHeapList.java index 0648e8fbc923..0fd75bae3cc8 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/util/ImageHeapList.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/util/ImageHeapList.java @@ -38,15 +38,16 @@ import com.oracle.svm.core.Uninterruptible; /** - * At list that is filled at image build time while the static analysis running, and then read at + * A list that is filled at image build time while the static analysis is running, and then read at * run time. * - * Filling the list at image build time is thread safe. Every object to the list is properly added - * to the shadow heap. + * Filling the list at image build time is thread safe. Every object added to the list while the + * static analysis is running is properly added to the shadow heap. * * The list is immutable at run time. The run-time list can optionally be sorted, to make code at * run time deterministic regardless of the order in which elements are discovered and added at - * image build time. + * image build time. Sorting happens at image build time, but does not affect the list that users + * are adding to at image build time. */ @Platforms(Platform.HOSTED_ONLY.class) // public final class ImageHeapList { diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/HostedConfiguration.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/HostedConfiguration.java index d454cfe8c104..9a5d1f444efb 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/HostedConfiguration.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/HostedConfiguration.java @@ -77,7 +77,6 @@ import jdk.graal.compiler.core.common.CompressEncoding; import jdk.graal.compiler.core.common.spi.MetaAccessExtensionProvider; import jdk.graal.compiler.debug.DebugContext; -import jdk.graal.compiler.nodes.StructuredGraph; import jdk.graal.compiler.options.OptionValues; import jdk.internal.ValueBased; import jdk.vm.ci.meta.JavaKind; @@ -211,10 +210,6 @@ public MethodTypeFlowBuilder createMethodTypeFlowBuilder(PointsToAnalysis bb, Po return new SVMMethodTypeFlowBuilder(bb, method, flowsGraph, graphKind); } - public void registerUsedElements(PointsToAnalysis bb, StructuredGraph graph) { - SVMMethodTypeFlowBuilder.registerUsedElements(bb, graph); - } - public MetaAccessExtensionProvider createAnalysisMetaAccessExtensionProvider() { return new AnalysisMetaAccessExtensionProvider(); } diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/NativeImageGenerator.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/NativeImageGenerator.java index 38677107e9e8..3e153b31d453 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/NativeImageGenerator.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/NativeImageGenerator.java @@ -89,6 +89,7 @@ import com.oracle.graal.pointsto.ObjectScanningObserver; import com.oracle.graal.pointsto.api.PointstoOptions; import com.oracle.graal.pointsto.constraints.UnsupportedFeatureException; +import com.oracle.graal.pointsto.flow.MethodTypeFlowBuilder; import com.oracle.graal.pointsto.flow.context.bytecode.BytecodeSensitiveAnalysisPolicy; import com.oracle.graal.pointsto.heap.HeapSnapshotVerifier; import com.oracle.graal.pointsto.heap.ImageHeap; @@ -1155,7 +1156,7 @@ public static void performSnippetGraphAnalysis(BigBang bb, SubstrateReplacements Collection snippetGraphs = replacements.getSnippetGraphs(GraalOptions.TrackNodeSourcePosition.getValue(options), options); if (bb instanceof NativeImagePointsToAnalysis pointsToAnalysis) { for (StructuredGraph graph : snippetGraphs) { - HostedConfiguration.instance().registerUsedElements(pointsToAnalysis, graph); + MethodTypeFlowBuilder.registerUsedElements(pointsToAnalysis, graph); } } else if (bb instanceof NativeImageReachabilityAnalysisEngine reachabilityAnalysis) { for (StructuredGraph graph : snippetGraphs) { diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/analysis/flow/SVMMethodTypeFlowBuilder.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/analysis/flow/SVMMethodTypeFlowBuilder.java index de83d64c6372..38bc4b175194 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/analysis/flow/SVMMethodTypeFlowBuilder.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/analysis/flow/SVMMethodTypeFlowBuilder.java @@ -31,7 +31,6 @@ import com.oracle.graal.pointsto.flow.MethodTypeFlowBuilder; import com.oracle.graal.pointsto.flow.TypeFlow; import com.oracle.graal.pointsto.flow.builder.TypeFlowBuilder; -import com.oracle.graal.pointsto.heap.ImageHeapConstant; import com.oracle.graal.pointsto.meta.AnalysisField; import com.oracle.graal.pointsto.meta.AnalysisType; import com.oracle.graal.pointsto.meta.PointsToAnalysisMethod; @@ -46,18 +45,12 @@ import jdk.graal.compiler.core.common.type.ObjectStamp; import jdk.graal.compiler.core.common.type.Stamp; -import jdk.graal.compiler.debug.GraalError; -import jdk.graal.compiler.graph.Node; import jdk.graal.compiler.nodes.CallTargetNode.InvokeKind; -import jdk.graal.compiler.nodes.ConstantNode; import jdk.graal.compiler.nodes.FixedNode; import jdk.graal.compiler.nodes.NodeView; -import jdk.graal.compiler.nodes.StructuredGraph; import jdk.graal.compiler.nodes.ValueNode; import jdk.graal.compiler.nodes.java.LoadFieldNode; import jdk.vm.ci.code.BytecodePosition; -import jdk.vm.ci.meta.JavaConstant; -import jdk.vm.ci.meta.JavaKind; public class SVMMethodTypeFlowBuilder extends MethodTypeFlowBuilder { @@ -76,41 +69,6 @@ protected SVMHost getHostVM() { return (SVMHost) bb.getHostVM(); } - public static void registerUsedElements(PointsToAnalysis bb, StructuredGraph graph) { - MethodTypeFlowBuilder.registerUsedElements(bb, graph); - - for (Node n : graph.getNodes()) { - if (n instanceof ConstantNode) { - ConstantNode cn = (ConstantNode) n; - JavaConstant constant = cn.asJavaConstant(); - if (cn.hasUsages() && cn.isJavaConstant() && constant.getJavaKind() == JavaKind.Object && constant.isNonNull()) { - if (constant instanceof ImageHeapConstant) { - /* No replacement for ImageHeapObject. */ - } else if (!ignoreConstant(bb, cn)) { - /* - * Constants that are embedded into graphs via constant folding of static - * fields have already been replaced. But constants embedded manually by - * graph builder plugins, or class constants that come directly from - * constant bytecodes, are not replaced. We verify here that the object - * replacer would not replace such objects. - * - * But more importantly, some object replacers also perform actions like - * forcing eager initialization of fields. We need to make sure that these - * object replacers really see all objects that are embedded into compiled - * code. - */ - Object value = bb.getSnippetReflectionProvider().asObject(Object.class, constant); - Object replaced = bb.getUniverse().replaceObject(value); - if (value != replaced) { - throw GraalError.shouldNotReachHere("Missed object replacement during graph building: " + - value + " (" + value.getClass() + ") != " + replaced + " (" + replaced.getClass() + ")"); // ExcludeFromJacocoGeneratedReport - } - } - } - } - } - } - @SuppressWarnings("serial") public static class UnsafeOffsetError extends UserException { From de154093ddfdea0c048ab37dc3e4adc798cc2b74 Mon Sep 17 00:00:00 2001 From: Josef Eisl Date: Sat, 13 Jan 2024 12:46:50 +0100 Subject: [PATCH 451/593] svm: adopt "JDK-8322829: Refactor nioBlocker to avoid blocking while holding Thread's interrupt lock" --- .../svm/core/thread/Target_java_lang_Thread.java | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/thread/Target_java_lang_Thread.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/thread/Target_java_lang_Thread.java index 0bc51646f8b3..a92af03365a6 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/thread/Target_java_lang_Thread.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/thread/Target_java_lang_Thread.java @@ -31,8 +31,6 @@ import java.util.Map; import java.util.Objects; -import jdk.graal.compiler.api.directives.GraalDirectives; -import jdk.graal.compiler.replacements.ReplacementsUtil; import org.graalvm.nativeimage.IsolateThread; import org.graalvm.nativeimage.Platforms; import org.graalvm.nativeimage.impl.InternalPlatform; @@ -49,10 +47,15 @@ import com.oracle.svm.core.annotate.TargetClass; import com.oracle.svm.core.annotate.TargetElement; import com.oracle.svm.core.jdk.JDK21OrEarlier; +import com.oracle.svm.core.jdk.JDK22OrEarlier; import com.oracle.svm.core.jdk.JDK22OrLater; +import com.oracle.svm.core.jdk.JDK23OrLater; import com.oracle.svm.core.monitor.MonitorSupport; import com.oracle.svm.core.util.VMError; +import jdk.graal.compiler.api.directives.GraalDirectives; +import jdk.graal.compiler.replacements.ReplacementsUtil; + @TargetClass(Thread.class) @SuppressWarnings({"unused"}) public final class Target_java_lang_Thread { @@ -505,7 +508,14 @@ static void setScopedValueBindings(Object bindings) { static native Object findScopedValueBindings(); @Substitute - static void blockedOn(Target_sun_nio_ch_Interruptible b) { + @TargetElement(name = "blockedOn", onlyWith = JDK22OrEarlier.class) + static void blockedOnJDK22(Target_sun_nio_ch_Interruptible b) { + JavaThreads.blockedOn(b); + } + + @Substitute + @TargetElement(onlyWith = JDK23OrLater.class) + void blockedOn(Target_sun_nio_ch_Interruptible b) { JavaThreads.blockedOn(b); } From e959a513c82e99d905ab0534aec0f3ed7ed551d4 Mon Sep 17 00:00:00 2001 From: Josef Eisl Date: Sat, 13 Jan 2024 12:50:52 +0100 Subject: [PATCH 452/593] svm: adopt "JDK-8322878: Including sealing information Class.toGenericString()" --- .../src/com/oracle/svm/core/hub/DynamicHub.java | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/hub/DynamicHub.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/hub/DynamicHub.java index 83de69f9fe13..349f08a0eb6a 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/hub/DynamicHub.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/hub/DynamicHub.java @@ -102,6 +102,7 @@ import com.oracle.svm.core.heap.UnknownPrimitiveField; import com.oracle.svm.core.jdk.JDK21OrEarlier; import com.oracle.svm.core.jdk.JDK22OrLater; +import com.oracle.svm.core.jdk.JDK23OrLater; import com.oracle.svm.core.jdk.Resources; import com.oracle.svm.core.meta.SharedType; import com.oracle.svm.core.reflect.MissingReflectionRegistrationUtils; @@ -1446,6 +1447,14 @@ public String toString() { @KeepOriginal public native String toGenericString(); + @KeepOriginal + @TargetElement(onlyWith = JDK23OrLater.class) + private native void addSealingInfo(int modifiers, StringBuilder sb); + + @KeepOriginal + @TargetElement(onlyWith = JDK23OrLater.class) + private native boolean hasSealedAncestor(Class clazz); + @KeepOriginal public native boolean isSynthetic(); From 997e00ffcdf99e6b7ad3efe4b9e975280e3acc2b Mon Sep 17 00:00:00 2001 From: ol-automation_ww Date: Sat, 13 Jan 2024 20:01:33 +0000 Subject: [PATCH 453/593] [GR-23997] Periodic update of the graal import (2024-01-12). PullRequest: js/3025 --- vm/mx.vm/suite.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/vm/mx.vm/suite.py b/vm/mx.vm/suite.py index 51b89ece551b..ff1cd2e47163 100644 --- a/vm/mx.vm/suite.py +++ b/vm/mx.vm/suite.py @@ -33,7 +33,7 @@ "name": "graal-nodejs", "subdir": True, "dynamic": True, - "version": "999f4ab64ed6978692183f24bc836d2eed76046f", + "version": "ceb352c9066feee3e58f24f7e1eb4709171d5b08", "urls" : [ {"url" : "https://github.com/graalvm/graaljs.git", "kind" : "git"}, ] @@ -42,7 +42,7 @@ "name": "graal-js", "subdir": True, "dynamic": True, - "version": "999f4ab64ed6978692183f24bc836d2eed76046f", + "version": "ceb352c9066feee3e58f24f7e1eb4709171d5b08", "urls": [ {"url": "https://github.com/graalvm/graaljs.git", "kind" : "git"}, ] From 11233a92bf4ba79eb3ce568044090c01df3688a8 Mon Sep 17 00:00:00 2001 From: Martin Entlicher Date: Wed, 10 Jan 2024 10:09:26 +0100 Subject: [PATCH 454/593] Migrated Chrome Inspector and DAP to system threads. (GR-42173) --- .../test/InspectorTestInstrument.java | 3 +- .../chromeinspector/test/InspectorTester.java | 7 +- .../chromeinspector/InspectorDebugger.java | 35 ++++---- .../server/InspectServerSession.java | 36 +++++--- .../server/InspectorServer.java | 19 +++- .../dap/server/DebugProtocolServerImpl.java | 86 +++++++++++++------ .../tools/dap/types/DebugProtocolServer.java | 12 ++- .../test/InstrumentSystemThreadTest.java | 9 +- .../truffle/polyglot/PolyglotEngineImpl.java | 13 ++- 9 files changed, 149 insertions(+), 71 deletions(-) diff --git a/tools/src/com.oracle.truffle.tools.chromeinspector.test/src/com/oracle/truffle/tools/chromeinspector/test/InspectorTestInstrument.java b/tools/src/com.oracle.truffle.tools.chromeinspector.test/src/com/oracle/truffle/tools/chromeinspector/test/InspectorTestInstrument.java index f2194eb6907f..5811e6e49a28 100644 --- a/tools/src/com.oracle.truffle.tools.chromeinspector.test/src/com/oracle/truffle/tools/chromeinspector/test/InspectorTestInstrument.java +++ b/tools/src/com.oracle.truffle.tools.chromeinspector.test/src/com/oracle/truffle/tools/chromeinspector/test/InspectorTestInstrument.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2024, 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 @@ -97,6 +97,7 @@ protected void onFinalize(Env env) { InspectServerSession session = (sessionRef != null) ? sessionRef.get() : null; if (session != null) { session.notifyClosing(); + session.dispose(); } } diff --git a/tools/src/com.oracle.truffle.tools.chromeinspector.test/src/com/oracle/truffle/tools/chromeinspector/test/InspectorTester.java b/tools/src/com.oracle.truffle.tools.chromeinspector.test/src/com/oracle/truffle/tools/chromeinspector/test/InspectorTester.java index 5de895d65a5c..bc39a63290ab 100644 --- a/tools/src/com.oracle.truffle.tools.chromeinspector.test/src/com/oracle/truffle/tools/chromeinspector/test/InspectorTester.java +++ b/tools/src/com.oracle.truffle.tools.chromeinspector.test/src/com/oracle/truffle/tools/chromeinspector/test/InspectorTester.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2024, 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 @@ -347,11 +347,6 @@ public void run() { // To cleanup any references to the closed context, we need to set a new instance // of ProxyLanguage. ProxyLanguage.setDelegate(new ProxyLanguage()); - try { - inspect.sendClose(); - } catch (IOException e) { - fail(e.getLocalizedMessage()); - } inspect = null; inspectorContext = null; evalValue = null; diff --git a/tools/src/com.oracle.truffle.tools.chromeinspector/src/com/oracle/truffle/tools/chromeinspector/InspectorDebugger.java b/tools/src/com.oracle.truffle.tools.chromeinspector/src/com/oracle/truffle/tools/chromeinspector/InspectorDebugger.java index ad87616b8c9c..9ce349cdcc5d 100644 --- a/tools/src/com.oracle.truffle.tools.chromeinspector/src/com/oracle/truffle/tools/chromeinspector/InspectorDebugger.java +++ b/tools/src/com.oracle.truffle.tools.chromeinspector/src/com/oracle/truffle/tools/chromeinspector/InspectorDebugger.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2024, 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 @@ -26,6 +26,8 @@ import java.io.File; import java.io.PrintWriter; +import java.lang.ref.Reference; +import java.lang.ref.WeakReference; import java.util.ArrayList; import java.util.HashSet; import java.util.LinkedList; @@ -1064,6 +1066,7 @@ private class SuspendedCallbackImpl implements SuspendedCallback { private final ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1, new SchedulerThreadFactory()); private final AtomicReference> future = new AtomicReference<>(); private Thread locked = null; + private volatile Reference schedulerThread; @Override public void onSuspend(SuspendedEvent se) { @@ -1266,27 +1269,27 @@ private void dispose() { scheduler.shutdown(); try { scheduler.awaitTermination(30, TimeUnit.SECONDS); + Thread t = (schedulerThread != null) ? schedulerThread.get() : null; + if (t != null) { + t.join(); + } } catch (InterruptedException e) { + // Interrupted } } - } - private static class SchedulerThreadFactory implements ThreadFactory { + private class SchedulerThreadFactory implements ThreadFactory { - private final ThreadGroup group; - - @SuppressWarnings("deprecation") - SchedulerThreadFactory() { - SecurityManager s = System.getSecurityManager(); - this.group = (s != null) ? s.getThreadGroup() : Thread.currentThread().getThreadGroup(); - } + SchedulerThreadFactory() { + } - @Override - public Thread newThread(Runnable r) { - Thread t = new Thread(group, r, "Suspend Unlocking Scheduler"); - t.setDaemon(true); - t.setPriority(Thread.NORM_PRIORITY); - return t; + @Override + public Thread newThread(Runnable r) { + Thread t = context.getEnv().createSystemThread(r); + t.setName("chromeinspector.server.Suspend_Unlocking_Scheduler"); + schedulerThread = new WeakReference<>(t); + return t; + } } } diff --git a/tools/src/com.oracle.truffle.tools.chromeinspector/src/com/oracle/truffle/tools/chromeinspector/server/InspectServerSession.java b/tools/src/com.oracle.truffle.tools.chromeinspector/src/com/oracle/truffle/tools/chromeinspector/server/InspectServerSession.java index e871dfd3f02e..9de807e465fe 100644 --- a/tools/src/com.oracle.truffle.tools.chromeinspector/src/com/oracle/truffle/tools/chromeinspector/server/InspectServerSession.java +++ b/tools/src/com.oracle.truffle.tools.chromeinspector/src/com/oracle/truffle/tools/chromeinspector/server/InspectServerSession.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2024, 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 @@ -98,7 +98,7 @@ private static IOException createClosedException() { @Override public void sendClose() throws IOException { - if (processThread == null) { + if (isClosed()) { throw createClosedException(); } Runnable onCloseRunnable = onClose; @@ -109,7 +109,8 @@ public void sendClose() throws IOException { } boolean isClosed() { - return processThread == null; + CommandProcessThread cmdProcessThread = processThread; + return cmdProcessThread == null || cmdProcessThread.isClosed(); } // For tests only @@ -141,7 +142,6 @@ public void dispose() { cmdProcessThread = processThread; if (cmdProcessThread != null) { cmdProcessThread.dispose(); - processThread = null; } } if (cmdProcessThread != null) { @@ -189,7 +189,7 @@ private void startUp() { @Override public void sendText(String message) throws IOException { - if (processThread == null) { + if (isClosed()) { throw createClosedException(); } Command cmd; @@ -271,14 +271,14 @@ public void sendBinary(ByteBuffer data) { @Override public void sendPing(ByteBuffer data) throws IOException { - if (processThread == null) { + if (isClosed()) { throw createClosedException(); } } @Override public void sendPong(ByteBuffer data) throws IOException { - if (processThread == null) { + if (isClosed()) { throw createClosedException(); } } @@ -618,14 +618,15 @@ void run() { } } - private class CommandProcessThread extends Thread { + private class CommandProcessThread implements Runnable { + private final Thread thread; private volatile boolean disposed = false; private final BlockingQueue commands = new LinkedBlockingQueue<>(); CommandProcessThread() { - super("chromeinspector.server.CommandProcessThread"); - setDaemon(true); + thread = context.getEnv().createSystemThread(this); + thread.setName("chromeinspector.server.CommandProcessThread"); } void push(Command cmd) { @@ -639,9 +640,17 @@ void push(Command cmd) { } } + void start() { + thread.start(); + } + void dispose() { disposed = true; - interrupt(); + thread.interrupt(); + } + + boolean isClosed() { + return disposed && !thread.isAlive(); } @Override @@ -679,6 +688,11 @@ public void run() { } } + private void join() throws InterruptedException { + thread.join(); + commands.clear(); + } + } } diff --git a/tools/src/com.oracle.truffle.tools.chromeinspector/src/com/oracle/truffle/tools/chromeinspector/server/InspectorServer.java b/tools/src/com.oracle.truffle.tools.chromeinspector/src/com/oracle/truffle/tools/chromeinspector/server/InspectorServer.java index 31add7248573..e30c731988ab 100644 --- a/tools/src/com.oracle.truffle.tools.chromeinspector/src/com/oracle/truffle/tools/chromeinspector/server/InspectorServer.java +++ b/tools/src/com.oracle.truffle.tools.chromeinspector/src/com/oracle/truffle/tools/chromeinspector/server/InspectorServer.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2024, 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 @@ -470,6 +470,7 @@ public void close(Token token) throws IOException { if (iws != null) { iws.connection.close(1001 /* Going Away */); } + sps.dispose(); } if (sessions.isEmpty()) { try { @@ -526,6 +527,18 @@ boolean getDebugBrkAndReset() { ConnectionWatcher getConnectionWatcher() { return connectionWatcher; } + + void dispose() { + InspectServerSession iss = serverSession.getAndSet(null); + if (iss != null) { + iss.dispose(); + } else { + InspectWebSocketHandler iws = activeWS; + if (iws != null) { + iws.disposeSession(); + } + } + } } private class InspectWebSocketHandler { @@ -612,6 +625,10 @@ void onPing() { void onPong() { iss.context.logMessage("CLIENT: ", "PONG"); } + + void disposeSession() { + iss.dispose(); + } } private static class HTTPChannelWrapper implements ByteChannel { diff --git a/tools/src/com.oracle.truffle.tools.dap/src/com/oracle/truffle/tools/dap/server/DebugProtocolServerImpl.java b/tools/src/com.oracle.truffle.tools.dap/src/com/oracle/truffle/tools/dap/server/DebugProtocolServerImpl.java index f7f5f1ee1717..28a149eb16c7 100644 --- a/tools/src/com.oracle.truffle.tools.dap/src/com/oracle/truffle/tools/dap/server/DebugProtocolServerImpl.java +++ b/tools/src/com.oracle.truffle.tools.dap/src/com/oracle/truffle/tools/dap/server/DebugProtocolServerImpl.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2024, 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 @@ -39,6 +39,7 @@ import com.oracle.truffle.api.debug.SuspensionFilter; import com.oracle.truffle.api.instrumentation.ContextsListener; import com.oracle.truffle.api.instrumentation.EventBinding; +import com.oracle.truffle.api.instrumentation.TruffleInstrument; import com.oracle.truffle.api.nodes.LanguageInfo; import com.oracle.truffle.api.source.Source; import com.oracle.truffle.api.source.SourceSection; @@ -92,6 +93,8 @@ import org.graalvm.shadowed.org.json.JSONObject; import java.io.IOException; +import java.lang.ref.Reference; +import java.lang.ref.WeakReference; import java.net.ServerSocket; import java.net.Socket; import java.net.SocketException; @@ -102,11 +105,9 @@ import java.util.concurrent.CompletableFuture; import java.util.concurrent.CopyOnWriteArrayList; import java.util.concurrent.ExecutionException; -import java.util.concurrent.ExecutorService; -import java.util.concurrent.Executors; +import java.util.concurrent.Executor; import java.util.concurrent.Future; import java.util.concurrent.Phaser; -import java.util.concurrent.ThreadFactory; import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicReference; import java.util.function.Consumer; @@ -125,9 +126,10 @@ public final class DebugProtocolServerImpl extends DebugProtocolServer { private volatile DebuggerSession debuggerSession; private final Enabler ioEnabler; private volatile boolean launched; // true when launched, false when attached - private boolean disposed = false; + private volatile boolean disposed = false; private final List runOnDispose = new CopyOnWriteArrayList<>(); private final List sourcePath; + private volatile OneTimeExecutor clientConnectionExecutor; private DebugProtocolServerImpl(ExecutionContext context, final boolean debugBreak, final boolean waitAttached, @SuppressWarnings("unused") final boolean inspectInitialization, final List sourcePath) { @@ -287,6 +289,7 @@ public void dispose() { if (disposed) { return; } + disposed = true; DebugProtocolClient theClient = client; if (theClient != null) { theClient.terminated(TerminatedEvent.EventBody.create()); @@ -294,6 +297,7 @@ public void dispose() { for (Runnable r : runOnDispose) { r.run(); } + clientConnectionExecutor.shutDownAndJoin(); } private void onDispose(Runnable r) { @@ -595,23 +599,57 @@ public void log(Level level, String msg, Throwable thrown) { }; } - public CompletableFuture start(final ServerSocket serverSocket) { - ExecutorService clientConnectionExecutor = Executors.newSingleThreadExecutor(new ThreadFactory() { + /** + * The executors created by Executors do not allow to join the threads in the pool. System + * threads must be joined before Engine close and ExecutorService.awaitTermination() does not + * guarantee threads termination. + */ + private static class OneTimeExecutor implements Executor { - @Override - public Thread newThread(Runnable r) { - Thread thread = Executors.defaultThreadFactory().newThread(r); - thread.setName("DAP client connection thread"); - return thread; + private final TruffleInstrument.Env env; + private final String threadName; + private Reference thread; + private boolean shutDown; + + OneTimeExecutor(TruffleInstrument.Env env, String threadName) { + this.env = env; + this.threadName = threadName; + } + + public synchronized void execute(Runnable command) { + if (shutDown) { + return; } - }); + if (thread != null) { + throw new IllegalStateException("This is a one-time executor."); + } + Thread t = env.createSystemThread(command); + t.setName(threadName); + t.start(); + thread = new WeakReference<>(t); + } + + synchronized void shutDownAndJoin() { + Thread t = (thread != null) ? thread.get() : null; + if (t != null) { + t.interrupt(); + try { + t.join(); + } catch (InterruptedException ex) { + // Interrupted + } + } + shutDown = true; + } + } + + public CompletableFuture start(final ServerSocket serverSocket) { + clientConnectionExecutor = new OneTimeExecutor(context.getEnv(), "DAP client connection thread"); context.getInfo().println("[Graal DAP] Starting server and listening on " + serverSocket.getLocalSocketAddress()); return CompletableFuture.runAsync(new Runnable() { @Override public void run() { - // We want to shut down the executor after this task finishes - clientConnectionExecutor.shutdown(); AtomicBoolean terminated = new AtomicBoolean(false); try { if (serverSocket.isClosed()) { @@ -627,27 +665,21 @@ public void run() { context.getErr().println("[Graal DAP] Error while closing the server socket: " + e.getLocalizedMessage()); } }); + if (disposed) { + // Disposed in the mean time. + return; + } try (Socket clientSocket = serverSocket.accept()) { context.getInfo().println("[Graal DAP] Client connected on " + clientSocket.getRemoteSocketAddress()); - ExecutorService dapRequestExecutor = Executors.newCachedThreadPool(new ThreadFactory() { - private final ThreadFactory factory = Executors.defaultThreadFactory(); - - @Override - public Thread newThread(Runnable r) { - Thread thread = factory.newThread(r); - thread.setName("DAP request handler " + thread.getName()); - return thread; - } - }); - + OneTimeExecutor dapRequestExecutor = new OneTimeExecutor(context.getEnv(), "DAP request handler"); Future listenFuture = Session.connect(DebugProtocolServerImpl.this, clientSocket.getInputStream(), clientSocket.getOutputStream(), dapRequestExecutor); try { listenFuture.get(); } catch (InterruptedException | ExecutionException e) { context.getErr().println("[Graal DAP] Error: " + e.getLocalizedMessage()); } finally { - dapRequestExecutor.shutdown(); + dapRequestExecutor.shutDownAndJoin(); } } } catch (IOException e) { diff --git a/tools/src/com.oracle.truffle.tools.dap/src/com/oracle/truffle/tools/dap/types/DebugProtocolServer.java b/tools/src/com.oracle.truffle.tools.dap/src/com/oracle/truffle/tools/dap/types/DebugProtocolServer.java index 23ba1e9c4809..a601cf763232 100644 --- a/tools/src/com.oracle.truffle.tools.dap/src/com/oracle/truffle/tools/dap/types/DebugProtocolServer.java +++ b/tools/src/com.oracle.truffle.tools.dap/src/com/oracle/truffle/tools/dap/types/DebugProtocolServer.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2024, 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 @@ -40,8 +40,10 @@ import java.util.concurrent.CompletableFuture; import java.util.concurrent.CompletionException; import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executor; import java.util.concurrent.Future; +import java.util.concurrent.FutureTask; +import java.util.concurrent.RunnableFuture; import java.util.concurrent.atomic.AtomicInteger; import java.util.function.Consumer; import java.util.logging.Level; @@ -765,9 +767,11 @@ private ExceptionWithMessage asExceptionWithMessage(Throwable t) { return t instanceof CompletionException ? asExceptionWithMessage(t.getCause()) : t instanceof ExceptionWithMessage ? (ExceptionWithMessage) t : null; } - public static Future connect(DebugProtocolServer server, InputStream in, OutputStream out, ExecutorService executors) { + public static Future connect(DebugProtocolServer server, InputStream in, OutputStream out, Executor executor) { Session s = new Session(server, in, out); - return executors.submit(s); + RunnableFuture future = new FutureTask<>(s, null); + executor.execute(future); + return future; } } diff --git a/truffle/src/com.oracle.truffle.api.instrumentation.test/src/com/oracle/truffle/api/instrumentation/test/InstrumentSystemThreadTest.java b/truffle/src/com.oracle.truffle.api.instrumentation.test/src/com/oracle/truffle/api/instrumentation/test/InstrumentSystemThreadTest.java index cf1220c885d2..9d1dff095821 100644 --- a/truffle/src/com.oracle.truffle.api.instrumentation.test/src/com/oracle/truffle/api/instrumentation/test/InstrumentSystemThreadTest.java +++ b/truffle/src/com.oracle.truffle.api.instrumentation.test/src/com/oracle/truffle/api/instrumentation/test/InstrumentSystemThreadTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * The Universal Permissive License (UPL), Version 1.0 @@ -96,8 +96,11 @@ public void testNonTerminatedSystemThread() throws InterruptedException { started.await(); assertFails((Runnable) engine::close, PolyglotException.class, (pe) -> { Assert.assertTrue(pe.isInternalError()); - Assert.assertEquals(String.format("java.lang.IllegalStateException: The engine has an alive system thread Forgotten thread created by instrument %s.", ProxyInstrument.ID), - pe.getMessage()); + String message = pe.getMessage(); + Assert.assertTrue(message, message.startsWith("java.lang.IllegalStateException: Alive system thread 'Forgotten thread'")); + // There is a system thread dump: + Assert.assertTrue(message, message.contains("com.oracle.truffle.polyglot.SystemThread.run")); + Assert.assertTrue(message, message.endsWith(String.format("The engine has an alive system thread 'Forgotten thread' created by instrument %s.", ProxyInstrument.ID))); }); } finally { closed.countDown(); diff --git a/truffle/src/com.oracle.truffle.polyglot/src/com/oracle/truffle/polyglot/PolyglotEngineImpl.java b/truffle/src/com.oracle.truffle.polyglot/src/com/oracle/truffle/polyglot/PolyglotEngineImpl.java index 13d7b5f75ecd..29af364b69d9 100644 --- a/truffle/src/com.oracle.truffle.polyglot/src/com/oracle/truffle/polyglot/PolyglotEngineImpl.java +++ b/truffle/src/com.oracle.truffle.polyglot/src/com/oracle/truffle/polyglot/PolyglotEngineImpl.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * The Universal Permissive License (UPL), Version 1.0 @@ -1296,7 +1296,16 @@ void ensureClosed(boolean force, boolean initiatedByContext) { this.lock.notifyAll(); if (!activeSystemThreads.isEmpty()) { InstrumentSystemThread thread = activeSystemThreads.iterator().next(); - throw new IllegalStateException(String.format("The engine has an alive system thread %s created by instrument %s.", thread.getName(), thread.instrumentId)); + StringBuilder stack = new StringBuilder("Alive system thread '"); + stack.append(thread.getName()); + stack.append('\''); + stack.append(System.lineSeparator()); + for (StackTraceElement e : thread.getStackTrace()) { + stack.append("\tat "); + stack.append(e); + stack.append(System.lineSeparator()); + } + throw new IllegalStateException(String.format("%sThe engine has an alive system thread '%s' created by instrument %s.", stack, thread.getName(), thread.instrumentId)); } if (specializationStatistics != null) { StringWriter logMessage = new StringWriter(); From 4ac2265b3223d06cc34986ba9ec1f2f54c245b83 Mon Sep 17 00:00:00 2001 From: Fabio Niephaus Date: Mon, 15 Jan 2024 08:27:43 +0100 Subject: [PATCH 455/593] Fix Cpuid1Ecx feature parsing for AMD CPUs. See https://bugs.openjdk.org/browse/JDK-8280867 --- .../include/amd64hotspotcpuinfo.h | 5 ++--- .../src/cpuid.c | 22 ++++++++----------- 2 files changed, 11 insertions(+), 16 deletions(-) diff --git a/substratevm/src/com.oracle.svm.native.libchelper/include/amd64hotspotcpuinfo.h b/substratevm/src/com.oracle.svm.native.libchelper/include/amd64hotspotcpuinfo.h index 6ba282049f49..ac7d2cc7c505 100644 --- a/substratevm/src/com.oracle.svm.native.libchelper/include/amd64hotspotcpuinfo.h +++ b/substratevm/src/com.oracle.svm.native.libchelper/include/amd64hotspotcpuinfo.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 2023, 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 @@ -141,12 +141,11 @@ typedef union { uint32_t LahfSahf : 1, CmpLegacy : 1, : 3, - lzcnt_intel : 1, lzcnt : 1, sse4a : 1, misalignsse : 1, prefetchw : 1, - : 22; + : 23; } bits; } ExtCpuid1Ecx; diff --git a/substratevm/src/com.oracle.svm.native.libchelper/src/cpuid.c b/substratevm/src/com.oracle.svm.native.libchelper/src/cpuid.c index b967d65889b8..1ae435454f44 100644 --- a/substratevm/src/com.oracle.svm.native.libchelper/src/cpuid.c +++ b/substratevm/src/com.oracle.svm.native.libchelper/src/cpuid.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2023, 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 @@ -516,19 +516,16 @@ NO_INLINE static void set_cpufeatures(CPUFeatures *features, CpuidInfo *_cpuid_i // Intel features. if (is_intel(_cpuid_info)) { - if (_cpuid_info->ext_cpuid1_ecx.bits.lzcnt_intel != 0) + if (_cpuid_info->ext_cpuid1_ecx.bits.lzcnt != 0) { features->fLZCNT = 1; - // for Intel, ecx.bits.misalignsse bit (bit 8) indicates support for prefetchw - if (_cpuid_info->ext_cpuid1_ecx.bits.misalignsse != 0) - { + } + if (_cpuid_info->ext_cpuid1_ecx.bits.prefetchw != 0) { features->fAMD_3DNOW_PREFETCH = 1; } - if (_cpuid_info->sef_cpuid7_ebx.bits.clwb != 0) - { + if (_cpuid_info->sef_cpuid7_ebx.bits.clwb != 0) { features->fCLWB = 1; } - if (_cpuid_info->sef_cpuid7_edx.bits.serialize != 0) - { + if (_cpuid_info->sef_cpuid7_edx.bits.serialize != 0) { features->fSERIALIZE = 1; } } @@ -536,11 +533,10 @@ NO_INLINE static void set_cpufeatures(CPUFeatures *features, CpuidInfo *_cpuid_i // ZX features. if (is_zx(_cpuid_info)) { - if (_cpuid_info->ext_cpuid1_ecx.bits.lzcnt_intel != 0) + if (_cpuid_info->ext_cpuid1_ecx.bits.lzcnt != 0) { features->fLZCNT = 1; - // for ZX, ecx.bits.misalignsse bit (bit 8) indicates support for prefetchw - if (_cpuid_info->ext_cpuid1_ecx.bits.misalignsse != 0) - { + } + if (_cpuid_info->ext_cpuid1_ecx.bits.prefetchw != 0) { features->fAMD_3DNOW_PREFETCH = 1; } } From 2cd91c75350189c129e6d4651f812876844f8288 Mon Sep 17 00:00:00 2001 From: Josef Eisl Date: Mon, 15 Jan 2024 08:47:42 +0100 Subject: [PATCH 456/593] compiler: adopt "JDK-8322636: [JVMCI] HotSpotSpeculationLog can be inconsistent across a single compile" --- .../hotspot/test/HotSpotManagedFailedSpeculationListTest.java | 1 + 1 file changed, 1 insertion(+) diff --git a/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/hotspot/test/HotSpotManagedFailedSpeculationListTest.java b/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/hotspot/test/HotSpotManagedFailedSpeculationListTest.java index 2a733a92f88a..9dc0ba9a98e7 100644 --- a/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/hotspot/test/HotSpotManagedFailedSpeculationListTest.java +++ b/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/hotspot/test/HotSpotManagedFailedSpeculationListTest.java @@ -102,6 +102,7 @@ public void testDeoptimize() throws Exception { private void cutGraphTether() { // Assert that MY_SPECULATION was recorded as a failed speculation SpeculationLog log = lastCompiledGraph.getSpeculationLog(); + log.collectFailedSpeculations(); Assert.assertFalse("expected failed " + MY_SPECULATION + " in " + log, log.maySpeculate(MY_SPECULATION)); lastCompiledGraph = null; From 13cf33a4afe5411b34915dbc459661f656892311 Mon Sep 17 00:00:00 2001 From: Marouane El Hallaoui Date: Mon, 15 Jan 2024 13:49:11 +0100 Subject: [PATCH 457/593] deploy snapshots --- common.json | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/common.json b/common.json index d66895606c42..ff21eeb5c876 100644 --- a/common.json +++ b/common.json @@ -45,12 +45,12 @@ "labsjdk-ee-21-llvm": {"name": "labsjdk", "version": "ee-21.0.1+11-jvmci-23.1-b26-sulong", "platformspecific": true }, "oraclejdk-latest": {"name": "jpg-jdk", "version": "23", "build_id": "5", "release": true, "platformspecific": true, "extrabundles": ["static-libs"]}, - "labsjdk-ce-latest": {"name": "labsjdk", "version": "ce-23+5-jvmci-b01-20240112101422-340c6f0aca", "platformspecific": true }, - "labsjdk-ce-latestDebug": {"name": "labsjdk", "version": "ce-23+5-jvmci-b01-20240112101422-340c6f0aca-debug", "platformspecific": true }, - "labsjdk-ce-latest-llvm": {"name": "labsjdk", "version": "ce-23+5-jvmci-b01-20240112101422-340c6f0aca-sulong", "platformspecific": true }, - "labsjdk-ee-latest": {"name": "labsjdk", "version": "ee-23+5-jvmci-b01-20240112101422-340c6f0aca+8a910e360e", "platformspecific": true }, - "labsjdk-ee-latestDebug": {"name": "labsjdk", "version": "ee-23+5-jvmci-b01-20240112101422-340c6f0aca+8a910e360e-debug", "platformspecific": true }, - "labsjdk-ee-latest-llvm": {"name": "labsjdk", "version": "ee-23+5-jvmci-b01-20240112101422-340c6f0aca+8a910e360e-sulong", "platformspecific": true } + "labsjdk-ce-latest": {"name": "labsjdk", "version": "ce-23+5-jvmci-b01", "platformspecific": true }, + "labsjdk-ce-latestDebug": {"name": "labsjdk", "version": "ce-23+5-jvmci-b01-debug", "platformspecific": true }, + "labsjdk-ce-latest-llvm": {"name": "labsjdk", "version": "ce-23+5-jvmci-b01-sulong", "platformspecific": true }, + "labsjdk-ee-latest": {"name": "labsjdk", "version": "ee-23+5-jvmci-b01", "platformspecific": true }, + "labsjdk-ee-latestDebug": {"name": "labsjdk", "version": "ee-23+5-jvmci-b01-debug", "platformspecific": true }, + "labsjdk-ee-latest-llvm": {"name": "labsjdk", "version": "ee-23+5-jvmci-b01-sulong", "platformspecific": true } }, "eclipse": { From 16f5cd8e2520213bfad1b758a29e0c6b5146e09d Mon Sep 17 00:00:00 2001 From: Jakub Chaloupka Date: Mon, 15 Jan 2024 13:49:12 +0100 Subject: [PATCH 458/593] Fix GradualInstrumentationTest#testRepeatedInstrumentationChangesParentsInMaterializedTreeIfSubtreesAreNotCloned by making sure that retired nodes from the first instrumentation are kept alive. --- .../test/GradualInstrumentationTest.java | 8 ++++++-- .../test/InstrumentationTestLanguage.java | 16 ++++++++++++---- 2 files changed, 18 insertions(+), 6 deletions(-) diff --git a/truffle/src/com.oracle.truffle.api.instrumentation.test/src/com/oracle/truffle/api/instrumentation/test/GradualInstrumentationTest.java b/truffle/src/com.oracle.truffle.api.instrumentation.test/src/com/oracle/truffle/api/instrumentation/test/GradualInstrumentationTest.java index e4d9b23f6e79..b64f3b46c419 100644 --- a/truffle/src/com.oracle.truffle.api.instrumentation.test/src/com/oracle/truffle/api/instrumentation/test/GradualInstrumentationTest.java +++ b/truffle/src/com.oracle.truffle.api.instrumentation.test/src/com/oracle/truffle/api/instrumentation/test/GradualInstrumentationTest.java @@ -248,12 +248,16 @@ public void testRepeatedInstrumentationChangesParentsInMaterializedTreeIfSubtree * materialized node has an expression as a child and the children of that expression * consist of only one expression, then the nested expression is connected as a child * directly to the materialized node in place of its parent and for each expression which is - * ommited this way, one child expression is added to the extra statement node. Since the NC + * omitted this way, one child expression is added to the extra statement node. Since the NC * node erroneously does not clone the subtree on materialization, the repeated * instrumentation changes the parent of the nested expression to its original expression * parent, and so in the new materialized tree, the nested expression node which is now a * direct child of the materialized NC node is not instrumented in the new tree, because it - * was already instrumented in the old tree (it already has instrumentation wrapper). + * was already instrumented in the old tree (it already has instrumentation wrapper). The + * stability of this test depends on keeping the node + * MaterializeChildStatementAndExpressionNode retired during the first instrumentation alive + * so that it is used in the second instrumentation. Therefore, the reference to it is kept + * in a field of MaterializedChildStatementAndExpressionNode. */ assertEquals("+S+S+E-E-S-S", listener2.getRecording()); } diff --git a/truffle/src/com.oracle.truffle.api.instrumentation.test/src/com/oracle/truffle/api/instrumentation/test/InstrumentationTestLanguage.java b/truffle/src/com.oracle.truffle.api.instrumentation.test/src/com/oracle/truffle/api/instrumentation/test/InstrumentationTestLanguage.java index 84a7f77a57f9..0ea8396f43af 100644 --- a/truffle/src/com.oracle.truffle.api.instrumentation.test/src/com/oracle/truffle/api/instrumentation/test/InstrumentationTestLanguage.java +++ b/truffle/src/com.oracle.truffle.api.instrumentation.test/src/com/oracle/truffle/api/instrumentation/test/InstrumentationTestLanguage.java @@ -2751,7 +2751,7 @@ public InstrumentableNode materializeInstrumentableNodes(Set> materializedTags) static class MaterializedChildStatementAndExpressionNode extends StatementNode { @Child private InstrumentedNode statementNode; + /* + * Keep the reference to the original node this node is materialization of in order for it + * not to be collected by GC so that it is still kept in retired nodes in the instrumented + * AST. + */ + private final Node retiredNode; - MaterializedChildStatementAndExpressionNode(SourceSection sourceSection, BaseNode[] expressions, BaseNode[] children) { + MaterializedChildStatementAndExpressionNode(Node retiredNode, SourceSection sourceSection, BaseNode[] expressions, BaseNode[] children) { super(children); + this.retiredNode = retiredNode; this.statementNode = new StatementNode(expressions); this.statementNode.setSourceSection(sourceSection); } - MaterializedChildStatementAndExpressionNode(InstrumentedNode statementNode, BaseNode[] children) { + MaterializedChildStatementAndExpressionNode(Node retiredNode, InstrumentedNode statementNode, BaseNode[] children) { super(children); this.statementNode = statementNode; + this.retiredNode = retiredNode; } @Override @@ -2788,7 +2796,7 @@ public Object execute(VirtualFrame frame) { @Override protected BaseNode copyUninitialized(Set> materializedTags) { - return new MaterializedChildStatementAndExpressionNode(cloneUninitialized(statementNode, materializedTags), cloneUninitialized(children, materializedTags)); + return new MaterializedChildStatementAndExpressionNode(retiredNode, cloneUninitialized(statementNode, materializedTags), cloneUninitialized(children, materializedTags)); } } From 429151925d9d8f692b13e8239cf14ce00c6bdab2 Mon Sep 17 00:00:00 2001 From: Francois Farquet Date: Thu, 28 Dec 2023 11:26:58 +0100 Subject: [PATCH 459/593] Remove dacapo timing suites --- .../ci/ci_common/benchmark-builders.jsonnet | 2 -- .../ci/ci_common/benchmark-suites.libsonnet | 20 ------------------- 2 files changed, 22 deletions(-) diff --git a/compiler/ci/ci_common/benchmark-builders.jsonnet b/compiler/ci/ci_common/benchmark-builders.jsonnet index 132fbc7348e2..988f903b02bc 100644 --- a/compiler/ci/ci_common/benchmark-builders.jsonnet +++ b/compiler/ci/ci_common/benchmark-builders.jsonnet @@ -13,10 +13,8 @@ [ c.daily + c.opt_post_merge + hw.x52 + jdk + cc.libgraal + bench.dacapo + PR_bench_libgraal, c.weekly + hw.x52 + jdk + cc.libgraal + bench.dacapo_size_variants, - c.weekly + hw.x52 + jdk + cc.libgraal + bench.dacapo_timing, c.daily + c.opt_post_merge + hw.x52 + jdk + cc.libgraal + bench.scala_dacapo + PR_bench_libgraal, c.weekly + hw.x52 + jdk + cc.libgraal + bench.scala_dacapo_size_variants, - c.weekly + hw.x52 + jdk + cc.libgraal + bench.scala_dacapo_timing, c.daily + c.opt_post_merge + hw.x52 + jdk + cc.libgraal + bench.renaissance + PR_bench_libgraal, c.daily + c.opt_post_merge + hw.x52 + jdk + cc.libgraal + bench.specjvm2008 + PR_bench_libgraal, c.weekly + hw.x52 + jdk + cc.libgraal + bench.specjbb2015, diff --git a/compiler/ci/ci_common/benchmark-suites.libsonnet b/compiler/ci/ci_common/benchmark-suites.libsonnet index 3482f880443d..b1d149e03b2b 100644 --- a/compiler/ci/ci_common/benchmark-suites.libsonnet +++ b/compiler/ci/ci_common/benchmark-suites.libsonnet @@ -65,16 +65,6 @@ max_jdk_version:: null }, - dacapo_timing: cc.compiler_benchmark + c.heap.default + { - suite:: "dacapo-timing", - run+: [ - self.benchmark_cmd + ["dacapo-timing:*", "--"] + self.extra_vm_args - ], - timelimit: "45:00", - min_jdk_version:: 8, - max_jdk_version:: null - }, - scala_dacapo: cc.compiler_benchmark + c.heap.default + { suite:: "scala-dacapo", run+: [ @@ -108,16 +98,6 @@ max_jdk_version:: null }, - scala_dacapo_timing: cc.compiler_benchmark + c.heap.default + { - suite:: "scala-dacapo-timing", - run+: [ - self.benchmark_cmd + ["scala-dacapo-timing:*", "--"] + self.extra_vm_args - ], - timelimit: "45:00", - min_jdk_version:: 8, - max_jdk_version:: null - }, - renaissance_template(suite_version=null, suite_name="renaissance", max_jdk_version=null):: cc.compiler_benchmark + c.heap.default + { suite:: suite_name, local suite_version_args = if suite_version != null then ["--bench-suite-version=" + suite_version] else [], From 25daf7b36279b3215b32245e7f02d1ebef1f2f13 Mon Sep 17 00:00:00 2001 From: Francois Farquet Date: Thu, 28 Dec 2023 11:32:38 +0100 Subject: [PATCH 460/593] Drop SpecJBB2015 full machines benchmarking due to low interest for it --- compiler/ci/ci_common/benchmark-builders.jsonnet | 1 - compiler/ci/ci_common/benchmark-suites.libsonnet | 15 +-------------- 2 files changed, 1 insertion(+), 15 deletions(-) diff --git a/compiler/ci/ci_common/benchmark-builders.jsonnet b/compiler/ci/ci_common/benchmark-builders.jsonnet index 988f903b02bc..ef13e2ebbe1e 100644 --- a/compiler/ci/ci_common/benchmark-builders.jsonnet +++ b/compiler/ci/ci_common/benchmark-builders.jsonnet @@ -18,7 +18,6 @@ c.daily + c.opt_post_merge + hw.x52 + jdk + cc.libgraal + bench.renaissance + PR_bench_libgraal, c.daily + c.opt_post_merge + hw.x52 + jdk + cc.libgraal + bench.specjvm2008 + PR_bench_libgraal, c.weekly + hw.x52 + jdk + cc.libgraal + bench.specjbb2015, - c.weekly + hw.x52 + jdk + cc.libgraal + bench.specjbb2015_full_machine, c.daily + c.opt_post_merge + hw.x52 + jdk + cc.libgraal + bench.awfy + PR_bench_libgraal, c.daily + hw.x52 + jdk + cc.libgraal + bench.microservice_benchmarks, c.daily + hw.x52 + jdk + cc.libgraal + bench.micros_graal_whitebox, diff --git a/compiler/ci/ci_common/benchmark-suites.libsonnet b/compiler/ci/ci_common/benchmark-suites.libsonnet index b1d149e03b2b..aca6bf978178 100644 --- a/compiler/ci/ci_common/benchmark-suites.libsonnet +++ b/compiler/ci/ci_common/benchmark-suites.libsonnet @@ -12,7 +12,7 @@ spec_suites:: unique_suites([$.specjvm2008, $.specjbb2015]), jmh_micros_suites:: unique_suites([$.micros_graal_dist, $.micros_misc_graal_dist , $.micros_shootout_graal_dist]), graal_internals_suites:: unique_suites([$.micros_graal_whitebox]), - special_suites:: unique_suites([$.dacapo_size_variants, $.scala_dacapo_size_variants, $.specjbb2015_full_machine]), + special_suites:: unique_suites([$.dacapo_size_variants, $.scala_dacapo_size_variants]), microservice_suites:: unique_suites([$.microservice_benchmarks]), main_suites:: unique_suites([$.specjvm2008] + self.open_suites), @@ -128,19 +128,6 @@ max_jdk_version:: null }, - specjbb2015_full_machine: cc.compiler_benchmark + c.heap.large_with_large_young_gen + { - suite:: "specjbb2015-full-machine", - downloads+: { - "SPECJBB2015": { name: "specjbb2015", version: "1.03" } - }, - run+: [ - self.plain_benchmark_cmd + ["specjbb2015", "--"] + self.extra_vm_args - ], - timelimit: "3:00:00", - min_jdk_version:: 8, - max_jdk_version:: null - }, - specjvm2008: cc.compiler_benchmark + c.heap.default + { suite:: "specjvm2008", downloads+: { From c44746e33a6a3d99f36c7d1d19b2303bb9a5e2c5 Mon Sep 17 00:00:00 2001 From: Francois Farquet Date: Thu, 28 Dec 2023 11:37:15 +0100 Subject: [PATCH 461/593] Use main suites instead of dedicated profiled suites --- compiler/ci/ci_common/benchmark-builders.jsonnet | 2 +- compiler/ci/ci_common/benchmark-suites.libsonnet | 1 - compiler/ci/ci_includes/baseline-benchmarks.jsonnet | 4 ++-- 3 files changed, 3 insertions(+), 4 deletions(-) diff --git a/compiler/ci/ci_common/benchmark-builders.jsonnet b/compiler/ci/ci_common/benchmark-builders.jsonnet index ef13e2ebbe1e..ceae186fcba1 100644 --- a/compiler/ci/ci_common/benchmark-builders.jsonnet +++ b/compiler/ci/ci_common/benchmark-builders.jsonnet @@ -40,7 +40,7 @@ c.weekly + hw.x52 + jdk + cc.libgraal + suite + cc.footprint_tracking + { job_prefix:: "bench-compiler-footprint" } ] for jdk in cc.bench_jdks - for suite in bench.groups.profiled_suites + for suite in bench.groups.main_suites ]), local weekly_amd64_forks_builds = std.flattenArrays([ diff --git a/compiler/ci/ci_common/benchmark-suites.libsonnet b/compiler/ci/ci_common/benchmark-suites.libsonnet index aca6bf978178..d10e902772b5 100644 --- a/compiler/ci/ci_common/benchmark-suites.libsonnet +++ b/compiler/ci/ci_common/benchmark-suites.libsonnet @@ -19,7 +19,6 @@ all_suites:: unique_suites(self.main_suites + self.spec_suites + self.jmh_micros_suites + self.special_suites + self.microservice_suites), weekly_forks_suites:: self.main_suites, - profiled_suites:: std.setDiff(self.main_suites, [$.specjbb2015], keyF=_suite_key), all_but_main_suites:: std.setDiff(self.all_suites, self.main_suites, keyF=_suite_key), }, diff --git a/compiler/ci/ci_includes/baseline-benchmarks.jsonnet b/compiler/ci/ci_includes/baseline-benchmarks.jsonnet index 57f4c503cfb3..7759a72a603e 100644 --- a/compiler/ci/ci_includes/baseline-benchmarks.jsonnet +++ b/compiler/ci/ci_includes/baseline-benchmarks.jsonnet @@ -14,7 +14,7 @@ local hotspot_aarch64_builds = [ c.weekly + hw.a12c + cc.latest_jdk + cc.c2 + suite - for suite in bench.groups.all_suites + for suite in bench.groups.main_suites ], local hotspot_profiling_builds = std.flattenArrays([ @@ -24,7 +24,7 @@ c.weekly + hw.x52 + cc.latest_jdk + cc.c2 + suite + cc.footprint_tracking + { job_prefix:: "bench-compiler-footprint" }, c.weekly + hw.a12c + cc.latest_jdk + cc.c2 + suite + cc.footprint_tracking + { job_prefix:: "bench-compiler-footprint" } ] - for suite in bench.groups.profiled_suites + for suite in bench.groups.main_suites ]), local weekly_forks_amd64_builds = std.flattenArrays([ From 82e11fd3bdd0a8a119bde0a1715b3919f5bd1b44 Mon Sep 17 00:00:00 2001 From: Francois Farquet Date: Thu, 28 Dec 2023 11:44:59 +0100 Subject: [PATCH 462/593] Restrict aarch64 benchmarking to main suites --- compiler/ci/ci_common/benchmark-builders.jsonnet | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/ci/ci_common/benchmark-builders.jsonnet b/compiler/ci/ci_common/benchmark-builders.jsonnet index ceae186fcba1..7cb9638298dd 100644 --- a/compiler/ci/ci_common/benchmark-builders.jsonnet +++ b/compiler/ci/ci_common/benchmark-builders.jsonnet @@ -57,7 +57,7 @@ local aarch64_builds = [ c.daily + hw.a12c + cc.latest_jdk + cc.libgraal + suite, - for suite in bench.groups.all_suites + for suite in bench.groups.main_suites ], local avx_builds = [ From d9bb5d2b341cea03e1aa23354d30a164a9b8dae8 Mon Sep 17 00:00:00 2001 From: Francois Farquet Date: Thu, 28 Dec 2023 14:03:07 +0100 Subject: [PATCH 463/593] Migrate JIT benchmarks to JDK latest --- .../ci/ci_common/benchmark-builders.jsonnet | 22 +++++++------- .../ci/ci_common/compiler-common.libsonnet | 10 +++++-- .../ci_includes/baseline-benchmarks.jsonnet | 29 ++++++++++--------- 3 files changed, 35 insertions(+), 26 deletions(-) diff --git a/compiler/ci/ci_common/benchmark-builders.jsonnet b/compiler/ci/ci_common/benchmark-builders.jsonnet index 7cb9638298dd..7a22ad0a2d7c 100644 --- a/compiler/ci/ci_common/benchmark-builders.jsonnet +++ b/compiler/ci/ci_common/benchmark-builders.jsonnet @@ -31,7 +31,7 @@ c.daily + hw.e4_8_64 + jdk + cc.libgraal + bench.specjvm2008 + {job_prefix:: "bench-e4vm-compiler"}, c.daily + hw.e4_8_64 + jdk + cc.libgraal + bench.microservice_benchmarks + {job_prefix:: "bench-e4vm-compiler"}, ] - for jdk in cc.bench_jdks + for jdk in cc.product_jdks ]), local profiling_builds = std.flattenArrays([ @@ -39,56 +39,58 @@ c.weekly + hw.x52 + jdk + cc.libgraal + suite + cc.enable_profiling + { job_prefix:: "bench-compiler-profiling" }, c.weekly + hw.x52 + jdk + cc.libgraal + suite + cc.footprint_tracking + { job_prefix:: "bench-compiler-footprint" } ] - for jdk in cc.bench_jdks + for jdk in cc.product_jdks for suite in bench.groups.main_suites ]), local weekly_amd64_forks_builds = std.flattenArrays([ bc.generate_fork_builds(c.weekly + hw.x52 + jdk + cc.libgraal + suite, subdir='compiler') + bc.generate_fork_builds(c.monthly + hw.x52 + jdk + cc.jargraal + suite, subdir='compiler') - for jdk in cc.bench_jdks + for jdk in cc.product_jdks for suite in bench.groups.weekly_forks_suites ]), local weekly_aarch64_forks_builds = std.flattenArrays([ - bc.generate_fork_builds(c.weekly + hw.a12c + cc.latest_jdk + cc.libgraal + suite, subdir='compiler') + bc.generate_fork_builds(c.weekly + hw.a12c + jdk + cc.libgraal + suite, subdir='compiler') + for jdk in cc.product_jdks for suite in bench.groups.weekly_forks_suites ]), local aarch64_builds = [ - c.daily + hw.a12c + cc.latest_jdk + cc.libgraal + suite, + c.daily + hw.a12c + jdk + cc.libgraal + suite, + for jdk in cc.product_jdks for suite in bench.groups.main_suites ], local avx_builds = [ c.monthly + hw.x82 + jdk + cc.libgraal + avx + suite, for avx in [cc.avx2_mode, cc.avx3_mode] - for jdk in cc.bench_jdks + for jdk in cc.product_jdks for suite in bench.groups.main_suites ], local zgc_builds = [ c.weekly + hw.x52 + jdk + cc.libgraal + cc.zgc_mode + suite, - for jdk in cc.bench_jdks + for jdk in cc.product_jdks for suite in bench.groups.main_suites + [bench.specjbb2015] ], local zgc_avx_builds = [ c.monthly + hw.x82 + jdk + cc.libgraal + cc.zgc_mode + avx + suite, for avx in [cc.avx2_mode, cc.avx3_mode] - for jdk in cc.bench_jdks + for jdk in cc.product_jdks for suite in bench.groups.main_suites ], local no_tiered_builds = [ c.weekly + hw.x52 + jdk + cc.libgraal + cc.no_tiered_comp + suite, - for jdk in cc.bench_jdks + for jdk in cc.product_jdks for suite in bench.groups.main_suites ], local no_profile_info_builds = [ c.weekly + hw.x52 + jdk + cc.libgraal + cc.no_profile_info + suite, - for jdk in cc.bench_jdks + for jdk in cc.product_jdks for suite in bench.groups.main_suites ], diff --git a/compiler/ci/ci_common/compiler-common.libsonnet b/compiler/ci/ci_common/compiler-common.libsonnet index 4a2088a86eb2..9d51ac8fd90e 100644 --- a/compiler/ci/ci_common/compiler-common.libsonnet +++ b/compiler/ci/ci_common/compiler-common.libsonnet @@ -33,9 +33,13 @@ ] }, - latest_jdk:: common["labsjdk-ee-21"], - bench_jdks:: [ - self.latest_jdk + product_jdks:: [ + common["labsjdk-ee-latest"], + ], + + jdks_of_interest:: [ + common["labsjdk-ee-21"], + common["labsjdk-ee-latest"], ], compiler_benchmarks_notifications:: { diff --git a/compiler/ci/ci_includes/baseline-benchmarks.jsonnet b/compiler/ci/ci_includes/baseline-benchmarks.jsonnet index 7759a72a603e..f558cd1ae1b5 100644 --- a/compiler/ci/ci_includes/baseline-benchmarks.jsonnet +++ b/compiler/ci/ci_includes/baseline-benchmarks.jsonnet @@ -8,45 +8,48 @@ local hotspot_amd64_builds = [ c.weekly + hw.x52 + jdk + cc.c2 + suite - for jdk in cc.bench_jdks + for jdk in cc.product_jdks for suite in bench.groups.all_suites ], local hotspot_aarch64_builds = [ - c.weekly + hw.a12c + cc.latest_jdk + cc.c2 + suite + c.weekly + hw.a12c + jdk + cc.c2 + suite + for jdk in cc.product_jdks for suite in bench.groups.main_suites ], local hotspot_profiling_builds = std.flattenArrays([ [ - c.weekly + hw.x52 + cc.latest_jdk + cc.c2 + suite + cc.enable_profiling + { job_prefix:: "bench-compiler-profiling" }, - c.weekly + hw.a12c + cc.latest_jdk + cc.c2 + suite + cc.enable_profiling + { job_prefix:: "bench-compiler-profiling" }, - c.weekly + hw.x52 + cc.latest_jdk + cc.c2 + suite + cc.footprint_tracking + { job_prefix:: "bench-compiler-footprint" }, - c.weekly + hw.a12c + cc.latest_jdk + cc.c2 + suite + cc.footprint_tracking + { job_prefix:: "bench-compiler-footprint" } + c.weekly + hw.x52 + jdk + cc.c2 + suite + cc.enable_profiling + { job_prefix:: "bench-compiler-profiling" }, + c.weekly + hw.a12c + jdk + cc.c2 + suite + cc.enable_profiling + { job_prefix:: "bench-compiler-profiling" }, + c.weekly + hw.x52 + jdk + cc.c2 + suite + cc.footprint_tracking + { job_prefix:: "bench-compiler-footprint" }, + c.weekly + hw.a12c + jdk + cc.c2 + suite + cc.footprint_tracking + { job_prefix:: "bench-compiler-footprint" } ] + for jdk in cc.product_jdks for suite in bench.groups.main_suites ]), local weekly_forks_amd64_builds = std.flattenArrays([ bc.generate_fork_builds(c.weekly + hw.x52 + jdk + cc.c2 + suite) - for jdk in cc.bench_jdks + for jdk in cc.jdks_of_interest for suite in bench.groups.weekly_forks_suites ]), local weekly_forks_aarch64_builds = std.flattenArrays([ - bc.generate_fork_builds(c.weekly + hw.a12c + cc.latest_jdk + cc.c2 + suite) + bc.generate_fork_builds(c.weekly + hw.a12c + jdk + cc.c2 + suite) + for jdk in cc.product_jdks for suite in bench.groups.weekly_forks_suites ]), local daily_economy_builds = [ c.daily + hw.x52 + jdk + cc.libgraal + cc.economy_mode + suite - for jdk in cc.bench_jdks + for jdk in cc.product_jdks for suite in bench.groups.main_suites ], local weekly_economy_builds = [ c.weekly + hw.x52 + jdk + cc.libgraal + cc.economy_mode + suite - for jdk in cc.bench_jdks + for jdk in cc.product_jdks for suite in bench.groups.all_but_main_suites ], @@ -56,7 +59,7 @@ c.weekly + hw.x52 + jdk + cc.c2 + cc.no_tiered_comp + suite, c.weekly + hw.x52 + jdk + cc.libgraal + cc.economy_mode + cc.no_tiered_comp + suite ] - for jdk in cc.bench_jdks + for jdk in cc.product_jdks for suite in bench.groups.main_suites ]), @@ -64,7 +67,7 @@ [ c.weekly + hw.x52 + jdk + cc.c2 + cc.zgc_mode + suite, ] - for jdk in cc.bench_jdks + for jdk in cc.product_jdks for suite in bench.groups.main_suites ]) + std.flattenArrays([ [ @@ -73,7 +76,7 @@ c.weekly + hw.x52 + jdk + cc.c2 + cc.zgc_mode + bench.microservice_benchmarks, c.weekly + hw.x52 + jdk + cc.c2 + cc.gen_zgc_mode + bench.microservice_benchmarks, ] - for jdk in cc.bench_jdks + for jdk in cc.product_jdks ]), local all_builds = hotspot_amd64_builds + hotspot_aarch64_builds + hotspot_profiling_builds + weekly_forks_amd64_builds + weekly_forks_aarch64_builds + daily_economy_builds + weekly_economy_builds + no_tiered_builds + gc_variants_builds, From 9835bc694a5876d600f2b90624da4e36841f91cb Mon Sep 17 00:00:00 2001 From: Francois Farquet Date: Thu, 28 Dec 2023 14:01:36 +0100 Subject: [PATCH 464/593] CI overlay bump --- graal-common.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/graal-common.json b/graal-common.json index cafe1f9650fb..c1c0a6470476 100644 --- a/graal-common.json +++ b/graal-common.json @@ -1,6 +1,6 @@ { "README": "This file contains definitions that are useful for the jsonnet CI files of the graal and graal-enterprise repositories.", "ci": { - "overlay": "a3a0f1c506dc9974814a49de1cd24504c25c56f3" + "overlay": "ad801a5f7147561be19dd164003600bd31a43075" } } From c9de8f1073453b5d0efd579ecddfb6fd852f8016 Mon Sep 17 00:00:00 2001 From: Fabio Niephaus Date: Mon, 15 Jan 2024 14:42:42 +0100 Subject: [PATCH 465/593] Let `getMaxLaneCount()` report zero for now. --- .../jdk/Target_jdk_internal_vm_vector_VectorSupport.java | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/Target_jdk_internal_vm_vector_VectorSupport.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/Target_jdk_internal_vm_vector_VectorSupport.java index 448d7af7d8f1..a976f2fc8e73 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/Target_jdk_internal_vm_vector_VectorSupport.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/Target_jdk_internal_vm_vector_VectorSupport.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2023, 2024, 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,7 +27,6 @@ import com.oracle.svm.core.annotate.Delete; import com.oracle.svm.core.annotate.Substitute; import com.oracle.svm.core.annotate.TargetClass; -import com.oracle.svm.core.util.VMError; @TargetClass(className = "jdk.internal.vm.vector.VectorSupport") public final class Target_jdk_internal_vm_vector_VectorSupport { @@ -37,6 +36,10 @@ public final class Target_jdk_internal_vm_vector_VectorSupport { @SuppressWarnings("unused") @Substitute public static int getMaxLaneCount(Class etype) { - throw VMError.unsupportedFeature("VectorSupport.getMaxLaneCount not supported."); + /* + * GR-51303: The Vector API is not yet optimized by the Graal compiler. But instead of + * letting applications fail, always return a max lane count of zero for now. + */ + return 0; } } From fcda67373264aa45ce8a417c96a501c294d1e900 Mon Sep 17 00:00:00 2001 From: Codrut Stancu Date: Mon, 15 Jan 2024 16:00:35 +0100 Subject: [PATCH 466/593] Refactor DisallowedImageHeapObjectFeature. --- .../DisallowedImageHeapObjectFeature.java | 18 +++--------------- 1 file changed, 3 insertions(+), 15 deletions(-) diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/DisallowedImageHeapObjectFeature.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/DisallowedImageHeapObjectFeature.java index da33d69a6f90..3739b8c57a99 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/DisallowedImageHeapObjectFeature.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/DisallowedImageHeapObjectFeature.java @@ -37,7 +37,6 @@ import java.util.Arrays; import java.util.HashSet; import java.util.IdentityHashMap; -import java.util.List; import java.util.Map; import java.util.Random; import java.util.Set; @@ -46,14 +45,11 @@ import javax.management.MBeanServerConnection; -import org.graalvm.nativeimage.hosted.Feature; - import com.oracle.graal.pointsto.constraints.UnsupportedFeatureException; import com.oracle.svm.core.SubstrateOptions; import com.oracle.svm.core.feature.AutomaticallyRegisteredFeature; import com.oracle.svm.core.feature.InternalFeature; import com.oracle.svm.core.image.DisallowedImageHeapObjects; -import com.oracle.svm.core.jdk.management.ManagementFeature; import com.oracle.svm.core.jdk.management.ManagementSupport; import com.oracle.svm.core.option.SubstrateOptionsParser; import com.oracle.svm.hosted.FeatureImpl; @@ -71,21 +67,10 @@ public class DisallowedImageHeapObjectFeature implements InternalFeature { private String[] disallowedSubstrings; private Map disallowedByteSubstrings; - @Override - public List> getRequiredFeatures() { - /* - * Ensure that object replaced registered by ManagementFeature runs before our object - * replacer. - */ - return Arrays.asList(ManagementFeature.class); - } - @Override public void duringSetup(DuringSetupAccess a) { FeatureImpl.DuringSetupAccessImpl access = (FeatureImpl.DuringSetupAccessImpl) a; classInitialization = access.getHostVM().getClassInitializationSupport(); - access.registerObjectReachableCallback(String.class, this::onStringReachable); - access.registerObjectReachableCallback(byte[].class, this::onByteArrayReachable); access.registerObjectReachableCallback(MBeanServerConnection.class, this::onMBeanServerConnectionReachable); access.registerObjectReachableCallback(PlatformManagedObject.class, this::onPlatformManagedObjectReachable); access.registerObjectReachableCallback(Random.class, (a1, obj) -> DisallowedImageHeapObjects.onRandomReachable(obj, this::error)); @@ -101,6 +86,9 @@ public void duringSetup(DuringSetupAccess a) { access.registerObjectReachableCallback(CANCELLABLE_CLASS, (a1, obj) -> DisallowedImageHeapObjects.onCancellableReachable(obj, this::error)); if (SubstrateOptions.DetectUserDirectoriesInImageHeap.getValue()) { + access.registerObjectReachableCallback(String.class, this::onStringReachable); + access.registerObjectReachableCallback(byte[].class, this::onByteArrayReachable); + /* * We do not check for the temp directory name and the user name because they have a too * high chance of being short or generic terms that appear in valid strings. From 888a494dad0b6c36d47cfbc452a53afb0ff4ccce Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Paul=20W=C3=B6gerer?= Date: Mon, 15 Jan 2024 17:18:24 +0100 Subject: [PATCH 467/593] Only use -H:Path validation in non-bundle mode When a bundle gets applied, the -H:Path value is purely virtual before it gets redirected to imagePathOutputDir. Validating the virtual value makes no sense (and causes errors if the path does not exist anymore) --- .../src/com/oracle/svm/driver/NativeImage.java | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/substratevm/src/com.oracle.svm.driver/src/com/oracle/svm/driver/NativeImage.java b/substratevm/src/com.oracle.svm.driver/src/com/oracle/svm/driver/NativeImage.java index c230b49e1cde..23f204a2bbcd 100644 --- a/substratevm/src/com.oracle.svm.driver/src/com/oracle/svm/driver/NativeImage.java +++ b/substratevm/src/com.oracle.svm.driver/src/com/oracle/svm/driver/NativeImage.java @@ -1225,13 +1225,15 @@ private int completeImageBuild() { if (!imageNamePathParent.isAbsolute()) { imageNamePathParent = imagePath.resolve(imageNamePathParent); } - if (!Files.isDirectory(imageNamePathParent)) { - throw NativeImage.showError("Writing image to non-existent directory " + imageNamePathParent + " is not allowed. " + - "Create the missing directory if you want the image to be written to that location."); - } - if (!Files.isWritable(imageNamePathParent)) { - throw NativeImage.showError("Writing image to directory without write access " + imageNamePathParent + " is not possible. " + - "Ensure the directory has write access or specify image path with write access."); + if (!useBundle()) { + if (!Files.isDirectory(imageNamePathParent)) { + throw NativeImage.showError("Writing image to non-existent directory " + imageNamePathParent + " is not allowed. " + + "Create the missing directory if you want the image to be written to that location."); + } + if (!Files.isWritable(imageNamePathParent)) { + throw NativeImage.showError("Writing image to directory without write access " + imageNamePathParent + " is not possible. " + + "Ensure the directory has write access or specify image path with write access."); + } } imagePath = imageNamePathParent; /* Update arguments passed to builder */ From 9c21634fcdd1551e86059864f52ae509928829ed Mon Sep 17 00:00:00 2001 From: Fabio Niephaus Date: Mon, 15 Jan 2024 17:51:49 +0100 Subject: [PATCH 468/593] Inform users about Vector API perf expectations. --- .../com/oracle/svm/hosted/ProgressReporterFeature.java | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/ProgressReporterFeature.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/ProgressReporterFeature.java index 66e44e88b66a..f9938176c596 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/ProgressReporterFeature.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/ProgressReporterFeature.java @@ -45,6 +45,7 @@ import com.oracle.svm.hosted.util.CPUTypeAMD64; import com.oracle.svm.hosted.util.CPUTypeRISCV64; import com.oracle.svm.util.LogUtils; +import com.oracle.svm.util.ReflectionUtil; @AutomaticallyRegisteredFeature public class ProgressReporterFeature implements InternalFeature { @@ -62,6 +63,15 @@ public void duringAnalysis(DuringAnalysisAccess access) { reporter.reportStageProgress(); } + @Override + public void afterAnalysis(AfterAnalysisAccess access) { + var vectorSpeciesClass = ReflectionUtil.lookupClass(true, "jdk.incubator.vector.VectorSpecies"); + if (vectorSpeciesClass != null && access.isReachable(vectorSpeciesClass)) { + LogUtils.warning( + "This application uses a preview of the Vector API, which is functional but slow on Native Image because it is not yet optimized by the Graal compiler. Please keep this in mind when evaluating performance."); + } + } + @Override public void afterCompilation(AfterCompilationAccess access) { if (SubstrateOptions.BuildOutputBreakdowns.getValue()) { From 81eba3e271b8d2205b9507b44f0b6e61c1fb8abb Mon Sep 17 00:00:00 2001 From: Yudi Zheng Date: Fri, 12 Jan 2024 16:36:39 +0100 Subject: [PATCH 469/593] Avoid inflating monitors when installing hash codes for LM_LIGHTWEIGHT. --- .../replacements/HotSpotHashCodeSnippets.java | 38 ++++++++++++------- 1 file changed, 24 insertions(+), 14 deletions(-) diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/replacements/HotSpotHashCodeSnippets.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/replacements/HotSpotHashCodeSnippets.java index a3e3871ecdd2..d17236151da0 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/replacements/HotSpotHashCodeSnippets.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/replacements/HotSpotHashCodeSnippets.java @@ -31,19 +31,22 @@ import static jdk.graal.compiler.hotspot.replacements.HotSpotReplacementsUtil.loadWordFromObject; import static jdk.graal.compiler.hotspot.replacements.HotSpotReplacementsUtil.lockMaskInPlace; import static jdk.graal.compiler.hotspot.replacements.HotSpotReplacementsUtil.markOffset; +import static jdk.graal.compiler.hotspot.replacements.HotSpotReplacementsUtil.monitorMask; import static jdk.graal.compiler.hotspot.replacements.HotSpotReplacementsUtil.uninitializedIdentityHashCodeValue; import static jdk.graal.compiler.hotspot.replacements.HotSpotReplacementsUtil.unlockedMask; +import static jdk.graal.compiler.hotspot.replacements.HotSpotReplacementsUtil.useLightweightLocking; import static jdk.graal.compiler.nodes.extended.BranchProbabilityNode.FAST_PATH_PROBABILITY; import static jdk.graal.compiler.nodes.extended.BranchProbabilityNode.probability; +import org.graalvm.word.WordFactory; + import jdk.graal.compiler.lir.SyncPort; import jdk.graal.compiler.replacements.IdentityHashCodeSnippets; import jdk.graal.compiler.word.Word; -import org.graalvm.word.WordFactory; // @formatter:off -@SyncPort(from = "https://github.com/openjdk/jdk/blob/ce8399fd6071766114f5f201b6e44a7abdba9f5a/src/hotspot/share/opto/library_call.cpp#L4485-L4609", - sha1 = "34281fb78c4f0657a704dbda3e3cc85ed56dd2ad") +@SyncPort(from = "https://github.com/openjdk/jdk/blob/c5e72450966ad50d57a8d22e9d634bfcb319aee9/src/hotspot/share/opto/library_call.cpp#L4511-L4643", + sha1 = "9776f1621d6e2daecd17acf0cd89039339b28a1d") // @formatter:on public class HotSpotHashCodeSnippets extends IdentityHashCodeSnippets { @@ -51,19 +54,26 @@ public class HotSpotHashCodeSnippets extends IdentityHashCodeSnippets { protected int computeIdentityHashCode(final Object x) { Word mark = loadWordFromObject(x, markOffset(INJECTED_VMCONFIG)); - // When the object is unlocked, HotSpot reuses upper bits (e.g., [38:8] in 64-bits VM) of - // the mark word in object header for caching identity hash code. The same bits are part of - // the thread pointer in the case of biased locking, pointer to the displaced mark in a - // thread's stack in the case of stack locking, or pointer to the monitor object in the case - // of inflated lock. + // In HotSpot, the upper bits (i.e., [63:2] in 64-bits VM) of the mark word in object header + // are + // 1) not used with lightweight locking; + // 2) pointer to the displaced mark in a thread's stack with stack locking; or + // 3) pointer to the monitor object with heavy monitor locking. + // + // When these upper bits are not used, i.e., when an object is either unlocked or locked + // with lightweight locking, HotSpot reuses fraction of the upper bits (e.g., [38:8] in + // 64-bits VM) for caching the identity hash code. Therefore, + // 1) when lightweight locking is employed as fast locking scheme (-XX:LockingMode=2), we + // only need to test if the object is NOT in a monitor-locked state, i.e., lock bits not + // equals to 0b10; + // 2) when stack locking is employed as fast locking scheme (-XX:LockingMode=1) or no fast + // locking scheme is employed (-XX:LockingMode=0), we need to test if the object is + // unlocked, i.e., lock bits equals to 0b01. // - // To test if an object is unlocked, we simply need to compare the lock bits against the - // constant unlocked value. The lock bits are the least significant 3 bits prior to Java 18 - // (1 bit for biased locking and 2 bits for stack locking or heavy locking), and 2 bits - // afterwards due to elimination of the biased locking. The unlocked values are 001 and 01 - // respectively. See src/hotspot/share/oops/markWord.hpp for more details. + // See src/hotspot/share/oops/markWord.hpp for more details. final Word lockBits = mark.and(lockMaskInPlace(INJECTED_VMCONFIG)); - if (probability(FAST_PATH_PROBABILITY, lockBits.equal(WordFactory.unsigned(unlockedMask(INJECTED_VMCONFIG))))) { + if (probability(FAST_PATH_PROBABILITY, useLightweightLocking(INJECTED_VMCONFIG) ? lockBits.notEqual(WordFactory.unsigned(monitorMask(INJECTED_VMCONFIG))) + : lockBits.equal(WordFactory.unsigned(unlockedMask(INJECTED_VMCONFIG))))) { int hash = (int) mark.unsignedShiftRight(identityHashCodeShift(INJECTED_VMCONFIG)).rawValue(); if (probability(FAST_PATH_PROBABILITY, hash != uninitializedIdentityHashCodeValue(INJECTED_VMCONFIG))) { return hash; From 48597d42ec32ef47564e49478070172a294cd291 Mon Sep 17 00:00:00 2001 From: Yudi Zheng Date: Fri, 12 Jan 2024 16:48:29 +0100 Subject: [PATCH 470/593] Update SyncPort information. --- .../lir/processor/SyncPortProcessor.java | 66 ++++++++++--------- .../meta/HotSpotGraphBuilderPlugins.java | 2 +- .../hotspot/replacements/MonitorSnippets.java | 4 +- .../VirtualThreadUpdateJFRSnippets.java | 2 +- .../lir/aarch64/AArch64BitSwapOp.java | 2 +- .../AArch64NormalizedUnsignedCompareOp.java | 2 +- .../lir/amd64/AMD64BigIntegerMulAddOp.java | 6 +- .../amd64/AMD64BigIntegerMultiplyToLenOp.java | 4 +- .../amd64/AMD64BigIntegerSquareToLenOp.java | 4 +- .../compiler/lir/amd64/AMD64BitSwapOp.java | 2 +- .../lir/amd64/AMD64CountPositivesOp.java | 2 +- .../lir/amd64/AMD64EncodeArrayOp.java | 2 +- .../lir/amd64/AMD64RoundFloatToIntegerOp.java | 2 +- .../lir/amd64/AMD64StringUTF16CompressOp.java | 2 +- .../lir/amd64/AMD64VectorizedHashCodeOp.java | 6 +- .../lir/amd64/AMD64VectorizedMismatchOp.java | 2 +- 16 files changed, 57 insertions(+), 53 deletions(-) diff --git a/compiler/src/jdk.graal.compiler.processor/src/jdk/graal/compiler/lir/processor/SyncPortProcessor.java b/compiler/src/jdk.graal.compiler.processor/src/jdk/graal/compiler/lir/processor/SyncPortProcessor.java index f09b680fdd9a..c4c75c337899 100644 --- a/compiler/src/jdk.graal.compiler.processor/src/jdk/graal/compiler/lir/processor/SyncPortProcessor.java +++ b/compiler/src/jdk.graal.compiler.processor/src/jdk/graal/compiler/lir/processor/SyncPortProcessor.java @@ -129,15 +129,19 @@ private void compareDigest(MessageDigest md, AnnotationMirror annotationMirror, } String extraMessage = ""; - if (!isURLOverwritten) { - String urlOld = String.format("https://raw.githubusercontent.com/openjdk/jdk/%s/%s", commit, path); - String sha1Old = digest(proxy, md, urlOld, lineStart - 1, lineEnd); - if (sha1.equals(sha1Old)) { - String latestCommit = getLatestCommit(proxy); - int idx = find(proxy, urlOld, url, lineStart - 1, lineEnd, SEARCH_RANGE); - if (idx != -1) { - int idxInclusive = idx + 1; - kind = NOTE; + + String urlOld = String.format("https://raw.githubusercontent.com/openjdk/jdk/%s/%s", commit, path); + String sha1Old = digest(proxy, md, urlOld, lineStart - 1, lineEnd); + + if (sha1.equals(sha1Old)) { + String latestCommit = getLatestCommit(proxy); + int idx = find(proxy, urlOld, url, lineStart - 1, lineEnd, SEARCH_RANGE); + if (idx != -1) { + int idxInclusive = idx + 1; + kind = NOTE; + if (isURLOverwritten) { + extraMessage = " The original code snippet is shifted."; + } else { String urlFormat = "https://github.com/openjdk/jdk/blob/%s/%s#L%d-L%d"; String newUrl = String.format(urlFormat, latestCommit, path, idxInclusive, idxInclusive + (lineEnd - lineStart)); extraMessage = String.format(""" @@ -153,33 +157,33 @@ private void compareDigest(MessageDigest md, AnnotationMirror annotationMirror, assert !newUrl.contains("+"); dumpUpdateCommands.printf("sed -i s+%s+%s+g $(git grep --files-with-matches %s)%n", oldUrl, newUrl, sha1); } - } else { - extraMessage = String.format(""" - See also: - https://github.com/openjdk/jdk/compare/%s...%s - https://github.com/openjdk/jdk/commits/%s/%s - """, - commit, - latestCommit, - latestCommit, - path); - if (Boolean.parseBoolean(System.getenv(SYNC_DUMP_ENV_VAR))) { - dump(proxy, urlOld, lineStart - 1, lineEnd, element + ".old"); - dump(proxy, url, lineStart - 1, lineEnd, element + ".new"); - } } } else { extraMessage = String.format(""" - New SyncPort? Then: - @SyncPort(from = "https://github.com/openjdk/jdk/blob/%s/%s#L%d-L%d", - sha1 = "%s") + See also: + https://github.com/openjdk/jdk/compare/%s...%s + https://github.com/openjdk/jdk/commits/%s/%s """, - getLatestCommit(proxy), - path, - lineStart, - lineEnd, - sha1Latest); + commit, + latestCommit, + latestCommit, + path); + if (Boolean.parseBoolean(System.getenv(SYNC_DUMP_ENV_VAR))) { + dump(proxy, urlOld, lineStart - 1, lineEnd, element + ".old"); + dump(proxy, url, lineStart - 1, lineEnd, element + ".new"); + } } + } else { + extraMessage = String.format(""" + New SyncPort? Then: + @SyncPort(from = "https://github.com/openjdk/jdk/blob/%s/%s#L%d-L%d", + sha1 = "%s") + """, + getLatestCommit(proxy), + path, + lineStart, + lineEnd, + sha1Latest); } env().getMessager().printMessage(kind, String.format("Sha1 digest of %s (ported by %s) does not match %s%s#L%d-L%d : expected %s but was %s.%s", diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/meta/HotSpotGraphBuilderPlugins.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/meta/HotSpotGraphBuilderPlugins.java index 50564e33e2c5..0a7b679fe171 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/meta/HotSpotGraphBuilderPlugins.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/meta/HotSpotGraphBuilderPlugins.java @@ -667,7 +667,7 @@ public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Rec } // @formatter:off - @SyncPort(from = "https://github.com/openjdk/jdk/blob/ce8399fd6071766114f5f201b6e44a7abdba9f5a/src/hotspot/share/opto/library_call.cpp#L2873-L2928", + @SyncPort(from = "https://github.com/openjdk/jdk/blob/c5e72450966ad50d57a8d22e9d634bfcb319aee9/src/hotspot/share/opto/library_call.cpp#L2877-L2932", sha1 = "5c117a305e90a48f0a6fe86ace2c15942393c0ab") // @formatter:on private static void inlineNativeNotifyJvmtiFunctions(GraalHotSpotVMConfig config, GraphBuilderContext b, ResolvedJavaMethod targetMethod, ForeignCallDescriptor descriptor, diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/replacements/MonitorSnippets.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/replacements/MonitorSnippets.java index 47b0ae46618b..f4c377f212b9 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/replacements/MonitorSnippets.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/replacements/MonitorSnippets.java @@ -329,7 +329,7 @@ private static boolean tryStackLocking(Object object, Word lock, Word mark, Word } // @formatter:off - @SyncPort(from = "https://github.com/openjdk/jdk/blob/ce8399fd6071766114f5f201b6e44a7abdba9f5a/src/hotspot/cpu/x86/macroAssembler_x86.cpp#L9963-L9997", + @SyncPort(from = "https://github.com/openjdk/jdk/blob/c5e72450966ad50d57a8d22e9d634bfcb319aee9/src/hotspot/cpu/x86/macroAssembler_x86.cpp#L9877-L9911", sha1 = "7a02d52b6b621959389e574984ca20b52100fe5e") // @formatter:on private static boolean tryLightweightLocking(Object object, Word lock, Word mark, Word thread, boolean trace, Counters counters, Register stackPointerRegister) { @@ -431,7 +431,7 @@ private static boolean tryStackUnlocking(Object object, Word displacedMark, Word } // @formatter:off - @SyncPort(from = "https://github.com/openjdk/jdk/blob/ce8399fd6071766114f5f201b6e44a7abdba9f5a/src/hotspot/cpu/x86/macroAssembler_x86.cpp#L9999-L10028", + @SyncPort(from = "https://github.com/openjdk/jdk/blob/c5e72450966ad50d57a8d22e9d634bfcb319aee9/src/hotspot/cpu/x86/macroAssembler_x86.cpp#L9913-L9942", sha1 = "666343ea6d941f68ed863a396d9496cb3ce1b69b") // @formatter:on private static boolean tryLightweightUnlocking(Object object, Word thread, boolean trace, Counters counters) { diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/replacements/VirtualThreadUpdateJFRSnippets.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/replacements/VirtualThreadUpdateJFRSnippets.java index c44a41c86ca8..ae6b70921240 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/replacements/VirtualThreadUpdateJFRSnippets.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/replacements/VirtualThreadUpdateJFRSnippets.java @@ -64,7 +64,7 @@ * Snippet for updating JFR thread local data on {@code Thread#setCurrentThread} events. */ // @formatter:off -@SyncPort(from = "https://github.com/openjdk/jdk/blob/ce8399fd6071766114f5f201b6e44a7abdba9f5a/src/hotspot/share/opto/library_call.cpp#L3458-L3584", +@SyncPort(from = "https://github.com/openjdk/jdk/blob/c5e72450966ad50d57a8d22e9d634bfcb319aee9/src/hotspot/share/opto/library_call.cpp#L3485-L3611", sha1 = "1f980401f5d7d9a363577635fd57fc1e24505d91") // @formatter:on public class VirtualThreadUpdateJFRSnippets implements Snippets { diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/aarch64/AArch64BitSwapOp.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/aarch64/AArch64BitSwapOp.java index ae0125c9d1b6..290fbedde039 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/aarch64/AArch64BitSwapOp.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/aarch64/AArch64BitSwapOp.java @@ -36,7 +36,7 @@ import jdk.vm.ci.meta.AllocatableValue; // @formatter:off -@SyncPort(from = "https://github.com/openjdk/jdk/blob/0a3a925ad88921d387aa851157f54ac0054d347b/src/hotspot/cpu/aarch64/aarch64.ad#L13942-L13966", +@SyncPort(from = "https://github.com/openjdk/jdk/blob/c5e72450966ad50d57a8d22e9d634bfcb319aee9/src/hotspot/cpu/aarch64/aarch64.ad#L13960-L13984", sha1 = "5e7655c00a9d610fa3c992305c0f6aeba32b2d6c") // @formatter:on public class AArch64BitSwapOp extends AArch64LIRInstruction { diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/aarch64/AArch64NormalizedUnsignedCompareOp.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/aarch64/AArch64NormalizedUnsignedCompareOp.java index c075bd76e86a..8b19fa5adc71 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/aarch64/AArch64NormalizedUnsignedCompareOp.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/aarch64/AArch64NormalizedUnsignedCompareOp.java @@ -41,7 +41,7 @@ * Returns -1, 0, or 1 if either x < y, x == y, or x > y. */ // @formatter:off -@SyncPort(from = "https://github.com/openjdk/jdk/blob/0a3a925ad88921d387aa851157f54ac0054d347b/src/hotspot/cpu/aarch64/aarch64.ad#L9594-L9676", +@SyncPort(from = "https://github.com/openjdk/jdk/blob/c5e72450966ad50d57a8d22e9d634bfcb319aee9/src/hotspot/cpu/aarch64/aarch64.ad#L9612-L9694", sha1 = "84da421c1489e188366d61bb4298e0425ccac14b") // @formatter:on public class AArch64NormalizedUnsignedCompareOp extends AArch64LIRInstruction { diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/amd64/AMD64BigIntegerMulAddOp.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/amd64/AMD64BigIntegerMulAddOp.java index dc890ce120d6..438b251fcb67 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/amd64/AMD64BigIntegerMulAddOp.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/amd64/AMD64BigIntegerMulAddOp.java @@ -57,11 +57,11 @@ import jdk.vm.ci.meta.Value; // @formatter:off -@SyncPort(from = "https://github.com/openjdk/jdk/blob/ce8399fd6071766114f5f201b6e44a7abdba9f5a/src/hotspot/cpu/x86/stubGenerator_x86_64.cpp#L3186-L3238", +@SyncPort(from = "https://github.com/openjdk/jdk/blob/c5e72450966ad50d57a8d22e9d634bfcb319aee9/src/hotspot/cpu/x86/stubGenerator_x86_64.cpp#L3188-L3240", sha1 = "2f3b577fa7f0ced9cc2514af80d2c2833ab7caf2") -@SyncPort(from = "https://github.com/openjdk/jdk/blob/ce8399fd6071766114f5f201b6e44a7abdba9f5a/src/hotspot/cpu/x86/macroAssembler_x86.cpp#L7138-L7172", +@SyncPort(from = "https://github.com/openjdk/jdk/blob/c5e72450966ad50d57a8d22e9d634bfcb319aee9/src/hotspot/cpu/x86/macroAssembler_x86.cpp#L7052-L7086", sha1 = "e68b8c7bdb37d4bd1350c7e1219fdcb419d2618a") -@SyncPort(from = "https://github.com/openjdk/jdk/blob/ce8399fd6071766114f5f201b6e44a7abdba9f5a/src/hotspot/cpu/x86/macroAssembler_x86.cpp#L7390-L7567", +@SyncPort(from = "https://github.com/openjdk/jdk/blob/c5e72450966ad50d57a8d22e9d634bfcb319aee9/src/hotspot/cpu/x86/macroAssembler_x86.cpp#L7304-L7481", sha1 = "d89ad721deb560178359f86e8c6c96ffc6530878") // @formatter:on public final class AMD64BigIntegerMulAddOp extends AMD64LIRInstruction { diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/amd64/AMD64BigIntegerMultiplyToLenOp.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/amd64/AMD64BigIntegerMultiplyToLenOp.java index 28a44acb64f5..6d28398db26c 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/amd64/AMD64BigIntegerMultiplyToLenOp.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/amd64/AMD64BigIntegerMultiplyToLenOp.java @@ -57,9 +57,9 @@ import jdk.vm.ci.meta.Value; // @formatter:off -@SyncPort(from = "https://github.com/openjdk/jdk/blob/ce8399fd6071766114f5f201b6e44a7abdba9f5a/src/hotspot/cpu/x86/stubGenerator_x86_64.cpp#L2949-L3010", +@SyncPort(from = "https://github.com/openjdk/jdk/blob/c5e72450966ad50d57a8d22e9d634bfcb319aee9/src/hotspot/cpu/x86/stubGenerator_x86_64.cpp#L2951-L3012", sha1 = "a4f29fea55385633aac2f71f50d57f9b378516d9") -@SyncPort(from = "https://github.com/openjdk/jdk/blob/ce8399fd6071766114f5f201b6e44a7abdba9f5a/src/hotspot/cpu/x86/macroAssembler_x86.cpp#L6394-L6851", +@SyncPort(from = "https://github.com/openjdk/jdk/blob/c5e72450966ad50d57a8d22e9d634bfcb319aee9/src/hotspot/cpu/x86/macroAssembler_x86.cpp#L6308-L6765", sha1 = "6aac8a818c14df53d6201ac3df0bc35d3aaac9e4") // @formatter:on public final class AMD64BigIntegerMultiplyToLenOp extends AMD64LIRInstruction { diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/amd64/AMD64BigIntegerSquareToLenOp.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/amd64/AMD64BigIntegerSquareToLenOp.java index 37057795d21c..e7f9699ef9a7 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/amd64/AMD64BigIntegerSquareToLenOp.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/amd64/AMD64BigIntegerSquareToLenOp.java @@ -56,9 +56,9 @@ import jdk.vm.ci.meta.Value; // @formatter:off -@SyncPort(from = "https://github.com/openjdk/jdk/blob/ce8399fd6071766114f5f201b6e44a7abdba9f5a/src/hotspot/cpu/x86/stubGenerator_x86_64.cpp#L3064-L3108", +@SyncPort(from = "https://github.com/openjdk/jdk/blob/c5e72450966ad50d57a8d22e9d634bfcb319aee9/src/hotspot/cpu/x86/stubGenerator_x86_64.cpp#L3066-L3110", sha1 = "ab70559cefe0dc177a290d417047955fba3ad1fc") -@SyncPort(from = "https://github.com/openjdk/jdk/blob/ce8399fd6071766114f5f201b6e44a7abdba9f5a/src/hotspot/cpu/x86/macroAssembler_x86.cpp#L7075-L7388", +@SyncPort(from = "https://github.com/openjdk/jdk/blob/c5e72450966ad50d57a8d22e9d634bfcb319aee9/src/hotspot/cpu/x86/macroAssembler_x86.cpp#L6989-L7302", sha1 = "2e4ea1436904cbd5a933eb8c687296d9bbefe4f0") // @formatter:on public final class AMD64BigIntegerSquareToLenOp extends AMD64LIRInstruction { diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/amd64/AMD64BitSwapOp.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/amd64/AMD64BitSwapOp.java index 3d8d01cfc6cd..8c8e25dbc212 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/amd64/AMD64BitSwapOp.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/amd64/AMD64BitSwapOp.java @@ -43,7 +43,7 @@ import jdk.vm.ci.meta.Value; // @formatter:off -@SyncPort(from = "https://github.com/openjdk/jdk/blob/ce8399fd6071766114f5f201b6e44a7abdba9f5a/src/hotspot/cpu/x86/c2_MacroAssembler_x86.cpp#L5798-L5880", +@SyncPort(from = "https://github.com/openjdk/jdk/blob/c5e72450966ad50d57a8d22e9d634bfcb319aee9/src/hotspot/cpu/x86/c2_MacroAssembler_x86.cpp#L5800-L5882", sha1 = "cb807f6ece0a42ba5abae88477e8899436d09a4e") // @formatter:on public final class AMD64BitSwapOp extends AMD64LIRInstruction { diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/amd64/AMD64CountPositivesOp.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/amd64/AMD64CountPositivesOp.java index d4fa8acfda21..bffce3fcfa26 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/amd64/AMD64CountPositivesOp.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/amd64/AMD64CountPositivesOp.java @@ -55,7 +55,7 @@ import jdk.vm.ci.meta.Value; // @formatter:off -@SyncPort(from = "https://github.com/openjdk/jdk/blob/486594d4273e9d5a8db43de861e3ca3ce823f0da/src/hotspot/cpu/x86/c2_MacroAssembler_x86.cpp#L3868-L4138", +@SyncPort(from = "https://github.com/openjdk/jdk/blob/c5e72450966ad50d57a8d22e9d634bfcb319aee9/src/hotspot/cpu/x86/c2_MacroAssembler_x86.cpp#L3870-L4140", sha1 = "684b5353c58bbf92e4403aa985113a78a1f38930") // @formatter:on @Opcode("AMD64_COUNT_POSITIVES") diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/amd64/AMD64EncodeArrayOp.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/amd64/AMD64EncodeArrayOp.java index 7aefa3260b4b..3a27fe0b6fbd 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/amd64/AMD64EncodeArrayOp.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/amd64/AMD64EncodeArrayOp.java @@ -54,7 +54,7 @@ import jdk.vm.ci.meta.Value; // @formatter:off -@SyncPort(from = "https://github.com/openjdk/jdk/blob/ce8399fd6071766114f5f201b6e44a7abdba9f5a/src/hotspot/cpu/x86/macroAssembler_x86.cpp#L6233-L6391", +@SyncPort(from = "https://github.com/openjdk/jdk/blob/c5e72450966ad50d57a8d22e9d634bfcb319aee9/src/hotspot/cpu/x86/macroAssembler_x86.cpp#L6147-L6305", sha1 = "90e15d79705bc87ffbefbcaa4bdfa55123c12aba") // @formatter:on @Opcode("AMD64_ENCODE_ARRAY") diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/amd64/AMD64RoundFloatToIntegerOp.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/amd64/AMD64RoundFloatToIntegerOp.java index 594e423f4fb2..0a405f9cca82 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/amd64/AMD64RoundFloatToIntegerOp.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/amd64/AMD64RoundFloatToIntegerOp.java @@ -46,7 +46,7 @@ * {@link Math#round} algorithm for details. */ // @formatter:off -@SyncPort(from = "https://github.com/openjdk/jdk/blob/ce8399fd6071766114f5f201b6e44a7abdba9f5a/src/hotspot/cpu/x86/macroAssembler_x86.cpp#L9733-L9829", +@SyncPort(from = "https://github.com/openjdk/jdk/blob/c5e72450966ad50d57a8d22e9d634bfcb319aee9/src/hotspot/cpu/x86/macroAssembler_x86.cpp#L9647-L9743", sha1 = "9e13c7375bbb35809ad79ebd6a9cc19e66f57aa1") @SyncPort(from = "https://github.com/openjdk/jdk/blob/ce8399fd6071766114f5f201b6e44a7abdba9f5a/src/hotspot/cpu/x86/stubGenerator_x86_64.cpp#L598-L765", sha1 = "312f16a0551887f78cc567638477bbbcbc3765c5") diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/amd64/AMD64StringUTF16CompressOp.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/amd64/AMD64StringUTF16CompressOp.java index 7db93a43c2b3..ef3497e10251 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/amd64/AMD64StringUTF16CompressOp.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/amd64/AMD64StringUTF16CompressOp.java @@ -59,7 +59,7 @@ import jdk.vm.ci.meta.Value; // @formatter:off -@SyncPort(from = "https://github.com/openjdk/jdk/blob/ce8399fd6071766114f5f201b6e44a7abdba9f5a/src/hotspot/cpu/x86/macroAssembler_x86.cpp#L8647-L8855", +@SyncPort(from = "https://github.com/openjdk/jdk/blob/c5e72450966ad50d57a8d22e9d634bfcb319aee9/src/hotspot/cpu/x86/macroAssembler_x86.cpp#L8561-L8769", sha1 = "3e365037f473204b3f742ab364bd9ad514e72161") // @formatter:on @Opcode("AMD64_STRING_COMPRESS") diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/amd64/AMD64VectorizedHashCodeOp.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/amd64/AMD64VectorizedHashCodeOp.java index 52c9b349db4d..1552c66e5318 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/amd64/AMD64VectorizedHashCodeOp.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/amd64/AMD64VectorizedHashCodeOp.java @@ -75,11 +75,11 @@ import jdk.vm.ci.meta.Value; // @formatter:off -@SyncPort(from = "https://github.com/openjdk/jdk/blob/ce8399fd6071766114f5f201b6e44a7abdba9f5a/src/hotspot/cpu/x86/c2_MacroAssembler_x86.cpp#L1744-L1843", +@SyncPort(from = "https://github.com/openjdk/jdk/blob/c5e72450966ad50d57a8d22e9d634bfcb319aee9/src/hotspot/cpu/x86/c2_MacroAssembler_x86.cpp#L1746-L1845", sha1 = "a93850c44f7e34fcec05226bae95fd695b2ea2f7") -@SyncPort(from = "https://github.com/openjdk/jdk/blob/ce8399fd6071766114f5f201b6e44a7abdba9f5a/src/hotspot/cpu/x86/c2_MacroAssembler_x86.cpp#L1965-L2011", +@SyncPort(from = "https://github.com/openjdk/jdk/blob/c5e72450966ad50d57a8d22e9d634bfcb319aee9/src/hotspot/cpu/x86/c2_MacroAssembler_x86.cpp#L1967-L2013", sha1 = "9cbba8bd6c4037427fa46f067abb722b15aca90c") -@SyncPort(from = "https://github.com/openjdk/jdk/blob/ce8399fd6071766114f5f201b6e44a7abdba9f5a/src/hotspot/cpu/x86/c2_MacroAssembler_x86.cpp#L3283-L3470", +@SyncPort(from = "https://github.com/openjdk/jdk/blob/c5e72450966ad50d57a8d22e9d634bfcb319aee9/src/hotspot/cpu/x86/c2_MacroAssembler_x86.cpp#L3285-L3472", sha1 = "2457cf3f9d3ff89c1515fa5d95cc7c8437a5318b") // @formatter:on @Opcode("VECTORIZED_HASHCODE") diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/amd64/AMD64VectorizedMismatchOp.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/amd64/AMD64VectorizedMismatchOp.java index 1733a56696db..6af46b9ee2e4 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/amd64/AMD64VectorizedMismatchOp.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/amd64/AMD64VectorizedMismatchOp.java @@ -61,7 +61,7 @@ * instructions where possible. */ // @formatter:off -@SyncPort(from = "https://github.com/openjdk/jdk/blob/ce8399fd6071766114f5f201b6e44a7abdba9f5a/src/hotspot/cpu/x86/macroAssembler_x86.cpp#L6853-L7071", +@SyncPort(from = "https://github.com/openjdk/jdk/blob/c5e72450966ad50d57a8d22e9d634bfcb319aee9/src/hotspot/cpu/x86/macroAssembler_x86.cpp#L6767-L6985", sha1 = "72f9b7a60b75ecabf09fc10cb01a9504be97957a") // @formatter:on @Opcode("VECTORIZED_MISMATCH") From a186a559eff5f76a1795dbe94ba5be1b041f9d19 Mon Sep 17 00:00:00 2001 From: Fabio Niephaus Date: Mon, 15 Jan 2024 13:19:10 +0100 Subject: [PATCH 471/593] Add `@SyncPort` to `AMD64LibCHelper`. --- .../com/oracle/svm/core/amd64/AMD64LibCHelper.java | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/amd64/AMD64LibCHelper.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/amd64/AMD64LibCHelper.java index b6cf3d51402d..40e66a67c958 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/amd64/AMD64LibCHelper.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/amd64/AMD64LibCHelper.java @@ -36,6 +36,17 @@ import org.graalvm.nativeimage.c.type.CCharPointer; import org.graalvm.word.PointerBase; +import jdk.graal.compiler.lir.SyncPort; + +// @formatter:off +@SyncPort(from = "https://github.com/openjdk/jdk/blob/34f85ee94e8b45bcebbf8ba52a38c92a7185b54a/src/hotspot/cpu/x86/vm_version_x86.hpp#L40-L304", + sha1 = "5cc04c08555379223cc02a15774159076d3cdf1d") +/* + * To be kept in sync with: + * - substratevm/src/com.oracle.svm.native.libchelper/include/amd64hotspotcpuinfo.h + * - substratevm/src/com.oracle.svm.native.libchelper/src/cpuid.c + */ +// @formatter:on @CLibrary(value = "libchelper", requireStatic = true) public class AMD64LibCHelper { @Platforms(Platform.AMD64.class) From 58d9e1ba464bed017e64863eb71d7b155040bf59 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Paul=20W=C3=B6gerer?= Date: Mon, 15 Jan 2024 18:16:56 +0100 Subject: [PATCH 472/593] Explain reasoning as comment --- .../src/com/oracle/svm/driver/NativeImage.java | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/substratevm/src/com.oracle.svm.driver/src/com/oracle/svm/driver/NativeImage.java b/substratevm/src/com.oracle.svm.driver/src/com/oracle/svm/driver/NativeImage.java index 23f204a2bbcd..e8f20a52df2d 100644 --- a/substratevm/src/com.oracle.svm.driver/src/com/oracle/svm/driver/NativeImage.java +++ b/substratevm/src/com.oracle.svm.driver/src/com/oracle/svm/driver/NativeImage.java @@ -1226,6 +1226,11 @@ private int completeImageBuild() { imageNamePathParent = imagePath.resolve(imageNamePathParent); } if (!useBundle()) { + /* + * In bundle-mode the value of imagePath is purely virtual before it gets + * substituted by substituteImagePath(imagePath) below. Validating the virtual value + * would make no sense (and cause errors if the path does not exist anymore) + */ if (!Files.isDirectory(imageNamePathParent)) { throw NativeImage.showError("Writing image to non-existent directory " + imageNamePathParent + " is not allowed. " + "Create the missing directory if you want the image to be written to that location."); From 00813e90aa5331667086ed9b789b46a80cc57b37 Mon Sep 17 00:00:00 2001 From: Peter Hofer Date: Mon, 8 Jan 2024 18:30:49 +0100 Subject: [PATCH 473/593] Support multiple image heaps at runtime. --- .../oracle/svm/core/genscavenge/GCImpl.java | 10 ++- .../oracle/svm/core/genscavenge/HeapImpl.java | 89 ++++++++++++------- .../svm/core/genscavenge/HeapVerifier.java | 14 +-- .../svm/core/genscavenge/ImageHeapInfo.java | 7 ++ .../graal/GenScavengeGCFeature.java | 4 +- 5 files changed, 79 insertions(+), 45 deletions(-) diff --git a/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/GCImpl.java b/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/GCImpl.java index 82d65d75e344..610ab4450a60 100644 --- a/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/GCImpl.java +++ b/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/GCImpl.java @@ -912,8 +912,9 @@ private void blackenDirtyImageHeapRoots() { Timer blackenImageHeapRootsTimer = timers.blackenImageHeapRoots.open(); try { - ImageHeapInfo info = HeapImpl.getImageHeapInfo(); - blackenDirtyImageHeapChunkRoots(info.getFirstWritableAlignedChunk(), info.getFirstWritableUnalignedChunk()); + for (ImageHeapInfo info = HeapImpl.getFirstImageHeapInfo(); info != null; info = info.next) { + blackenDirtyImageHeapChunkRoots(info.getFirstWritableAlignedChunk(), info.getFirstWritableUnalignedChunk()); + } if (AuxiliaryImageHeap.isPresent()) { ImageHeapInfo auxInfo = AuxiliaryImageHeap.singleton().getImageHeapInfo(); @@ -959,7 +960,10 @@ private void blackenImageHeapRoots() { Timer blackenImageHeapRootsTimer = timers.blackenImageHeapRoots.open(); try { - blackenImageHeapRoots(HeapImpl.getImageHeapInfo()); + for (ImageHeapInfo info = HeapImpl.getFirstImageHeapInfo(); info != null; info = info.next) { + blackenImageHeapRoots(info); + } + if (AuxiliaryImageHeap.isPresent()) { ImageHeapInfo auxImageHeapInfo = AuxiliaryImageHeap.singleton().getImageHeapInfo(); if (auxImageHeapInfo != null) { diff --git a/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/HeapImpl.java b/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/HeapImpl.java index 21cbe165518b..47b8f9d1d702 100644 --- a/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/HeapImpl.java +++ b/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/HeapImpl.java @@ -108,7 +108,7 @@ public final class HeapImpl extends Heap { private final ObjectHeaderImpl objectHeaderImpl = new ObjectHeaderImpl(); private final GCImpl gcImpl; private final RuntimeCodeInfoGCSupportImpl runtimeCodeInfoGcSupport; - private final ImageHeapInfo imageHeapInfo = new ImageHeapInfo(); + private final ImageHeapInfo firstImageHeapInfo = new ImageHeapInfo(); private final HeapAccounting accounting = new HeapAccounting(); /** Head of the linked list of currently pending (ready to be enqueued) {@link Reference}s. */ @@ -143,8 +143,8 @@ public static HeapImpl getHeapImpl() { } @Fold - public static ImageHeapInfo getImageHeapInfo() { - return getHeapImpl().imageHeapInfo; + public static ImageHeapInfo getFirstImageHeapInfo() { + return getHeapImpl().firstImageHeapInfo; } @Fold @@ -179,7 +179,12 @@ public boolean isInPrimaryImageHeap(Object obj) { @Override @Uninterruptible(reason = "Called from uninterruptible code.", mayBeInlined = true) public boolean isInPrimaryImageHeap(Pointer objPointer) { - return imageHeapInfo.isInImageHeap(objPointer); + for (ImageHeapInfo info = firstImageHeapInfo; info != null; info = info.next) { + if (info.isInImageHeap(objPointer)) { + return true; + } + } + return false; } @Override @@ -283,7 +288,9 @@ void logChunks(Log log) { void logImageHeapPartitionBoundaries(Log log) { log.string("Native image heap boundaries:").indent(true); - imageHeapInfo.print(log); + for (ImageHeapInfo info = firstImageHeapInfo; info != null; info = info.next) { + info.print(log); + } log.indent(false); if (AuxiliaryImageHeap.isPresent()) { @@ -326,7 +333,11 @@ static void logZapValues(Log log) { @Override @Uninterruptible(reason = "Called from uninterruptible code.", mayBeInlined = true) public int getClassCount() { - return imageHeapInfo.dynamicHubCount; + int count = firstImageHeapInfo.dynamicHubCount; + for (ImageHeapInfo info = firstImageHeapInfo.next; info != null; info = info.next) { + count += info.dynamicHubCount; + } + return count; } @Override @@ -334,14 +345,16 @@ protected List> getAllClasses() { /* Two threads might race to set classList, but they compute the same result. */ if (classList == null) { ArrayList> list = new ArrayList<>(1024); - ImageHeapWalker.walkRegions(imageHeapInfo, new ClassListBuilderVisitor(list)); + for (ImageHeapInfo info = firstImageHeapInfo; info != null; info = info.next) { + ImageHeapWalker.walkRegions(info, new ClassListBuilderVisitor(list)); + } list.trimToSize(); /* Ensure that other threads see consistent values once the list is published. */ MembarNode.memoryBarrier(MembarNode.FenceKind.STORE_STORE); classList = list; } - assert classList.size() == imageHeapInfo.dynamicHubCount; + assert classList.size() == getClassCount(); return classList; } @@ -429,11 +442,15 @@ public int getImageHeapOffsetInAddressSpace() { @Override public boolean walkImageHeapObjects(ObjectVisitor visitor) { VMOperation.guaranteeInProgressAtSafepoint("Must only be called at a safepoint"); - if (visitor != null) { - return ImageHeapWalker.walkImageHeapObjects(imageHeapInfo, visitor) && - (!AuxiliaryImageHeap.isPresent() || AuxiliaryImageHeap.singleton().walkObjects(visitor)); + if (visitor == null) { + return true; } - return true; + for (ImageHeapInfo info = firstImageHeapInfo; info != null; info = info.next) { + if (!ImageHeapWalker.walkImageHeapObjects(info, visitor)) { + return false; + } + } + return !AuxiliaryImageHeap.isPresent() || AuxiliaryImageHeap.singleton().walkObjects(visitor); } @Override @@ -694,28 +711,32 @@ static Pointer getImageHeapStart() { } private boolean printLocationInfo(Log log, Pointer ptr, boolean allowJavaHeapAccess, boolean allowUnsafeOperations) { - if (imageHeapInfo.isInReadOnlyPrimitivePartition(ptr)) { - log.string("points into the image heap (read-only primitives)"); - return true; - } else if (imageHeapInfo.isInReadOnlyReferencePartition(ptr)) { - log.string("points into the image heap (read-only references)"); - return true; - } else if (imageHeapInfo.isInReadOnlyRelocatablePartition(ptr)) { - log.string("points into the image heap (read-only relocatables)"); - return true; - } else if (imageHeapInfo.isInWritablePrimitivePartition(ptr)) { - log.string("points into the image heap (writable primitives)"); - return true; - } else if (imageHeapInfo.isInWritableReferencePartition(ptr)) { - log.string("points into the image heap (writable references)"); - return true; - } else if (imageHeapInfo.isInWritableHugePartition(ptr)) { - log.string("points into the image heap (writable huge)"); - return true; - } else if (imageHeapInfo.isInReadOnlyHugePartition(ptr)) { - log.string("points into the image heap (read-only huge)"); - return true; - } else if (AuxiliaryImageHeap.isPresent() && AuxiliaryImageHeap.singleton().containsObject(ptr)) { + for (ImageHeapInfo info = firstImageHeapInfo; info != null; info = info.next) { + if (info.isInReadOnlyPrimitivePartition(ptr)) { + log.string("points into the image heap (read-only primitives)"); + return true; + } else if (info.isInReadOnlyReferencePartition(ptr)) { + log.string("points into the image heap (read-only references)"); + return true; + } else if (info.isInReadOnlyRelocatablePartition(ptr)) { + log.string("points into the image heap (read-only relocatables)"); + return true; + } else if (info.isInWritablePrimitivePartition(ptr)) { + log.string("points into the image heap (writable primitives)"); + return true; + } else if (info.isInWritableReferencePartition(ptr)) { + log.string("points into the image heap (writable references)"); + return true; + } else if (info.isInWritableHugePartition(ptr)) { + log.string("points into the image heap (writable huge)"); + return true; + } else if (info.isInReadOnlyHugePartition(ptr)) { + log.string("points into the image heap (read-only huge)"); + return true; + } + } + + if (AuxiliaryImageHeap.isPresent() && AuxiliaryImageHeap.singleton().containsObject(ptr)) { log.string("points into the auxiliary image heap"); return true; } else if (printTlabInfo(log, ptr, CurrentIsolate.getCurrentThread())) { diff --git a/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/HeapVerifier.java b/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/HeapVerifier.java index 6e098e8497fe..dfc0a53d55e3 100644 --- a/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/HeapVerifier.java +++ b/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/HeapVerifier.java @@ -68,9 +68,10 @@ public static boolean verify(Occasion occasion) { private static boolean verifyImageHeap() { boolean success = true; - ImageHeapInfo info = HeapImpl.getImageHeapInfo(); - success &= verifyAlignedChunks(null, info.getFirstWritableAlignedChunk()); - success &= verifyUnalignedChunks(null, info.getFirstWritableUnalignedChunk()); + for (ImageHeapInfo info = HeapImpl.getFirstImageHeapInfo(); info != null; info = info.next) { + success &= verifyAlignedChunks(null, info.getFirstWritableAlignedChunk()); + success &= verifyUnalignedChunks(null, info.getFirstWritableUnalignedChunk()); + } return success; } @@ -145,9 +146,10 @@ private static boolean verifyRememberedSets() { * For the image heap, we can't verify that all cards are clean after a GC because the GC * itself may result in dirty cards. */ - ImageHeapInfo info = HeapImpl.getImageHeapInfo(); - success &= rememberedSet.verify(info.getFirstWritableAlignedChunk()); - success &= rememberedSet.verify(info.getFirstWritableUnalignedChunk()); + for (ImageHeapInfo info = HeapImpl.getFirstImageHeapInfo(); info != null; info = info.next) { + success &= rememberedSet.verify(info.getFirstWritableAlignedChunk()); + success &= rememberedSet.verify(info.getFirstWritableUnalignedChunk()); + } OldGeneration oldGeneration = HeapImpl.getHeapImpl().getOldGeneration(); Space toSpace = oldGeneration.getToSpace(); diff --git a/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/ImageHeapInfo.java b/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/ImageHeapInfo.java index 637b534b64d9..9526b250500f 100644 --- a/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/ImageHeapInfo.java +++ b/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/ImageHeapInfo.java @@ -79,7 +79,14 @@ public final class ImageHeapInfo { @UnknownPrimitiveField(availability = AfterHeapLayout.class) public int dynamicHubCount; + public final ImageHeapInfo next; + public ImageHeapInfo() { + this(null); + } + + public ImageHeapInfo(ImageHeapInfo next) { + this.next = next; } @SuppressWarnings("hiding") diff --git a/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/graal/GenScavengeGCFeature.java b/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/graal/GenScavengeGCFeature.java index a5a1cc983c51..780dc3dbfa96 100644 --- a/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/graal/GenScavengeGCFeature.java +++ b/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/graal/GenScavengeGCFeature.java @@ -142,13 +142,13 @@ public void beforeAnalysis(BeforeAnalysisAccess access) { @Override public void afterAnalysis(AfterAnalysisAccess access) { - ImageHeapLayouter heapLayouter = new ChunkedImageHeapLayouter(HeapImpl.getImageHeapInfo(), 0); + ImageHeapLayouter heapLayouter = new ChunkedImageHeapLayouter(HeapImpl.getFirstImageHeapInfo(), 0); ImageSingletons.add(ImageHeapLayouter.class, heapLayouter); } @Override public void beforeCompilation(BeforeCompilationAccess access) { - ImageHeapInfo imageHeapInfo = HeapImpl.getImageHeapInfo(); + ImageHeapInfo imageHeapInfo = HeapImpl.getFirstImageHeapInfo(); access.registerAsImmutable(imageHeapInfo); } From 46f86b830087e78e2c47a108ec0a60d48e440d9b Mon Sep 17 00:00:00 2001 From: Peter Hofer Date: Mon, 8 Jan 2024 18:39:54 +0100 Subject: [PATCH 474/593] Make NativeImageHeapWriter aware of the start offset used by ImageHeapLayouter. --- .../genscavenge/ChunkedImageHeapLayouter.java | 5 +++ .../svm/core/image/ImageHeapLayouter.java | 8 +++++ .../hosted/image/NativeImageHeapWriter.java | 35 ++++++++++--------- 3 files changed, 32 insertions(+), 16 deletions(-) diff --git a/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/ChunkedImageHeapLayouter.java b/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/ChunkedImageHeapLayouter.java index 2f249e9f0fbc..b812cbb1dd28 100644 --- a/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/ChunkedImageHeapLayouter.java +++ b/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/ChunkedImageHeapLayouter.java @@ -107,6 +107,11 @@ public ChunkedImageHeapLayouter(ImageHeapInfo heapInfo, long startOffset) { this.hugeObjectThreshold = hugeThreshold.rawValue(); } + @Override + public long getStartOffset() { + return startOffset; + } + @Override public ChunkedImageHeapPartition[] getPartitions() { return partitions; diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/image/ImageHeapLayouter.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/image/ImageHeapLayouter.java index cd6a55a21b12..038f950b2404 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/image/ImageHeapLayouter.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/image/ImageHeapLayouter.java @@ -26,12 +26,20 @@ import java.nio.ByteBuffer; +import com.oracle.svm.core.heap.Heap; + /** * This class is responsible for computing and storing the layout of the native image heap. A native * image heap consist of multiple {@link ImageHeapPartition}s. Every object in the native image heap * is assigned to a position within a {@link ImageHeapPartition}. */ public interface ImageHeapLayouter { + /** + * The offset of this image heap relative to the start of the first image heap (which itself is + * not the same as the heap base, see {@link Heap#getImageHeapOffsetInAddressSpace}). + */ + long getStartOffset(); + /** * Returns all native image heap partitions. */ diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/NativeImageHeapWriter.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/NativeImageHeapWriter.java index aa9fdc11e037..b09c6891095c 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/NativeImageHeapWriter.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/NativeImageHeapWriter.java @@ -142,7 +142,7 @@ private static void verifyTargetDidNotChange(Object target, Object reason, Objec } private void writeField(RelocatableBuffer buffer, ObjectInfo fields, HostedField field, JavaConstant receiver, ObjectInfo info) { - int index = fields.getIndexInBuffer(field.getLocation()); + int index = getIndexInBuffer(fields, field.getLocation()); JavaConstant value; try { value = heap.hConstantReflection.readFieldValue(field, receiver); @@ -326,10 +326,9 @@ private void writeObject(ObjectInfo info, RelocatableBuffer buffer) { */ ObjectLayout objectLayout = heap.objectLayout; DynamicHubLayout dynamicHubLayout = heap.dynamicHubLayout; - final int indexInBuffer = info.getIndexInBuffer(objectLayout.getHubOffset()); - assert objectLayout.isAligned(indexInBuffer); + assert objectLayout.isAligned(getIndexInBuffer(info, 0)); - writeObjectHeader(buffer, indexInBuffer, info); + writeObjectHeader(buffer, getIndexInBuffer(info, objectLayout.getHubOffset()), info); ByteBuffer bufferBytes = buffer.getByteBuffer(); HostedClass clazz = info.getClazz(); @@ -354,7 +353,7 @@ private void writeObject(ObjectInfo info, RelocatableBuffer buffer) { short[] typeIDSlots = (short[]) heap.readInlinedField(dynamicHubLayout.typeIDSlotsField, con); int typeIDSlotsLength = typeIDSlots.length; for (int i = 0; i < typeIDSlotsLength; i++) { - int index = info.getIndexInBuffer(dynamicHubLayout.getTypeIDSlotsOffset(i)); + int index = getIndexInBuffer(info, dynamicHubLayout.getTypeIDSlotsOffset(i)); short value = typeIDSlots[i]; bufferBytes.putShort(index, value); } @@ -362,11 +361,11 @@ private void writeObject(ObjectInfo info, RelocatableBuffer buffer) { /* Write vtable slots and length. */ Object vTable = heap.readInlinedField(dynamicHubLayout.vTableField, con); int vtableLength = Array.getLength(vTable); - bufferBytes.putInt(info.getIndexInBuffer(dynamicHubLayout.getVTableLengthOffset()), vtableLength); + bufferBytes.putInt(getIndexInBuffer(info, dynamicHubLayout.getVTableLengthOffset()), vtableLength); final JavaKind elementStorageKind = dynamicHubLayout.getVTableSlotStorageKind(); for (int i = 0; i < vtableLength; i++) { Object vtableSlot = Array.get(vTable, i); - int elementIndex = info.getIndexInBuffer(dynamicHubLayout.getVTableSlotOffset(i)); + int elementIndex = getIndexInBuffer(info, dynamicHubLayout.getVTableSlotOffset(i)); writeConstant(buffer, elementIndex, elementStorageKind, vtableSlot, info); } @@ -381,9 +380,9 @@ private void writeObject(ObjectInfo info, RelocatableBuffer buffer) { HostedField hybridArrayField = hybridLayout.getArrayField(); Object hybridArray = heap.readInlinedField(hybridArrayField, con); int length = Array.getLength(hybridArray); - bufferBytes.putInt(info.getIndexInBuffer(objectLayout.getArrayLengthOffset()), length); + bufferBytes.putInt(getIndexInBuffer(info, objectLayout.getArrayLengthOffset()), length); for (int i = 0; i < length; i++) { - final int elementIndex = info.getIndexInBuffer(hybridLayout.getArrayElementOffset(i)); + final int elementIndex = getIndexInBuffer(info, hybridLayout.getArrayElementOffset(i)); final JavaKind elementStorageKind = hybridLayout.getArrayElementStorageKind(); final Object array = Array.get(hybridArray, i); writeConstant(buffer, elementIndex, elementStorageKind, array, info); @@ -409,7 +408,7 @@ private void writeObject(ObjectInfo info, RelocatableBuffer buffer) { /* Write the identity hashcode */ assert idHashOffset > 0; - bufferBytes.putInt(info.getIndexInBuffer(idHashOffset), info.getIdentityHashCode()); + bufferBytes.putInt(getIndexInBuffer(info, idHashOffset), info.getIdentityHashCode()); } else if (clazz.isArray()) { @@ -417,8 +416,8 @@ private void writeObject(ObjectInfo info, RelocatableBuffer buffer) { JavaConstant constant = info.getConstant(); int length = heap.hConstantReflection.readArrayLength(constant); - bufferBytes.putInt(info.getIndexInBuffer(objectLayout.getArrayLengthOffset()), length); - bufferBytes.putInt(info.getIndexInBuffer(objectLayout.getArrayIdentityHashOffset(kind, length)), info.getIdentityHashCode()); + bufferBytes.putInt(getIndexInBuffer(info, objectLayout.getArrayLengthOffset()), length); + bufferBytes.putInt(getIndexInBuffer(info, objectLayout.getArrayIdentityHashOffset(kind, length)), info.getIdentityHashCode()); if (constant instanceof ImageHeapConstant) { if (clazz.getComponentType().isPrimitive()) { @@ -426,7 +425,7 @@ private void writeObject(ObjectInfo info, RelocatableBuffer buffer) { writePrimitiveArray(info, buffer, objectLayout, kind, imageHeapArray.getArray(), length); } else { heap.hConstantReflection.forEachArrayElement(constant, (element, index) -> { - final int elementIndex = info.getIndexInBuffer(objectLayout.getArrayElementOffset(kind, index)); + final int elementIndex = getIndexInBuffer(info, objectLayout.getArrayElementOffset(kind, index)); writeConstant(buffer, elementIndex, kind, element, info); }); } @@ -436,7 +435,7 @@ private void writeObject(ObjectInfo info, RelocatableBuffer buffer) { Object[] oarray = (Object[]) array; assert oarray.length == length; for (int i = 0; i < length; i++) { - final int elementIndex = info.getIndexInBuffer(objectLayout.getArrayElementOffset(kind, i)); + final int elementIndex = getIndexInBuffer(info, objectLayout.getArrayElementOffset(kind, i)); Object element = maybeReplace(oarray[i], info); assert (oarray[i] instanceof RelocatedPointer) == (element instanceof RelocatedPointer); writeConstant(buffer, elementIndex, kind, element, info); @@ -450,8 +449,12 @@ private void writeObject(ObjectInfo info, RelocatableBuffer buffer) { } } - private static void writePrimitiveArray(ObjectInfo info, RelocatableBuffer buffer, ObjectLayout objectLayout, JavaKind kind, Object array, int length) { - int elementIndex = info.getIndexInBuffer(objectLayout.getArrayElementOffset(kind, 0)); + private int getIndexInBuffer(ObjectInfo info, long offset) { + return info.getIndexInBuffer(offset - heap.getLayouter().getStartOffset()); + } + + private void writePrimitiveArray(ObjectInfo info, RelocatableBuffer buffer, ObjectLayout objectLayout, JavaKind kind, Object array, int length) { + int elementIndex = getIndexInBuffer(info, objectLayout.getArrayElementOffset(kind, 0)); int elementTypeSize = Unsafe.getUnsafe().arrayIndexScale(array.getClass()); assert elementTypeSize == kind.getByteCount(); Unsafe.getUnsafe().copyMemory(array, Unsafe.getUnsafe().arrayBaseOffset(array.getClass()), buffer.getBackingArray(), From dc9e68fd8b66e7edcb3778e5ce1b94c583fae4ce Mon Sep 17 00:00:00 2001 From: Peter Hofer Date: Mon, 8 Jan 2024 18:41:03 +0100 Subject: [PATCH 475/593] Correctly generate exported symbols list when there are no global symbols. --- .../oracle/svm/hosted/image/CCLinkerInvocation.java | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/CCLinkerInvocation.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/CCLinkerInvocation.java index 4972c17a268b..38a6cdc24562 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/CCLinkerInvocation.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/CCLinkerInvocation.java @@ -36,8 +36,6 @@ import java.util.stream.Collectors; import java.util.stream.Stream; -import jdk.graal.compiler.options.Option; -import jdk.graal.compiler.options.OptionStability; import org.graalvm.nativeimage.ImageSingletons; import org.graalvm.nativeimage.Platform; @@ -58,6 +56,9 @@ import com.oracle.svm.hosted.c.libc.HostedLibCBase; import com.oracle.svm.hosted.jdk.JNIRegistrationSupport; +import jdk.graal.compiler.options.Option; +import jdk.graal.compiler.options.OptionStability; + public abstract class CCLinkerInvocation implements LinkerInvocation { protected CCLinkerInvocation(AbstractImage.NativeImageKind imageKind, NativeLibraries nativeLibs, List imageSymbols) { @@ -279,9 +280,11 @@ private static class BinutilsCCLinkerInvocation extends CCLinkerInvocation { StringBuilder exportedSymbols = new StringBuilder(); exportedSymbols.append("{\n"); /* Only exported symbols are global ... */ - exportedSymbols.append("global:\n"); - Stream.concat(getImageSymbols(true).stream(), JNIRegistrationSupport.getShimLibrarySymbols()) - .forEach(symbol -> exportedSymbols.append('\"').append(symbol).append("\";\n")); + Set globalSymbols = Stream.concat(getImageSymbols(true).stream(), JNIRegistrationSupport.getShimLibrarySymbols()).collect(Collectors.toSet()); + if (!globalSymbols.isEmpty()) { + exportedSymbols.append("global:\n"); + globalSymbols.forEach(symbol -> exportedSymbols.append('\"').append(symbol).append("\";\n")); + } /* ... everything else is local. */ exportedSymbols.append("local: *;\n"); exportedSymbols.append("};"); From a30f385e430580fff5511937c78154fed9c96ab9 Mon Sep 17 00:00:00 2001 From: Peter Hofer Date: Tue, 19 Dec 2023 16:52:33 +0100 Subject: [PATCH 476/593] Refactor LinuxImageHeapProvider so it can be extended to load more than one image heap. --- .../posix/linux/LinuxImageHeapProvider.java | 359 ++++++++++-------- .../core/os/AbstractImageHeapProvider.java | 11 +- 2 files changed, 202 insertions(+), 168 deletions(-) diff --git a/substratevm/src/com.oracle.svm.core.posix/src/com/oracle/svm/core/posix/linux/LinuxImageHeapProvider.java b/substratevm/src/com.oracle.svm.core.posix/src/com/oracle/svm/core/posix/linux/LinuxImageHeapProvider.java index 21101ca87597..5546d1f963ee 100644 --- a/substratevm/src/com.oracle.svm.core.posix/src/com/oracle/svm/core/posix/linux/LinuxImageHeapProvider.java +++ b/substratevm/src/com.oracle.svm.core.posix/src/com/oracle/svm/core/posix/linux/LinuxImageHeapProvider.java @@ -32,8 +32,8 @@ import static com.oracle.svm.core.Isolates.IMAGE_HEAP_WRITABLE_BEGIN; import static com.oracle.svm.core.Isolates.IMAGE_HEAP_WRITABLE_END; import static com.oracle.svm.core.posix.linux.ProcFSSupport.findMapping; -import static com.oracle.svm.core.util.PointerUtils.roundUp; import static com.oracle.svm.core.util.UnsignedUtils.isAMultiple; +import static com.oracle.svm.core.util.UnsignedUtils.roundUp; import static org.graalvm.word.WordFactory.signed; import java.util.concurrent.ThreadLocalRandom; @@ -42,6 +42,7 @@ import org.graalvm.nativeimage.c.type.CCharPointer; import org.graalvm.nativeimage.c.type.WordPointer; import org.graalvm.word.ComparableWord; +import org.graalvm.word.LocationIdentity; import org.graalvm.word.Pointer; import org.graalvm.word.PointerBase; import org.graalvm.word.SignedWord; @@ -57,14 +58,13 @@ import com.oracle.svm.core.headers.LibC; import com.oracle.svm.core.heap.Heap; import com.oracle.svm.core.os.AbstractImageHeapProvider; -import com.oracle.svm.core.os.CopyingImageHeapProvider; import com.oracle.svm.core.os.VirtualMemoryProvider; import com.oracle.svm.core.os.VirtualMemoryProvider.Access; import com.oracle.svm.core.posix.PosixUtils; import com.oracle.svm.core.posix.headers.Fcntl; import com.oracle.svm.core.posix.headers.Unistd; +import com.oracle.svm.core.util.VMError; -import jdk.graal.compiler.nodes.NamedLocationIdentity; import jdk.graal.compiler.word.Word; /** @@ -92,27 +92,102 @@ public class LinuxImageHeapProvider extends AbstractImageHeapProvider { private static final CGlobalData CACHED_IMAGE_FD = CGlobalDataFactory.createWord(UNASSIGNED_FD); private static final CGlobalData CACHED_IMAGE_HEAP_OFFSET = CGlobalDataFactory.createWord(); - private static final int MAX_PATHLEN = 4096; - - private static final CopyingImageHeapProvider fallbackCopyingProvider = new CopyingImageHeapProvider(); - @Override public boolean guaranteesHeapPreferredAddressSpaceAlignment() { return true; } + @Override + @Uninterruptible(reason = "Called from uninterruptible code.", mayBeInlined = true) + protected UnsignedWord getImageHeapAddressSpaceSize() { + int imageHeapOffset = Heap.getHeap().getImageHeapOffsetInAddressSpace(); + assert imageHeapOffset >= 0; + UnsignedWord size = WordFactory.unsigned(imageHeapOffset); + size = size.add(getImageHeapSizeInFile(IMAGE_HEAP_BEGIN.get(), IMAGE_HEAP_END.get())); + return size; + } + + @Uninterruptible(reason = "Called from uninterruptible code.", mayBeInlined = true) + protected UnsignedWord getTotalRequiredAddressSpaceSize() { + UnsignedWord size = getImageHeapAddressSpaceSize(); + if (DynamicMethodAddressResolutionHeapSupport.isEnabled()) { + size = size.add(DynamicMethodAddressResolutionHeapSupport.get().getDynamicMethodAddressResolverPreHeapMemoryBytes()); + } + return size; + } + @Override @Uninterruptible(reason = "Called during isolate initialization.") public int initialize(Pointer reservedAddressSpace, UnsignedWord reservedSize, WordPointer basePointer, WordPointer endPointer) { + Pointer heapBase; + Pointer allocatedMemory = WordFactory.nullPointer(); + UnsignedWord requiredSize = getTotalRequiredAddressSpaceSize(); + if (reservedAddressSpace.isNull()) { + UnsignedWord alignment = WordFactory.unsigned(Heap.getHeap().getPreferredAddressSpaceAlignment()); + allocatedMemory = VirtualMemoryProvider.get().reserve(requiredSize, alignment, false); + if (allocatedMemory.isNull()) { + return CEntryPointErrors.RESERVE_ADDRESS_SPACE_FAILED; + } + heapBase = allocatedMemory; + } else { + if (reservedSize.belowThan(requiredSize)) { + return CEntryPointErrors.INSUFFICIENT_ADDRESS_SPACE; + } + heapBase = reservedAddressSpace; + } + UnsignedWord remainingSize = requiredSize; + + if (DynamicMethodAddressResolutionHeapSupport.isEnabled()) { + int error = DynamicMethodAddressResolutionHeapSupport.get().initialize(); + if (error != CEntryPointErrors.NO_ERROR) { + freeImageHeap(allocatedMemory); + return error; + } + + UnsignedWord preHeapRequiredBytes = DynamicMethodAddressResolutionHeapSupport.get().getDynamicMethodAddressResolverPreHeapMemoryBytes(); + heapBase = heapBase.add(preHeapRequiredBytes); + remainingSize = remainingSize.subtract(preHeapRequiredBytes); + + Pointer installOffset = heapBase.subtract(DynamicMethodAddressResolutionHeapSupport.get().getRequiredPreHeapMemoryInBytes()); + error = DynamicMethodAddressResolutionHeapSupport.get().install(installOffset); + if (error != CEntryPointErrors.NO_ERROR) { + freeImageHeap(allocatedMemory); + return error; + } + } + + int imageHeapOffsetInAddressSpace = Heap.getHeap().getImageHeapOffsetInAddressSpace(); + basePointer.write(heapBase); + Pointer firstBase = heapBase.add(imageHeapOffsetInAddressSpace); + remainingSize = remainingSize.subtract(imageHeapOffsetInAddressSpace); + int result = initializeImageHeap(firstBase, remainingSize, endPointer, + CACHED_IMAGE_FD.get(), CACHED_IMAGE_HEAP_OFFSET.get(), MAGIC.get(), + IMAGE_HEAP_BEGIN.get(), IMAGE_HEAP_END.get(), + IMAGE_HEAP_RELOCATABLE_BEGIN.get(), IMAGE_HEAP_A_RELOCATABLE_POINTER.get(), IMAGE_HEAP_RELOCATABLE_END.get(), + IMAGE_HEAP_WRITABLE_BEGIN.get(), IMAGE_HEAP_WRITABLE_END.get()); + if (result != CEntryPointErrors.NO_ERROR) { + freeImageHeap(allocatedMemory); + } + return result; + } + + @Uninterruptible(reason = "Called during isolate initialization.") + private int initializeImageHeap(Pointer imageHeap, UnsignedWord reservedSize, WordPointer endPointer, WordPointer cachedFd, WordPointer cachedOffset, + Pointer magicAddress, Word heapBeginSym, Word heapEndSym, Word heapRelocsSym, Pointer heapAnyRelocPointer, Word heapRelocsEndSym, Word heapWritableSym, Word heapWritableEndSym) { + assert heapBeginSym.belowOrEqual(heapWritableSym) && heapWritableSym.belowOrEqual(heapWritableEndSym) && heapWritableEndSym.belowOrEqual(heapEndSym); + assert heapBeginSym.belowOrEqual(heapRelocsSym) && heapRelocsSym.belowOrEqual(heapRelocsEndSym) && heapRelocsEndSym.belowOrEqual(heapEndSym); + assert heapAnyRelocPointer.isNull() || (heapRelocsSym.belowOrEqual(heapAnyRelocPointer) && heapAnyRelocPointer.belowThan(heapRelocsEndSym)); + + SignedWord fd = cachedFd.read(); + /* * Find and open the image file. We cache the file descriptor and the determined offset in * the file for subsequent isolate initializations. We intentionally allow racing in this * step to avoid stalling threads. */ - SignedWord fd = CACHED_IMAGE_FD.get().read(); if (fd.equal(UNASSIGNED_FD)) { - int opened = openImageFile(); - SignedWord previous = ((Pointer) CACHED_IMAGE_FD.get()).compareAndSwapWord(0, fd, signed(opened), NamedLocationIdentity.OFF_HEAP_LOCATION); + int opened = openImageFile(cachedOffset, heapBeginSym, heapRelocsSym, magicAddress); + SignedWord previous = ((Pointer) cachedFd).compareAndSwapWord(0, fd, signed(opened), LocationIdentity.ANY_LOCATION); if (previous.equal(fd)) { fd = signed(opened); } else { @@ -123,108 +198,78 @@ public int initialize(Pointer reservedAddressSpace, UnsignedWord reservedSize, W } } + UnsignedWord pageSize = VirtualMemoryProvider.get().getGranularity(); + UnsignedWord imageHeapSize = getImageHeapSizeInFile(heapBeginSym, heapEndSym); + assert reservedSize.aboveOrEqual(imageHeapSize); + if (endPointer.isNonNull()) { + endPointer.write(roundUp(imageHeap.add(imageHeapSize), pageSize)); + } + /* * If we cannot find or open the image file, fall back to copy it from memory (the image * heap must be in pristine condition for that). */ if (fd.equal(CANNOT_OPEN_FD)) { - return fallbackCopyingProvider.initialize(reservedAddressSpace, reservedSize, basePointer, endPointer); - } - - boolean haveDynamicMethodResolution = DynamicMethodAddressResolutionHeapSupport.isEnabled(); - if (haveDynamicMethodResolution) { - int res = DynamicMethodAddressResolutionHeapSupport.get().initialize(); - if (res != CEntryPointErrors.NO_ERROR) { - return res; - } - } - - UnsignedWord pageSize = VirtualMemoryProvider.get().getGranularity(); - UnsignedWord imageHeapSizeInFile = getImageHeapSizeInFile(); - - UnsignedWord preHeapRequiredBytes = WordFactory.zero(); - if (haveDynamicMethodResolution) { - preHeapRequiredBytes = DynamicMethodAddressResolutionHeapSupport.get().getDynamicMethodAddressResolverPreHeapMemoryBytes(); - } - - // Reserve an address space for the image heap if necessary. - UnsignedWord imageHeapAddressSpaceSize = getImageHeapAddressSpaceSize(); - UnsignedWord totalAddressSpaceSize = imageHeapAddressSpaceSize.add(preHeapRequiredBytes); - - Pointer heapBase; - Pointer allocatedMemory = WordFactory.nullPointer(); - if (reservedAddressSpace.isNull()) { - UnsignedWord alignment = WordFactory.unsigned(Heap.getHeap().getPreferredAddressSpaceAlignment()); - heapBase = allocatedMemory = VirtualMemoryProvider.get().reserve(totalAddressSpaceSize, alignment, false); - if (allocatedMemory.isNull()) { - return CEntryPointErrors.RESERVE_ADDRESS_SPACE_FAILED; - } - } else { - if (reservedSize.belowThan(totalAddressSpaceSize)) { - return CEntryPointErrors.INSUFFICIENT_ADDRESS_SPACE; - } - heapBase = reservedAddressSpace; - } - - if (haveDynamicMethodResolution) { - heapBase = heapBase.add(preHeapRequiredBytes); - if (allocatedMemory.isNonNull()) { - allocatedMemory.add(preHeapRequiredBytes); - } - Pointer installOffset = heapBase.subtract(DynamicMethodAddressResolutionHeapSupport.get().getRequiredPreHeapMemoryInBytes()); - int error = DynamicMethodAddressResolutionHeapSupport.get().install(installOffset); - - if (error != CEntryPointErrors.NO_ERROR) { - freeImageHeap(allocatedMemory); - return error; - } + return initializeImageHeapByCopying(imageHeap, heapBeginSym, heapEndSym, heapWritableSym, heapWritableEndSym, imageHeapSize); } // Create memory mappings from the image file. - UnsignedWord fileOffset = CACHED_IMAGE_HEAP_OFFSET.get().read(); - Pointer imageHeap = getImageHeapBegin(heapBase); - imageHeap = VirtualMemoryProvider.get().mapFile(imageHeap, imageHeapSizeInFile, fd, fileOffset, Access.READ); + UnsignedWord fileOffset = cachedOffset.read(); + imageHeap = VirtualMemoryProvider.get().mapFile(imageHeap, imageHeapSize, fd, fileOffset, Access.READ); if (imageHeap.isNull()) { - freeImageHeap(allocatedMemory); return CEntryPointErrors.MAP_HEAP_FAILED; } - Pointer relocsBegin = imageHeap.add(IMAGE_HEAP_RELOCATABLE_BEGIN.get().subtract(IMAGE_HEAP_BEGIN.get())); - ComparableWord relocatedValue = IMAGE_HEAP_A_RELOCATABLE_POINTER.get().readWord(0); - ComparableWord mappedValue = relocsBegin.readWord(0); - if (relocatedValue.notEqual(mappedValue)) { - /* - * Addresses were relocated by dynamic linker, so copy them, but first remap the pages - * to avoid swapping them in from disk. - */ - UnsignedWord relocsSize = IMAGE_HEAP_RELOCATABLE_END.get().subtract(IMAGE_HEAP_RELOCATABLE_BEGIN.get()); - if (!isAMultiple(relocsSize, pageSize)) { - freeImageHeap(allocatedMemory); - return CEntryPointErrors.PROTECT_HEAP_FAILED; - } - Pointer committedRelocsBegin = VirtualMemoryProvider.get().commit(relocsBegin, relocsSize, Access.READ | Access.WRITE); - if (committedRelocsBegin.isNull() || committedRelocsBegin != relocsBegin) { - freeImageHeap(allocatedMemory); - return CEntryPointErrors.PROTECT_HEAP_FAILED; - } - LibC.memcpy(relocsBegin, IMAGE_HEAP_RELOCATABLE_BEGIN.get(), relocsSize); - if (VirtualMemoryProvider.get().protect(relocsBegin, relocsSize, Access.READ) != 0) { - freeImageHeap(allocatedMemory); - return CEntryPointErrors.PROTECT_HEAP_FAILED; + if (heapAnyRelocPointer.isNonNull()) { + ComparableWord relocatedValue = heapAnyRelocPointer.readWord(0); + ComparableWord mappedValue = imageHeap.readWord(heapAnyRelocPointer.subtract(heapBeginSym)); + if (relocatedValue.notEqual(mappedValue)) { + /* + * Addresses were relocated by dynamic linker, so copy them, but first remap the + * pages to avoid swapping them in from disk. + */ + Pointer relocsBegin = imageHeap.add(heapRelocsSym.subtract(heapBeginSym)); + UnsignedWord relocsSize = heapRelocsEndSym.subtract(heapRelocsSym); + if (!isAMultiple(relocsSize, pageSize)) { + return CEntryPointErrors.PROTECT_HEAP_FAILED; + } + Pointer committedRelocsBegin = VirtualMemoryProvider.get().commit(relocsBegin, relocsSize, Access.READ | Access.WRITE); + if (committedRelocsBegin.isNull() || committedRelocsBegin != relocsBegin) { + return CEntryPointErrors.PROTECT_HEAP_FAILED; + } + LibC.memcpy(relocsBegin, heapRelocsSym, relocsSize); + if (VirtualMemoryProvider.get().protect(relocsBegin, relocsSize, Access.READ) != 0) { + return CEntryPointErrors.PROTECT_HEAP_FAILED; + } } } // Unprotect writable pages. - Pointer writableBegin = imageHeap.add(IMAGE_HEAP_WRITABLE_BEGIN.get().subtract(IMAGE_HEAP_BEGIN.get())); - UnsignedWord writableSize = IMAGE_HEAP_WRITABLE_END.get().subtract(IMAGE_HEAP_WRITABLE_BEGIN.get()); + Pointer writableBegin = imageHeap.add(heapWritableSym.subtract(heapBeginSym)); + UnsignedWord writableSize = heapWritableEndSym.subtract(heapWritableSym); if (VirtualMemoryProvider.get().protect(writableBegin, writableSize, Access.READ | Access.WRITE) != 0) { - freeImageHeap(allocatedMemory); return CEntryPointErrors.PROTECT_HEAP_FAILED; } - basePointer.write(heapBase); - if (endPointer.isNonNull()) { - endPointer.write(roundUp(imageHeap.add(imageHeapSizeInFile), pageSize)); + return CEntryPointErrors.NO_ERROR; + } + + @Uninterruptible(reason = "Called during isolate initialization.") + private static int initializeImageHeapByCopying(Pointer imageHeap, Word heapBeginSym, Word heapEndSym, Word heapWritableSym, Word heapWritableEndSym, UnsignedWord imageHeapSize) { + Pointer committedBegin = VirtualMemoryProvider.get().commit(imageHeap, imageHeapSize, Access.READ | Access.WRITE); + if (committedBegin.isNull()) { + return CEntryPointErrors.MAP_HEAP_FAILED; + } + LibC.memcpy(imageHeap, heapBeginSym, imageHeapSize); + + Word readOnlyBytesAtBegin = heapWritableSym.subtract(heapBeginSym); + if (readOnlyBytesAtBegin.aboveThan(0) && VirtualMemoryProvider.get().protect(imageHeap, readOnlyBytesAtBegin, Access.READ) != 0) { + return CEntryPointErrors.PROTECT_HEAP_FAILED; + } + Pointer writableEnd = imageHeap.add(heapWritableEndSym.subtract(heapBeginSym)); + Word readOnlyBytesAtEnd = heapEndSym.subtract(heapWritableEndSym); + if (readOnlyBytesAtEnd.aboveThan(0) && VirtualMemoryProvider.get().protect(writableEnd, readOnlyBytesAtEnd, Access.READ) != 0) { + return CEntryPointErrors.PROTECT_HEAP_FAILED; } return CEntryPointErrors.NO_ERROR; } @@ -237,112 +282,96 @@ public int initialize(Pointer reservedAddressSpace, UnsignedWord reservedSize, W * first isolate. We do not use /proc/self/exe because it breaks with some tools like Valgrind. */ @Uninterruptible(reason = "Called during isolate initialization.") - private static int openImageFile() { + private static int openImageFile(WordPointer cachedOffset, Word heapBeginSym, Word heapRelocsSym, Pointer magicAddress) { final int failfd = (int) CANNOT_OPEN_FD.rawValue(); int mapfd = Fcntl.NoTransitions.open(PROC_SELF_MAPS.get(), Fcntl.O_RDONLY(), 0); if (mapfd == -1) { return failfd; } - final int bufferSize = MAX_PATHLEN; + final int bufferSize = 4096; // assumed MAX_PATHLEN CCharPointer buffer = StackValue.get(bufferSize); - // Find the offset of the magic word in the image file. We cannot reliably compute it from - // the image heap offset below because it might be in a different file segment. - Pointer magicAddress = MAGIC.get(); - int wordSize = ConfigurationValues.getTarget().wordSize; - WordPointer magicMappingStart = StackValue.get(WordPointer.class); - WordPointer magicMappingFileOffset = StackValue.get(WordPointer.class); - boolean found = findMapping(mapfd, buffer, bufferSize, magicAddress, magicAddress.add(wordSize), magicMappingStart, magicMappingFileOffset, false); - if (!found) { - Unistd.NoTransitions.close(mapfd); - return failfd; - } - Word magicFileOffset = (Word) magicAddress.subtract(magicMappingStart.read()).add(magicMappingFileOffset.read()); - - if (Unistd.NoTransitions.lseek(mapfd, signed(0), Unistd.SEEK_SET()).notEqual(0)) { - Unistd.NoTransitions.close(mapfd); - return failfd; - } // The relocatables partition might stretch over two adjacent mappings due to permission // differences, so only locate the mapping for the first page of relocatables UnsignedWord pageSize = VirtualMemoryProvider.get().getGranularity(); WordPointer relocsMappingStart = StackValue.get(WordPointer.class); WordPointer relocsMappingFileOffset = StackValue.get(WordPointer.class); - found = findMapping(mapfd, buffer, bufferSize, IMAGE_HEAP_RELOCATABLE_BEGIN.get(), - IMAGE_HEAP_RELOCATABLE_BEGIN.get().add(pageSize), relocsMappingStart, relocsMappingFileOffset, true); - Unistd.NoTransitions.close(mapfd); + boolean found = findMapping(mapfd, buffer, bufferSize, heapRelocsSym, heapRelocsSym.add(pageSize), relocsMappingStart, relocsMappingFileOffset, true); if (!found) { + Unistd.NoTransitions.close(mapfd); return failfd; } int opened = Fcntl.NoTransitions.open(buffer, Fcntl.O_RDONLY(), 0); if (opened < 0) { + Unistd.NoTransitions.close(mapfd); return failfd; } - // Compare the magic word in memory with the magic word read from the file - if (Unistd.NoTransitions.lseek(opened, magicFileOffset, Unistd.SEEK_SET()).notEqual(magicFileOffset)) { - Unistd.NoTransitions.close(opened); - return failfd; - } - if (PosixUtils.readBytes(opened, buffer, wordSize, 0) != wordSize) { + boolean valid = magicAddress.isNull() || checkImageFileMagic(mapfd, opened, buffer, bufferSize, magicAddress); + Unistd.NoTransitions.close(mapfd); + if (!valid) { Unistd.NoTransitions.close(opened); return failfd; } - Word fileMagic = ((WordPointer) buffer).read(); - if (fileMagic.notEqual(magicAddress.readWord(0))) { - return failfd; // magic number mismatch - } - Word imageHeapRelocsOffset = IMAGE_HEAP_RELOCATABLE_BEGIN.get().subtract(IMAGE_HEAP_BEGIN.get()); - Word imageHeapOffset = IMAGE_HEAP_RELOCATABLE_BEGIN.get().subtract(relocsMappingStart.read()).subtract(imageHeapRelocsOffset); + Word imageHeapRelocsOffset = heapRelocsSym.subtract(heapBeginSym); + Word imageHeapOffset = heapRelocsSym.subtract(relocsMappingStart.read()).subtract(imageHeapRelocsOffset); UnsignedWord fileOffset = imageHeapOffset.add(relocsMappingFileOffset.read()); - CACHED_IMAGE_HEAP_OFFSET.get().write(fileOffset); + cachedOffset.write(fileOffset); return opened; } - @Override - @Uninterruptible(reason = "Called during isolate tear-down.") - public int freeImageHeap(PointerBase heapBase) { - if (heapBase.isNonNull()) { - if (heapBase.equal(IMAGE_HEAP_BEGIN.get())) { - assert Heap.getHeap().getImageHeapOffsetInAddressSpace() == 0; - /* - * This isolate uses the image heap mapped by the loader. We shouldn't unmap it in - * case we are a dynamic library and dlclose() is called on us and tries to access - * the pages. However, the heap need not stay resident, so we remap it as an - * anonymous mapping. For future isolates, we still need the read-only heap - * partition with relocatable addresses that were adjusted by the loader, so we - * leave it. (We have already checked that that partition is page-aligned) - */ - assert Heap.getHeap().getImageHeapOffsetInAddressSpace() == 0; - UnsignedWord beforeRelocSize = IMAGE_HEAP_RELOCATABLE_BEGIN.get().subtract((Pointer) heapBase); - Pointer newHeapBase = VirtualMemoryProvider.get().commit(heapBase, beforeRelocSize, Access.READ); + @Uninterruptible(reason = "Called during isolate initialization.") + private static boolean checkImageFileMagic(int mapfd, int imagefd, CCharPointer buffer, int bufferSize, Pointer magicAddress) { + if (Unistd.NoTransitions.lseek(mapfd, signed(0), Unistd.SEEK_SET()).notEqual(0)) { + return false; + } - if (newHeapBase.isNull() || newHeapBase.notEqual(heapBase)) { - return CEntryPointErrors.MAP_HEAP_FAILED; - } + // Find the offset of the magic word in the image file. We cannot reliably compute it + // from the image heap offset below because it might be in a different file segment. + int wordSize = ConfigurationValues.getTarget().wordSize; + WordPointer magicMappingStart = StackValue.get(WordPointer.class); + WordPointer magicMappingFileOffset = StackValue.get(WordPointer.class); + boolean found = findMapping(mapfd, buffer, bufferSize, magicAddress, magicAddress.add(wordSize), magicMappingStart, magicMappingFileOffset, false); + if (!found) { + return false; + } + Word magicFileOffset = (Word) magicAddress.subtract(magicMappingStart.read()).add(magicMappingFileOffset.read()); - Word relocEnd = IMAGE_HEAP_RELOCATABLE_END.get(); - Word afterRelocSize = IMAGE_HEAP_END.get().subtract(relocEnd); - Pointer newRelocEnd = VirtualMemoryProvider.get().commit(relocEnd, afterRelocSize, Access.READ); + // Compare the magic word in memory with the magic word read from the file + if (Unistd.NoTransitions.lseek(imagefd, magicFileOffset, Unistd.SEEK_SET()).notEqual(magicFileOffset)) { + return false; + } - if (newRelocEnd.isNull() || newRelocEnd.notEqual(relocEnd)) { - return CEntryPointErrors.MAP_HEAP_FAILED; - } - } else { - UnsignedWord totalAddressSpaceSize = getImageHeapAddressSpaceSize(); - Pointer addressSpaceStart = (Pointer) heapBase; - if (DynamicMethodAddressResolutionHeapSupport.isEnabled()) { - UnsignedWord preHeapRequiredBytes = DynamicMethodAddressResolutionHeapSupport.get().getDynamicMethodAddressResolverPreHeapMemoryBytes(); - totalAddressSpaceSize = totalAddressSpaceSize.add(preHeapRequiredBytes); - addressSpaceStart = addressSpaceStart.subtract(preHeapRequiredBytes); - } + if (PosixUtils.readBytes(imagefd, buffer, wordSize, 0) != wordSize) { + return false; + } + Word fileMagic = ((WordPointer) buffer).read(); + return fileMagic.equal(magicAddress.readWord(0)); + } - if (VirtualMemoryProvider.get().free(addressSpaceStart, totalAddressSpaceSize) != 0) { - return CEntryPointErrors.FREE_IMAGE_HEAP_FAILED; - } - } + @Override + @Uninterruptible(reason = "Called during isolate tear-down.") + public int freeImageHeap(PointerBase heapBase) { + if (heapBase.isNull()) { // no memory allocated + return CEntryPointErrors.NO_ERROR; + } + VMError.guarantee(heapBase.notEqual(IMAGE_HEAP_BEGIN.get()), "reusing the image heap is no longer supported"); + + UnsignedWord totalAddressSpaceSize = getTotalRequiredAddressSpaceSize(); + Pointer addressSpaceStart = (Pointer) heapBase; + if (DynamicMethodAddressResolutionHeapSupport.isEnabled()) { + UnsignedWord preHeapRequiredBytes = DynamicMethodAddressResolutionHeapSupport.get().getDynamicMethodAddressResolverPreHeapMemoryBytes(); + addressSpaceStart = addressSpaceStart.subtract(preHeapRequiredBytes); + } + if (VirtualMemoryProvider.get().free(addressSpaceStart, totalAddressSpaceSize) != 0) { + return CEntryPointErrors.FREE_IMAGE_HEAP_FAILED; } return CEntryPointErrors.NO_ERROR; } + + @Override + protected UnsignedWord getImageHeapSizeInFile() { + throw VMError.shouldNotReachHere("use the variant that takes pointers"); + } } diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/os/AbstractImageHeapProvider.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/os/AbstractImageHeapProvider.java index e89f419d15b6..0542aec4b56c 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/os/AbstractImageHeapProvider.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/os/AbstractImageHeapProvider.java @@ -37,15 +37,20 @@ public abstract class AbstractImageHeapProvider implements ImageHeapProvider { @Uninterruptible(reason = "Called from uninterruptible code.", mayBeInlined = true) - protected static UnsignedWord getImageHeapAddressSpaceSize() { + protected UnsignedWord getImageHeapAddressSpaceSize() { UnsignedWord imageHeapSizeInFile = getImageHeapSizeInFile(); return imageHeapSizeInFile.add(Heap.getHeap().getImageHeapOffsetInAddressSpace()); } + @Uninterruptible(reason = "Called from uninterruptible code.", mayBeInlined = true) + protected static UnsignedWord getImageHeapSizeInFile(Word beginAddress, Word endAddress) { + assert endAddress.aboveOrEqual(endAddress); + return endAddress.subtract(beginAddress); + } + @Uninterruptible(reason = "Called from uninterruptible code.", mayBeInlined = true) protected static UnsignedWord getImageHeapSizeInFile() { - Word imageHeapBegin = IMAGE_HEAP_BEGIN.get(); - return IMAGE_HEAP_END.get().subtract(imageHeapBegin); + return getImageHeapSizeInFile(IMAGE_HEAP_BEGIN.get(), IMAGE_HEAP_END.get()); } @Uninterruptible(reason = "Called from uninterruptible code.", mayBeInlined = true) From 673d6c38550740c3b69b75fd443d05e6cf8a41d3 Mon Sep 17 00:00:00 2001 From: Peter Hofer Date: Thu, 11 Jan 2024 22:12:51 +0100 Subject: [PATCH 477/593] Fix LinuxImageHeapProvider error handling without reserved address space when DynamicMethodAddressResolutionHeapSupport enabled. --- .../posix/linux/LinuxImageHeapProvider.java | 41 +++++++++++-------- 1 file changed, 24 insertions(+), 17 deletions(-) diff --git a/substratevm/src/com.oracle.svm.core.posix/src/com/oracle/svm/core/posix/linux/LinuxImageHeapProvider.java b/substratevm/src/com.oracle.svm.core.posix/src/com/oracle/svm/core/posix/linux/LinuxImageHeapProvider.java index 5546d1f963ee..a83423b7a6ba 100644 --- a/substratevm/src/com.oracle.svm.core.posix/src/com/oracle/svm/core/posix/linux/LinuxImageHeapProvider.java +++ b/substratevm/src/com.oracle.svm.core.posix/src/com/oracle/svm/core/posix/linux/LinuxImageHeapProvider.java @@ -119,41 +119,48 @@ protected UnsignedWord getTotalRequiredAddressSpaceSize() { @Override @Uninterruptible(reason = "Called during isolate initialization.") public int initialize(Pointer reservedAddressSpace, UnsignedWord reservedSize, WordPointer basePointer, WordPointer endPointer) { - Pointer heapBase; - Pointer allocatedMemory = WordFactory.nullPointer(); + Pointer selfReservedMemory = WordFactory.nullPointer(); UnsignedWord requiredSize = getTotalRequiredAddressSpaceSize(); if (reservedAddressSpace.isNull()) { UnsignedWord alignment = WordFactory.unsigned(Heap.getHeap().getPreferredAddressSpaceAlignment()); - allocatedMemory = VirtualMemoryProvider.get().reserve(requiredSize, alignment, false); - if (allocatedMemory.isNull()) { + selfReservedMemory = VirtualMemoryProvider.get().reserve(requiredSize, alignment, false); + if (selfReservedMemory.isNull()) { return CEntryPointErrors.RESERVE_ADDRESS_SPACE_FAILED; } - heapBase = allocatedMemory; - } else { - if (reservedSize.belowThan(requiredSize)) { - return CEntryPointErrors.INSUFFICIENT_ADDRESS_SPACE; - } - heapBase = reservedAddressSpace; + } else if (reservedSize.belowThan(requiredSize)) { + return CEntryPointErrors.INSUFFICIENT_ADDRESS_SPACE; } UnsignedWord remainingSize = requiredSize; + Pointer heapBase; + Pointer selfReservedHeapBase; if (DynamicMethodAddressResolutionHeapSupport.isEnabled()) { + UnsignedWord preHeapRequiredBytes = DynamicMethodAddressResolutionHeapSupport.get().getDynamicMethodAddressResolverPreHeapMemoryBytes(); + if (selfReservedMemory.isNonNull()) { + selfReservedHeapBase = selfReservedMemory.add(preHeapRequiredBytes); + heapBase = selfReservedHeapBase; + } else { + heapBase = reservedAddressSpace.add(preHeapRequiredBytes); + selfReservedHeapBase = WordFactory.nullPointer(); + } + assert heapBase.isNonNull(); + remainingSize = remainingSize.subtract(preHeapRequiredBytes); + int error = DynamicMethodAddressResolutionHeapSupport.get().initialize(); if (error != CEntryPointErrors.NO_ERROR) { - freeImageHeap(allocatedMemory); + freeImageHeap(selfReservedHeapBase); return error; } - UnsignedWord preHeapRequiredBytes = DynamicMethodAddressResolutionHeapSupport.get().getDynamicMethodAddressResolverPreHeapMemoryBytes(); - heapBase = heapBase.add(preHeapRequiredBytes); - remainingSize = remainingSize.subtract(preHeapRequiredBytes); - Pointer installOffset = heapBase.subtract(DynamicMethodAddressResolutionHeapSupport.get().getRequiredPreHeapMemoryInBytes()); error = DynamicMethodAddressResolutionHeapSupport.get().install(installOffset); if (error != CEntryPointErrors.NO_ERROR) { - freeImageHeap(allocatedMemory); + freeImageHeap(selfReservedHeapBase); return error; } + } else { + heapBase = selfReservedMemory.isNonNull() ? selfReservedMemory : reservedAddressSpace; + selfReservedHeapBase = selfReservedMemory; } int imageHeapOffsetInAddressSpace = Heap.getHeap().getImageHeapOffsetInAddressSpace(); @@ -166,7 +173,7 @@ public int initialize(Pointer reservedAddressSpace, UnsignedWord reservedSize, W IMAGE_HEAP_RELOCATABLE_BEGIN.get(), IMAGE_HEAP_A_RELOCATABLE_POINTER.get(), IMAGE_HEAP_RELOCATABLE_END.get(), IMAGE_HEAP_WRITABLE_BEGIN.get(), IMAGE_HEAP_WRITABLE_END.get()); if (result != CEntryPointErrors.NO_ERROR) { - freeImageHeap(allocatedMemory); + freeImageHeap(selfReservedHeapBase); } return result; } From 96bed32949298933a72cf48930062f8c0ea5d6e2 Mon Sep 17 00:00:00 2001 From: Patrick Date: Fri, 12 Jan 2024 16:39:30 +0100 Subject: [PATCH 478/593] Mark more features and methods as NATIVE_ONLY --- .../src/com/oracle/svm/core/monitor/MonitorFeature.java | 3 +++ .../com/oracle/svm/core/thread/Target_java_lang_Thread.java | 1 + .../src/com/oracle/svm/hosted/meta/KnownOffsetsFeature.java | 3 +++ .../src/com/oracle/svm/hosted/thread/VMThreadMTFeature.java | 3 +++ 4 files changed, 10 insertions(+) diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/monitor/MonitorFeature.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/monitor/MonitorFeature.java index d11cf0de643e..beda35f08bb0 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/monitor/MonitorFeature.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/monitor/MonitorFeature.java @@ -30,6 +30,8 @@ import jdk.graal.compiler.options.OptionValues; import jdk.graal.compiler.phases.util.Providers; import org.graalvm.nativeimage.ImageSingletons; +import org.graalvm.nativeimage.Platforms; +import org.graalvm.nativeimage.impl.InternalPlatform; import com.oracle.svm.core.SubstrateOptions; import com.oracle.svm.core.feature.InternalFeature; @@ -39,6 +41,7 @@ import com.oracle.svm.core.feature.AutomaticallyRegisteredFeature; @AutomaticallyRegisteredFeature +@Platforms(InternalPlatform.NATIVE_ONLY.class) public class MonitorFeature implements InternalFeature { @Override diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/thread/Target_java_lang_Thread.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/thread/Target_java_lang_Thread.java index 0bc51646f8b3..2b6d3aaa4d28 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/thread/Target_java_lang_Thread.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/thread/Target_java_lang_Thread.java @@ -321,6 +321,7 @@ public boolean isInterrupted() { * underlying mechanisms. */ @Substitute + @Platforms(InternalPlatform.NATIVE_ONLY.class) void interrupt0() { /* * The interrupted flag is maintained by the JDK in Java code, i.e., already set by the diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/meta/KnownOffsetsFeature.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/meta/KnownOffsetsFeature.java index a0c1afe3eeab..ebfd4dcca701 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/meta/KnownOffsetsFeature.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/meta/KnownOffsetsFeature.java @@ -29,7 +29,9 @@ import java.util.List; import org.graalvm.nativeimage.ImageSingletons; +import org.graalvm.nativeimage.Platforms; import org.graalvm.nativeimage.hosted.Feature; +import org.graalvm.nativeimage.impl.InternalPlatform; import com.oracle.svm.core.SubstrateOptions; import com.oracle.svm.core.code.ImageCodeInfo; @@ -47,6 +49,7 @@ import com.oracle.svm.util.ReflectionUtil; @AutomaticallyRegisteredFeature +@Platforms(InternalPlatform.NATIVE_ONLY.class) public final class KnownOffsetsFeature implements InternalFeature { @Override diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/thread/VMThreadMTFeature.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/thread/VMThreadMTFeature.java index d2ec00a1b831..d6305aac8623 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/thread/VMThreadMTFeature.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/thread/VMThreadMTFeature.java @@ -28,6 +28,8 @@ import org.graalvm.nativeimage.ImageSingletons; import org.graalvm.nativeimage.IsolateThread; +import org.graalvm.nativeimage.Platforms; +import org.graalvm.nativeimage.impl.InternalPlatform; import com.oracle.svm.core.ParsingReason; import com.oracle.svm.core.SubstrateOptions; @@ -68,6 +70,7 @@ * offset in the {@link IsolateThread} data structure. */ @AutomaticallyRegisteredFeature +@Platforms(InternalPlatform.NATIVE_ONLY.class) public class VMThreadMTFeature implements InternalFeature { private final VMThreadLocalCollector threadLocalCollector = new VMThreadLocalCollector(); From f759aaa7a18ecf853c74512cc02d105025da422f Mon Sep 17 00:00:00 2001 From: Patrick Date: Mon, 15 Jan 2024 15:23:46 +0100 Subject: [PATCH 479/593] Make HeapImpl.getImageHeapStart a method on Heap class --- .../src/com/oracle/svm/core/genscavenge/HeapImpl.java | 5 +++-- .../com/oracle/svm/core/genscavenge/ImageHeapWalker.java | 3 ++- .../src/com/oracle/svm/core/heap/Heap.java | 6 ++++++ 3 files changed, 11 insertions(+), 3 deletions(-) diff --git a/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/HeapImpl.java b/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/HeapImpl.java index 21cbe165518b..25818c421e3e 100644 --- a/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/HeapImpl.java +++ b/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/HeapImpl.java @@ -687,10 +687,11 @@ public long getIdentityHashSalt(Object obj) { return HeapChunk.getIdentityHashSalt(chunk).rawValue(); } + @Override @Uninterruptible(reason = "Called from uninterruptible code.", mayBeInlined = true) - static Pointer getImageHeapStart() { + public Pointer getImageHeapStart() { Pointer heapBase = (Pointer) Isolates.getHeapBase(CurrentIsolate.getIsolate()); - return heapBase.add(Heap.getHeap().getImageHeapOffsetInAddressSpace()); + return heapBase.add(getImageHeapOffsetInAddressSpace()); } private boolean printLocationInfo(Log log, Pointer ptr, boolean allowJavaHeapAccess, boolean allowUnsafeOperations) { diff --git a/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/ImageHeapWalker.java b/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/ImageHeapWalker.java index 504f477c9776..851515b69755 100644 --- a/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/ImageHeapWalker.java +++ b/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/ImageHeapWalker.java @@ -33,6 +33,7 @@ import com.oracle.svm.core.AlwaysInline; import com.oracle.svm.core.MemoryWalker; import com.oracle.svm.core.Uninterruptible; +import com.oracle.svm.core.heap.Heap; import com.oracle.svm.core.heap.ObjectVisitor; import com.oracle.svm.core.hub.LayoutEncoding; import com.oracle.svm.core.util.UnsignedUtils; @@ -93,7 +94,7 @@ private static boolean walkPartitionInline(Object firstObject, Object lastObject Pointer current = firstPointer; /* Compute the enclosing chunk without assuming that the image heap is aligned. */ - Pointer base = HeapImpl.getImageHeapStart(); + Pointer base = Heap.getHeap().getImageHeapStart(); Pointer offset = current.subtract(base); UnsignedWord chunkOffset = alignedChunks ? UnsignedUtils.roundDown(offset, HeapParameters.getAlignedHeapChunkAlignment()) : offset.subtract(UnalignedHeapChunk.getObjectStartOffset()); diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/heap/Heap.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/heap/Heap.java index 0ff251b63ab4..5baf9ef42a9b 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/heap/Heap.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/heap/Heap.java @@ -45,6 +45,7 @@ import com.oracle.svm.core.os.CommittedMemoryProvider; import jdk.graal.compiler.api.replacements.Fold; +import jdk.graal.compiler.debug.GraalError; public abstract class Heap { @Fold @@ -143,6 +144,11 @@ public void visitLoadedClasses(Consumer> visitor) { @Fold public abstract int getPreferredAddressSpaceAlignment(); + @Uninterruptible(reason = "Called from uninterruptible code.", mayBeInlined = true) + public Pointer getImageHeapStart() { + throw GraalError.unimplemented("Heap.getImageHeapStart not implemented"); + } + /** * Returns an offset relative to the heap base, at which the image heap should be mapped into * the address space. From 9df0df7cbd93af1ca0e22a3a30b209e89fc36189 Mon Sep 17 00:00:00 2001 From: Patrick Date: Mon, 15 Jan 2024 15:57:49 +0100 Subject: [PATCH 480/593] Remove VMThreadSTFeature --- .../svm/hosted/thread/VMThreadSTFeature.java | 235 ------------------ 1 file changed, 235 deletions(-) delete mode 100644 substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/thread/VMThreadSTFeature.java diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/thread/VMThreadSTFeature.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/thread/VMThreadSTFeature.java deleted file mode 100644 index a896eca1c47a..000000000000 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/thread/VMThreadSTFeature.java +++ /dev/null @@ -1,235 +0,0 @@ -/* - * Copyright (c) 2014, 2022, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.oracle.svm.hosted.thread; - -import java.util.List; - -import jdk.graal.compiler.api.replacements.SnippetReflectionProvider; -import jdk.graal.compiler.core.common.NumUtil; -import jdk.graal.compiler.core.common.memory.BarrierType; -import jdk.graal.compiler.core.common.memory.MemoryOrderMode; -import jdk.graal.compiler.nodes.ValueNode; -import jdk.graal.compiler.nodes.graphbuilderconf.GraphBuilderConfiguration.Plugins; -import jdk.graal.compiler.nodes.graphbuilderconf.GraphBuilderContext; -import jdk.graal.compiler.nodes.graphbuilderconf.InvocationPlugin.Receiver; -import jdk.graal.compiler.nodes.graphbuilderconf.InvocationPlugin.RequiredInvocationPlugin; -import jdk.graal.compiler.nodes.graphbuilderconf.InvocationPlugins.Registration; -import jdk.graal.compiler.phases.util.Providers; -import org.graalvm.nativeimage.ImageSingletons; -import org.graalvm.nativeimage.IsolateThread; -import org.graalvm.nativeimage.Platforms; -import org.graalvm.nativeimage.impl.InternalPlatform; - -import com.oracle.svm.core.ParsingReason; -import com.oracle.svm.core.SubstrateOptions; -import com.oracle.svm.core.config.ConfigurationValues; -import com.oracle.svm.core.config.ObjectLayout; -import com.oracle.svm.core.feature.AutomaticallyRegisteredFeature; -import com.oracle.svm.core.feature.InternalFeature; -import com.oracle.svm.core.graal.thread.AddressOfVMThreadLocalNode; -import com.oracle.svm.core.graal.thread.CompareAndSetVMThreadLocalNode; -import com.oracle.svm.core.graal.thread.LoadVMThreadLocalNode; -import com.oracle.svm.core.graal.thread.StoreVMThreadLocalNode; -import com.oracle.svm.core.graal.thread.VMThreadLocalSTHolderNode; -import com.oracle.svm.core.threadlocal.FastThreadLocal; -import com.oracle.svm.core.threadlocal.FastThreadLocalBytes; -import com.oracle.svm.core.threadlocal.FastThreadLocalWord; -import com.oracle.svm.core.threadlocal.VMThreadLocalInfo; -import com.oracle.svm.core.threadlocal.VMThreadLocalInfos; -import com.oracle.svm.core.threadlocal.VMThreadLocalSTSupport; - -import jdk.vm.ci.meta.JavaKind; -import jdk.vm.ci.meta.ResolvedJavaMethod; - -/** - * Collects all VM thread local variables during native image generation and assigns them their - * offset in the Object[] and byte[] array that hold the values. - */ -@AutomaticallyRegisteredFeature -@Platforms(InternalPlatform.NATIVE_ONLY.class) -public class VMThreadSTFeature implements InternalFeature { - - private final VMThreadLocalCollector threadLocalCollector = new VMThreadLocalCollector(); - - @Override - public boolean isInConfiguration(IsInConfigurationAccess access) { - return !SubstrateOptions.MultiThreaded.getValue(); - } - - @Override - public void duringSetup(DuringSetupAccess config) { - ImageSingletons.add(VMThreadLocalSTSupport.class, new VMThreadLocalSTSupport()); - config.registerObjectReplacer(threadLocalCollector); - } - - /** - * Intrinsify the {@code get()} and {@code set()} methods during bytecode parsing. We know that - * every subclass of VMThreadLocal has the same methods. Only the signatures differ based on the - * type of value. - *

    - * The value is stored in the two arrays that are in the image heap: a Object[] array for thread - * local object variables, and a byte[] array for all thread local primitive variables. - * Therefore, we need the proper read/write barriers. The {@link IsolateThread} parameter is - * ignored. - */ - @Override - public void registerInvocationPlugins(Providers providers, SnippetReflectionProvider snippetReflection, Plugins plugins, ParsingReason reason) { - for (Class threadLocalClass : VMThreadLocalInfo.THREAD_LOCAL_CLASSES) { - Registration r = new Registration(plugins.getInvocationPlugins(), threadLocalClass); - Class valueClass = VMThreadLocalInfo.getValueClass(threadLocalClass); - - registerAccessors(r, snippetReflection, valueClass, false); - registerAccessors(r, snippetReflection, valueClass, true); - - /* compareAndSet() method without the VMThread parameter. */ - r.register(new RequiredInvocationPlugin("compareAndSet", Receiver.class, valueClass, valueClass) { - @Override - public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode expect, ValueNode update) { - return handleCompareAndSet(b, snippetReflection, targetMethod, receiver, expect, update); - } - }); - /* get() method with the VMThread parameter. */ - r.register(new RequiredInvocationPlugin("compareAndSet", Receiver.class, IsolateThread.class, valueClass, valueClass) { - @Override - public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode threadNode, ValueNode expect, ValueNode update) { - return handleCompareAndSet(b, snippetReflection, targetMethod, receiver, expect, update); - } - }); - } - - Class[] typesWithGetAddress = new Class[]{FastThreadLocalBytes.class, FastThreadLocalWord.class}; - for (Class type : typesWithGetAddress) { - Registration r = new Registration(plugins.getInvocationPlugins(), type); - /* getAddress() method without the VMThread parameter. */ - r.register(new RequiredInvocationPlugin("getAddress", Receiver.class) { - @Override - public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver) { - return handleGetAddress(b, snippetReflection, targetMethod, receiver); - } - }); - /* getAddress() method with the VMThread parameter. */ - r.register(new RequiredInvocationPlugin("getAddress", Receiver.class, IsolateThread.class) { - @Override - public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode threadNode) { - return handleGetAddress(b, snippetReflection, targetMethod, receiver); - } - }); - } - } - - private void registerAccessors(Registration r, SnippetReflectionProvider snippetReflection, Class valueClass, boolean isVolatile) { - /* - * Volatile accesses do not need memory barriers in single-threaded mode, i.e., we register - * the same plugin for normal and volatile accesses. - */ - String suffix = isVolatile ? "Volatile" : ""; - - /* get() method without the VMThread parameter. */ - r.register(new RequiredInvocationPlugin("get" + suffix, Receiver.class) { - @Override - public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver) { - return handleGet(b, snippetReflection, targetMethod, receiver); - } - }); - /* get() method with the VMThread parameter. */ - r.register(new RequiredInvocationPlugin("get" + suffix, Receiver.class, IsolateThread.class) { - @Override - public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode threadNode) { - return handleGet(b, snippetReflection, targetMethod, receiver); - } - }); - /* set() method without the VMThread parameter. */ - r.register(new RequiredInvocationPlugin("set" + suffix, Receiver.class, valueClass) { - @Override - public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode valueNode) { - return handleSet(b, snippetReflection, receiver, valueNode); - } - }); - /* set() method with the VMThread parameter. */ - r.register(new RequiredInvocationPlugin("set" + suffix, Receiver.class, IsolateThread.class, valueClass) { - @Override - public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode threadNode, ValueNode valueNode) { - return handleSet(b, snippetReflection, receiver, valueNode); - } - }); - } - - private boolean handleGet(GraphBuilderContext b, SnippetReflectionProvider snippetReflection, ResolvedJavaMethod targetMethod, Receiver receiver) { - VMThreadLocalInfo info = threadLocalCollector.findInfo(b, snippetReflection, receiver.get()); - VMThreadLocalSTHolderNode holder = b.add(new VMThreadLocalSTHolderNode(info)); - b.addPush(targetMethod.getSignature().getReturnKind(), new LoadVMThreadLocalNode(b.getMetaAccess(), info, holder, BarrierType.NONE, MemoryOrderMode.PLAIN)); - return true; - } - - private boolean handleSet(GraphBuilderContext b, SnippetReflectionProvider snippetReflection, Receiver receiver, ValueNode valueNode) { - VMThreadLocalInfo info = threadLocalCollector.findInfo(b, snippetReflection, receiver.get()); - VMThreadLocalSTHolderNode holder = b.add(new VMThreadLocalSTHolderNode(info)); - StoreVMThreadLocalNode store = new StoreVMThreadLocalNode(info, holder, valueNode, BarrierType.ARRAY, MemoryOrderMode.PLAIN); - b.add(store); - assert store.stateAfter() != null : store + " has no state after with graph builder context " + b; - return true; - } - - private boolean handleCompareAndSet(GraphBuilderContext b, SnippetReflectionProvider snippetReflection, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode expect, ValueNode update) { - VMThreadLocalInfo threadLocalInfo = threadLocalCollector.findInfo(b, snippetReflection, receiver.get()); - VMThreadLocalSTHolderNode holder = b.add(new VMThreadLocalSTHolderNode(threadLocalInfo)); - CompareAndSetVMThreadLocalNode cas = new CompareAndSetVMThreadLocalNode(threadLocalInfo, holder, expect, update); - b.addPush(targetMethod.getSignature().getReturnKind(), cas); - assert cas.stateAfter() != null : cas + " has no state after with graph builder context " + b; - return true; - } - - private boolean handleGetAddress(GraphBuilderContext b, SnippetReflectionProvider snippetReflection, ResolvedJavaMethod targetMethod, Receiver receiver) { - VMThreadLocalInfo threadLocalInfo = threadLocalCollector.findInfo(b, snippetReflection, receiver.get()); - VMThreadLocalSTHolderNode holder = b.add(new VMThreadLocalSTHolderNode(threadLocalInfo)); - b.addPush(targetMethod.getSignature().getReturnKind(), new AddressOfVMThreadLocalNode(threadLocalInfo, holder)); - return true; - } - - @Override - public void beforeCompilation(BeforeCompilationAccess config) { - List sortedThreadLocalInfos = threadLocalCollector.sortThreadLocals(); - ObjectLayout layout = ConfigurationValues.getObjectLayout(); - int nextObject = 0; - int nextPrimitive = 0; - for (VMThreadLocalInfo info : sortedThreadLocalInfos) { - if (info.isObject) { - info.offset = NumUtil.safeToInt(layout.getArrayElementOffset(JavaKind.Object, nextObject)); - nextObject += 1; - } else { - assert nextPrimitive % Math.min(8, info.sizeInBytes) == 0 : "alignment mismatch: " + info.sizeInBytes + ", " + nextPrimitive; - info.offset = NumUtil.safeToInt(layout.getArrayElementOffset(JavaKind.Byte, nextPrimitive)); - nextPrimitive += info.sizeInBytes; - } - } - - VMThreadLocalSTSupport support = ImageSingletons.lookup(VMThreadLocalSTSupport.class); - support.objectThreadLocals = new Object[nextObject]; - support.primitiveThreadLocals = new byte[nextPrimitive]; - - /* Remember the final sorted list. */ - VMThreadLocalInfos.setInfos(sortedThreadLocalInfos); - } -} From 280c3bd68b33f9c8c380cae5649b2ad55b74cdb3 Mon Sep 17 00:00:00 2001 From: Patrick Date: Mon, 15 Jan 2024 15:57:57 +0100 Subject: [PATCH 481/593] Make VMThreadLocalCollector public --- .../com/oracle/svm/hosted/thread/VMThreadLocalCollector.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/thread/VMThreadLocalCollector.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/thread/VMThreadLocalCollector.java index 35578af1f3e7..499bdeecaa21 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/thread/VMThreadLocalCollector.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/thread/VMThreadLocalCollector.java @@ -45,7 +45,7 @@ /** * Collects all {@link FastThreadLocal} instances that are actually used by the application. */ -class VMThreadLocalCollector implements Function { +public class VMThreadLocalCollector implements Function { final Map threadLocals = ObservableImageHeapMapProvider.create(); private boolean sealed; From 838157c19ca91274ef658649f6dc20666347696a Mon Sep 17 00:00:00 2001 From: Patrick Date: Mon, 15 Jan 2024 16:06:28 +0100 Subject: [PATCH 482/593] Remove VMThreadLocalSTHolderNode --- .../thread/VMThreadLocalSTHolderNode.java | 71 ------------------- 1 file changed, 71 deletions(-) delete mode 100644 substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/graal/thread/VMThreadLocalSTHolderNode.java diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/graal/thread/VMThreadLocalSTHolderNode.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/graal/thread/VMThreadLocalSTHolderNode.java deleted file mode 100644 index 4f410d71afcb..000000000000 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/graal/thread/VMThreadLocalSTHolderNode.java +++ /dev/null @@ -1,71 +0,0 @@ -/* - * Copyright (c) 2014, 2017, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.oracle.svm.core.graal.thread; - -import org.graalvm.nativeimage.ImageSingletons; - -import com.oracle.svm.core.threadlocal.VMThreadLocalInfo; -import com.oracle.svm.core.threadlocal.VMThreadLocalSTSupport; - -import jdk.graal.compiler.api.replacements.SnippetReflectionProvider; -import jdk.graal.compiler.core.common.LIRKind; -import jdk.graal.compiler.core.common.type.StampFactory; -import jdk.graal.compiler.graph.NodeClass; -import jdk.graal.compiler.nodeinfo.NodeCycles; -import jdk.graal.compiler.nodeinfo.NodeInfo; -import jdk.graal.compiler.nodeinfo.NodeSize; -import jdk.graal.compiler.nodes.FixedWithNextNode; -import jdk.graal.compiler.nodes.NodeView; -import jdk.graal.compiler.nodes.spi.LIRLowerable; -import jdk.graal.compiler.nodes.spi.NodeLIRBuilderTool; - -@NodeInfo(cycles = NodeCycles.CYCLES_0, size = NodeSize.SIZE_1) -public class VMThreadLocalSTHolderNode extends FixedWithNextNode implements LIRLowerable { - public static final NodeClass TYPE = NodeClass.create(VMThreadLocalSTHolderNode.class); - - protected final VMThreadLocalInfo threadLocalInfo; - - public VMThreadLocalSTHolderNode(VMThreadLocalInfo threadLocalInfo) { - super(TYPE, StampFactory.objectNonNull()); - this.threadLocalInfo = threadLocalInfo; - } - - public VMThreadLocalInfo getThreadLocalInfo() { - return threadLocalInfo; - } - - @Override - public void generate(NodeLIRBuilderTool gen) { - Object holder; - if (threadLocalInfo.isObject) { - holder = ImageSingletons.lookup(VMThreadLocalSTSupport.class).objectThreadLocals; - } else { - holder = ImageSingletons.lookup(VMThreadLocalSTSupport.class).primitiveThreadLocals; - } - SnippetReflectionProvider snippetReflection = gen.getLIRGeneratorTool().getSnippetReflection(); - LIRKind kind = gen.getLIRGeneratorTool().getLIRKind(stamp(NodeView.DEFAULT)); - gen.setResult(this, gen.getLIRGeneratorTool().emitLoadConstant(kind, snippetReflection.forObject(holder))); - } -} From bff0de3ff28150114f4014164b1b4547ba5544af Mon Sep 17 00:00:00 2001 From: Patrick Date: Mon, 15 Jan 2024 16:17:12 +0100 Subject: [PATCH 483/593] Remove SingleThreadedMonitorSupport --- .../svm/core/monitor/MonitorFeature.java | 11 ++- .../monitor/SingleThreadedMonitorSupport.java | 90 ------------------- 2 files changed, 5 insertions(+), 96 deletions(-) delete mode 100644 substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/monitor/SingleThreadedMonitorSupport.java diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/monitor/MonitorFeature.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/monitor/MonitorFeature.java index beda35f08bb0..25456a4c0a80 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/monitor/MonitorFeature.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/monitor/MonitorFeature.java @@ -26,19 +26,20 @@ import java.util.Map; -import jdk.graal.compiler.graph.Node; -import jdk.graal.compiler.options.OptionValues; -import jdk.graal.compiler.phases.util.Providers; import org.graalvm.nativeimage.ImageSingletons; import org.graalvm.nativeimage.Platforms; import org.graalvm.nativeimage.impl.InternalPlatform; import com.oracle.svm.core.SubstrateOptions; +import com.oracle.svm.core.feature.AutomaticallyRegisteredFeature; import com.oracle.svm.core.feature.InternalFeature; import com.oracle.svm.core.graal.meta.RuntimeConfiguration; import com.oracle.svm.core.graal.meta.SubstrateForeignCallsProvider; import com.oracle.svm.core.graal.snippets.NodeLoweringProvider; -import com.oracle.svm.core.feature.AutomaticallyRegisteredFeature; + +import jdk.graal.compiler.graph.Node; +import jdk.graal.compiler.options.OptionValues; +import jdk.graal.compiler.phases.util.Providers; @AutomaticallyRegisteredFeature @Platforms(InternalPlatform.NATIVE_ONLY.class) @@ -48,8 +49,6 @@ public class MonitorFeature implements InternalFeature { public void afterRegistration(AfterRegistrationAccess access) { if (SubstrateOptions.MultiThreaded.getValue()) { ImageSingletons.add(MonitorSupport.class, new MultiThreadedMonitorSupport()); - } else { - ImageSingletons.add(MonitorSupport.class, new SingleThreadedMonitorSupport()); } } diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/monitor/SingleThreadedMonitorSupport.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/monitor/SingleThreadedMonitorSupport.java deleted file mode 100644 index c0f7ad2d5063..000000000000 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/monitor/SingleThreadedMonitorSupport.java +++ /dev/null @@ -1,90 +0,0 @@ -/* - * Copyright (c) 2020, 2020, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.oracle.svm.core.monitor; - -import com.oracle.svm.core.Uninterruptible; -import com.oracle.svm.core.thread.ThreadStatus; - -/** - * Without support for threads, there is no need for any monitor operations. - */ -public class SingleThreadedMonitorSupport extends MonitorSupport { - @Override - public void monitorEnter(Object obj, MonitorInflationCause cause) { - /* Synchronization is a no-op in single threaded mode. */ - } - - @Override - public void monitorExit(Object obj, MonitorInflationCause cause) { - /* Synchronization is a no-op in single threaded mode. */ - } - - @Override - public Object prepareRelockObject(Object obj) { - return null; - } - - @Uninterruptible(reason = "called during deoptimization") - @Override - public void doRelockObject(Object obj, Object lockData) { - } - - @Override - public boolean isLockedByCurrentThread(Object obj) { - /* - * Since monitorenter and monitorexit are no-ops, we do not know the real answer. But since - * the current thread has exclusive access to the object, true is a correct answer. Callers - * of isLockedByCurrentThread usually want to ensure that synchronization has occurred, - * i.e., assert that the returned value is true. - */ - return true; - } - - @Override - public boolean isLockedByAnyThread(Object obj) { - return isLockedByCurrentThread(obj); - } - - @Override - protected void doWait(Object obj, long timeoutMillis) throws InterruptedException { - /* - * There is no other thread that can interrupt waiting, so it is just sleeping. It is - * questionable whether this implementation is useful, especially waiting without a timeout. - * But it is the best thing we can do. - */ - Thread.sleep(timeoutMillis == 0 ? Long.MAX_VALUE : timeoutMillis); - } - - @Override - public void notify(Object obj, boolean notifyAll) { - /* No other thread can be waiting, so notify is a no-op. */ - return; - } - - @Override - public int getParkedThreadStatus(Thread thread, boolean timed) { - return timed ? ThreadStatus.PARKED_TIMED : ThreadStatus.PARKED; - } -} From 22cc05e7729445c22e6855d776eecca896bb8d0a Mon Sep 17 00:00:00 2001 From: Codrut Stancu Date: Mon, 15 Jan 2024 19:05:52 +0100 Subject: [PATCH 484/593] Refactor ImageHeapScanner. --- .../graal/pointsto/heap/ImageHeapScanner.java | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/heap/ImageHeapScanner.java b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/heap/ImageHeapScanner.java index f0f850cebdfe..6694b2b98464 100644 --- a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/heap/ImageHeapScanner.java +++ b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/heap/ImageHeapScanner.java @@ -518,16 +518,16 @@ protected void onObjectReachable(ImageHeapConstant imageHeapConstant, ScanReason AnalysisType type = imageHeapConstant.getType(metaAccess); Object object = bb.getSnippetReflectionProvider().asObject(Object.class, imageHeapConstant); - try { - /* Simulated constants don't have a backing object and don't need to be processed. */ - if (object != null) { + /* Simulated constants don't have a backing object and don't need to be processed. */ + if (object != null) { + try { type.notifyObjectReachable(universe.getConcurrentAnalysisAccess(), object); + } catch (UnsupportedFeatureException e) { + /* Enhance the unsupported feature message with the object trace and rethrow. */ + StringBuilder backtrace = new StringBuilder(); + ObjectScanner.buildObjectBacktrace(bb, reason, backtrace); + throw new UnsupportedFeatureException(e.getMessage() + System.lineSeparator() + backtrace); } - } catch (UnsupportedFeatureException e) { - /* Enhance the unsupported feature message with the object trace and rethrow. */ - StringBuilder backtrace = new StringBuilder(); - ObjectScanner.buildObjectBacktrace(bb, reason, backtrace); - throw new UnsupportedFeatureException(e.getMessage() + System.lineSeparator() + backtrace); } markTypeInstantiated(objectType, reason); From 8ca4b83c9b9da37f1b1dbf4496ff82d63f16738d Mon Sep 17 00:00:00 2001 From: Codrut Stancu Date: Mon, 15 Jan 2024 19:58:35 +0100 Subject: [PATCH 485/593] Add ImageHeapConstant.getType(). --- .../com/oracle/graal/pointsto/heap/ImageHeapConstant.java | 5 +++++ .../com/oracle/graal/pointsto/heap/ImageHeapScanner.java | 6 +++--- .../hosted/ameta/AnalysisConstantReflectionProvider.java | 2 +- .../SimulateClassInitializerGraphDecoder.java | 8 ++++---- .../src/com/oracle/svm/hosted/meta/HostedMetaAccess.java | 6 ++---- .../oracle/svm/hosted/phases/SharedGraphBuilderPhase.java | 2 +- 6 files changed, 16 insertions(+), 13 deletions(-) diff --git a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/heap/ImageHeapConstant.java b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/heap/ImageHeapConstant.java index 549c87d40745..2f7f4aa43610 100644 --- a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/heap/ImageHeapConstant.java +++ b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/heap/ImageHeapConstant.java @@ -201,10 +201,15 @@ public boolean isDefaultForKind() { } @Override + @Deprecated public AnalysisType getType(MetaAccessProvider provider) { return constantData.type; } + public AnalysisType getType() { + return constantData.type; + } + @Override public Object asBoxedPrimitive() { return null; diff --git a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/heap/ImageHeapScanner.java b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/heap/ImageHeapScanner.java index 939849b0368c..41672026a734 100644 --- a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/heap/ImageHeapScanner.java +++ b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/heap/ImageHeapScanner.java @@ -515,13 +515,13 @@ protected void onObjectReachable(ImageHeapConstant imageHeapConstant, ScanReason AnalysisType objectType = metaAccess.lookupJavaType(imageHeapConstant); imageHeap.addReachableObject(objectType, imageHeapConstant); - AnalysisType type = imageHeapConstant.getType(metaAccess); + AnalysisType type = imageHeapConstant.getType(); Object object = bb.getSnippetReflectionProvider().asObject(Object.class, imageHeapConstant); type.notifyObjectReachable(universe.getConcurrentAnalysisAccess(), object); markTypeInstantiated(objectType, reason); if (imageHeapConstant instanceof ImageHeapObjectArray imageHeapArray) { - AnalysisType arrayType = imageHeapArray.getType(metaAccess); + AnalysisType arrayType = imageHeapArray.getType(); for (int idx = 0; idx < imageHeapArray.getLength(); idx++) { JavaConstant elementValue = imageHeapArray.readElementValue(idx); ArrayScan arrayScanReason = new ArrayScan(arrayType, imageHeapArray, reason, idx); @@ -663,7 +663,7 @@ protected AnalysisFuture patchInstanceField(ImageHeapInstance rece protected AnalysisFuture patchArrayElement(ImageHeapObjectArray arrayObject, int index, JavaConstant elementValue, ScanReason reason, Consumer onAnalysisModified) { AnalysisFuture task = new AnalysisFuture<>(() -> { - JavaConstant value = onArrayElementReachable(arrayObject, arrayObject.getType(metaAccess), elementValue, index, reason, onAnalysisModified); + JavaConstant value = onArrayElementReachable(arrayObject, arrayObject.getType(), elementValue, index, reason, onAnalysisModified); arrayObject.setElement(index, value); return value; }); diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/ameta/AnalysisConstantReflectionProvider.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/ameta/AnalysisConstantReflectionProvider.java index 9ba901df5171..b5e155ad4eef 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/ameta/AnalysisConstantReflectionProvider.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/ameta/AnalysisConstantReflectionProvider.java @@ -117,7 +117,7 @@ public JavaConstant unboxPrimitive(JavaConstant source) { * Unbox by reading the known single field "value", which is a primitive field of the * correct unboxed type. */ - AnalysisType type = imageHeapConstant.getType(metaAccess); + AnalysisType type = imageHeapConstant.getType(); if (BOXING_CLASSES.contains(type.getJavaClass())) { imageHeapConstant.ensureReaderInstalled(); ResolvedJavaField[] fields = type.getInstanceFields(true); diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/classinitialization/SimulateClassInitializerGraphDecoder.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/classinitialization/SimulateClassInitializerGraphDecoder.java index d757991a844c..6ab70f66725d 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/classinitialization/SimulateClassInitializerGraphDecoder.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/classinitialization/SimulateClassInitializerGraphDecoder.java @@ -304,7 +304,7 @@ private Node handleStoreIndexedNode(StoreIndexedNode node) { int idx = asIntegerOrMinusOne(node.index()); if (array != null && value != null && idx >= 0 && idx < array.getLength()) { - var componentType = array.getType(metaAccess).getComponentType(); + var componentType = array.getType().getComponentType(); if (node.elementKind().isPrimitive() || value.isNull() || componentType.isAssignableFrom(((TypedConstant) value).getType(metaAccess))) { array.setElement(idx, adaptForImageHeap(value, componentType.getStorageKind())); return null; @@ -339,8 +339,8 @@ protected boolean handleArrayCopy(ImageHeapArray source, int sourcePos, ImageHea return false; } - var sourceComponentType = source.getType(metaAccess).getComponentType(); - var destComponentType = dest.getType(metaAccess).getComponentType(); + var sourceComponentType = source.getType().getComponentType(); + var destComponentType = dest.getType().getComponentType(); if (sourceComponentType.getJavaKind() != destComponentType.getJavaKind()) { return false; } @@ -535,7 +535,7 @@ private ValueNode handleBoxNode(BoxNode node) { private ValueNode handleObjectClone(SimulateClassInitializerInlineScope countersScope, ObjectClone node) { var originalImageHeapConstant = asActiveImageHeapConstant(node.getObject()); if (originalImageHeapConstant != null) { - var type = originalImageHeapConstant.getType(metaAccess); + var type = originalImageHeapConstant.getType(); if ((originalImageHeapConstant instanceof ImageHeapArray originalArray && accumulateNewArraySize(countersScope, type, originalArray.getLength(), node.asNode())) || (type.isCloneableWithAllocation() && accumulateNewInstanceSize(countersScope, type, node.asNode()))) { var cloned = originalImageHeapConstant.forObjectClone(); diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/meta/HostedMetaAccess.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/meta/HostedMetaAccess.java index 70040834ee8e..87c83d1bd96b 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/meta/HostedMetaAccess.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/meta/HostedMetaAccess.java @@ -38,7 +38,6 @@ import com.oracle.graal.pointsto.meta.AnalysisMetaAccess; import com.oracle.svm.core.deopt.Deoptimizer; -import jdk.graal.compiler.core.common.type.TypedConstant; import jdk.vm.ci.meta.DeoptimizationAction; import jdk.vm.ci.meta.DeoptimizationReason; import jdk.vm.ci.meta.JavaConstant; @@ -58,9 +57,8 @@ public HostedType lookupJavaType(Class clazz) { @Override public HostedType lookupJavaType(JavaConstant constant) { - if (constant instanceof ImageHeapConstant) { - ResolvedJavaType type = ((TypedConstant) constant).getType(this); - return (HostedType) universe.lookup(type); + if (constant instanceof ImageHeapConstant ihc) { + return (HostedType) universe.lookup(ihc.getType()); } return (HostedType) super.lookupJavaType(constant); } diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/phases/SharedGraphBuilderPhase.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/phases/SharedGraphBuilderPhase.java index aa017bdf5f4e..b94c1f202b5b 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/phases/SharedGraphBuilderPhase.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/phases/SharedGraphBuilderPhase.java @@ -1254,7 +1254,7 @@ protected boolean checkBootstrapParameters(ResolvedJavaMethod bootstrapMethod, L } } else { if (!(bootstrapMethod.isVarArgs() && staticArguments.size() == i - 3) && staticArguments.get(i - 3) instanceof ImageHeapConstant imageHeapConstant) { - Class parameterClass = OriginalClassProvider.getJavaClass(imageHeapConstant.getType(getMetaAccess())); + Class parameterClass = OriginalClassProvider.getJavaClass(imageHeapConstant.getType()); /* * Having incompatible types here causes a ClassCastException in * MethodHandle.invoke on the bootstrap method invocation. From 07bc6b7731bb3520a0a532c601e9a3af51b708aa Mon Sep 17 00:00:00 2001 From: Codrut Stancu Date: Mon, 15 Jan 2024 21:13:42 +0100 Subject: [PATCH 486/593] Cleanup TypedConstant uses in SimulateClassInitializerGraphDecoder. --- .../SimulateClassInitializerGraphDecoder.java | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/classinitialization/SimulateClassInitializerGraphDecoder.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/classinitialization/SimulateClassInitializerGraphDecoder.java index 6ab70f66725d..9c0fce256baa 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/classinitialization/SimulateClassInitializerGraphDecoder.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/classinitialization/SimulateClassInitializerGraphDecoder.java @@ -68,7 +68,6 @@ import com.oracle.svm.hosted.fieldfolding.IsStaticFinalFieldInitializedNode; import com.oracle.svm.hosted.fieldfolding.MarkStaticFinalFieldInitializedNode; -import jdk.graal.compiler.core.common.type.TypedConstant; import jdk.graal.compiler.debug.DebugContext; import jdk.graal.compiler.graph.Node; import jdk.graal.compiler.nodes.AbstractBeginNode; @@ -305,7 +304,7 @@ private Node handleStoreIndexedNode(StoreIndexedNode node) { if (array != null && value != null && idx >= 0 && idx < array.getLength()) { var componentType = array.getType().getComponentType(); - if (node.elementKind().isPrimitive() || value.isNull() || componentType.isAssignableFrom(((TypedConstant) value).getType(metaAccess))) { + if (node.elementKind().isPrimitive() || value.isNull() || componentType.isAssignableFrom(((ImageHeapConstant) value).getType())) { array.setElement(idx, adaptForImageHeap(value, componentType.getStorageKind())); return null; } @@ -348,7 +347,7 @@ protected boolean handleArrayCopy(ImageHeapArray source, int sourcePos, ImageHea for (int i = 0; i < length; i++) { var elementValue = (JavaConstant) source.getElement(sourcePos + i); if (elementValue.isNonNull()) { - var elementValueType = ((TypedConstant) elementValue).getType(metaAccess); + var elementValueType = ((ImageHeapConstant) elementValue).getType(); if (!destComponentType.isAssignableFrom(elementValueType)) { return false; } From 19e9b846839095c177a0d157c9c28dfec35a4193 Mon Sep 17 00:00:00 2001 From: ol-automation_ww Date: Tue, 16 Jan 2024 01:35:06 +0000 Subject: [PATCH 487/593] [GR-5369] Periodic update of the Graal import. PullRequest: fastr/2880 --- vm/mx.vm/suite.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vm/mx.vm/suite.py b/vm/mx.vm/suite.py index ff1cd2e47163..07285c737e64 100644 --- a/vm/mx.vm/suite.py +++ b/vm/mx.vm/suite.py @@ -57,7 +57,7 @@ }, { "name": "fastr", - "version": "ea083f09c707b48b25d58fda6cb290187726d9f6", + "version": "30c9a306722976d566f84810269dc4e02dec9bac", "dynamic": True, "urls": [ {"url": "https://github.com/oracle/fastr.git", "kind": "git"}, From 6384078e9740cf2850a436f840798695afd4fefb Mon Sep 17 00:00:00 2001 From: Jakub Chaloupka Date: Tue, 16 Jan 2024 09:55:01 +0100 Subject: [PATCH 488/593] Shorten test method names. --- .../api/instrumentation/test/GradualInstrumentationTest.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/truffle/src/com.oracle.truffle.api.instrumentation.test/src/com/oracle/truffle/api/instrumentation/test/GradualInstrumentationTest.java b/truffle/src/com.oracle.truffle.api.instrumentation.test/src/com/oracle/truffle/api/instrumentation/test/GradualInstrumentationTest.java index b64f3b46c419..6017f3a6ca93 100644 --- a/truffle/src/com.oracle.truffle.api.instrumentation.test/src/com/oracle/truffle/api/instrumentation/test/GradualInstrumentationTest.java +++ b/truffle/src/com.oracle.truffle.api.instrumentation.test/src/com/oracle/truffle/api/instrumentation/test/GradualInstrumentationTest.java @@ -204,7 +204,7 @@ public void testProbesWithRetiredNodeReferencesAreNotDisposed() throws Interrupt * new materialized subtree are not present when the subtree is cloned during materialization. */ @Test - public void testRepeatedInstrumentationDoesNotChangeParentsInMaterializedTree() { + public void testSubTreeClonedForMaterialization() { Source source = Source.create(ID, "ROOT(MATERIALIZE_CHILD_STMT_AND_EXPR(EXPRESSION(EXPRESSION)))"); // execute first so that the next execution cannot take advantage of the "onFirstExecution" // optimization @@ -231,7 +231,7 @@ public void testRepeatedInstrumentationDoesNotChangeParentsInMaterializedTree() * subtree can lead to some nodes in the new tree not be materialized. */ @Test - public void testRepeatedInstrumentationChangesParentsInMaterializedTreeIfSubtreesAreNotCloned() { + public void testSubTreeNotClonedForMaterialization() { Source source = Source.create(ID, "ROOT(MATERIALIZE_CHILD_STMT_AND_EXPR_NC(EXPRESSION(EXPRESSION)))"); // execute first so that the next execution cannot take advantage of the "onFirstExecution" // optimization From f960ea89b48c467bb4793253f83adf1940f509e6 Mon Sep 17 00:00:00 2001 From: Patrick Date: Tue, 16 Jan 2024 11:22:28 +0100 Subject: [PATCH 489/593] Fix Uninterruptible violation --- .../src/com/oracle/svm/core/heap/Heap.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/heap/Heap.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/heap/Heap.java index 5baf9ef42a9b..4c12c4e5d552 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/heap/Heap.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/heap/Heap.java @@ -43,9 +43,9 @@ import com.oracle.svm.core.log.Log; import com.oracle.svm.core.option.RuntimeOptionKey; import com.oracle.svm.core.os.CommittedMemoryProvider; +import com.oracle.svm.core.util.VMError; import jdk.graal.compiler.api.replacements.Fold; -import jdk.graal.compiler.debug.GraalError; public abstract class Heap { @Fold @@ -146,7 +146,7 @@ public void visitLoadedClasses(Consumer> visitor) { @Uninterruptible(reason = "Called from uninterruptible code.", mayBeInlined = true) public Pointer getImageHeapStart() { - throw GraalError.unimplemented("Heap.getImageHeapStart not implemented"); + throw VMError.unimplemented("Heap.getImageHeapStart not implemented"); } /** From c43d7b81f17e41007c8d600f64e3aaacaee1c2a2 Mon Sep 17 00:00:00 2001 From: Patrick Date: Tue, 16 Jan 2024 12:29:03 +0100 Subject: [PATCH 490/593] Fix compilation error --- .../src/com/oracle/svm/core/genscavenge/HeapImpl.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/HeapImpl.java b/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/HeapImpl.java index 25818c421e3e..e640727ed231 100644 --- a/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/HeapImpl.java +++ b/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/HeapImpl.java @@ -691,7 +691,7 @@ public long getIdentityHashSalt(Object obj) { @Uninterruptible(reason = "Called from uninterruptible code.", mayBeInlined = true) public Pointer getImageHeapStart() { Pointer heapBase = (Pointer) Isolates.getHeapBase(CurrentIsolate.getIsolate()); - return heapBase.add(getImageHeapOffsetInAddressSpace()); + return heapBase.add(Heap.getHeap().getImageHeapOffsetInAddressSpace()); } private boolean printLocationInfo(Log log, Pointer ptr, boolean allowJavaHeapAccess, boolean allowUnsafeOperations) { From a8bc3bdeeb6df533757e859bf15598be14953d02 Mon Sep 17 00:00:00 2001 From: ol-automation_ww Date: Fri, 12 Jan 2024 21:09:12 +0000 Subject: [PATCH 491/593] Update truffleruby import. --- vm/mx.vm/suite.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vm/mx.vm/suite.py b/vm/mx.vm/suite.py index 51b89ece551b..84c7a0524a1e 100644 --- a/vm/mx.vm/suite.py +++ b/vm/mx.vm/suite.py @@ -49,7 +49,7 @@ }, { "name": "truffleruby", - "version": "7c5bef1358b704a5cfa67ff17c4c763d567ff9e0", + "version": "1f80340cfdfb46bb987738350d541eaf77e3b3ba", "dynamic": True, "urls": [ {"url": "https://github.com/oracle/truffleruby.git", "kind": "git"}, From cae1323b19d0f599c809bb88f2b6382f29276f04 Mon Sep 17 00:00:00 2001 From: Ondrej Tethal Date: Tue, 16 Jan 2024 14:51:51 +0000 Subject: [PATCH 492/593] [GR-21590] Update imports PullRequest: graalpython/3151 --- vm/mx.vm/suite.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vm/mx.vm/suite.py b/vm/mx.vm/suite.py index 07285c737e64..0092214808f2 100644 --- a/vm/mx.vm/suite.py +++ b/vm/mx.vm/suite.py @@ -65,7 +65,7 @@ }, { "name": "graalpython", - "version": "67b5c3646f888b05825a6b36701f6294cc76d818", + "version": "20f59532d4fb1f61ad6c36b1137d31c7ed713238", "dynamic": True, "urls": [ {"url": "https://github.com/graalvm/graalpython.git", "kind": "git"}, From 0074f542c0dfce6da5f2a74e48e1bc75c141b7ff Mon Sep 17 00:00:00 2001 From: Carlo Refice Date: Mon, 15 Jan 2024 13:21:17 +0100 Subject: [PATCH 493/593] Stackifier: always generate labeled blocks around switch statements to prevent unreachable breaks --- .../blocks/LabeledBlockGeneration.java | 39 +++++++++++++++++++ 1 file changed, 39 insertions(+) diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hightiercodegen/reconstruction/stackifier/blocks/LabeledBlockGeneration.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hightiercodegen/reconstruction/stackifier/blocks/LabeledBlockGeneration.java index ba94c507cf69..69390f3ba214 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hightiercodegen/reconstruction/stackifier/blocks/LabeledBlockGeneration.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hightiercodegen/reconstruction/stackifier/blocks/LabeledBlockGeneration.java @@ -174,6 +174,15 @@ public boolean isLabeledBlockNeeded(HIRBlock block, HIRBlock successor) { if (isLastBlockInThenBranch(block, stackifierData)) { return !isJumpingToAfterElseBranch(block, successor, stackifierData); } + if (isLastBlockInSwitchArm(block, stackifierData)) { + /* + * Always generate a labeled block around switch statements as a target for switch arms + * to jump out of. This can result in less than optimal code if all switch arms jump to + * the merge block after the switch, but determining that is tricky to do correctly + * without having knowing the order in which blocks will be lowered. + */ + return true; + } return successor.getId() != block.getId() + 1; } @@ -246,6 +255,36 @@ private static boolean isLastBlockInThenBranch(HIRBlock block, StackifierData st return false; } + /** + * Checks if the given block is the last block in one of the arms of an + * {@link IntegerSwitchNode}. + * + * Example: + * + *

    +     * switch (x) {
    +     *     case 1:
    +     *         A();
    +     *         B();
    +     *         break;
    +     * }
    +     * C();
    +     * 
    + * + * For the example above this function returns true for the basic block {@code B} and false + * otherwise. + */ + private static boolean isLastBlockInSwitchArm(HIRBlock block, StackifierData stackifierData) { + Scope scope = stackifierData.getEnclosingScope().get(block); + if (scope != null) { + HIRBlock startBlock = scope.getStartBlock(); + if (startBlock.getEndNode() instanceof IntegerSwitchNode) { + return scope.getLastBlock() == block; + } + } + return false; + } + /** * Checks if the edge from {@code block} to {@code successor} is jumping over all * {@link HIRBlock}s in the catch scope. From 3fd34720b32c6a546a90bcf97b0e9940a0494163 Mon Sep 17 00:00:00 2001 From: Tomas Zezula Date: Wed, 10 Jan 2024 13:53:08 +0100 Subject: [PATCH 494/593] [GR-51153] Added a test for linking classes by compiler. --- .../test/ClassLinkedByCompilerTest.java | 65 +++++++++++++++++++ 1 file changed, 65 insertions(+) create mode 100644 compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/truffle/test/ClassLinkedByCompilerTest.java diff --git a/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/truffle/test/ClassLinkedByCompilerTest.java b/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/truffle/test/ClassLinkedByCompilerTest.java new file mode 100644 index 000000000000..65b98032de96 --- /dev/null +++ b/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/truffle/test/ClassLinkedByCompilerTest.java @@ -0,0 +1,65 @@ +/* + * Copyright (c) 2024, 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 jdk.graal.compiler.truffle.test; + +import com.oracle.truffle.api.frame.VirtualFrame; +import com.oracle.truffle.api.nodes.RootNode; +import com.oracle.truffle.compiler.TruffleCompilationTask; +import com.oracle.truffle.runtime.OptimizedCallTarget; +import jdk.graal.compiler.truffle.TruffleCompilerImpl; +import jdk.vm.ci.meta.ResolvedJavaType; +import org.junit.Test; + +public class ClassLinkedByCompilerTest extends PartialEvaluationTest { + + @Test + public void testClassLinkedByCompiler() { + RootNode root = new RootNodeImpl(); + OptimizedCallTarget compilable = (OptimizedCallTarget) root.getCallTarget(); + TruffleCompilationTask task = newTask(); + TruffleCompilerImpl compiler = getTruffleCompiler(compilable); + ResolvedJavaType unlinked = getMetaAccess().lookupJavaType(Unlinked.class); + assertFalse("Class should not be linked before compilation.", unlinked.isLinked()); + compiler.doCompile(task, compilable, null); + assertTrue("Class must be linked during compilation.", unlinked.isLinked()); + } + + static final class RootNodeImpl extends RootNode { + + RootNodeImpl() { + super(null); + } + + public Object execute(VirtualFrame frame) { + return Unlinked.call(); + } + } + + static final class Unlinked { + static boolean call() { + return true; + } + } +} From 4148e1d996bbdf1ad4aa0393abf1fe3d8e1f9c56 Mon Sep 17 00:00:00 2001 From: Vojin Jovanovic Date: Tue, 16 Jan 2024 15:53:48 +0100 Subject: [PATCH 495/593] Fix class initializaiton error message --- .../ClassInitializationFeature.java | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/classinitialization/ClassInitializationFeature.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/classinitialization/ClassInitializationFeature.java index 4ae08fda305e..3ee6460175dd 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/classinitialization/ClassInitializationFeature.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/classinitialization/ClassInitializationFeature.java @@ -39,10 +39,6 @@ import java.util.stream.StreamSupport; import org.graalvm.collections.Pair; -import jdk.graal.compiler.graph.Node; -import jdk.graal.compiler.java.LambdaUtils; -import jdk.graal.compiler.options.OptionValues; -import jdk.graal.compiler.phases.util.Providers; import org.graalvm.nativeimage.impl.clinit.ClassInitializationTracking; import com.oracle.graal.pointsto.constraints.UnsupportedFeatureException; @@ -68,6 +64,11 @@ import com.oracle.svm.hosted.FeatureImpl.AfterAnalysisAccessImpl; import com.oracle.svm.hosted.FeatureImpl.BeforeAnalysisAccessImpl; +import jdk.graal.compiler.graph.Node; +import jdk.graal.compiler.java.LambdaUtils; +import jdk.graal.compiler.options.OptionValues; +import jdk.graal.compiler.phases.util.Providers; + @AutomaticallyRegisteredFeature public class ClassInitializationFeature implements InternalFeature { private static final String NATIVE_IMAGE_CLASS_REASON = "Native Image classes are always initialized at build time"; @@ -173,10 +174,8 @@ private Object checkImageHeapInstance(Object obj) { To fix this, include %s in your configuration. If the classes do not originate from your code, it is advised to update all library or framework dependencies to the latest version before addressing this error. """ .replaceAll("\n", System.lineSeparator()) - .formatted( - SubstrateOptionsParser.commandArgument(ClassInitializationOptions.StrictImageHeap, "+", true, false), - SubstrateOptionsParser.commandArgument(ClassInitializationOptions.ClassInitialization, proxyOrLambda ? proxyLambdaInterfaceCSV : typeName, - "initialize-at-build-time", true, false)); + .formatted(SubstrateOptionsParser.commandArgument(ClassInitializationOptions.ClassInitialization, proxyOrLambda ? proxyLambdaInterfaceCSV : typeName, + "initialize-at-build-time", true, false)); } msg += System.lineSeparator() + "The following detailed trace displays from which field in the code the object was reached."; From 7962149d7b79e1bf7d49bc6a9f1c42edd2b4ecb9 Mon Sep 17 00:00:00 2001 From: Tomas Zezula Date: Fri, 12 Jan 2024 12:27:16 +0100 Subject: [PATCH 496/593] PolyglotCachingTests asserting GC run in a subprocess. --- .../com/oracle/truffle/api/test/GCUtils.java | 11 +- .../test/polyglot/PolyglotCachingTest.java | 187 ++++++++++-------- 2 files changed, 114 insertions(+), 84 deletions(-) diff --git a/truffle/src/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/GCUtils.java b/truffle/src/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/GCUtils.java index e4ef781a97f4..3a180f8436c9 100644 --- a/truffle/src/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/GCUtils.java +++ b/truffle/src/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/GCUtils.java @@ -418,6 +418,14 @@ abstract Result analyse(Collection> references, boolean f private static final class HeapDumpAnalyser extends ReachabilityAnalyser { + /** + * The size of the buffer used for copying heap dump files is set at 16KB. This size is + * chosen to accommodate the variability in file system block sizes, which can range from + * 4KB to 16KB. The upper bound of 16KB is selected, considering that heap dumps are + * frequently large in size. + */ + private static final int BLOCK_SIZE = 16384; + private static volatile HotSpotDiagnosticMXBean hotSpotDiagnosticMBean; private static volatile Reference[] todo; @@ -472,7 +480,6 @@ Result analyse(Collection> references, boolean force, boo delete(tmpDirectory); } else if (copyHeapDump) { compress(heapDumpFile, targetFile); - System.out.println("[DEBUG] HEAP DUMP STORED: " + targetFile); delete(tmpDirectory); } } @@ -485,7 +492,7 @@ Result analyse(Collection> references, boolean force, boo private static void compress(Path src, Path target) throws IOException { try (BufferedInputStream in = new BufferedInputStream(Files.newInputStream(src)); GZIPOutputStream out = new GZIPOutputStream(new BufferedOutputStream(Files.newOutputStream(target)))) { - byte[] buffer = new byte[16384]; + byte[] buffer = new byte[BLOCK_SIZE]; while (true) { int count = in.read(buffer, 0, buffer.length); if (count < 0) { diff --git a/truffle/src/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/polyglot/PolyglotCachingTest.java b/truffle/src/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/polyglot/PolyglotCachingTest.java index b62ce6a2adc2..6a7716c0adde 100644 --- a/truffle/src/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/polyglot/PolyglotCachingTest.java +++ b/truffle/src/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/polyglot/PolyglotCachingTest.java @@ -49,6 +49,7 @@ import static org.junit.Assert.assertNotSame; import static org.junit.Assert.assertTrue; +import java.io.IOException; import java.lang.ref.WeakReference; import java.lang.reflect.Field; import java.util.ArrayList; @@ -59,6 +60,8 @@ import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicReference; +import com.oracle.truffle.api.test.SubprocessTestUtils; +import org.graalvm.nativeimage.ImageInfo; import org.graalvm.polyglot.Context; import org.graalvm.polyglot.Engine; import org.graalvm.polyglot.HostAccess; @@ -296,22 +299,23 @@ public void testParsedASTIsNotCollectedIfSourceIsAlive() { * Test that CallTargets can get collected when their source instance is not alive. */ @Test - public void testParsedASTIsCollectedIfSourceIsNotAlive() { + public void testParsedASTIsCollectedIfSourceIsNotAlive() throws Exception { Assume.assumeFalse("This test is too slow in fastdebug.", System.getProperty("java.vm.version").contains("fastdebug")); - - try (Engine engine = Engine.create()) { - for (int i = 0; i < GCUtils.GC_TEST_ITERATIONS; i++) { + runInSubprocess(() -> { + try (Engine engine = Engine.create()) { + for (int i = 0; i < GCUtils.GC_TEST_ITERATIONS; i++) { + try (Context context = Context.newBuilder().engine(engine).build()) { + Source source = Source.create(CallTargetStoringTestLanguage.ID, String.valueOf(i)); + assertEquals("foobar", context.eval(source).asString()); + assertEquals("foobar", context.eval(source).asString()); + System.gc(); + } + } try (Context context = Context.newBuilder().engine(engine).build()) { - Source source = Source.create(CallTargetStoringTestLanguage.ID, String.valueOf(i)); - assertEquals("foobar", context.eval(source).asString()); - assertEquals("foobar", context.eval(source).asString()); - System.gc(); + evalTestLanguage(context, CallTargetsFreedAssertTestLanguage.class, "", true); } } - try (Context context = Context.newBuilder().engine(engine).build()) { - evalTestLanguage(context, CallTargetsFreedAssertTestLanguage.class, "", true); - } - } + }); } /* @@ -319,34 +323,36 @@ public void testParsedASTIsCollectedIfSourceIsNotAlive() { * test for GR-35371. */ @Test - public void testParsedASTIsCollectedIfSourceIsNotAliveWithInstrumentation() { + public void testParsedASTIsCollectedIfSourceIsNotAliveWithInstrumentation() throws Exception { Assume.assumeFalse("This test is too slow in fastdebug.", System.getProperty("java.vm.version").contains("fastdebug")); - - AtomicBoolean entered = new AtomicBoolean(); - try (Engine engine = Engine.create()) { - ExecutionListener.newBuilder().expressions(true).onEnter((event) -> { - // this makes sure even some lazy initialization of some event field causes leaks - event.getLocation(); - event.getInputValues(); - event.getReturnValue(); - event.getRootName(); - event.getException(); - entered.set(true); - - }).collectExceptions(true).collectInputValues(true).collectReturnValue(true).attach(engine); - for (int i = 0; i < GCUtils.GC_TEST_ITERATIONS; i++) { + runInSubprocess(() -> { + AtomicBoolean entered = new AtomicBoolean(); + try (Engine engine = Engine.create()) { + ExecutionListener.newBuilder().expressions(true).onEnter((event) -> { + // this makes sure even some lazy initialization of some event field causes + // leaks + event.getLocation(); + event.getInputValues(); + event.getReturnValue(); + event.getRootName(); + event.getException(); + entered.set(true); + + }).collectExceptions(true).collectInputValues(true).collectReturnValue(true).attach(engine); + for (int i = 0; i < GCUtils.GC_TEST_ITERATIONS; i++) { + try (Context context = Context.newBuilder().engine(engine).build()) { + Source source = Source.create(CallTargetStoringTestLanguage.ID, String.valueOf(i)); + assertEquals("foobar", context.eval(source).asString()); + assertEquals("foobar", context.eval(source).asString()); + System.gc(); + } + } try (Context context = Context.newBuilder().engine(engine).build()) { - Source source = Source.create(CallTargetStoringTestLanguage.ID, String.valueOf(i)); - assertEquals("foobar", context.eval(source).asString()); - assertEquals("foobar", context.eval(source).asString()); - System.gc(); + evalTestLanguage(context, CallTargetsFreedAssertTestLanguage.class, "", true); } + assertTrue(entered.get()); } - try (Context context = Context.newBuilder().engine(engine).build()) { - evalTestLanguage(context, CallTargetsFreedAssertTestLanguage.class, "", true); - } - assertTrue(entered.get()); - } + }); } /* @@ -354,34 +360,36 @@ public void testParsedASTIsCollectedIfSourceIsNotAliveWithInstrumentation() { * Regression test for GR-35420. */ @Test - public void testParsedASTIsCollectedIfSourceIsNotAliveWithCopySource() { + public void testParsedASTIsCollectedIfSourceIsNotAliveWithCopySource() throws Exception { Assume.assumeFalse("This test is too slow in fastdebug.", System.getProperty("java.vm.version").contains("fastdebug")); - - AtomicBoolean entered = new AtomicBoolean(); - try (Engine engine = Engine.create()) { - ExecutionListener.newBuilder().expressions(true).onEnter((event) -> { - // this makes sure even some lazy initialization of some event field causes leaks - event.getLocation(); - event.getInputValues(); - event.getReturnValue(); - event.getRootName(); - event.getException(); - entered.set(true); - - }).collectExceptions(true).collectInputValues(true).collectReturnValue(true).attach(engine); - for (int i = 0; i < GCUtils.GC_TEST_ITERATIONS; i++) { + runInSubprocess(() -> { + AtomicBoolean entered = new AtomicBoolean(); + try (Engine engine = Engine.create()) { + ExecutionListener.newBuilder().expressions(true).onEnter((event) -> { + // this makes sure even some lazy initialization of some event field causes + // leaks + event.getLocation(); + event.getInputValues(); + event.getReturnValue(); + event.getRootName(); + event.getException(); + entered.set(true); + + }).collectExceptions(true).collectInputValues(true).collectReturnValue(true).attach(engine); + for (int i = 0; i < GCUtils.GC_TEST_ITERATIONS; i++) { + try (Context context = Context.newBuilder().engine(engine).build()) { + Source source = Source.create(CallTargetStoringCopySourceTestLanguage.ID, String.valueOf(i)); + assertEquals("foobar", context.eval(source).asString()); + assertEquals("foobar", context.eval(source).asString()); + System.gc(); + } + } try (Context context = Context.newBuilder().engine(engine).build()) { - Source source = Source.create(CallTargetStoringCopySourceTestLanguage.ID, String.valueOf(i)); - assertEquals("foobar", context.eval(source).asString()); - assertEquals("foobar", context.eval(source).asString()); - System.gc(); + evalTestLanguage(context, CallTargetsFreedAssertTestLanguage.class, "", true); } + assertTrue(entered.get()); } - try (Context context = Context.newBuilder().engine(engine).build()) { - evalTestLanguage(context, CallTargetsFreedAssertTestLanguage.class, "", true); - } - assertTrue(entered.get()); - } + }); } /* @@ -389,18 +397,19 @@ public void testParsedASTIsCollectedIfSourceIsNotAliveWithCopySource() { * collect the source together with the cached CallTargets. */ @Test - public void testSourceFreeContextStrong() { + public void testSourceFreeContextStrong() throws Exception { Assume.assumeFalse("This test is too slow in fastdebug.", System.getProperty("java.vm.version").contains("fastdebug")); - - try (Context survivingContext = Context.create()) { - for (int i = 0; i < GCUtils.GC_TEST_ITERATIONS; i++) { - Source source = Source.create(CallTargetStoringTestLanguage.ID, String.valueOf(i)); - assertEquals("foobar", survivingContext.eval(source).asString()); - assertEquals("foobar", survivingContext.eval(source).asString()); - System.gc(); + runInSubprocess(() -> { + try (Context survivingContext = Context.create()) { + for (int i = 0; i < GCUtils.GC_TEST_ITERATIONS; i++) { + Source source = Source.create(CallTargetStoringTestLanguage.ID, String.valueOf(i)); + assertEquals("foobar", survivingContext.eval(source).asString()); + assertEquals("foobar", survivingContext.eval(source).asString()); + System.gc(); + } + evalTestLanguage(survivingContext, CallTargetsFreedAssertTestLanguage.class, "", true); } - evalTestLanguage(survivingContext, CallTargetsFreedAssertTestLanguage.class, "", true); - } + }); } /* @@ -428,6 +437,20 @@ public void testSourceStrongContextFree() { } } + /** + * Executes the provided {@code runnable}, potentially in a separate process. In HotSpot, the + * {@code runnable} is executed in a separate JVM. In native-image, the {@code runnable} is + * executed within the same process. + */ + + private static void runInSubprocess(Runnable runnable) throws IOException, InterruptedException { + if (ImageInfo.inImageCode()) { + runnable.run(); + } else { + SubprocessTestUtils.newBuilder(PolyglotCachingTest.class, runnable).run(); + } + } + /* * The purpose of this set is to store objects between calls using different contexts in a * polyglot isolate. This would otherwise be very hard to do. If polyglot isolate is not used, @@ -495,20 +518,20 @@ protected Object execute(RootNode node, Env env, Object[] contextArguments, Obje * was not closed. */ @Test - public void testEngineStrongContextFree() { + public void testEngineStrongContextFree() throws Exception { Assume.assumeFalse("This test is too slow in fastdebug.", System.getProperty("java.vm.version").contains("fastdebug")); - - try (Engine engine = Engine.create()) { - GCUtils.assertObjectsCollectible((iteration) -> { - Context context = Context.newBuilder().engine(engine).build(); - context.eval(LanguageInstanceStoringTestLanguage.ID, String.valueOf(iteration)); - return context; - }); - try (Context context = Context.newBuilder().engine(engine).build()) { - evalTestLanguage(context, LanguageInstancesAssertTestLanguage.class, ""); + runInSubprocess(() -> { + try (Engine engine = Engine.create()) { + GCUtils.assertObjectsCollectible((iteration) -> { + Context context = Context.newBuilder().engine(engine).build(); + context.eval(LanguageInstanceStoringTestLanguage.ID, String.valueOf(iteration)); + return context; + }); + try (Context context = Context.newBuilder().engine(engine).build()) { + evalTestLanguage(context, LanguageInstancesAssertTestLanguage.class, ""); + } } - } - + }); } @GenerateWrapper From 84946c3b1376b542149c913dce2f7f33dbb0b426 Mon Sep 17 00:00:00 2001 From: Matthias Neugschwandtner Date: Wed, 10 Jan 2024 11:16:35 +0100 Subject: [PATCH 497/593] Randomized entry points for untrusted code --- docs/security/polyglot-sandbox.md | 8 ++++++-- sdk/CHANGELOG.md | 3 +++ 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/docs/security/polyglot-sandbox.md b/docs/security/polyglot-sandbox.md index af56eed520e6..5e160bdc72c7 100644 --- a/docs/security/polyglot-sandbox.md +++ b/docs/security/polyglot-sandbox.md @@ -464,6 +464,11 @@ Absent knowledge of the random key, the attacker cannot predict the encrypted co GraalVM blinds all immediate values and data embedded in code pages of runtime compiled guest code down to a size of four bytes. +### Randomized Function Entry Points + +A predictable code layout makes it easier for attackers to find gadgets that have been introduced, for example, via the aforementioned JIT spray attack. +While runtime compiled methods are already placed in memory that is subject to address space layout randomization (ASLR) by the operating system, GraalVM additionally pads the starting offset of functions with a random number of trap instructions. + ### Speculative Execution Attack Mitigations Speculative execution attacks such as Spectre exploit the fact that a CPU may transiently execute instructions based on branch prediction information. @@ -472,8 +477,7 @@ However, the execution may have caused side effects in the micro-architectural s For example, data may have been pulled into the cache during transient execution - a side-channel that can be read by timing data access. GraalVM protects against Spectre attacks by inserting speculative execution barrier instructions in runtime compiled guest code to prevent attackers from crafting speculative execution gadgets. -A speculative execution barrier is placed at each target of a conditional branch to stop speculative execution based on the pattern history table (Spectre V1). -Speculative execution barriers are also placed at each possible indirect branch target to stop speculative execution based on the branch target buffer (Spectre V2). +A speculative execution barrier is placed at each target of a conditional branch that is relevant to Java memory safety to stop speculative execution. ## Sharing Execution Engines diff --git a/sdk/CHANGELOG.md b/sdk/CHANGELOG.md index 8c4922462a3b..e27cf3dba7d9 100644 --- a/sdk/CHANGELOG.md +++ b/sdk/CHANGELOG.md @@ -2,6 +2,9 @@ This changelog summarizes major changes between GraalVM SDK versions. The main focus is on APIs exported by GraalVM SDK. +## Version 24.1.0 +* GR-51177 Enable random offsets of runtime compiled function entry points for the UNTRUSTED polyglot sandbox policy. + ## Version 24.0.0 * (GR-49334) Deprecated the `FileSystems#allowLanguageHomeAccess()` method and introduced `FileSystem#allowInternalResourceAccess()` as a replacement. To ensure compatibility, both methods now provide support for language homes and internal resources. * (GR-49386) Added `Value#readBuffer(long, byte[], int, int)` to enable bulk reads of buffers into byte arrays. From 7f08daff941ed8e3569bea84debd9ddd56579b91 Mon Sep 17 00:00:00 2001 From: Tomas Zezula Date: Mon, 15 Jan 2024 09:53:38 +0100 Subject: [PATCH 498/593] [GR-46114] Update JavaDocs for SandboxPolicy.UNTRUSTED. --- .../org/graalvm/polyglot/SandboxPolicy.java | 26 ++++++++++++++++--- 1 file changed, 22 insertions(+), 4 deletions(-) diff --git a/sdk/src/org.graalvm.polyglot/src/org/graalvm/polyglot/SandboxPolicy.java b/sdk/src/org.graalvm.polyglot/src/org/graalvm/polyglot/SandboxPolicy.java index 4c97248f5549..ced4388e23f5 100644 --- a/sdk/src/org.graalvm.polyglot/src/org/graalvm/polyglot/SandboxPolicy.java +++ b/sdk/src/org.graalvm.polyglot/src/org/graalvm/polyglot/SandboxPolicy.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2023, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * The Universal Permissive License (UPL), Version 1.0 @@ -227,9 +227,27 @@ public enum SandboxPolicy { * In addition to the {@link #ISOLATED} constraints, the {@code UNTRUSTED} sandbox policy adds * the following requirements: *
      - *
    • If {@link HostAccess} is not specified, the {@link HostAccess#UNTRUSTED} is used. - * Otherwise, the specified {@link HostAccess} must meet all the constraints of the - * {@link #ISOLATED} sandbox policy.
    • + *
    • If {@link HostAccess} is not explicitly specified, the {@link HostAccess#UNTRUSTED} is + * utilized. In the case where a specific {@link HostAccess} is provided, it must strictly + * adhere to all the constraints outlined in the {@link #ISOLATED} sandbox policy. Additionally, + * for UNTRUSTED, the following {@link HostAccess} options are not allowed: + *
        + *
      • Setting {@link HostAccess.Builder#allowImplementationsAnnotatedBy(Class) implementations + * of types annotated by an annotation}.
      • + *
      • Setting {@link HostAccess.Builder#allowArrayAccess(boolean) array access} to + * {@code true}.
      • + *
      • Setting {@link HostAccess.Builder#allowListAccess(boolean) list access} to + * {@code true}.
      • + *
      • Setting {@link HostAccess.Builder#allowMapAccess(boolean) map access} to + * {@code true}.
      • + *
      • Setting {@link HostAccess.Builder#allowBufferAccess(boolean) buffer access} to + * {@code true}.
      • + *
      • Setting {@link HostAccess.Builder#allowIterableAccess(boolean) iterable access} to + * {@code true}.
      • + *
      • Setting {@link HostAccess.Builder#allowIteratorAccess(boolean) iterator access} to + * {@code true}.
      • + *
      + *
    • *
    • The {@code engine.UntrustedCodeMitigation} option is preset to {@code software} if it has * not been explicitly set.
    • *
    • The {@code sandbox.MaxCPUTime}, {@code sandbox.MaxHeapMemory}, From d03ec78afbed9b8288a67f588d32ce4390b483ff Mon Sep 17 00:00:00 2001 From: Boris Spasojevic Date: Wed, 17 Jan 2024 10:23:28 +0100 Subject: [PATCH 499/593] Handle relative path issue for CPUSampler. --- .../tools/profiler/impl/CPUSamplerCLI.java | 20 +++++++++---------- .../profiler/impl/CPUSamplerInstrument.java | 15 ++++++++++++-- 2 files changed, 22 insertions(+), 13 deletions(-) diff --git a/tools/src/com.oracle.truffle.tools.profiler/src/com/oracle/truffle/tools/profiler/impl/CPUSamplerCLI.java b/tools/src/com.oracle.truffle.tools.profiler/src/com/oracle/truffle/tools/profiler/impl/CPUSamplerCLI.java index db5498b80b75..b8fa0f2f62b7 100644 --- a/tools/src/com.oracle.truffle.tools.profiler/src/com/oracle/truffle/tools/profiler/impl/CPUSamplerCLI.java +++ b/tools/src/com.oracle.truffle.tools.profiler/src/com/oracle/truffle/tools/profiler/impl/CPUSamplerCLI.java @@ -45,6 +45,8 @@ import org.graalvm.options.OptionStability; import org.graalvm.options.OptionType; import org.graalvm.options.OptionValues; +import org.graalvm.shadowed.org.json.JSONArray; +import org.graalvm.shadowed.org.json.JSONObject; import com.oracle.truffle.api.Option; import com.oracle.truffle.api.TruffleContext; @@ -52,8 +54,6 @@ import com.oracle.truffle.tools.profiler.CPUSampler; import com.oracle.truffle.tools.profiler.CPUSamplerData; import com.oracle.truffle.tools.profiler.ProfilerNode; -import org.graalvm.shadowed.org.json.JSONArray; -import org.graalvm.shadowed.org.json.JSONObject; @Option.Group(CPUSamplerInstrument.ID) class CPUSamplerCLI extends ProfilerCLI { @@ -221,8 +221,8 @@ public int[] apply(String s) { @Option(name = "SampleContextInitialization", help = "Enables sampling of code executed during context initialization", category = OptionCategory.EXPERT, stability = OptionStability.STABLE) // static final OptionKey SAMPLE_CONTEXT_INITIALIZATION = new OptionKey<>(false); - static void handleOutput(TruffleInstrument.Env env, CPUSampler sampler) { - PrintStream out = chooseOutputStream(env); + static void handleOutput(TruffleInstrument.Env env, CPUSampler sampler, String absoluteOutputPath) { + PrintStream out = chooseOutputStream(env, absoluteOutputPath); Map data = sampler.getData(); OptionValues options = env.getOptions(); switch (chooseOutput(options)) { @@ -242,12 +242,10 @@ static void handleOutput(TruffleInstrument.Env env, CPUSampler sampler) { } } - private static PrintStream chooseOutputStream(TruffleInstrument.Env env) { - OptionValues options = env.getOptions(); - final String outputPath = getOutputPath(env, options); - if (outputPath != null) { + private static PrintStream chooseOutputStream(TruffleInstrument.Env env, String absoluteOutputPath) { + if (absoluteOutputPath != null) { try { - final File file = new File(outputPath); + final File file = new File(absoluteOutputPath); new PrintStream(env.out()).println("Printing output to " + file.getAbsolutePath()); return new PrintStream(new FileOutputStream(file)); } catch (FileNotFoundException e) { @@ -257,9 +255,9 @@ private static PrintStream chooseOutputStream(TruffleInstrument.Env env) { return new PrintStream(env.out()); } - private static String getOutputPath(TruffleInstrument.Env env, OptionValues options) { + static String getOutputPath(OptionValues options) { if (OUTPUT_FILE.hasBeenSet(options)) { - return OUTPUT_FILE.getValue(env.getOptions()); + return OUTPUT_FILE.getValue(options); } if (ENABLED.getValue(options).output == Output.FLAMEGRAPH) { return DEFAULT_FLAMEGRAPH_FILE; diff --git a/tools/src/com.oracle.truffle.tools.profiler/src/com/oracle/truffle/tools/profiler/impl/CPUSamplerInstrument.java b/tools/src/com.oracle.truffle.tools.profiler/src/com/oracle/truffle/tools/profiler/impl/CPUSamplerInstrument.java index 0719cd306a90..20e85fb2fce3 100644 --- a/tools/src/com.oracle.truffle.tools.profiler/src/com/oracle/truffle/tools/profiler/impl/CPUSamplerInstrument.java +++ b/tools/src/com.oracle.truffle.tools.profiler/src/com/oracle/truffle/tools/profiler/impl/CPUSamplerInstrument.java @@ -27,6 +27,7 @@ import static com.oracle.truffle.tools.profiler.impl.CPUSamplerCLI.GATHER_HIT_TIMES; import static com.oracle.truffle.tools.profiler.impl.CPUSamplerCLI.SAMPLE_CONTEXT_INITIALIZATION; +import java.io.File; import java.lang.reflect.Method; import org.graalvm.options.OptionDescriptors; @@ -61,9 +62,17 @@ public CPUSamplerInstrument() { * @since 0.30 */ public static final String ID = "cpusampler"; + private static final ProfilerToolFactory factory = getDefaultFactory(); static final String VERSION = "0.5.0"; private CPUSampler sampler; - private static final ProfilerToolFactory factory = getDefaultFactory(); + + // Guest languages could change the working directory of the current process, + // The JVM assumes that the working directory does not change. + // When this assumption is broken relative file paths no longer work correctly. + // For this reason we save the absolute path to the output file at the very start so that we + // avoid issues of broken relative paths + // See GR-36526 for more context. + private String absoluteOutputPath; @SuppressWarnings("unchecked") private static ProfilerToolFactory getDefaultFactory() { @@ -109,6 +118,8 @@ protected void onCreate(Env env) { sampler.setGatherSelfHitTimes(options.get(GATHER_HIT_TIMES)); sampler.setSampleContextInitialization(options.get(SAMPLE_CONTEXT_INITIALIZATION)); sampler.setCollecting(true); + String outputPath = CPUSamplerCLI.getOutputPath(options); + absoluteOutputPath = (outputPath != null) ? new File(outputPath).getAbsolutePath() : null; } env.registerService(sampler); } @@ -142,7 +153,7 @@ protected void onFinalize(Env env) { OptionValues options = env.getOptions(); CPUSamplerCLI.EnableOptionData enableOptionData = options.get(CPUSamplerCLI.ENABLED); if (enableOptionData.enabled) { - CPUSamplerCLI.handleOutput(env, sampler); + CPUSamplerCLI.handleOutput(env, sampler, absoluteOutputPath); } } From f87969f403cad10ca5ae7deff747c239a370aef9 Mon Sep 17 00:00:00 2001 From: Tomas Zezula Date: Tue, 16 Jan 2024 11:08:49 +0100 Subject: [PATCH 500/593] [GR-49739] Context-bound TruffleLoggers ignore log level. --- .../api/test/polyglot/LoggingTest.java | 25 +++++++++++++++++++ .../com/oracle/truffle/api/TruffleLogger.java | 19 ++++++++++---- .../com/oracle/truffle/api/impl/Accessor.java | 2 ++ .../truffle/polyglot/EngineAccessor.java | 5 ++++ .../truffle/polyglot/PolyglotContextImpl.java | 7 ++++-- .../truffle/polyglot/PolyglotLoggers.java | 6 ++++- 6 files changed, 56 insertions(+), 8 deletions(-) diff --git a/truffle/src/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/polyglot/LoggingTest.java b/truffle/src/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/polyglot/LoggingTest.java index bc11b90d221e..58584cb4ef7e 100644 --- a/truffle/src/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/polyglot/LoggingTest.java +++ b/truffle/src/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/polyglot/LoggingTest.java @@ -1282,6 +1282,31 @@ public void testInterpreterOnlyWarning() { } } + @Test + public void testGR49739() { + AtomicReference loggerHolder = new AtomicReference<>(); + AbstractLoggingLanguage.action = (ctx, defaultLoggers) -> { + loggerHolder.set(ctx.env.getLogger("after.close")); + return false; + }; + Context.Builder contextBuilder = newContextBuilder(); + contextBuilder.option("log." + LoggingLanguageFirst.ID + ".level", "CONFIG"); + Context ctx = contextBuilder.build(); + Reference ctxRef = new WeakReference<>(ctx); + try { + ctx.eval(LoggingLanguageFirst.ID, ""); + } finally { + ctx.close(); + ctx = null; + } + GCUtils.assertGc("Context should be collected.", ctxRef); + TruffleLogger closedLogger = loggerHolder.getAndSet(null); + Assert.assertNotNull(closedLogger); + AbstractPolyglotTest.assertFails(() -> closedLogger.config("Should fail"), AssertionError.class, (e) -> { + Assert.assertTrue(e.getMessage().contains("Invalid sharing of bound TruffleLogger")); + }); + } + private static boolean hasInterpreterOnlyWarning(Iterable> log) { for (Map.Entry record : log) { String message = record.getValue(); diff --git a/truffle/src/com.oracle.truffle.api/src/com/oracle/truffle/api/TruffleLogger.java b/truffle/src/com.oracle.truffle.api/src/com/oracle/truffle/api/TruffleLogger.java index c24834a237c8..d8472c91d5a3 100644 --- a/truffle/src/com.oracle.truffle.api/src/com/oracle/truffle/api/TruffleLogger.java +++ b/truffle/src/com.oracle.truffle.api/src/com/oracle/truffle/api/TruffleLogger.java @@ -982,6 +982,7 @@ synchronized void close() { } synchronized boolean isLoggable(final String loggerName, final Level level) { + final Set toRemove = collectRemovedLevels(); if (!toRemove.isEmpty()) { reconfigure(Collections.emptyMap(), toRemove); @@ -1132,11 +1133,19 @@ private Set removeContext(Object vmObject) { private Set collectRemovedLevels() { assert Thread.holdsLock(this); - final Set toRemove = new HashSet<>(); - ContextWeakReference ref; - while ((ref = (ContextWeakReference) contextsRefQueue.poll()) != null) { - activeContexts.remove(ref); - toRemove.addAll(ref.configuredLoggers.keySet()); + Set toRemove = new HashSet<>(); + /* + * Context-bound loggers are designed to operate within a single context and should not + * be reconfigured when the context is closed or subject to garbage collection. + * Preserving the log levels after the context is closed serves the purpose of detecting + * code where the logger is misused and logs after the context closure. + */ + if (!LanguageAccessor.ENGINE.isContextBoundLogger(getSPI())) { + ContextWeakReference ref; + while ((ref = (ContextWeakReference) contextsRefQueue.poll()) != null) { + activeContexts.remove(ref); + toRemove.addAll(ref.configuredLoggers.keySet()); + } } return toRemove; } diff --git a/truffle/src/com.oracle.truffle.api/src/com/oracle/truffle/api/impl/Accessor.java b/truffle/src/com.oracle.truffle.api/src/com/oracle/truffle/api/impl/Accessor.java index d68a33908c0a..263483012b08 100644 --- a/truffle/src/com.oracle.truffle.api/src/com/oracle/truffle/api/impl/Accessor.java +++ b/truffle/src/com.oracle.truffle.api/src/com/oracle/truffle/api/impl/Accessor.java @@ -512,6 +512,8 @@ public abstract TruffleContext createInternalContext(Object sourcePolyglotLangua public abstract LogRecord createLogRecord(Object loggerCache, Level level, String loggerName, String message, String className, String methodName, Object[] parameters, Throwable thrown); + public abstract boolean isContextBoundLogger(Object loggerCache); + public abstract Object getOuterContext(Object polyglotContext); public abstract boolean isCharacterBasedSource(Object fsEngineObject, String language, String mimeType); diff --git a/truffle/src/com.oracle.truffle.polyglot/src/com/oracle/truffle/polyglot/EngineAccessor.java b/truffle/src/com.oracle.truffle.polyglot/src/com/oracle/truffle/polyglot/EngineAccessor.java index 9ec3721901a6..0236a2e86106 100644 --- a/truffle/src/com.oracle.truffle.polyglot/src/com/oracle/truffle/polyglot/EngineAccessor.java +++ b/truffle/src/com.oracle.truffle.polyglot/src/com/oracle/truffle/polyglot/EngineAccessor.java @@ -1373,6 +1373,11 @@ public LogRecord createLogRecord(Object loggerCache, Level level, String loggerN return ((PolyglotLoggers.LoggerCache) loggerCache).createLogRecord(level, loggerName, message, className, methodName, parameters, thrown); } + @Override + public boolean isContextBoundLogger(Object loggerCache) { + return ((PolyglotLoggers.LoggerCache) loggerCache).isContextBoundLogger(); + } + @Override public Object getOuterContext(Object polyglotContext) { return getOuterContext((PolyglotContextImpl) polyglotContext); diff --git a/truffle/src/com.oracle.truffle.polyglot/src/com/oracle/truffle/polyglot/PolyglotContextImpl.java b/truffle/src/com.oracle.truffle.polyglot/src/com/oracle/truffle/polyglot/PolyglotContextImpl.java index 9c9f42c9eefb..85db78735913 100644 --- a/truffle/src/com.oracle.truffle.polyglot/src/com/oracle/truffle/polyglot/PolyglotContextImpl.java +++ b/truffle/src/com.oracle.truffle.polyglot/src/com/oracle/truffle/polyglot/PolyglotContextImpl.java @@ -2843,7 +2843,10 @@ private boolean finishClose(boolean cancelOrExitOperation, boolean notifyInstrum } if (parent == null) { if (!this.config.logLevels.isEmpty()) { - EngineAccessor.LANGUAGE.configureLoggers(this, null, getAllLoggers()); + Object defaultLoggers = EngineAccessor.LANGUAGE.getDefaultLoggers(); + Object engineLoggers = engine.getEngineLoggers(); + Object[] loggersToRecompute = engineLoggers != null ? new Object[]{defaultLoggers, engineLoggers} : new Object[]{defaultLoggers}; + EngineAccessor.LANGUAGE.configureLoggers(this, null, loggersToRecompute); } if (this.config.logHandler != null && !PolyglotLoggers.haveSameTarget(this.config.logHandler, engine.logHandler)) { this.config.logHandler.close(); @@ -3653,7 +3656,7 @@ private Object[] getAllLoggers() { if (contextLoggers != null) { allLoggers.add(contextLoggers); } - return allLoggers.toArray(new Object[allLoggers.size()]); + return allLoggers.toArray(new Object[0]); } static class ContextWeakReference extends WeakReference { diff --git a/truffle/src/com.oracle.truffle.polyglot/src/com/oracle/truffle/polyglot/PolyglotLoggers.java b/truffle/src/com.oracle.truffle.polyglot/src/com/oracle/truffle/polyglot/PolyglotLoggers.java index 9a98094f7274..2d537c00b0bd 100644 --- a/truffle/src/com.oracle.truffle.polyglot/src/com/oracle/truffle/polyglot/PolyglotLoggers.java +++ b/truffle/src/com.oracle.truffle.polyglot/src/com/oracle/truffle/polyglot/PolyglotLoggers.java @@ -218,6 +218,10 @@ private LoggerCache(LogHandler handler, boolean useCurrentContext, Map= 0; i = loggerName.indexOf('.', i + 1)) { + for (int i = loggerName.indexOf('.'); i >= 0; i = loggerName.indexOf('.', i + 1)) { if (i + 1 < loggerName.length() && Character.isUpperCase(loggerName.charAt(i + 1))) { index = i + 1; break; From 064863e5f9b68792d54ef77de5adb64a24502fc1 Mon Sep 17 00:00:00 2001 From: Boris Spasojevic Date: Wed, 17 Jan 2024 10:35:44 +0100 Subject: [PATCH 501/593] Handle relative path issue for CPUTracer. --- .../tools/profiler/impl/CPUTracerCLI.java | 24 +++++++++++++++---- .../profiler/impl/CPUTracerInstrument.java | 16 +++++++++++-- .../tools/profiler/impl/ProfilerCLI.java | 21 +--------------- 3 files changed, 35 insertions(+), 26 deletions(-) diff --git a/tools/src/com.oracle.truffle.tools.profiler/src/com/oracle/truffle/tools/profiler/impl/CPUTracerCLI.java b/tools/src/com.oracle.truffle.tools.profiler/src/com/oracle/truffle/tools/profiler/impl/CPUTracerCLI.java index 937e1e2e9b90..ad5f0291cd0f 100644 --- a/tools/src/com.oracle.truffle.tools.profiler/src/com/oracle/truffle/tools/profiler/impl/CPUTracerCLI.java +++ b/tools/src/com.oracle.truffle.tools.profiler/src/com/oracle/truffle/tools/profiler/impl/CPUTracerCLI.java @@ -24,6 +24,9 @@ */ package com.oracle.truffle.tools.profiler.impl; +import java.io.File; +import java.io.FileNotFoundException; +import java.io.FileOutputStream; import java.io.PrintStream; import java.util.ArrayList; import java.util.Collection; @@ -36,12 +39,12 @@ import org.graalvm.options.OptionKey; import org.graalvm.options.OptionStability; import org.graalvm.options.OptionType; +import org.graalvm.shadowed.org.json.JSONArray; +import org.graalvm.shadowed.org.json.JSONObject; import com.oracle.truffle.api.Option; import com.oracle.truffle.api.instrumentation.TruffleInstrument; import com.oracle.truffle.tools.profiler.CPUTracer; -import org.graalvm.shadowed.org.json.JSONArray; -import org.graalvm.shadowed.org.json.JSONObject; @Option.Group(CPUTracerInstrument.ID) class CPUTracerCLI extends ProfilerCLI { @@ -101,8 +104,8 @@ public Output apply(String s) { @Option(name = "OutputFile", help = "Save output to the given file. Output is printed to standard output stream by default.", usageSyntax = "", category = OptionCategory.USER, stability = OptionStability.STABLE) // static final OptionKey OUTPUT_FILE = new OptionKey<>(""); - public static void handleOutput(TruffleInstrument.Env env, CPUTracer tracer) { - PrintStream out = chooseOutputStream(env, OUTPUT_FILE); + public static void handleOutput(TruffleInstrument.Env env, CPUTracer tracer, String absoluteOutputPath) { + PrintStream out = chooseOutputStream(env, absoluteOutputPath); switch (env.getOptions().get(OUTPUT)) { case HISTOGRAM: printTracerHistogram(out, tracer); @@ -113,6 +116,19 @@ public static void handleOutput(TruffleInstrument.Env env, CPUTracer tracer) { } } + protected static PrintStream chooseOutputStream(TruffleInstrument.Env env, String absoluteOutputPath) { + try { + if (CPUTracerCLI.OUTPUT_FILE.hasBeenSet(env.getOptions())) { + final File file = new File(absoluteOutputPath); + return new PrintStream(new FileOutputStream(file)); + } else { + return new PrintStream(env.out()); + } + } catch (FileNotFoundException e) { + throw handleFileNotFound(); + } + } + private static void printTracerJson(PrintStream out, CPUTracer tracer) { JSONObject output = new JSONObject(); output.put("tool", CPUTracerInstrument.ID); diff --git a/tools/src/com.oracle.truffle.tools.profiler/src/com/oracle/truffle/tools/profiler/impl/CPUTracerInstrument.java b/tools/src/com.oracle.truffle.tools.profiler/src/com/oracle/truffle/tools/profiler/impl/CPUTracerInstrument.java index 64f9cd30af3e..b42b975e3327 100644 --- a/tools/src/com.oracle.truffle.tools.profiler/src/com/oracle/truffle/tools/profiler/impl/CPUTracerInstrument.java +++ b/tools/src/com.oracle.truffle.tools.profiler/src/com/oracle/truffle/tools/profiler/impl/CPUTracerInstrument.java @@ -24,6 +24,7 @@ */ package com.oracle.truffle.tools.profiler.impl; +import java.io.File; import java.io.PrintStream; import java.lang.reflect.Method; @@ -58,11 +59,18 @@ public CPUTracerInstrument() { * @since 0.30 */ public static final String ID = "cputracer"; + private static final ProfilerToolFactory factory = getDefaultFactory(); static final String VERSION = "0.3.0"; private boolean enabled; private CPUTracer tracer; - private static final ProfilerToolFactory factory = getDefaultFactory(); + // Guest languages could change the working directory of the current process, + // The JVM assumes that the working directory does not change. + // When this assumption is broken relative file paths no longer work correctly. + // For this reason we save the absolute path to the output file at the very start so that we + // avoid issues of broken relative paths + // See GR-36526 for more context. + String absoluteOutputPath; @SuppressWarnings("unchecked") private static ProfilerToolFactory getDefaultFactory() { @@ -111,6 +119,10 @@ protected void onCreate(Env env) { return; } tracer.setCollecting(true); + if (CPUTracerCLI.OUTPUT_FILE.hasBeenSet(env.getOptions())) { + final String outputPath = CPUTracerCLI.OUTPUT_FILE.getValue(env.getOptions()); + absoluteOutputPath = new File(outputPath).getAbsolutePath(); + } } env.registerService(tracer); } @@ -145,7 +157,7 @@ protected OptionDescriptors getOptionDescriptors() { @Override protected void onFinalize(Env env) { if (enabled) { - CPUTracerCLI.handleOutput(env, tracer); + CPUTracerCLI.handleOutput(env, tracer, absoluteOutputPath); } } diff --git a/tools/src/com.oracle.truffle.tools.profiler/src/com/oracle/truffle/tools/profiler/impl/ProfilerCLI.java b/tools/src/com.oracle.truffle.tools.profiler/src/com/oracle/truffle/tools/profiler/impl/ProfilerCLI.java index b01f78ffefcb..350f15202203 100644 --- a/tools/src/com.oracle.truffle.tools.profiler/src/com/oracle/truffle/tools/profiler/impl/ProfilerCLI.java +++ b/tools/src/com.oracle.truffle.tools.profiler/src/com/oracle/truffle/tools/profiler/impl/ProfilerCLI.java @@ -25,9 +25,6 @@ package com.oracle.truffle.tools.profiler.impl; import java.io.File; -import java.io.FileNotFoundException; -import java.io.FileOutputStream; -import java.io.PrintStream; import java.nio.file.Path; import java.nio.file.Paths; import java.util.ArrayList; @@ -36,15 +33,13 @@ import java.util.function.Predicate; import java.util.regex.Pattern; -import org.graalvm.options.OptionKey; +import org.graalvm.shadowed.org.json.JSONObject; import com.oracle.truffle.api.exception.AbstractTruffleException; import com.oracle.truffle.api.instrumentation.SourceSectionFilter; import com.oracle.truffle.api.instrumentation.StandardTags; -import com.oracle.truffle.api.instrumentation.TruffleInstrument; import com.oracle.truffle.api.source.Source; import com.oracle.truffle.api.source.SourceSection; -import org.graalvm.shadowed.org.json.JSONObject; abstract class ProfilerCLI { @@ -237,20 +232,6 @@ public int hashCode() { } } - protected static PrintStream chooseOutputStream(TruffleInstrument.Env env, OptionKey option) { - try { - if (option.hasBeenSet(env.getOptions())) { - final String outputPath = option.getValue(env.getOptions()); - final File file = new File(outputPath); - return new PrintStream(new FileOutputStream(file)); - } else { - return new PrintStream(env.out()); - } - } catch (FileNotFoundException e) { - throw handleFileNotFound(); - } - } - protected static AbstractTruffleException handleFileNotFound() { return new AbstractTruffleException() { static final long serialVersionUID = -1; From 6bddbc9423c66b2e7907b91ef964cdd879661da0 Mon Sep 17 00:00:00 2001 From: Boris Spasojevic Date: Wed, 17 Jan 2024 10:50:34 +0100 Subject: [PATCH 502/593] Handle relative path error for Coverage. --- .../coverage/impl/CoverageInstrument.java | 20 ++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) diff --git a/tools/src/com.oracle.truffle.tools.coverage/src/com/oracle/truffle/tools/coverage/impl/CoverageInstrument.java b/tools/src/com.oracle.truffle.tools.coverage/src/com/oracle/truffle/tools/coverage/impl/CoverageInstrument.java index 715faef9e829..33222654376b 100644 --- a/tools/src/com.oracle.truffle.tools.coverage/src/com/oracle/truffle/tools/coverage/impl/CoverageInstrument.java +++ b/tools/src/com.oracle.truffle.tools.coverage/src/com/oracle/truffle/tools/coverage/impl/CoverageInstrument.java @@ -108,6 +108,14 @@ public Output apply(String s) { private CoverageTracker tracker; private Boolean enabled; + // Guest languages could change the working directory of the current process, + // The JVM assumes that the working directory does not change. + // When this assumption is broken relative file paths no longer work correctly. + // For this reason we save the absolute path to the output file at the very start so that we + // avoid issues of broken relative paths + // See GR-36526 for more context. + private String absoluteOutputPath; + public static CoverageTracker getTracker(Engine engine) { Instrument instrument = engine.getInstruments().get(ID); if (instrument == null) { @@ -123,11 +131,10 @@ public static void setFactory(Function factory) { CoverageInstrument.factory = factory; } - protected static PrintStream chooseOutputStream(TruffleInstrument.Env env, OptionKey option) { + protected static PrintStream chooseOutputStream(Env env, String absoluteOutputPath) { try { - if (option.hasBeenSet(env.getOptions())) { - final String outputPath = option.getValue(env.getOptions()); - final File file = new File(outputPath); + if (CoverageInstrument.OUTPUT_FILE.hasBeenSet(env.getOptions())) { + final File file = new File(absoluteOutputPath); new PrintStream(env.out()).println("Printing output to " + file.getAbsolutePath()); return new PrintStream(new FileOutputStream(file)); } else { @@ -171,6 +178,9 @@ protected void onCreate(Env env) { enabled = ENABLED.getValue(options); if (enabled) { tracker.start(new CoverageTracker.Config(getSourceSectionFilter(options), Count.getValue(options))); + if (CoverageInstrument.OUTPUT_FILE.hasBeenSet(env.getOptions())) { + absoluteOutputPath = new File(CoverageInstrument.OUTPUT_FILE.getValue(env.getOptions())).getAbsolutePath(); + } } } @@ -180,7 +190,7 @@ protected void onFinalize(Env env) { SourceCoverage[] coverage = tracker.getCoverage(); final OptionValues options = env.getOptions(); final boolean strictLines = StrictLines.getValue(options); - PrintStream out = chooseOutputStream(env, OUTPUT_FILE); + PrintStream out = chooseOutputStream(env, absoluteOutputPath); switch (OUTPUT.getValue(options)) { case HISTOGRAM: new CoverageCLI(out, coverage, strictLines).printHistogramOutput(); From 8c4314dfb7512581e242017f6f79b1cd740fdab9 Mon Sep 17 00:00:00 2001 From: Boris Spasojevic Date: Wed, 17 Jan 2024 11:02:22 +0100 Subject: [PATCH 503/593] Improve java doc for UnknownObjectField and UnknownPrimitiveField. --- .../src/com/oracle/svm/core/heap/UnknownObjectField.java | 4 ++++ .../com/oracle/svm/core/heap/UnknownPrimitiveField.java | 8 +++++++- 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/heap/UnknownObjectField.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/heap/UnknownObjectField.java index 2c719934b729..5da2dbbdb46e 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/heap/UnknownObjectField.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/heap/UnknownObjectField.java @@ -40,6 +40,10 @@ * * It is assumed that a field of type c may hold a reference to any subtype of c. It is also assumed * that any subtype of c is instantiated. + * + * This annotation is only necessary during the image build. It prevents the static analysis from + * wrongly constant-folding a value that is initialized late during the image build and therefore + * not available during analysis. */ @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.FIELD) diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/heap/UnknownPrimitiveField.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/heap/UnknownPrimitiveField.java index 8e9261066ed7..bd24dfaa4126 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/heap/UnknownPrimitiveField.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/heap/UnknownPrimitiveField.java @@ -35,7 +35,13 @@ import com.oracle.svm.core.BuildPhaseProvider.AfterAnalysis; -/** For fields with this annotation no static analysis is done. */ +/** + * For fields with this annotation no static analysis is done. + * + * This annotation is only necessary during the image build. It prevents the static analysis from + * wrongly constant-folding a value that is initialized late during the image build and therefore + * not available during analysis. + */ @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.FIELD) @Platforms(Platform.HOSTED_ONLY.class) From 0e831b341b5d345b57da904da896a70b4e5b68a6 Mon Sep 17 00:00:00 2001 From: Fabio Niephaus Date: Wed, 17 Jan 2024 11:05:20 +0100 Subject: [PATCH 504/593] Remove pending analysis operations message. --- .../src/com/oracle/graal/pointsto/AbstractAnalysisEngine.java | 1 - 1 file changed, 1 deletion(-) diff --git a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/AbstractAnalysisEngine.java b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/AbstractAnalysisEngine.java index 4deb02bf6041..bbf510b6a0cd 100644 --- a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/AbstractAnalysisEngine.java +++ b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/AbstractAnalysisEngine.java @@ -186,7 +186,6 @@ public void runAnalysis(DebugContext debugContext, Function 0; if (pendingOperations) { - System.out.println("Found pending operations, continuing analysis."); continue; } /* Outer analysis loop is done. Check if heap verification modifies analysis. */ From e0209328be9e961b08bd17d0c1e682b7253fb9f4 Mon Sep 17 00:00:00 2001 From: Patrick Date: Wed, 17 Jan 2024 13:26:17 +0100 Subject: [PATCH 505/593] Remove deprecated TemporaryWorkdirMixin There is one in `mx_benchmark` that should be used and this class is not used anywhere in the graal codebase --- .../mx.java-benchmarks/mx_java_benchmarks.py | 55 +------------------ 1 file changed, 1 insertion(+), 54 deletions(-) diff --git a/java-benchmarks/mx.java-benchmarks/mx_java_benchmarks.py b/java-benchmarks/mx.java-benchmarks/mx_java_benchmarks.py index 40d5e229eb59..ac30a27444cb 100644 --- a/java-benchmarks/mx.java-benchmarks/mx_java_benchmarks.py +++ b/java-benchmarks/mx.java-benchmarks/mx_java_benchmarks.py @@ -1,5 +1,5 @@ # -# Copyright (c) 2018, 2023, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2018, 2024, 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 @@ -110,20 +110,6 @@ def createBenchmarkShortcut(benchSuite, args): return mx_benchmark.benchmark([benchSuite + ":" + benchname] + remaining_args) -def _create_temporary_workdir_parser(): - parser = argparse.ArgumentParser(add_help=False, usage=mx_benchmark._mx_benchmark_usage_example + " -- -- ...") - group = parser.add_mutually_exclusive_group() - group.add_argument("--keep-scratch", action="store_true", help="Do not delete scratch directory after benchmark execution.") - group.add_argument("--no-scratch", action="store_true", help="Do not execute benchmark in scratch directory.") - return parser - - -mx_benchmark.parsers["temporary_workdir_parser"] = ParserEntry( - _create_temporary_workdir_parser(), - "\n\nFlags for benchmark suites with temporary working directories:\n" -) - - # Adds a java VM from JAVA_HOME without any assumption about it mx_benchmark.add_java_vm(mx_benchmark.DefaultJavaVm('java-home', 'default'), _suite, 1) @@ -132,45 +118,6 @@ def java_home_jdk(): return mx.get_jdk() -class TemporaryWorkdirMixin(mx_benchmark.VmBenchmarkSuite): - def before(self, bmSuiteArgs): - parser = mx_benchmark.parsers["temporary_workdir_parser"].parser - bmArgs, otherArgs = parser.parse_known_args(bmSuiteArgs) - self.keepScratchDir = bmArgs.keep_scratch - if not bmArgs.no_scratch: - self._create_tmp_workdir() - else: - mx.warn("NO scratch directory created! (--no-scratch)") - self.workdir = None - super(TemporaryWorkdirMixin, self).before(otherArgs) - - def _create_tmp_workdir(self): - mx.log_deprecation("mx_java_benchmarks.mx_benchmark.TemporaryWorkdirMixin is deprecated. Use mx_benchmark.mx_benchmark.TemporaryWorkdirMixin instead.") - self.workdir = mkdtemp(prefix=self.name() + '-work.', dir='.') - - def workingDirectory(self, benchmarks, bmSuiteArgs): - return self.workdir - - def after(self, bmSuiteArgs): - if hasattr(self, "keepScratchDir") and self.keepScratchDir: - mx.warn("Scratch directory NOT deleted (--keep-scratch): {0}".format(self.workdir)) - elif self.workdir: - rmtree(self.workdir) - super(TemporaryWorkdirMixin, self).after(bmSuiteArgs) - - def repairDatapointsAndFail(self, benchmarks, bmSuiteArgs, partialResults, message): - try: - super(TemporaryWorkdirMixin, self).repairDatapointsAndFail(benchmarks, bmSuiteArgs, partialResults, message) - finally: - if self.workdir: - # keep old workdir for investigation, create a new one for further benchmarking - mx.warn("Keeping scratch directory after failed benchmark: {0}".format(self.workdir)) - self._create_tmp_workdir() - - def parserNames(self): - return super(TemporaryWorkdirMixin, self).parserNames() + ["temporary_workdir_parser"] - - class BaseMicroserviceBenchmarkSuite(mx_benchmark.BenchmarkSuite): def group(self): return "Graal" From e0e67dd0c59a296dc888f1ae66abdb6ff16c13fe Mon Sep 17 00:00:00 2001 From: Patrick Date: Wed, 17 Jan 2024 13:27:36 +0100 Subject: [PATCH 506/593] Remove python2 code in mx_java_benchmarks --- .../mx.java-benchmarks/mx_java_benchmarks.py | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) diff --git a/java-benchmarks/mx.java-benchmarks/mx_java_benchmarks.py b/java-benchmarks/mx.java-benchmarks/mx_java_benchmarks.py index ac30a27444cb..22bea937c151 100644 --- a/java-benchmarks/mx.java-benchmarks/mx_java_benchmarks.py +++ b/java-benchmarks/mx.java-benchmarks/mx_java_benchmarks.py @@ -43,16 +43,12 @@ _suite = mx.suite('java-benchmarks') -if sys.version_info[0] < 3: - from ConfigParser import ConfigParser - from StringIO import StringIO - def _configparser_read_file(configp, fp): - configp.readfp(fp) -else: - from configparser import ConfigParser - from io import StringIO - def _configparser_read_file(configp, fp): - configp.read_file(fp) +from configparser import ConfigParser +from io import StringIO + + +def _configparser_read_file(configp, fp): + configp.read_file(fp) # Short-hand commands used to quickly run common benchmarks. From 94ba60868fdfdeb39d3992d225aeab2cd98dd15d Mon Sep 17 00:00:00 2001 From: Patrick Date: Wed, 17 Jan 2024 14:20:13 +0100 Subject: [PATCH 507/593] Remove repairDatapoints The repaired datapoints are never used, functionality will be removed from mx --- .../mx.java-benchmarks/mx_java_benchmarks.py | 42 ------------------- 1 file changed, 42 deletions(-) diff --git a/java-benchmarks/mx.java-benchmarks/mx_java_benchmarks.py b/java-benchmarks/mx.java-benchmarks/mx_java_benchmarks.py index 22bea937c151..360f657355f4 100644 --- a/java-benchmarks/mx.java-benchmarks/mx_java_benchmarks.py +++ b/java-benchmarks/mx.java-benchmarks/mx_java_benchmarks.py @@ -669,48 +669,6 @@ def createCommandLineArgs(self, benchmarks, bmSuiteArgs): self.vmArgs(bmSuiteArgs) + ["-jar"] + [self.daCapoPath()] + [benchmarks[0]] + runArgs) - def repairDatapoints(self, benchmarks, bmSuiteArgs, partialResults): - parser = argparse.ArgumentParser(add_help=False) - parser.add_argument("-n", "--iterations", default=None) - args, _ = parser.parse_known_args(self.runArgs(bmSuiteArgs)) - if args.iterations and args.iterations.isdigit(): - iterations = int(args.iterations) - else: - iterations = self.daCapoIterations()[benchmarks[0]] - iterations = iterations + self.getExtraIterationCount(iterations) - for i in range(0, iterations): - if next((p for p in partialResults if p["metric.iteration"] == i), None) is None: - datapoint = { - "benchmark": benchmarks[0], - "bench-suite": self.benchSuiteName(), - "vm": "jvmci", - "config.name": "default", - "config.vm-flags": self.shorten_vm_flags(self.vmArgs(bmSuiteArgs)), - "metric.name": "warmup", - "metric.value": -1, - "metric.unit": "ms", - "metric.type": "numeric", - "metric.score-function": "id", - "metric.better": "lower", - "metric.iteration": i - } - partialResults.append(datapoint) - datapoint = { - "benchmark": benchmarks[0], - "bench-suite": self.benchSuiteName(), - "vm": "jvmci", - "config.name": "default", - "config.vm-flags": self.shorten_vm_flags(self.vmArgs(bmSuiteArgs)), - "metric.name": "time", - "metric.value": -1, - "metric.unit": "ms", - "metric.type": "numeric", - "metric.score-function": "id", - "metric.better": "lower", - "metric.iteration": 0 - } - partialResults.append(datapoint) - def benchmarkList(self, bmSuiteArgs): missing_sizes = set(self.daCapoIterations().keys()).difference(set(self.daCapoSizes().keys())) if len(missing_sizes) > 0: From ed00168772aa46f29b924d8bebbff2de5b9ae411 Mon Sep 17 00:00:00 2001 From: Peter Hofer Date: Thu, 11 Jan 2024 22:37:53 +0100 Subject: [PATCH 508/593] Image heap provider fixes and cleanups. --- .../posix/linux/LinuxImageHeapProvider.java | 74 ++++++------------- ...micMethodAddressResolutionHeapSupport.java | 27 +------ .../os/AbstractCopyingImageHeapProvider.java | 69 +++++++++-------- .../core/os/AbstractImageHeapProvider.java | 28 ++++++- 4 files changed, 84 insertions(+), 114 deletions(-) diff --git a/substratevm/src/com.oracle.svm.core.posix/src/com/oracle/svm/core/posix/linux/LinuxImageHeapProvider.java b/substratevm/src/com.oracle.svm.core.posix/src/com/oracle/svm/core/posix/linux/LinuxImageHeapProvider.java index a83423b7a6ba..70a546c3339a 100644 --- a/substratevm/src/com.oracle.svm.core.posix/src/com/oracle/svm/core/posix/linux/LinuxImageHeapProvider.java +++ b/substratevm/src/com.oracle.svm.core.posix/src/com/oracle/svm/core/posix/linux/LinuxImageHeapProvider.java @@ -90,32 +90,15 @@ public class LinuxImageHeapProvider extends AbstractImageHeapProvider { private static final SignedWord UNASSIGNED_FD = signed(-1); private static final SignedWord CANNOT_OPEN_FD = signed(-2); private static final CGlobalData CACHED_IMAGE_FD = CGlobalDataFactory.createWord(UNASSIGNED_FD); - private static final CGlobalData CACHED_IMAGE_HEAP_OFFSET = CGlobalDataFactory.createWord(); + private static final CGlobalData CACHED_IMAGE_HEAP_OFFSET_IN_FILE = CGlobalDataFactory.createWord(); + + private static final int MAX_PATHLEN = 4096; @Override public boolean guaranteesHeapPreferredAddressSpaceAlignment() { return true; } - @Override - @Uninterruptible(reason = "Called from uninterruptible code.", mayBeInlined = true) - protected UnsignedWord getImageHeapAddressSpaceSize() { - int imageHeapOffset = Heap.getHeap().getImageHeapOffsetInAddressSpace(); - assert imageHeapOffset >= 0; - UnsignedWord size = WordFactory.unsigned(imageHeapOffset); - size = size.add(getImageHeapSizeInFile(IMAGE_HEAP_BEGIN.get(), IMAGE_HEAP_END.get())); - return size; - } - - @Uninterruptible(reason = "Called from uninterruptible code.", mayBeInlined = true) - protected UnsignedWord getTotalRequiredAddressSpaceSize() { - UnsignedWord size = getImageHeapAddressSpaceSize(); - if (DynamicMethodAddressResolutionHeapSupport.isEnabled()) { - size = size.add(DynamicMethodAddressResolutionHeapSupport.get().getDynamicMethodAddressResolverPreHeapMemoryBytes()); - } - return size; - } - @Override @Uninterruptible(reason = "Called during isolate initialization.") public int initialize(Pointer reservedAddressSpace, UnsignedWord reservedSize, WordPointer basePointer, WordPointer endPointer) { @@ -135,7 +118,7 @@ public int initialize(Pointer reservedAddressSpace, UnsignedWord reservedSize, W Pointer heapBase; Pointer selfReservedHeapBase; if (DynamicMethodAddressResolutionHeapSupport.isEnabled()) { - UnsignedWord preHeapRequiredBytes = DynamicMethodAddressResolutionHeapSupport.get().getDynamicMethodAddressResolverPreHeapMemoryBytes(); + UnsignedWord preHeapRequiredBytes = getPreHeapAlignedSizeForDynamicMethodAddressResolver(); if (selfReservedMemory.isNonNull()) { selfReservedHeapBase = selfReservedMemory.add(preHeapRequiredBytes); heapBase = selfReservedHeapBase; @@ -143,7 +126,6 @@ public int initialize(Pointer reservedAddressSpace, UnsignedWord reservedSize, W heapBase = reservedAddressSpace.add(preHeapRequiredBytes); selfReservedHeapBase = WordFactory.nullPointer(); } - assert heapBase.isNonNull(); remainingSize = remainingSize.subtract(preHeapRequiredBytes); int error = DynamicMethodAddressResolutionHeapSupport.get().initialize(); @@ -152,8 +134,7 @@ public int initialize(Pointer reservedAddressSpace, UnsignedWord reservedSize, W return error; } - Pointer installOffset = heapBase.subtract(DynamicMethodAddressResolutionHeapSupport.get().getRequiredPreHeapMemoryInBytes()); - error = DynamicMethodAddressResolutionHeapSupport.get().install(installOffset); + error = DynamicMethodAddressResolutionHeapSupport.get().install(heapBase); if (error != CEntryPointErrors.NO_ERROR) { freeImageHeap(selfReservedHeapBase); return error; @@ -165,10 +146,10 @@ public int initialize(Pointer reservedAddressSpace, UnsignedWord reservedSize, W int imageHeapOffsetInAddressSpace = Heap.getHeap().getImageHeapOffsetInAddressSpace(); basePointer.write(heapBase); - Pointer firstBase = heapBase.add(imageHeapOffsetInAddressSpace); + Pointer imageHeapStart = heapBase.add(imageHeapOffsetInAddressSpace); remainingSize = remainingSize.subtract(imageHeapOffsetInAddressSpace); - int result = initializeImageHeap(firstBase, remainingSize, endPointer, - CACHED_IMAGE_FD.get(), CACHED_IMAGE_HEAP_OFFSET.get(), MAGIC.get(), + int result = initializeImageHeap(imageHeapStart, remainingSize, endPointer, + CACHED_IMAGE_FD.get(), CACHED_IMAGE_HEAP_OFFSET_IN_FILE.get(), MAGIC.get(), IMAGE_HEAP_BEGIN.get(), IMAGE_HEAP_END.get(), IMAGE_HEAP_RELOCATABLE_BEGIN.get(), IMAGE_HEAP_A_RELOCATABLE_POINTER.get(), IMAGE_HEAP_RELOCATABLE_END.get(), IMAGE_HEAP_WRITABLE_BEGIN.get(), IMAGE_HEAP_WRITABLE_END.get()); @@ -179,7 +160,7 @@ public int initialize(Pointer reservedAddressSpace, UnsignedWord reservedSize, W } @Uninterruptible(reason = "Called during isolate initialization.") - private int initializeImageHeap(Pointer imageHeap, UnsignedWord reservedSize, WordPointer endPointer, WordPointer cachedFd, WordPointer cachedOffset, + private int initializeImageHeap(Pointer imageHeap, UnsignedWord reservedSize, WordPointer endPointer, WordPointer cachedFd, WordPointer cachedOffsetInFile, Pointer magicAddress, Word heapBeginSym, Word heapEndSym, Word heapRelocsSym, Pointer heapAnyRelocPointer, Word heapRelocsEndSym, Word heapWritableSym, Word heapWritableEndSym) { assert heapBeginSym.belowOrEqual(heapWritableSym) && heapWritableSym.belowOrEqual(heapWritableEndSym) && heapWritableEndSym.belowOrEqual(heapEndSym); assert heapBeginSym.belowOrEqual(heapRelocsSym) && heapRelocsSym.belowOrEqual(heapRelocsEndSym) && heapRelocsEndSym.belowOrEqual(heapEndSym); @@ -193,7 +174,7 @@ private int initializeImageHeap(Pointer imageHeap, UnsignedWord reservedSize, Wo * step to avoid stalling threads. */ if (fd.equal(UNASSIGNED_FD)) { - int opened = openImageFile(cachedOffset, heapBeginSym, heapRelocsSym, magicAddress); + int opened = openImageFile(heapBeginSym, magicAddress, cachedOffsetInFile); SignedWord previous = ((Pointer) cachedFd).compareAndSwapWord(0, fd, signed(opened), LocationIdentity.ANY_LOCATION); if (previous.equal(fd)) { fd = signed(opened); @@ -221,7 +202,7 @@ private int initializeImageHeap(Pointer imageHeap, UnsignedWord reservedSize, Wo } // Create memory mappings from the image file. - UnsignedWord fileOffset = cachedOffset.read(); + UnsignedWord fileOffset = cachedOffsetInFile.read(); imageHeap = VirtualMemoryProvider.get().mapFile(imageHeap, imageHeapSize, fd, fileOffset, Access.READ); if (imageHeap.isNull()) { return CEntryPointErrors.MAP_HEAP_FAILED; @@ -232,8 +213,8 @@ private int initializeImageHeap(Pointer imageHeap, UnsignedWord reservedSize, Wo ComparableWord mappedValue = imageHeap.readWord(heapAnyRelocPointer.subtract(heapBeginSym)); if (relocatedValue.notEqual(mappedValue)) { /* - * Addresses were relocated by dynamic linker, so copy them, but first remap the - * pages to avoid swapping them in from disk. + * Addresses were relocated by the dynamic linker, so copy them, but first remap the + * pages as anonymous memory to avoid swapping in part of the image from disk. */ Pointer relocsBegin = imageHeap.add(heapRelocsSym.subtract(heapBeginSym)); UnsignedWord relocsSize = heapRelocsEndSym.subtract(heapRelocsSym); @@ -283,27 +264,24 @@ private static int initializeImageHeapByCopying(Pointer imageHeap, Word heapBegi /** * Locate our image file, containing the image heap. Unfortunately we must open it by its path. - * - * NOTE: we look for the relocatables partition of the linker-mapped heap because it always - * stays mapped, while the rest of the linker-mapped heap can be unmapped after tearing down the - * first isolate. We do not use /proc/self/exe because it breaks with some tools like Valgrind. + * We do not use /proc/self/exe because it breaks with some tools like Valgrind. */ @Uninterruptible(reason = "Called during isolate initialization.") - private static int openImageFile(WordPointer cachedOffset, Word heapBeginSym, Word heapRelocsSym, Pointer magicAddress) { + private static int openImageFile(Word heapBeginSym, Pointer magicAddress, WordPointer cachedImageHeapOffsetInFile) { final int failfd = (int) CANNOT_OPEN_FD.rawValue(); int mapfd = Fcntl.NoTransitions.open(PROC_SELF_MAPS.get(), Fcntl.O_RDONLY(), 0); if (mapfd == -1) { return failfd; } - final int bufferSize = 4096; // assumed MAX_PATHLEN + final int bufferSize = MAX_PATHLEN; CCharPointer buffer = StackValue.get(bufferSize); // The relocatables partition might stretch over two adjacent mappings due to permission // differences, so only locate the mapping for the first page of relocatables UnsignedWord pageSize = VirtualMemoryProvider.get().getGranularity(); - WordPointer relocsMappingStart = StackValue.get(WordPointer.class); - WordPointer relocsMappingFileOffset = StackValue.get(WordPointer.class); - boolean found = findMapping(mapfd, buffer, bufferSize, heapRelocsSym, heapRelocsSym.add(pageSize), relocsMappingStart, relocsMappingFileOffset, true); + WordPointer imageHeapMappingStart = StackValue.get(WordPointer.class); + WordPointer imageHeapMappingFileOffset = StackValue.get(WordPointer.class); + boolean found = findMapping(mapfd, buffer, bufferSize, heapBeginSym, heapBeginSym.add(pageSize), imageHeapMappingStart, imageHeapMappingFileOffset, true); if (!found) { Unistd.NoTransitions.close(mapfd); return failfd; @@ -321,10 +299,9 @@ private static int openImageFile(WordPointer cachedOffset, Word heapBeginSym, Wo return failfd; } - Word imageHeapRelocsOffset = heapRelocsSym.subtract(heapBeginSym); - Word imageHeapOffset = heapRelocsSym.subtract(relocsMappingStart.read()).subtract(imageHeapRelocsOffset); - UnsignedWord fileOffset = imageHeapOffset.add(relocsMappingFileOffset.read()); - cachedOffset.write(fileOffset); + Word imageHeapOffsetInMapping = heapBeginSym.subtract(imageHeapMappingStart.read()); + UnsignedWord imageHeapOffsetInFile = imageHeapOffsetInMapping.add(imageHeapMappingFileOffset.read()); + cachedImageHeapOffsetInFile.write(imageHeapOffsetInFile); return opened; } @@ -368,7 +345,7 @@ public int freeImageHeap(PointerBase heapBase) { UnsignedWord totalAddressSpaceSize = getTotalRequiredAddressSpaceSize(); Pointer addressSpaceStart = (Pointer) heapBase; if (DynamicMethodAddressResolutionHeapSupport.isEnabled()) { - UnsignedWord preHeapRequiredBytes = DynamicMethodAddressResolutionHeapSupport.get().getDynamicMethodAddressResolverPreHeapMemoryBytes(); + UnsignedWord preHeapRequiredBytes = getPreHeapAlignedSizeForDynamicMethodAddressResolver(); addressSpaceStart = addressSpaceStart.subtract(preHeapRequiredBytes); } if (VirtualMemoryProvider.get().free(addressSpaceStart, totalAddressSpaceSize) != 0) { @@ -376,9 +353,4 @@ public int freeImageHeap(PointerBase heapBase) { } return CEntryPointErrors.NO_ERROR; } - - @Override - protected UnsignedWord getImageHeapSizeInFile() { - throw VMError.shouldNotReachHere("use the variant that takes pointers"); - } } diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/code/DynamicMethodAddressResolutionHeapSupport.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/code/DynamicMethodAddressResolutionHeapSupport.java index 6080aa77ceb5..185727ad3f44 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/code/DynamicMethodAddressResolutionHeapSupport.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/code/DynamicMethodAddressResolutionHeapSupport.java @@ -24,19 +24,11 @@ */ package com.oracle.svm.core.code; -import static com.oracle.svm.core.util.PointerUtils.roundUp; - -import jdk.graal.compiler.api.replacements.Fold; -import org.graalvm.nativeimage.CurrentIsolate; import org.graalvm.nativeimage.ImageSingletons; import org.graalvm.word.Pointer; -import org.graalvm.word.PointerBase; import org.graalvm.word.UnsignedWord; -import org.graalvm.word.WordFactory; -import com.oracle.svm.core.Isolates; -import com.oracle.svm.core.Uninterruptible; -import com.oracle.svm.core.heap.Heap; +import jdk.graal.compiler.api.replacements.Fold; public abstract class DynamicMethodAddressResolutionHeapSupport { @@ -54,20 +46,5 @@ public static DynamicMethodAddressResolutionHeapSupport get() { public abstract UnsignedWord getRequiredPreHeapMemoryInBytes(); - public abstract int install(Pointer address); - - @Uninterruptible(reason = "Called from uninterruptible code.", mayBeInlined = true) - public UnsignedWord getDynamicMethodAddressResolverPreHeapMemoryBytes() { - UnsignedWord requiredPreHeapMemoryInBytes = getRequiredPreHeapMemoryInBytes(); - /* Ensure there is enough space to properly align the heap */ - UnsignedWord heapAlignment = WordFactory.unsigned(Heap.getHeap().getPreferredAddressSpaceAlignment()); - return roundUp((PointerBase) requiredPreHeapMemoryInBytes, heapAlignment); - } - - @Uninterruptible(reason = "Called from uninterruptible code.", mayBeInlined = true) - public Pointer getPreHeapMappingStartAddress() { - UnsignedWord heapBase = (UnsignedWord) Isolates.getHeapBase(CurrentIsolate.getIsolate()); - return (Pointer) heapBase.subtract(getRequiredPreHeapMemoryInBytes()); - } - + public abstract int install(Pointer heapBase); } diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/os/AbstractCopyingImageHeapProvider.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/os/AbstractCopyingImageHeapProvider.java index d9ad6a514744..b4842d5d4ec0 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/os/AbstractCopyingImageHeapProvider.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/os/AbstractCopyingImageHeapProvider.java @@ -25,6 +25,7 @@ package com.oracle.svm.core.os; import static com.oracle.svm.core.Isolates.IMAGE_HEAP_BEGIN; +import static com.oracle.svm.core.Isolates.IMAGE_HEAP_END; import static com.oracle.svm.core.Isolates.IMAGE_HEAP_WRITABLE_BEGIN; import static com.oracle.svm.core.Isolates.IMAGE_HEAP_WRITABLE_END; import static com.oracle.svm.core.util.PointerUtils.roundUp; @@ -51,56 +52,52 @@ public boolean guaranteesHeapPreferredAddressSpaceAlignment() { @Override @Uninterruptible(reason = "Called during isolate initialization.") public int initialize(Pointer reservedAddressSpace, UnsignedWord reservedSize, WordPointer basePointer, WordPointer endPointer) { - boolean haveDynamicMethodResolution = DynamicMethodAddressResolutionHeapSupport.isEnabled(); - UnsignedWord preHeapRequiredBytes = WordFactory.zero(); - UnsignedWord alignment = WordFactory.unsigned(Heap.getHeap().getPreferredAddressSpaceAlignment()); - - if (haveDynamicMethodResolution) { - int res = DynamicMethodAddressResolutionHeapSupport.get().initialize(); - if (res != CEntryPointErrors.NO_ERROR) { - return res; + Pointer selfReservedMemory = WordFactory.nullPointer(); + UnsignedWord requiredSize = getTotalRequiredAddressSpaceSize(); + if (reservedAddressSpace.isNull()) { + UnsignedWord alignment = WordFactory.unsigned(Heap.getHeap().getPreferredAddressSpaceAlignment()); + selfReservedMemory = VirtualMemoryProvider.get().reserve(requiredSize, alignment, false); + if (selfReservedMemory.isNull()) { + return CEntryPointErrors.RESERVE_ADDRESS_SPACE_FAILED; } - preHeapRequiredBytes = DynamicMethodAddressResolutionHeapSupport.get().getDynamicMethodAddressResolverPreHeapMemoryBytes(); + } else if (reservedSize.belowThan(requiredSize)) { + return CEntryPointErrors.INSUFFICIENT_ADDRESS_SPACE; } - // Reserve an address space for the image heap if necessary. - UnsignedWord imageHeapAddressSpaceSize = getImageHeapAddressSpaceSize(); - UnsignedWord totalAddressSpaceSize = imageHeapAddressSpaceSize.add(preHeapRequiredBytes); - Pointer heapBase; - Pointer allocatedMemory = WordFactory.nullPointer(); - if (reservedAddressSpace.isNull()) { - heapBase = allocatedMemory = VirtualMemoryProvider.get().reserve(totalAddressSpaceSize, alignment, false); - if (allocatedMemory.isNull()) { - return CEntryPointErrors.RESERVE_ADDRESS_SPACE_FAILED; + Pointer selfReservedHeapBase; + if (DynamicMethodAddressResolutionHeapSupport.isEnabled()) { + UnsignedWord preHeapRequiredBytes = getPreHeapAlignedSizeForDynamicMethodAddressResolver(); + if (selfReservedMemory.isNonNull()) { + selfReservedHeapBase = selfReservedMemory.add(preHeapRequiredBytes); + heapBase = selfReservedHeapBase; + } else { + heapBase = reservedAddressSpace.add(preHeapRequiredBytes); + selfReservedHeapBase = WordFactory.nullPointer(); } - } else { - if (reservedSize.belowThan(totalAddressSpaceSize)) { - return CEntryPointErrors.INSUFFICIENT_ADDRESS_SPACE; - } - heapBase = reservedAddressSpace; - } - if (haveDynamicMethodResolution) { - heapBase = heapBase.add(preHeapRequiredBytes); - if (allocatedMemory.isNonNull()) { - allocatedMemory.add(preHeapRequiredBytes); + int error = DynamicMethodAddressResolutionHeapSupport.get().initialize(); + if (error != CEntryPointErrors.NO_ERROR) { + freeImageHeap(selfReservedHeapBase); + return error; } - Pointer installOffset = heapBase.subtract(DynamicMethodAddressResolutionHeapSupport.get().getRequiredPreHeapMemoryInBytes()); - int error = DynamicMethodAddressResolutionHeapSupport.get().install(installOffset); + error = DynamicMethodAddressResolutionHeapSupport.get().install(heapBase); if (error != CEntryPointErrors.NO_ERROR) { - freeImageHeap(allocatedMemory); + freeImageHeap(selfReservedHeapBase); return error; } + } else { + heapBase = selfReservedMemory.isNonNull() ? selfReservedMemory : reservedAddressSpace; + selfReservedHeapBase = selfReservedMemory; } // Copy the memory to the reserved address space. - UnsignedWord imageHeapSizeInFile = getImageHeapSizeInFile(); + UnsignedWord imageHeapSizeInFile = getImageHeapSizeInFile(IMAGE_HEAP_BEGIN.get(), IMAGE_HEAP_END.get()); Pointer imageHeap = getImageHeapBegin(heapBase); int result = commitAndCopyMemory(IMAGE_HEAP_BEGIN.get(), imageHeapSizeInFile, imageHeap); if (result != CEntryPointErrors.NO_ERROR) { - freeImageHeap(allocatedMemory); + freeImageHeap(selfReservedHeapBase); return result; } @@ -109,7 +106,7 @@ public int initialize(Pointer reservedAddressSpace, UnsignedWord reservedSize, W UnsignedWord writableBeginPageOffset = UnsignedUtils.roundDown(IMAGE_HEAP_WRITABLE_BEGIN.get().subtract(IMAGE_HEAP_BEGIN.get()), pageSize); if (writableBeginPageOffset.aboveThan(0)) { if (VirtualMemoryProvider.get().protect(imageHeap, writableBeginPageOffset, Access.READ) != 0) { - freeImageHeap(allocatedMemory); + freeImageHeap(selfReservedHeapBase); return CEntryPointErrors.PROTECT_HEAP_FAILED; } } @@ -120,7 +117,7 @@ public int initialize(Pointer reservedAddressSpace, UnsignedWord reservedSize, W Pointer afterWritableBoundary = imageHeap.add(writableEndPageOffset); UnsignedWord afterWritableSize = imageHeapSizeInFile.subtract(writableEndPageOffset); if (VirtualMemoryProvider.get().protect(afterWritableBoundary, afterWritableSize, Access.READ) != 0) { - freeImageHeap(allocatedMemory); + freeImageHeap(selfReservedHeapBase); return CEntryPointErrors.PROTECT_HEAP_FAILED; } } @@ -152,7 +149,7 @@ public int freeImageHeap(PointerBase heapBase) { UnsignedWord totalAddressSpaceSize = getImageHeapAddressSpaceSize(); Pointer addressSpaceStart = (Pointer) heapBase; if (DynamicMethodAddressResolutionHeapSupport.isEnabled()) { - UnsignedWord preHeapRequiredBytes = DynamicMethodAddressResolutionHeapSupport.get().getDynamicMethodAddressResolverPreHeapMemoryBytes(); + UnsignedWord preHeapRequiredBytes = getPreHeapAlignedSizeForDynamicMethodAddressResolver(); totalAddressSpaceSize = totalAddressSpaceSize.add(preHeapRequiredBytes); addressSpaceStart = addressSpaceStart.subtract(preHeapRequiredBytes); } diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/os/AbstractImageHeapProvider.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/os/AbstractImageHeapProvider.java index 0542aec4b56c..dbfcc8031032 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/os/AbstractImageHeapProvider.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/os/AbstractImageHeapProvider.java @@ -26,20 +26,36 @@ import static com.oracle.svm.core.Isolates.IMAGE_HEAP_BEGIN; import static com.oracle.svm.core.Isolates.IMAGE_HEAP_END; +import static com.oracle.svm.core.util.PointerUtils.roundUp; import org.graalvm.word.Pointer; +import org.graalvm.word.PointerBase; import org.graalvm.word.UnsignedWord; +import org.graalvm.word.WordFactory; import com.oracle.svm.core.Uninterruptible; +import com.oracle.svm.core.code.DynamicMethodAddressResolutionHeapSupport; import com.oracle.svm.core.heap.Heap; import jdk.graal.compiler.word.Word; public abstract class AbstractImageHeapProvider implements ImageHeapProvider { + @Uninterruptible(reason = "Called from uninterruptible code.", mayBeInlined = true) + protected UnsignedWord getTotalRequiredAddressSpaceSize() { + UnsignedWord size = getImageHeapAddressSpaceSize(); + if (DynamicMethodAddressResolutionHeapSupport.isEnabled()) { + size = size.add(getPreHeapAlignedSizeForDynamicMethodAddressResolver()); + } + return size; + } + @Uninterruptible(reason = "Called from uninterruptible code.", mayBeInlined = true) protected UnsignedWord getImageHeapAddressSpaceSize() { - UnsignedWord imageHeapSizeInFile = getImageHeapSizeInFile(); - return imageHeapSizeInFile.add(Heap.getHeap().getImageHeapOffsetInAddressSpace()); + int imageHeapOffset = Heap.getHeap().getImageHeapOffsetInAddressSpace(); + assert imageHeapOffset >= 0; + UnsignedWord size = WordFactory.unsigned(imageHeapOffset); + size = size.add(getImageHeapSizeInFile(IMAGE_HEAP_BEGIN.get(), IMAGE_HEAP_END.get())); + return size; } @Uninterruptible(reason = "Called from uninterruptible code.", mayBeInlined = true) @@ -57,4 +73,12 @@ protected static UnsignedWord getImageHeapSizeInFile() { protected static Pointer getImageHeapBegin(Pointer heapBase) { return heapBase.add(Heap.getHeap().getImageHeapOffsetInAddressSpace()); } + + @Uninterruptible(reason = "Called from uninterruptible code.", mayBeInlined = true) + protected static UnsignedWord getPreHeapAlignedSizeForDynamicMethodAddressResolver() { + UnsignedWord requiredPreHeapMemoryInBytes = DynamicMethodAddressResolutionHeapSupport.get().getRequiredPreHeapMemoryInBytes(); + /* Ensure there is enough space to properly align the heap */ + UnsignedWord heapAlignment = WordFactory.unsigned(Heap.getHeap().getPreferredAddressSpaceAlignment()); + return roundUp((PointerBase) requiredPreHeapMemoryInBytes, heapAlignment); + } } From 81655edfee772677187aaa67d595a5f24a5254cc Mon Sep 17 00:00:00 2001 From: Peter Hofer Date: Fri, 12 Jan 2024 14:17:26 +0100 Subject: [PATCH 509/593] Change offsets used in heap layouting to be relative to the heap base. --- .../objectfile/debugentry/DebugInfoBase.java | 8 ++--- .../debuginfo/DebugInfoProvider.java | 4 +-- .../genscavenge/ChunkedImageHeapLayouter.java | 36 +++---------------- .../graal/GenScavengeGCFeature.java | 2 +- .../svm/core/image/ImageHeapLayoutInfo.java | 25 ++++++++----- .../svm/core/image/ImageHeapLayouter.java | 12 +------ .../svm/core/image/ImageHeapObject.java | 1 + .../hosted/image/LIRNativeImageCodeCache.java | 12 +++---- .../oracle/svm/hosted/image/NativeImage.java | 20 +++++------ .../image/NativeImageDebugInfoProvider.java | 5 --- .../NativeImageDebugInfoProviderBase.java | 6 ++-- .../svm/hosted/image/NativeImageHeap.java | 35 ------------------ .../hosted/image/NativeImageHeapWriter.java | 18 ++++++---- 13 files changed, 60 insertions(+), 124 deletions(-) diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/debugentry/DebugInfoBase.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/debugentry/DebugInfoBase.java index 20eb9894eacd..1ae3c4217fb2 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/debugentry/DebugInfoBase.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/debugentry/DebugInfoBase.java @@ -36,7 +36,6 @@ import org.graalvm.collections.EconomicMap; import org.graalvm.collections.EconomicSet; -import jdk.graal.compiler.debug.DebugContext; import com.oracle.objectfile.debugentry.range.PrimaryRange; import com.oracle.objectfile.debugentry.range.Range; @@ -49,6 +48,7 @@ import com.oracle.objectfile.debuginfo.DebugInfoProvider.DebugTypeInfo.DebugTypeKind; import com.oracle.objectfile.elf.dwarf.DwarfDebugInfo; +import jdk.graal.compiler.debug.DebugContext; import jdk.vm.ci.meta.ResolvedJavaType; /** @@ -351,10 +351,10 @@ public void installDebugInfo(DebugInfoProvider debugInfoProvider) { String provenance = debugDataInfo.getProvenance(); String typeName = debugDataInfo.getTypeName(); String partitionName = debugDataInfo.getPartition(); - /* Address is heap-register relative pointer. */ - long address = debugDataInfo.getAddress(); + /* Offset is relative to heap-base register. */ + long offset = debugDataInfo.getOffset(); long size = debugDataInfo.getSize(); - debugContext.log(DebugContext.INFO_LEVEL, "Data: address 0x%x size 0x%x type %s partition %s provenance %s ", address, size, typeName, partitionName, provenance); + debugContext.log(DebugContext.INFO_LEVEL, "Data: offset 0x%x size 0x%x type %s partition %s provenance %s ", offset, size, typeName, partitionName, provenance); } })); // populate a file and dir list and associated index for each class entry diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/debuginfo/DebugInfoProvider.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/debuginfo/DebugInfoProvider.java index 1c7908fa0a67..4cb38abb7897 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/debuginfo/DebugInfoProvider.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/debuginfo/DebugInfoProvider.java @@ -31,11 +31,11 @@ import java.util.function.Consumer; import java.util.stream.Stream; +import jdk.graal.compiler.debug.DebugContext; import jdk.vm.ci.meta.JavaConstant; import jdk.vm.ci.meta.JavaKind; import jdk.vm.ci.meta.ResolvedJavaMethod; import jdk.vm.ci.meta.ResolvedJavaType; -import jdk.graal.compiler.debug.DebugContext; /** * Interfaces used to allow a native image to communicate details of types, code and data to the @@ -356,8 +356,6 @@ interface DebugDataInfo { long getOffset(); - long getAddress(); - long getSize(); } diff --git a/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/ChunkedImageHeapLayouter.java b/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/ChunkedImageHeapLayouter.java index b812cbb1dd28..bb4b5bf8f713 100644 --- a/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/ChunkedImageHeapLayouter.java +++ b/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/ChunkedImageHeapLayouter.java @@ -35,7 +35,6 @@ import com.oracle.svm.core.genscavenge.ChunkedImageHeapAllocator.Chunk; import com.oracle.svm.core.genscavenge.ChunkedImageHeapAllocator.UnalignedChunk; import com.oracle.svm.core.genscavenge.remset.RememberedSet; -import com.oracle.svm.core.heap.Heap; import com.oracle.svm.core.hub.DynamicHub; import com.oracle.svm.core.image.ImageHeap; import com.oracle.svm.core.image.ImageHeapLayoutInfo; @@ -83,10 +82,9 @@ public class ChunkedImageHeapLayouter implements ImageHeapLayouter { private final long hugeObjectThreshold; private ChunkedImageHeapAllocator allocator; + /** @param startOffset Offset relative to the heap base. */ @SuppressWarnings("this-escape") public ChunkedImageHeapLayouter(ImageHeapInfo heapInfo, long startOffset) { - assert startOffset == 0 || startOffset >= Heap.getHeap().getImageHeapOffsetInAddressSpace() : "must be relative to the heap base"; - this.partitions = new ChunkedImageHeapPartition[PARTITION_COUNT]; this.partitions[READ_ONLY_PRIMITIVE] = new ChunkedImageHeapPartition("readOnlyPrimitive", false, false); this.partitions[READ_ONLY_REFERENCE] = new ChunkedImageHeapPartition("readOnlyReference", false, false); @@ -107,11 +105,6 @@ public ChunkedImageHeapLayouter(ImageHeapInfo heapInfo, long startOffset) { this.hugeObjectThreshold = hugeThreshold.rawValue(); } - @Override - public long getStartOffset() { - return startOffset; - } - @Override public ChunkedImageHeapPartition[] getPartitions() { return partitions; @@ -214,34 +207,15 @@ private ImageHeapLayoutInfo populateInfoObjects(int dynamicHubCount) { break; } - initializeHeapInfo(dynamicHubCount, offsetOfFirstWritableAlignedChunk, offsetOfFirstWritableUnalignedChunk); - return createLayoutInfo(startOffset, offsetOfFirstWritableAlignedChunk); - } - - private void initializeHeapInfo(int dynamicHubCount, long offsetOfFirstWritableAlignedChunk, long offsetOfFirstWritableUnalignedChunk) { - long writableAligned = offsetOfFirstWritableAlignedChunk; - long writableUnaligned = offsetOfFirstWritableUnalignedChunk; - - if (startOffset == 0) { - // Adjust all offsets by the offset of the image heap in the address space. - int imageHeapOffsetInAddressSpace = Heap.getHeap().getImageHeapOffsetInAddressSpace(); - writableAligned += imageHeapOffsetInAddressSpace; - if (writableUnaligned >= 0) { - writableUnaligned += imageHeapOffsetInAddressSpace; - } - } - heapInfo.initialize(getReadOnlyPrimitive().firstObject, getReadOnlyPrimitive().lastObject, getReadOnlyReference().firstObject, getReadOnlyReference().lastObject, getReadOnlyRelocatable().firstObject, getReadOnlyRelocatable().lastObject, getWritablePrimitive().firstObject, getWritablePrimitive().lastObject, getWritableReference().firstObject, getWritableReference().lastObject, getWritableHuge().firstObject, getWritableHuge().lastObject, - getReadOnlyHuge().firstObject, getReadOnlyHuge().lastObject, writableAligned, writableUnaligned, dynamicHubCount); - } + getReadOnlyHuge().firstObject, getReadOnlyHuge().lastObject, offsetOfFirstWritableAlignedChunk, offsetOfFirstWritableUnalignedChunk, dynamicHubCount); - private ImageHeapLayoutInfo createLayoutInfo(long heapStartOffset, long writableBeginOffset) { long writableEnd = getWritableHuge().getStartOffset() + getWritableHuge().getSize(); - long writableSize = writableEnd - writableBeginOffset; - long imageHeapSize = getReadOnlyHuge().getStartOffset() + getReadOnlyHuge().getSize() - heapStartOffset; - return new ImageHeapLayoutInfo(writableBeginOffset, writableSize, getReadOnlyRelocatable().getStartOffset(), getReadOnlyRelocatable().getSize(), imageHeapSize); + long writableSize = writableEnd - offsetOfFirstWritableAlignedChunk; + long imageHeapSize = getReadOnlyHuge().getStartOffset() + getReadOnlyHuge().getSize() - startOffset; + return new ImageHeapLayoutInfo(startOffset, offsetOfFirstWritableAlignedChunk, writableSize, getReadOnlyRelocatable().getStartOffset(), getReadOnlyRelocatable().getSize(), imageHeapSize); } @Override diff --git a/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/graal/GenScavengeGCFeature.java b/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/graal/GenScavengeGCFeature.java index 780dc3dbfa96..5718f341c24d 100644 --- a/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/graal/GenScavengeGCFeature.java +++ b/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/graal/GenScavengeGCFeature.java @@ -142,7 +142,7 @@ public void beforeAnalysis(BeforeAnalysisAccess access) { @Override public void afterAnalysis(AfterAnalysisAccess access) { - ImageHeapLayouter heapLayouter = new ChunkedImageHeapLayouter(HeapImpl.getFirstImageHeapInfo(), 0); + ImageHeapLayouter heapLayouter = new ChunkedImageHeapLayouter(HeapImpl.getFirstImageHeapInfo(), Heap.getHeap().getImageHeapOffsetInAddressSpace()); ImageSingletons.add(ImageHeapLayouter.class, heapLayouter); } diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/image/ImageHeapLayoutInfo.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/image/ImageHeapLayoutInfo.java index 716339ea2421..52bf25045ae3 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/image/ImageHeapLayoutInfo.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/image/ImageHeapLayoutInfo.java @@ -27,21 +27,32 @@ import com.oracle.svm.core.BuildPhaseProvider.AfterHeapLayout; import com.oracle.svm.core.heap.UnknownPrimitiveField; +/** Layout offsets and sizes. All offsets are relative to the heap base. */ public class ImageHeapLayoutInfo { + @UnknownPrimitiveField(availability = AfterHeapLayout.class) private final long startOffset; + @UnknownPrimitiveField(availability = AfterHeapLayout.class) private final long imageHeapSize; + @UnknownPrimitiveField(availability = AfterHeapLayout.class) private final long writableOffset; @UnknownPrimitiveField(availability = AfterHeapLayout.class) private final long writableSize; @UnknownPrimitiveField(availability = AfterHeapLayout.class) private final long readOnlyRelocatableOffset; @UnknownPrimitiveField(availability = AfterHeapLayout.class) private final long readOnlyRelocatableSize; - @UnknownPrimitiveField(availability = AfterHeapLayout.class) private final long imageHeapSize; - - public ImageHeapLayoutInfo(long writableOffset, long writableSize, long readOnlyRelocatableOffset, long readOnlyRelocatableSize, long imageHeapSize) { + public ImageHeapLayoutInfo(long startOffset, long writableOffset, long writableSize, long readOnlyRelocatableOffset, long readOnlyRelocatableSize, long imageHeapSize) { + this.startOffset = startOffset; + this.imageHeapSize = imageHeapSize; this.writableOffset = writableOffset; this.writableSize = writableSize; this.readOnlyRelocatableOffset = readOnlyRelocatableOffset; this.readOnlyRelocatableSize = readOnlyRelocatableSize; - this.imageHeapSize = imageHeapSize; + } + + public long getStartOffset() { + return startOffset; + } + + public long getImageHeapSize() { + return imageHeapSize; } public long getWritableOffset() { @@ -60,11 +71,7 @@ public long getReadOnlyRelocatableSize() { return readOnlyRelocatableSize; } - public boolean isReadOnlyRelocatable(int offset) { + public boolean isReadOnlyRelocatable(long offset) { return offset >= readOnlyRelocatableOffset && offset < readOnlyRelocatableOffset + readOnlyRelocatableSize; } - - public long getImageHeapSize() { - return imageHeapSize; - } } diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/image/ImageHeapLayouter.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/image/ImageHeapLayouter.java index 038f950b2404..ca4e4bfd9fc8 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/image/ImageHeapLayouter.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/image/ImageHeapLayouter.java @@ -26,20 +26,12 @@ import java.nio.ByteBuffer; -import com.oracle.svm.core.heap.Heap; - /** * This class is responsible for computing and storing the layout of the native image heap. A native * image heap consist of multiple {@link ImageHeapPartition}s. Every object in the native image heap * is assigned to a position within a {@link ImageHeapPartition}. */ public interface ImageHeapLayouter { - /** - * The offset of this image heap relative to the start of the first image heap (which itself is - * not the same as the heap base, see {@link Heap#getImageHeapOffsetInAddressSpace}). - */ - long getStartOffset(); - /** * Returns all native image heap partitions. */ @@ -51,9 +43,7 @@ public interface ImageHeapLayouter { void assignObjectToPartition(ImageHeapObject info, boolean immutable, boolean references, boolean relocatable); /** - * This method places all heap partitions as one contiguous memory block in one section. After - * calling that method, all native image heap objects are assigned their final address. This - * address must not change anymore. + * Places all heap partitions and assigns objects their final offsets. */ ImageHeapLayoutInfo layout(ImageHeap imageHeap, int pageSize); diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/image/ImageHeapObject.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/image/ImageHeapObject.java index 9e4fd57d4e44..b916134a958a 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/image/ImageHeapObject.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/image/ImageHeapObject.java @@ -39,6 +39,7 @@ public interface ImageHeapObject { void setOffsetInPartition(long value); + /** Returns the heap-base relative offset of this object. */ long getOffset(); ImageHeapPartition getPartition(); diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/LIRNativeImageCodeCache.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/LIRNativeImageCodeCache.java index c7cf1c37bec5..694707325b24 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/LIRNativeImageCodeCache.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/LIRNativeImageCodeCache.java @@ -34,11 +34,6 @@ import java.util.stream.StreamSupport; import org.graalvm.collections.Pair; -import jdk.graal.compiler.code.CompilationResult; -import jdk.graal.compiler.code.CompilationResult.CodeAnnotation; -import jdk.graal.compiler.core.common.NumUtil; -import jdk.graal.compiler.debug.DebugContext; -import jdk.graal.compiler.debug.Indent; import com.oracle.graal.pointsto.BigBang; import com.oracle.objectfile.ObjectFile; @@ -52,6 +47,11 @@ import com.oracle.svm.hosted.image.NativeImageHeap.ObjectInfo; import com.oracle.svm.hosted.meta.HostedMethod; +import jdk.graal.compiler.code.CompilationResult; +import jdk.graal.compiler.code.CompilationResult.CodeAnnotation; +import jdk.graal.compiler.core.common.NumUtil; +import jdk.graal.compiler.debug.DebugContext; +import jdk.graal.compiler.debug.Indent; import jdk.vm.ci.code.TargetDescription; import jdk.vm.ci.code.site.Call; import jdk.vm.ci.code.site.ConstantReference; @@ -356,7 +356,7 @@ public void patchMethods(DebugContext debug, RelocatableBuffer relocs, ObjectFil HostedImageHeapConstantPatch patch = (HostedImageHeapConstantPatch) codeAnnotation; ObjectInfo objectInfo = imageHeap.getConstantInfo(patch.constant); - long objectAddress = objectInfo.getAddress(); + long objectAddress = objectInfo.getOffset(); if (targetCode == null) { targetCode = ByteBuffer.wrap(compilation.getTargetCode()).order(target.arch.getByteOrder()); diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/NativeImage.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/NativeImage.java index db3d31bca211..3d9db20447b3 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/NativeImage.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/NativeImage.java @@ -470,16 +470,17 @@ public void build(String imageName, DebugContext debug) { heapSection = objectFile.newProgbitsSection(SectionName.SVM_HEAP.getFormatDependentName(objectFile.getFormat()), alignment, writable, false, heapSectionImpl); objectFile.createDefinedSymbol(heapSection.getName(), heapSection, 0, 0, false, false); - long offsetOfARelocatablePointer = writer.writeHeap(debug, heapSectionBuffer); - assert !SubstrateOptions.SpawnIsolates.getValue() || heapSectionBuffer.getByteBuffer().getLong((int) offsetOfARelocatablePointer) == 0L; + long sectionOffsetOfARelocatablePointer = writer.writeHeap(debug, heapSectionBuffer); + assert !SubstrateOptions.SpawnIsolates.getValue() || heapSectionBuffer.getByteBuffer().getLong((int) sectionOffsetOfARelocatablePointer) == 0L; defineDataSymbol(Isolates.IMAGE_HEAP_BEGIN_SYMBOL_NAME, heapSection, 0); defineDataSymbol(Isolates.IMAGE_HEAP_END_SYMBOL_NAME, heapSection, imageHeapSize); - defineDataSymbol(Isolates.IMAGE_HEAP_RELOCATABLE_BEGIN_SYMBOL_NAME, heapSection, heapLayout.getReadOnlyRelocatableOffset()); - defineDataSymbol(Isolates.IMAGE_HEAP_RELOCATABLE_END_SYMBOL_NAME, heapSection, heapLayout.getReadOnlyRelocatableOffset() + heapLayout.getReadOnlyRelocatableSize()); - defineDataSymbol(Isolates.IMAGE_HEAP_A_RELOCATABLE_POINTER_SYMBOL_NAME, heapSection, offsetOfARelocatablePointer); - defineDataSymbol(Isolates.IMAGE_HEAP_WRITABLE_BEGIN_SYMBOL_NAME, heapSection, heapLayout.getWritableOffset()); - defineDataSymbol(Isolates.IMAGE_HEAP_WRITABLE_END_SYMBOL_NAME, heapSection, heapLayout.getWritableOffset() + heapLayout.getWritableSize()); + defineDataSymbol(Isolates.IMAGE_HEAP_RELOCATABLE_BEGIN_SYMBOL_NAME, heapSection, heapLayout.getReadOnlyRelocatableOffset() - heapLayout.getStartOffset()); + defineDataSymbol(Isolates.IMAGE_HEAP_RELOCATABLE_END_SYMBOL_NAME, heapSection, + heapLayout.getReadOnlyRelocatableOffset() + heapLayout.getReadOnlyRelocatableSize() - heapLayout.getStartOffset()); + defineDataSymbol(Isolates.IMAGE_HEAP_A_RELOCATABLE_POINTER_SYMBOL_NAME, heapSection, sectionOffsetOfARelocatablePointer); + defineDataSymbol(Isolates.IMAGE_HEAP_WRITABLE_BEGIN_SYMBOL_NAME, heapSection, heapLayout.getWritableOffset() - heapLayout.getStartOffset()); + defineDataSymbol(Isolates.IMAGE_HEAP_WRITABLE_END_SYMBOL_NAME, heapSection, heapLayout.getWritableOffset() + heapLayout.getWritableSize() - heapLayout.getStartOffset()); // Mark the sections with the relocations from the maps. markRelocationSitesFromBuffer(textBuffer, textImpl); @@ -625,8 +626,7 @@ private void markDataRelocationSite(ProgbitsSectionImpl sectionImpl, int offset, assert ConfigurationValues.getTarget().arch instanceof AArch64 || info.getRelocationSize() == 4 || info.getRelocationSize() == 8 : "AMD64 Data relocation size should be 4 or 8 bytes."; assert targetObjectInfo != null; String targetSectionName = heapSection.getName(); - long address = targetObjectInfo.getAddress(); - long relocationAddend = address + info.getAddend(); + long relocationAddend = targetObjectInfo.getOffset() + info.getAddend(); sectionImpl.markRelocationSite(offset, info.getRelocationKind(), targetSectionName, relocationAddend); } @@ -661,7 +661,7 @@ private void markDataRelocationSiteFromText(RelocatableBuffer buffer, final Prog } else if (target instanceof ConstantReference) { // Direct object reference in code that must be patched (not a linker relocation) JavaConstant constant = (JavaConstant) ((ConstantReference) target).getConstant(); - long address = heap.getConstantInfo(constant).getAddress(); + long address = heap.getConstantInfo(constant).getOffset(); int encShift = ImageSingletons.lookup(CompressEncoding.class).getShift(); long targetValue = address >>> encShift; assert (targetValue << encShift) == address : "Reference compression shift discards non-zero bits: " + Long.toHexString(address); diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/NativeImageDebugInfoProvider.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/NativeImageDebugInfoProvider.java index 01b93643d288..c6a615a91ca2 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/NativeImageDebugInfoProvider.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/NativeImageDebugInfoProvider.java @@ -2622,11 +2622,6 @@ public long getOffset() { return objectInfo.getOffset(); } - @Override - public long getAddress() { - return objectInfo.getAddress(); - } - @Override public long getSize() { return objectInfo.getSize(); diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/NativeImageDebugInfoProviderBase.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/NativeImageDebugInfoProviderBase.java index 87ca9b83eabe..4f4c16778549 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/NativeImageDebugInfoProviderBase.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/NativeImageDebugInfoProviderBase.java @@ -118,8 +118,8 @@ public NativeImageDebugInfoProviderBase(NativeImageCodeCache codeCache, NativeIm this.referenceSize = getObjectLayout().getReferenceSize(); this.referenceAlignment = getObjectLayout().getAlignment(); /* Offsets need to be adjusted relative to the heap base plus partition-specific offset. */ - primitiveStartOffset = (int) primitiveFields.getAddress(); - referenceStartOffset = (int) objectFields.getAddress(); + primitiveStartOffset = (int) primitiveFields.getOffset(); + referenceStartOffset = (int) objectFields.getOffset(); javaKindToHostedType = initJavaKindToHostedTypes(metaAccess); } @@ -408,7 +408,7 @@ public long objectOffset(JavaConstant constant) { assert constant.getJavaKind() == JavaKind.Object && !constant.isNull() : "invalid constant for object offset lookup"; NativeImageHeap.ObjectInfo objectInfo = heap.getConstantInfo(constant); if (objectInfo != null) { - return objectInfo.getAddress(); + return objectInfo.getOffset(); } return -1; } diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/NativeImageHeap.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/NativeImageHeap.java index dfdeb0a694f1..1eaccf439cf1 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/NativeImageHeap.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/NativeImageHeap.java @@ -59,7 +59,6 @@ import com.oracle.svm.core.config.ConfigurationValues; import com.oracle.svm.core.config.ObjectLayout; import com.oracle.svm.core.heap.FillerObject; -import com.oracle.svm.core.heap.Heap; import com.oracle.svm.core.hub.DynamicHub; import com.oracle.svm.core.hub.DynamicHubCompanion; import com.oracle.svm.core.hub.LayoutEncoding; @@ -89,7 +88,6 @@ import jdk.graal.compiler.api.replacements.Fold; import jdk.graal.compiler.core.common.CompressEncoding; -import jdk.graal.compiler.core.common.NumUtil; import jdk.graal.compiler.core.common.type.CompressibleConstant; import jdk.graal.compiler.core.common.type.TypedConstant; import jdk.vm.ci.meta.JavaConstant; @@ -742,8 +740,6 @@ static class AddObjectData { final Object reason; } - private final int imageHeapOffsetInAddressSpace = Heap.getHeap().getImageHeapOffsetInAddressSpace(); - public final class ObjectInfo implements ImageHeapObject { private final JavaConstant constant; private final HostedClass clazz; @@ -818,37 +814,6 @@ public void setHeapPartition(ImageHeapPartition value) { this.partition = value; } - /** - * Returns the index into the {@link RelocatableBuffer} to which this object is written. - */ - public int getIndexInBuffer(long index) { - long result = getOffset() + index; - return NumUtil.safeToInt(result); - } - - /** - * If heap base addressing is enabled, this returns the heap-base relative address of this - * object. Otherwise, this returns the offset of the object within a native image section - * (e.g., read-only or writable). - */ - public long getAddress() { - /* - * At run-time, the image heap may be mapped in a way that there is some extra space at - * the beginning of the heap. So, all heap-base-relative addresses must be adjusted by - * that offset. - */ - return imageHeapOffsetInAddressSpace + getOffset(); - } - - /** - * Similar to {@link #getAddress()} but this method is typically used to get the address of - * a field within an object. - */ - public long getAddress(long delta) { - assert delta >= 0 && delta < getSize() : "Index: " + delta + " out of bounds: [0 .. " + getSize() + ")."; - return getAddress() + delta; - } - @Override public long getSize() { return size; diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/NativeImageHeapWriter.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/NativeImageHeapWriter.java index b09c6891095c..fc19798434e0 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/NativeImageHeapWriter.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/NativeImageHeapWriter.java @@ -176,7 +176,7 @@ void writeReference(RelocatableBuffer buffer, int index, JavaConstant target, Ob verifyTargetDidNotChange(target, reason, targetInfo); if (useHeapBase) { int shift = compressEncoding.getShift(); - writeReferenceValue(buffer, index, targetInfo.getAddress() >>> shift); + writeReferenceValue(buffer, index, targetInfo.getOffset() >>> shift); } else { addDirectRelocationWithoutAddend(buffer, index, referenceSize(), target); } @@ -239,7 +239,7 @@ private void writeObjectHeader(RelocatableBuffer buffer, int index, ObjectInfo o ObjectHeader objectHeader = Heap.getHeap().getObjectHeader(); if (NativeImageHeap.useHeapBase()) { - long targetOffset = hubInfo.getAddress(); + long targetOffset = hubInfo.getOffset(); long headerBits = objectHeader.encodeAsImageHeapObjectHeader(obj, targetOffset); writeReferenceValue(buffer, index, headerBits); } else { @@ -251,7 +251,7 @@ private void writeObjectHeader(RelocatableBuffer buffer, int index, ObjectInfo o private void addDirectRelocationWithoutAddend(RelocatableBuffer buffer, int index, int size, Object target) { assert size == 4 || size == 8; - assert !NativeImageHeap.spawnIsolates() || heapLayout.isReadOnlyRelocatable(index); + assert !NativeImageHeap.spawnIsolates() || isReadOnlyRelocatable(index); buffer.addRelocationWithoutAddend(index, size == 8 ? ObjectFile.RelocationKind.DIRECT_8 : ObjectFile.RelocationKind.DIRECT_4, target); if (sectionOffsetOfARelocatablePointer == -1) { sectionOffsetOfARelocatablePointer = index; @@ -259,7 +259,7 @@ private void addDirectRelocationWithoutAddend(RelocatableBuffer buffer, int inde } private void addDirectRelocationWithAddend(RelocatableBuffer buffer, int index, DynamicHub target, long objectHeaderBits) { - assert !NativeImageHeap.spawnIsolates() || heapLayout.isReadOnlyRelocatable(index); + assert !NativeImageHeap.spawnIsolates() || isReadOnlyRelocatable(index); buffer.addRelocationWithAddend(index, referenceSize() == 8 ? ObjectFile.RelocationKind.DIRECT_8 : ObjectFile.RelocationKind.DIRECT_4, objectHeaderBits, snippetReflection().forObject(target)); if (sectionOffsetOfARelocatablePointer == -1) { sectionOffsetOfARelocatablePointer = index; @@ -449,8 +449,14 @@ private void writeObject(ObjectInfo info, RelocatableBuffer buffer) { } } - private int getIndexInBuffer(ObjectInfo info, long offset) { - return info.getIndexInBuffer(offset - heap.getLayouter().getStartOffset()); + private int getIndexInBuffer(ObjectInfo objInfo, long offset) { + long index = objInfo.getOffset() + offset - heapLayout.getStartOffset(); + return NumUtil.safeToInt(index); + } + + private boolean isReadOnlyRelocatable(int indexInBuffer) { + long offset = indexInBuffer + heapLayout.getStartOffset(); + return heapLayout.isReadOnlyRelocatable(offset); } private void writePrimitiveArray(ObjectInfo info, RelocatableBuffer buffer, ObjectLayout objectLayout, JavaKind kind, Object array, int length) { From c0cd5b6d1695ee7a8882733b2f0948c3a6cd12cf Mon Sep 17 00:00:00 2001 From: Patrick Date: Wed, 17 Jan 2024 17:29:13 +0100 Subject: [PATCH 510/593] Move getImageHeapStart implementation to base class --- .../src/com/oracle/svm/core/genscavenge/HeapImpl.java | 8 -------- .../src/com/oracle/svm/core/heap/Heap.java | 6 ++++-- 2 files changed, 4 insertions(+), 10 deletions(-) diff --git a/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/HeapImpl.java b/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/HeapImpl.java index e640727ed231..95965e8591bc 100644 --- a/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/HeapImpl.java +++ b/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/HeapImpl.java @@ -35,7 +35,6 @@ import org.graalvm.word.Pointer; import org.graalvm.word.UnsignedWord; -import com.oracle.svm.core.Isolates; import com.oracle.svm.core.MemoryWalker; import com.oracle.svm.core.NeverInline; import com.oracle.svm.core.SubstrateDiagnostics; @@ -687,13 +686,6 @@ public long getIdentityHashSalt(Object obj) { return HeapChunk.getIdentityHashSalt(chunk).rawValue(); } - @Override - @Uninterruptible(reason = "Called from uninterruptible code.", mayBeInlined = true) - public Pointer getImageHeapStart() { - Pointer heapBase = (Pointer) Isolates.getHeapBase(CurrentIsolate.getIsolate()); - return heapBase.add(Heap.getHeap().getImageHeapOffsetInAddressSpace()); - } - private boolean printLocationInfo(Log log, Pointer ptr, boolean allowJavaHeapAccess, boolean allowUnsafeOperations) { if (imageHeapInfo.isInReadOnlyPrimitivePartition(ptr)) { log.string("points into the image heap (read-only primitives)"); diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/heap/Heap.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/heap/Heap.java index 4c12c4e5d552..6288d81158b6 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/heap/Heap.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/heap/Heap.java @@ -29,6 +29,7 @@ import java.util.List; import java.util.function.Consumer; +import org.graalvm.nativeimage.CurrentIsolate; import org.graalvm.nativeimage.ImageSingletons; import org.graalvm.nativeimage.IsolateThread; import org.graalvm.nativeimage.Platform; @@ -36,6 +37,7 @@ import org.graalvm.word.Pointer; import org.graalvm.word.UnsignedWord; +import com.oracle.svm.core.Isolates; import com.oracle.svm.core.Uninterruptible; import com.oracle.svm.core.hub.DynamicHub; import com.oracle.svm.core.hub.PredefinedClassesSupport; @@ -43,7 +45,6 @@ import com.oracle.svm.core.log.Log; import com.oracle.svm.core.option.RuntimeOptionKey; import com.oracle.svm.core.os.CommittedMemoryProvider; -import com.oracle.svm.core.util.VMError; import jdk.graal.compiler.api.replacements.Fold; @@ -146,7 +147,8 @@ public void visitLoadedClasses(Consumer> visitor) { @Uninterruptible(reason = "Called from uninterruptible code.", mayBeInlined = true) public Pointer getImageHeapStart() { - throw VMError.unimplemented("Heap.getImageHeapStart not implemented"); + Pointer heapBase = (Pointer) Isolates.getHeapBase(CurrentIsolate.getIsolate()); + return heapBase.add(Heap.getHeap().getImageHeapOffsetInAddressSpace()); } /** From f52cdbb9939964d095223c7fb75b71f0d4b2124f Mon Sep 17 00:00:00 2001 From: Tom Rodriguez Date: Wed, 20 Dec 2023 00:20:29 -0800 Subject: [PATCH 511/593] Avoid applying loop phases if there are no loops --- .../graal/compiler/loop/phases/LoopPhase.java | 6 ++++++ .../jdk/graal/compiler/phases/BasePhase.java | 20 ++++++++++++++++--- .../DisableOverflownCountedLoopsPhase.java | 5 +++++ 3 files changed, 28 insertions(+), 3 deletions(-) diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/loop/phases/LoopPhase.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/loop/phases/LoopPhase.java index a53c988b219e..f69568ff0df8 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/loop/phases/LoopPhase.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/loop/phases/LoopPhase.java @@ -24,6 +24,7 @@ */ package jdk.graal.compiler.loop.phases; +import jdk.graal.compiler.nodes.StructuredGraph; import jdk.graal.compiler.nodes.loop.LoopPolicies; import jdk.graal.compiler.nodes.spi.CoreProviders; import jdk.graal.compiler.phases.common.CanonicalizerPhase; @@ -41,4 +42,9 @@ public LoopPhase(P policies, CanonicalizerPhase canonicalizer) { protected P getPolicies() { return policies; } + + @Override + public boolean shouldApply(StructuredGraph graph) { + return graph.hasLoops(); + } } diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/phases/BasePhase.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/phases/BasePhase.java index 6450ad7488f9..19406c5730de 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/phases/BasePhase.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/phases/BasePhase.java @@ -32,9 +32,8 @@ import java.util.concurrent.ConcurrentHashMap; import java.util.regex.Pattern; -import jdk.graal.compiler.phases.contract.NodeCostUtil; -import jdk.graal.compiler.phases.contract.PhaseSizeContract; import org.graalvm.collections.EconomicMap; + import jdk.graal.compiler.core.common.util.CompilationAlarm; import jdk.graal.compiler.debug.CounterKey; import jdk.graal.compiler.debug.DebugCloseable; @@ -60,7 +59,8 @@ import jdk.graal.compiler.options.OptionKey; import jdk.graal.compiler.options.OptionType; import jdk.graal.compiler.options.OptionValues; - +import jdk.graal.compiler.phases.contract.NodeCostUtil; +import jdk.graal.compiler.phases.contract.PhaseSizeContract; import jdk.vm.ci.meta.JavaMethod; import jdk.vm.ci.meta.SpeculationLog; @@ -300,6 +300,16 @@ public boolean mustApply(GraphState graphState) { return false; } + /** + * Returns false if this phase can be skipped for {@code graph}. This purely about avoiding + * unnecessary work such as applying loop optimization to code without loops. + * + * @param graph the graph to be processed + */ + public boolean shouldApply(StructuredGraph graph) { + return true; + } + /** * Gets a precondition that prevents {@linkplain #apply(StructuredGraph, Object, boolean) * applying} this phase to a graph whose state is {@code graphState}. @@ -388,6 +398,10 @@ protected ApplyScope applyScope(StructuredGraph graph, C context) { @SuppressWarnings("try") public final void apply(final StructuredGraph graph, final C context, final boolean dumpGraph) { + if (!shouldApply(graph)) { + return; + } + OptionValues options = graph.getOptions(); Optional cannotBeApplied = this.notApplicableTo(graph.getGraphState()); diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/phases/common/DisableOverflownCountedLoopsPhase.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/phases/common/DisableOverflownCountedLoopsPhase.java index 3f416ee40d09..455504690409 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/phases/common/DisableOverflownCountedLoopsPhase.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/phases/common/DisableOverflownCountedLoopsPhase.java @@ -42,6 +42,11 @@ public Optional notApplicableTo(GraphState graphState) { return ALWAYS_APPLICABLE; } + @Override + public boolean shouldApply(StructuredGraph graph) { + return graph.hasLoops(); + } + @Override protected void run(StructuredGraph graph) { for (LoopBeginNode lb : graph.getNodes(LoopBeginNode.TYPE)) { From a96119505efed9bbf0a1c953602575260d789edd Mon Sep 17 00:00:00 2001 From: Tom Rodriguez Date: Wed, 20 Dec 2023 00:32:29 -0800 Subject: [PATCH 512/593] Only verify node inputs if graph has changed --- .../core/aarch64/AArch64AddressNode.java | 4 +- .../src/jdk/graal/compiler/graph/Graph.java | 7 +- .../src/jdk/graal/compiler/graph/Node.java | 73 +++++++++++++------ .../compiler/nodes/AbstractBeginNode.java | 4 +- .../graal/compiler/nodes/AbstractEndNode.java | 4 +- .../compiler/nodes/AbstractMergeNode.java | 4 +- .../compiler/nodes/AbstractStateSplit.java | 4 +- .../compiler/nodes/BinaryOpLogicNode.java | 5 -- .../jdk/graal/compiler/nodes/FixedNode.java | 4 +- .../jdk/graal/compiler/nodes/FrameState.java | 4 +- .../compiler/nodes/FullInfopointNode.java | 9 +-- .../compiler/nodes/GetObjectAddressNode.java | 5 +- .../src/jdk/graal/compiler/nodes/IfNode.java | 4 +- .../graal/compiler/nodes/LoopBeginNode.java | 4 +- .../jdk/graal/compiler/nodes/LoopEndNode.java | 4 +- .../graal/compiler/nodes/LoopExitNode.java | 4 +- .../jdk/graal/compiler/nodes/MergeNode.java | 4 +- .../src/jdk/graal/compiler/nodes/PhiNode.java | 4 +- .../jdk/graal/compiler/nodes/ProxyNode.java | 4 +- .../graal/compiler/nodes/ValuePhiNode.java | 4 +- .../nodes/calc/FloatingIntegerDivRemNode.java | 4 +- .../graal/compiler/nodes/calc/IsNullNode.java | 5 +- .../nodes/extended/CaptureStateBeginNode.java | 4 +- .../compiler/nodes/java/AccessFieldNode.java | 5 +- .../nodes/java/ExceptionObjectNode.java | 8 +- .../nodes/java/MethodCallTargetNode.java | 4 +- .../nodes/memory/FloatingReadNode.java | 4 +- .../nodes/virtual/CommitAllocationNode.java | 4 +- .../jdk/graal/compiler/phases/BasePhase.java | 4 +- 29 files changed, 111 insertions(+), 90 deletions(-) diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/core/aarch64/AArch64AddressNode.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/core/aarch64/AArch64AddressNode.java index 5ace4ecc783d..5d52053db079 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/core/aarch64/AArch64AddressNode.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/core/aarch64/AArch64AddressNode.java @@ -91,7 +91,7 @@ public void generate(NodeLIRBuilderTool gen) { } @Override - public boolean verify() { + public boolean verifyNode() { assertTrue(bitMemoryTransferSize == AArch64Address.ANY_SIZE || bitMemoryTransferSize == 8 || bitMemoryTransferSize == 16 || bitMemoryTransferSize == 32 || bitMemoryTransferSize == 64 || bitMemoryTransferSize == 128, "Invalid memory transfer size."); switch (addressingMode) { @@ -115,7 +115,7 @@ public boolean verify() { default: fail("Pairwise and post/pre index addressing modes should not be present."); } - return super.verify(); + return super.verifyNode(); } @Override diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/graph/Graph.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/graph/Graph.java index 43aa8bc31fdf..8a6cf2d724c9 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/graph/Graph.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/graph/Graph.java @@ -1359,11 +1359,16 @@ void unregister(Node node) { } public boolean verify() { + verify(true); + return true; + } + + public boolean verify(boolean verifyInputs) { if (verifyGraphs) { for (Node node : getNodes()) { try { try { - assert node.verify(); + assert node.verify(verifyInputs); } catch (AssertionError t) { throw new GraalError(t); } catch (RuntimeException t) { diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/graph/Node.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/graph/Node.java index 742a302258cd..c549d71f2ef5 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/graph/Node.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/graph/Node.java @@ -1390,42 +1390,71 @@ final Node clone(Graph into, EnumSet edgesToCopy) { protected void afterClone(@SuppressWarnings("unused") Node other) { } + @SuppressWarnings("unchecked") protected boolean verifyInputs() { - for (Position pos : inputPositions()) { - Node input = pos.get(this); - if (input == null) { - assertTrue(pos.isInputOptional(), "non-optional input %s cannot be null in %s (fix nullness or use @OptionalInput)", pos, this); - } else { - assertFalse(input.isDeleted(), "input was deleted %s", input); - assertTrue(input.isAlive(), "input is not alive yet, i.e., it was not yet added to the graph"); - assertTrue(pos.getInputType() == InputType.Unchecked || input.isAllowedUsageType(pos.getInputType()), "invalid usage type input:%s inputType:%s inputField:%s", input, - pos.getInputType(), pos.getName()); - Class expectedType = pos.getType(); - assertTrue(expectedType.isAssignableFrom(input.getClass()), "Invalid input type for %s: expected a %s but was a %s", pos, expectedType, input.getClass()); - } - } - /* - * Verify properties of input list objects themselves, as opposed to their contents. The - * iteration over input positions above visits the contents of input lists but does not - * distinguish between null and empty lists. - */ InputEdges inputEdges = nodeClass.getInputEdges(); + + // Verify properties of direct inputs + for (int i = 0; i < inputEdges.getDirectCount(); i++) { + Node input = (Node) inputEdges.get(this, i); + verifyInput(inputEdges, i, input); + } + + // Verify properties of input list objects for (int i = inputEdges.getDirectCount(); i < inputEdges.getCount(); i++) { Object inputList = inputEdges.get(this, i); if (inputList == null) { assertTrue(inputEdges.isOptional(i), "non-optional input list %s cannot be null in %s (fix nullness or use @OptionalInput)", inputEdges.getName(i), this); + } else { + NodeList nodeList = (NodeList) inputList; + for (Node input : nodeList) { + verifyInput(inputEdges, i, input); + } } } return true; } - public boolean verify() { + private void verifyInput(InputEdges inputEdges, int i, Node input) { + if (input == null) { + assertTrue(inputEdges.isOptional(i), "non-optional input list %s cannot be null in %s (fix nullness or use @OptionalInput)", inputEdges.getName(i), this); + } else { + assertFalse(input.isDeleted(), "input was deleted %s", input); + assertTrue(input.isAlive(), "input is not alive yet, i.e., it was not yet added to the graph"); + InputType inputType = inputEdges.getInputType(i); + assertTrue(inputType == InputType.Unchecked || input.isAllowedUsageType(inputType), "invalid usage type input:%s inputType:%s inputField:%s", input, + inputType, inputEdges.getName(i)); + Class expectedType = i < inputEdges.getDirectCount() ? inputEdges.getType(i) : Node.class; + assertTrue(expectedType.isAssignableFrom(input.getClass()), "Invalid input type for %s: expected a %s but was a %s", inputEdges.getName(i), expectedType, input.getClass()); + } + } + + public final boolean verify() { + return verify(true); + } + + /** + * Basic verification of node properties. This method is final so that a node cannot + * accidentally skip calling super(). Node specific verification should be done in + * {@link #verifyNode()}. + */ + public final boolean verify(boolean verifyInputs) { assertTrue(isAlive(), "cannot verify inactive node %s", this); - assertTrue(graph() != null, "null graph"); - verifyInputs(); + assertTrue(graph != null, "null graph"); + if (verifyInputs) { + verifyInputs(); + } if (graph.verifyGraphEdges) { verifyEdges(); } + verifyNode(); + return true; + } + + /** + * Verify node properties which are not covered by {@link #verify()}. + */ + protected boolean verifyNode() { return true; } @@ -1441,7 +1470,7 @@ public boolean verifyEdges() { for (Node successor : successors()) { assertTrue(successor.predecessor() == this, "missing predecessor in %s (actual: %s)", successor, successor.predecessor()); - assertTrue(successor.graph() == graph(), "mismatching graph in successor %s", successor); + assertTrue(successor.graph == graph, "mismatching graph in successor %s", successor); } for (Node usage : usages()) { assertFalse(usage.isDeleted(), "usage %s must never be deleted", usage); diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/nodes/AbstractBeginNode.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/nodes/AbstractBeginNode.java index 3696d6bd11e5..a1c1ad49fa3e 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/nodes/AbstractBeginNode.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/nodes/AbstractBeginNode.java @@ -86,9 +86,9 @@ public void prepareDelete(FixedNode evacuateFrom) { } @Override - public boolean verify() { + public boolean verifyNode() { assertTrue(predecessor() != null || this == graph().start() || this instanceof AbstractMergeNode, "begin nodes must be connected"); - return super.verify(); + return super.verifyNode(); } @Override diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/nodes/AbstractEndNode.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/nodes/AbstractEndNode.java index 677b06c45d12..de5805a6440d 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/nodes/AbstractEndNode.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/nodes/AbstractEndNode.java @@ -55,9 +55,9 @@ public AbstractMergeNode merge() { } @Override - public boolean verify() { + public boolean verifyNode() { assertTrue(getUsageCount() <= 1, "at most one usage"); - return super.verify(); + return super.verifyNode(); } @Override diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/nodes/AbstractMergeNode.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/nodes/AbstractMergeNode.java index 08cd6736a9b5..c778cdf11d14 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/nodes/AbstractMergeNode.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/nodes/AbstractMergeNode.java @@ -266,8 +266,8 @@ protected boolean verifyState() { } @Override - public boolean verify() { + public boolean verifyNode() { assert !this.graph().getGraphState().getFrameStateVerification().implies(GraphState.FrameStateVerificationFeature.MERGES) || verifyState() : "Merge must have a state until FSA " + this; - return super.verify(); + return super.verifyNode(); } } diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/nodes/AbstractStateSplit.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/nodes/AbstractStateSplit.java index 57085ca34577..a2dec2c4aee9 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/nodes/AbstractStateSplit.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/nodes/AbstractStateSplit.java @@ -65,9 +65,9 @@ protected AbstractStateSplit(NodeClass c, Stamp st } @Override - public boolean verify() { + public boolean verifyNode() { assert !hasSideEffect() || !this.graph().getGraphState().getFrameStateVerification().implies(GraphState.FrameStateVerificationFeature.STATE_SPLITS) || this.stateAfter != null : "State split with side-effect must have a state until FSA " + this; - return super.verify(); + return super.verifyNode(); } } diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/nodes/BinaryOpLogicNode.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/nodes/BinaryOpLogicNode.java index 524a8c258be2..79f1e0887be6 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/nodes/BinaryOpLogicNode.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/nodes/BinaryOpLogicNode.java @@ -72,11 +72,6 @@ public BinaryOpLogicNode(NodeClass c, ValueNode x, this.y = y; } - @Override - public boolean verify() { - return super.verify(); - } - /** * Ensure a canonical ordering of inputs for commutative nodes to improve GVN results. Order the * inputs by increasing {@link Node#id} and call {@link Graph#findDuplicate(Node)} on the node diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/nodes/FixedNode.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/nodes/FixedNode.java index ebb2b18dd2db..37d9777d914a 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/nodes/FixedNode.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/nodes/FixedNode.java @@ -37,9 +37,9 @@ protected FixedNode(NodeClass c, Stamp stamp) { } @Override - public boolean verify() { + public boolean verifyNode() { assertTrue(this.successors().isNotEmpty() || this.predecessor() != null, "FixedNode should not float: %s", this); - return super.verify(); + return super.verifyNode(); } /* This method is final to ensure that it can be de-virtualized and inlined. */ diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/nodes/FrameState.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/nodes/FrameState.java index 3dd1c222eb41..47b3f0ec8b13 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/nodes/FrameState.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/nodes/FrameState.java @@ -922,7 +922,7 @@ public Map getDebugProperties(Map map) { } @Override - public boolean verify() { + public boolean verifyNode() { if (virtualObjectMappingCount() > 0) { for (EscapeObjectState state : virtualObjectMappings()) { assertTrue(state != null, "must be non-null"); @@ -955,7 +955,7 @@ public boolean verify() { assertTrue(value == null || value instanceof VirtualObjectNode || (value.getStackKind() != JavaKind.Void), "unexpected value %s at frame state %s", value, this); } verifyAfterExceptionState(); - return super.verify(); + return super.verifyNode(); } private int outerLockDepth() { diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/nodes/FullInfopointNode.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/nodes/FullInfopointNode.java index 819923d067c9..1efda41f33fb 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/nodes/FullInfopointNode.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/nodes/FullInfopointNode.java @@ -30,13 +30,12 @@ import jdk.graal.compiler.core.common.type.StampFactory; import jdk.graal.compiler.graph.NodeClass; +import jdk.graal.compiler.nodeinfo.NodeInfo; import jdk.graal.compiler.nodes.spi.LIRLowerable; import jdk.graal.compiler.nodes.spi.NodeLIRBuilderTool; import jdk.graal.compiler.nodes.spi.NodeWithState; import jdk.graal.compiler.nodes.spi.Simplifiable; import jdk.graal.compiler.nodes.spi.SimplifierTool; -import jdk.graal.compiler.nodeinfo.NodeInfo; - import jdk.vm.ci.code.site.InfopointReason; /** @@ -82,10 +81,4 @@ public void generate(NodeLIRBuilderTool generator) { public FrameState getState() { return state; } - - @Override - public boolean verify() { - return state != null && super.verify(); - } - } diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/nodes/GetObjectAddressNode.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/nodes/GetObjectAddressNode.java index 5d4438880789..3d22c1a45b49 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/nodes/GetObjectAddressNode.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/nodes/GetObjectAddressNode.java @@ -34,7 +34,6 @@ import jdk.graal.compiler.nodeinfo.NodeInfo; import jdk.graal.compiler.nodes.spi.LIRLowerable; import jdk.graal.compiler.nodes.spi.NodeLIRBuilderTool; - import jdk.vm.ci.meta.AllocatableValue; import jdk.vm.ci.meta.JavaKind; @@ -70,8 +69,8 @@ public void generate(NodeLIRBuilderTool gen) { } @Override - public boolean verify() { + public boolean verifyNode() { assert graph().getGuardsStage().areFrameStatesAtDeopts() || graph().isSubstitution() : "GetObjectAddressNode can't be used directly until frame states are fixed"; - return super.verify(); + return super.verifyNode(); } } diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/nodes/IfNode.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/nodes/IfNode.java index fbc0f26b3364..2dfeb8906e6b 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/nodes/IfNode.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/nodes/IfNode.java @@ -197,11 +197,11 @@ public void generate(NodeLIRBuilderTool gen) { } @Override - public boolean verify() { + public boolean verifyNode() { assertTrue(condition() != null, "missing condition"); assertTrue(trueSuccessor() != null, "missing trueSuccessor"); assertTrue(falseSuccessor() != null, "missing falseSuccessor"); - return super.verify(); + return super.verifyNode(); } public void eliminateNegation() { diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/nodes/LoopBeginNode.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/nodes/LoopBeginNode.java index e38172576a71..541612517904 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/nodes/LoopBeginNode.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/nodes/LoopBeginNode.java @@ -419,9 +419,9 @@ public AbstractEndNode phiPredecessorAt(int index) { } @Override - public boolean verify() { + public boolean verifyNode() { assertTrue(loopEnds().isNotEmpty(), "missing loopEnd"); - return super.verify(); + return super.verifyNode(); } int nextEndIndex() { diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/nodes/LoopEndNode.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/nodes/LoopEndNode.java index ec858676a615..77006a90621c 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/nodes/LoopEndNode.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/nodes/LoopEndNode.java @@ -147,10 +147,10 @@ public void generate(NodeLIRBuilderTool gen) { } @Override - public boolean verify() { + public boolean verifyNode() { assertTrue(loopBegin != null, "must have a loop begin"); assertTrue(hasNoUsages(), "LoopEnds can not be used"); - return super.verify(); + return super.verifyNode(); } /** diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/nodes/LoopExitNode.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/nodes/LoopExitNode.java index 2a085dba2492..8f40c80b019b 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/nodes/LoopExitNode.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/nodes/LoopExitNode.java @@ -149,7 +149,7 @@ public void simplify(SimplifierTool tool) { } @Override - public boolean verify() { + public boolean verifyNode() { /* * State verification for loop exits is special in that loop exits with exception handling * BCIs must not survive until code generation, thus they are cleared shortly before frame @@ -162,6 +162,6 @@ public boolean verify() { // in the wrong place in the earliest local schedule. Ensuring there's a BeginNode before // the LoopExitNode creates an earlier location where those nodes can be scheduled. assert !(predecessor() instanceof InvokeWithExceptionNode) : Assertions.errorMessageContext("pred", predecessor()); - return super.verify(); + return super.verifyNode(); } } diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/nodes/MergeNode.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/nodes/MergeNode.java index e0090049c545..4a4f6a56a016 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/nodes/MergeNode.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/nodes/MergeNode.java @@ -51,8 +51,8 @@ public static void removeMergeIfDegenerated(MergeNode node) { } @Override - public boolean verify() { + public boolean verifyNode() { assertTrue(this.forwardEndCount() > 1, "Must merge more than one end."); - return super.verify(); + return super.verifyNode(); } } diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/nodes/PhiNode.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/nodes/PhiNode.java index b64076edb69a..0697d99e8757 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/nodes/PhiNode.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/nodes/PhiNode.java @@ -74,10 +74,10 @@ public void setMerge(AbstractMergeNode x) { } @Override - public boolean verify() { + public boolean verifyNode() { assertTrue(merge() != null, "missing merge"); assertTrue(merge().phiPredecessorCount() == valueCount(), "mismatch between merge predecessor count and phi value count: %d != %d", merge().phiPredecessorCount(), valueCount()); - return super.verify(); + return super.verifyNode(); } /** diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/nodes/ProxyNode.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/nodes/ProxyNode.java index bdfec4b6feea..e35f74fc2664 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/nodes/ProxyNode.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/nodes/ProxyNode.java @@ -76,9 +76,9 @@ public ValueNode getOriginalNode() { } @Override - public boolean verify() { + public boolean verifyNode() { assert !(value() instanceof ProxyNode) || ((ProxyNode) value()).loopExit != loopExit : Assertions.errorMessageContext("this", this, "value", value()); - return super.verify(); + return super.verifyNode(); } public static ValueProxyNode forValue(ValueNode value, LoopExitNode exit) { diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/nodes/ValuePhiNode.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/nodes/ValuePhiNode.java index 2e767ada56f6..356684481259 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/nodes/ValuePhiNode.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/nodes/ValuePhiNode.java @@ -196,7 +196,7 @@ private static ValueNode stripProxies(ValueNode v) { } @Override - public boolean verify() { + public boolean verifyNode() { Stamp s = null; for (ValueNode input : values()) { assert input != null; @@ -209,7 +209,7 @@ public boolean verify() { } } } - return super.verify(); + return super.verifyNode(); } @Override diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/nodes/calc/FloatingIntegerDivRemNode.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/nodes/calc/FloatingIntegerDivRemNode.java index bb137dea2724..84d18aecb7db 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/nodes/calc/FloatingIntegerDivRemNode.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/nodes/calc/FloatingIntegerDivRemNode.java @@ -124,7 +124,7 @@ private boolean overflowVisibleSideEffect() { } @Override - public boolean verify() { + public boolean verifyNode() { /* * Special case unconditionally deopting rem operations: Other optimziations can lead to * graphs where the rem operation will unconditionally deopt. @@ -150,6 +150,6 @@ public boolean verify() { boolean cannotDeopt = (!canDivideByZero() && !overflowVisibleSideEffect()); boolean isAfterStage = graph().isAfterStage(GraphState.StageFlag.FIXED_READS); GraalError.guarantee(guardWillAlwaysDeopt || cannotDeopt || isAfterStage, "Floating irem must never create an exception or trap"); - return super.verify(); + return super.verifyNode(); } } diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/nodes/calc/IsNullNode.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/nodes/calc/IsNullNode.java index b55497fc214e..00f81edcd074 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/nodes/calc/IsNullNode.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/nodes/calc/IsNullNode.java @@ -43,7 +43,6 @@ import jdk.graal.compiler.nodes.spi.NodeLIRBuilderTool; import jdk.graal.compiler.nodes.type.NarrowOopStamp; import jdk.graal.compiler.nodes.type.StampTool; - import jdk.vm.ci.meta.JavaConstant; import jdk.vm.ci.meta.TriState; @@ -95,10 +94,10 @@ public void generate(NodeLIRBuilderTool gen) { } @Override - public boolean verify() { + public boolean verifyNode() { assertTrue(getValue() != null, "is null input must not be null"); assertTrue(getValue().stamp(NodeView.DEFAULT).isPointerStamp(), "input must be a pointer not %s", getValue().stamp(NodeView.DEFAULT)); - return super.verify(); + return super.verifyNode(); } @Override diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/nodes/extended/CaptureStateBeginNode.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/nodes/extended/CaptureStateBeginNode.java index e3f840b9e5d5..8530a9b92398 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/nodes/extended/CaptureStateBeginNode.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/nodes/extended/CaptureStateBeginNode.java @@ -67,7 +67,7 @@ public Node canonical(CanonicalizerTool tool) { } @Override - public boolean verify() { + public boolean verifyNode() { if (predecessor() instanceof LoopExitNode loopExit) { /* * Must guarantee only value and memory proxies are attached to the loop exit. Anything @@ -76,6 +76,6 @@ public boolean verify() { assert loopExit.usages().stream().allMatch(NodePredicates.isA(ValueProxyNode.class).or(MemoryProxyNode.class)) : String.format("LoopExit has disallowed usages %s", loopExit); } - return super.verify(); + return super.verifyNode(); } } diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/nodes/java/AccessFieldNode.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/nodes/java/AccessFieldNode.java index d4b5ea72f827..63328c2348f2 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/nodes/java/AccessFieldNode.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/nodes/java/AccessFieldNode.java @@ -40,7 +40,6 @@ import jdk.graal.compiler.nodes.memory.MemoryAccess; import jdk.graal.compiler.nodes.memory.OrderedMemoryAccess; import jdk.graal.compiler.nodes.spi.Lowerable; - import jdk.vm.ci.meta.ResolvedJavaField; /** @@ -129,9 +128,9 @@ public String toString(Verbosity verbosity) { } @Override - public boolean verify() { + public boolean verifyNode() { assertTrue((object == null) == isStatic(), "static field must not have object, instance field must have object"); - return super.verify(); + return super.verifyNode(); } @Override diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/nodes/java/ExceptionObjectNode.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/nodes/java/ExceptionObjectNode.java index e227f2b0c58d..f5d1b57f599b 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/nodes/java/ExceptionObjectNode.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/nodes/java/ExceptionObjectNode.java @@ -28,6 +28,8 @@ import static jdk.graal.compiler.nodeinfo.NodeCycles.CYCLES_8; import static jdk.graal.compiler.nodeinfo.NodeSize.SIZE_8; +import org.graalvm.word.LocationIdentity; + import jdk.graal.compiler.core.common.type.StampFactory; import jdk.graal.compiler.core.common.type.TypeReference; import jdk.graal.compiler.debug.GraalError; @@ -48,8 +50,6 @@ import jdk.graal.compiler.nodes.memory.SingleMemoryKill; import jdk.graal.compiler.nodes.spi.Lowerable; import jdk.graal.compiler.nodes.spi.LoweringTool; -import org.graalvm.word.LocationIdentity; - import jdk.vm.ci.meta.JavaKind; import jdk.vm.ci.meta.MetaAccessProvider; @@ -137,12 +137,12 @@ private static ValueNode getExceptionValueFromState(StateSplit exceptionObjectNo } @Override - public boolean verify() { + public boolean verifyNode() { assertTrue(graph().getGraphState().getFrameStateVerification() == GraphState.FrameStateVerification.NONE || stateAfter() != null, "an exception handler needs a frame state"); assertTrue(graph().getGraphState().getFrameStateVerification() == GraphState.FrameStateVerification.NONE || stateAfter().stackSize() == 1 && stateAfter().stackAt(0).stamp(NodeView.DEFAULT).getStackKind() == JavaKind.Object, "an exception handler's frame state must have only the exception on the stack"); - return super.verify(); + return super.verifyNode(); } @Override diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/nodes/java/MethodCallTargetNode.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/nodes/java/MethodCallTargetNode.java index f5cf48c1c4cd..b91c05e8dd6f 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/nodes/java/MethodCallTargetNode.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/nodes/java/MethodCallTargetNode.java @@ -98,7 +98,7 @@ public JavaKind returnKind() { } @Override - public boolean verify() { + public boolean verifyNode() { assert getUsageCount() <= 1 : "call target may only be used by a single invoke"; for (Node n : usages()) { assertTrue(n instanceof Invoke, "call target can only be used from an invoke (%s)", n); @@ -111,7 +111,7 @@ public boolean verify() { } else { assertFalse(targetMethod().isStatic(), "static calls are only allowed for non-static methods (%s)", targetMethod()); } - return super.verify(); + return super.verifyNode(); } @Override diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/nodes/memory/FloatingReadNode.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/nodes/memory/FloatingReadNode.java index a69fe8897fff..f72c9d5047fc 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/nodes/memory/FloatingReadNode.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/nodes/memory/FloatingReadNode.java @@ -125,10 +125,10 @@ public FixedAccessNode asFixedNode() { } @Override - public boolean verify() { + public boolean verifyNode() { MemoryKill lla = getLastLocationAccess(); assert lla != null || getLocationIdentity().isImmutable() : "lastLocationAccess of " + this + " shouldn't be null for mutable location identity " + getLocationIdentity(); - return super.verify(); + return super.verifyNode(); } @Override diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/nodes/virtual/CommitAllocationNode.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/nodes/virtual/CommitAllocationNode.java index 4b70092b4555..b0b1b1a7dbae 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/nodes/virtual/CommitAllocationNode.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/nodes/virtual/CommitAllocationNode.java @@ -119,7 +119,7 @@ public List getEnsureVirtual() { } @Override - public boolean verify() { + public boolean verifyNode() { assertTrue(virtualObjects.size() + 1 == lockIndexes.size(), "lockIndexes size doesn't match %s, %s", virtualObjects, lockIndexes); assertTrue(lockIndexes.get(lockIndexes.size() - 1) == locks.size(), "locks size doesn't match %s,%s", lockIndexes, locks); int valueCount = 0; @@ -128,7 +128,7 @@ public boolean verify() { } assertTrue(values.size() == valueCount, "values size doesn't match"); assertTrue(virtualObjects.size() == ensureVirtual.size(), "ensureVirtual size doesn't match"); - return super.verify(); + return super.verifyNode(); } @Override diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/phases/BasePhase.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/phases/BasePhase.java index 19406c5730de..749fac59da4f 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/phases/BasePhase.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/phases/BasePhase.java @@ -472,7 +472,9 @@ public final void apply(final StructuredGraph graph, final C context, final bool if (debug.isVerifyEnabled()) { debug.verify(graph, "%s", getName()); } - assert graph.verify(); + + // Only verify inputs if the graph edges have changed + assert graph.verify(graph.getEdgeModificationCount() != edgesBefore); /* * Reset the progress-based compilation alarm to ensure that progress tracking happens * for each phase in isolation. This prevents false alarms where the same progress state From ed6a559117b9a68d33c0fbf1011225cd62c90802 Mon Sep 17 00:00:00 2001 From: Tom Rodriguez Date: Wed, 20 Dec 2023 00:55:23 -0800 Subject: [PATCH 513/593] Remove excessive verification of NodeSourcePositions during inlining --- .../src/jdk/graal/compiler/core/GraalCompiler.java | 2 +- .../compiler/phases/common/inlining/InliningUtil.java | 10 ++++++---- .../graal/compiler/replacements/SnippetTemplate.java | 6 ++++-- 3 files changed, 11 insertions(+), 7 deletions(-) diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/core/GraalCompiler.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/core/GraalCompiler.java index c6fd755d57c8..c6777576569c 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/core/GraalCompiler.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/core/GraalCompiler.java @@ -50,7 +50,6 @@ import jdk.graal.compiler.phases.tiers.Suites; import jdk.graal.compiler.phases.tiers.TargetProvider; import jdk.graal.compiler.phases.util.Providers; - import jdk.vm.ci.meta.ProfilingInfo; import jdk.vm.ci.meta.ResolvedJavaMethod; @@ -285,6 +284,7 @@ public static void emitFrontEnd(Providers providers, TargetProvider target, Stru try (CompilerPhaseScope cps = debug.enterCompilerPhase("Parsing")) { graphBuilderSuite.apply(graph, highTierContext); new DeadCodeEliminationPhase(DeadCodeEliminationPhase.Optionality.Optional).apply(graph); + assert graph.verifySourcePositions(true); debug.dump(DebugContext.BASIC_LEVEL, graph, "After parsing"); } } else { diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/phases/common/inlining/InliningUtil.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/phases/common/inlining/InliningUtil.java index 63b000578b11..ab45ce736feb 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/phases/common/inlining/InliningUtil.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/phases/common/inlining/InliningUtil.java @@ -811,16 +811,15 @@ public static void updateSourcePosition(StructuredGraph invokeGraph, Unmodifiabl * Not every duplicate node is newly created, so only update the position of the newly * created nodes. */ - EconomicSet newNodes = EconomicSet.create(Equivalence.DEFAULT); - newNodes.addAll(invokeGraph.getNewNodes(mark)); EconomicMap posMap = EconomicMap.create(Equivalence.DEFAULT); UnmodifiableMapCursor cursor = duplicates.getEntries(); ResolvedJavaMethod inlineeRoot = null; while (cursor.advance()) { Node value = cursor.getValue(); - if (!newNodes.contains(value)) { + if (!invokeGraph.isNew(mark, value)) { continue; } + if (isSubstitution && invokePos == null) { // There's no caller information so the source position for this node will be // invalid, so it should be cleared. @@ -830,6 +829,10 @@ public static void updateSourcePosition(StructuredGraph invokeGraph, Unmodifiabl if (oldPos != null) { NodeSourcePosition updatedPos = posMap.get(oldPos); if (updatedPos == null) { + // This verifies that all the incoming source positions agree about their + // root method. It then inserts invokePos as the caller so they will all + // continue to agree about the root method since it will be + // invokePos.getRootMethod. if (inlineeRoot == null) { assert (inlineeRoot = oldPos.getRootMethod()) != null; } else { @@ -854,7 +857,6 @@ public static void updateSourcePosition(StructuredGraph invokeGraph, Unmodifiabl } } } - assert invokeGraph.verifySourcePositions(false); } public static void processMonitorId(FrameState stateAfter, MonitorIdNode monitorIdNode) { diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/replacements/SnippetTemplate.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/replacements/SnippetTemplate.java index 610c3f29772d..73d428343697 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/replacements/SnippetTemplate.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/replacements/SnippetTemplate.java @@ -2254,8 +2254,10 @@ private EconomicMap inlineSnippet(Node replacee, DebugContext debug, if (scope != null) { log.addLog(duplicates, snippet.getInliningLog()); } - NodeSourcePosition position = replacee.getNodeSourcePosition(); - InliningUtil.updateSourcePosition(replaceeGraph, duplicates, mark, position, true); + if (replaceeGraph.trackNodeSourcePosition()) { + NodeSourcePosition position = replacee.getNodeSourcePosition(); + InliningUtil.updateSourcePosition(replaceeGraph, duplicates, mark, position, true); + } debug.dump(DebugContext.DETAILED_LEVEL, replaceeGraph, "After inlining snippet %s", snippet.method()); return duplicates; } From 566dce3a2ffb0eb82205100549c14d6ae4186d32 Mon Sep 17 00:00:00 2001 From: Tom Rodriguez Date: Wed, 20 Dec 2023 01:15:39 -0800 Subject: [PATCH 514/593] Reduce excessive calls to graph.verify --- .../compiler/phases/common/FixReadsPhase.java | 15 ++++++--------- .../compiler/phases/common/LoweringPhase.java | 1 - .../graal/compiler/phases/util/GraphOrder.java | 4 ++-- 3 files changed, 8 insertions(+), 12 deletions(-) diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/phases/common/FixReadsPhase.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/phases/common/FixReadsPhase.java index c15b66359e3f..7e4915893158 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/phases/common/FixReadsPhase.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/phases/common/FixReadsPhase.java @@ -24,14 +24,13 @@ */ package jdk.graal.compiler.phases.common; +import java.util.ListIterator; import java.util.Optional; -import jdk.graal.compiler.phases.BasePhase; -import jdk.graal.compiler.phases.graph.ScheduledNodeIterator; -import jdk.graal.compiler.phases.util.Providers; import org.graalvm.collections.EconomicMap; import org.graalvm.collections.Equivalence; import org.graalvm.collections.MapCursor; + import jdk.graal.compiler.core.common.GraalOptions; import jdk.graal.compiler.core.common.cfg.BlockMap; import jdk.graal.compiler.core.common.type.FloatStamp; @@ -69,9 +68,9 @@ import jdk.graal.compiler.nodes.calc.BinaryNode; import jdk.graal.compiler.nodes.calc.ConditionalNode; import jdk.graal.compiler.nodes.calc.UnaryNode; -import jdk.graal.compiler.nodes.cfg.HIRBlock; import jdk.graal.compiler.nodes.cfg.ControlFlowGraph; import jdk.graal.compiler.nodes.cfg.ControlFlowGraph.RecursiveVisitor; +import jdk.graal.compiler.nodes.cfg.HIRBlock; import jdk.graal.compiler.nodes.extended.GuardingNode; import jdk.graal.compiler.nodes.extended.IntegerSwitchNode; import jdk.graal.compiler.nodes.memory.FixedAccessNode; @@ -84,14 +83,14 @@ import jdk.graal.compiler.nodes.spi.CoreProvidersDelegate; import jdk.graal.compiler.nodes.util.GraphUtil; import jdk.graal.compiler.options.OptionValues; - +import jdk.graal.compiler.phases.BasePhase; +import jdk.graal.compiler.phases.graph.ScheduledNodeIterator; +import jdk.graal.compiler.phases.util.Providers; import jdk.vm.ci.meta.Assumptions; import jdk.vm.ci.meta.Constant; import jdk.vm.ci.meta.MetaAccessProvider; import jdk.vm.ci.meta.TriState; -import java.util.ListIterator; - /** * This phase lowers {@link FloatingReadNode FloatingReadNodes} into corresponding fixed reads. * After this operation, there are no longer any nodes in the graph that have to remain below a @@ -681,7 +680,6 @@ public Optional notApplicableTo(GraphState graphState) { @Override @SuppressWarnings("try") protected void run(StructuredGraph graph, CoreProviders context) { - assert graph.verify(); schedulePhase.apply(graph, context); ScheduleResult schedule = graph.getLastSchedule(); FixReadsClosure fixReadsClosure = new FixReadsClosure(graph); @@ -689,7 +687,6 @@ protected void run(StructuredGraph graph, CoreProviders context) { fixReadsClosure.processNodes(block, schedule); } - assert graph.verify(); if (GraalOptions.RawConditionalElimination.getValue(graph.getOptions())) { schedule.getCFG().visitDominatorTree(createVisitor(graph, schedule, context), false); } diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/phases/common/LoweringPhase.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/phases/common/LoweringPhase.java index 130dd42fd6bd..1b9f8c0ab979 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/phases/common/LoweringPhase.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/phases/common/LoweringPhase.java @@ -303,7 +303,6 @@ private void lower(StructuredGraph graph, CoreProviders context, LoweringMode mo if (!listener.getNodes().isEmpty()) { canonicalizer.applyIncremental(graph, context, listener.getNodes()); } - assert graph.verify(); } /** diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/phases/util/GraphOrder.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/phases/util/GraphOrder.java index ae450183bc58..840858decca2 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/phases/util/GraphOrder.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/phases/util/GraphOrder.java @@ -27,9 +27,9 @@ import java.util.ArrayList; import java.util.List; -import jdk.graal.compiler.phases.graph.ReentrantBlockIterator; import org.graalvm.collections.EconomicMap; import org.graalvm.collections.Equivalence; + import jdk.graal.compiler.debug.Assertions; import jdk.graal.compiler.debug.DebugContext; import jdk.graal.compiler.debug.GraalError; @@ -58,6 +58,7 @@ import jdk.graal.compiler.nodes.VirtualState.NodePositionClosure; import jdk.graal.compiler.nodes.cfg.HIRBlock; import jdk.graal.compiler.nodes.virtual.VirtualObjectNode; +import jdk.graal.compiler.phases.graph.ReentrantBlockIterator; import jdk.graal.compiler.phases.graph.StatelessPostOrderNodeIterator; import jdk.graal.compiler.phases.schedule.SchedulePhase; import jdk.graal.compiler.phases.schedule.SchedulePhase.SchedulingStrategy; @@ -159,7 +160,6 @@ public static boolean assertSchedulableGraph(StructuredGraph g) { // no longer use assertSchedulableGraph after the floating reads phase SchedulePhase.runWithoutContextOptimizations(g, SchedulePhase.SchedulingStrategy.LATEST_OUT_OF_LOOPS, true); } - assert g.verify(); return true; } From d5f4beda393bf79cde4047628c94eb4c0f7d5cac Mon Sep 17 00:00:00 2001 From: Tom Rodriguez Date: Fri, 12 Jan 2024 22:51:40 -0800 Subject: [PATCH 515/593] Fix message --- .../jdk.graal.compiler/src/jdk/graal/compiler/graph/Node.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/graph/Node.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/graph/Node.java index c549d71f2ef5..be35ee3ae83a 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/graph/Node.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/graph/Node.java @@ -1417,7 +1417,7 @@ protected boolean verifyInputs() { private void verifyInput(InputEdges inputEdges, int i, Node input) { if (input == null) { - assertTrue(inputEdges.isOptional(i), "non-optional input list %s cannot be null in %s (fix nullness or use @OptionalInput)", inputEdges.getName(i), this); + assertTrue(inputEdges.isOptional(i), "non-optional input %s cannot be null in %s (fix nullness or use @OptionalInput)", inputEdges.getName(i), this); } else { assertFalse(input.isDeleted(), "input was deleted %s", input); assertTrue(input.isAlive(), "input is not alive yet, i.e., it was not yet added to the graph"); From d8e7897d54160c05ced5ba695dc10ccc6d019135 Mon Sep 17 00:00:00 2001 From: Tom Rodriguez Date: Fri, 12 Jan 2024 22:52:15 -0800 Subject: [PATCH 516/593] Perform dumping even if shouldApply returns false --- .../jdk/graal/compiler/phases/BasePhase.java | 37 ++++++++++++++----- 1 file changed, 28 insertions(+), 9 deletions(-) diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/phases/BasePhase.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/phases/BasePhase.java index 749fac59da4f..60fdb5c5899b 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/phases/BasePhase.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/phases/BasePhase.java @@ -24,6 +24,8 @@ */ package jdk.graal.compiler.phases; +import static jdk.graal.compiler.debug.DebugOptions.PrintUnmodifiedGraphs; + import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; @@ -353,18 +355,19 @@ private BasePhase getEnclosingPhase(DebugContext debug) { return null; } - private boolean dumpBefore(final StructuredGraph graph, final C context, boolean isTopLevel) { + private boolean dumpBefore(final StructuredGraph graph, final C context, boolean isTopLevel, boolean applied) { + String tag = applied ? "" : " (skipped)"; DebugContext debug = graph.getDebug(); if (isTopLevel && (debug.isDumpEnabled(DebugContext.VERBOSE_LEVEL) || shouldDumpBeforeAtBasicLevel() && debug.isDumpEnabled(DebugContext.BASIC_LEVEL))) { if (shouldDumpBeforeAtBasicLevel()) { - debug.dump(DebugContext.BASIC_LEVEL, graph, "Before phase %s", getName()); + debug.dump(DebugContext.BASIC_LEVEL, graph, "Before phase %s%s", getName(), tag); } else { - debug.dump(DebugContext.VERBOSE_LEVEL, graph, "Before phase %s", getName()); + debug.dump(DebugContext.VERBOSE_LEVEL, graph, "Before phase %s%s", getName(), tag); } } else if (!isTopLevel && debug.isDumpEnabled(DebugContext.VERBOSE_LEVEL + 1)) { - debug.dump(DebugContext.VERBOSE_LEVEL + 1, graph, "Before subphase %s", getName()); + debug.dump(DebugContext.VERBOSE_LEVEL + 1, graph, "Before subphase %s%s", getName(), tag); } else if (debug.isDumpEnabled(DebugContext.ENABLED_LEVEL) && shouldDump(graph, context)) { - debug.dump(DebugContext.ENABLED_LEVEL, graph, "Before %s %s", isTopLevel ? "phase" : "subphase", getName()); + debug.dump(DebugContext.ENABLED_LEVEL, graph, "Before %s %s%s", isTopLevel ? "phase" : "subphase", getName(), tag); return true; } return false; @@ -398,12 +401,29 @@ protected ApplyScope applyScope(StructuredGraph graph, C context) { @SuppressWarnings("try") public final void apply(final StructuredGraph graph, final C context, final boolean dumpGraph) { + DebugContext debug = graph.getDebug(); + OptionValues options = graph.getOptions(); + if (!shouldApply(graph)) { + // Preserve the dumping so the IGV output still includes an entry for the phase even + // though it didn't do anything to the graph + if (dumpGraph && debug.areScopesEnabled() && !PrintUnmodifiedGraphs.getValue(options)) { + try (DebugContext.Scope s = debug.scope(getName(), this)) { + boolean isTopLevel = getEnclosingPhase(debug) == null; + dumpBefore(graph, context, isTopLevel, false); + } catch (Throwable t) { + throw debug.handle(t); + } + } + + try { + updateGraphState(graph.getGraphState()); + } catch (Throwable t) { + throw debug.handle(t); + } return; } - OptionValues options = graph.getOptions(); - Optional cannotBeApplied = this.notApplicableTo(graph.getGraphState()); if (cannotBeApplied.isPresent()) { String name = this.getClass().getName(); @@ -419,7 +439,6 @@ public final void apply(final StructuredGraph graph, final C context, final bool return; } - DebugContext debug = graph.getDebug(); try (DebugContext.Scope s = debug.scope(getName(), this); CompilerPhaseScope cps = getClass() != PhaseSuite.class ? debug.enterCompilerPhase(getName()) : null; DebugCloseable l = graph.getOptimizationLog().enterPhase(getName()); @@ -437,7 +456,7 @@ public final void apply(final StructuredGraph graph, final C context, final bool boolean isTopLevel = getEnclosingPhase(graph.getDebug()) == null; boolean dumpedBefore = false; if (dumpGraph && debug.areScopesEnabled()) { - dumpedBefore = dumpBefore(graph, context, isTopLevel); + dumpedBefore = dumpBefore(graph, context, isTopLevel, true); } inputNodesCount.add(debug, graph.getNodeCount()); From aabecf079495da66579bd0f1e9e400a563876264 Mon Sep 17 00:00:00 2001 From: Tom Rodriguez Date: Wed, 20 Dec 2023 11:23:16 -0800 Subject: [PATCH 517/593] Make BytecodeParser abstract --- .../microbenchmarks/graal/util/GraalUtil.java | 5 +- .../core/test/CheckGraalInvariants.java | 4 +- .../core/test/FinalizableSubclassTest.java | 10 +-- .../compiler/core/test/GraalCompilerTest.java | 16 ++-- .../compiler/core/test/NewInstanceTest.java | 10 +-- .../core/test/StaticInterfaceFieldTest.java | 10 +-- .../core/test/UnbalancedMonitorsTest.java | 15 ++-- .../core/test/VerifyAssertionUsageTest.java | 4 +- .../core/test/VerifyBailoutUsageTest.java | 8 +- .../core/test/VerifyDebugUsageTest.java | 8 +- .../core/test/VerifyVirtualizableTest.java | 8 +- .../core/test/tutorial/StaticAnalysis.java | 4 +- .../hotspot/test/LambdaStableNameTest.java | 4 +- .../replacements/test/PEGraphDecoderTest.java | 15 ++-- .../replacements/test/SnippetsTest.java | 5 +- .../hotspot/HotSpotGraalCompiler.java | 6 +- .../hotspot/HotSpotGraphBuilderPhase.java | 5 ++ .../HotSpotStableMethodNameFormatter.java | 49 ++++++++++++ .../hotspot/ProfileReplaySupport.java | 6 +- .../graal/compiler/java/BytecodeParser.java | 2 +- .../java/DefaultGraphBuilderPhase.java | 75 +++++++++++++++++++ .../compiler/java/GraphBuilderPhase.java | 25 +++---- .../java/StableMethodNameFormatter.java | 24 +++--- .../replacements/CachingPEGraphDecoder.java | 32 ++++---- .../compiler/truffle/PartialEvaluator.java | 11 ++- .../hotspot/HotSpotPartialEvaluator.java | 17 ++++- .../plugins/StandaloneGraphBuilderPhase.java | 4 +- .../AArch64SubstrateSuitesCreator.java | 3 +- .../amd64/AMD64SubstrateSuitesCreator.java | 3 +- .../graal/code/SubstrateSuitesCreator.java | 3 +- .../hotspot/libgraal/LibGraalFeature.java | 5 ++ .../LambdaSubstrateGraphBuilderPhase.java | 5 ++ ...trinsifyMethodHandlesInvocationPlugin.java | 3 +- .../serialize/SerializationFeature.java | 3 +- .../api/SubstratePartialEvaluator.java | 21 ++++-- 35 files changed, 297 insertions(+), 131 deletions(-) create mode 100644 compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/HotSpotStableMethodNameFormatter.java create mode 100644 compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/java/DefaultGraphBuilderPhase.java diff --git a/compiler/src/jdk.graal.compiler.microbenchmarks/src/jdk/graal/compiler/microbenchmarks/graal/util/GraalUtil.java b/compiler/src/jdk.graal.compiler.microbenchmarks/src/jdk/graal/compiler/microbenchmarks/graal/util/GraalUtil.java index a6fc3afa0006..07e1f93aaf99 100644 --- a/compiler/src/jdk.graal.compiler.microbenchmarks/src/jdk/graal/compiler/microbenchmarks/graal/util/GraalUtil.java +++ b/compiler/src/jdk.graal.compiler.microbenchmarks/src/jdk/graal/compiler/microbenchmarks/graal/util/GraalUtil.java @@ -28,7 +28,7 @@ import java.util.List; import jdk.graal.compiler.graph.Node; -import jdk.graal.compiler.java.GraphBuilderPhase; +import jdk.graal.compiler.java.DefaultGraphBuilderPhase; import jdk.graal.compiler.nodes.StructuredGraph; import jdk.graal.compiler.nodes.StructuredGraph.AllowAssumptions; import jdk.graal.compiler.nodes.graphbuilderconf.GraphBuilderConfiguration; @@ -37,7 +37,6 @@ import jdk.graal.compiler.phases.OptimisticOptimizations; import jdk.graal.compiler.phases.PhaseSuite; import jdk.graal.compiler.phases.tiers.HighTierContext; - import jdk.vm.ci.meta.ResolvedJavaMethod; public class GraalUtil { @@ -139,7 +138,7 @@ public static StructuredGraph getGraph(GraalState graal, ResolvedJavaMethod java } StructuredGraph graph = builder.build(); PhaseSuite graphBuilderSuite = new PhaseSuite<>(); - graphBuilderSuite.appendPhase(new GraphBuilderPhase(GraphBuilderConfiguration.getDefault(new Plugins(new InvocationPlugins())))); + graphBuilderSuite.appendPhase(new DefaultGraphBuilderPhase(GraphBuilderConfiguration.getDefault(new Plugins(new InvocationPlugins())))); graphBuilderSuite.apply(graph, new HighTierContext(graal.providers, graphBuilderSuite, OptimisticOptimizations.ALL)); return graph; } diff --git a/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/core/test/CheckGraalInvariants.java b/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/core/test/CheckGraalInvariants.java index bd9e96415e78..f13ead5dfca1 100644 --- a/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/core/test/CheckGraalInvariants.java +++ b/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/core/test/CheckGraalInvariants.java @@ -73,7 +73,7 @@ import jdk.graal.compiler.debug.GraalError; import jdk.graal.compiler.graph.Node; import jdk.graal.compiler.graph.NodeClass; -import jdk.graal.compiler.java.GraphBuilderPhase; +import jdk.graal.compiler.java.DefaultGraphBuilderPhase; import jdk.graal.compiler.nodeinfo.NodeInfo; import jdk.graal.compiler.nodes.FrameState; import jdk.graal.compiler.nodes.PhiNode; @@ -242,7 +242,7 @@ public static void runTest(InvariantsTool tool) { Plugins plugins = new Plugins(new InvocationPlugins()); plugins.setClassInitializationPlugin(new DoNotInitializeClassInitializationPlugin()); GraphBuilderConfiguration config = GraphBuilderConfiguration.getDefault(plugins).withEagerResolving(true).withUnresolvedIsError(true); - graphBuilderSuite.appendPhase(new GraphBuilderPhase(config)); + graphBuilderSuite.appendPhase(new DefaultGraphBuilderPhase(config)); HighTierContext context = new HighTierContext(providers, graphBuilderSuite, OptimisticOptimizations.NONE); Assume.assumeTrue(VerifyPhase.class.desiredAssertionStatus()); diff --git a/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/core/test/FinalizableSubclassTest.java b/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/core/test/FinalizableSubclassTest.java index 6108fc04be92..9cad025ca71d 100644 --- a/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/core/test/FinalizableSubclassTest.java +++ b/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/core/test/FinalizableSubclassTest.java @@ -30,8 +30,11 @@ import java.lang.reflect.Constructor; import java.util.HashMap; +import org.junit.Assert; +import org.junit.Test; + import jdk.graal.compiler.debug.DebugContext; -import jdk.graal.compiler.java.GraphBuilderPhase; +import jdk.graal.compiler.java.DefaultGraphBuilderPhase; import jdk.graal.compiler.nodes.StructuredGraph; import jdk.graal.compiler.nodes.StructuredGraph.AllowAssumptions; import jdk.graal.compiler.nodes.extended.LoadHubNode; @@ -42,9 +45,6 @@ import jdk.graal.compiler.phases.common.CanonicalizerPhase; import jdk.graal.compiler.phases.common.HighTierLoweringPhase; import jdk.graal.compiler.phases.tiers.HighTierContext; -import org.junit.Assert; -import org.junit.Test; - import jdk.vm.ci.meta.Assumptions; import jdk.vm.ci.meta.Assumptions.Assumption; import jdk.vm.ci.meta.Assumptions.LeafType; @@ -81,7 +81,7 @@ private StructuredGraph parseAndProcess(Class cl, AllowAssumptions allowAssum StructuredGraph graph = new StructuredGraph.Builder(options, debug, allowAssumptions).method(javaMethod).build(); try (DebugContext.Scope s = debug.scope("FinalizableSubclassTest", graph)) { GraphBuilderConfiguration conf = GraphBuilderConfiguration.getSnippetDefault(getDefaultGraphBuilderPlugins()); - new GraphBuilderPhase.Instance(getProviders(), conf, OptimisticOptimizations.ALL, null).apply(graph); + new DefaultGraphBuilderPhase.Instance(getProviders(), conf, OptimisticOptimizations.ALL, null).apply(graph); HighTierContext context = new HighTierContext(getProviders(), getDefaultGraphBuilderSuite(), OptimisticOptimizations.ALL); createInliningPhase().apply(graph, context); diff --git a/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/core/test/GraalCompilerTest.java b/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/core/test/GraalCompilerTest.java index fa410ecc3d87..9dce45fab91f 100644 --- a/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/core/test/GraalCompilerTest.java +++ b/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/core/test/GraalCompilerTest.java @@ -25,10 +25,10 @@ package jdk.graal.compiler.core.test; import static java.lang.reflect.Modifier.isStatic; -import static jdk.vm.ci.runtime.JVMCICompiler.INVOCATION_ENTRY_BCI; import static jdk.graal.compiler.nodes.ConstantNode.getConstantNodes; import static jdk.graal.compiler.nodes.graphbuilderconf.InlineInvokePlugin.InlineInfo.DO_NOT_INLINE_NO_EXCEPTION; import static jdk.graal.compiler.nodes.graphbuilderconf.InlineInvokePlugin.InlineInfo.DO_NOT_INLINE_WITH_EXCEPTION; +import static jdk.vm.ci.runtime.JVMCICompiler.INVOCATION_ENTRY_BCI; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; @@ -57,6 +57,13 @@ import java.util.concurrent.ConcurrentHashMap; import java.util.function.Supplier; +import org.junit.After; +import org.junit.Assert; +import org.junit.Before; +import org.junit.BeforeClass; +import org.junit.Test; +import org.junit.internal.AssumptionViolatedException; + import jdk.graal.compiler.api.replacements.SnippetReflectionProvider; import jdk.graal.compiler.api.test.Graal; import jdk.graal.compiler.api.test.ModuleSupport; @@ -137,13 +144,6 @@ import jdk.graal.compiler.printer.GraalDebugHandlersFactory; import jdk.graal.compiler.runtime.RuntimeProvider; import jdk.graal.compiler.test.GraalTest; -import org.junit.After; -import org.junit.Assert; -import org.junit.Before; -import org.junit.BeforeClass; -import org.junit.Test; -import org.junit.internal.AssumptionViolatedException; - import jdk.vm.ci.code.Architecture; import jdk.vm.ci.code.BailoutException; import jdk.vm.ci.code.CodeCacheProvider; diff --git a/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/core/test/NewInstanceTest.java b/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/core/test/NewInstanceTest.java index f1e4927d80ce..a5c2b2a7f644 100644 --- a/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/core/test/NewInstanceTest.java +++ b/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/core/test/NewInstanceTest.java @@ -29,7 +29,10 @@ import java.io.InputStream; import java.lang.reflect.Constructor; -import jdk.graal.compiler.java.GraphBuilderPhase; +import org.junit.Assert; +import org.junit.Test; + +import jdk.graal.compiler.java.DefaultGraphBuilderPhase; import jdk.graal.compiler.nodes.DeoptimizeNode; import jdk.graal.compiler.nodes.StructuredGraph; import jdk.graal.compiler.nodes.StructuredGraph.AllowAssumptions; @@ -37,9 +40,6 @@ import jdk.graal.compiler.nodes.java.NewInstanceNode; import jdk.graal.compiler.options.OptionValues; import jdk.graal.compiler.phases.OptimisticOptimizations; -import org.junit.Assert; -import org.junit.Test; - import jdk.vm.ci.meta.ResolvedJavaMethod; public class NewInstanceTest extends GraalCompilerTest { @@ -76,7 +76,7 @@ private StructuredGraph parseAndProcess(Class cl) { StructuredGraph graph = new StructuredGraph.Builder(options, getDebugContext(options, null, javaMethod), AllowAssumptions.YES).method(javaMethod).build(); GraphBuilderConfiguration conf = GraphBuilderConfiguration.getSnippetDefault(getDefaultGraphBuilderPlugins()).withUnresolvedIsError(false); - new GraphBuilderPhase.Instance(getProviders(), conf, OptimisticOptimizations.ALL, null).apply(graph); + new DefaultGraphBuilderPhase.Instance(getProviders(), conf, OptimisticOptimizations.ALL, null).apply(graph); return graph; } diff --git a/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/core/test/StaticInterfaceFieldTest.java b/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/core/test/StaticInterfaceFieldTest.java index e14176f98fd6..f87fa53e0058 100644 --- a/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/core/test/StaticInterfaceFieldTest.java +++ b/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/core/test/StaticInterfaceFieldTest.java @@ -26,11 +26,14 @@ import java.lang.reflect.Method; +import org.junit.Assume; +import org.junit.Test; + import jdk.graal.compiler.api.test.Graal; import jdk.graal.compiler.debug.DebugCloseable; import jdk.graal.compiler.debug.DebugContext; import jdk.graal.compiler.debug.DebugContext.Builder; -import jdk.graal.compiler.java.GraphBuilderPhase; +import jdk.graal.compiler.java.DefaultGraphBuilderPhase; import jdk.graal.compiler.nodes.StructuredGraph; import jdk.graal.compiler.nodes.graphbuilderconf.GraphBuilderConfiguration; import jdk.graal.compiler.nodes.graphbuilderconf.GraphBuilderConfiguration.Plugins; @@ -43,9 +46,6 @@ import jdk.graal.compiler.phases.util.Providers; import jdk.graal.compiler.runtime.RuntimeProvider; import jdk.graal.compiler.test.GraalTest; -import org.junit.Assume; -import org.junit.Test; - import jdk.vm.ci.meta.MetaAccessProvider; import jdk.vm.ci.meta.ResolvedJavaMethod; @@ -83,7 +83,7 @@ private void eagerlyParseMethod(Class clazz, String methodName) { PhaseSuite graphBuilderSuite = new PhaseSuite<>(); Plugins plugins = new Plugins(new InvocationPlugins()); GraphBuilderConfiguration config = GraphBuilderConfiguration.getDefault(plugins).withEagerResolving(true).withUnresolvedIsError(true); - graphBuilderSuite.appendPhase(new GraphBuilderPhase(config)); + graphBuilderSuite.appendPhase(new DefaultGraphBuilderPhase(config)); HighTierContext context = new HighTierContext(providers, graphBuilderSuite, OptimisticOptimizations.NONE); Assume.assumeTrue(VerifyPhase.class.desiredAssertionStatus()); diff --git a/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/core/test/UnbalancedMonitorsTest.java b/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/core/test/UnbalancedMonitorsTest.java index 6c4ae7dc6426..4d84509ff775 100644 --- a/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/core/test/UnbalancedMonitorsTest.java +++ b/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/core/test/UnbalancedMonitorsTest.java @@ -24,6 +24,13 @@ */ package jdk.graal.compiler.core.test; +import org.junit.Test; +import org.objectweb.asm.ClassWriter; +import org.objectweb.asm.Label; +import org.objectweb.asm.MethodVisitor; +import org.objectweb.asm.Opcodes; + +import jdk.graal.compiler.java.DefaultGraphBuilderPhase; import jdk.graal.compiler.java.GraphBuilderPhase; import jdk.graal.compiler.nodes.StructuredGraph; import jdk.graal.compiler.nodes.graphbuilderconf.GraphBuilderConfiguration; @@ -31,12 +38,6 @@ import jdk.graal.compiler.nodes.graphbuilderconf.InvocationPlugins; import jdk.graal.compiler.options.OptionValues; import jdk.graal.compiler.phases.OptimisticOptimizations; -import org.junit.Test; -import org.objectweb.asm.ClassWriter; -import org.objectweb.asm.Label; -import org.objectweb.asm.MethodVisitor; -import org.objectweb.asm.Opcodes; - import jdk.vm.ci.code.BailoutException; import jdk.vm.ci.meta.ResolvedJavaMethod; @@ -90,7 +91,7 @@ private void checkForBailout(String name) throws ClassNotFoundException { GraphBuilderConfiguration graphBuilderConfig = GraphBuilderConfiguration.getDefault(plugins).withEagerResolving(true).withUnresolvedIsError(true); OptimisticOptimizations optimisticOpts = OptimisticOptimizations.NONE; - GraphBuilderPhase.Instance graphBuilder = new GraphBuilderPhase.Instance(getProviders(), graphBuilderConfig, optimisticOpts, null); + GraphBuilderPhase.Instance graphBuilder = new DefaultGraphBuilderPhase.Instance(getProviders(), graphBuilderConfig, optimisticOpts, null); graphBuilder.apply(graph); } catch (BailoutException e) { if (e.getMessage().contains("unbalanced monitors") || diff --git a/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/core/test/VerifyAssertionUsageTest.java b/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/core/test/VerifyAssertionUsageTest.java index 3505e1679f3f..4cf0931ccf27 100644 --- a/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/core/test/VerifyAssertionUsageTest.java +++ b/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/core/test/VerifyAssertionUsageTest.java @@ -40,7 +40,7 @@ import jdk.graal.compiler.debug.DebugContext; import jdk.graal.compiler.debug.DebugContext.Builder; import jdk.graal.compiler.graph.Node; -import jdk.graal.compiler.java.GraphBuilderPhase; +import jdk.graal.compiler.java.DefaultGraphBuilderPhase; import jdk.graal.compiler.nodes.StructuredGraph; import jdk.graal.compiler.nodes.graphbuilderconf.GraphBuilderConfiguration; import jdk.graal.compiler.nodes.graphbuilderconf.GraphBuilderConfiguration.Plugins; @@ -430,7 +430,7 @@ private static void testDebugUsageClass(Class c) { PhaseSuite graphBuilderSuite = new PhaseSuite<>(); Plugins plugins = new Plugins(new InvocationPlugins()); GraphBuilderConfiguration config = GraphBuilderConfiguration.getDefault(plugins).withEagerResolving(true).withUnresolvedIsError(true); - graphBuilderSuite.appendPhase(new GraphBuilderPhase(config)); + graphBuilderSuite.appendPhase(new DefaultGraphBuilderPhase(config)); HighTierContext context = new HighTierContext(providers, graphBuilderSuite, OptimisticOptimizations.NONE); OptionValues options = GraalCompilerTest.getInitialOptions(); DebugContext debug = new Builder(options).build(); diff --git a/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/core/test/VerifyBailoutUsageTest.java b/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/core/test/VerifyBailoutUsageTest.java index 0266a63455f3..2a23d1f11d15 100644 --- a/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/core/test/VerifyBailoutUsageTest.java +++ b/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/core/test/VerifyBailoutUsageTest.java @@ -27,6 +27,8 @@ import java.lang.reflect.Method; import java.lang.reflect.Modifier; +import org.junit.Test; + import jdk.graal.compiler.api.test.Graal; import jdk.graal.compiler.core.common.PermanentBailoutException; import jdk.graal.compiler.core.common.RetryableBailoutException; @@ -34,7 +36,7 @@ import jdk.graal.compiler.debug.DebugContext; import jdk.graal.compiler.debug.DebugContext.Builder; import jdk.graal.compiler.debug.GraalError; -import jdk.graal.compiler.java.GraphBuilderPhase; +import jdk.graal.compiler.java.DefaultGraphBuilderPhase; import jdk.graal.compiler.nodes.StructuredGraph; import jdk.graal.compiler.nodes.graphbuilderconf.GraphBuilderConfiguration; import jdk.graal.compiler.nodes.graphbuilderconf.GraphBuilderConfiguration.Plugins; @@ -46,8 +48,6 @@ import jdk.graal.compiler.phases.tiers.HighTierContext; import jdk.graal.compiler.phases.util.Providers; import jdk.graal.compiler.runtime.RuntimeProvider; -import org.junit.Test; - import jdk.vm.ci.code.BailoutException; import jdk.vm.ci.meta.MetaAccessProvider; import jdk.vm.ci.meta.ResolvedJavaMethod; @@ -122,7 +122,7 @@ private static void testBailoutUsage(Class c) { PhaseSuite graphBuilderSuite = new PhaseSuite<>(); Plugins plugins = new Plugins(new InvocationPlugins()); GraphBuilderConfiguration config = GraphBuilderConfiguration.getDefault(plugins).withEagerResolving(true).withUnresolvedIsError(true); - graphBuilderSuite.appendPhase(new GraphBuilderPhase(config)); + graphBuilderSuite.appendPhase(new DefaultGraphBuilderPhase(config)); HighTierContext context = new HighTierContext(providers, graphBuilderSuite, OptimisticOptimizations.NONE); OptionValues options = GraalCompilerTest.getInitialOptions(); DebugContext debug = new Builder(options).build(); diff --git a/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/core/test/VerifyDebugUsageTest.java b/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/core/test/VerifyDebugUsageTest.java index dff21b01441b..e92a9cac2289 100644 --- a/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/core/test/VerifyDebugUsageTest.java +++ b/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/core/test/VerifyDebugUsageTest.java @@ -29,6 +29,8 @@ import java.lang.reflect.Method; import java.lang.reflect.Modifier; +import org.junit.Test; + import jdk.graal.compiler.api.test.Graal; import jdk.graal.compiler.debug.DebugCloseable; import jdk.graal.compiler.debug.DebugContext; @@ -36,7 +38,7 @@ import jdk.graal.compiler.debug.GraalError; import jdk.graal.compiler.debug.Indent; import jdk.graal.compiler.graph.Node; -import jdk.graal.compiler.java.GraphBuilderPhase; +import jdk.graal.compiler.java.DefaultGraphBuilderPhase; import jdk.graal.compiler.nodes.StructuredGraph; import jdk.graal.compiler.nodes.graphbuilderconf.GraphBuilderConfiguration; import jdk.graal.compiler.nodes.graphbuilderconf.GraphBuilderConfiguration.Plugins; @@ -48,8 +50,6 @@ import jdk.graal.compiler.phases.tiers.HighTierContext; import jdk.graal.compiler.phases.util.Providers; import jdk.graal.compiler.runtime.RuntimeProvider; -import org.junit.Test; - import jdk.vm.ci.meta.MetaAccessProvider; import jdk.vm.ci.meta.ResolvedJavaMethod; @@ -331,7 +331,7 @@ private static void testDebugUsageClass(Class c) { PhaseSuite graphBuilderSuite = new PhaseSuite<>(); Plugins plugins = new Plugins(new InvocationPlugins()); GraphBuilderConfiguration config = GraphBuilderConfiguration.getDefault(plugins).withEagerResolving(true).withUnresolvedIsError(true); - graphBuilderSuite.appendPhase(new GraphBuilderPhase(config)); + graphBuilderSuite.appendPhase(new DefaultGraphBuilderPhase(config)); HighTierContext context = new HighTierContext(providers, graphBuilderSuite, OptimisticOptimizations.NONE); OptionValues options = getInitialOptions(); DebugContext debug = new Builder(options).build(); diff --git a/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/core/test/VerifyVirtualizableTest.java b/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/core/test/VerifyVirtualizableTest.java index 46b480724f0b..75525bed59bf 100644 --- a/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/core/test/VerifyVirtualizableTest.java +++ b/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/core/test/VerifyVirtualizableTest.java @@ -31,13 +31,15 @@ import java.lang.reflect.Method; import java.lang.reflect.Modifier; +import org.junit.Test; + import jdk.graal.compiler.api.test.Graal; import jdk.graal.compiler.core.common.type.StampFactory; import jdk.graal.compiler.debug.DebugCloseable; import jdk.graal.compiler.debug.DebugContext; import jdk.graal.compiler.debug.DebugContext.Builder; import jdk.graal.compiler.graph.NodeClass; -import jdk.graal.compiler.java.GraphBuilderPhase; +import jdk.graal.compiler.java.DefaultGraphBuilderPhase; import jdk.graal.compiler.nodeinfo.NodeInfo; import jdk.graal.compiler.nodes.ConstantNode; import jdk.graal.compiler.nodes.StructuredGraph; @@ -55,8 +57,6 @@ import jdk.graal.compiler.phases.tiers.HighTierContext; import jdk.graal.compiler.phases.util.Providers; import jdk.graal.compiler.runtime.RuntimeProvider; -import org.junit.Test; - import jdk.vm.ci.meta.MetaAccessProvider; import jdk.vm.ci.meta.ResolvedJavaMethod; @@ -270,7 +270,7 @@ private static void testVirtualizableEffects(Class c) { PhaseSuite graphBuilderSuite = new PhaseSuite<>(); Plugins plugins = new Plugins(new InvocationPlugins()); GraphBuilderConfiguration config = GraphBuilderConfiguration.getDefault(plugins).withEagerResolving(true).withUnresolvedIsError(true); - graphBuilderSuite.appendPhase(new GraphBuilderPhase(config)); + graphBuilderSuite.appendPhase(new DefaultGraphBuilderPhase(config)); HighTierContext context = new HighTierContext(providers, graphBuilderSuite, OptimisticOptimizations.NONE); OptionValues options = getInitialOptions(); DebugContext debug = new Builder(options).build(); diff --git a/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/core/test/tutorial/StaticAnalysis.java b/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/core/test/tutorial/StaticAnalysis.java index 14fbcc81c45a..3b8ce8bec5e5 100644 --- a/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/core/test/tutorial/StaticAnalysis.java +++ b/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/core/test/tutorial/StaticAnalysis.java @@ -39,6 +39,7 @@ import jdk.graal.compiler.debug.GraalError; import jdk.graal.compiler.graph.Node; import jdk.graal.compiler.graph.NodeMap; +import jdk.graal.compiler.java.DefaultGraphBuilderPhase; import jdk.graal.compiler.java.GraphBuilderPhase; import jdk.graal.compiler.nodes.CallTargetNode.InvokeKind; import jdk.graal.compiler.nodes.ConstantNode; @@ -63,7 +64,6 @@ import jdk.graal.compiler.options.OptionValues; import jdk.graal.compiler.phases.OptimisticOptimizations; import jdk.graal.compiler.phases.graph.StatelessPostOrderNodeIterator; - import jdk.vm.ci.meta.JavaConstant; import jdk.vm.ci.meta.JavaKind; import jdk.vm.ci.meta.ResolvedJavaField; @@ -275,7 +275,7 @@ protected void process() { */ OptimisticOptimizations optimisticOpts = OptimisticOptimizations.NONE; - GraphBuilderPhase.Instance graphBuilder = new GraphBuilderPhase.Instance(providers, graphBuilderConfig, optimisticOpts, null); + GraphBuilderPhase.Instance graphBuilder = new DefaultGraphBuilderPhase.Instance(providers, graphBuilderConfig, optimisticOpts, null); graphBuilder.apply(graph); } catch (Throwable ex) { debug.handle(ex); diff --git a/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/hotspot/test/LambdaStableNameTest.java b/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/hotspot/test/LambdaStableNameTest.java index 8e0f80faa413..f9846ed1139f 100644 --- a/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/hotspot/test/LambdaStableNameTest.java +++ b/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/hotspot/test/LambdaStableNameTest.java @@ -40,7 +40,7 @@ import jdk.graal.compiler.debug.DebugContext; import jdk.graal.compiler.debug.DebugContext.Builder; import jdk.graal.compiler.hotspot.meta.HotSpotJITClassInitializationPlugin; -import jdk.graal.compiler.java.GraphBuilderPhase; +import jdk.graal.compiler.java.DefaultGraphBuilderPhase; import jdk.graal.compiler.java.LambdaUtils; import jdk.graal.compiler.options.OptionValues; import jdk.graal.compiler.phases.OptimisticOptimizations; @@ -57,7 +57,7 @@ private String findStableLambdaName(ResolvedJavaType type) { Providers providers = compiler.getGraalRuntime().getCapability(RuntimeProvider.class).getHostBackend().getProviders(); final HotSpotJITClassInitializationPlugin initializationPlugin = new HotSpotJITClassInitializationPlugin(); return LambdaUtils.findStableLambdaName(initializationPlugin, providers, type, options, debug, this, - config -> new GraphBuilderPhase.Instance(providers, config, OptimisticOptimizations.NONE, null)); + config -> new DefaultGraphBuilderPhase.Instance(providers, config, OptimisticOptimizations.NONE, null)); } @Test diff --git a/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/replacements/test/PEGraphDecoderTest.java b/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/replacements/test/PEGraphDecoderTest.java index 5d95cf731ae9..ca895efc1a52 100644 --- a/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/replacements/test/PEGraphDecoderTest.java +++ b/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/replacements/test/PEGraphDecoderTest.java @@ -28,12 +28,18 @@ import org.graalvm.collections.EconomicMap; import org.graalvm.collections.EconomicSet; +import org.graalvm.word.LocationIdentity; +import org.junit.Assert; +import org.junit.Test; + import jdk.graal.compiler.core.common.memory.BarrierType; import jdk.graal.compiler.core.common.memory.MemoryOrderMode; import jdk.graal.compiler.core.common.type.StampFactory; import jdk.graal.compiler.core.test.GraalCompilerTest; import jdk.graal.compiler.debug.DebugContext; import jdk.graal.compiler.debug.DebugOptions; +import jdk.graal.compiler.java.DefaultGraphBuilderPhase; +import jdk.graal.compiler.java.GraphBuilderPhase; import jdk.graal.compiler.nodes.AbstractBeginNode; import jdk.graal.compiler.nodes.CompanionObjectEncoder; import jdk.graal.compiler.nodes.EncodedGraph; @@ -56,10 +62,6 @@ import jdk.graal.compiler.phases.OptimisticOptimizations; import jdk.graal.compiler.replacements.CachingPEGraphDecoder; import jdk.graal.compiler.util.CollectionsUtil; -import org.graalvm.word.LocationIdentity; -import org.junit.Assert; -import org.junit.Test; - import jdk.vm.ci.meta.JavaKind; import jdk.vm.ci.meta.ResolvedJavaMethod; @@ -231,8 +233,9 @@ private StructuredGraph test(String methodName, EconomicMap null, false, false, true); + GraphBuilderPhase.Instance instance = new DefaultGraphBuilderPhase.Instance(getProviders(), graphBuilderConfig, OptimisticOptimizations.NONE, null); + CachingPEGraphDecoder decoder = new CachingPEGraphDecoder(getTarget().arch, targetGraph, getProviders(), graphBuilderConfig, + null, null, new InlineInvokePlugin[]{new InlineAll()}, null, null, null, null, null, graphCache, () -> null, instance, false, false, true); decoder.decode(testMethod); debug.dump(DebugContext.BASIC_LEVEL, targetGraph, "Target Graph"); diff --git a/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/replacements/test/SnippetsTest.java b/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/replacements/test/SnippetsTest.java index ef2a578dc044..439c27ea7770 100644 --- a/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/replacements/test/SnippetsTest.java +++ b/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/replacements/test/SnippetsTest.java @@ -24,7 +24,7 @@ */ package jdk.graal.compiler.replacements.test; -import jdk.graal.compiler.java.GraphBuilderPhase; +import jdk.graal.compiler.java.DefaultGraphBuilderPhase; import jdk.graal.compiler.java.GraphBuilderPhase.Instance; import jdk.graal.compiler.nodes.StructuredGraph; import jdk.graal.compiler.nodes.StructuredGraph.Builder; @@ -36,7 +36,6 @@ import jdk.graal.compiler.phases.util.Providers; import jdk.graal.compiler.replacements.ReplacementsImpl; import jdk.graal.compiler.replacements.classfile.ClassfileBytecodeProvider; - import jdk.vm.ci.meta.ResolvedJavaMethod; public abstract class SnippetsTest extends ReplacementsTest { @@ -57,7 +56,7 @@ protected GraphMaker createGraphMaker(ResolvedJavaMethod substitute, ResolvedJav @Override protected Instance createGraphBuilder(Providers providers1, GraphBuilderConfiguration graphBuilderConfig, OptimisticOptimizations optimisticOpts, IntrinsicContext initialIntrinsicContext) { - return new GraphBuilderPhase.Instance(providers1, graphBuilderConfig, optimisticOpts, initialIntrinsicContext); + return new DefaultGraphBuilderPhase.Instance(providers1, graphBuilderConfig, optimisticOpts, initialIntrinsicContext); } }; } diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/HotSpotGraalCompiler.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/HotSpotGraalCompiler.java index ef66baafe509..8fece4155ff0 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/HotSpotGraalCompiler.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/HotSpotGraalCompiler.java @@ -35,6 +35,7 @@ import jdk.graal.compiler.core.GraalCompiler; import jdk.graal.compiler.core.common.CompilationIdentifier; import jdk.graal.compiler.core.common.util.CompilationAlarm; +import jdk.graal.compiler.debug.Assertions; import jdk.graal.compiler.debug.DebugContext; import jdk.graal.compiler.debug.DebugContext.Activation; import jdk.graal.compiler.debug.DebugHandlersFactory; @@ -43,7 +44,6 @@ import jdk.graal.compiler.hotspot.meta.HotSpotProviders; import jdk.graal.compiler.hotspot.phases.OnStackReplacementPhase; import jdk.graal.compiler.java.GraphBuilderPhase; -import jdk.graal.compiler.java.StableMethodNameFormatter; import jdk.graal.compiler.lir.asm.CompilationResultBuilderFactory; import jdk.graal.compiler.lir.phases.LIRSuites; import jdk.graal.compiler.nodes.Cancellable; @@ -59,8 +59,6 @@ import jdk.graal.compiler.phases.tiers.Suites; import jdk.graal.compiler.printer.GraalDebugHandlersFactory; import jdk.graal.compiler.serviceprovider.GraalUnsafeAccess; -import jdk.graal.compiler.debug.Assertions; - import jdk.vm.ci.code.CompilationRequest; import jdk.vm.ci.code.CompilationRequestResult; import jdk.vm.ci.hotspot.HotSpotCompilationRequest; @@ -242,7 +240,7 @@ public CompilationResult compileHelper(CompilationResultBuilderFactory crbf, Com eagerResolving, isOSR); GraalCompiler.compileGraph(graph, method, providers, backend, graphBuilderSuite, optimisticOpts, profilingInfo, suites, lirSuites, result, crbf, true); - graph.getOptimizationLog().emit(new StableMethodNameFormatter(providers, graph.getDebug())); + graph.getOptimizationLog().emit(new HotSpotStableMethodNameFormatter(providers, graph.getDebug())); if (!isOSR) { profilingInfo.setCompilerIRSize(StructuredGraph.class, graph.getNodeCount()); } diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/HotSpotGraphBuilderPhase.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/HotSpotGraphBuilderPhase.java index 7410dc5f825c..40750f76da08 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/HotSpotGraphBuilderPhase.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/HotSpotGraphBuilderPhase.java @@ -36,6 +36,11 @@ public HotSpotGraphBuilderPhase(GraphBuilderConfiguration config) { super(config); } + @Override + public GraphBuilderPhase copyWithConfig(GraphBuilderConfiguration config) { + return new HotSpotGraphBuilderPhase(config); + } + @Override protected Instance createInstance(CoreProviders providers, GraphBuilderConfiguration instanceGBConfig, OptimisticOptimizations optimisticOpts, IntrinsicContext initialIntrinsicContext) { return new HotSpotGraphBuilderInstance(providers, instanceGBConfig, optimisticOpts, initialIntrinsicContext); diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/HotSpotStableMethodNameFormatter.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/HotSpotStableMethodNameFormatter.java new file mode 100644 index 000000000000..f789b3e74d0f --- /dev/null +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/HotSpotStableMethodNameFormatter.java @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2023, 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 jdk.graal.compiler.hotspot; + +import jdk.graal.compiler.debug.DebugContext; +import jdk.graal.compiler.java.GraphBuilderPhase; +import jdk.graal.compiler.java.StableMethodNameFormatter; +import jdk.graal.compiler.phases.util.Providers; + +/** + * A simple wrapper that creates the right subclass of {@link GraphBuilderPhase}. + */ +public class HotSpotStableMethodNameFormatter extends StableMethodNameFormatter { + + public HotSpotStableMethodNameFormatter(Providers providers, DebugContext debug) { + this(providers, debug, false); + } + + public HotSpotStableMethodNameFormatter(Providers providers, DebugContext debug, boolean considerMH) { + super(providers, debug, considerMH); + } + + @Override + protected GraphBuilderPhase createGraphBuilderPhase() { + return new HotSpotGraphBuilderPhase(config); + } +} diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/ProfileReplaySupport.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/ProfileReplaySupport.java index b3c0a9ae489f..0f8587b8fe85 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/ProfileReplaySupport.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/ProfileReplaySupport.java @@ -42,8 +42,8 @@ import java.util.stream.Collectors; import java.util.stream.Stream; -import jdk.graal.compiler.util.json.JSONFormatter; import org.graalvm.collections.EconomicMap; + import jdk.graal.compiler.code.CompilationResult; import jdk.graal.compiler.core.common.CompilationIdentifier; import jdk.graal.compiler.core.common.cfg.BasicBlock; @@ -68,8 +68,8 @@ import jdk.graal.compiler.options.OptionKey; import jdk.graal.compiler.options.OptionType; import jdk.graal.compiler.phases.schedule.SchedulePhase; +import jdk.graal.compiler.util.json.JSONFormatter; import jdk.graal.compiler.util.json.JSONParser; - import jdk.vm.ci.hotspot.HotSpotResolvedJavaMethod; import jdk.vm.ci.meta.ResolvedJavaMethod; @@ -145,7 +145,7 @@ public static ProfileReplaySupport profileReplayPrologue(DebugContext debug, Hot StableProfileProvider profileProvider, TypeFilter profileSaveFilter) { if (SaveProfiles.getValue(debug.getOptions()) || LoadProfiles.getValue(debug.getOptions()) != null) { LambdaNameFormatter lambdaNameFormatter = new LambdaNameFormatter() { - private final StableMethodNameFormatter stableFormatter = new StableMethodNameFormatter(graalRuntime.getHostBackend().getProviders(), debug, true); + private final StableMethodNameFormatter stableFormatter = new HotSpotStableMethodNameFormatter(graalRuntime.getHostBackend().getProviders(), debug, true); @Override public boolean isLambda(ResolvedJavaMethod m) { diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/java/BytecodeParser.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/java/BytecodeParser.java index 2d0902c10edf..ed3b63743fb8 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/java/BytecodeParser.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/java/BytecodeParser.java @@ -463,7 +463,7 @@ /** * The {@code GraphBuilder} class parses the bytecode of a method and builds the IR graph. */ -public class BytecodeParser extends CoreProvidersDelegate implements GraphBuilderContext { +public abstract class BytecodeParser extends CoreProvidersDelegate implements GraphBuilderContext { /** * The minimum value to which {@link BytecodeParserOptions#TraceBytecodeParserLevel} must be set diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/java/DefaultGraphBuilderPhase.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/java/DefaultGraphBuilderPhase.java new file mode 100644 index 000000000000..7c24b438d550 --- /dev/null +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/java/DefaultGraphBuilderPhase.java @@ -0,0 +1,75 @@ +/* + * Copyright (c) 2023, 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 jdk.graal.compiler.java; + +import jdk.graal.compiler.nodes.StructuredGraph; +import jdk.graal.compiler.nodes.graphbuilderconf.GraphBuilderConfiguration; +import jdk.graal.compiler.nodes.graphbuilderconf.IntrinsicContext; +import jdk.graal.compiler.nodes.spi.CoreProviders; +import jdk.graal.compiler.phases.OptimisticOptimizations; +import jdk.vm.ci.meta.ResolvedJavaMethod; + +/** + * This is used when a platform independent instance of {@link BytecodeParser} is needed. In normal + * usage the proper parser from the platform suites should be used instead. + */ +public class DefaultGraphBuilderPhase extends GraphBuilderPhase { + public DefaultGraphBuilderPhase(GraphBuilderConfiguration config) { + super(config); + } + + @Override + public GraphBuilderPhase copyWithConfig(GraphBuilderConfiguration config) { + return new DefaultGraphBuilderPhase(config); + } + + @Override + protected Instance createInstance(CoreProviders providers, GraphBuilderConfiguration instanceGBConfig, OptimisticOptimizations optimisticOpts, IntrinsicContext initialIntrinsicContext) { + return new Instance(providers, instanceGBConfig, optimisticOpts, initialIntrinsicContext); + } + + public static class Instance extends GraphBuilderPhase.Instance { + + public Instance(CoreProviders providers, GraphBuilderConfiguration graphBuilderConfig, OptimisticOptimizations optimisticOpts, IntrinsicContext initialIntrinsicContext) { + super(providers, graphBuilderConfig, optimisticOpts, initialIntrinsicContext); + } + + @Override + protected BytecodeParser createBytecodeParser(StructuredGraph graph, BytecodeParser parent, ResolvedJavaMethod method, int entryBCI, IntrinsicContext intrinsicContext) { + return new DefaultBytecodeParser(this, graph, parent, method, entryBCI, intrinsicContext); + } + } + + /** + * A non-abstract subclass of {@link BytecodeParser}. This exists mainly the use of non-platform + * specific {@link BytecodeParser} can be audited. + */ + static class DefaultBytecodeParser extends BytecodeParser { + protected DefaultBytecodeParser(GraphBuilderPhase.Instance graphBuilderInstance, StructuredGraph graph, BytecodeParser parent, ResolvedJavaMethod method, int entryBCI, + IntrinsicContext intrinsicContext) { + super(graphBuilderInstance, graph, parent, method, entryBCI, intrinsicContext); + } + } +} diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/java/GraphBuilderPhase.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/java/GraphBuilderPhase.java index 770968b6610e..ae1059a9482c 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/java/GraphBuilderPhase.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/java/GraphBuilderPhase.java @@ -31,21 +31,20 @@ import jdk.graal.compiler.nodes.graphbuilderconf.GraphBuilderConfiguration; import jdk.graal.compiler.nodes.graphbuilderconf.IntrinsicContext; import jdk.graal.compiler.nodes.spi.CoreProviders; -import jdk.graal.compiler.phases.Phase; import jdk.graal.compiler.phases.BasePhase; import jdk.graal.compiler.phases.OptimisticOptimizations; +import jdk.graal.compiler.phases.Phase; import jdk.graal.compiler.phases.tiers.HighTierContext; - import jdk.vm.ci.meta.ResolvedJavaMethod; /** * Parses the bytecodes of a method and builds the IR graph. */ -public class GraphBuilderPhase extends BasePhase { +public abstract class GraphBuilderPhase extends BasePhase { private final GraphBuilderConfiguration graphBuilderConfig; - public GraphBuilderPhase(GraphBuilderConfiguration config) { + protected GraphBuilderPhase(GraphBuilderConfiguration config) { this.graphBuilderConfig = config; } @@ -54,6 +53,11 @@ public boolean checkContract() { return false; } + /** + * Create a new instance of this GraphBuilderPhase with the supplied {@code config}. + */ + public abstract GraphBuilderPhase copyWithConfig(GraphBuilderConfiguration config); + @Override public Optional notApplicableTo(GraphState graphState) { return ALWAYS_APPLICABLE; @@ -68,19 +72,16 @@ public GraphBuilderConfiguration getGraphBuilderConfig() { return graphBuilderConfig; } - protected Instance createInstance(CoreProviders providers, GraphBuilderConfiguration instanceGBConfig, OptimisticOptimizations optimisticOpts, IntrinsicContext initialIntrinsicContext) { - return new Instance(providers, instanceGBConfig, optimisticOpts, initialIntrinsicContext); - } + protected abstract Instance createInstance(CoreProviders providers, GraphBuilderConfiguration instanceGBConfig, OptimisticOptimizations optimisticOpts, IntrinsicContext initialIntrinsicContext); - // Fully qualified name is a workaround for JDK-8056066 - public static class Instance extends Phase { + public abstract static class Instance extends Phase { protected final CoreProviders providers; protected final GraphBuilderConfiguration graphBuilderConfig; protected final OptimisticOptimizations optimisticOpts; private final IntrinsicContext initialIntrinsicContext; - public Instance(CoreProviders providers, GraphBuilderConfiguration graphBuilderConfig, OptimisticOptimizations optimisticOpts, IntrinsicContext initialIntrinsicContext) { + protected Instance(CoreProviders providers, GraphBuilderConfiguration graphBuilderConfig, OptimisticOptimizations optimisticOpts, IntrinsicContext initialIntrinsicContext) { this.graphBuilderConfig = graphBuilderConfig; this.optimisticOpts = optimisticOpts; this.providers = providers; @@ -103,8 +104,6 @@ protected void run(StructuredGraph graph) { } /* Hook for subclasses of Instance to provide a subclass of BytecodeParser. */ - protected BytecodeParser createBytecodeParser(StructuredGraph graph, BytecodeParser parent, ResolvedJavaMethod method, int entryBCI, IntrinsicContext intrinsicContext) { - return new BytecodeParser(this, graph, parent, method, entryBCI, intrinsicContext); - } + protected abstract BytecodeParser createBytecodeParser(StructuredGraph graph, BytecodeParser parent, ResolvedJavaMethod method, int entryBCI, IntrinsicContext intrinsicContext); } } diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/java/StableMethodNameFormatter.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/java/StableMethodNameFormatter.java index 4e41bf410602..8a6d6eca90a8 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/java/StableMethodNameFormatter.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/java/StableMethodNameFormatter.java @@ -35,6 +35,7 @@ import org.graalvm.collections.EconomicMap; import org.graalvm.collections.Equivalence; + import jdk.graal.compiler.debug.DebugContext; import jdk.graal.compiler.nodes.Invoke; import jdk.graal.compiler.nodes.StructuredGraph; @@ -43,7 +44,6 @@ import jdk.graal.compiler.phases.OptimisticOptimizations; import jdk.graal.compiler.phases.tiers.HighTierContext; import jdk.graal.compiler.phases.util.Providers; - import jdk.vm.ci.meta.ResolvedJavaMethod; import jdk.vm.ci.meta.ResolvedJavaType; @@ -92,7 +92,7 @@ public class StableMethodNameFormatter implements Function persistentGraphCache; private final EconomicMap localGraphCache; private final Supplier createPersistentCachedGraphScope; private final BasePhase postParsingPhase; private final boolean allowAssumptionsDuringParsing; + private final GraphBuilderPhase.Instance graphBuilderPhaseInstance; /** * Creates a new CachingPEGraphDecoder. @@ -84,11 +82,21 @@ public class CachingPEGraphDecoder extends PEGraphDecoder { * @param forceLink if {@code true} and the graph contains an invoke of a method from a class * that has not yet been linked, linking is performed. */ - public CachingPEGraphDecoder(Architecture architecture, StructuredGraph graph, Providers providers, GraphBuilderConfiguration graphBuilderConfig, OptimisticOptimizations optimisticOpts, - LoopExplosionPlugin loopExplosionPlugin, InvocationPlugins invocationPlugins, InlineInvokePlugin[] inlineInvokePlugins, + public CachingPEGraphDecoder(Architecture architecture, + StructuredGraph graph, + Providers providers, + GraphBuilderConfiguration graphBuilderConfig, + LoopExplosionPlugin loopExplosionPlugin, + InvocationPlugins invocationPlugins, + InlineInvokePlugin[] inlineInvokePlugins, ParameterPlugin parameterPlugin, - NodePlugin[] nodePlugins, ResolvedJavaMethod peRootForInlining, SourceLanguagePositionProvider sourceLanguagePositionProvider, - BasePhase postParsingPhase, EconomicMap persistentGraphCache, Supplier createPersistentCachedGraphScope, + NodePlugin[] nodePlugins, + ResolvedJavaMethod peRootForInlining, + SourceLanguagePositionProvider sourceLanguagePositionProvider, + BasePhase postParsingPhase, + EconomicMap persistentGraphCache, + Supplier createPersistentCachedGraphScope, + GraphBuilderPhase.Instance graphBuilderPhaseInstance, boolean allowAssumptionsDuringParsing, boolean needsExplicitException, boolean forceLink) { @@ -100,16 +108,12 @@ public CachingPEGraphDecoder(Architecture architecture, StructuredGraph graph, P this.providers = providers; this.graphBuilderConfig = graphBuilderConfig; - this.optimisticOpts = optimisticOpts; this.postParsingPhase = postParsingPhase; this.persistentGraphCache = persistentGraphCache; this.createPersistentCachedGraphScope = createPersistentCachedGraphScope; this.localGraphCache = EconomicMap.create(); this.allowAssumptionsDuringParsing = allowAssumptionsDuringParsing; - } - - protected GraphBuilderPhase.Instance createGraphBuilderPhaseInstance(IntrinsicContext initialIntrinsicContext) { - return new GraphBuilderPhase.Instance(providers, graphBuilderConfig, optimisticOpts, initialIntrinsicContext); + this.graphBuilderPhaseInstance = graphBuilderPhaseInstance; } @SuppressWarnings("try") @@ -161,8 +165,6 @@ private StructuredGraph buildGraph(ResolvedJavaMethod method, BytecodeProvider i if (intrinsicBytecodeProvider != null) { throw GraalError.shouldNotReachHere("isn't this dead?"); // ExcludeFromJacocoGeneratedReport } - IntrinsicContext initialIntrinsicContext = null; - GraphBuilderPhase.Instance graphBuilderPhaseInstance = createGraphBuilderPhaseInstance(initialIntrinsicContext); graphBuilderPhaseInstance.apply(graphToEncode); canonicalizer.apply(graphToEncode, providers); if (postParsingPhase != null) { diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/truffle/PartialEvaluator.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/truffle/PartialEvaluator.java index f4988f47d0a5..4ad4b4557378 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/truffle/PartialEvaluator.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/truffle/PartialEvaluator.java @@ -44,6 +44,7 @@ import jdk.graal.compiler.graph.Node; import jdk.graal.compiler.graph.SourceLanguagePosition; import jdk.graal.compiler.graph.SourceLanguagePositionProvider; +import jdk.graal.compiler.java.GraphBuilderPhase; import jdk.graal.compiler.nodes.ConstantNode; import jdk.graal.compiler.nodes.DeoptimizeNode; import jdk.graal.compiler.nodes.EncodedGraph; @@ -60,7 +61,9 @@ import jdk.graal.compiler.nodes.graphbuilderconf.LoopExplosionPlugin; import jdk.graal.compiler.nodes.graphbuilderconf.NodePlugin; import jdk.graal.compiler.nodes.graphbuilderconf.ParameterPlugin; +import jdk.graal.compiler.nodes.spi.CoreProviders; import jdk.graal.compiler.options.OptionValues; +import jdk.graal.compiler.phases.OptimisticOptimizations; import jdk.graal.compiler.phases.contract.NodeCostUtil; import jdk.graal.compiler.phases.util.Providers; import jdk.graal.compiler.replacements.CachingPEGraphDecoder; @@ -409,11 +412,15 @@ protected PEGraphDecoder createGraphDecoder(TruffleTierContext context, Invocati Providers compilationUnitProviders = config.lastTier().providers().copyWith(constantFieldProvider); assert !allowAssumptionsDuringParsing || !persistentEncodedGraphCache; - return new CachingPEGraphDecoder(config.architecture(), context.graph, compilationUnitProviders, newConfig, TruffleCompilerImpl.Optimizations, + return new CachingPEGraphDecoder(config.architecture(), context.graph, compilationUnitProviders, newConfig, loopExplosionPlugin, decodingPlugins, inlineInvokePlugins, parameterPlugin, nodePluginList, types.OptimizedCallTarget_callInlined, - sourceLanguagePositionProvider, postParsingPhase, graphCache, createCachedGraphScope, allowAssumptionsDuringParsing, false, true); + sourceLanguagePositionProvider, postParsingPhase, graphCache, createCachedGraphScope, + createGraphBuilderPhaseInstance(compilationUnitProviders, newConfig, TruffleCompilerImpl.Optimizations), + allowAssumptionsDuringParsing, false, true); } + protected abstract GraphBuilderPhase.Instance createGraphBuilderPhaseInstance(CoreProviders providers, GraphBuilderConfiguration graphBuilderConfig, OptimisticOptimizations optimisticOpts); + @SuppressWarnings("try") public void doGraphPE(TruffleTierContext context, InlineInvokePlugin inlineInvokePlugin, EconomicMap graphCache) { InlineInvokePlugin[] inlineInvokePlugins = new InlineInvokePlugin[]{ diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/truffle/hotspot/HotSpotPartialEvaluator.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/truffle/hotspot/HotSpotPartialEvaluator.java index ffef4c899bcb..22d26b2950b2 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/truffle/hotspot/HotSpotPartialEvaluator.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/truffle/hotspot/HotSpotPartialEvaluator.java @@ -30,20 +30,24 @@ import java.util.function.Supplier; import org.graalvm.collections.EconomicMap; + +import com.oracle.truffle.compiler.ConstantFieldInfo; +import com.oracle.truffle.compiler.PartialEvaluationMethodInfo; + import jdk.graal.compiler.core.common.util.FieldKey; import jdk.graal.compiler.core.common.util.MethodKey; import jdk.graal.compiler.hotspot.HotSpotGraalServices; +import jdk.graal.compiler.hotspot.HotSpotGraphBuilderInstance; +import jdk.graal.compiler.java.GraphBuilderPhase; import jdk.graal.compiler.nodes.EncodedGraph; import jdk.graal.compiler.nodes.graphbuilderconf.GraphBuilderConfiguration; import jdk.graal.compiler.nodes.graphbuilderconf.InvocationPlugins; +import jdk.graal.compiler.nodes.spi.CoreProviders; import jdk.graal.compiler.options.OptionValues; +import jdk.graal.compiler.phases.OptimisticOptimizations; import jdk.graal.compiler.truffle.PartialEvaluator; import jdk.graal.compiler.truffle.TruffleCompilerConfiguration; import jdk.graal.compiler.truffle.TruffleElementCache; - -import com.oracle.truffle.compiler.ConstantFieldInfo; -import com.oracle.truffle.compiler.PartialEvaluationMethodInfo; - import jdk.vm.ci.meta.ResolvedJavaField; import jdk.vm.ci.meta.ResolvedJavaMethod; @@ -76,6 +80,11 @@ public int getJvmciReservedReference0Offset() { return jvmciReservedReference0Offset; } + @Override + protected GraphBuilderPhase.Instance createGraphBuilderPhaseInstance(CoreProviders providers, GraphBuilderConfiguration graphBuilderConfig, OptimisticOptimizations optimisticOpts) { + return new HotSpotGraphBuilderInstance(providers, graphBuilderConfig, optimisticOpts, null); + } + @Override protected void initialize(OptionValues options) { super.initialize(options); diff --git a/substratevm/src/com.oracle.graal.pointsto.standalone/src/com/oracle/graal/pointsto/standalone/plugins/StandaloneGraphBuilderPhase.java b/substratevm/src/com.oracle.graal.pointsto.standalone/src/com/oracle/graal/pointsto/standalone/plugins/StandaloneGraphBuilderPhase.java index 4b941e94f50e..9fb9a0445ec0 100644 --- a/substratevm/src/com.oracle.graal.pointsto.standalone/src/com/oracle/graal/pointsto/standalone/plugins/StandaloneGraphBuilderPhase.java +++ b/substratevm/src/com.oracle.graal.pointsto.standalone/src/com/oracle/graal/pointsto/standalone/plugins/StandaloneGraphBuilderPhase.java @@ -26,13 +26,13 @@ package com.oracle.graal.pointsto.standalone.plugins; -import jdk.graal.compiler.java.GraphBuilderPhase; +import jdk.graal.compiler.java.DefaultGraphBuilderPhase; import jdk.graal.compiler.nodes.graphbuilderconf.GraphBuilderConfiguration; import jdk.graal.compiler.nodes.graphbuilderconf.IntrinsicContext; import jdk.graal.compiler.nodes.spi.CoreProviders; import jdk.graal.compiler.phases.OptimisticOptimizations; -public class StandaloneGraphBuilderPhase extends GraphBuilderPhase.Instance { +public class StandaloneGraphBuilderPhase extends DefaultGraphBuilderPhase.Instance { public StandaloneGraphBuilderPhase(CoreProviders providers, GraphBuilderConfiguration graphBuilderConfig, OptimisticOptimizations optimisticOpts, IntrinsicContext initialIntrinsicContext) { super(providers, graphBuilderConfig, optimisticOpts, initialIntrinsicContext); } diff --git a/substratevm/src/com.oracle.svm.core.graal.aarch64/src/com/oracle/svm/core/graal/aarch64/AArch64SubstrateSuitesCreator.java b/substratevm/src/com.oracle.svm.core.graal.aarch64/src/com/oracle/svm/core/graal/aarch64/AArch64SubstrateSuitesCreator.java index d85fa5c9be5d..485fe020bad0 100644 --- a/substratevm/src/com.oracle.svm.core.graal.aarch64/src/com/oracle/svm/core/graal/aarch64/AArch64SubstrateSuitesCreator.java +++ b/substratevm/src/com.oracle.svm.core.graal.aarch64/src/com/oracle/svm/core/graal/aarch64/AArch64SubstrateSuitesCreator.java @@ -25,6 +25,7 @@ package com.oracle.svm.core.graal.aarch64; import jdk.graal.compiler.core.aarch64.AArch64SuitesCreator; +import jdk.graal.compiler.java.DefaultGraphBuilderPhase; import jdk.graal.compiler.java.GraphBuilderPhase; import jdk.graal.compiler.nodes.graphbuilderconf.GraphBuilderConfiguration; import jdk.graal.compiler.phases.tiers.CompilerConfiguration; @@ -37,7 +38,7 @@ public AArch64SubstrateSuitesCreator(CompilerConfiguration compilerConfiguration @Override protected GraphBuilderPhase createGraphBuilderPhase(GraphBuilderConfiguration graphBuilderConfiguration) { - return new GraphBuilderPhase(graphBuilderConfiguration); + return new DefaultGraphBuilderPhase(graphBuilderConfiguration); } } diff --git a/substratevm/src/com.oracle.svm.core.graal.amd64/src/com/oracle/svm/core/graal/amd64/AMD64SubstrateSuitesCreator.java b/substratevm/src/com.oracle.svm.core.graal.amd64/src/com/oracle/svm/core/graal/amd64/AMD64SubstrateSuitesCreator.java index 9639b648d33f..870bc4e99114 100644 --- a/substratevm/src/com.oracle.svm.core.graal.amd64/src/com/oracle/svm/core/graal/amd64/AMD64SubstrateSuitesCreator.java +++ b/substratevm/src/com.oracle.svm.core.graal.amd64/src/com/oracle/svm/core/graal/amd64/AMD64SubstrateSuitesCreator.java @@ -25,6 +25,7 @@ package com.oracle.svm.core.graal.amd64; import jdk.graal.compiler.core.amd64.AMD64SuitesCreator; +import jdk.graal.compiler.java.DefaultGraphBuilderPhase; import jdk.graal.compiler.java.GraphBuilderPhase; import jdk.graal.compiler.nodes.graphbuilderconf.GraphBuilderConfiguration; import jdk.graal.compiler.phases.tiers.CompilerConfiguration; @@ -37,7 +38,7 @@ public AMD64SubstrateSuitesCreator(CompilerConfiguration compilerConfiguration) @Override protected GraphBuilderPhase createGraphBuilderPhase(GraphBuilderConfiguration graphBuilderConfiguration) { - return new GraphBuilderPhase(graphBuilderConfiguration); + return new DefaultGraphBuilderPhase(graphBuilderConfiguration); } } diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/graal/code/SubstrateSuitesCreator.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/graal/code/SubstrateSuitesCreator.java index 2bd5d5881848..8a9c4cf3eea8 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/graal/code/SubstrateSuitesCreator.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/graal/code/SubstrateSuitesCreator.java @@ -24,6 +24,7 @@ */ package com.oracle.svm.core.graal.code; +import jdk.graal.compiler.java.DefaultGraphBuilderPhase; import jdk.graal.compiler.java.DefaultSuitesCreator; import jdk.graal.compiler.java.GraphBuilderPhase; import jdk.graal.compiler.nodes.graphbuilderconf.GraphBuilderConfiguration; @@ -37,7 +38,7 @@ public SubstrateSuitesCreator(CompilerConfiguration compilerConfiguration) { @Override protected GraphBuilderPhase createGraphBuilderPhase(GraphBuilderConfiguration graphBuilderConfiguration) { - return new GraphBuilderPhase(graphBuilderConfiguration); + return new DefaultGraphBuilderPhase(graphBuilderConfiguration); } } diff --git a/substratevm/src/com.oracle.svm.graal.hotspot.libgraal/src/com/oracle/svm/graal/hotspot/libgraal/LibGraalFeature.java b/substratevm/src/com.oracle.svm.graal.hotspot.libgraal/src/com/oracle/svm/graal/hotspot/libgraal/LibGraalFeature.java index e6a69114e665..75a8f54df3d8 100644 --- a/substratevm/src/com.oracle.svm.graal.hotspot.libgraal/src/com/oracle/svm/graal/hotspot/libgraal/LibGraalFeature.java +++ b/substratevm/src/com.oracle.svm.graal.hotspot.libgraal/src/com/oracle/svm/graal/hotspot/libgraal/LibGraalFeature.java @@ -963,6 +963,11 @@ private static boolean notifyCrash(String crashMessage) { final class Target_jdk_graal_compiler_hotspot_SymbolicSnippetEncoder { } +@TargetClass(className = "jdk.graal.compiler.java.DefaultGraphBuilderPhase$DefaultBytecodeParser", onlyWith = LibGraalFeature.IsEnabled.class) +@Delete("shouldn't appear in libgraal") +final class Target_jdk_graal_compiler_java_DefaultGraphBuilderPhase_DefaultBytecodeParser { +} + @TargetClass(value = HotSpotForeignCallLinkageImpl.class, onlyWith = LibGraalFeature.IsEnabled.class) final class Target_jdk_graal_compiler_hotspot_HotSpotForeignCallLinkageImpl { /** diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/lambda/LambdaSubstrateGraphBuilderPhase.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/lambda/LambdaSubstrateGraphBuilderPhase.java index 375b2372a739..af3fe2815911 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/lambda/LambdaSubstrateGraphBuilderPhase.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/lambda/LambdaSubstrateGraphBuilderPhase.java @@ -43,6 +43,11 @@ public LambdaSubstrateGraphBuilderPhase(GraphBuilderConfiguration config) { super(config); } + @Override + public GraphBuilderPhase copyWithConfig(GraphBuilderConfiguration config) { + return new LambdaSubstrateGraphBuilderPhase(config); + } + @Override protected Instance createInstance(CoreProviders providers, GraphBuilderConfiguration instanceGBConfig, OptimisticOptimizations optimisticOpts, IntrinsicContext initialIntrinsicContext) { return new LambdaSubstrateGraphBuilderInstance(providers, instanceGBConfig, optimisticOpts, initialIntrinsicContext); diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/phases/IntrinsifyMethodHandlesInvocationPlugin.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/phases/IntrinsifyMethodHandlesInvocationPlugin.java index be055c089ecc..55beff2cf285 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/phases/IntrinsifyMethodHandlesInvocationPlugin.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/phases/IntrinsifyMethodHandlesInvocationPlugin.java @@ -72,6 +72,7 @@ import jdk.graal.compiler.graph.NodeClass; import jdk.graal.compiler.graph.NodeMap; import jdk.graal.compiler.java.BytecodeParser; +import jdk.graal.compiler.java.DefaultGraphBuilderPhase; import jdk.graal.compiler.java.GraphBuilderPhase; import jdk.graal.compiler.nodeinfo.NodeCycles; import jdk.graal.compiler.nodeinfo.NodeInfo; @@ -541,7 +542,7 @@ private boolean processInvokeWithMethodHandle(GraphBuilderContext b, Replacement graphBuilderPlugins.setClassInitializationPlugin(new NoClassInitializationPlugin()); GraphBuilderConfiguration graphBuilderConfig = GraphBuilderConfiguration.getSnippetDefault(graphBuilderPlugins); - GraphBuilderPhase.Instance graphBuilder = new GraphBuilderPhase.Instance(parsingProviders, graphBuilderConfig, OptimisticOptimizations.NONE, null); + GraphBuilderPhase.Instance graphBuilder = new DefaultGraphBuilderPhase.Instance(parsingProviders, graphBuilderConfig, OptimisticOptimizations.NONE, null); DebugContext debug = b.getDebug(); StructuredGraph graph = new StructuredGraph.Builder(b.getOptions(), debug) diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/reflect/serialize/SerializationFeature.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/reflect/serialize/SerializationFeature.java index 367cea10ee1d..afe382878ab6 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/reflect/serialize/SerializationFeature.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/reflect/serialize/SerializationFeature.java @@ -83,6 +83,7 @@ import jdk.graal.compiler.debug.DebugContext; import jdk.graal.compiler.graph.iterators.NodeIterable; +import jdk.graal.compiler.java.DefaultGraphBuilderPhase; import jdk.graal.compiler.java.GraphBuilderPhase; import jdk.graal.compiler.java.LambdaUtils; import jdk.graal.compiler.nodes.ConstantNode; @@ -212,7 +213,7 @@ private static void registerLambdasFromConstantNodesInGraph(StructuredGraph grap @SuppressWarnings("try") private static void registerLambdasFromMethod(ResolvedJavaMethod method, SerializationBuilder serializationBuilder, OptionValues options) { - GraphBuilderPhase lambdaParserPhase = new GraphBuilderPhase(buildLambdaParserConfig()); + GraphBuilderPhase lambdaParserPhase = new DefaultGraphBuilderPhase(buildLambdaParserConfig()); StructuredGraph graph = createMethodGraph(method, lambdaParserPhase, options); registerLambdasFromConstantNodesInGraph(graph, serializationBuilder); } diff --git a/substratevm/src/com.oracle.svm.truffle/src/com/oracle/svm/truffle/api/SubstratePartialEvaluator.java b/substratevm/src/com.oracle.svm.truffle/src/com/oracle/svm/truffle/api/SubstratePartialEvaluator.java index 0bb5779e22e9..a0ceaf9cce3d 100644 --- a/substratevm/src/com.oracle.svm.truffle/src/com/oracle/svm/truffle/api/SubstratePartialEvaluator.java +++ b/substratevm/src/com.oracle.svm.truffle/src/com/oracle/svm/truffle/api/SubstratePartialEvaluator.java @@ -28,7 +28,15 @@ import java.util.function.Supplier; import org.graalvm.collections.EconomicMap; +import org.graalvm.nativeimage.Platform; +import org.graalvm.nativeimage.Platforms; + +import com.oracle.truffle.compiler.ConstantFieldInfo; +import com.oracle.truffle.compiler.PartialEvaluationMethodInfo; + import jdk.graal.compiler.graph.SourceLanguagePositionProvider; +import jdk.graal.compiler.java.DefaultGraphBuilderPhase; +import jdk.graal.compiler.java.GraphBuilderPhase; import jdk.graal.compiler.nodes.EncodedGraph; import jdk.graal.compiler.nodes.StructuredGraph; import jdk.graal.compiler.nodes.graphbuilderconf.GraphBuilderConfiguration; @@ -37,6 +45,8 @@ import jdk.graal.compiler.nodes.graphbuilderconf.InvocationPlugins; import jdk.graal.compiler.nodes.graphbuilderconf.NodePlugin; import jdk.graal.compiler.nodes.graphbuilderconf.ParameterPlugin; +import jdk.graal.compiler.nodes.spi.CoreProviders; +import jdk.graal.compiler.phases.OptimisticOptimizations; import jdk.graal.compiler.phases.util.Providers; import jdk.graal.compiler.replacements.PEGraphDecoder; import jdk.graal.compiler.replacements.PEGraphDecoder.SpecialCallTargetCacheKey; @@ -44,12 +54,6 @@ import jdk.graal.compiler.truffle.PartialEvaluatorConfiguration; import jdk.graal.compiler.truffle.TruffleCompilerConfiguration; import jdk.graal.compiler.truffle.TruffleTierContext; -import org.graalvm.nativeimage.Platform; -import org.graalvm.nativeimage.Platforms; - -import com.oracle.truffle.compiler.ConstantFieldInfo; -import com.oracle.truffle.compiler.PartialEvaluationMethodInfo; - import jdk.vm.ci.meta.ResolvedJavaField; import jdk.vm.ci.meta.ResolvedJavaMethod; @@ -73,6 +77,11 @@ protected PEGraphDecoder createGraphDecoder(TruffleTierContext context, Invocati inlineInvokePlugins, parameterPlugin, nodePlugins, types.OptimizedCallTarget_callInlined, sourceLanguagePositionProvider, specialCallTargetCache, invocationPluginsCache); } + @Override + protected GraphBuilderPhase.Instance createGraphBuilderPhaseInstance(CoreProviders providers, GraphBuilderConfiguration graphBuilderConfig, OptimisticOptimizations optimisticOpts) { + return new DefaultGraphBuilderPhase.Instance(providers, graphBuilderConfig, optimisticOpts, null); + } + @Override protected StructuredGraph.Builder customizeStructuredGraphBuilder(StructuredGraph.Builder builder) { /* From 2d5aa3125165983ab45db9e709009f802a6e24c7 Mon Sep 17 00:00:00 2001 From: Christian Wimmer Date: Wed, 17 Jan 2024 12:41:50 -0800 Subject: [PATCH 518/593] Registering a class as initialize-at-build-time should immediately trigger initialization --- .../hosted/RuntimeClassInitialization.java | 12 +- ...ostedUsagesClassInitializationSupport.java | 27 +-- .../test/clinit/TestClassInitialization.java | 154 ++++++++++++++++++ 3 files changed, 173 insertions(+), 20 deletions(-) diff --git a/sdk/src/org.graalvm.nativeimage/src/org/graalvm/nativeimage/hosted/RuntimeClassInitialization.java b/sdk/src/org.graalvm.nativeimage/src/org/graalvm/nativeimage/hosted/RuntimeClassInitialization.java index 5d9a0ebc98a5..e2f32a2f425d 100644 --- a/sdk/src/org.graalvm.nativeimage/src/org/graalvm/nativeimage/hosted/RuntimeClassInitialization.java +++ b/sdk/src/org.graalvm.nativeimage/src/org/graalvm/nativeimage/hosted/RuntimeClassInitialization.java @@ -103,12 +103,20 @@ public static void initializeAtRunTime(Class... classes) { /** * Registers the provided classes as eagerly initialized during image-build time. *

      - * All static initializers of {@code classes} will be executed during image-build time and - * static fields that are assigned values will be available at runtime. {@code static final} + * All static initializers of {@code classes} will be executed immediately at image-build time + * and static fields that are assigned values will be available at runtime. {@code static final} * fields will be considered as constant. *

      * It is up to the user to ensure that this behavior makes sense and does not lead to wrong * application behavior. + *

      + * After this method returns, all listed classes are initialized in the VM that runs the image + * generator. Therefore, this method can be used to resolve deadlocks and cycles in class + * initializer by starting initialization with a known-good entry class. + *

      + * All superclasses and superinterfaces that are initialized before any of the listed classes + * are registered for initialization at build time too. Please look at the Java specification + * for the exact rules, especially regarding interfaces that declare default methods. * * @since 19.0 */ diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/classinitialization/AllowAllHostedUsagesClassInitializationSupport.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/classinitialization/AllowAllHostedUsagesClassInitializationSupport.java index 3e0d94661338..f9b73e77c941 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/classinitialization/AllowAllHostedUsagesClassInitializationSupport.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/classinitialization/AllowAllHostedUsagesClassInitializationSupport.java @@ -26,14 +26,13 @@ import java.lang.reflect.Proxy; -import jdk.graal.compiler.java.LambdaUtils; - import com.oracle.graal.pointsto.meta.AnalysisMetaAccess; import com.oracle.graal.pointsto.meta.AnalysisUniverse; import com.oracle.svm.core.util.UserError; import com.oracle.svm.core.util.VMError; import com.oracle.svm.hosted.ImageClassLoader; +import jdk.graal.compiler.java.LambdaUtils; import jdk.vm.ci.meta.MetaAccessProvider; class AllowAllHostedUsagesClassInitializationSupport extends ClassInitializationSupport { @@ -45,21 +44,7 @@ class AllowAllHostedUsagesClassInitializationSupport extends ClassInitialization @Override public void initializeAtBuildTime(Class aClass, String reason) { UserError.guarantee(!configurationSealed, "The class initialization configuration can be changed only before the phase analysis."); - Class cur = aClass; - do { - classInitializationConfiguration.insert(cur.getTypeName(), InitKind.BUILD_TIME, cur == aClass ? reason : "super type of " + aClass.getTypeName(), true); - initializeInterfacesAtBuildTime(cur.getInterfaces(), "interface of " + aClass.getTypeName()); - cur = cur.getSuperclass(); - } while (cur != null); - } - - private void initializeInterfacesAtBuildTime(Class[] interfaces, String reason) { - for (Class iface : interfaces) { - if (metaAccess.lookupJavaType(iface).declaresDefaultMethods()) { - classInitializationConfiguration.insert(iface.getTypeName(), InitKind.BUILD_TIME, reason, true); - } - initializeInterfacesAtBuildTime(iface.getInterfaces(), reason); - } + forceInitializeHosted(aClass, reason, false); } @Override @@ -103,7 +88,13 @@ public void forceInitializeHosted(Class clazz, String reason, boolean allowIn classInitKinds.put(clazz, initKind); forceInitializeHosted(clazz.getSuperclass(), "super type of " + clazz.getTypeName(), allowInitializationErrors); - forceInitializeInterfaces(clazz.getInterfaces(), "super type of " + clazz.getTypeName()); + if (!clazz.isInterface()) { + /* + * Initialization of an interface does not trigger initialization of superinterfaces. + * Regardless whether any of the involved interfaces declare default methods. + */ + forceInitializeInterfaces(clazz.getInterfaces(), "super type of " + clazz.getTypeName()); + } } private void forceInitializeInterfaces(Class[] interfaces, String reason) { diff --git a/substratevm/src/com.oracle.svm.test/src/com/oracle/svm/test/clinit/TestClassInitialization.java b/substratevm/src/com.oracle.svm.test/src/com/oracle/svm/test/clinit/TestClassInitialization.java index 983a46edc6e9..0eb3cf8a072d 100644 --- a/substratevm/src/com.oracle.svm.test/src/com/oracle/svm/test/clinit/TestClassInitialization.java +++ b/substratevm/src/com.oracle.svm.test/src/com/oracle/svm/test/clinit/TestClassInitialization.java @@ -28,6 +28,7 @@ import java.lang.reflect.Method; import java.util.ArrayList; import java.util.Arrays; +import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -663,6 +664,100 @@ static synchronized int synchronizedMethod() { } } +class InitializationOrder { + static final List> initializationOrder = Collections.synchronizedList(new ArrayList<>()); +} + +interface Test1_I1 { + default void defaultI1() { + } + + int order = add(); + + static int add() { + InitializationOrder.initializationOrder.add(Test1_I1.class); + return 42; + } +} + +interface Test1_I2 extends Test1_I1 { + int order = add(); + + static int add() { + InitializationOrder.initializationOrder.add(Test1_I2.class); + return 42; + } +} + +interface Test1_I3 extends Test1_I2 { + default void defaultI3() { + } + + int order = add(); + + static int add() { + InitializationOrder.initializationOrder.add(Test1_I3.class); + return 42; + } +} + +interface Test1_I4 extends Test1_I3 { + int order = add(); + + static int add() { + InitializationOrder.initializationOrder.add(Test1_I4.class); + return 42; + } +} + +class Test1_A implements Test1_I4 { + static { + InitializationOrder.initializationOrder.add(Test1_A.class); + } +} + +interface Test2_I1 { + default void defaultI1() { + } + + int order = add(); + + static int add() { + InitializationOrder.initializationOrder.add(Test2_I1.class); + return 42; + } +} + +interface Test2_I2 extends Test2_I1 { + int order = add(); + + static int add() { + InitializationOrder.initializationOrder.add(Test2_I2.class); + return 42; + } +} + +interface Test2_I3 extends Test2_I2 { + default void defaultI3() { + } + + int order = add(); + + static int add() { + InitializationOrder.initializationOrder.add(Test2_I3.class); + return 42; + } +} + +interface Test2_I4 extends Test2_I3 { + int order = add(); + + static int add() { + InitializationOrder.initializationOrder.add(Test2_I4.class); + return 42; + } +} + abstract class TestClassInitializationFeature implements Feature { private void checkClasses(boolean checkSafeEarly, boolean checkSafeLate) { @@ -695,6 +790,65 @@ abstract void checkClass(Class checkedClass, boolean checkSafeEarly, boolean public void afterRegistration(AfterRegistrationAccess access) { /* We need to access the checkedClasses array both at image build time and run time. */ RuntimeClassInitialization.initializeAtBuildTime(TestClassInitialization.class); + + /* + * Initialization of a class first triggers initialization of all superinterfaces that + * declared default methods. + */ + InitializationOrder.initializationOrder.clear(); + assertNotInitialized(Test1_I1.class, Test1_I2.class, Test1_I3.class, Test1_I4.class, Test1_A.class); + RuntimeClassInitialization.initializeAtBuildTime(Test1_A.class); + assertNotInitialized(Test1_I2.class, Test1_I4.class); + assertInitialized(Test1_I1.class, Test1_I3.class, Test1_A.class); + assertArraysEqual(new Object[]{Test1_I1.class, Test1_I3.class, Test1_A.class}, InitializationOrder.initializationOrder.toArray()); + + /* + * The old class initialization policy is wrong regarding interfaces, but we do not want to + * change that now because it will be deleted soon. + */ + if (TestClassInitialization.simulationEnabled) { + + /* + * Initialization of an interface does not trigger initialization of superinterfaces. + * Regardless whether any of the involved interfaces declare default methods. + */ + InitializationOrder.initializationOrder.clear(); + assertNotInitialized(Test2_I1.class, Test2_I2.class, Test2_I3.class, Test2_I4.class); + RuntimeClassInitialization.initializeAtBuildTime(Test2_I4.class); + assertNotInitialized(Test2_I1.class, Test2_I2.class, Test2_I3.class); + assertInitialized(Test2_I4.class); + assertArraysEqual(new Object[]{Test2_I4.class}, InitializationOrder.initializationOrder.toArray()); + RuntimeClassInitialization.initializeAtBuildTime(Test2_I3.class); + assertNotInitialized(Test2_I1.class, Test2_I2.class); + assertInitialized(Test2_I3.class, Test2_I4.class); + assertArraysEqual(new Object[]{Test2_I4.class, Test2_I3.class}, InitializationOrder.initializationOrder.toArray()); + RuntimeClassInitialization.initializeAtBuildTime(Test2_I2.class); + assertNotInitialized(Test2_I1.class); + assertInitialized(Test2_I2.class, Test2_I3.class, Test2_I4.class); + assertArraysEqual(new Object[]{Test2_I4.class, Test2_I3.class, Test2_I2.class}, InitializationOrder.initializationOrder.toArray()); + } + } + + private void assertNotInitialized(Class... classes) { + for (var clazz : classes) { + if (!Unsafe.getUnsafe().shouldBeInitialized(clazz)) { + throw new AssertionError("Already initialized: " + clazz); + } + } + } + + private void assertInitialized(Class... classes) { + for (var clazz : classes) { + if (Unsafe.getUnsafe().shouldBeInitialized(clazz)) { + throw new AssertionError("Not initialized: " + clazz); + } + } + } + + private static void assertArraysEqual(Object[] expected, Object[] actual) { + if (!Arrays.equals(expected, actual)) { + throw new RuntimeException("expected " + Arrays.toString(expected) + " but found " + Arrays.toString(actual)); + } } @Override From 1b6b909a3b60afa8e185fdca62018bfd964df0e8 Mon Sep 17 00:00:00 2001 From: Tom Rodriguez Date: Wed, 17 Jan 2024 13:03:23 -0800 Subject: [PATCH 519/593] Move DefaultGraphBuilderPhase into test package --- .../microbenchmarks/graal/util/GraalUtil.java | 2 +- .../core/test/CheckGraalInvariants.java | 5 ++- .../core/test}/DefaultGraphBuilderPhase.java | 4 +- .../core/test/FinalizableSubclassTest.java | 1 - .../compiler/core/test/GraalCompilerTest.java | 12 ++++- .../compiler/core/test/NewInstanceTest.java | 1 - .../core/test/StaticInterfaceFieldTest.java | 1 - .../core/test/UnbalancedMonitorsTest.java | 1 - .../core/test/VerifyAssertionUsageTest.java | 1 - .../core/test/VerifyBailoutUsageTest.java | 1 - .../core/test/VerifyDebugUsageTest.java | 1 - .../core/test/VerifyVirtualizableTest.java | 1 - .../core/test/tutorial/StaticAnalysis.java | 2 +- .../hotspot/test/LambdaStableNameTest.java | 2 +- .../replacements/test/PEGraphDecoderTest.java | 2 +- .../replacements/test/SnippetsTest.java | 2 +- .../HotSpotStableMethodNameFormatter.java | 7 +-- .../java/StableMethodNameFormatter.java | 24 +++++----- .../pointsto/standalone/StandaloneHost.java | 2 +- .../plugins/StandaloneGraphBuilderPhase.java | 44 +++++++++++++++++-- .../AArch64SubstrateSuitesCreator.java | 4 +- .../amd64/AMD64SubstrateSuitesCreator.java | 4 +- .../graal/code/SubstrateSuitesCreator.java | 4 +- .../hotspot/libgraal/LibGraalFeature.java | 5 --- ...trinsifyMethodHandlesInvocationPlugin.java | 4 +- .../serialize/SerializationFeature.java | 2 +- .../api/SubstratePartialEvaluator.java | 4 +- 27 files changed, 88 insertions(+), 55 deletions(-) rename compiler/src/{jdk.graal.compiler/src/jdk/graal/compiler/java => jdk.graal.compiler.test/src/jdk/graal/compiler/core/test}/DefaultGraphBuilderPhase.java (96%) diff --git a/compiler/src/jdk.graal.compiler.microbenchmarks/src/jdk/graal/compiler/microbenchmarks/graal/util/GraalUtil.java b/compiler/src/jdk.graal.compiler.microbenchmarks/src/jdk/graal/compiler/microbenchmarks/graal/util/GraalUtil.java index 07e1f93aaf99..a891b3db866d 100644 --- a/compiler/src/jdk.graal.compiler.microbenchmarks/src/jdk/graal/compiler/microbenchmarks/graal/util/GraalUtil.java +++ b/compiler/src/jdk.graal.compiler.microbenchmarks/src/jdk/graal/compiler/microbenchmarks/graal/util/GraalUtil.java @@ -27,8 +27,8 @@ import java.lang.reflect.Method; import java.util.List; +import jdk.graal.compiler.core.test.DefaultGraphBuilderPhase; import jdk.graal.compiler.graph.Node; -import jdk.graal.compiler.java.DefaultGraphBuilderPhase; import jdk.graal.compiler.nodes.StructuredGraph; import jdk.graal.compiler.nodes.StructuredGraph.AllowAssumptions; import jdk.graal.compiler.nodes.graphbuilderconf.GraphBuilderConfiguration; diff --git a/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/core/test/CheckGraalInvariants.java b/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/core/test/CheckGraalInvariants.java index f13ead5dfca1..eb2df16c6eff 100644 --- a/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/core/test/CheckGraalInvariants.java +++ b/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/core/test/CheckGraalInvariants.java @@ -73,7 +73,6 @@ import jdk.graal.compiler.debug.GraalError; import jdk.graal.compiler.graph.Node; import jdk.graal.compiler.graph.NodeClass; -import jdk.graal.compiler.java.DefaultGraphBuilderPhase; import jdk.graal.compiler.nodeinfo.NodeInfo; import jdk.graal.compiler.nodes.FrameState; import jdk.graal.compiler.nodes.PhiNode; @@ -142,6 +141,10 @@ private static boolean shouldVerifyEquals(ResolvedJavaMethod m) { return true; } + public static void main(String[] args) { + + } + public static String relativeFileName(String absolutePath) { int lastFileSeparatorIndex = absolutePath.lastIndexOf(File.separator); return absolutePath.substring(lastFileSeparatorIndex >= 0 ? lastFileSeparatorIndex : 0); diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/java/DefaultGraphBuilderPhase.java b/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/core/test/DefaultGraphBuilderPhase.java similarity index 96% rename from compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/java/DefaultGraphBuilderPhase.java rename to compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/core/test/DefaultGraphBuilderPhase.java index 7c24b438d550..ad3ba8f38007 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/java/DefaultGraphBuilderPhase.java +++ b/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/core/test/DefaultGraphBuilderPhase.java @@ -22,8 +22,10 @@ * or visit www.oracle.com if you need additional information or have any * questions. */ -package jdk.graal.compiler.java; +package jdk.graal.compiler.core.test; +import jdk.graal.compiler.java.BytecodeParser; +import jdk.graal.compiler.java.GraphBuilderPhase; import jdk.graal.compiler.nodes.StructuredGraph; import jdk.graal.compiler.nodes.graphbuilderconf.GraphBuilderConfiguration; import jdk.graal.compiler.nodes.graphbuilderconf.IntrinsicContext; diff --git a/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/core/test/FinalizableSubclassTest.java b/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/core/test/FinalizableSubclassTest.java index 9cad025ca71d..72050663b966 100644 --- a/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/core/test/FinalizableSubclassTest.java +++ b/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/core/test/FinalizableSubclassTest.java @@ -34,7 +34,6 @@ import org.junit.Test; import jdk.graal.compiler.debug.DebugContext; -import jdk.graal.compiler.java.DefaultGraphBuilderPhase; import jdk.graal.compiler.nodes.StructuredGraph; import jdk.graal.compiler.nodes.StructuredGraph.AllowAssumptions; import jdk.graal.compiler.nodes.extended.LoadHubNode; diff --git a/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/core/test/GraalCompilerTest.java b/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/core/test/GraalCompilerTest.java index 9dce45fab91f..8e368f66adb9 100644 --- a/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/core/test/GraalCompilerTest.java +++ b/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/core/test/GraalCompilerTest.java @@ -503,7 +503,7 @@ protected void assertEquals(StructuredGraph expected, boolean checkConstants, boolean addGaphsToDebugContext) { DebugContext debug = actual.getDebug(); - actual.getOptimizationLog().emit(new StableMethodNameFormatter(getProviders(), debug)); + actual.getOptimizationLog().emit(new StableMethodNameFormatter(getDefaultGraphBuilderPhase(), getProviders(), debug)); String expectedString = getCanonicalGraphString(expected, excludeVirtual, checkConstants); String actualString = getCanonicalGraphString(actual, excludeVirtual, checkConstants); @@ -1263,7 +1263,7 @@ protected CompilationResult compile(ResolvedJavaMethod installedCodeOwner, Struc Request request = new Request<>(graphToCompile, installedCodeOwner, getProviders(), getBackend(), getDefaultGraphBuilderSuite(), getOptimisticOptimizations(), graphToCompile.getProfilingInfo(), suites, createLIRSuites(options), compilationResult, CompilationResultBuilderFactory.Default, null, true); CompilationResult result = GraalCompiler.compile(request); - graphToCompile.getOptimizationLog().emit(new StableMethodNameFormatter(getProviders(), graphToCompile.getDebug())); + graphToCompile.getOptimizationLog().emit(new StableMethodNameFormatter(getDefaultGraphBuilderPhase(), getProviders(), graphToCompile.getDebug())); return result; } catch (Throwable e) { throw debug.handle(e); @@ -1610,6 +1610,14 @@ protected PhaseSuite getDefaultGraphBuilderSuite() { return backend.getSuites().getDefaultGraphBuilderSuite().copy(); } + protected GraphBuilderPhase getDefaultGraphBuilderPhase() { + return (GraphBuilderPhase) getDefaultGraphBuilderSuite().findPhase(GraphBuilderPhase.class).previous(); + } + + protected GraphBuilderPhase getDefaultGraphBuilderPhase(GraphBuilderConfiguration config) { + return getDefaultGraphBuilderPhase().copyWithConfig(config); + } + /** * Registers extra invocation plugins for this test. The extra plugins are removed in the * {@link #afterTest()} method. diff --git a/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/core/test/NewInstanceTest.java b/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/core/test/NewInstanceTest.java index a5c2b2a7f644..1e8d6ce48902 100644 --- a/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/core/test/NewInstanceTest.java +++ b/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/core/test/NewInstanceTest.java @@ -32,7 +32,6 @@ import org.junit.Assert; import org.junit.Test; -import jdk.graal.compiler.java.DefaultGraphBuilderPhase; import jdk.graal.compiler.nodes.DeoptimizeNode; import jdk.graal.compiler.nodes.StructuredGraph; import jdk.graal.compiler.nodes.StructuredGraph.AllowAssumptions; diff --git a/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/core/test/StaticInterfaceFieldTest.java b/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/core/test/StaticInterfaceFieldTest.java index f87fa53e0058..d61e2e80a567 100644 --- a/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/core/test/StaticInterfaceFieldTest.java +++ b/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/core/test/StaticInterfaceFieldTest.java @@ -33,7 +33,6 @@ import jdk.graal.compiler.debug.DebugCloseable; import jdk.graal.compiler.debug.DebugContext; import jdk.graal.compiler.debug.DebugContext.Builder; -import jdk.graal.compiler.java.DefaultGraphBuilderPhase; import jdk.graal.compiler.nodes.StructuredGraph; import jdk.graal.compiler.nodes.graphbuilderconf.GraphBuilderConfiguration; import jdk.graal.compiler.nodes.graphbuilderconf.GraphBuilderConfiguration.Plugins; diff --git a/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/core/test/UnbalancedMonitorsTest.java b/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/core/test/UnbalancedMonitorsTest.java index 4d84509ff775..ef450d1ca4b5 100644 --- a/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/core/test/UnbalancedMonitorsTest.java +++ b/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/core/test/UnbalancedMonitorsTest.java @@ -30,7 +30,6 @@ import org.objectweb.asm.MethodVisitor; import org.objectweb.asm.Opcodes; -import jdk.graal.compiler.java.DefaultGraphBuilderPhase; import jdk.graal.compiler.java.GraphBuilderPhase; import jdk.graal.compiler.nodes.StructuredGraph; import jdk.graal.compiler.nodes.graphbuilderconf.GraphBuilderConfiguration; diff --git a/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/core/test/VerifyAssertionUsageTest.java b/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/core/test/VerifyAssertionUsageTest.java index 4cf0931ccf27..93600bf858bc 100644 --- a/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/core/test/VerifyAssertionUsageTest.java +++ b/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/core/test/VerifyAssertionUsageTest.java @@ -40,7 +40,6 @@ import jdk.graal.compiler.debug.DebugContext; import jdk.graal.compiler.debug.DebugContext.Builder; import jdk.graal.compiler.graph.Node; -import jdk.graal.compiler.java.DefaultGraphBuilderPhase; import jdk.graal.compiler.nodes.StructuredGraph; import jdk.graal.compiler.nodes.graphbuilderconf.GraphBuilderConfiguration; import jdk.graal.compiler.nodes.graphbuilderconf.GraphBuilderConfiguration.Plugins; diff --git a/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/core/test/VerifyBailoutUsageTest.java b/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/core/test/VerifyBailoutUsageTest.java index 2a23d1f11d15..bce5c88cd2a4 100644 --- a/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/core/test/VerifyBailoutUsageTest.java +++ b/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/core/test/VerifyBailoutUsageTest.java @@ -36,7 +36,6 @@ import jdk.graal.compiler.debug.DebugContext; import jdk.graal.compiler.debug.DebugContext.Builder; import jdk.graal.compiler.debug.GraalError; -import jdk.graal.compiler.java.DefaultGraphBuilderPhase; import jdk.graal.compiler.nodes.StructuredGraph; import jdk.graal.compiler.nodes.graphbuilderconf.GraphBuilderConfiguration; import jdk.graal.compiler.nodes.graphbuilderconf.GraphBuilderConfiguration.Plugins; diff --git a/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/core/test/VerifyDebugUsageTest.java b/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/core/test/VerifyDebugUsageTest.java index e92a9cac2289..6baa94b6dced 100644 --- a/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/core/test/VerifyDebugUsageTest.java +++ b/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/core/test/VerifyDebugUsageTest.java @@ -38,7 +38,6 @@ import jdk.graal.compiler.debug.GraalError; import jdk.graal.compiler.debug.Indent; import jdk.graal.compiler.graph.Node; -import jdk.graal.compiler.java.DefaultGraphBuilderPhase; import jdk.graal.compiler.nodes.StructuredGraph; import jdk.graal.compiler.nodes.graphbuilderconf.GraphBuilderConfiguration; import jdk.graal.compiler.nodes.graphbuilderconf.GraphBuilderConfiguration.Plugins; diff --git a/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/core/test/VerifyVirtualizableTest.java b/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/core/test/VerifyVirtualizableTest.java index 75525bed59bf..0a3699919f14 100644 --- a/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/core/test/VerifyVirtualizableTest.java +++ b/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/core/test/VerifyVirtualizableTest.java @@ -39,7 +39,6 @@ import jdk.graal.compiler.debug.DebugContext; import jdk.graal.compiler.debug.DebugContext.Builder; import jdk.graal.compiler.graph.NodeClass; -import jdk.graal.compiler.java.DefaultGraphBuilderPhase; import jdk.graal.compiler.nodeinfo.NodeInfo; import jdk.graal.compiler.nodes.ConstantNode; import jdk.graal.compiler.nodes.StructuredGraph; diff --git a/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/core/test/tutorial/StaticAnalysis.java b/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/core/test/tutorial/StaticAnalysis.java index 3b8ce8bec5e5..41839e7fa3d5 100644 --- a/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/core/test/tutorial/StaticAnalysis.java +++ b/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/core/test/tutorial/StaticAnalysis.java @@ -34,12 +34,12 @@ import java.util.Map; import java.util.Set; +import jdk.graal.compiler.core.test.DefaultGraphBuilderPhase; import jdk.graal.compiler.debug.DebugContext; import jdk.graal.compiler.debug.DebugContext.Builder; import jdk.graal.compiler.debug.GraalError; import jdk.graal.compiler.graph.Node; import jdk.graal.compiler.graph.NodeMap; -import jdk.graal.compiler.java.DefaultGraphBuilderPhase; import jdk.graal.compiler.java.GraphBuilderPhase; import jdk.graal.compiler.nodes.CallTargetNode.InvokeKind; import jdk.graal.compiler.nodes.ConstantNode; diff --git a/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/hotspot/test/LambdaStableNameTest.java b/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/hotspot/test/LambdaStableNameTest.java index f9846ed1139f..f4c423b6de1a 100644 --- a/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/hotspot/test/LambdaStableNameTest.java +++ b/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/hotspot/test/LambdaStableNameTest.java @@ -37,10 +37,10 @@ import org.objectweb.asm.Type; import jdk.graal.compiler.api.runtime.GraalJVMCICompiler; +import jdk.graal.compiler.core.test.DefaultGraphBuilderPhase; import jdk.graal.compiler.debug.DebugContext; import jdk.graal.compiler.debug.DebugContext.Builder; import jdk.graal.compiler.hotspot.meta.HotSpotJITClassInitializationPlugin; -import jdk.graal.compiler.java.DefaultGraphBuilderPhase; import jdk.graal.compiler.java.LambdaUtils; import jdk.graal.compiler.options.OptionValues; import jdk.graal.compiler.phases.OptimisticOptimizations; diff --git a/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/replacements/test/PEGraphDecoderTest.java b/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/replacements/test/PEGraphDecoderTest.java index ca895efc1a52..e0cd367817dc 100644 --- a/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/replacements/test/PEGraphDecoderTest.java +++ b/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/replacements/test/PEGraphDecoderTest.java @@ -35,10 +35,10 @@ import jdk.graal.compiler.core.common.memory.BarrierType; import jdk.graal.compiler.core.common.memory.MemoryOrderMode; import jdk.graal.compiler.core.common.type.StampFactory; +import jdk.graal.compiler.core.test.DefaultGraphBuilderPhase; import jdk.graal.compiler.core.test.GraalCompilerTest; import jdk.graal.compiler.debug.DebugContext; import jdk.graal.compiler.debug.DebugOptions; -import jdk.graal.compiler.java.DefaultGraphBuilderPhase; import jdk.graal.compiler.java.GraphBuilderPhase; import jdk.graal.compiler.nodes.AbstractBeginNode; import jdk.graal.compiler.nodes.CompanionObjectEncoder; diff --git a/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/replacements/test/SnippetsTest.java b/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/replacements/test/SnippetsTest.java index 439c27ea7770..94a7dcdbfea8 100644 --- a/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/replacements/test/SnippetsTest.java +++ b/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/replacements/test/SnippetsTest.java @@ -24,7 +24,7 @@ */ package jdk.graal.compiler.replacements.test; -import jdk.graal.compiler.java.DefaultGraphBuilderPhase; +import jdk.graal.compiler.core.test.DefaultGraphBuilderPhase; import jdk.graal.compiler.java.GraphBuilderPhase.Instance; import jdk.graal.compiler.nodes.StructuredGraph; import jdk.graal.compiler.nodes.StructuredGraph.Builder; diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/HotSpotStableMethodNameFormatter.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/HotSpotStableMethodNameFormatter.java index f789b3e74d0f..6f42868d3a89 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/HotSpotStableMethodNameFormatter.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/HotSpotStableMethodNameFormatter.java @@ -39,11 +39,6 @@ public HotSpotStableMethodNameFormatter(Providers providers, DebugContext debug) } public HotSpotStableMethodNameFormatter(Providers providers, DebugContext debug, boolean considerMH) { - super(providers, debug, considerMH); - } - - @Override - protected GraphBuilderPhase createGraphBuilderPhase() { - return new HotSpotGraphBuilderPhase(config); + super(new HotSpotGraphBuilderPhase(getGraphBuilderConfiguration()), providers, debug, considerMH); } } diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/java/StableMethodNameFormatter.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/java/StableMethodNameFormatter.java index 8a6d6eca90a8..7cdbdb937721 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/java/StableMethodNameFormatter.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/java/StableMethodNameFormatter.java @@ -92,8 +92,6 @@ public class StableMethodNameFormatter implements Function methodName = EconomicMap.create(Equivalence.IDENTITY); - public StableMethodNameFormatter(Providers providers, DebugContext debug) { - this(providers, debug, false); + private final GraphBuilderPhase graphBuilderPhase; + + public StableMethodNameFormatter(GraphBuilderPhase graphBuilderPhase, Providers providers, DebugContext debug) { + this(graphBuilderPhase, providers, debug, false); } - public StableMethodNameFormatter(Providers providers, DebugContext debug, boolean considerMH) { + public StableMethodNameFormatter(GraphBuilderPhase graphBuilderPhase, Providers providers, DebugContext debug, boolean considerMH) { this.providers = providers; - GraphBuilderConfiguration.Plugins plugins = new GraphBuilderConfiguration.Plugins(new InvocationPlugins()); - this.config = GraphBuilderConfiguration.getDefault(plugins).withEagerResolving(true); + final GraphBuilderConfiguration config; + config = getGraphBuilderConfiguration(); + this.graphBuilderPhase = graphBuilderPhase.copyWithConfig(config); this.debug = debug; this.considerMH = considerMH; } - protected GraphBuilderPhase createGraphBuilderPhase() { - return new DefaultGraphBuilderPhase(config); + protected static GraphBuilderConfiguration getGraphBuilderConfiguration() { + GraphBuilderConfiguration.Plugins plugins = new GraphBuilderConfiguration.Plugins(new InvocationPlugins()); + return GraphBuilderConfiguration.getDefault(plugins).withEagerResolving(true); } /** @@ -172,7 +174,7 @@ private String findStableMHName(ResolvedJavaMethod method) { StructuredGraph methodGraph = new StructuredGraph.Builder(debug.getOptions(), debug).method(method).build(); try (DebugContext.Scope ignored = debug.scope("Lambda method analysis", methodGraph, method, this)) { HighTierContext context = new HighTierContext(providers, null, OptimisticOptimizations.NONE); - createGraphBuilderPhase().apply(methodGraph, context); + graphBuilderPhase.apply(methodGraph, context); } catch (Throwable e) { throw debug.handle(e); } @@ -196,7 +198,7 @@ private String findStableLambdaMethodName(ResolvedJavaMethod method) { StructuredGraph methodGraph = new StructuredGraph.Builder(debug.getOptions(), debug).method(method).build(); try (DebugContext.Scope ignored = debug.scope("Lambda method analysis", methodGraph, method, this)) { HighTierContext context = new HighTierContext(providers, null, OptimisticOptimizations.NONE); - createGraphBuilderPhase().apply(methodGraph, context); + graphBuilderPhase.apply(methodGraph, context); } catch (Throwable e) { throw debug.handle(e); } diff --git a/substratevm/src/com.oracle.graal.pointsto.standalone/src/com/oracle/graal/pointsto/standalone/StandaloneHost.java b/substratevm/src/com.oracle.graal.pointsto.standalone/src/com/oracle/graal/pointsto/standalone/StandaloneHost.java index cf0e0990c0dd..c6b1e77ea27f 100644 --- a/substratevm/src/com.oracle.graal.pointsto.standalone/src/com/oracle/graal/pointsto/standalone/StandaloneHost.java +++ b/substratevm/src/com.oracle.graal.pointsto.standalone/src/com/oracle/graal/pointsto/standalone/StandaloneHost.java @@ -85,7 +85,7 @@ public void onTypeReachable(BigBang bb, AnalysisType type) { @Override public GraphBuilderPhase.Instance createGraphBuilderPhase(HostedProviders builderProviders, GraphBuilderConfiguration graphBuilderConfig, OptimisticOptimizations optimisticOpts, IntrinsicContext initialIntrinsicContext) { - return new StandaloneGraphBuilderPhase(builderProviders, graphBuilderConfig, optimisticOpts, initialIntrinsicContext); + return new StandaloneGraphBuilderPhase.Instance(builderProviders, graphBuilderConfig, optimisticOpts, initialIntrinsicContext); } public void setImageName(String name) { diff --git a/substratevm/src/com.oracle.graal.pointsto.standalone/src/com/oracle/graal/pointsto/standalone/plugins/StandaloneGraphBuilderPhase.java b/substratevm/src/com.oracle.graal.pointsto.standalone/src/com/oracle/graal/pointsto/standalone/plugins/StandaloneGraphBuilderPhase.java index 9fb9a0445ec0..435219ac2dc6 100644 --- a/substratevm/src/com.oracle.graal.pointsto.standalone/src/com/oracle/graal/pointsto/standalone/plugins/StandaloneGraphBuilderPhase.java +++ b/substratevm/src/com.oracle.graal.pointsto.standalone/src/com/oracle/graal/pointsto/standalone/plugins/StandaloneGraphBuilderPhase.java @@ -26,14 +26,50 @@ package com.oracle.graal.pointsto.standalone.plugins; -import jdk.graal.compiler.java.DefaultGraphBuilderPhase; +import jdk.graal.compiler.java.BytecodeParser; +import jdk.graal.compiler.java.GraphBuilderPhase; +import jdk.graal.compiler.nodes.StructuredGraph; import jdk.graal.compiler.nodes.graphbuilderconf.GraphBuilderConfiguration; import jdk.graal.compiler.nodes.graphbuilderconf.IntrinsicContext; import jdk.graal.compiler.nodes.spi.CoreProviders; import jdk.graal.compiler.phases.OptimisticOptimizations; +import jdk.vm.ci.meta.ResolvedJavaMethod; -public class StandaloneGraphBuilderPhase extends DefaultGraphBuilderPhase.Instance { - public StandaloneGraphBuilderPhase(CoreProviders providers, GraphBuilderConfiguration graphBuilderConfig, OptimisticOptimizations optimisticOpts, IntrinsicContext initialIntrinsicContext) { - super(providers, graphBuilderConfig, optimisticOpts, initialIntrinsicContext); +public class StandaloneGraphBuilderPhase extends GraphBuilderPhase { + public StandaloneGraphBuilderPhase(GraphBuilderConfiguration config) { + super(config); + } + + @Override + public GraphBuilderPhase copyWithConfig(GraphBuilderConfiguration config) { + return new StandaloneGraphBuilderPhase(config); + } + + @Override + protected Instance createInstance(CoreProviders providers, GraphBuilderConfiguration instanceGBConfig, OptimisticOptimizations optimisticOpts, IntrinsicContext initialIntrinsicContext) { + return new Instance(providers, instanceGBConfig, optimisticOpts, initialIntrinsicContext); + } + + public static class Instance extends GraphBuilderPhase.Instance { + + public Instance(CoreProviders providers, GraphBuilderConfiguration graphBuilderConfig, OptimisticOptimizations optimisticOpts, IntrinsicContext initialIntrinsicContext) { + super(providers, graphBuilderConfig, optimisticOpts, initialIntrinsicContext); + } + + @Override + protected BytecodeParser createBytecodeParser(StructuredGraph graph, BytecodeParser parent, ResolvedJavaMethod method, int entryBCI, IntrinsicContext intrinsicContext) { + return new StandaloneBytecodeParser(this, graph, parent, method, entryBCI, intrinsicContext); + } + } + + /** + * A non-abstract subclass of {@link BytecodeParser}. This exists mainly the use of non-platform + * specific {@link BytecodeParser} can be audited. + */ + static class StandaloneBytecodeParser extends BytecodeParser { + protected StandaloneBytecodeParser(GraphBuilderPhase.Instance graphBuilderInstance, StructuredGraph graph, BytecodeParser parent, ResolvedJavaMethod method, int entryBCI, + IntrinsicContext intrinsicContext) { + super(graphBuilderInstance, graph, parent, method, entryBCI, intrinsicContext); + } } } diff --git a/substratevm/src/com.oracle.svm.core.graal.aarch64/src/com/oracle/svm/core/graal/aarch64/AArch64SubstrateSuitesCreator.java b/substratevm/src/com.oracle.svm.core.graal.aarch64/src/com/oracle/svm/core/graal/aarch64/AArch64SubstrateSuitesCreator.java index 485fe020bad0..fdf4d372c934 100644 --- a/substratevm/src/com.oracle.svm.core.graal.aarch64/src/com/oracle/svm/core/graal/aarch64/AArch64SubstrateSuitesCreator.java +++ b/substratevm/src/com.oracle.svm.core.graal.aarch64/src/com/oracle/svm/core/graal/aarch64/AArch64SubstrateSuitesCreator.java @@ -25,7 +25,7 @@ package com.oracle.svm.core.graal.aarch64; import jdk.graal.compiler.core.aarch64.AArch64SuitesCreator; -import jdk.graal.compiler.java.DefaultGraphBuilderPhase; +import jdk.graal.compiler.debug.GraalError; import jdk.graal.compiler.java.GraphBuilderPhase; import jdk.graal.compiler.nodes.graphbuilderconf.GraphBuilderConfiguration; import jdk.graal.compiler.phases.tiers.CompilerConfiguration; @@ -38,7 +38,7 @@ public AArch64SubstrateSuitesCreator(CompilerConfiguration compilerConfiguration @Override protected GraphBuilderPhase createGraphBuilderPhase(GraphBuilderConfiguration graphBuilderConfiguration) { - return new DefaultGraphBuilderPhase(graphBuilderConfiguration); + throw GraalError.shouldNotReachHere("this path is unused"); } } diff --git a/substratevm/src/com.oracle.svm.core.graal.amd64/src/com/oracle/svm/core/graal/amd64/AMD64SubstrateSuitesCreator.java b/substratevm/src/com.oracle.svm.core.graal.amd64/src/com/oracle/svm/core/graal/amd64/AMD64SubstrateSuitesCreator.java index 870bc4e99114..11e75c709ae1 100644 --- a/substratevm/src/com.oracle.svm.core.graal.amd64/src/com/oracle/svm/core/graal/amd64/AMD64SubstrateSuitesCreator.java +++ b/substratevm/src/com.oracle.svm.core.graal.amd64/src/com/oracle/svm/core/graal/amd64/AMD64SubstrateSuitesCreator.java @@ -25,7 +25,7 @@ package com.oracle.svm.core.graal.amd64; import jdk.graal.compiler.core.amd64.AMD64SuitesCreator; -import jdk.graal.compiler.java.DefaultGraphBuilderPhase; +import jdk.graal.compiler.debug.GraalError; import jdk.graal.compiler.java.GraphBuilderPhase; import jdk.graal.compiler.nodes.graphbuilderconf.GraphBuilderConfiguration; import jdk.graal.compiler.phases.tiers.CompilerConfiguration; @@ -38,7 +38,7 @@ public AMD64SubstrateSuitesCreator(CompilerConfiguration compilerConfiguration) @Override protected GraphBuilderPhase createGraphBuilderPhase(GraphBuilderConfiguration graphBuilderConfiguration) { - return new DefaultGraphBuilderPhase(graphBuilderConfiguration); + throw GraalError.shouldNotReachHere("this path is unused"); } } diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/graal/code/SubstrateSuitesCreator.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/graal/code/SubstrateSuitesCreator.java index 8a9c4cf3eea8..2016e3cbe101 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/graal/code/SubstrateSuitesCreator.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/graal/code/SubstrateSuitesCreator.java @@ -24,7 +24,7 @@ */ package com.oracle.svm.core.graal.code; -import jdk.graal.compiler.java.DefaultGraphBuilderPhase; +import jdk.graal.compiler.debug.GraalError; import jdk.graal.compiler.java.DefaultSuitesCreator; import jdk.graal.compiler.java.GraphBuilderPhase; import jdk.graal.compiler.nodes.graphbuilderconf.GraphBuilderConfiguration; @@ -38,7 +38,7 @@ public SubstrateSuitesCreator(CompilerConfiguration compilerConfiguration) { @Override protected GraphBuilderPhase createGraphBuilderPhase(GraphBuilderConfiguration graphBuilderConfiguration) { - return new DefaultGraphBuilderPhase(graphBuilderConfiguration); + throw GraalError.shouldNotReachHere("this path is unused"); } } diff --git a/substratevm/src/com.oracle.svm.graal.hotspot.libgraal/src/com/oracle/svm/graal/hotspot/libgraal/LibGraalFeature.java b/substratevm/src/com.oracle.svm.graal.hotspot.libgraal/src/com/oracle/svm/graal/hotspot/libgraal/LibGraalFeature.java index 75a8f54df3d8..e6a69114e665 100644 --- a/substratevm/src/com.oracle.svm.graal.hotspot.libgraal/src/com/oracle/svm/graal/hotspot/libgraal/LibGraalFeature.java +++ b/substratevm/src/com.oracle.svm.graal.hotspot.libgraal/src/com/oracle/svm/graal/hotspot/libgraal/LibGraalFeature.java @@ -963,11 +963,6 @@ private static boolean notifyCrash(String crashMessage) { final class Target_jdk_graal_compiler_hotspot_SymbolicSnippetEncoder { } -@TargetClass(className = "jdk.graal.compiler.java.DefaultGraphBuilderPhase$DefaultBytecodeParser", onlyWith = LibGraalFeature.IsEnabled.class) -@Delete("shouldn't appear in libgraal") -final class Target_jdk_graal_compiler_java_DefaultGraphBuilderPhase_DefaultBytecodeParser { -} - @TargetClass(value = HotSpotForeignCallLinkageImpl.class, onlyWith = LibGraalFeature.IsEnabled.class) final class Target_jdk_graal_compiler_hotspot_HotSpotForeignCallLinkageImpl { /** diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/phases/IntrinsifyMethodHandlesInvocationPlugin.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/phases/IntrinsifyMethodHandlesInvocationPlugin.java index 55beff2cf285..56e4ceea05ac 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/phases/IntrinsifyMethodHandlesInvocationPlugin.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/phases/IntrinsifyMethodHandlesInvocationPlugin.java @@ -71,8 +71,8 @@ import jdk.graal.compiler.graph.Node; import jdk.graal.compiler.graph.NodeClass; import jdk.graal.compiler.graph.NodeMap; +import jdk.graal.compiler.hotspot.HotSpotGraphBuilderInstance; import jdk.graal.compiler.java.BytecodeParser; -import jdk.graal.compiler.java.DefaultGraphBuilderPhase; import jdk.graal.compiler.java.GraphBuilderPhase; import jdk.graal.compiler.nodeinfo.NodeCycles; import jdk.graal.compiler.nodeinfo.NodeInfo; @@ -542,7 +542,7 @@ private boolean processInvokeWithMethodHandle(GraphBuilderContext b, Replacement graphBuilderPlugins.setClassInitializationPlugin(new NoClassInitializationPlugin()); GraphBuilderConfiguration graphBuilderConfig = GraphBuilderConfiguration.getSnippetDefault(graphBuilderPlugins); - GraphBuilderPhase.Instance graphBuilder = new DefaultGraphBuilderPhase.Instance(parsingProviders, graphBuilderConfig, OptimisticOptimizations.NONE, null); + GraphBuilderPhase.Instance graphBuilder = new HotSpotGraphBuilderInstance(parsingProviders, graphBuilderConfig, OptimisticOptimizations.NONE, null); DebugContext debug = b.getDebug(); StructuredGraph graph = new StructuredGraph.Builder(b.getOptions(), debug) diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/reflect/serialize/SerializationFeature.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/reflect/serialize/SerializationFeature.java index afe382878ab6..2851112a1688 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/reflect/serialize/SerializationFeature.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/reflect/serialize/SerializationFeature.java @@ -81,9 +81,9 @@ import com.oracle.svm.util.LogUtils; import com.oracle.svm.util.ReflectionUtil; +import jdk.graal.compiler.core.test.DefaultGraphBuilderPhase; import jdk.graal.compiler.debug.DebugContext; import jdk.graal.compiler.graph.iterators.NodeIterable; -import jdk.graal.compiler.java.DefaultGraphBuilderPhase; import jdk.graal.compiler.java.GraphBuilderPhase; import jdk.graal.compiler.java.LambdaUtils; import jdk.graal.compiler.nodes.ConstantNode; diff --git a/substratevm/src/com.oracle.svm.truffle/src/com/oracle/svm/truffle/api/SubstratePartialEvaluator.java b/substratevm/src/com.oracle.svm.truffle/src/com/oracle/svm/truffle/api/SubstratePartialEvaluator.java index a0ceaf9cce3d..b9b41ef38ccc 100644 --- a/substratevm/src/com.oracle.svm.truffle/src/com/oracle/svm/truffle/api/SubstratePartialEvaluator.java +++ b/substratevm/src/com.oracle.svm.truffle/src/com/oracle/svm/truffle/api/SubstratePartialEvaluator.java @@ -34,8 +34,8 @@ import com.oracle.truffle.compiler.ConstantFieldInfo; import com.oracle.truffle.compiler.PartialEvaluationMethodInfo; +import jdk.graal.compiler.debug.GraalError; import jdk.graal.compiler.graph.SourceLanguagePositionProvider; -import jdk.graal.compiler.java.DefaultGraphBuilderPhase; import jdk.graal.compiler.java.GraphBuilderPhase; import jdk.graal.compiler.nodes.EncodedGraph; import jdk.graal.compiler.nodes.StructuredGraph; @@ -79,7 +79,7 @@ protected PEGraphDecoder createGraphDecoder(TruffleTierContext context, Invocati @Override protected GraphBuilderPhase.Instance createGraphBuilderPhaseInstance(CoreProviders providers, GraphBuilderConfiguration graphBuilderConfig, OptimisticOptimizations optimisticOpts) { - return new DefaultGraphBuilderPhase.Instance(providers, graphBuilderConfig, optimisticOpts, null); + throw GraalError.shouldNotReachHere("this path is unused"); } @Override From 856468a21c8e44a91572401d34ecf10c75b8123a Mon Sep 17 00:00:00 2001 From: Christian Haeubl Date: Wed, 10 Jan 2024 14:06:39 +0100 Subject: [PATCH 520/593] Use a common ThreadStartRoutinePrologue on all platforms. --- .../posix/thread/PosixPlatformThreads.java | 20 +------------------ .../core/windows/WindowsPlatformThreads.java | 20 +------------------ .../svm/core/thread/PlatformThreads.java | 19 ++++++++++++++++++ 3 files changed, 21 insertions(+), 38 deletions(-) diff --git a/substratevm/src/com.oracle.svm.core.posix/src/com/oracle/svm/core/posix/thread/PosixPlatformThreads.java b/substratevm/src/com.oracle.svm.core.posix/src/com/oracle/svm/core/posix/thread/PosixPlatformThreads.java index eca2a6bd717d..927a93f978a6 100644 --- a/substratevm/src/com.oracle.svm.core.posix/src/com/oracle/svm/core/posix/thread/PosixPlatformThreads.java +++ b/substratevm/src/com.oracle.svm.core.posix/src/com/oracle/svm/core/posix/thread/PosixPlatformThreads.java @@ -37,7 +37,6 @@ import org.graalvm.nativeimage.c.function.CEntryPointLiteral; import org.graalvm.nativeimage.c.function.CFunctionPointer; import org.graalvm.nativeimage.c.struct.SizeOf; -import org.graalvm.nativeimage.c.type.CCharPointer; import org.graalvm.nativeimage.c.type.CTypeConversion; import org.graalvm.nativeimage.c.type.CTypeConversion.CCharPointerHolder; import org.graalvm.nativeimage.c.type.VoidPointer; @@ -53,10 +52,6 @@ import com.oracle.svm.core.annotate.Inject; import com.oracle.svm.core.annotate.RecomputeFieldValue; import com.oracle.svm.core.annotate.TargetClass; -import com.oracle.svm.core.c.CGlobalData; -import com.oracle.svm.core.c.CGlobalDataFactory; -import com.oracle.svm.core.c.function.CEntryPointActions; -import com.oracle.svm.core.c.function.CEntryPointErrors; import com.oracle.svm.core.c.function.CEntryPointOptions; import com.oracle.svm.core.c.function.CEntryPointSetup.LeaveDetachThreadEpilogue; import com.oracle.svm.core.feature.AutomaticallyRegisteredImageSingleton; @@ -189,21 +184,8 @@ protected void yieldCurrent() { private static final CEntryPointLiteral pthreadStartRoutine = CEntryPointLiteral.create(PosixPlatformThreads.class, "pthreadStartRoutine", ThreadStartData.class); - private static class PthreadStartRoutinePrologue implements CEntryPointOptions.Prologue { - private static final CGlobalData errorMessage = CGlobalDataFactory.createCString("Failed to attach a newly launched thread."); - - @SuppressWarnings("unused") - @Uninterruptible(reason = "prologue") - static void enter(ThreadStartData data) { - int code = CEntryPointActions.enterAttachThread(data.getIsolate(), true, false); - if (code != CEntryPointErrors.NO_ERROR) { - CEntryPointActions.failFatally(code, errorMessage.get()); - } - } - } - @CEntryPoint(include = CEntryPoint.NotIncludedAutomatically.class, publishAs = Publish.NotPublished) - @CEntryPointOptions(prologue = PthreadStartRoutinePrologue.class, epilogue = LeaveDetachThreadEpilogue.class) + @CEntryPointOptions(prologue = ThreadStartRoutinePrologue.class, epilogue = LeaveDetachThreadEpilogue.class) static WordBase pthreadStartRoutine(ThreadStartData data) { ObjectHandle threadHandle = data.getThreadHandle(); freeStartData(data); diff --git a/substratevm/src/com.oracle.svm.core.windows/src/com/oracle/svm/core/windows/WindowsPlatformThreads.java b/substratevm/src/com.oracle.svm.core.windows/src/com/oracle/svm/core/windows/WindowsPlatformThreads.java index 205116ac9aab..0371b461b79a 100644 --- a/substratevm/src/com.oracle.svm.core.windows/src/com/oracle/svm/core/windows/WindowsPlatformThreads.java +++ b/substratevm/src/com.oracle.svm.core.windows/src/com/oracle/svm/core/windows/WindowsPlatformThreads.java @@ -35,7 +35,6 @@ import org.graalvm.nativeimage.c.struct.RawField; import org.graalvm.nativeimage.c.struct.RawStructure; import org.graalvm.nativeimage.c.struct.SizeOf; -import org.graalvm.nativeimage.c.type.CCharPointer; import org.graalvm.nativeimage.c.type.CIntPointer; import org.graalvm.nativeimage.c.type.VoidPointer; import org.graalvm.nativeimage.c.type.WordPointer; @@ -44,10 +43,6 @@ import org.graalvm.word.WordFactory; import com.oracle.svm.core.Uninterruptible; -import com.oracle.svm.core.c.CGlobalData; -import com.oracle.svm.core.c.CGlobalDataFactory; -import com.oracle.svm.core.c.function.CEntryPointActions; -import com.oracle.svm.core.c.function.CEntryPointErrors; import com.oracle.svm.core.c.function.CEntryPointOptions; import com.oracle.svm.core.c.function.CEntryPointSetup.LeaveDetachThreadEpilogue; import com.oracle.svm.core.feature.AutomaticallyRegisteredImageSingleton; @@ -190,21 +185,8 @@ interface WindowsThreadStartData extends ThreadStartData { private static final CEntryPointLiteral osThreadStartRoutine = CEntryPointLiteral.create(WindowsPlatformThreads.class, "osThreadStartRoutine", WindowsThreadStartData.class); - private static class OSThreadStartRoutinePrologue implements CEntryPointOptions.Prologue { - private static final CGlobalData errorMessage = CGlobalDataFactory.createCString("Failed to attach a newly launched thread."); - - @SuppressWarnings("unused") - @Uninterruptible(reason = "prologue") - static void enter(WindowsThreadStartData data) { - int code = CEntryPointActions.enterAttachThread(data.getIsolate(), true, false); - if (code != CEntryPointErrors.NO_ERROR) { - CEntryPointActions.failFatally(code, errorMessage.get()); - } - } - } - @CEntryPoint(include = CEntryPoint.NotIncludedAutomatically.class, publishAs = Publish.NotPublished) - @CEntryPointOptions(prologue = OSThreadStartRoutinePrologue.class, epilogue = LeaveDetachThreadEpilogue.class) + @CEntryPointOptions(prologue = ThreadStartRoutinePrologue.class, epilogue = LeaveDetachThreadEpilogue.class) static WordBase osThreadStartRoutine(WindowsThreadStartData data) { ObjectHandle threadHandle = data.getThreadHandle(); WinBase.HANDLE osThreadHandle = data.getOSThreadHandle(); diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/thread/PlatformThreads.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/thread/PlatformThreads.java index 6407d06ac432..b126902e583f 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/thread/PlatformThreads.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/thread/PlatformThreads.java @@ -63,6 +63,7 @@ import org.graalvm.nativeimage.c.function.CodePointer; import org.graalvm.nativeimage.c.struct.RawField; import org.graalvm.nativeimage.c.struct.RawStructure; +import org.graalvm.nativeimage.c.type.CCharPointer; import org.graalvm.nativeimage.c.type.WordPointer; import org.graalvm.word.ComparableWord; import org.graalvm.word.Pointer; @@ -79,6 +80,11 @@ import com.oracle.svm.core.annotate.Alias; import com.oracle.svm.core.annotate.TargetClass; import com.oracle.svm.core.annotate.TargetElement; +import com.oracle.svm.core.c.CGlobalData; +import com.oracle.svm.core.c.CGlobalDataFactory; +import com.oracle.svm.core.c.function.CEntryPointActions; +import com.oracle.svm.core.c.function.CEntryPointErrors; +import com.oracle.svm.core.c.function.CEntryPointOptions; import com.oracle.svm.core.heap.Heap; import com.oracle.svm.core.heap.ReferenceHandler; import com.oracle.svm.core.heap.ReferenceHandlerThread; @@ -1194,6 +1200,19 @@ static void blockedOn(Target_sun_nio_ch_Interruptible b) { } } + protected static class ThreadStartRoutinePrologue implements CEntryPointOptions.Prologue { + private static final CGlobalData errorMessage = CGlobalDataFactory.createCString("Failed to attach a newly launched thread."); + + @SuppressWarnings("unused") + @Uninterruptible(reason = "prologue") + static void enter(ThreadStartData data) { + int code = CEntryPointActions.enterAttachThread(data.getIsolate(), true, false); + if (code != CEntryPointErrors.NO_ERROR) { + CEntryPointActions.failFatally(code, errorMessage.get()); + } + } + } + @RawStructure public interface OSThreadHandle extends PointerBase { } From 5d56813c8eb552655770ed52575d8aaf6235d3ff Mon Sep 17 00:00:00 2001 From: Peter Hofer Date: Tue, 2 Jan 2024 16:52:04 +0100 Subject: [PATCH 521/593] Merge image heap primitive and reference partitions. --- .../genscavenge/ChunkedImageHeapLayouter.java | 66 ++++++-------- .../oracle/svm/core/genscavenge/GCImpl.java | 11 ++- .../oracle/svm/core/genscavenge/HeapImpl.java | 16 ++-- .../svm/core/genscavenge/ImageHeapInfo.java | 82 +++++++---------- .../svm/core/genscavenge/ImageHeapWalker.java | 87 +++++-------------- .../src/com/oracle/svm/core/MemoryWalker.java | 2 - 6 files changed, 90 insertions(+), 174 deletions(-) diff --git a/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/ChunkedImageHeapLayouter.java b/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/ChunkedImageHeapLayouter.java index bb4b5bf8f713..62e31ff27342 100644 --- a/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/ChunkedImageHeapLayouter.java +++ b/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/ChunkedImageHeapLayouter.java @@ -45,10 +45,8 @@ import jdk.graal.compiler.core.common.NumUtil; public class ChunkedImageHeapLayouter implements ImageHeapLayouter { - /** A partition holding objects with only read-only primitive values, but no references. */ - private static final int READ_ONLY_PRIMITIVE = 0; - /** A partition holding objects with read-only references and primitive values. */ - private static final int READ_ONLY_REFERENCE = READ_ONLY_PRIMITIVE + 1; + /** A partition holding read-only objects. */ + private static final int READ_ONLY_REGULAR = 0; /** * A pseudo-partition used during image building to consolidate objects that contain relocatable * references. @@ -62,13 +60,11 @@ public class ChunkedImageHeapLayouter implements ImageHeapLayouter { * read-only reference partition is resized to include the read-only relocation partition as * well. */ - private static final int READ_ONLY_RELOCATABLE = READ_ONLY_REFERENCE + 1; - /** A partition holding objects with writable primitive values, but no references. */ - private static final int WRITABLE_PRIMITIVE = READ_ONLY_RELOCATABLE + 1; - /** A partition holding objects with writable references and primitive values. */ - private static final int WRITABLE_REFERENCE = WRITABLE_PRIMITIVE + 1; + private static final int READ_ONLY_RELOCATABLE = READ_ONLY_REGULAR + 1; + /** A partition holding writable objects. */ + private static final int WRITABLE_REGULAR = READ_ONLY_RELOCATABLE + 1; /** A partition holding very large writable objects with or without references. */ - private static final int WRITABLE_HUGE = WRITABLE_REFERENCE + 1; + private static final int WRITABLE_HUGE = WRITABLE_REGULAR + 1; /** * A partition holding very large read-only objects with or without references, but never with * relocatable references. @@ -86,11 +82,9 @@ public class ChunkedImageHeapLayouter implements ImageHeapLayouter { @SuppressWarnings("this-escape") public ChunkedImageHeapLayouter(ImageHeapInfo heapInfo, long startOffset) { this.partitions = new ChunkedImageHeapPartition[PARTITION_COUNT]; - this.partitions[READ_ONLY_PRIMITIVE] = new ChunkedImageHeapPartition("readOnlyPrimitive", false, false); - this.partitions[READ_ONLY_REFERENCE] = new ChunkedImageHeapPartition("readOnlyReference", false, false); + this.partitions[READ_ONLY_REGULAR] = new ChunkedImageHeapPartition("readOnly", false, false); this.partitions[READ_ONLY_RELOCATABLE] = new ChunkedImageHeapPartition("readOnlyRelocatable", false, false); - this.partitions[WRITABLE_PRIMITIVE] = new ChunkedImageHeapPartition("writablePrimitive", true, false); - this.partitions[WRITABLE_REFERENCE] = new ChunkedImageHeapPartition("writableReference", true, false); + this.partitions[WRITABLE_REGULAR] = new ChunkedImageHeapPartition("writable", true, false); this.partitions[WRITABLE_HUGE] = new ChunkedImageHeapPartition("writableHuge", true, true); this.partitions[READ_ONLY_HUGE] = new ChunkedImageHeapPartition("readOnlyHuge", false, true); @@ -116,12 +110,12 @@ private ChunkedImageHeapPartition getLastPartition() { @Override public void assignObjectToPartition(ImageHeapObject info, boolean immutable, boolean references, boolean relocatable) { - ChunkedImageHeapPartition partition = choosePartition(info, immutable, references, relocatable); + ChunkedImageHeapPartition partition = choosePartition(info, immutable, relocatable); info.setHeapPartition(partition); partition.assign(info); } - private ChunkedImageHeapPartition choosePartition(@SuppressWarnings("unused") ImageHeapObject info, boolean immutable, boolean hasReferences, boolean hasRelocatables) { + private ChunkedImageHeapPartition choosePartition(ImageHeapObject info, boolean immutable, boolean hasRelocatables) { if (immutable) { if (hasRelocatables) { VMError.guarantee(info.getSize() < hugeObjectThreshold, "Objects with relocatable pointers cannot be huge objects"); @@ -131,13 +125,13 @@ private ChunkedImageHeapPartition choosePartition(@SuppressWarnings("unused") Im VMError.guarantee(info.getObjectClass() != DynamicHub.class, "Class metadata (dynamic hubs) cannot be huge objects"); return getReadOnlyHuge(); } - return hasReferences ? getReadOnlyReference() : getReadOnlyPrimitive(); + return getReadOnlyRegular(); } else { assert info.getObjectClass() != DynamicHub.class : "Class metadata (dynamic hubs) cannot be writable"; if (info.getSize() >= hugeObjectThreshold) { return getWritableHuge(); } - return hasReferences ? getWritableReference() : getWritablePrimitive(); + return getWritableRegular(); } } @@ -152,7 +146,7 @@ public ImageHeapLayoutInfo layout(ImageHeap imageHeap, int pageSize) { if (partition == getReadOnlyRelocatable()) { startAlignment = pageSize; endAlignment = pageSize; - } else if (partition == getWritablePrimitive()) { + } else if (partition == getWritableRegular()) { startAlignment = pageSize; } else if (partition == getWritableHuge()) { endAlignment = pageSize; @@ -191,7 +185,7 @@ private ImageHeapLayoutInfo doLayout(ImageHeap imageHeap) { private ImageHeapLayoutInfo populateInfoObjects(int dynamicHubCount) { // Determine writable start boundary from chunks: a chunk that contains writable objects // must also have a writable card table - long offsetOfFirstWritableAlignedChunk = getWritablePrimitive().getStartOffset(); + long offsetOfFirstWritableAlignedChunk = getWritableRegular().getStartOffset(); for (AlignedChunk chunk : allocator.getAlignedChunks()) { if (chunk.isWritable() && chunk.getBegin() < offsetOfFirstWritableAlignedChunk) { assert offsetOfFirstWritableAlignedChunk <= chunk.getEnd(); @@ -200,17 +194,21 @@ private ImageHeapLayoutInfo populateInfoObjects(int dynamicHubCount) { } } long offsetOfFirstWritableUnalignedChunk = -1; + long offsetOfLastWritableUnalignedChunk = -1; for (UnalignedChunk chunk : allocator.getUnalignedChunks()) { - if (chunk.isWritable()) { + if (!chunk.isWritable()) { + break; + } + if (offsetOfFirstWritableUnalignedChunk == -1) { offsetOfFirstWritableUnalignedChunk = chunk.getBegin(); } - break; + offsetOfLastWritableUnalignedChunk = chunk.getBegin(); } - heapInfo.initialize(getReadOnlyPrimitive().firstObject, getReadOnlyPrimitive().lastObject, getReadOnlyReference().firstObject, getReadOnlyReference().lastObject, - getReadOnlyRelocatable().firstObject, getReadOnlyRelocatable().lastObject, getWritablePrimitive().firstObject, getWritablePrimitive().lastObject, - getWritableReference().firstObject, getWritableReference().lastObject, getWritableHuge().firstObject, getWritableHuge().lastObject, - getReadOnlyHuge().firstObject, getReadOnlyHuge().lastObject, offsetOfFirstWritableAlignedChunk, offsetOfFirstWritableUnalignedChunk, dynamicHubCount); + heapInfo.initialize(getReadOnlyRegular().firstObject, getReadOnlyRegular().lastObject, getReadOnlyRelocatable().firstObject, getReadOnlyRelocatable().lastObject, + getWritableRegular().firstObject, getWritableRegular().lastObject, getWritableHuge().firstObject, getWritableHuge().lastObject, + getReadOnlyHuge().firstObject, getReadOnlyHuge().lastObject, offsetOfFirstWritableAlignedChunk, offsetOfFirstWritableUnalignedChunk, offsetOfLastWritableUnalignedChunk, + dynamicHubCount); long writableEnd = getWritableHuge().getStartOffset() + getWritableHuge().getSize(); long writableSize = writableEnd - offsetOfFirstWritableAlignedChunk; @@ -254,24 +252,16 @@ private static void writeHeader(ImageHeapChunkWriter writer, Chunk previous, Chu } } - private ChunkedImageHeapPartition getReadOnlyPrimitive() { - return partitions[READ_ONLY_PRIMITIVE]; - } - - private ChunkedImageHeapPartition getReadOnlyReference() { - return partitions[READ_ONLY_REFERENCE]; + private ChunkedImageHeapPartition getReadOnlyRegular() { + return partitions[READ_ONLY_REGULAR]; } private ChunkedImageHeapPartition getReadOnlyRelocatable() { return partitions[READ_ONLY_RELOCATABLE]; } - private ChunkedImageHeapPartition getWritablePrimitive() { - return partitions[WRITABLE_PRIMITIVE]; - } - - private ChunkedImageHeapPartition getWritableReference() { - return partitions[WRITABLE_REFERENCE]; + private ChunkedImageHeapPartition getWritableRegular() { + return partitions[WRITABLE_REGULAR]; } private ChunkedImageHeapPartition getWritableHuge() { diff --git a/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/GCImpl.java b/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/GCImpl.java index 610ab4450a60..f83c01b48363 100644 --- a/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/GCImpl.java +++ b/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/GCImpl.java @@ -913,13 +913,13 @@ private void blackenDirtyImageHeapRoots() { Timer blackenImageHeapRootsTimer = timers.blackenImageHeapRoots.open(); try { for (ImageHeapInfo info = HeapImpl.getFirstImageHeapInfo(); info != null; info = info.next) { - blackenDirtyImageHeapChunkRoots(info.getFirstWritableAlignedChunk(), info.getFirstWritableUnalignedChunk()); + blackenDirtyImageHeapChunkRoots(info.getFirstWritableAlignedChunk(), info.getFirstWritableUnalignedChunk(), info.getLastWritableUnalignedChunk()); } if (AuxiliaryImageHeap.isPresent()) { ImageHeapInfo auxInfo = AuxiliaryImageHeap.singleton().getImageHeapInfo(); if (auxInfo != null) { - blackenDirtyImageHeapChunkRoots(auxInfo.getFirstWritableAlignedChunk(), auxInfo.getFirstWritableUnalignedChunk()); + blackenDirtyImageHeapChunkRoots(auxInfo.getFirstWritableAlignedChunk(), auxInfo.getFirstWritableUnalignedChunk(), auxInfo.getLastWritableUnalignedChunk()); } } } finally { @@ -928,7 +928,7 @@ private void blackenDirtyImageHeapRoots() { } @Uninterruptible(reason = "Called from uninterruptible code.", mayBeInlined = true) - private void blackenDirtyImageHeapChunkRoots(AlignedHeader firstAligned, UnalignedHeader firstUnaligned) { + private void blackenDirtyImageHeapChunkRoots(AlignedHeader firstAligned, UnalignedHeader firstUnaligned, UnalignedHeader lastUnaligned) { /* * We clean and remark cards of the image heap only during complete collections when we also * collect the old generation and can easily remark references into it. It also only makes a @@ -945,6 +945,9 @@ private void blackenDirtyImageHeapChunkRoots(AlignedHeader firstAligned, Unalign UnalignedHeader unaligned = firstUnaligned; while (unaligned.isNonNull()) { RememberedSet.get().walkDirtyObjects(unaligned, greyToBlackObjectVisitor, clean); + if (unaligned.equal(lastUnaligned)) { + break; + } unaligned = HeapChunk.getNext(unaligned); } } @@ -977,7 +980,7 @@ private void blackenImageHeapRoots() { @Uninterruptible(reason = "Called from uninterruptible code.", mayBeInlined = true) private void blackenImageHeapRoots(ImageHeapInfo imageHeapInfo) { - ImageHeapWalker.walkPartitionInline(imageHeapInfo.firstWritableReferenceObject, imageHeapInfo.lastWritableReferenceObject, greyToBlackObjectVisitor, true); + ImageHeapWalker.walkPartitionInline(imageHeapInfo.firstWritableRegularObject, imageHeapInfo.lastWritableRegularObject, greyToBlackObjectVisitor, true); ImageHeapWalker.walkPartitionInline(imageHeapInfo.firstWritableHugeObject, imageHeapInfo.lastWritableHugeObject, greyToBlackObjectVisitor, false); } diff --git a/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/HeapImpl.java b/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/HeapImpl.java index 47b8f9d1d702..13a38a1304c9 100644 --- a/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/HeapImpl.java +++ b/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/HeapImpl.java @@ -367,7 +367,7 @@ private static class ClassListBuilderVisitor implements MemoryWalker.ImageHeapRe @Override public boolean visitNativeImageHeapRegion(T region, MemoryWalker.NativeImageHeapRegionAccess access) { - if (!access.isWritable(region) && access.containsReferences(region)) { + if (!access.isWritable(region)) { access.visitObjects(region, this); } return true; @@ -712,20 +712,14 @@ static Pointer getImageHeapStart() { private boolean printLocationInfo(Log log, Pointer ptr, boolean allowJavaHeapAccess, boolean allowUnsafeOperations) { for (ImageHeapInfo info = firstImageHeapInfo; info != null; info = info.next) { - if (info.isInReadOnlyPrimitivePartition(ptr)) { - log.string("points into the image heap (read-only primitives)"); - return true; - } else if (info.isInReadOnlyReferencePartition(ptr)) { - log.string("points into the image heap (read-only references)"); + if (info.isInReadOnlyRegularPartition(ptr)) { + log.string("points into the image heap (read-only)"); return true; } else if (info.isInReadOnlyRelocatablePartition(ptr)) { log.string("points into the image heap (read-only relocatables)"); return true; - } else if (info.isInWritablePrimitivePartition(ptr)) { - log.string("points into the image heap (writable primitives)"); - return true; - } else if (info.isInWritableReferencePartition(ptr)) { - log.string("points into the image heap (writable references)"); + } else if (info.isInWritableRegularPartition(ptr)) { + log.string("points into the image heap (writable)"); return true; } else if (info.isInWritableHugePartition(ptr)) { log.string("points into the image heap (writable huge)"); diff --git a/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/ImageHeapInfo.java b/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/ImageHeapInfo.java index 9526b250500f..d81eb32f5be6 100644 --- a/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/ImageHeapInfo.java +++ b/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/ImageHeapInfo.java @@ -49,20 +49,14 @@ public final class ImageHeapInfo { /** Indicates no chunk with {@link #initialize} chunk offset parameters. */ public static final long NO_CHUNK = -1; - @UnknownObjectField(availability = AfterHeapLayout.class, canBeNull = true) public Object firstReadOnlyPrimitiveObject; - @UnknownObjectField(availability = AfterHeapLayout.class, canBeNull = true) public Object lastReadOnlyPrimitiveObject; - - @UnknownObjectField(availability = AfterHeapLayout.class, canBeNull = true) public Object firstReadOnlyReferenceObject; - @UnknownObjectField(availability = AfterHeapLayout.class, canBeNull = true) public Object lastReadOnlyReferenceObject; + @UnknownObjectField(availability = AfterHeapLayout.class, canBeNull = true) public Object firstReadOnlyRegularObject; + @UnknownObjectField(availability = AfterHeapLayout.class, canBeNull = true) public Object lastReadOnlyRegularObject; @UnknownObjectField(availability = AfterHeapLayout.class, canBeNull = true) public Object firstReadOnlyRelocatableObject; @UnknownObjectField(availability = AfterHeapLayout.class, canBeNull = true) public Object lastReadOnlyRelocatableObject; - @UnknownObjectField(availability = AfterHeapLayout.class, canBeNull = true) public Object firstWritablePrimitiveObject; - @UnknownObjectField(availability = AfterHeapLayout.class, canBeNull = true) public Object lastWritablePrimitiveObject; - - @UnknownObjectField(availability = AfterHeapLayout.class, canBeNull = true) public Object firstWritableReferenceObject; - @UnknownObjectField(availability = AfterHeapLayout.class, canBeNull = true) public Object lastWritableReferenceObject; + @UnknownObjectField(availability = AfterHeapLayout.class, canBeNull = true) public Object firstWritableRegularObject; + @UnknownObjectField(availability = AfterHeapLayout.class, canBeNull = true) public Object lastWritableRegularObject; @UnknownObjectField(availability = AfterHeapLayout.class, canBeNull = true) public Object firstWritableHugeObject; @UnknownObjectField(availability = AfterHeapLayout.class, canBeNull = true) public Object lastWritableHugeObject; @@ -76,6 +70,7 @@ public final class ImageHeapInfo { // All offsets are relative to the heap base. @UnknownPrimitiveField(availability = AfterHeapLayout.class) public long offsetOfFirstWritableAlignedChunk; @UnknownPrimitiveField(availability = AfterHeapLayout.class) public long offsetOfFirstWritableUnalignedChunk; + @UnknownPrimitiveField(availability = AfterHeapLayout.class) public long offsetOfLastWritableUnalignedChunk; @UnknownPrimitiveField(availability = AfterHeapLayout.class) public int dynamicHubCount; @@ -90,45 +85,37 @@ public ImageHeapInfo(ImageHeapInfo next) { } @SuppressWarnings("hiding") - public void initialize(Object firstReadOnlyPrimitiveObject, Object lastReadOnlyPrimitiveObject, Object firstReadOnlyReferenceObject, Object lastReadOnlyReferenceObject, - Object firstReadOnlyRelocatableObject, Object lastReadOnlyRelocatableObject, Object firstWritablePrimitiveObject, Object lastWritablePrimitiveObject, - Object firstWritableReferenceObject, Object lastWritableReferenceObject, Object firstWritableHugeObject, Object lastWritableHugeObject, + public void initialize(Object firstReadOnlyRegularObject, Object lastReadOnlyRegularObject, Object firstReadOnlyRelocatableObject, Object lastReadOnlyRelocatableObject, + Object firstWritableRegularObject, Object lastWritableRegularObject, Object firstWritableHugeObject, Object lastWritableHugeObject, Object firstReadOnlyHugeObject, Object lastReadOnlyHugeObject, long offsetOfFirstWritableAlignedChunk, long offsetOfFirstWritableUnalignedChunk, - int dynamicHubCount) { + long offsetOfLastWritableUnalignedChunk, int dynamicHubCount) { assert offsetOfFirstWritableAlignedChunk == NO_CHUNK || offsetOfFirstWritableAlignedChunk >= 0; assert offsetOfFirstWritableUnalignedChunk == NO_CHUNK || offsetOfFirstWritableUnalignedChunk >= 0; - this.firstReadOnlyPrimitiveObject = firstReadOnlyPrimitiveObject; - this.lastReadOnlyPrimitiveObject = lastReadOnlyPrimitiveObject; - this.firstReadOnlyReferenceObject = firstReadOnlyReferenceObject; - this.lastReadOnlyReferenceObject = lastReadOnlyReferenceObject; + this.firstReadOnlyRegularObject = firstReadOnlyRegularObject; + this.lastReadOnlyRegularObject = lastReadOnlyRegularObject; this.firstReadOnlyRelocatableObject = firstReadOnlyRelocatableObject; this.lastReadOnlyRelocatableObject = lastReadOnlyRelocatableObject; - this.firstWritablePrimitiveObject = firstWritablePrimitiveObject; - this.lastWritablePrimitiveObject = lastWritablePrimitiveObject; - this.firstWritableReferenceObject = firstWritableReferenceObject; - this.lastWritableReferenceObject = lastWritableReferenceObject; + this.firstWritableRegularObject = firstWritableRegularObject; + this.lastWritableRegularObject = lastWritableRegularObject; this.firstWritableHugeObject = firstWritableHugeObject; this.lastWritableHugeObject = lastWritableHugeObject; this.firstReadOnlyHugeObject = firstReadOnlyHugeObject; this.lastReadOnlyHugeObject = lastReadOnlyHugeObject; this.offsetOfFirstWritableAlignedChunk = offsetOfFirstWritableAlignedChunk; this.offsetOfFirstWritableUnalignedChunk = offsetOfFirstWritableUnalignedChunk; + this.offsetOfLastWritableUnalignedChunk = offsetOfLastWritableUnalignedChunk; this.dynamicHubCount = dynamicHubCount; // Compute boundaries for checks considering partitions can be empty (first == last == null) - Object firstReadOnlyObject = (firstReadOnlyPrimitiveObject != null) ? firstReadOnlyPrimitiveObject - : ((firstReadOnlyReferenceObject != null) ? firstReadOnlyReferenceObject : firstReadOnlyRelocatableObject); - Object lastReadOnlyObject = (lastReadOnlyRelocatableObject != null) ? lastReadOnlyRelocatableObject - : ((lastReadOnlyReferenceObject != null) ? lastReadOnlyReferenceObject : lastReadOnlyPrimitiveObject); - Object firstWritableObject = (firstWritablePrimitiveObject != null) ? firstWritablePrimitiveObject : firstWritableReferenceObject; - Object lastWritableObject = (lastWritableReferenceObject != null) ? lastWritableReferenceObject : lastWritablePrimitiveObject; - Object firstRegularObject = (firstReadOnlyObject != null) ? firstReadOnlyObject : firstWritableObject; - Object lastRegularObject = (lastWritableObject != null) ? lastWritableObject : lastReadOnlyObject; + Object firstReadOnlyNonHugeObject = (firstReadOnlyRegularObject != null) ? firstReadOnlyRegularObject : firstReadOnlyRelocatableObject; + Object lastReadOnlyNonHugeObject = (lastReadOnlyRelocatableObject != null) ? lastReadOnlyRelocatableObject : lastReadOnlyRegularObject; + Object firstNonHugeObject = (firstReadOnlyNonHugeObject != null) ? firstReadOnlyNonHugeObject : firstWritableRegularObject; + Object lastNonHugeObject = (lastWritableRegularObject != null) ? lastWritableRegularObject : lastReadOnlyNonHugeObject; Object firstHugeObject = (firstWritableHugeObject != null) ? firstWritableHugeObject : firstReadOnlyHugeObject; Object lastHugeObject = (lastReadOnlyHugeObject != null) ? lastReadOnlyHugeObject : lastWritableHugeObject; - this.firstObject = (firstRegularObject != null) ? firstRegularObject : firstHugeObject; - this.lastObject = (lastHugeObject != null) ? lastHugeObject : lastRegularObject; + this.firstObject = (firstNonHugeObject != null) ? firstNonHugeObject : firstHugeObject; + this.lastObject = (lastHugeObject != null) ? lastHugeObject : lastNonHugeObject; } /* @@ -140,15 +127,9 @@ public void initialize(Object firstReadOnlyPrimitiveObject, Object lastReadOnlyP */ @Uninterruptible(reason = "Called from uninterruptible code.", mayBeInlined = true) - public boolean isInReadOnlyPrimitivePartition(Pointer ptr) { + public boolean isInReadOnlyRegularPartition(Pointer ptr) { assert ptr.isNonNull(); - return Word.objectToUntrackedPointer(firstReadOnlyPrimitiveObject).belowOrEqual(ptr) && ptr.belowThan(getObjectEnd(lastReadOnlyPrimitiveObject)); - } - - @Uninterruptible(reason = "Called from uninterruptible code.", mayBeInlined = true) - public boolean isInReadOnlyReferencePartition(Pointer ptr) { - assert ptr.isNonNull(); - return Word.objectToUntrackedPointer(firstReadOnlyReferenceObject).belowOrEqual(ptr) && ptr.belowThan(getObjectEnd(lastReadOnlyReferenceObject)); + return Word.objectToUntrackedPointer(firstReadOnlyRegularObject).belowOrEqual(ptr) && ptr.belowThan(getObjectEnd(lastReadOnlyRegularObject)); } @Uninterruptible(reason = "Called from uninterruptible code.", mayBeInlined = true) @@ -158,15 +139,9 @@ public boolean isInReadOnlyRelocatablePartition(Pointer ptr) { } @Uninterruptible(reason = "Called from uninterruptible code.", mayBeInlined = true) - public boolean isInWritablePrimitivePartition(Pointer ptr) { + public boolean isInWritableRegularPartition(Pointer ptr) { assert ptr.isNonNull(); - return Word.objectToUntrackedPointer(firstWritablePrimitiveObject).belowOrEqual(ptr) && ptr.belowThan(getObjectEnd(lastWritablePrimitiveObject)); - } - - @Uninterruptible(reason = "Called from uninterruptible code.", mayBeInlined = true) - public boolean isInWritableReferencePartition(Pointer ptr) { - assert ptr.isNonNull(); - return Word.objectToUntrackedPointer(firstWritableReferenceObject).belowOrEqual(ptr) && ptr.belowThan(getObjectEnd(lastWritableReferenceObject)); + return Word.objectToUntrackedPointer(firstWritableRegularObject).belowOrEqual(ptr) && ptr.belowThan(getObjectEnd(lastWritableRegularObject)); } @Uninterruptible(reason = "Called from uninterruptible code.", mayBeInlined = true) @@ -207,6 +182,11 @@ public UnalignedHeader getFirstWritableUnalignedChunk() { return asImageHeapChunk(offsetOfFirstWritableUnalignedChunk); } + @Uninterruptible(reason = "Called from uninterruptible code.", mayBeInlined = true) + public UnalignedHeader getLastWritableUnalignedChunk() { + return asImageHeapChunk(offsetOfLastWritableUnalignedChunk); + } + @Uninterruptible(reason = "Called from uninterruptible code.", mayBeInlined = true) private static Pointer getObjectEnd(Object obj) { if (obj == null) { @@ -227,11 +207,9 @@ private static > T asImageHeapChunk(long offsetInI } public void print(Log log) { - log.string("ReadOnly Primitives: ").zhex(Word.objectToUntrackedPointer(firstReadOnlyPrimitiveObject)).string(" - ").zhex(getObjectEnd(lastReadOnlyPrimitiveObject)).newline(); - log.string("ReadOnly References: ").zhex(Word.objectToUntrackedPointer(firstReadOnlyReferenceObject)).string(" - ").zhex(getObjectEnd(lastReadOnlyReferenceObject)).newline(); + log.string("ReadOnly: ").zhex(Word.objectToUntrackedPointer(firstReadOnlyRegularObject)).string(" - ").zhex(getObjectEnd(lastReadOnlyRegularObject)).newline(); log.string("ReadOnly Relocatables: ").zhex(Word.objectToUntrackedPointer(firstReadOnlyRelocatableObject)).string(" - ").zhex(getObjectEnd(lastReadOnlyRelocatableObject)).newline(); - log.string("Writable Primitives: ").zhex(Word.objectToUntrackedPointer(firstWritablePrimitiveObject)).string(" - ").zhex(getObjectEnd(lastWritablePrimitiveObject)).newline(); - log.string("Writable References: ").zhex(Word.objectToUntrackedPointer(firstWritableReferenceObject)).string(" - ").zhex(getObjectEnd(lastWritableReferenceObject)).newline(); + log.string("Writable: ").zhex(Word.objectToUntrackedPointer(firstWritableRegularObject)).string(" - ").zhex(getObjectEnd(lastWritableRegularObject)).newline(); log.string("Writable Huge: ").zhex(Word.objectToUntrackedPointer(firstWritableHugeObject)).string(" - ").zhex(getObjectEnd(lastWritableHugeObject)).newline(); log.string("ReadOnly Huge: ").zhex(Word.objectToUntrackedPointer(firstReadOnlyHugeObject)).string(" - ").zhex(getObjectEnd(lastReadOnlyHugeObject)).newline(); } diff --git a/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/ImageHeapWalker.java b/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/ImageHeapWalker.java index 504f477c9776..adc4aca32c74 100644 --- a/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/ImageHeapWalker.java +++ b/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/ImageHeapWalker.java @@ -40,11 +40,9 @@ import jdk.graal.compiler.word.Word; public final class ImageHeapWalker { - private static final MemoryWalker.NativeImageHeapRegionAccess READ_ONLY_PRIMITIVE_WALKER = new ReadOnlyPrimitiveMemoryWalkerAccess(); - private static final MemoryWalker.NativeImageHeapRegionAccess READ_ONLY_REFERENCE_WALKER = new ReadOnlyReferenceMemoryWalkerAccess(); + private static final MemoryWalker.NativeImageHeapRegionAccess READ_ONLY_REGULAR_WALKER = new ReadOnlyRegularMemoryWalkerAccess(); private static final MemoryWalker.NativeImageHeapRegionAccess READ_ONLY_RELOCATABLE_WALKER = new ReadOnlyRelocatableMemoryWalkerAccess(); - private static final MemoryWalker.NativeImageHeapRegionAccess WRITABLE_PRIMITIVE_WALKER = new WritablePrimitiveMemoryWalkerAccess(); - private static final MemoryWalker.NativeImageHeapRegionAccess WRITABLE_REFERENCE_WALKER = new WritableReferenceMemoryWalkerAccess(); + private static final MemoryWalker.NativeImageHeapRegionAccess WRITABLE_REGULAR_WALKER = new WritableRegularMemoryWalkerAccess(); private static final MemoryWalker.NativeImageHeapRegionAccess WRITABLE_HUGE_WALKER = new WritableHugeMemoryWalkerAccess(); private static final MemoryWalker.NativeImageHeapRegionAccess READ_ONLY_HUGE_WALKER = new ReadOnlyHugeMemoryWalkerAccess(); @@ -52,21 +50,17 @@ private ImageHeapWalker() { } public static boolean walkRegions(ImageHeapInfo heapInfo, MemoryWalker.ImageHeapRegionVisitor visitor) { - return visitor.visitNativeImageHeapRegion(heapInfo, READ_ONLY_PRIMITIVE_WALKER) && - visitor.visitNativeImageHeapRegion(heapInfo, READ_ONLY_REFERENCE_WALKER) && + return visitor.visitNativeImageHeapRegion(heapInfo, READ_ONLY_REGULAR_WALKER) && visitor.visitNativeImageHeapRegion(heapInfo, READ_ONLY_RELOCATABLE_WALKER) && - visitor.visitNativeImageHeapRegion(heapInfo, WRITABLE_PRIMITIVE_WALKER) && - visitor.visitNativeImageHeapRegion(heapInfo, WRITABLE_REFERENCE_WALKER) && + visitor.visitNativeImageHeapRegion(heapInfo, WRITABLE_REGULAR_WALKER) && visitor.visitNativeImageHeapRegion(heapInfo, WRITABLE_HUGE_WALKER) && visitor.visitNativeImageHeapRegion(heapInfo, READ_ONLY_HUGE_WALKER); } public static boolean walkImageHeapObjects(ImageHeapInfo heapInfo, ObjectVisitor visitor) { - return walkPartition(heapInfo.firstReadOnlyPrimitiveObject, heapInfo.lastReadOnlyPrimitiveObject, visitor, true) && - walkPartition(heapInfo.firstReadOnlyReferenceObject, heapInfo.lastReadOnlyReferenceObject, visitor, true) && + return walkPartition(heapInfo.firstReadOnlyRegularObject, heapInfo.lastReadOnlyRegularObject, visitor, true) && walkPartition(heapInfo.firstReadOnlyRelocatableObject, heapInfo.lastReadOnlyRelocatableObject, visitor, true) && - walkPartition(heapInfo.firstWritablePrimitiveObject, heapInfo.lastWritablePrimitiveObject, visitor, true) && - walkPartition(heapInfo.firstWritableReferenceObject, heapInfo.lastWritableReferenceObject, visitor, true) && + walkPartition(heapInfo.firstWritableRegularObject, heapInfo.lastWritableRegularObject, visitor, true) && walkPartition(heapInfo.firstWritableHugeObject, heapInfo.lastWritableHugeObject, visitor, false) && walkPartition(heapInfo.firstReadOnlyHugeObject, heapInfo.lastReadOnlyHugeObject, visitor, false); } @@ -142,14 +136,12 @@ private static boolean visitObjectInline(ObjectVisitor visitor, Object currentOb abstract class MemoryWalkerAccessBase implements MemoryWalker.NativeImageHeapRegionAccess { private final String regionName; - private final boolean containsReferences; private final boolean isWritable; private final boolean hasHugeObjects; @Platforms(Platform.HOSTED_ONLY.class) - MemoryWalkerAccessBase(String regionName, boolean containsReferences, boolean isWritable, boolean hasHugeObjects) { + MemoryWalkerAccessBase(String regionName, boolean isWritable, boolean hasHugeObjects) { this.regionName = regionName; - this.containsReferences = containsReferences; this.isWritable = isWritable; this.hasHugeObjects = hasHugeObjects; } @@ -174,11 +166,6 @@ public String getRegionName(ImageHeapInfo region) { return regionName; } - @Override - public boolean containsReferences(ImageHeapInfo region) { - return containsReferences; - } - @Override public boolean isWritable(ImageHeapInfo region) { return isWritable; @@ -196,44 +183,27 @@ public final boolean visitObjects(ImageHeapInfo region, ObjectVisitor visitor) { protected abstract Object getLastObject(ImageHeapInfo info); } -final class ReadOnlyPrimitiveMemoryWalkerAccess extends MemoryWalkerAccessBase { +final class ReadOnlyRegularMemoryWalkerAccess extends MemoryWalkerAccessBase { @Platforms(Platform.HOSTED_ONLY.class) - ReadOnlyPrimitiveMemoryWalkerAccess() { - super("read-only primitives", false, false, false); + ReadOnlyRegularMemoryWalkerAccess() { + super("read-only", false, false); } @Override public Object getFirstObject(ImageHeapInfo info) { - return info.firstReadOnlyPrimitiveObject; + return info.firstReadOnlyRegularObject; } @Override public Object getLastObject(ImageHeapInfo info) { - return info.lastReadOnlyPrimitiveObject; - } -} - -final class ReadOnlyReferenceMemoryWalkerAccess extends MemoryWalkerAccessBase { - @Platforms(Platform.HOSTED_ONLY.class) - ReadOnlyReferenceMemoryWalkerAccess() { - super("read-only references", true, false, false); - } - - @Override - public Object getFirstObject(ImageHeapInfo info) { - return info.firstReadOnlyReferenceObject; - } - - @Override - public Object getLastObject(ImageHeapInfo info) { - return info.lastReadOnlyReferenceObject; + return info.lastReadOnlyRegularObject; } } final class ReadOnlyRelocatableMemoryWalkerAccess extends MemoryWalkerAccessBase { @Platforms(Platform.HOSTED_ONLY.class) ReadOnlyRelocatableMemoryWalkerAccess() { - super("read-only relocatables", true, false, false); + super("read-only relocatables", false, false); } @Override @@ -247,44 +217,27 @@ public Object getLastObject(ImageHeapInfo info) { } } -final class WritablePrimitiveMemoryWalkerAccess extends MemoryWalkerAccessBase { - @Platforms(Platform.HOSTED_ONLY.class) - WritablePrimitiveMemoryWalkerAccess() { - super("writable primitives", false, true, false); - } - - @Override - public Object getFirstObject(ImageHeapInfo info) { - return info.firstWritablePrimitiveObject; - } - - @Override - public Object getLastObject(ImageHeapInfo info) { - return info.lastWritablePrimitiveObject; - } -} - -final class WritableReferenceMemoryWalkerAccess extends MemoryWalkerAccessBase { +final class WritableRegularMemoryWalkerAccess extends MemoryWalkerAccessBase { @Platforms(Platform.HOSTED_ONLY.class) - WritableReferenceMemoryWalkerAccess() { - super("writable references", true, true, false); + WritableRegularMemoryWalkerAccess() { + super("writable", true, false); } @Override public Object getFirstObject(ImageHeapInfo info) { - return info.firstWritableReferenceObject; + return info.firstWritableRegularObject; } @Override public Object getLastObject(ImageHeapInfo info) { - return info.lastWritableReferenceObject; + return info.lastWritableRegularObject; } } final class WritableHugeMemoryWalkerAccess extends MemoryWalkerAccessBase { @Platforms(Platform.HOSTED_ONLY.class) WritableHugeMemoryWalkerAccess() { - super("writable huge", true, true, true); + super("writable huge", true, true); } @Override @@ -301,7 +254,7 @@ public Object getLastObject(ImageHeapInfo info) { final class ReadOnlyHugeMemoryWalkerAccess extends MemoryWalkerAccessBase { @Platforms(Platform.HOSTED_ONLY.class) ReadOnlyHugeMemoryWalkerAccess() { - super("read-only huge", true, false, true); + super("read-only huge", false, true); } @Override diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/MemoryWalker.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/MemoryWalker.java index 85104becd0a4..9a55368319d0 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/MemoryWalker.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/MemoryWalker.java @@ -64,8 +64,6 @@ public interface NativeImageHeapRegionAccess { String getRegionName(T region); - boolean containsReferences(T region); - boolean isWritable(T region); boolean visitObjects(T region, ObjectVisitor visitor); From e01a26aae3f0e7cd69fbcce34d15cf69b59b6c94 Mon Sep 17 00:00:00 2001 From: Peter Hofer Date: Fri, 5 Jan 2024 11:37:12 +0100 Subject: [PATCH 522/593] Remove unused walker code and minor cleanups. --- .../core/genscavenge/AlignedHeapChunk.java | 34 ----------- .../svm/core/genscavenge/HeapChunk.java | 40 ------------- .../oracle/svm/core/genscavenge/HeapImpl.java | 5 +- .../svm/core/genscavenge/HeapVerifier.java | 1 - .../svm/core/genscavenge/OldGeneration.java | 5 -- .../oracle/svm/core/genscavenge/Space.java | 16 ----- .../core/genscavenge/UnalignedHeapChunk.java | 28 --------- .../svm/core/genscavenge/YoungGeneration.java | 13 ---- .../graal/GenScavengeGCFeature.java | 2 +- .../src/com/oracle/svm/core/MemoryWalker.java | 57 ------------------ .../svm/core/code/CodeInfoMemoryWalker.java | 60 ------------------- .../oracle/svm/core/code/ImageCodeInfo.java | 9 +-- 12 files changed, 4 insertions(+), 266 deletions(-) delete mode 100644 substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/code/CodeInfoMemoryWalker.java diff --git a/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/AlignedHeapChunk.java b/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/AlignedHeapChunk.java index 8e45dbc58ced..54ed7ea421b3 100644 --- a/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/AlignedHeapChunk.java +++ b/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/AlignedHeapChunk.java @@ -24,18 +24,13 @@ */ package com.oracle.svm.core.genscavenge; -import org.graalvm.nativeimage.ImageSingletons; -import org.graalvm.nativeimage.Platform; -import org.graalvm.nativeimage.Platforms; import org.graalvm.nativeimage.c.struct.RawStructure; import org.graalvm.word.Pointer; import org.graalvm.word.UnsignedWord; import org.graalvm.word.WordFactory; import com.oracle.svm.core.AlwaysInline; -import com.oracle.svm.core.MemoryWalker; import com.oracle.svm.core.Uninterruptible; -import com.oracle.svm.core.feature.AutomaticallyRegisteredImageSingleton; import com.oracle.svm.core.genscavenge.remset.RememberedSet; import com.oracle.svm.core.heap.ObjectVisitor; import com.oracle.svm.core.os.CommittedMemoryProvider; @@ -117,11 +112,6 @@ static Pointer allocateMemory(AlignedHeader that, UnsignedWord size) { return result; } - @Uninterruptible(reason = "Called from uninterruptible code.", mayBeInlined = true) - static UnsignedWord getCommittedObjectMemory(AlignedHeader that) { - return HeapChunk.getEndOffset(that).subtract(getObjectsStartOffset()); - } - @Uninterruptible(reason = "Called from uninterruptible code.", mayBeInlined = true) public static AlignedHeader getEnclosingChunk(Object obj) { Pointer ptr = Word.objectToUntrackedPointer(obj); @@ -157,28 +147,4 @@ static boolean walkObjectsFromInline(AlignedHeader that, Pointer start, ObjectVi public static UnsignedWord getObjectsStartOffset() { return RememberedSet.get().getHeaderSizeOfAlignedChunk(); } - - @Fold - static MemoryWalker.HeapChunkAccess getMemoryWalkerAccess() { - return ImageSingletons.lookup(AlignedHeapChunk.MemoryWalkerAccessImpl.class); - } - - /** Methods for a {@link MemoryWalker} to access an aligned heap chunk. */ - @AutomaticallyRegisteredImageSingleton(onlyWith = UseSerialOrEpsilonGC.class) - static final class MemoryWalkerAccessImpl extends HeapChunk.MemoryWalkerAccessImpl { - - @Platforms(Platform.HOSTED_ONLY.class) - MemoryWalkerAccessImpl() { - } - - @Override - public boolean isAligned(AlignedHeapChunk.AlignedHeader heapChunk) { - return true; - } - - @Override - public UnsignedWord getAllocationStart(AlignedHeapChunk.AlignedHeader heapChunk) { - return getObjectsStart(heapChunk); - } - } } diff --git a/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/HeapChunk.java b/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/HeapChunk.java index 84406410daf5..002d30d46e0b 100644 --- a/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/HeapChunk.java +++ b/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/HeapChunk.java @@ -26,8 +26,6 @@ import java.util.function.IntUnaryOperator; -import org.graalvm.nativeimage.Platform; -import org.graalvm.nativeimage.Platforms; import org.graalvm.nativeimage.c.struct.RawField; import org.graalvm.nativeimage.c.struct.RawStructure; import org.graalvm.nativeimage.c.struct.UniqueLocationIdentity; @@ -40,7 +38,6 @@ import org.graalvm.word.WordFactory; import com.oracle.svm.core.AlwaysInline; -import com.oracle.svm.core.MemoryWalker; import com.oracle.svm.core.NeverInline; import com.oracle.svm.core.Uninterruptible; import com.oracle.svm.core.c.struct.PinnedObjectField; @@ -352,41 +349,4 @@ public static HeapChunk.Header getEnclosingHeapChunk(Pointer ptrToObj, Unsign return UnalignedHeapChunk.getEnclosingChunkFromObjectPointer(ptrToObj); } } - - abstract static class MemoryWalkerAccessImpl> implements MemoryWalker.HeapChunkAccess { - @Platforms(Platform.HOSTED_ONLY.class) - MemoryWalkerAccessImpl() { - } - - @Override - public UnsignedWord getStart(T heapChunk) { - return (UnsignedWord) heapChunk; - } - - @Override - public UnsignedWord getSize(T heapChunk) { - return HeapChunk.getEndOffset(heapChunk); - } - - @Override - public UnsignedWord getAllocationEnd(T heapChunk) { - return HeapChunk.getTopPointer(heapChunk); - } - - @Override - public String getRegion(T heapChunk) { - /* This method knows too much about spaces, especially the "free" space. */ - Space space = getSpace(heapChunk); - String result; - if (space == null) { - result = "free"; - } else if (space.isYoungSpace()) { - result = "young"; - } else { - result = "old"; - } - return result; - } - - } } diff --git a/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/HeapImpl.java b/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/HeapImpl.java index 13a38a1304c9..a38f23320dc1 100644 --- a/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/HeapImpl.java +++ b/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/HeapImpl.java @@ -99,8 +99,6 @@ public final class HeapImpl extends Heap { private static final VMMutex REF_MUTEX = new VMMutex("referencePendingList"); private static final VMCondition REF_CONDITION = new VMCondition(REF_MUTEX); - private final int pageSize; - // Singleton instances, created during image generation. private final YoungGeneration youngGeneration = new YoungGeneration("YoungGeneration"); private final OldGeneration oldGeneration = new OldGeneration("OldGeneration"); @@ -125,8 +123,7 @@ public final class HeapImpl extends Heap { private List> classList; @Platforms(Platform.HOSTED_ONLY.class) - public HeapImpl(int pageSize) { - this.pageSize = pageSize; + public HeapImpl() { this.gcImpl = new GCImpl(); this.runtimeCodeInfoGcSupport = new RuntimeCodeInfoGCSupportImpl(); HeapParameters.initialize(); diff --git a/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/HeapVerifier.java b/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/HeapVerifier.java index dfc0a53d55e3..df4b460ba43c 100644 --- a/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/HeapVerifier.java +++ b/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/HeapVerifier.java @@ -399,7 +399,6 @@ private static class ObjectReferenceVerifier implements ObjectReferenceVisitor { ObjectReferenceVerifier() { } - @SuppressWarnings("hiding") public void initialize() { this.result = true; } diff --git a/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/OldGeneration.java b/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/OldGeneration.java index 5f6d0deb6fa2..dabffb701de7 100644 --- a/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/OldGeneration.java +++ b/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/OldGeneration.java @@ -32,7 +32,6 @@ import org.graalvm.word.UnsignedWord; import com.oracle.svm.core.AlwaysInline; -import com.oracle.svm.core.MemoryWalker; import com.oracle.svm.core.Uninterruptible; import com.oracle.svm.core.genscavenge.GCImpl.ChunkReleaser; import com.oracle.svm.core.genscavenge.remset.RememberedSet; @@ -152,10 +151,6 @@ void emptyFromSpaceIntoToSpace() { getToSpace().absorb(getFromSpace()); } - boolean walkHeapChunks(MemoryWalker.Visitor visitor) { - return getFromSpace().walkHeapChunks(visitor) && getToSpace().walkHeapChunks(visitor); - } - /** * This value is only updated during a GC. Be careful when calling this method during a GC as it * might wrongly include chunks that will be freed at the end of the GC. diff --git a/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/Space.java b/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/Space.java index 83b27eff8126..18df3161d601 100644 --- a/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/Space.java +++ b/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/Space.java @@ -36,7 +36,6 @@ import org.graalvm.word.WordFactory; import com.oracle.svm.core.AlwaysInline; -import com.oracle.svm.core.MemoryWalker; import com.oracle.svm.core.SubstrateOptions; import com.oracle.svm.core.Uninterruptible; import com.oracle.svm.core.UnmanagedMemoryUtil; @@ -510,21 +509,6 @@ void absorb(Space src) { } } - boolean walkHeapChunks(MemoryWalker.Visitor visitor) { - boolean continueVisiting = true; - AlignedHeapChunk.AlignedHeader aChunk = getFirstAlignedHeapChunk(); - while (continueVisiting && aChunk.isNonNull()) { - continueVisiting = visitor.visitHeapChunk(aChunk, AlignedHeapChunk.getMemoryWalkerAccess()); - aChunk = HeapChunk.getNext(aChunk); - } - UnalignedHeapChunk.UnalignedHeader uChunk = getFirstUnalignedHeapChunk(); - while (continueVisiting && uChunk.isNonNull()) { - continueVisiting = visitor.visitHeapChunk(uChunk, UnalignedHeapChunk.getMemoryWalkerAccess()); - uChunk = HeapChunk.getNext(uChunk); - } - return continueVisiting; - } - /** * This value is only updated during a GC. Be careful when calling this method during a GC as it * might wrongly include chunks that will be freed at the end of the GC. diff --git a/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/UnalignedHeapChunk.java b/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/UnalignedHeapChunk.java index afcdc50fa19e..d7d4002e3a9b 100644 --- a/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/UnalignedHeapChunk.java +++ b/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/UnalignedHeapChunk.java @@ -24,19 +24,14 @@ */ package com.oracle.svm.core.genscavenge; -import org.graalvm.nativeimage.ImageSingletons; -import org.graalvm.nativeimage.Platform; -import org.graalvm.nativeimage.Platforms; import org.graalvm.nativeimage.c.struct.RawStructure; import org.graalvm.word.Pointer; import org.graalvm.word.UnsignedWord; import org.graalvm.word.WordFactory; import com.oracle.svm.core.AlwaysInline; -import com.oracle.svm.core.MemoryWalker; import com.oracle.svm.core.Uninterruptible; import com.oracle.svm.core.config.ConfigurationValues; -import com.oracle.svm.core.feature.AutomaticallyRegisteredImageSingleton; import com.oracle.svm.core.genscavenge.remset.RememberedSet; import com.oracle.svm.core.heap.ObjectVisitor; import com.oracle.svm.core.os.CommittedMemoryProvider; @@ -161,27 +156,4 @@ static UnsignedWord getObjectStartOffset() { public static UnsignedWord getCommittedObjectMemory(UnalignedHeader that) { return HeapChunk.getEndOffset(that).subtract(getObjectStartOffset()); } - - @Fold - public static MemoryWalker.HeapChunkAccess getMemoryWalkerAccess() { - return ImageSingletons.lookup(UnalignedHeapChunk.MemoryWalkerAccessImpl.class); - } - - @AutomaticallyRegisteredImageSingleton(onlyWith = UseSerialOrEpsilonGC.class) - static final class MemoryWalkerAccessImpl extends HeapChunk.MemoryWalkerAccessImpl { - - @Platforms(Platform.HOSTED_ONLY.class) - MemoryWalkerAccessImpl() { - } - - @Override - public boolean isAligned(UnalignedHeapChunk.UnalignedHeader heapChunk) { - return false; - } - - @Override - public UnsignedWord getAllocationStart(UnalignedHeapChunk.UnalignedHeader heapChunk) { - return getObjectStart(heapChunk); - } - } } diff --git a/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/YoungGeneration.java b/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/YoungGeneration.java index 8b92be57c986..10806e651939 100644 --- a/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/YoungGeneration.java +++ b/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/YoungGeneration.java @@ -30,7 +30,6 @@ import org.graalvm.word.WordFactory; import com.oracle.svm.core.AlwaysInline; -import com.oracle.svm.core.MemoryWalker; import com.oracle.svm.core.Uninterruptible; import com.oracle.svm.core.genscavenge.GCImpl.ChunkReleaser; import com.oracle.svm.core.heap.ObjectHeader; @@ -153,18 +152,6 @@ void swapSpaces() { assert survivorsToSpacesAccounting.getChunkBytes().equal(0); } - boolean walkHeapChunks(MemoryWalker.Visitor visitor) { - if (getEden().walkHeapChunks(visitor)) { - for (int i = 0; i < maxSurvivorSpaces; i++) { - if (!(getSurvivorFromSpaceAt(i).walkHeapChunks(visitor) && getSurvivorToSpaceAt(i).walkHeapChunks(visitor))) { - return false; - } - } - return true; - } - return false; - } - @Uninterruptible(reason = "Called from uninterruptible code.", mayBeInlined = true) void prepareForPromotion() { for (int i = 0; i < maxSurvivorSpaces; i++) { diff --git a/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/graal/GenScavengeGCFeature.java b/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/graal/GenScavengeGCFeature.java index 5718f341c24d..edf0b18a7773 100644 --- a/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/graal/GenScavengeGCFeature.java +++ b/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/graal/GenScavengeGCFeature.java @@ -90,7 +90,7 @@ public void afterRegistration(AfterRegistrationAccess access) { @Override public void duringSetup(DuringSetupAccess access) { - HeapImpl heap = new HeapImpl(SubstrateOptions.getPageSize()); + HeapImpl heap = new HeapImpl(); ImageSingletons.add(Heap.class, heap); ImageSingletons.add(GCAllocationSupport.class, new GenScavengeAllocationSupport()); diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/MemoryWalker.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/MemoryWalker.java index 9a55368319d0..468709b3a2c3 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/MemoryWalker.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/MemoryWalker.java @@ -24,10 +24,8 @@ */ package com.oracle.svm.core; -import org.graalvm.word.PointerBase; import org.graalvm.word.UnsignedWord; -import com.oracle.svm.core.code.CodeInfo; import com.oracle.svm.core.heap.ObjectVisitor; import com.oracle.svm.core.heap.RestrictHeapAccess; @@ -39,22 +37,6 @@ public interface ImageHeapRegionVisitor { boolean visitNativeImageHeapRegion(T region, MemoryWalker.NativeImageHeapRegionAccess access); } - public interface Visitor extends ImageHeapRegionVisitor { - /** - * Visit a heap chunk, using the provided access methods. Return true if visiting should - * continue, else false. - */ - @RestrictHeapAccess(access = RestrictHeapAccess.Access.NO_ALLOCATION, reason = "Must not allocate while visiting memory.") - boolean visitHeapChunk(T heapChunk, HeapChunkAccess access); - - /** - * Visit compiled code, using the provided access methods. Return true if visiting should - * continue, else false. - */ - @RestrictHeapAccess(access = RestrictHeapAccess.Access.NO_ALLOCATION, reason = "Must not allocate while visiting memory.") - boolean visitCode(T codeInfo, CodeAccess access); - } - /** A set of access methods for visiting regions of the native image heap. */ public interface NativeImageHeapRegionAccess { @@ -69,43 +51,4 @@ public interface NativeImageHeapRegionAccess { boolean visitObjects(T region, ObjectVisitor visitor); } - /** A set of access methods for visiting heap chunk memory. */ - public interface HeapChunkAccess { - - /** Return the start of the heap chunk. */ - UnsignedWord getStart(T heapChunk); - - /** Return the size of the heap chunk. */ - UnsignedWord getSize(T heapChunk); - - /** Return the address where allocation starts within the heap chunk. */ - UnsignedWord getAllocationStart(T heapChunk); - - /** - * Return the address where allocation has ended within the heap chunk. This is the first - * address past the end of allocated space within the heap chunk. - */ - UnsignedWord getAllocationEnd(T heapChunk); - - /** - * Return the name of the region that contains the heap chunk. E.g., "young", "old", "free", - * etc. - */ - String getRegion(T heapChunk); - - /** Return true if the heap chunk is an aligned heap chunk, else false. */ - boolean isAligned(T heapChunk); - } - - /** A set of access methods for visiting code memory. */ - public interface CodeAccess { - - UnsignedWord getStart(T codeInfo); - - UnsignedWord getCodeAndDataMemorySize(T codeInfo); - - UnsignedWord getNativeMetadataSize(T codeInfo); - - String getName(T codeInfo); - } } diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/code/CodeInfoMemoryWalker.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/code/CodeInfoMemoryWalker.java deleted file mode 100644 index 10e3aa9a2aad..000000000000 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/code/CodeInfoMemoryWalker.java +++ /dev/null @@ -1,60 +0,0 @@ -/* - * Copyright (c) 2019, 2019, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.oracle.svm.core.code; - -import org.graalvm.nativeimage.Platform; -import org.graalvm.nativeimage.Platforms; -import org.graalvm.word.UnsignedWord; - -import com.oracle.svm.core.MemoryWalker; -import com.oracle.svm.core.feature.AutomaticallyRegisteredImageSingleton; - -@AutomaticallyRegisteredImageSingleton -final class CodeInfoMemoryWalker implements MemoryWalker.CodeAccess { - - @Platforms(Platform.HOSTED_ONLY.class) - CodeInfoMemoryWalker() { - } - - @Override - public UnsignedWord getStart(CodeInfo codeInfo) { - return (UnsignedWord) CodeInfoAccess.getCodeStart(codeInfo); - } - - @Override - public UnsignedWord getCodeAndDataMemorySize(CodeInfo codeInfo) { - return CodeInfoAccess.getCodeSize(codeInfo).add(CodeInfoAccess.getCodeAndDataMemorySize(codeInfo)); - } - - @Override - public UnsignedWord getNativeMetadataSize(CodeInfo codeInfo) { - return CodeInfoAccess.getNativeMetadataSize(codeInfo); - } - - @Override - public String getName(CodeInfo codeInfo) { - return CodeInfoAccess.getName(codeInfo); - } -} diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/code/ImageCodeInfo.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/code/ImageCodeInfo.java index 084e5265f513..fec3fde15470 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/code/ImageCodeInfo.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/code/ImageCodeInfo.java @@ -26,8 +26,6 @@ import java.util.List; -import jdk.graal.compiler.word.Word; -import org.graalvm.nativeimage.ImageSingletons; import org.graalvm.nativeimage.Platform; import org.graalvm.nativeimage.Platforms; import org.graalvm.nativeimage.c.function.CodePointer; @@ -35,7 +33,6 @@ import org.graalvm.word.UnsignedWord; import com.oracle.svm.core.BuildPhaseProvider.AfterCompilation; -import com.oracle.svm.core.MemoryWalker; import com.oracle.svm.core.Uninterruptible; import com.oracle.svm.core.c.CIsolateData; import com.oracle.svm.core.c.CIsolateDataFactory; @@ -46,6 +43,8 @@ import com.oracle.svm.core.heap.UnknownPrimitiveField; import com.oracle.svm.core.util.VMError; +import jdk.graal.compiler.word.Word; + public class ImageCodeInfo { public static final String CODE_INFO_NAME = "image code"; @@ -122,10 +121,6 @@ public NonmovableArray getStackReferenceMapEncoding() { return NonmovableArrays.fromImageHeap(referenceMapEncoding); } - public boolean walkImageCode(MemoryWalker.Visitor visitor) { - return visitor.visitCode(CodeInfoTable.getImageCodeInfo(), ImageSingletons.lookup(CodeInfoMemoryWalker.class)); - } - public HostedImageCodeInfo getHostedImageCodeInfo() { return hostedImageCodeInfo; } From 21c82ca47405877dea8059257f164f03857ee7d1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gerg=C3=B6=20Barany?= Date: Thu, 18 Jan 2024 10:57:44 +0100 Subject: [PATCH 523/593] Don't add node with dead input --- .../graph/test/NodeValidationChecksTest.java | 11 +++--- .../jdk/graal/compiler/graph/NodeClass.java | 10 +++--- .../compiler/nodes/java/ArrayLengthNode.java | 34 +++++++++++++------ .../graal/compiler/nodes/memory/ReadNode.java | 15 ++------ 4 files changed, 38 insertions(+), 32 deletions(-) diff --git a/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/graph/test/NodeValidationChecksTest.java b/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/graph/test/NodeValidationChecksTest.java index 8cdb0d443edc..89858770cfde 100644 --- a/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/graph/test/NodeValidationChecksTest.java +++ b/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/graph/test/NodeValidationChecksTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2024, 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,6 +30,7 @@ import org.junit.Assert; import org.junit.Test; +import jdk.graal.compiler.debug.GraalError; import jdk.graal.compiler.graph.Graph; import jdk.graal.compiler.graph.Node; import jdk.graal.compiler.graph.NodeClass; @@ -58,8 +59,8 @@ public void testInputNotAlive() { try { graph.add(new TestNode(node, null)); Assert.fail("Exception expected."); - } catch (AssertionError e) { - Assert.assertTrue(e.getMessage().contains("Input")); + } catch (GraalError e) { + Assert.assertTrue(e.getMessage().contains("input")); Assert.assertTrue(e.getMessage().contains("not alive")); } } @@ -71,8 +72,8 @@ public void testSuccessorNotAlive() { try { graph.add(new TestNode(null, node)); Assert.fail("Exception expected."); - } catch (AssertionError e) { - Assert.assertTrue(e.getMessage().contains("Successor")); + } catch (GraalError e) { + Assert.assertTrue(e.getMessage().contains("successor")); Assert.assertTrue(e.getMessage().contains("not alive")); } } diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/graph/NodeClass.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/graph/NodeClass.java index daaa40fcb799..420f5e5f2c55 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/graph/NodeClass.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/graph/NodeClass.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, 2024, 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 @@ -1340,7 +1340,7 @@ public void registerAtSuccessorsAsPredecessor(Node node) { if ((myMask & LIST_MASK) == 0) { Node curNode = Edges.getNodeUnsafe(node, offset); if (curNode != null) { - assert curNode.isAlive() : "Successor not alive"; + GraalError.guarantee(curNode.isAlive(), "Adding %s to the graph but its successor %s is not alive", node, curNode); node.updatePredecessor(null, curNode); } } else { @@ -1356,7 +1356,7 @@ private static void registerAtSuccessorsAsPredecessorHelper(Node node, long offs for (int i = 0; i < list.size(); ++i) { Node curNode = list.get(i); if (curNode != null) { - assert curNode.isAlive() : "Successor not alive"; + GraalError.guarantee(curNode.isAlive(), "Adding %s to the graph but its successor %s is not alive", node, curNode); node.updatePredecessor(null, curNode); } } @@ -1419,7 +1419,7 @@ void registerAtInputsAsUsage(Node node) { if ((myMask & LIST_MASK) == 0) { Node curNode = Edges.getNodeUnsafe(node, offset); if (curNode != null) { - assert curNode.isAlive() : "Input " + curNode + " of node " + node + " is not alive"; + GraalError.guarantee(curNode.isAlive(), "Adding %s to the graph but its input %s is not alive", node, curNode); curNode.addUsage(node); } } else { @@ -1435,7 +1435,7 @@ private static void registerAtInputsAsUsageHelper(Node node, long offset) { for (int i = 0; i < list.size(); ++i) { Node curNode = list.get(i); if (curNode != null) { - assert curNode.isAlive() : "Input not alive " + curNode; + GraalError.guarantee(curNode.isAlive(), "Adding %s to the graph but its input %s is not alive", node, curNode); curNode.addUsage(node); } } diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/nodes/java/ArrayLengthNode.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/nodes/java/ArrayLengthNode.java index 86862a9895d2..5bb5f1ccf1a6 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/nodes/java/ArrayLengthNode.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/nodes/java/ArrayLengthNode.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2009, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2009, 2024, 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 @@ -31,6 +31,7 @@ import jdk.graal.compiler.core.common.type.AbstractObjectStamp; import jdk.graal.compiler.core.common.type.StampFactory; +import jdk.graal.compiler.graph.Graph; import jdk.graal.compiler.graph.Node.NodeIntrinsicFactory; import jdk.graal.compiler.graph.NodeClass; import jdk.graal.compiler.nodeinfo.NodeInfo; @@ -170,19 +171,32 @@ public void simplify(SimplifierTool tool) { * */ StructuredGraph graph = graph(); - ValueNode replacement = length; - if (!length.isConstant() && length.stamp(NodeView.DEFAULT).canBeImprovedWith(StampFactory.positiveInt())) { - ValueAnchorNode guard = graph.add(new ValueAnchorNode()); - graph.addAfterFixed(this, guard); - replacement = graph.addWithoutUnique(new PiNode(length, StampFactory.positiveInt(), guard)); - } - if (!replacement.isAlive()) { - replacement = graph.addOrUnique(replacement); - } + ValueNode replacement = maybeAddPositivePi(length, this); graph.replaceFixedWithFloating(this, replacement); } } + /** + * If necessary, improves the {@code length}'s stamp to a positive value by adding a + * {@link PiNode} for it. The pi will be attached to a new {@link ValueAnchorNode} after the + * {@code insertionPosition}. + * + * @return the {@code length} or its {@linkplain Graph#addOrUnique unique representative} if the + * length's stamp is already positive; otherwise, a new {@link PiNode} proving a + * positive stamp for the length + */ + public static ValueNode maybeAddPositivePi(ValueNode length, FixedWithNextNode insertionPosition) { + StructuredGraph graph = insertionPosition.graph(); + length = graph.addOrUnique(length); + ValueNode replacement = length; + if (!length.isConstant() && length.stamp(NodeView.DEFAULT).canBeImprovedWith(StampFactory.positiveInt())) { + ValueAnchorNode g = graph.add(new ValueAnchorNode()); + graph.addAfterFixed(insertionPosition, g); + replacement = graph.addWithoutUnique(new PiNode(length, StampFactory.positiveInt(), g)); + } + return replacement; + } + /** * Gets the length of an array if possible. * diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/nodes/memory/ReadNode.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/nodes/memory/ReadNode.java index 20f02c13659f..78cbb551190c 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/nodes/memory/ReadNode.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/nodes/memory/ReadNode.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, 2024, 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 @@ -51,13 +51,12 @@ import jdk.graal.compiler.nodes.FixedWithNextNode; import jdk.graal.compiler.nodes.FrameState; import jdk.graal.compiler.nodes.NodeView; -import jdk.graal.compiler.nodes.PiNode; import jdk.graal.compiler.nodes.StructuredGraph; import jdk.graal.compiler.nodes.ValueNode; import jdk.graal.compiler.nodes.calc.NarrowNode; import jdk.graal.compiler.nodes.calc.ZeroExtendNode; import jdk.graal.compiler.nodes.extended.GuardingNode; -import jdk.graal.compiler.nodes.extended.ValueAnchorNode; +import jdk.graal.compiler.nodes.java.ArrayLengthNode; import jdk.graal.compiler.nodes.memory.address.AddressNode; import jdk.graal.compiler.nodes.memory.address.OffsetAddressNode; import jdk.graal.compiler.nodes.spi.ArrayLengthProvider; @@ -166,15 +165,7 @@ public void simplify(SimplifierTool tool) { ValueNode length = GraphUtil.arrayLength(objAddress.getBase(), ArrayLengthProvider.FindLengthMode.CANONICALIZE_READ, constantReflection); if (length != null) { StructuredGraph graph = graph(); - ValueNode replacement = length; - if (!length.isConstant() && length.stamp(NodeView.DEFAULT).canBeImprovedWith(StampFactory.positiveInt())) { - ValueAnchorNode g = graph.add(new ValueAnchorNode()); - graph.addAfterFixed(this, g); - replacement = graph.addWithoutUnique(new PiNode(length, StampFactory.positiveInt(), g)); - } - if (!replacement.isAlive()) { - replacement = graph.addOrUnique(replacement); - } + ValueNode replacement = ArrayLengthNode.maybeAddPositivePi(length, this); graph.replaceFixedWithFloating(this, replacement); } } From 591fd7e5699fb8445a018a0d76c6cca53a2ff0c0 Mon Sep 17 00:00:00 2001 From: Olya Gupalo Date: Fri, 12 Jan 2024 16:04:17 +0100 Subject: [PATCH 524/593] Review Foreign Function and Memory API in Native Image doc --- .../native-image/ForeignInterface.md | 46 +++++++++++-------- 1 file changed, 28 insertions(+), 18 deletions(-) diff --git a/docs/reference-manual/native-image/ForeignInterface.md b/docs/reference-manual/native-image/ForeignInterface.md index 1254b59b4ae9..f7724069ae94 100644 --- a/docs/reference-manual/native-image/ForeignInterface.md +++ b/docs/reference-manual/native-image/ForeignInterface.md @@ -1,34 +1,40 @@ --- layout: docs -toc_group: dynamic-features +toc_group: native-code-interoperability link_title: Foreign Interface -permalink: /reference-manual/native-image/dynamic-features/foreign-interface/ +permalink: /reference-manual/native-image/native-code-interoperability/foreign-interface/ +redirect_from: /reference-manual/native-image/dynamic-features/foreign-interface/ --- -# Foreign Function & Memory API in Native Image +# Foreign Function and Memory API in Native Image -The Foreign Function & Memory (FFM) API is an interface that enables Java code to interact with native code and vice versa. -It has been finalized in JDK 22 with [JEP 454](https://openjdk.org/jeps/454){:target="_blank"}. -Support in Native Image is currently experimental and needs to be explicitly enabled with `-H:+ForeignAPISupport` (requiring `-H:+UnlockExperimentalVMOptions`). -Modules that are permitted to perform "restricted" native operations (including creating handles for calls to or from native code) must be specified using `--enable-native-access=`. -This page gives an overview of support for the FFM API in Native Image. +The Foreign Function and Memory (FFM) API is an interface that enables Java code to interact with native code and vice versa. +It is finalized in JDK 22 with [JEP 454](https://openjdk.org/jeps/454){:target="_blank"}. +Support in Native Image is currently experimental and must be explicitly enabled with `-H:+ForeignAPISupport` (in addition to `-H:+UnlockExperimentalVMOptions`). +Modules that are permitted to perform "restricted" native operations (including creating handles for calls to or from native code) must be specified using the `--enable-native-access=` option. +This page gives an overview of the FFM API support in Native Image. -## Foreign memory -Foreign memory functionality is generally supported. Shared arenas are currently not supported. +## Foreign Memory + +Foreign memory functionality is generally supported. +Shared arenas are currently not supported. + +## Foreign Functions -## Foreign functions The FFM API enables Java code to call _down_ to native functions, and conversely allows native code to call _up_ to invoke Java code via method handles. -These two kinds of calls are referred to as "downcalls" and "upcalls" respectively and are collectively referred to as "foreign calls". +These two kinds of calls are referred to as "downcalls" and "upcalls" respectively, and are collectively referred to as "foreign calls". + +> Note: Currently, only downcalls are supported, and only on the AMD64 architecture. -Currently, only downcalls are supported, and only on the AMD64 architecture. +### Looking Up Native Functions -### Looking up native functions The FFM API provides the `SymbolLookup` interface to find functions in native libraries by name. `SymbolLookup.loaderLookup()` is currently the only supported kind of `SymbolLookup`. -### Registering foreign calls -In order to perform calls to native code at runtime, supporting code must be generated at image build time. -Therefore, the `native-image` tool must be provided with descriptors that characterize functions to which downcalls may be performed at runtime. +### Registering Foreign Calls + +In order to perform calls to native code at run time, supporting code must be generated at image build time. +Therefore, the `native-image` tool must be provided with descriptors that characterize the functions to which downcalls may be performed at run time. These descriptors can be registered using a custom `Feature`, for example: ```java @@ -44,9 +50,13 @@ class ForeignRegistrationFeature implements Feature { } } ``` -To activate the custom feature, `--features=com.example.ForeignRegistrationFeature` (the fully-qualified name of the feature class) needs to be passed to `native-image`. +To activate the custom feature, pass the `--features=com.example.ForeignRegistrationFeature` option (the fully-qualified name of the feature class) to `native-image`. It is recommended to do so [with a _native-image.properties_ file](BuildConfiguration.md#embed-a-configuration-file). ### Upcalls Upcalls are not yet supported. + +### Related Documentation + +- [Interoperability with Native Code](InteropWithNativeCode.md) \ No newline at end of file From df6b90b3151ec8aadfab517ca58af76f40831876 Mon Sep 17 00:00:00 2001 From: Olya Gupalo Date: Thu, 18 Jan 2024 14:59:17 +0100 Subject: [PATCH 525/593] Update Related Docs section in InteropWithNativeCode.md --- docs/reference-manual/native-image/ForeignInterface.md | 2 +- docs/reference-manual/native-image/InteropWithNativeCode.md | 5 +++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/docs/reference-manual/native-image/ForeignInterface.md b/docs/reference-manual/native-image/ForeignInterface.md index f7724069ae94..a7ebcb22d9cc 100644 --- a/docs/reference-manual/native-image/ForeignInterface.md +++ b/docs/reference-manual/native-image/ForeignInterface.md @@ -24,7 +24,7 @@ Shared arenas are currently not supported. The FFM API enables Java code to call _down_ to native functions, and conversely allows native code to call _up_ to invoke Java code via method handles. These two kinds of calls are referred to as "downcalls" and "upcalls" respectively, and are collectively referred to as "foreign calls". -> Note: Currently, only downcalls are supported, and only on the AMD64 architecture. +> Note: Currently, only downcalls are supported, and only on the x64 architecture. ### Looking Up Native Functions diff --git a/docs/reference-manual/native-image/InteropWithNativeCode.md b/docs/reference-manual/native-image/InteropWithNativeCode.md index da0446ec4fe5..cd004d78f06d 100644 --- a/docs/reference-manual/native-image/InteropWithNativeCode.md +++ b/docs/reference-manual/native-image/InteropWithNativeCode.md @@ -16,8 +16,9 @@ There are two mechanisms for calling natively compiled Java methods: ### Related Documentation -- [Build a Native Shared Library](guides/build-native-shared-library.md) -- [Embedding Truffle Languages](https://nirvdrum.com/2022/05/09/truffle-language-embedding.html)-- a blog post by Kevin Menard where he compares both mechanisms in Native Image for exposing Java methods +- [Foreign Function and Memory API in Native Image](ForeignInterface.md) - [Java Native Interface (JNI) on Native Image](JNI.md) - [JNI Invocation API](JNIInvocationAPI.md) - [Native Image C API](C-API.md) +- [Build a Native Shared Library](guides/build-native-shared-library.md) +- [Embedding Truffle Languages](https://nirvdrum.com/2022/05/09/truffle-language-embedding.html)-- a blog post by Kevin Menard where he compares both mechanisms in Native Image for exposing Java methods \ No newline at end of file From 4805ca1374da082b25581342d53374aec87525b7 Mon Sep 17 00:00:00 2001 From: Olya Gupalo Date: Thu, 18 Jan 2024 16:46:52 +0100 Subject: [PATCH 526/593] Update graalvm17 command in OCI Cloud Shell and Cloud Editor guides --- .../graalvm-enterprise/oci/cloud-shell.md | 8 ++++---- .../graalvm-enterprise/oci/code-editor.md | 12 ++++++------ 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/docs/getting-started/graalvm-enterprise/oci/cloud-shell.md b/docs/getting-started/graalvm-enterprise/oci/cloud-shell.md index c91999c8e467..18cf3cbbbd9d 100644 --- a/docs/getting-started/graalvm-enterprise/oci/cloud-shell.md +++ b/docs/getting-started/graalvm-enterprise/oci/cloud-shell.md @@ -9,7 +9,7 @@ This guide shows you how to get started with Oracle GraalVM in Oracle Cloud Infr [OCI Cloud Shell](https://docs.oracle.com/en-us/iaas/Content/API/Concepts/cloudshellintro.htm) is a browser-based terminal accessible from the Oracle Cloud Console. It provides access to a Linux shell with a pre-authenticated OCI Command Line Interface (CLI), preinstalled developer tools, and comes with 5GB of storage. -Oracle GraalVM JDK 17 with Native Image is preinstalled in Cloud Shell, so you do not have to install and configure a development machine. +Oracle GraalVM for JDK 17 is preinstalled in Cloud Shell, so you do not have to install and configure a development machine. > Note: Oracle GraalVM license and support are included in the Oracle Cloud Infrastructure subscription at no additional cost. @@ -24,14 +24,14 @@ Cloud Shell has several preinstalled JDKs, including Oracle GraalVM JDK. ```shell csruntimectl java list ``` - The output lists the JDKs preinstalled in Cloud Shell: GraalVM for JDK 17, Oracle JDK 11, and Oracle JDK 8. The JDK marked with an asterisk is the current JDK. + The output lists the JDKs preinstalled in Cloud Shell: Oracle GraalVM for JDK 17, Oracle JDK 11, and Oracle JDK 8. The JDK marked with an asterisk is the current JDK. 3. Select GraalVM for JDK 17 as the current JDK: ```shell - csruntimectl java set graalvmeejdk-17 + csruntimectl java set graalvmjdk-17 ``` - You will see the confirmation message printed `The current managed java version is set to graalvmeejdk-17`. + You will see the confirmation message printed `The current managed java version is set to graalvmjdk-17`. 4. Now confirm the values of the environment variables `PATH` and `JAVA_HOME`, and the version of `java`, the `native-image` generator: diff --git a/docs/getting-started/graalvm-enterprise/oci/code-editor.md b/docs/getting-started/graalvm-enterprise/oci/code-editor.md index b1be705a6957..dbfa776766ac 100644 --- a/docs/getting-started/graalvm-enterprise/oci/code-editor.md +++ b/docs/getting-started/graalvm-enterprise/oci/code-editor.md @@ -9,7 +9,7 @@ This guide shows you how to get started with Oracle GraalVM in Oracle Cloud Infr [OCI Code Editor](https://docs.oracle.com/en-us/iaas/Content/API/Concepts/code_editor_intro.htm) provides a rich, in-console editing environment that enables you to edit code without having to switch between the Oracle Cloud Console and your local development environment. The Code Editor enables you to edit and deploy code for OCI services directly from the OCI Console. -Oracle GraalVM JDK 17 with Native Image is preinstalled in Cloud Shell, so you do not have to install and configure a development machine. Code Editor's integration with Cloud Shell gives you direct access to it. +Oracle GraalVM for JDK 17 is preinstalled in Cloud Shell, so you do not have to install and configure a development machine. Code Editor's integration with Cloud Shell gives you direct access to it. > Note: Oracle GraalVM license and support are included in the Oracle Cloud Infrastructure subscription at no additional cost. @@ -27,14 +27,14 @@ Oracle GraalVM JDK 17 with Native Image is preinstalled in Cloud Shell, so you d ```shell csruntimectl java list ``` - The output lists the JDKs preinstalled in Cloud Shell: GraalVM for JDK 17, Oracle JDK 11, and Oracle JDK 8. The JDK marked with an asterisk is the current JDK. + The output lists the JDKs preinstalled in Cloud Shell: Oracle GraalVM for JDK 17, Oracle JDK 11, and Oracle JDK 8. The JDK marked with an asterisk is the current JDK. -2. Select GraalVM for JDK 17 as the current JDK: +2. Select Oracle GraalVM for JDK 17 as the current JDK: ```shell - csruntimectl java set graalvmeejdk-17 + csruntimectl java set graalvmjdk-17 ``` - You will see the confirmation message printed `The current managed java version is set to graalvmeejdk-17`. + You will see the confirmation message printed `The current managed java version is set to graalvmjdk-17`. 3. Now confirm the values of the environment variables `PATH` and `JAVA_HOME`, and the version of `java`, the `native-image` generator: ```shell @@ -86,7 +86,7 @@ Oracle GraalVM JDK 17 with Native Image is preinstalled in Cloud Shell, so you d 3. Run the JAR: ```shell - java -jar target/my-app-1.0-SNAPSHOT.jar + java -jar target/my-app-1.0-SNAPSHOT.jar ``` It prints out “Hello World!”. From e4857021dc71c36d955ea4a4223108e40be197f0 Mon Sep 17 00:00:00 2001 From: Sachin Pikle Date: Thu, 18 Jan 2024 17:18:38 +0000 Subject: [PATCH 527/593] Using true --- .../graalvm-enterprise/oci/code-editor.md | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/docs/getting-started/graalvm-enterprise/oci/code-editor.md b/docs/getting-started/graalvm-enterprise/oci/code-editor.md index dbfa776766ac..397e638a20f8 100644 --- a/docs/getting-started/graalvm-enterprise/oci/code-editor.md +++ b/docs/getting-started/graalvm-enterprise/oci/code-editor.md @@ -96,14 +96,20 @@ This Java application incorporates the [Maven plugin for GraalVM Native Image](h ### Quick Build Mode Enabled -1. Build a native executable using the `native` Maven profile. The quick build mode is enabled for this run: notice the `-Ob` option in the plugin's configuration in _pom.xml_. +1. To enable the quick build mode, uncomment this line in _pom.xml_, as follows: + + ```xml + true + ``` + +2. Build a native executable using the `native` Maven profile: ```shell mvn clean -Pnative -DskipTests package ``` This will generate a native executable for Linux in the _target_ directory, named _my-app_. -2. Run the app native executable in the background: +3. Run the app native executable in the background: ```shell ./target/my-app @@ -114,8 +120,9 @@ This Java application incorporates the [Maven plugin for GraalVM Native Image](h 1. To disable the quick build mode, comment out this line in _pom.xml_, as follows: ```xml - + ``` + 2. Build a native executable again: ```shell From 6fafe6b442f5a9d83d3b301b632e3aae96b5a09b Mon Sep 17 00:00:00 2001 From: Tom Rodriguez Date: Thu, 18 Jan 2024 11:24:13 -0800 Subject: [PATCH 528/593] Create trivial BytecodeParser subclass for use by SerializationFeature --- .../serialize/SerializationFeature.java | 33 +++++++++++++++++-- 1 file changed, 31 insertions(+), 2 deletions(-) diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/reflect/serialize/SerializationFeature.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/reflect/serialize/SerializationFeature.java index 2851112a1688..dc05a641ea7d 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/reflect/serialize/SerializationFeature.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/reflect/serialize/SerializationFeature.java @@ -81,15 +81,17 @@ import com.oracle.svm.util.LogUtils; import com.oracle.svm.util.ReflectionUtil; -import jdk.graal.compiler.core.test.DefaultGraphBuilderPhase; import jdk.graal.compiler.debug.DebugContext; import jdk.graal.compiler.graph.iterators.NodeIterable; +import jdk.graal.compiler.java.BytecodeParser; import jdk.graal.compiler.java.GraphBuilderPhase; import jdk.graal.compiler.java.LambdaUtils; import jdk.graal.compiler.nodes.ConstantNode; import jdk.graal.compiler.nodes.StructuredGraph; import jdk.graal.compiler.nodes.graphbuilderconf.GraphBuilderConfiguration; +import jdk.graal.compiler.nodes.graphbuilderconf.IntrinsicContext; import jdk.graal.compiler.nodes.graphbuilderconf.InvocationPlugins; +import jdk.graal.compiler.nodes.spi.CoreProviders; import jdk.graal.compiler.options.OptionValues; import jdk.graal.compiler.phases.OptimisticOptimizations; import jdk.graal.compiler.phases.tiers.HighTierContext; @@ -211,9 +213,36 @@ private static void registerLambdasFromConstantNodesInGraph(StructuredGraph grap } } + static class LambdaGraphBuilderPhase extends GraphBuilderPhase { + public LambdaGraphBuilderPhase(GraphBuilderConfiguration config) { + super(config); + } + + @Override + public GraphBuilderPhase copyWithConfig(GraphBuilderConfiguration config) { + return new LambdaGraphBuilderPhase(config); + } + + static class LambdaBytecodeParser extends BytecodeParser { + protected LambdaBytecodeParser(Instance graphBuilderInstance, StructuredGraph graph, BytecodeParser parent, ResolvedJavaMethod method, int entryBCI, IntrinsicContext intrinsicContext) { + super(graphBuilderInstance, graph, parent, method, entryBCI, intrinsicContext); + } + } + + @Override + protected Instance createInstance(CoreProviders providers, GraphBuilderConfiguration instanceGBConfig, OptimisticOptimizations optimisticOpts, IntrinsicContext initialIntrinsicContext) { + return new Instance(providers, instanceGBConfig, optimisticOpts, initialIntrinsicContext) { + @Override + protected BytecodeParser createBytecodeParser(StructuredGraph graph, BytecodeParser parent, ResolvedJavaMethod method, int entryBCI, IntrinsicContext intrinsicContext) { + return new LambdaBytecodeParser(this, graph, parent, method, entryBCI, intrinsicContext); + } + }; + } + } + @SuppressWarnings("try") private static void registerLambdasFromMethod(ResolvedJavaMethod method, SerializationBuilder serializationBuilder, OptionValues options) { - GraphBuilderPhase lambdaParserPhase = new DefaultGraphBuilderPhase(buildLambdaParserConfig()); + GraphBuilderPhase lambdaParserPhase = new LambdaGraphBuilderPhase(buildLambdaParserConfig()); StructuredGraph graph = createMethodGraph(method, lambdaParserPhase, options); registerLambdasFromConstantNodesInGraph(graph, serializationBuilder); } From c594ca20a7e20cc2a62ec84fbabff800ebd9b785 Mon Sep 17 00:00:00 2001 From: Tom Rodriguez Date: Thu, 18 Jan 2024 12:10:43 -0800 Subject: [PATCH 529/593] Rename Default to Test --- .../compiler/microbenchmarks/graal/util/GraalUtil.java | 4 ++-- .../graal/compiler/core/test/CheckGraalInvariants.java | 2 +- .../compiler/core/test/FinalizableSubclassTest.java | 2 +- .../jdk/graal/compiler/core/test/NewInstanceTest.java | 2 +- .../compiler/core/test/StaticInterfaceFieldTest.java | 2 +- ...GraphBuilderPhase.java => TestGraphBuilderPhase.java} | 9 ++++----- .../graal/compiler/core/test/UnbalancedMonitorsTest.java | 2 +- .../compiler/core/test/VerifyAssertionUsageTest.java | 2 +- .../graal/compiler/core/test/VerifyBailoutUsageTest.java | 2 +- .../graal/compiler/core/test/VerifyDebugUsageTest.java | 2 +- .../compiler/core/test/VerifyVirtualizableTest.java | 2 +- .../compiler/core/test/tutorial/StaticAnalysis.java | 4 ++-- .../compiler/hotspot/test/LambdaStableNameTest.java | 4 ++-- .../compiler/replacements/test/PEGraphDecoderTest.java | 4 ++-- .../graal/compiler/replacements/test/SnippetsTest.java | 4 ++-- .../hosted/lambda/LambdaSubstrateGraphBuilderPhase.java | 2 +- .../hosted/reflect/serialize/SerializationFeature.java | 2 +- 17 files changed, 25 insertions(+), 26 deletions(-) rename compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/core/test/{DefaultGraphBuilderPhase.java => TestGraphBuilderPhase.java} (90%) diff --git a/compiler/src/jdk.graal.compiler.microbenchmarks/src/jdk/graal/compiler/microbenchmarks/graal/util/GraalUtil.java b/compiler/src/jdk.graal.compiler.microbenchmarks/src/jdk/graal/compiler/microbenchmarks/graal/util/GraalUtil.java index a891b3db866d..049a3e51d070 100644 --- a/compiler/src/jdk.graal.compiler.microbenchmarks/src/jdk/graal/compiler/microbenchmarks/graal/util/GraalUtil.java +++ b/compiler/src/jdk.graal.compiler.microbenchmarks/src/jdk/graal/compiler/microbenchmarks/graal/util/GraalUtil.java @@ -27,7 +27,7 @@ import java.lang.reflect.Method; import java.util.List; -import jdk.graal.compiler.core.test.DefaultGraphBuilderPhase; +import jdk.graal.compiler.core.test.TestGraphBuilderPhase; import jdk.graal.compiler.graph.Node; import jdk.graal.compiler.nodes.StructuredGraph; import jdk.graal.compiler.nodes.StructuredGraph.AllowAssumptions; @@ -138,7 +138,7 @@ public static StructuredGraph getGraph(GraalState graal, ResolvedJavaMethod java } StructuredGraph graph = builder.build(); PhaseSuite graphBuilderSuite = new PhaseSuite<>(); - graphBuilderSuite.appendPhase(new DefaultGraphBuilderPhase(GraphBuilderConfiguration.getDefault(new Plugins(new InvocationPlugins())))); + graphBuilderSuite.appendPhase(new TestGraphBuilderPhase(GraphBuilderConfiguration.getDefault(new Plugins(new InvocationPlugins())))); graphBuilderSuite.apply(graph, new HighTierContext(graal.providers, graphBuilderSuite, OptimisticOptimizations.ALL)); return graph; } diff --git a/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/core/test/CheckGraalInvariants.java b/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/core/test/CheckGraalInvariants.java index eb2df16c6eff..49aae7ac88a4 100644 --- a/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/core/test/CheckGraalInvariants.java +++ b/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/core/test/CheckGraalInvariants.java @@ -245,7 +245,7 @@ public static void runTest(InvariantsTool tool) { Plugins plugins = new Plugins(new InvocationPlugins()); plugins.setClassInitializationPlugin(new DoNotInitializeClassInitializationPlugin()); GraphBuilderConfiguration config = GraphBuilderConfiguration.getDefault(plugins).withEagerResolving(true).withUnresolvedIsError(true); - graphBuilderSuite.appendPhase(new DefaultGraphBuilderPhase(config)); + graphBuilderSuite.appendPhase(new TestGraphBuilderPhase(config)); HighTierContext context = new HighTierContext(providers, graphBuilderSuite, OptimisticOptimizations.NONE); Assume.assumeTrue(VerifyPhase.class.desiredAssertionStatus()); diff --git a/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/core/test/FinalizableSubclassTest.java b/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/core/test/FinalizableSubclassTest.java index 72050663b966..4f1e10460f99 100644 --- a/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/core/test/FinalizableSubclassTest.java +++ b/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/core/test/FinalizableSubclassTest.java @@ -80,7 +80,7 @@ private StructuredGraph parseAndProcess(Class cl, AllowAssumptions allowAssum StructuredGraph graph = new StructuredGraph.Builder(options, debug, allowAssumptions).method(javaMethod).build(); try (DebugContext.Scope s = debug.scope("FinalizableSubclassTest", graph)) { GraphBuilderConfiguration conf = GraphBuilderConfiguration.getSnippetDefault(getDefaultGraphBuilderPlugins()); - new DefaultGraphBuilderPhase.Instance(getProviders(), conf, OptimisticOptimizations.ALL, null).apply(graph); + new TestGraphBuilderPhase.Instance(getProviders(), conf, OptimisticOptimizations.ALL, null).apply(graph); HighTierContext context = new HighTierContext(getProviders(), getDefaultGraphBuilderSuite(), OptimisticOptimizations.ALL); createInliningPhase().apply(graph, context); diff --git a/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/core/test/NewInstanceTest.java b/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/core/test/NewInstanceTest.java index 1e8d6ce48902..7ef8b69ed70b 100644 --- a/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/core/test/NewInstanceTest.java +++ b/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/core/test/NewInstanceTest.java @@ -75,7 +75,7 @@ private StructuredGraph parseAndProcess(Class cl) { StructuredGraph graph = new StructuredGraph.Builder(options, getDebugContext(options, null, javaMethod), AllowAssumptions.YES).method(javaMethod).build(); GraphBuilderConfiguration conf = GraphBuilderConfiguration.getSnippetDefault(getDefaultGraphBuilderPlugins()).withUnresolvedIsError(false); - new DefaultGraphBuilderPhase.Instance(getProviders(), conf, OptimisticOptimizations.ALL, null).apply(graph); + new TestGraphBuilderPhase.Instance(getProviders(), conf, OptimisticOptimizations.ALL, null).apply(graph); return graph; } diff --git a/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/core/test/StaticInterfaceFieldTest.java b/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/core/test/StaticInterfaceFieldTest.java index d61e2e80a567..2c5e51974830 100644 --- a/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/core/test/StaticInterfaceFieldTest.java +++ b/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/core/test/StaticInterfaceFieldTest.java @@ -82,7 +82,7 @@ private void eagerlyParseMethod(Class clazz, String methodName) { PhaseSuite graphBuilderSuite = new PhaseSuite<>(); Plugins plugins = new Plugins(new InvocationPlugins()); GraphBuilderConfiguration config = GraphBuilderConfiguration.getDefault(plugins).withEagerResolving(true).withUnresolvedIsError(true); - graphBuilderSuite.appendPhase(new DefaultGraphBuilderPhase(config)); + graphBuilderSuite.appendPhase(new TestGraphBuilderPhase(config)); HighTierContext context = new HighTierContext(providers, graphBuilderSuite, OptimisticOptimizations.NONE); Assume.assumeTrue(VerifyPhase.class.desiredAssertionStatus()); diff --git a/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/core/test/DefaultGraphBuilderPhase.java b/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/core/test/TestGraphBuilderPhase.java similarity index 90% rename from compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/core/test/DefaultGraphBuilderPhase.java rename to compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/core/test/TestGraphBuilderPhase.java index ad3ba8f38007..86ca81ae2a47 100644 --- a/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/core/test/DefaultGraphBuilderPhase.java +++ b/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/core/test/TestGraphBuilderPhase.java @@ -37,14 +37,14 @@ * This is used when a platform independent instance of {@link BytecodeParser} is needed. In normal * usage the proper parser from the platform suites should be used instead. */ -public class DefaultGraphBuilderPhase extends GraphBuilderPhase { - public DefaultGraphBuilderPhase(GraphBuilderConfiguration config) { +public class TestGraphBuilderPhase extends GraphBuilderPhase { + public TestGraphBuilderPhase(GraphBuilderConfiguration config) { super(config); } @Override public GraphBuilderPhase copyWithConfig(GraphBuilderConfiguration config) { - return new DefaultGraphBuilderPhase(config); + return new TestGraphBuilderPhase(config); } @Override @@ -65,8 +65,7 @@ protected BytecodeParser createBytecodeParser(StructuredGraph graph, BytecodePar } /** - * A non-abstract subclass of {@link BytecodeParser}. This exists mainly the use of non-platform - * specific {@link BytecodeParser} can be audited. + * A non-abstract subclass of {@link BytecodeParser} */ static class DefaultBytecodeParser extends BytecodeParser { protected DefaultBytecodeParser(GraphBuilderPhase.Instance graphBuilderInstance, StructuredGraph graph, BytecodeParser parent, ResolvedJavaMethod method, int entryBCI, diff --git a/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/core/test/UnbalancedMonitorsTest.java b/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/core/test/UnbalancedMonitorsTest.java index ef450d1ca4b5..b976ad24157b 100644 --- a/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/core/test/UnbalancedMonitorsTest.java +++ b/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/core/test/UnbalancedMonitorsTest.java @@ -90,7 +90,7 @@ private void checkForBailout(String name) throws ClassNotFoundException { GraphBuilderConfiguration graphBuilderConfig = GraphBuilderConfiguration.getDefault(plugins).withEagerResolving(true).withUnresolvedIsError(true); OptimisticOptimizations optimisticOpts = OptimisticOptimizations.NONE; - GraphBuilderPhase.Instance graphBuilder = new DefaultGraphBuilderPhase.Instance(getProviders(), graphBuilderConfig, optimisticOpts, null); + GraphBuilderPhase.Instance graphBuilder = new TestGraphBuilderPhase.Instance(getProviders(), graphBuilderConfig, optimisticOpts, null); graphBuilder.apply(graph); } catch (BailoutException e) { if (e.getMessage().contains("unbalanced monitors") || diff --git a/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/core/test/VerifyAssertionUsageTest.java b/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/core/test/VerifyAssertionUsageTest.java index 93600bf858bc..3cadb2349bf9 100644 --- a/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/core/test/VerifyAssertionUsageTest.java +++ b/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/core/test/VerifyAssertionUsageTest.java @@ -429,7 +429,7 @@ private static void testDebugUsageClass(Class c) { PhaseSuite graphBuilderSuite = new PhaseSuite<>(); Plugins plugins = new Plugins(new InvocationPlugins()); GraphBuilderConfiguration config = GraphBuilderConfiguration.getDefault(plugins).withEagerResolving(true).withUnresolvedIsError(true); - graphBuilderSuite.appendPhase(new DefaultGraphBuilderPhase(config)); + graphBuilderSuite.appendPhase(new TestGraphBuilderPhase(config)); HighTierContext context = new HighTierContext(providers, graphBuilderSuite, OptimisticOptimizations.NONE); OptionValues options = GraalCompilerTest.getInitialOptions(); DebugContext debug = new Builder(options).build(); diff --git a/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/core/test/VerifyBailoutUsageTest.java b/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/core/test/VerifyBailoutUsageTest.java index bce5c88cd2a4..a6dcc7c721e6 100644 --- a/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/core/test/VerifyBailoutUsageTest.java +++ b/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/core/test/VerifyBailoutUsageTest.java @@ -121,7 +121,7 @@ private static void testBailoutUsage(Class c) { PhaseSuite graphBuilderSuite = new PhaseSuite<>(); Plugins plugins = new Plugins(new InvocationPlugins()); GraphBuilderConfiguration config = GraphBuilderConfiguration.getDefault(plugins).withEagerResolving(true).withUnresolvedIsError(true); - graphBuilderSuite.appendPhase(new DefaultGraphBuilderPhase(config)); + graphBuilderSuite.appendPhase(new TestGraphBuilderPhase(config)); HighTierContext context = new HighTierContext(providers, graphBuilderSuite, OptimisticOptimizations.NONE); OptionValues options = GraalCompilerTest.getInitialOptions(); DebugContext debug = new Builder(options).build(); diff --git a/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/core/test/VerifyDebugUsageTest.java b/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/core/test/VerifyDebugUsageTest.java index 6baa94b6dced..d7500c7263f3 100644 --- a/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/core/test/VerifyDebugUsageTest.java +++ b/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/core/test/VerifyDebugUsageTest.java @@ -330,7 +330,7 @@ private static void testDebugUsageClass(Class c) { PhaseSuite graphBuilderSuite = new PhaseSuite<>(); Plugins plugins = new Plugins(new InvocationPlugins()); GraphBuilderConfiguration config = GraphBuilderConfiguration.getDefault(plugins).withEagerResolving(true).withUnresolvedIsError(true); - graphBuilderSuite.appendPhase(new DefaultGraphBuilderPhase(config)); + graphBuilderSuite.appendPhase(new TestGraphBuilderPhase(config)); HighTierContext context = new HighTierContext(providers, graphBuilderSuite, OptimisticOptimizations.NONE); OptionValues options = getInitialOptions(); DebugContext debug = new Builder(options).build(); diff --git a/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/core/test/VerifyVirtualizableTest.java b/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/core/test/VerifyVirtualizableTest.java index 0a3699919f14..6e70749237f3 100644 --- a/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/core/test/VerifyVirtualizableTest.java +++ b/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/core/test/VerifyVirtualizableTest.java @@ -269,7 +269,7 @@ private static void testVirtualizableEffects(Class c) { PhaseSuite graphBuilderSuite = new PhaseSuite<>(); Plugins plugins = new Plugins(new InvocationPlugins()); GraphBuilderConfiguration config = GraphBuilderConfiguration.getDefault(plugins).withEagerResolving(true).withUnresolvedIsError(true); - graphBuilderSuite.appendPhase(new DefaultGraphBuilderPhase(config)); + graphBuilderSuite.appendPhase(new TestGraphBuilderPhase(config)); HighTierContext context = new HighTierContext(providers, graphBuilderSuite, OptimisticOptimizations.NONE); OptionValues options = getInitialOptions(); DebugContext debug = new Builder(options).build(); diff --git a/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/core/test/tutorial/StaticAnalysis.java b/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/core/test/tutorial/StaticAnalysis.java index 41839e7fa3d5..c43edd11b766 100644 --- a/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/core/test/tutorial/StaticAnalysis.java +++ b/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/core/test/tutorial/StaticAnalysis.java @@ -34,7 +34,7 @@ import java.util.Map; import java.util.Set; -import jdk.graal.compiler.core.test.DefaultGraphBuilderPhase; +import jdk.graal.compiler.core.test.TestGraphBuilderPhase; import jdk.graal.compiler.debug.DebugContext; import jdk.graal.compiler.debug.DebugContext.Builder; import jdk.graal.compiler.debug.GraalError; @@ -275,7 +275,7 @@ protected void process() { */ OptimisticOptimizations optimisticOpts = OptimisticOptimizations.NONE; - GraphBuilderPhase.Instance graphBuilder = new DefaultGraphBuilderPhase.Instance(providers, graphBuilderConfig, optimisticOpts, null); + GraphBuilderPhase.Instance graphBuilder = new TestGraphBuilderPhase.Instance(providers, graphBuilderConfig, optimisticOpts, null); graphBuilder.apply(graph); } catch (Throwable ex) { debug.handle(ex); diff --git a/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/hotspot/test/LambdaStableNameTest.java b/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/hotspot/test/LambdaStableNameTest.java index f4c423b6de1a..b3448d12862a 100644 --- a/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/hotspot/test/LambdaStableNameTest.java +++ b/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/hotspot/test/LambdaStableNameTest.java @@ -37,7 +37,7 @@ import org.objectweb.asm.Type; import jdk.graal.compiler.api.runtime.GraalJVMCICompiler; -import jdk.graal.compiler.core.test.DefaultGraphBuilderPhase; +import jdk.graal.compiler.core.test.TestGraphBuilderPhase; import jdk.graal.compiler.debug.DebugContext; import jdk.graal.compiler.debug.DebugContext.Builder; import jdk.graal.compiler.hotspot.meta.HotSpotJITClassInitializationPlugin; @@ -57,7 +57,7 @@ private String findStableLambdaName(ResolvedJavaType type) { Providers providers = compiler.getGraalRuntime().getCapability(RuntimeProvider.class).getHostBackend().getProviders(); final HotSpotJITClassInitializationPlugin initializationPlugin = new HotSpotJITClassInitializationPlugin(); return LambdaUtils.findStableLambdaName(initializationPlugin, providers, type, options, debug, this, - config -> new DefaultGraphBuilderPhase.Instance(providers, config, OptimisticOptimizations.NONE, null)); + config -> new TestGraphBuilderPhase.Instance(providers, config, OptimisticOptimizations.NONE, null)); } @Test diff --git a/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/replacements/test/PEGraphDecoderTest.java b/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/replacements/test/PEGraphDecoderTest.java index e0cd367817dc..870dbab60f73 100644 --- a/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/replacements/test/PEGraphDecoderTest.java +++ b/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/replacements/test/PEGraphDecoderTest.java @@ -35,8 +35,8 @@ import jdk.graal.compiler.core.common.memory.BarrierType; import jdk.graal.compiler.core.common.memory.MemoryOrderMode; import jdk.graal.compiler.core.common.type.StampFactory; -import jdk.graal.compiler.core.test.DefaultGraphBuilderPhase; import jdk.graal.compiler.core.test.GraalCompilerTest; +import jdk.graal.compiler.core.test.TestGraphBuilderPhase; import jdk.graal.compiler.debug.DebugContext; import jdk.graal.compiler.debug.DebugOptions; import jdk.graal.compiler.java.GraphBuilderPhase; @@ -233,7 +233,7 @@ private StructuredGraph test(String methodName, EconomicMap null, instance, false, false, true); diff --git a/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/replacements/test/SnippetsTest.java b/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/replacements/test/SnippetsTest.java index 94a7dcdbfea8..96b6d9d45288 100644 --- a/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/replacements/test/SnippetsTest.java +++ b/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/replacements/test/SnippetsTest.java @@ -24,7 +24,7 @@ */ package jdk.graal.compiler.replacements.test; -import jdk.graal.compiler.core.test.DefaultGraphBuilderPhase; +import jdk.graal.compiler.core.test.TestGraphBuilderPhase; import jdk.graal.compiler.java.GraphBuilderPhase.Instance; import jdk.graal.compiler.nodes.StructuredGraph; import jdk.graal.compiler.nodes.StructuredGraph.Builder; @@ -56,7 +56,7 @@ protected GraphMaker createGraphMaker(ResolvedJavaMethod substitute, ResolvedJav @Override protected Instance createGraphBuilder(Providers providers1, GraphBuilderConfiguration graphBuilderConfig, OptimisticOptimizations optimisticOpts, IntrinsicContext initialIntrinsicContext) { - return new DefaultGraphBuilderPhase.Instance(providers1, graphBuilderConfig, optimisticOpts, initialIntrinsicContext); + return new TestGraphBuilderPhase.Instance(providers1, graphBuilderConfig, optimisticOpts, initialIntrinsicContext); } }; } diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/lambda/LambdaSubstrateGraphBuilderPhase.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/lambda/LambdaSubstrateGraphBuilderPhase.java index af3fe2815911..f5274b67152e 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/lambda/LambdaSubstrateGraphBuilderPhase.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/lambda/LambdaSubstrateGraphBuilderPhase.java @@ -54,7 +54,7 @@ protected Instance createInstance(CoreProviders providers, GraphBuilderConfigura } public static class LambdaSubstrateGraphBuilderInstance extends GraphBuilderPhase.Instance { - LambdaSubstrateGraphBuilderInstance(CoreProviders theProviders, GraphBuilderConfiguration graphBuilderConfig, OptimisticOptimizations optimisticOpts, + public LambdaSubstrateGraphBuilderInstance(CoreProviders theProviders, GraphBuilderConfiguration graphBuilderConfig, OptimisticOptimizations optimisticOpts, IntrinsicContext initialIntrinsicContext) { super(theProviders, graphBuilderConfig, optimisticOpts, initialIntrinsicContext); } diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/reflect/serialize/SerializationFeature.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/reflect/serialize/SerializationFeature.java index dc05a641ea7d..1cc2dcaa5539 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/reflect/serialize/SerializationFeature.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/reflect/serialize/SerializationFeature.java @@ -214,7 +214,7 @@ private static void registerLambdasFromConstantNodesInGraph(StructuredGraph grap } static class LambdaGraphBuilderPhase extends GraphBuilderPhase { - public LambdaGraphBuilderPhase(GraphBuilderConfiguration config) { + LambdaGraphBuilderPhase(GraphBuilderConfiguration config) { super(config); } From 1670e0c678a02e6f428d1d14526d300712da943b Mon Sep 17 00:00:00 2001 From: ol-automation_ww Date: Thu, 18 Jan 2024 23:55:48 +0000 Subject: [PATCH 530/593] update JVMCI to 23+6-jvmci-b01 --- common.json | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/common.json b/common.json index 4cff9f9703bb..0b09562a18d4 100644 --- a/common.json +++ b/common.json @@ -45,12 +45,12 @@ "labsjdk-ee-21-llvm": {"name": "labsjdk", "version": "ee-21.0.1+11-jvmci-23.1-b26-sulong", "platformspecific": true }, "oraclejdk-latest": {"name": "jpg-jdk", "version": "23", "build_id": "5", "release": true, "platformspecific": true, "extrabundles": ["static-libs"]}, - "labsjdk-ce-latest": {"name": "labsjdk", "version": "ce-23+5-jvmci-b01", "platformspecific": true }, - "labsjdk-ce-latestDebug": {"name": "labsjdk", "version": "ce-23+5-jvmci-b01-debug", "platformspecific": true }, - "labsjdk-ce-latest-llvm": {"name": "labsjdk", "version": "ce-23+5-jvmci-b01-sulong", "platformspecific": true }, - "labsjdk-ee-latest": {"name": "labsjdk", "version": "ee-23+5-jvmci-b01", "platformspecific": true }, - "labsjdk-ee-latestDebug": {"name": "labsjdk", "version": "ee-23+5-jvmci-b01-debug", "platformspecific": true }, - "labsjdk-ee-latest-llvm": {"name": "labsjdk", "version": "ee-23+5-jvmci-b01-sulong", "platformspecific": true } + "labsjdk-ce-latest": {"name": "labsjdk", "version": "ce-23+6-jvmci-b01-20240118214947-84bbd7f3ac", "platformspecific": true }, + "labsjdk-ce-latestDebug": {"name": "labsjdk", "version": "ce-23+6-jvmci-b01-20240118214947-84bbd7f3ac-debug", "platformspecific": true }, + "labsjdk-ce-latest-llvm": {"name": "labsjdk", "version": "ce-23+6-jvmci-b01-20240118214947-84bbd7f3ac-sulong", "platformspecific": true }, + "labsjdk-ee-latest": {"name": "labsjdk", "version": "ee-23+6-jvmci-b01-20240118214947-84bbd7f3ac+91bc32db03", "platformspecific": true }, + "labsjdk-ee-latestDebug": {"name": "labsjdk", "version": "ee-23+6-jvmci-b01-20240118214947-84bbd7f3ac+91bc32db03-debug", "platformspecific": true }, + "labsjdk-ee-latest-llvm": {"name": "labsjdk", "version": "ee-23+6-jvmci-b01-20240118214947-84bbd7f3ac+91bc32db03-sulong", "platformspecific": true } }, "eclipse": { From a2c70d0112b982572db8f94d906ff064a19f04bd Mon Sep 17 00:00:00 2001 From: Josef Eisl Date: Fri, 19 Jan 2024 08:27:27 +0100 Subject: [PATCH 531/593] ci: update oraclejdk-latest to 23+6 --- common.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/common.json b/common.json index 0b09562a18d4..7b1a39044dd9 100644 --- a/common.json +++ b/common.json @@ -44,7 +44,7 @@ "labsjdk-ee-21Debug": {"name": "labsjdk", "version": "ee-21.0.1+11-jvmci-23.1-b26-debug", "platformspecific": true }, "labsjdk-ee-21-llvm": {"name": "labsjdk", "version": "ee-21.0.1+11-jvmci-23.1-b26-sulong", "platformspecific": true }, - "oraclejdk-latest": {"name": "jpg-jdk", "version": "23", "build_id": "5", "release": true, "platformspecific": true, "extrabundles": ["static-libs"]}, + "oraclejdk-latest": {"name": "jpg-jdk", "version": "23", "build_id": "6", "release": true, "platformspecific": true, "extrabundles": ["static-libs"]}, "labsjdk-ce-latest": {"name": "labsjdk", "version": "ce-23+6-jvmci-b01-20240118214947-84bbd7f3ac", "platformspecific": true }, "labsjdk-ce-latestDebug": {"name": "labsjdk", "version": "ce-23+6-jvmci-b01-20240118214947-84bbd7f3ac-debug", "platformspecific": true }, "labsjdk-ce-latest-llvm": {"name": "labsjdk", "version": "ce-23+6-jvmci-b01-20240118214947-84bbd7f3ac-sulong", "platformspecific": true }, From a9b96f2cd9593aeb35ac69bd50e8660ee5d05f63 Mon Sep 17 00:00:00 2001 From: Jakub Chaloupka Date: Fri, 12 Jan 2024 16:39:29 +0100 Subject: [PATCH 532/593] Add Truffle Windows gate build on jdkLatest. --- truffle/ci/ci.jsonnet | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/truffle/ci/ci.jsonnet b/truffle/ci/ci.jsonnet index bdfb42748338..564f3100b7fb 100644 --- a/truffle/ci/ci.jsonnet +++ b/truffle/ci/ci.jsonnet @@ -139,15 +139,9 @@ ], }, - truffle_common + windows_amd64 + common.oraclejdk21 + devkits["windows-jdk21"] + guard { - name: "gate-truffle-nfi-windows-21", - # TODO make that a full gate run - # currently, some truffle unittests fail on windows - run: [ - ["mx", "build" ], - ["mx", "unittest", "--verbose" ], - ], - }, + # TODO Run full gate on Windows GR-51441 + windows_amd64 + gate_lite + common.oraclejdk21 + devkits["windows-jdk21"] + guard, + windows_amd64 + gate_lite + common.oraclejdkLatest + devkits["windows-jdkLatest"] + guard, truffle_common + linux_amd64 + common.oraclejdk21 + common.deps.eclipse + common.deps.jdt + guard + { name: "weekly-truffle-coverage-21-linux-amd64", From eab620727dab693efa6f8cf3e0b87e786ce07500 Mon Sep 17 00:00:00 2001 From: Jakub Chaloupka Date: Fri, 19 Jan 2024 08:59:21 +0100 Subject: [PATCH 533/593] Fix gates. --- .../graalvm/nativeimage/hosted/RuntimeClassInitialization.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sdk/src/org.graalvm.nativeimage/src/org/graalvm/nativeimage/hosted/RuntimeClassInitialization.java b/sdk/src/org.graalvm.nativeimage/src/org/graalvm/nativeimage/hosted/RuntimeClassInitialization.java index e2f32a2f425d..1d0d2c6d619a 100644 --- a/sdk/src/org.graalvm.nativeimage/src/org/graalvm/nativeimage/hosted/RuntimeClassInitialization.java +++ b/sdk/src/org.graalvm.nativeimage/src/org/graalvm/nativeimage/hosted/RuntimeClassInitialization.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * The Universal Permissive License (UPL), Version 1.0 From 254c019486767709ef6cdb67183354221ec065b9 Mon Sep 17 00:00:00 2001 From: David Leopoldseder Date: Fri, 19 Jan 2024 09:59:10 +0100 Subject: [PATCH 534/593] induction variables: only non overflowing constant properties should be considered constant properties --- .../DerivedConvertedInductionVariable.java | 20 +++--- .../loop/DerivedOffsetInductionVariable.java | 62 +++++++++++++----- .../loop/DerivedScaledInductionVariable.java | 64 +++++++++++++++---- 3 files changed, 105 insertions(+), 41 deletions(-) diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/nodes/loop/DerivedConvertedInductionVariable.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/nodes/loop/DerivedConvertedInductionVariable.java index e9b41992e27b..3587edd0690b 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/nodes/loop/DerivedConvertedInductionVariable.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/nodes/loop/DerivedConvertedInductionVariable.java @@ -81,6 +81,16 @@ public long constantStride() { return base.constantStride(); } + @Override + public boolean isConstantExtremum() { + return base.isConstantExtremum(); + } + + @Override + public long constantExtremum() { + return base.constantExtremum(); + } + @Override public ValueNode extremumNode(boolean assumeLoopEntered, Stamp s) { // base.extremumNode will already perform any necessary conversion operation based on the @@ -102,16 +112,6 @@ public ValueNode exitValueNode() { return op(base.exitValueNode(), true); } - @Override - public boolean isConstantExtremum() { - return base.isConstantExtremum(); - } - - @Override - public long constantExtremum() { - return base.constantExtremum(); - } - @Override public void deleteUnusedNodes() { } diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/nodes/loop/DerivedOffsetInductionVariable.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/nodes/loop/DerivedOffsetInductionVariable.java index 8d3635bbcf51..975e591cd545 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/nodes/loop/DerivedOffsetInductionVariable.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/nodes/loop/DerivedOffsetInductionVariable.java @@ -69,7 +69,15 @@ public ValueNode valueNode() { @Override public boolean isConstantInit() { - return offset.isConstant() && base.isConstantInit(); + try { + if (offset.isConstant() && base.isConstantInit()) { + constantInitSafe(); + return true; + } + } catch (ArithmeticException e) { + // fall through to return false + } + return false; } @Override @@ -79,17 +87,47 @@ public boolean isConstantStride() { @Override public long constantInit() { - return op(base.constantInit(), offset.asJavaConstant().asLong()); + return constantInitSafe(); + } + + private long constantInitSafe() throws ArithmeticException { + return opSafe(base.constantInit(), offset.asJavaConstant().asLong()); } @Override public long constantStride() { + return constantStrideSafe(); + } + + private long constantStrideSafe() throws ArithmeticException { if (value instanceof SubNode && base.valueNode() == value.getY()) { - return -base.constantStride(); + return Math.multiplyExact(base.constantStride(), -1); } return base.constantStride(); } + @Override + public boolean isConstantExtremum() { + try { + if (offset.isConstant() && base.isConstantExtremum()) { + constantExtremumSafe(); + return true; + } + } catch (ArithmeticException e) { + // fall through to return false + } + return false; + } + + @Override + public long constantExtremum() { + return constantExtremumSafe(); + } + + private long constantExtremumSafe() throws ArithmeticException { + return opSafe(base.constantExtremum(), offset.asJavaConstant().asLong()); + } + @Override public ValueNode initNode() { return op(base.initNode(), offset); @@ -118,26 +156,16 @@ public ValueNode exitValueNode() { return op(base.exitValueNode(), offset); } - @Override - public boolean isConstantExtremum() { - return offset.isConstant() && base.isConstantExtremum(); - } - - @Override - public long constantExtremum() { - return op(base.constantExtremum(), offset.asJavaConstant().asLong()); - } - - private long op(long b, long o) { + private long opSafe(long b, long o) throws ArithmeticException { if (value instanceof AddNode) { - return b + o; + return Math.addExact(b, o); } if (value instanceof SubNode) { if (base.valueNode() == value.getX()) { - return b - o; + return Math.subtractExact(b, o); } else { assert base.valueNode() == value.getY() : Assertions.errorMessage(base, base.valueNode(), value, value.getY()); - return o - b; + return Math.subtractExact(b, o); } } throw GraalError.shouldNotReachHereUnexpectedValue(value); // ExcludeFromJacocoGeneratedReport diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/nodes/loop/DerivedScaledInductionVariable.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/nodes/loop/DerivedScaledInductionVariable.java index d6f903ebc493..2398aef9d872 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/nodes/loop/DerivedScaledInductionVariable.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/nodes/loop/DerivedScaledInductionVariable.java @@ -91,47 +91,83 @@ public ValueNode strideNode() { @Override public boolean isConstantInit() { - return scale.isConstant() && base.isConstantInit(); + try { + if (scale.isConstant() && base.isConstantInit()) { + constantInitSafe(); + return true; + } + } catch (ArithmeticException e) { + // fall through to return false + } + return false; } @Override public boolean isConstantStride() { - return scale.isConstant() && base.isConstantStride(); + try { + if (scale.isConstant() && base.isConstantStride()) { + constantStrideSafe(); + return true; + } + } catch (ArithmeticException e) { + // fall through to return false + } + return false; } @Override public long constantInit() { - return base.constantInit() * scale.asJavaConstant().asLong(); + return constantInitSafe(); + } + + private long constantInitSafe() throws ArithmeticException { + return Math.multiplyExact(base.constantInit(), scale.asJavaConstant().asLong()); } @Override public long constantStride() { - return base.constantStride() * scale.asJavaConstant().asLong(); + return constantStrideSafe(); + } + + private long constantStrideSafe() throws ArithmeticException { + return Math.multiplyExact(base.constantStride(), scale.asJavaConstant().asLong()); } @Override - public ValueNode extremumNode(boolean assumeLoopEntered, Stamp stamp) { - return mul(graph(), base.extremumNode(assumeLoopEntered, stamp), IntegerConvertNode.convert(scale, stamp, graph(), NodeView.DEFAULT)); + public boolean isConstantExtremum() { + try { + if (scale.isConstant() && base.isConstantExtremum()) { + constantExtremumSafe(); + return true; + } + } catch (ArithmeticException e) { + // fall through to return false + } + return false; } @Override - public ValueNode extremumNode(boolean assumeLoopEntered, Stamp stamp, ValueNode maxTripCount) { - return mul(graph(), base.extremumNode(assumeLoopEntered, stamp, maxTripCount), IntegerConvertNode.convert(scale, stamp, graph(), NodeView.DEFAULT)); + public long constantExtremum() { + return constantExtremumSafe(); + } + + private long constantExtremumSafe() throws ArithmeticException { + return Math.multiplyExact(base.constantExtremum(), scale.asJavaConstant().asLong()); } @Override - public ValueNode exitValueNode() { - return mul(graph(), base.exitValueNode(), scale); + public ValueNode extremumNode(boolean assumeLoopEntered, Stamp stamp) { + return mul(graph(), base.extremumNode(assumeLoopEntered, stamp), IntegerConvertNode.convert(scale, stamp, graph(), NodeView.DEFAULT)); } @Override - public boolean isConstantExtremum() { - return scale.isConstant() && base.isConstantExtremum(); + public ValueNode extremumNode(boolean assumeLoopEntered, Stamp stamp, ValueNode maxTripCount) { + return mul(graph(), base.extremumNode(assumeLoopEntered, stamp, maxTripCount), IntegerConvertNode.convert(scale, stamp, graph(), NodeView.DEFAULT)); } @Override - public long constantExtremum() { - return base.constantExtremum() * scale.asJavaConstant().asLong(); + public ValueNode exitValueNode() { + return mul(graph(), base.exitValueNode(), scale); } @Override From 241802796ce65354fd3e7a8ea5551a005b6eba15 Mon Sep 17 00:00:00 2001 From: Codrut Stancu Date: Fri, 19 Jan 2024 10:52:41 +0100 Subject: [PATCH 535/593] Move all fields interceptions to FieldValueInterceptionSupport. --- .../graal/pointsto/heap/ImageHeapScanner.java | 24 +++---- .../AnalysisConstantReflectionProvider.java | 64 ++----------------- .../ameta/FieldValueInterceptionSupport.java | 62 +++++++++++++++++- .../svm/hosted/heap/SVMImageHeapScanner.java | 5 +- 4 files changed, 77 insertions(+), 78 deletions(-) diff --git a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/heap/ImageHeapScanner.java b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/heap/ImageHeapScanner.java index d426eaad05dd..0b7c598105d6 100644 --- a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/heap/ImageHeapScanner.java +++ b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/heap/ImageHeapScanner.java @@ -46,6 +46,7 @@ import com.oracle.graal.pointsto.constraints.UnsupportedFeatureException; import com.oracle.graal.pointsto.heap.HeapSnapshotVerifier.ScanningObserver; import com.oracle.graal.pointsto.heap.value.ValueSupplier; +import com.oracle.graal.pointsto.infrastructure.UniverseMetaAccess; import com.oracle.graal.pointsto.meta.AnalysisField; import com.oracle.graal.pointsto.meta.AnalysisMetaAccess; import com.oracle.graal.pointsto.meta.AnalysisType; @@ -338,6 +339,7 @@ private Optional maybeReplace(JavaConstant constant, ScanReason re Object replaced = universe.replaceObject(unwrapped); if (replaced != unwrapped) { JavaConstant replacedConstant = universe.getSnippetReflection().forObject(replaced); + validateReplacedConstant(metaAccess, replacedConstant); return Optional.of(replacedConstant); } } catch (UnsupportedFeatureException e) { @@ -351,6 +353,11 @@ private Optional maybeReplace(JavaConstant constant, ScanReason re return Optional.empty(); } + /** Hook to run validation checks on the replaced value. */ + @SuppressWarnings("unused") + public void validateReplacedConstant(UniverseMetaAccess access, JavaConstant value) { + } + public static void maybeForceHashCodeComputation(Object constant) { if (constant instanceof String stringConstant) { forceHashCodeComputation(stringConstant); @@ -402,17 +409,7 @@ protected JavaConstant createFieldValue(AnalysisField field, ImageHeapInstance r * ready to be materialized. */ AnalysisError.guarantee(rawValue.isAvailable(), "Value not yet available for %s", field); - - JavaConstant transformedValue; - try { - transformedValue = transformFieldValue(field, receiver, rawValue.get()); - } catch (UnsupportedFeatureException e) { - ObjectScanner.unsupportedFeatureDuringFieldScan(universe.getBigbang(), field, receiver, e, reason); - transformedValue = JavaConstant.NULL_POINTER; - } - assert transformedValue != null : field.getDeclaringClass().toJavaName() + "::" + field.getName(); - - return createImageHeapConstant(transformedValue, reason); + return createImageHeapConstant(rawValue.get(), reason); } private void notifyAnalysis(AnalysisField field, ImageHeapInstance receiver, JavaConstant fieldValue, ScanReason reason) { @@ -445,11 +442,6 @@ private boolean doNotifyAnalysis(AnalysisField field, JavaConstant receiver, Jav return analysisModified; } - @SuppressWarnings("unused") - protected JavaConstant transformFieldValue(AnalysisField field, JavaConstant receiverConstant, JavaConstant originalValueConstant) { - return originalValueConstant; - } - protected JavaConstant onArrayElementReachable(ImageHeapArray array, AnalysisType arrayType, JavaConstant rawElementValue, int elementIndex, ScanReason reason, Consumer onAnalysisModified) { JavaConstant elementValue = createImageHeapConstant(rawElementValue, reason); diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/ameta/AnalysisConstantReflectionProvider.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/ameta/AnalysisConstantReflectionProvider.java index b5e155ad4eef..d7703810ff3c 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/ameta/AnalysisConstantReflectionProvider.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/ameta/AnalysisConstantReflectionProvider.java @@ -45,8 +45,6 @@ import com.oracle.graal.pointsto.meta.AnalysisUniverse; import com.oracle.graal.pointsto.util.AnalysisError; import com.oracle.svm.core.FrameAccess; -import com.oracle.svm.core.RuntimeAssertionsSupport; -import com.oracle.svm.core.annotate.InjectAccessors; import com.oracle.svm.core.graal.meta.SharedConstantReflectionProvider; import com.oracle.svm.core.hub.DynamicHub; import com.oracle.svm.core.meta.ObjectConstantEquality; @@ -59,7 +57,6 @@ import com.oracle.svm.hosted.meta.RelocatableConstant; import jdk.graal.compiler.core.common.type.TypedConstant; -import jdk.graal.compiler.word.Word; import jdk.vm.ci.meta.Constant; import jdk.vm.ci.meta.JavaConstant; import jdk.vm.ci.meta.JavaKind; @@ -265,7 +262,7 @@ public ValueSupplier readHostedFieldValue(AnalysisField field, Jav /** Returns the hosted field value. The receiver must be a hosted constant. */ @Override public JavaConstant readHostedFieldValue(UniverseMetaAccess access, AnalysisField field, JavaConstant receiver) { - return interceptValue(access, field, doReadValue(field, universe.toHosted(receiver))); + return replaceObject(doReadValue(field, universe.toHosted(receiver))); } private JavaConstant doReadValue(AnalysisField field, JavaConstant receiver) { @@ -275,7 +272,7 @@ private JavaConstant doReadValue(AnalysisField field, JavaConstant receiver) { /** * For classes that are simulated as initialized, provide the value of static fields to the * static analysis so that they are seen properly as roots in the image heap. - * + *

      * We cannot return such simulated field values for "normal" field value reads because then they * would be seen during bytecode parsing too. Therefore, we only return such values when * explicitly requested via a flag. @@ -291,30 +288,6 @@ private JavaConstant readSimulatedValue(AnalysisField field) { return simulateClassInitializerSupport.getSimulatedFieldValue(field); } - public JavaConstant interceptValue(UniverseMetaAccess suppliedMetaAccess, AnalysisField field, JavaConstant value) { - JavaConstant result = value; - if (result != null) { - result = filterInjectedAccessor(field, result); - result = replaceObject(result); - result = interceptAssertionStatus(field, result); - result = interceptWordField(suppliedMetaAccess, field, result); - } - return result; - } - - private static JavaConstant filterInjectedAccessor(AnalysisField field, JavaConstant value) { - if (field.getAnnotation(InjectAccessors.class) != null) { - /* - * Fields whose accesses are intercepted by injected accessors are not actually present - * in the image. Ideally they should never be read, but there are corner cases where - * this happens. We intercept the value and return 0 / null. - */ - assert !field.isAccessed(); - return JavaConstant.defaultForKind(value.getJavaKind()); - } - return value; - } - /** * Run all registered object replacers. */ @@ -330,44 +303,21 @@ private JavaConstant replaceObject(JavaConstant value) { Object oldObject = universe.getSnippetReflection().asObject(Object.class, value); Object newObject = universe.replaceObject(oldObject); if (newObject != oldObject) { - return universe.getSnippetReflection().forObject(newObject); + JavaConstant replacedConstant = universe.getSnippetReflection().forObject(newObject); + validateReplacedConstant(metaAccess, replacedConstant); + return replacedConstant; } } return value; } /** - * Intercept assertion status: the value of the field during image generation does not matter at - * all (because it is the hosted assertion status), we instead return the appropriate runtime - * assertion status. Field loads are also intrinsified early in - * {@link com.oracle.svm.hosted.phases.EarlyConstantFoldLoadFieldPlugin}, but we could still see - * such a field here if user code, e.g., accesses it via reflection. - */ - private static JavaConstant interceptAssertionStatus(AnalysisField field, JavaConstant value) { - if (field.isStatic() && field.isSynthetic() && field.getName().startsWith("$assertionsDisabled")) { - Class clazz = field.getDeclaringClass().getJavaClass(); - boolean assertionsEnabled = RuntimeAssertionsSupport.singleton().desiredAssertionStatus(clazz); - return JavaConstant.forBoolean(!assertionsEnabled); - } - return value; - } - - /** - * Intercept {@link Word} fields. {@link Word} values are boxed objects in the hosted world, but - * primitive values in the runtime world, so the default value of {@link Word} fields is 0. - * * {@link HostedLookupSnippetReflectionProvider} replaces relocatable pointers with * {@link RelocatableConstant} and regular {@link WordBase} values with * {@link PrimitiveConstant}. No other {@link WordBase} values can be reachable at this point. */ - private JavaConstant interceptWordField(UniverseMetaAccess suppliedMetaAccess, AnalysisField field, JavaConstant value) { - if (value.getJavaKind() == JavaKind.Object) { - VMError.guarantee(value instanceof RelocatableConstant || !suppliedMetaAccess.isInstanceOf(value, WordBase.class)); - if (value.isNull() && field.getType().isWordType()) { - return JavaConstant.forIntegerKind(universe.getWordKind(), 0); - } - } - return value; + public static void validateReplacedConstant(UniverseMetaAccess access, JavaConstant value) { + VMError.guarantee(value instanceof RelocatableConstant || !access.isInstanceOf(value, WordBase.class)); } @Override diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/ameta/FieldValueInterceptionSupport.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/ameta/FieldValueInterceptionSupport.java index 4975cb5eb161..0f47e7f47d0d 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/ameta/FieldValueInterceptionSupport.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/ameta/FieldValueInterceptionSupport.java @@ -42,6 +42,9 @@ import com.oracle.graal.pointsto.meta.AnalysisType; import com.oracle.graal.pointsto.util.GraalAccess; import com.oracle.svm.core.BuildPhaseProvider; +import com.oracle.svm.core.FrameAccess; +import com.oracle.svm.core.RuntimeAssertionsSupport; +import com.oracle.svm.core.annotate.InjectAccessors; import com.oracle.svm.core.annotate.RecomputeFieldValue; import com.oracle.svm.core.fieldvaluetransformer.FieldValueTransformerWithAvailability; import com.oracle.svm.core.fieldvaluetransformer.FieldValueTransformerWithAvailability.ValueAvailability; @@ -57,8 +60,10 @@ import com.oracle.svm.hosted.substitute.FieldValueTransformation; import com.oracle.svm.util.ReflectionUtil; +import jdk.graal.compiler.word.Word; import jdk.vm.ci.hotspot.HotSpotResolvedJavaField; import jdk.vm.ci.meta.JavaConstant; +import jdk.vm.ci.meta.JavaKind; import jdk.vm.ci.meta.ResolvedJavaField; /** @@ -244,17 +249,68 @@ public boolean hasFieldValueTransformer(AnalysisField field) { JavaConstant readFieldValue(ClassInitializationSupport classInitializationSupport, AnalysisField field, JavaConstant receiver) { assert isValueAvailable(field) : field; - + JavaConstant value; var interceptor = lookupFieldValueInterceptor(field); if (interceptor instanceof FieldValueTransformation transformation) { - return transformation.readValue(classInitializationSupport, field.wrapped, receiver); + value = transformation.readValue(classInitializationSupport, field.wrapped, receiver); } else { /* * If the wrapped field is ComputedValueField, the ReadableJavaField handling does the * necessary field value transformations. */ - return ReadableJavaField.readFieldValue(classInitializationSupport, field.wrapped, receiver); + value = ReadableJavaField.readFieldValue(classInitializationSupport, field.wrapped, receiver); + } + return interceptValue(field, value); + } + + private JavaConstant interceptValue(AnalysisField field, JavaConstant value) { + JavaConstant result = value; + if (result != null) { + result = filterInjectedAccessor(field, result); + result = interceptAssertionStatus(field, result); + result = interceptWordField(field, result); + } + return result; + } + + /** + * Fields whose accesses are intercepted by injected accessors are not actually present in the + * image. Ideally they should never be read, but there are corner cases where this happens. We + * intercept the value and return 0 / null. + */ + private static JavaConstant filterInjectedAccessor(AnalysisField field, JavaConstant value) { + if (field.getAnnotation(InjectAccessors.class) != null) { + assert !field.isAccessed(); + return JavaConstant.defaultForKind(value.getJavaKind()); + } + return value; + } + + /** + * Intercept assertion status: the value of the field during image generation does not matter at + * all (because it is the hosted assertion status), we instead return the appropriate runtime + * assertion status. Field loads are also intrinsified early in + * {@link com.oracle.svm.hosted.phases.EarlyConstantFoldLoadFieldPlugin}, but we could still see + * such a field here if user code, e.g., accesses it via reflection. + */ + private static JavaConstant interceptAssertionStatus(AnalysisField field, JavaConstant value) { + if (field.isStatic() && field.isSynthetic() && field.getName().startsWith("$assertionsDisabled")) { + Class clazz = field.getDeclaringClass().getJavaClass(); + boolean assertionsEnabled = RuntimeAssertionsSupport.singleton().desiredAssertionStatus(clazz); + return JavaConstant.forBoolean(!assertionsEnabled); + } + return value; + } + + /** + * Intercept {@link Word} fields. {@link Word} values are boxed objects in the hosted world, but + * primitive values in the runtime world, so the default value of {@link Word} fields is 0. + */ + private static JavaConstant interceptWordField(AnalysisField field, JavaConstant value) { + if (value.getJavaKind() == JavaKind.Object && value.isNull() && field.getType().isWordType()) { + return JavaConstant.forIntegerKind(FrameAccess.getWordKind(), 0); } + return value; } private static FieldValueComputer createFieldValueComputer(AnalysisField field) { diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/heap/SVMImageHeapScanner.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/heap/SVMImageHeapScanner.java index d75382b40d3a..2ca95e78ecd7 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/heap/SVMImageHeapScanner.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/heap/SVMImageHeapScanner.java @@ -43,6 +43,7 @@ import com.oracle.graal.pointsto.heap.ImageHeapConstant; import com.oracle.graal.pointsto.heap.ImageHeapScanner; import com.oracle.graal.pointsto.heap.value.ValueSupplier; +import com.oracle.graal.pointsto.infrastructure.UniverseMetaAccess; import com.oracle.graal.pointsto.meta.AnalysisField; import com.oracle.graal.pointsto.meta.AnalysisMetaAccess; import com.oracle.svm.core.hub.DynamicHub; @@ -145,8 +146,8 @@ protected ValueSupplier readHostedFieldValue(AnalysisField field, } @Override - protected JavaConstant transformFieldValue(AnalysisField field, JavaConstant receiverConstant, JavaConstant originalValueConstant) { - return ((AnalysisConstantReflectionProvider) constantReflection).interceptValue(metaAccess, field, originalValueConstant); + public void validateReplacedConstant(UniverseMetaAccess access, JavaConstant value) { + AnalysisConstantReflectionProvider.validateReplacedConstant(access, value); } @Override From 6b8a51fe3382823ce8370158709c9dc88ce5daa5 Mon Sep 17 00:00:00 2001 From: Codrut Stancu Date: Fri, 19 Jan 2024 10:47:21 +0100 Subject: [PATCH 536/593] Refactor AnalysisConstantReflection.readHostedFieldValueWithReplacement(). It doesn't need the metaAccess parameter anymore, so we can simplify also the SVMImageHeapVerifier since we don't need the custom object scanner anymore. --- .../ConstantReflectionProviderExtension.java | 4 +-- .../oracle/graal/pointsto/ObjectScanner.java | 4 ++- .../AnalysisConstantReflectionProvider.java | 4 +-- .../svm/hosted/heap/SVMImageHeapVerifier.java | 30 ------------------- .../svm/hosted/image/NativeImageHeap.java | 2 +- 5 files changed, 7 insertions(+), 37 deletions(-) diff --git a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/ConstantReflectionProviderExtension.java b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/ConstantReflectionProviderExtension.java index 8ed8e2009a26..23d5b1538060 100644 --- a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/ConstantReflectionProviderExtension.java +++ b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/ConstantReflectionProviderExtension.java @@ -24,12 +24,10 @@ */ package com.oracle.graal.pointsto; -import com.oracle.graal.pointsto.infrastructure.UniverseMetaAccess; - import jdk.vm.ci.meta.ConstantReflectionProvider; import jdk.vm.ci.meta.JavaConstant; import jdk.vm.ci.meta.ResolvedJavaField; public interface ConstantReflectionProviderExtension extends ConstantReflectionProvider { - JavaConstant readHostedFieldValue(UniverseMetaAccess access, T field, JavaConstant receiver); + JavaConstant readHostedFieldValueWithReplacement(T field, JavaConstant receiver); } diff --git a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/ObjectScanner.java b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/ObjectScanner.java index 7122eeb5ca9e..203f7610b87a 100644 --- a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/ObjectScanner.java +++ b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/ObjectScanner.java @@ -212,7 +212,9 @@ protected void scanField(AnalysisField field, JavaConstant receiver, ScanReason @SuppressWarnings("unchecked") protected JavaConstant readFieldValue(AnalysisField field, JavaConstant receiver) { - return ((ConstantReflectionProviderExtension) bb.getConstantReflectionProvider()).readHostedFieldValue(bb.getMetaAccess(), field, receiver); + /* The object scanner processes hosted values. We must not see shadow heap values here. */ + AnalysisError.guarantee(!(receiver instanceof ImageHeapConstant)); + return ((ConstantReflectionProviderExtension) bb.getConstantReflectionProvider()).readHostedFieldValueWithReplacement(field, receiver); } /** diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/ameta/AnalysisConstantReflectionProvider.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/ameta/AnalysisConstantReflectionProvider.java index d7703810ff3c..738db3bd4abb 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/ameta/AnalysisConstantReflectionProvider.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/ameta/AnalysisConstantReflectionProvider.java @@ -231,7 +231,7 @@ public JavaConstant readValue(UniverseMetaAccess suppliedMetaAccess, AnalysisFie } if (value == null) { VMError.guarantee(!SimulateClassInitializerSupport.singleton().isEnabled()); - value = universe.getHeapScanner().createImageHeapConstant(readHostedFieldValue(suppliedMetaAccess, field, receiver), ObjectScanner.OtherReason.UNKNOWN); + value = universe.getHeapScanner().createImageHeapConstant(readHostedFieldValueWithReplacement(field, receiver), ObjectScanner.OtherReason.UNKNOWN); } return value; } @@ -261,7 +261,7 @@ public ValueSupplier readHostedFieldValue(AnalysisField field, Jav /** Returns the hosted field value. The receiver must be a hosted constant. */ @Override - public JavaConstant readHostedFieldValue(UniverseMetaAccess access, AnalysisField field, JavaConstant receiver) { + public JavaConstant readHostedFieldValueWithReplacement(AnalysisField field, JavaConstant receiver) { return replaceObject(doReadValue(field, universe.toHosted(receiver))); } diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/heap/SVMImageHeapVerifier.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/heap/SVMImageHeapVerifier.java index a152d8c57097..797c0431fbe3 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/heap/SVMImageHeapVerifier.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/heap/SVMImageHeapVerifier.java @@ -30,18 +30,13 @@ import com.oracle.graal.pointsto.BigBang; import com.oracle.graal.pointsto.ObjectScanner; -import com.oracle.graal.pointsto.ObjectScanningObserver; import com.oracle.graal.pointsto.heap.HeapSnapshotVerifier; import com.oracle.graal.pointsto.heap.ImageHeap; -import com.oracle.graal.pointsto.heap.ImageHeapConstant; import com.oracle.graal.pointsto.heap.ImageHeapScanner; import com.oracle.graal.pointsto.infrastructure.UniverseMetaAccess; -import com.oracle.graal.pointsto.meta.AnalysisField; import com.oracle.graal.pointsto.meta.AnalysisType; import com.oracle.graal.pointsto.util.CompletionExecutor; -import com.oracle.svm.core.util.VMError; import com.oracle.svm.hosted.SVMHost; -import com.oracle.svm.hosted.ameta.AnalysisConstantReflectionProvider; import jdk.vm.ci.meta.Constant; import jdk.vm.ci.meta.JavaConstant; @@ -84,31 +79,6 @@ private void verifyHub(SVMHost svmHost, ObjectScanner objectScanner, AnalysisTyp objectScanner.scanConstant(hubConstant, ObjectScanner.OtherReason.HUB); } - @Override - protected ObjectScanner installObjectScanner(UniverseMetaAccess metaAccess, CompletionExecutor executor) { - return new VerifierObjectScanner(bb, metaAccess, executor, scannedObjects, new ScanningObserver()); - } - - private static final class VerifierObjectScanner extends ObjectScanner { - private final UniverseMetaAccess metaAccess; - - VerifierObjectScanner(BigBang bb, UniverseMetaAccess metaAccess, CompletionExecutor executor, ReusableSet scannedObjects, ObjectScanningObserver scanningObserver) { - super(bb, executor, scannedObjects, scanningObserver); - this.metaAccess = metaAccess; - } - - @Override - protected JavaConstant readFieldValue(AnalysisField field, JavaConstant receiver) { - AnalysisConstantReflectionProvider constantReflectionProvider = (AnalysisConstantReflectionProvider) bb.getConstantReflectionProvider(); - /* - * The verifier compares the hosted values with the ones from the shadow heap, so the - * constant reflection must not return shadow heap values. - */ - VMError.guarantee(!(receiver instanceof ImageHeapConstant)); - return constantReflectionProvider.readHostedFieldValue(metaAccess, field, receiver); - } - } - private SVMHost svmHost() { return (SVMHost) bb.getHostVM(); } diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/NativeImageHeap.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/NativeImageHeap.java index 1eaccf439cf1..b640cf9a25e0 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/NativeImageHeap.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/NativeImageHeap.java @@ -260,7 +260,7 @@ Object readInlinedField(HostedField field, JavaConstant receiver) { JavaConstant hostedReceiver = ((ImageHeapInstance) receiver).getHostedObject(); /* Use the AnalysisConstantReflectionProvider to get direct access to hosted values. */ AnalysisConstantReflectionProvider analysisConstantReflection = hConstantReflection.getWrappedConstantReflection(); - return hUniverse.getSnippetReflection().asObject(Object.class, analysisConstantReflection.readHostedFieldValue(hMetaAccess, field.getWrapped(), hostedReceiver)); + return hUniverse.getSnippetReflection().asObject(Object.class, analysisConstantReflection.readHostedFieldValueWithReplacement(field.getWrapped(), hostedReceiver)); } private JavaConstant readConstantField(HostedField field, JavaConstant receiver) { From bc64b92733cc8a0d062a70ebf9725bfcfcdc04b1 Mon Sep 17 00:00:00 2001 From: Josef Eisl Date: Fri, 19 Jan 2024 10:05:07 +0100 Subject: [PATCH 537/593] compiler: update JVMCIVersionCheck --- .../src/jdk/graal/compiler/hotspot/JVMCIVersionCheck.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/JVMCIVersionCheck.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/JVMCIVersionCheck.java index 790aaa7808ec..e5c4472d1625 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/JVMCIVersionCheck.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/JVMCIVersionCheck.java @@ -54,8 +54,8 @@ public final class JVMCIVersionCheck { private static final Map> JVMCI_MIN_VERSIONS = Map.of( "21", Map.of(DEFAULT_VENDOR_ENTRY, new Version(23, 1, 26)), "23", Map.of( - "Oracle Corporation", new Version("23+5", 1), - DEFAULT_VENDOR_ENTRY, new Version("23+5", 1))); + "Oracle Corporation", new Version("23+6", 1), + DEFAULT_VENDOR_ENTRY, new Version("23+6", 1))); private static final int NA = 0; /** * Minimum Java release supported by Graal. From 22331469817042995a12aea4bf41fae486904beb Mon Sep 17 00:00:00 2001 From: Mike Hearn Date: Thu, 11 Jan 2024 16:56:03 +0100 Subject: [PATCH 538/593] Espresso: impose a 64mb floor on the heap size. This fixes Gradle toolchain discovery. --- .../truffle/espresso/libjavavm/Arguments.java | 56 ++++++++++++++++++- 1 file changed, 55 insertions(+), 1 deletion(-) diff --git a/espresso/src/com.oracle.truffle.espresso.libjavavm/src/com/oracle/truffle/espresso/libjavavm/Arguments.java b/espresso/src/com.oracle.truffle.espresso.libjavavm/src/com/oracle/truffle/espresso/libjavavm/Arguments.java index 8ed6fac272a5..f84b99fc360a 100644 --- a/espresso/src/com.oracle.truffle.espresso.libjavavm/src/com/oracle/truffle/espresso/libjavavm/Arguments.java +++ b/espresso/src/com.oracle.truffle.espresso.libjavavm/src/com/oracle/truffle/espresso/libjavavm/Arguments.java @@ -29,6 +29,7 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.List; +import java.util.Locale; import java.util.Map; import java.util.Set; @@ -86,6 +87,8 @@ public static int setupContext(Context.Builder builder, JNIJavaVMInitArgs args) List jvmArgs = new ArrayList<>(); boolean ignoreUnrecognized = false; + boolean autoAdjustHeapSize = true; + List xOptions = new ArrayList<>(); for (int i = 0; i < count; i++) { JNIJavaVMOption option = (JNIJavaVMOption) p.add(i * SizeOf.get(JNIJavaVMOption.class)); @@ -176,8 +179,12 @@ public static int setupContext(Context.Builder builder, JNIJavaVMInitArgs args) builder.option(JAVA_PROPS + "jdk.module.limitmods", optionString.substring("--limit-modules=".length())); } else if (optionString.equals("--enable-preview")) { builder.option("java.EnablePreview", "true"); + } else if (optionString.equals("-XX:-AutoAdjustHeapSize")) { + autoAdjustHeapSize = false; + } else if (optionString.equals("-XX:+AutoAdjustHeapSize")) { + autoAdjustHeapSize = true; } else if (isXOption(optionString)) { - RuntimeOptions.set(optionString.substring("-X".length()), null); + xOptions.add(optionString); } else if (optionString.equals("-XX:+IgnoreUnrecognizedVMOptions")) { ignoreUnrecognized = true; } else if (optionString.equals("-XX:-IgnoreUnrecognizedVMOptions")) { @@ -223,6 +230,14 @@ public static int setupContext(Context.Builder builder, JNIJavaVMInitArgs args) } } + for (String xOption : xOptions) { + var opt = xOption; + if (autoAdjustHeapSize) { + opt = maybeAdjustMaxHeapSize(xOption); + } + RuntimeOptions.set(opt.substring(2 /* drop the -X */), null); + } + if (bootClasspathPrepend != null) { builder.option("java.BootClasspathPrepend", bootClasspathPrepend); } @@ -251,6 +266,45 @@ public static int setupContext(Context.Builder builder, JNIJavaVMInitArgs args) return JNIErrors.JNI_OK(); } + private static String maybeAdjustMaxHeapSize(String optionString) { + // (Jan 2024) Espresso uses more memory than HotSpot does, so if the user has set a very + // small heap size that would work on HotSpot then we have to bump it up. 32mb is too small + // to run Gradle's JDK version probe program which is required to use Espresso with Gradle, + // so, we go to the next power of two beyond that. This number can be reduced in future when + // memory efficiency is better. + if (!optionString.startsWith("-Xmx")) { + return optionString; + } + long maxHeapSizeBytes = parseLong(optionString.substring(4)); + final int floorMB = 64; + if (maxHeapSizeBytes < floorMB * 1024 * 1024) { + return "-Xmx" + floorMB + "m"; + } else { + return optionString; + } + } + + private static long parseLong(String v) { + String valueString = v.trim().toLowerCase(Locale.ROOT); + long scale = 1; + if (valueString.endsWith("k")) { + scale = 1024L; + } else if (valueString.endsWith("m")) { + scale = 1024L * 1024L; + } else if (valueString.endsWith("g")) { + scale = 1024L * 1024L * 1024L; + } else if (valueString.endsWith("t")) { + scale = 1024L * 1024L * 1024L * 1024L; + } + + if (scale != 1) { + /* Remove trailing scale character. */ + valueString = valueString.substring(0, valueString.length() - 1); + } + + return Long.parseLong(valueString) * scale; + } + private static void buildJvmArg(List jvmArgs, String optionString) { for (String ignored : ignoredJvmArgs) { if (optionString.startsWith(ignored)) { From 9d4d1dde84da4a1c346a7051a4794a5df52aaac8 Mon Sep 17 00:00:00 2001 From: Josef Eisl Date: Fri, 19 Jan 2024 09:45:48 +0100 Subject: [PATCH 539/593] svm: adopt "JDK-8323425: JFR: Auto-generated filename doesn't work with time-limited recording" --- .../svm/core/jfr/JfrJdkCompatibility.java | 28 ++++++++++++++++++- .../com/oracle/svm/core/jfr/JfrManager.java | 9 +++--- 2 files changed, 32 insertions(+), 5 deletions(-) diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jfr/JfrJdkCompatibility.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jfr/JfrJdkCompatibility.java index bce971f070c5..5dd2b20f8f8e 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jfr/JfrJdkCompatibility.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jfr/JfrJdkCompatibility.java @@ -28,20 +28,26 @@ import java.lang.reflect.Method; import java.time.Duration; -import jdk.graal.compiler.serviceprovider.JavaVersionUtil; import org.graalvm.nativeimage.Platform; import org.graalvm.nativeimage.Platforms; +import com.oracle.svm.core.SubstrateUtil; import com.oracle.svm.core.annotate.Alias; import com.oracle.svm.core.annotate.TargetClass; +import com.oracle.svm.core.annotate.TargetElement; import com.oracle.svm.core.jdk.JDK21OrEarlier; +import com.oracle.svm.core.jdk.JDK22OrEarlier; import com.oracle.svm.core.jdk.JDK22OrLater; +import com.oracle.svm.core.jdk.JDK23OrLater; import com.oracle.svm.core.util.VMError; import com.oracle.svm.util.ReflectionUtil; +import jdk.graal.compiler.serviceprovider.JavaVersionUtil; import jdk.jfr.Recording; import jdk.jfr.internal.JVM; import jdk.jfr.internal.JVMSupport; +import jdk.jfr.internal.PlatformRecording; +import jdk.jfr.internal.SecuritySupport; /** * Compatibility class to handle incompatible changes between JDK 21 and JDK 22. Once support for @@ -109,6 +115,15 @@ public static JVM getJVMOrNull() throws IllegalAccessException, InvocationTarget return (JVM) getJVM.invoke(null); } } + + public static void setDumpDirectory(PlatformRecording platformRecording, SecuritySupport.SafePath directory) { + Target_jdk_jfr_internal_PlatformRecording pr = SubstrateUtil.cast(platformRecording, Target_jdk_jfr_internal_PlatformRecording.class); + if (JavaVersionUtil.JAVA_SPEC >= 23) { + pr.setDumpDirectory(directory); + } else { + pr.setDumpOnExitDirectory(directory); + } + } } @TargetClass(className = "jdk.jfr.internal.Utils", onlyWith = {JDK21OrEarlier.class, HasJfrSupport.class}) @@ -131,3 +146,14 @@ final class Target_jdk_jfr_internal_util_ValueFormatter { @Alias public static native String formatTimespan(Duration dValue, String separation); } + +@TargetClass(className = "jdk.jfr.internal.PlatformRecording") +final class Target_jdk_jfr_internal_PlatformRecording { + @Alias + @TargetElement(onlyWith = JDK23OrLater.class) + public native void setDumpDirectory(SecuritySupport.SafePath directory); + + @Alias + @TargetElement(onlyWith = JDK22OrEarlier.class) + public native void setDumpOnExitDirectory(SecuritySupport.SafePath directory); +} diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jfr/JfrManager.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jfr/JfrManager.java index f77545e4f5e8..a8a24b6eab57 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jfr/JfrManager.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jfr/JfrManager.java @@ -36,8 +36,6 @@ import java.util.HashMap; import java.util.Map; -import jdk.graal.compiler.api.replacements.Fold; -import jdk.graal.compiler.core.common.SuppressFBWarnings; import org.graalvm.nativeimage.ImageSingletons; import org.graalvm.nativeimage.Platform; import org.graalvm.nativeimage.Platforms; @@ -49,6 +47,9 @@ import com.oracle.svm.core.util.UserError.UserException; import com.oracle.svm.core.util.VMError; +import jdk.graal.compiler.api.replacements.Fold; +import jdk.graal.compiler.core.common.SuppressFBWarnings; +import jdk.graal.compiler.serviceprovider.JavaVersionUtil; import jdk.jfr.FlightRecorder; import jdk.jfr.Recording; import jdk.jfr.internal.LogLevel; @@ -200,11 +201,11 @@ private static void initRecording() { dumpOnExit = Boolean.TRUE; } Path p = Paths.get(path); - if (Files.isDirectory(p) && Boolean.TRUE.equals(dumpOnExit)) { + if (Files.isDirectory(p) && (JavaVersionUtil.JAVA_SPEC >= 23 || Boolean.TRUE.equals(dumpOnExit))) { // Decide destination filename at dump time // Purposely avoid generating filename in Recording#setDestination due to // security concerns - PrivateAccess.getInstance().getPlatformRecording(recording).setDumpOnExitDirectory(new SecuritySupport.SafePath(p)); + JfrJdkCompatibility.setDumpDirectory(PrivateAccess.getInstance().getPlatformRecording(recording), new SecuritySupport.SafePath(p)); } else { safePath = resolvePath(recording, path); recording.setDestination(safePath.toPath()); From bc86e804ea1f5defa7413186e3d3e5a8c620bfdf Mon Sep 17 00:00:00 2001 From: Christian Haeubl Date: Fri, 19 Jan 2024 09:55:29 +0100 Subject: [PATCH 540/593] Fix a bug in the IsolateArgumentParser. --- .../oracle/svm/core/IsolateArgumentParser.java | 17 ++++++++++------- .../graal/snippets/CEntryPointSnippets.java | 2 +- 2 files changed, 11 insertions(+), 8 deletions(-) diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/IsolateArgumentParser.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/IsolateArgumentParser.java index 598ae00f97e0..bc1dc541e959 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/IsolateArgumentParser.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/IsolateArgumentParser.java @@ -192,7 +192,10 @@ public void verifyOptionValues() { } private static boolean shouldValidate(RuntimeOptionKey option) { - if (SubstrateOptions.UseSerialGC.getValue()) { + if (!option.hasBeenSet()) { + /* Workaround for one specific Truffle language that does something weird. */ + return false; + } else if (SubstrateOptions.UseSerialGC.getValue()) { /* The serial GC supports changing the heap size at run-time to some degree. */ return option != SubstrateGCOptions.MinHeapSize && option != SubstrateGCOptions.MaxHeapSize && option != SubstrateGCOptions.MaxNewSize; } @@ -230,12 +233,10 @@ private static Object getOptionValue(int index) { } private static void validate(RuntimeOptionKey option, Object oldValue) { - if (option.hasBeenSet()) { - Object newValue = option.getValue(); - if (newValue == null || !newValue.equals(oldValue)) { - throw new IllegalArgumentException( - "The option '" + option.getName() + "' can't be changed after isolate creation. Old value: " + oldValue + ", new value: " + newValue); - } + Object newValue = option.getValue(); + if (newValue == null || !newValue.equals(oldValue)) { + throw new IllegalArgumentException( + "The option '" + option.getName() + "' can't be changed after isolate creation. Old value: " + oldValue + ", new value: " + newValue); } } @@ -344,6 +345,8 @@ private static boolean atojulong(CCharPointer s, CLongPointer result) { } CCharPointerPointer tailPtr = (CCharPointerPointer) StackValue.get(CCharPointer.class); + + LibC.setErrno(0); UnsignedWord n = LibC.strtoull(s, tailPtr, 10); if (LibC.errno() != 0) { return false; diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/graal/snippets/CEntryPointSnippets.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/graal/snippets/CEntryPointSnippets.java index 480183ad2464..8dfd1fe22fd9 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/graal/snippets/CEntryPointSnippets.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/graal/snippets/CEntryPointSnippets.java @@ -227,13 +227,13 @@ private static int createIsolate(CEntryPointCreateIsolateParameters providedPara if (!validPageSize) { return CEntryPointErrors.PAGE_SIZE_CHECK_FAILED; } - CLongPointer parsedArgs = StackValue.get(IsolateArgumentParser.getStructSize()); CEntryPointCreateIsolateParameters parameters = providedParameters; if (parameters.isNull() || parameters.version() < 1) { parameters = StackValue.get(CEntryPointCreateIsolateParameters.class); parameters.setReservedSpaceSize(WordFactory.zero()); parameters.setVersion(1); } + CLongPointer parsedArgs = StackValue.get(IsolateArgumentParser.getStructSize()); IsolateArgumentParser.parse(parameters, parsedArgs); if (parameters.reservedSpaceSize().equal(0)) { parameters.setReservedSpaceSize(WordFactory.unsigned(parsedArgs.read(IsolateArgumentParser.getOptionIndex(SubstrateGCOptions.ReservedAddressSpaceSize)))); From bc036552696aa9d0ab46e0d1ab393e5f337cf602 Mon Sep 17 00:00:00 2001 From: Marouane El Hallaoui Date: Fri, 19 Jan 2024 12:05:24 +0100 Subject: [PATCH 541/593] deploy labsjdk snapshots --- common.json | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/common.json b/common.json index 7b1a39044dd9..6799e780db29 100644 --- a/common.json +++ b/common.json @@ -45,12 +45,12 @@ "labsjdk-ee-21-llvm": {"name": "labsjdk", "version": "ee-21.0.1+11-jvmci-23.1-b26-sulong", "platformspecific": true }, "oraclejdk-latest": {"name": "jpg-jdk", "version": "23", "build_id": "6", "release": true, "platformspecific": true, "extrabundles": ["static-libs"]}, - "labsjdk-ce-latest": {"name": "labsjdk", "version": "ce-23+6-jvmci-b01-20240118214947-84bbd7f3ac", "platformspecific": true }, - "labsjdk-ce-latestDebug": {"name": "labsjdk", "version": "ce-23+6-jvmci-b01-20240118214947-84bbd7f3ac-debug", "platformspecific": true }, - "labsjdk-ce-latest-llvm": {"name": "labsjdk", "version": "ce-23+6-jvmci-b01-20240118214947-84bbd7f3ac-sulong", "platformspecific": true }, - "labsjdk-ee-latest": {"name": "labsjdk", "version": "ee-23+6-jvmci-b01-20240118214947-84bbd7f3ac+91bc32db03", "platformspecific": true }, - "labsjdk-ee-latestDebug": {"name": "labsjdk", "version": "ee-23+6-jvmci-b01-20240118214947-84bbd7f3ac+91bc32db03-debug", "platformspecific": true }, - "labsjdk-ee-latest-llvm": {"name": "labsjdk", "version": "ee-23+6-jvmci-b01-20240118214947-84bbd7f3ac+91bc32db03-sulong", "platformspecific": true } + "labsjdk-ce-latest": {"name": "labsjdk", "version": "ce-23+6-jvmci-b01", "platformspecific": true }, + "labsjdk-ce-latestDebug": {"name": "labsjdk", "version": "ce-23+6-jvmci-b01-debug", "platformspecific": true }, + "labsjdk-ce-latest-llvm": {"name": "labsjdk", "version": "ce-23+6-jvmci-b01-sulong", "platformspecific": true }, + "labsjdk-ee-latest": {"name": "labsjdk", "version": "ee-23+6-jvmci-b01", "platformspecific": true }, + "labsjdk-ee-latestDebug": {"name": "labsjdk", "version": "ee-23+6-jvmci-b01-debug", "platformspecific": true }, + "labsjdk-ee-latest-llvm": {"name": "labsjdk", "version": "ee-23+6-jvmci-b01-sulong", "platformspecific": true } }, "eclipse": { From 4a8ac4b7f9c019263b67573aee3e5a66c6c7fa0d Mon Sep 17 00:00:00 2001 From: Christian Haeubl Date: Thu, 18 Jan 2024 12:30:59 +0100 Subject: [PATCH 542/593] Fix a Windows-specific thread handle leak. --- .../posix/thread/PosixPlatformThreads.java | 33 ++-------- .../core/windows/WindowsPlatformThreads.java | 62 +++---------------- .../com/oracle/svm/core/JavaMainWrapper.java | 6 +- .../svm/core/thread/PlatformThreads.java | 21 +++++-- .../com/oracle/svm/core/thread/VMThreads.java | 10 ++- 5 files changed, 41 insertions(+), 91 deletions(-) diff --git a/substratevm/src/com.oracle.svm.core.posix/src/com/oracle/svm/core/posix/thread/PosixPlatformThreads.java b/substratevm/src/com.oracle.svm.core.posix/src/com/oracle/svm/core/posix/thread/PosixPlatformThreads.java index 927a93f978a6..bc9f8bfb5df6 100644 --- a/substratevm/src/com.oracle.svm.core.posix/src/com/oracle/svm/core/posix/thread/PosixPlatformThreads.java +++ b/substratevm/src/com.oracle.svm.core.posix/src/com/oracle/svm/core/posix/thread/PosixPlatformThreads.java @@ -24,17 +24,12 @@ */ package com.oracle.svm.core.posix.thread; -import jdk.graal.compiler.core.common.SuppressFBWarnings; import org.graalvm.nativeimage.ImageSingletons; -import org.graalvm.nativeimage.ObjectHandle; import org.graalvm.nativeimage.Platform; import org.graalvm.nativeimage.Platform.HOSTED_ONLY; import org.graalvm.nativeimage.Platforms; import org.graalvm.nativeimage.StackValue; import org.graalvm.nativeimage.UnmanagedMemory; -import org.graalvm.nativeimage.c.function.CEntryPoint; -import org.graalvm.nativeimage.c.function.CEntryPoint.Publish; -import org.graalvm.nativeimage.c.function.CEntryPointLiteral; import org.graalvm.nativeimage.c.function.CFunctionPointer; import org.graalvm.nativeimage.c.struct.SizeOf; import org.graalvm.nativeimage.c.type.CTypeConversion; @@ -52,8 +47,6 @@ import com.oracle.svm.core.annotate.Inject; import com.oracle.svm.core.annotate.RecomputeFieldValue; import com.oracle.svm.core.annotate.TargetClass; -import com.oracle.svm.core.c.function.CEntryPointOptions; -import com.oracle.svm.core.c.function.CEntryPointSetup.LeaveDetachThreadEpilogue; import com.oracle.svm.core.feature.AutomaticallyRegisteredImageSingleton; import com.oracle.svm.core.graal.stackvalue.UnsafeStackValue; import com.oracle.svm.core.posix.PosixUtils; @@ -72,9 +65,11 @@ import com.oracle.svm.core.thread.Parker; import com.oracle.svm.core.thread.Parker.ParkerFactory; import com.oracle.svm.core.thread.PlatformThreads; +import com.oracle.svm.core.thread.VMThreads.OSThreadHandle; import com.oracle.svm.core.util.UnsignedUtils; import com.oracle.svm.core.util.VMError; +import jdk.graal.compiler.core.common.SuppressFBWarnings; import jdk.internal.misc.Unsafe; @AutomaticallyRegisteredImageSingleton(PlatformThreads.class) @@ -116,7 +111,7 @@ protected boolean doStartThread(Thread thread, long stackSize) { ThreadStartData startData = prepareStart(thread, SizeOf.get(ThreadStartData.class)); Pthread.pthread_tPointer newThread = UnsafeStackValue.get(Pthread.pthread_tPointer.class); - if (Pthread.pthread_create(newThread, attributes, PosixPlatformThreads.pthreadStartRoutine.getFunctionPointer(), startData) != 0) { + if (Pthread.pthread_create(newThread, attributes, threadStartRoutine.getFunctionPointer(), startData) != 0) { undoPrepareStartOnError(thread, startData); return false; } @@ -182,19 +177,6 @@ protected void yieldCurrent() { Sched.sched_yield(); } - private static final CEntryPointLiteral pthreadStartRoutine = CEntryPointLiteral.create(PosixPlatformThreads.class, "pthreadStartRoutine", ThreadStartData.class); - - @CEntryPoint(include = CEntryPoint.NotIncludedAutomatically.class, publishAs = Publish.NotPublished) - @CEntryPointOptions(prologue = ThreadStartRoutinePrologue.class, epilogue = LeaveDetachThreadEpilogue.class) - static WordBase pthreadStartRoutine(ThreadStartData data) { - ObjectHandle threadHandle = data.getThreadHandle(); - freeStartData(data); - - threadStartRoutine(threadHandle); - - return WordFactory.nullPointer(); - } - @Override protected void beforeThreadRun(Thread thread) { /* Complete the initialization of the thread, now that it is (nearly) running. */ @@ -237,7 +219,7 @@ public OSThreadHandle startThreadUnmanaged(CFunctionPointer threadRoutine, Point return WordFactory.nullPointer(); } - return (OSThreadHandle) newThread.read(); + return newThread.read(); } finally { Pthread.pthread_attr_destroy_no_transition(attributes); } @@ -282,13 +264,6 @@ public void setUnmanagedThreadLocalValue(ThreadLocalKey key, WordBase value) { int resultCode = Pthread.pthread_setspecific((Pthread.pthread_key_t) key, (VoidPointer) value); PosixUtils.checkStatusIs0(resultCode, "pthread_setspecific(key, value): wrong arguments."); } - - @Override - @SuppressWarnings("unused") - @Uninterruptible(reason = "Called from uninterruptible code.", mayBeInlined = true) - public void closeOSThreadHandle(OSThreadHandle threadHandle) { - // pthread_t doesn't need closing - } } @TargetClass(Thread.class) diff --git a/substratevm/src/com.oracle.svm.core.windows/src/com/oracle/svm/core/windows/WindowsPlatformThreads.java b/substratevm/src/com.oracle.svm.core.windows/src/com/oracle/svm/core/windows/WindowsPlatformThreads.java index 0371b461b79a..c2cb0e7848d9 100644 --- a/substratevm/src/com.oracle.svm.core.windows/src/com/oracle/svm/core/windows/WindowsPlatformThreads.java +++ b/substratevm/src/com.oracle.svm.core.windows/src/com/oracle/svm/core/windows/WindowsPlatformThreads.java @@ -24,16 +24,10 @@ */ package com.oracle.svm.core.windows; -import org.graalvm.nativeimage.ObjectHandle; import org.graalvm.nativeimage.Platform; import org.graalvm.nativeimage.Platform.HOSTED_ONLY; import org.graalvm.nativeimage.Platforms; -import org.graalvm.nativeimage.c.function.CEntryPoint; -import org.graalvm.nativeimage.c.function.CEntryPoint.Publish; -import org.graalvm.nativeimage.c.function.CEntryPointLiteral; import org.graalvm.nativeimage.c.function.CFunctionPointer; -import org.graalvm.nativeimage.c.struct.RawField; -import org.graalvm.nativeimage.c.struct.RawStructure; import org.graalvm.nativeimage.c.struct.SizeOf; import org.graalvm.nativeimage.c.type.CIntPointer; import org.graalvm.nativeimage.c.type.VoidPointer; @@ -43,20 +37,20 @@ import org.graalvm.word.WordFactory; import com.oracle.svm.core.Uninterruptible; -import com.oracle.svm.core.c.function.CEntryPointOptions; -import com.oracle.svm.core.c.function.CEntryPointSetup.LeaveDetachThreadEpilogue; import com.oracle.svm.core.feature.AutomaticallyRegisteredImageSingleton; -import com.oracle.svm.core.graal.stackvalue.UnsafeStackValue; import com.oracle.svm.core.stack.StackOverflowCheck; import com.oracle.svm.core.thread.Parker; import com.oracle.svm.core.thread.Parker.ParkerFactory; import com.oracle.svm.core.thread.PlatformThreads; +import com.oracle.svm.core.thread.VMThreads.OSThreadHandle; import com.oracle.svm.core.util.TimeUtils; import com.oracle.svm.core.util.VMError; import com.oracle.svm.core.windows.headers.Process; import com.oracle.svm.core.windows.headers.SynchAPI; import com.oracle.svm.core.windows.headers.WinBase; +import jdk.graal.compiler.core.common.NumUtil; + @AutomaticallyRegisteredImageSingleton(PlatformThreads.class) @Platforms(Platform.WINDOWS.class) public final class WindowsPlatformThreads extends PlatformThreads { @@ -66,27 +60,21 @@ public final class WindowsPlatformThreads extends PlatformThreads { @Override protected boolean doStartThread(Thread thread, long stackSize) { - int threadStackSize = (int) stackSize; - int initFlag = Process.CREATE_SUSPENDED(); - - WindowsThreadStartData startData = prepareStart(thread, SizeOf.get(WindowsThreadStartData.class)); + int threadStackSize = NumUtil.safeToUInt(stackSize); + int initFlag = 0; // If caller specified a stack size, don't commit it all at once. if (threadStackSize != 0) { initFlag |= Process.STACK_SIZE_PARAM_IS_A_RESERVATION(); } - CIntPointer osThreadID = UnsafeStackValue.get(CIntPointer.class); - WinBase.HANDLE osThreadHandle = Process._beginthreadex(WordFactory.nullPointer(), threadStackSize, - WindowsPlatformThreads.osThreadStartRoutine.getFunctionPointer(), startData, initFlag, osThreadID); + ThreadStartData startData = prepareStart(thread, SizeOf.get(ThreadStartData.class)); + WinBase.HANDLE osThreadHandle = Process._beginthreadex(WordFactory.nullPointer(), threadStackSize, threadStartRoutine.getFunctionPointer(), startData, initFlag, WordFactory.nullPointer()); if (osThreadHandle.isNull()) { undoPrepareStartOnError(thread, startData); return false; } - startData.setOSThreadHandle(osThreadHandle); - - // Start the thread running - Process.ResumeThread(osThreadHandle); + WinBase.CloseHandle(osThreadHandle); return true; } @@ -102,7 +90,7 @@ public OSThreadHandle startThreadUnmanaged(CFunctionPointer threadRoutine, Point WinBase.HANDLE osThreadHandle = Process.NoTransitions._beginthreadex(WordFactory.nullPointer(), stackSize, threadRoutine, userData, initFlag, WordFactory.nullPointer()); - return (PlatformThreads.OSThreadHandle) osThreadHandle; + return (OSThreadHandle) osThreadHandle; } @Override @@ -172,38 +160,6 @@ protected void setNativeName(Thread thread, String name) { protected void yieldCurrent() { Process.SwitchToThread(); } - - @RawStructure - interface WindowsThreadStartData extends ThreadStartData { - - @RawField - WinBase.HANDLE getOSThreadHandle(); - - @RawField - void setOSThreadHandle(WinBase.HANDLE osHandle); - } - - private static final CEntryPointLiteral osThreadStartRoutine = CEntryPointLiteral.create(WindowsPlatformThreads.class, "osThreadStartRoutine", WindowsThreadStartData.class); - - @CEntryPoint(include = CEntryPoint.NotIncludedAutomatically.class, publishAs = Publish.NotPublished) - @CEntryPointOptions(prologue = ThreadStartRoutinePrologue.class, epilogue = LeaveDetachThreadEpilogue.class) - static WordBase osThreadStartRoutine(WindowsThreadStartData data) { - ObjectHandle threadHandle = data.getThreadHandle(); - WinBase.HANDLE osThreadHandle = data.getOSThreadHandle(); - freeStartData(data); - - try { - threadStartRoutine(threadHandle); - } finally { - /* - * Note that there is another handle to the thread stored in VMThreads.OSThreadHandleTL. - * This is necessary to ensure that the operating system does not release the thread - * resources too early. - */ - WinBase.CloseHandle(osThreadHandle); - } - return WordFactory.nullPointer(); - } } /** diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/JavaMainWrapper.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/JavaMainWrapper.java index f7802cf87943..5295e0aa7757 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/JavaMainWrapper.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/JavaMainWrapper.java @@ -35,7 +35,6 @@ import java.util.List; import java.util.function.BooleanSupplier; -import jdk.graal.compiler.word.Word; import org.graalvm.nativeimage.CurrentIsolate; import org.graalvm.nativeimage.ImageSingletons; import org.graalvm.nativeimage.Isolate; @@ -75,12 +74,15 @@ import com.oracle.svm.core.thread.PlatformThreads; import com.oracle.svm.core.thread.ThreadListenerSupport; import com.oracle.svm.core.thread.VMThreads; +import com.oracle.svm.core.thread.VMThreads.OSThreadHandle; import com.oracle.svm.core.util.CounterSupport; import com.oracle.svm.core.util.UserError; import com.oracle.svm.core.util.VMError; import com.oracle.svm.util.ClassUtil; import com.oracle.svm.util.ReflectionUtil; +import jdk.graal.compiler.word.Word; + @InternalVMMethod public class JavaMainWrapper { /* @@ -309,7 +311,7 @@ private static int doRunInNewThread(int argc, CCharPointerPointer argv) { MAIN_ISOLATE_PARAMETERS.get().setArgc(argc); MAIN_ISOLATE_PARAMETERS.get().setArgv(argv); long stackSize = SubstrateOptions.StackSize.getHostedValue(); - PlatformThreads.OSThreadHandle osThreadHandle = PlatformThreads.singleton().startThreadUnmanaged(RUN_MAIN_ROUTINE.get(), WordFactory.nullPointer(), (int) stackSize); + OSThreadHandle osThreadHandle = PlatformThreads.singleton().startThreadUnmanaged(RUN_MAIN_ROUTINE.get(), WordFactory.nullPointer(), (int) stackSize); if (osThreadHandle.isNull()) { CEntryPointActions.failFatally(1, START_THREAD_UNMANAGED_ERROR_MESSAGE.get()); return 1; diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/thread/PlatformThreads.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/thread/PlatformThreads.java index b126902e583f..f17f0241238c 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/thread/PlatformThreads.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/thread/PlatformThreads.java @@ -59,6 +59,7 @@ import org.graalvm.nativeimage.Platforms; import org.graalvm.nativeimage.UnmanagedMemory; import org.graalvm.nativeimage.c.function.CEntryPoint; +import org.graalvm.nativeimage.c.function.CEntryPointLiteral; import org.graalvm.nativeimage.c.function.CFunctionPointer; import org.graalvm.nativeimage.c.function.CodePointer; import org.graalvm.nativeimage.c.struct.RawField; @@ -85,6 +86,7 @@ import com.oracle.svm.core.c.function.CEntryPointActions; import com.oracle.svm.core.c.function.CEntryPointErrors; import com.oracle.svm.core.c.function.CEntryPointOptions; +import com.oracle.svm.core.c.function.CEntryPointSetup; import com.oracle.svm.core.heap.Heap; import com.oracle.svm.core.heap.ReferenceHandler; import com.oracle.svm.core.heap.ReferenceHandlerThread; @@ -99,6 +101,7 @@ import com.oracle.svm.core.nodes.CFunctionPrologueNode; import com.oracle.svm.core.stack.StackFrameVisitor; import com.oracle.svm.core.stack.StackOverflowCheck; +import com.oracle.svm.core.thread.VMThreads.OSThreadHandle; import com.oracle.svm.core.thread.VMThreads.StatusSupport; import com.oracle.svm.core.threadlocal.FastThreadLocal; import com.oracle.svm.core.threadlocal.FastThreadLocalFactory; @@ -128,6 +131,8 @@ public static PlatformThreads singleton() { return ImageSingletons.lookup(PlatformThreads.class); } + protected static final CEntryPointLiteral threadStartRoutine = CEntryPointLiteral.create(PlatformThreads.class, "threadStartRoutine", ThreadStartData.class); + /** The platform {@link java.lang.Thread} for the {@link IsolateThread}. */ static final FastThreadLocalObject currentThread = FastThreadLocalFactory.createObject(Thread.class, "PlatformThreads.currentThread").setMaxOffset(FastThreadLocal.BYTE_OFFSET); @@ -545,7 +550,7 @@ public void setUnmanagedThreadLocalValue(ThreadLocalKey key, WordBase value) { @SuppressWarnings("unused") @Uninterruptible(reason = "Called from uninterruptible code.", mayBeInlined = true) public void closeOSThreadHandle(OSThreadHandle threadHandle) { - throw VMError.shouldNotReachHere("Shouldn't call PlatformThreads.closeOSThreadHandle directly."); + /* On most platforms, OS thread handles don't need to be closed. */ } static final Method FORK_JOIN_POOL_TRY_TERMINATE_METHOD; @@ -768,6 +773,16 @@ void startThread(Thread thread, long stackSize) { */ protected abstract boolean doStartThread(Thread thread, long stackSize); + @CEntryPoint(include = CEntryPoint.NotIncludedAutomatically.class, publishAs = CEntryPoint.Publish.NotPublished) + @CEntryPointOptions(prologue = ThreadStartRoutinePrologue.class, epilogue = CEntryPointSetup.LeaveDetachThreadEpilogue.class) + protected static WordBase threadStartRoutine(ThreadStartData data) { + ObjectHandle threadHandle = data.getThreadHandle(); + freeStartData(data); + + threadStartRoutine(threadHandle); + return WordFactory.nullPointer(); + } + @SuppressFBWarnings(value = "Ru", justification = "We really want to call Thread.run and not Thread.start because we are in the low-level thread start routine") protected static void threadStartRoutine(ObjectHandle threadHandle) { Thread thread = ObjectHandles.getGlobal().get(threadHandle); @@ -1213,10 +1228,6 @@ static void enter(ThreadStartData data) { } } - @RawStructure - public interface OSThreadHandle extends PointerBase { - } - public interface ThreadLocalKey extends ComparableWord { } } diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/thread/VMThreads.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/thread/VMThreads.java index 6606fc0f7c62..44520a9fc8d1 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/thread/VMThreads.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/thread/VMThreads.java @@ -362,9 +362,11 @@ public void detachThread(IsolateThread thread) { assert thread.equal(CurrentIsolate.getCurrentThread()) : "Cannot detach different thread with this method"; // read thread local data (can't be accessed further below as the IsolateThread is freed) + OSThreadHandle threadHandle = OSThreadHandleTL.get(thread); OSThreadHandle nextOsThreadToCleanup = WordFactory.nullPointer(); - if (wasStartedByCurrentIsolate(thread)) { - nextOsThreadToCleanup = OSThreadHandleTL.get(thread); + boolean wasStartedByCurrentIsolate = wasStartedByCurrentIsolate(thread); + if (wasStartedByCurrentIsolate) { + nextOsThreadToCleanup = threadHandle; } threadExit(thread); @@ -401,6 +403,10 @@ public void detachThread(IsolateThread thread) { THREAD_MUTEX.unlockNoTransitionUnspecifiedOwner(); } + if (!wasStartedByCurrentIsolate) { + /* If a thread was attached, we need to free its thread handle. */ + PlatformThreads.singleton().closeOSThreadHandle(threadHandle); + } cleanupExitedOsThread(threadToCleanup); } From c5865f615e4b1a6e6b05c22c418cd6afaaf7f349 Mon Sep 17 00:00:00 2001 From: Sacha Coppey Date: Fri, 19 Jan 2024 13:30:16 +0100 Subject: [PATCH 543/593] Exclude option fields when include all fields --- .../src/com/oracle/svm/hosted/SVMHost.java | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/SVMHost.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/SVMHost.java index 5a1148b2696a..b4ffec34a7fb 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/SVMHost.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/SVMHost.java @@ -135,6 +135,7 @@ import jdk.graal.compiler.nodes.java.AccessFieldNode; import jdk.graal.compiler.nodes.java.AccessMonitorNode; import jdk.graal.compiler.options.Option; +import jdk.graal.compiler.options.OptionKey; import jdk.graal.compiler.options.OptionValues; import jdk.graal.compiler.phases.OptimisticOptimizations; import jdk.graal.compiler.phases.common.BoxNodeIdentityPhase; @@ -829,6 +830,10 @@ public boolean isFieldIncluded(BigBang bb, Field field) { if (NativeImageGenerator.checkName(field.getType().getName() + "." + field.getName()) != null) { return false; } + /* Options should not be in the image */ + if (OptionKey.class.isAssignableFrom(field.getType())) { + return false; + } /* Fields from this package should not be in the image */ if (field.getDeclaringClass().getName().startsWith("jdk.graal.compiler")) { return false; From 317f65d2b90e2a7170a9e74fef131eb49a05823d Mon Sep 17 00:00:00 2001 From: Fengyun Liu Date: Wed, 17 Jan 2024 14:11:49 +0100 Subject: [PATCH 544/593] Enable renaissance dotty --- java-benchmarks/mx.java-benchmarks/mx_java_benchmarks.py | 1 - substratevm/mx.substratevm/mx_substratevm_benchmark.py | 7 +++---- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/java-benchmarks/mx.java-benchmarks/mx_java_benchmarks.py b/java-benchmarks/mx.java-benchmarks/mx_java_benchmarks.py index 40d5e229eb59..45a30f22e366 100644 --- a/java-benchmarks/mx.java-benchmarks/mx_java_benchmarks.py +++ b/java-benchmarks/mx.java-benchmarks/mx_java_benchmarks.py @@ -1962,7 +1962,6 @@ def renaissanceIterations(self): del benchmarks["movie-lens"] del benchmarks["naive-bayes"] del benchmarks["page-rank"] - del benchmarks["dotty"] del benchmarks["neo4j-analytics"] return benchmarks diff --git a/substratevm/mx.substratevm/mx_substratevm_benchmark.py b/substratevm/mx.substratevm/mx_substratevm_benchmark.py index b42982dca4f8..a9c61de525bb 100644 --- a/substratevm/mx.substratevm/mx_substratevm_benchmark.py +++ b/substratevm/mx.substratevm/mx_substratevm_benchmark.py @@ -35,7 +35,6 @@ import mx_benchmark import mx_java_benchmarks import mx_sdk_benchmark -import mx_sdk_vm_impl _suite = mx.suite("substratevm") _successful_stage_pattern = re.compile(r'Successfully finished the last specified stage:.*$', re.MULTILINE) @@ -115,9 +114,9 @@ def list_jars(path): force_buildtime_init_slf4j_1_7_73, force_runtime_init_netty_4_1_72 ], - 'dotty' : mx_sdk_vm_impl.svm_experimental_options([ - '-H:+AllowJRTFileSystem' - ]) + 'dotty' : [ + '-H:+AllowJRTFileSystem' # Don't wrap the option with `mx_sdk_vm_impl.svm_experimental_options`, as all args are wrapped already. + ] } class RenaissanceNativeImageBenchmarkSuite(mx_java_benchmarks.RenaissanceBenchmarkSuite, mx_sdk_benchmark.NativeImageBenchmarkMixin): #pylint: disable=too-many-ancestors From f5611ab65c8591e5d0d588cae70209ec0706ac8d Mon Sep 17 00:00:00 2001 From: Codrut Stancu Date: Fri, 19 Jan 2024 15:00:42 +0100 Subject: [PATCH 545/593] Remove unused MetaAcess parameter. --- .../runtimecompilation/RuntimeCompiledMethodSupport.java | 2 +- .../svm/hosted/ameta/AnalysisConstantReflectionProvider.java | 4 ++-- .../src/com/oracle/svm/hosted/heap/SVMImageHeapScanner.java | 2 +- .../svm/hosted/meta/HostedConstantReflectionProvider.java | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/substratevm/src/com.oracle.svm.graal/src/com/oracle/svm/graal/hosted/runtimecompilation/RuntimeCompiledMethodSupport.java b/substratevm/src/com.oracle.svm.graal/src/com/oracle/svm/graal/hosted/runtimecompilation/RuntimeCompiledMethodSupport.java index 954cdc5616b8..a5a5749e3788 100644 --- a/substratevm/src/com.oracle.svm.graal/src/com/oracle/svm/graal/hosted/runtimecompilation/RuntimeCompiledMethodSupport.java +++ b/substratevm/src/com.oracle.svm.graal/src/com/oracle/svm/graal/hosted/runtimecompilation/RuntimeCompiledMethodSupport.java @@ -334,7 +334,7 @@ public JavaConstant readFieldValue(ResolvedJavaField field, JavaConstant receive * We cannot fold simulated values during initial before-analysis graph creation; * however, this runs after analysis has completed. */ - return readValue(metaAccess, (AnalysisField) field, receiver, true); + return readValue((AnalysisField) field, receiver, true); } } diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/ameta/AnalysisConstantReflectionProvider.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/ameta/AnalysisConstantReflectionProvider.java index 738db3bd4abb..ff34ef1ab1cd 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/ameta/AnalysisConstantReflectionProvider.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/ameta/AnalysisConstantReflectionProvider.java @@ -183,10 +183,10 @@ public void forEachArrayElement(JavaConstant array, ObjIntConsumer @Override public JavaConstant readFieldValue(ResolvedJavaField field, JavaConstant receiver) { - return readValue(metaAccess, (AnalysisField) field, receiver, false); + return readValue((AnalysisField) field, receiver, false); } - public JavaConstant readValue(UniverseMetaAccess suppliedMetaAccess, AnalysisField field, JavaConstant receiver, boolean returnSimulatedValues) { + public JavaConstant readValue(AnalysisField field, JavaConstant receiver, boolean returnSimulatedValues) { if (!field.isStatic()) { if (receiver.isNull() || !field.getDeclaringClass().isAssignableFrom(((TypedConstant) receiver).getType(metaAccess))) { /* diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/heap/SVMImageHeapScanner.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/heap/SVMImageHeapScanner.java index 2ca95e78ecd7..9145cd1689d6 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/heap/SVMImageHeapScanner.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/heap/SVMImageHeapScanner.java @@ -125,7 +125,7 @@ public boolean isValueAvailable(AnalysisField field) { @Override public JavaConstant readStaticFieldValue(AnalysisField field) { AnalysisConstantReflectionProvider aConstantReflection = (AnalysisConstantReflectionProvider) this.constantReflection; - JavaConstant constant = aConstantReflection.readValue(metaAccess, field, null, true); + JavaConstant constant = aConstantReflection.readValue(field, null, true); if (constant instanceof DirectSubstrateObjectConstant) { /* * The "late initialization" doesn't work with heap snapshots because the wrong value diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/meta/HostedConstantReflectionProvider.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/meta/HostedConstantReflectionProvider.java index c95c53e795b7..76fa3d0cd378 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/meta/HostedConstantReflectionProvider.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/meta/HostedConstantReflectionProvider.java @@ -107,7 +107,7 @@ public void forEachArrayElement(JavaConstant array, ObjIntConsumer public JavaConstant readFieldValue(ResolvedJavaField field, JavaConstant receiver) { var hField = (HostedField) field; assert checkHub(receiver) : "Receiver " + receiver + " of field " + hField + " read should not be java.lang.Class. Expecting to see DynamicHub here."; - return aConstantReflection.readValue(hMetaAccess, hField.getWrapped(), receiver, true); + return aConstantReflection.readValue(hField.getWrapped(), receiver, true); } public AnalysisConstantReflectionProvider getWrappedConstantReflection() { From 7a3c0353b4dabef174bb8eea6eab6f2ca001305a Mon Sep 17 00:00:00 2001 From: Tomas Zezula Date: Fri, 19 Jan 2024 15:53:53 +0100 Subject: [PATCH 546/593] [GR-51360] Module jdk.jfr not found, required by org.graalvm.polyglot. --- sdk/mx.sdk/suite.py | 6 ------ truffle/mx.truffle/suite.py | 1 + .../oracle/truffle/runtime/jfr/impl/ProviderImpl.java | 10 +++++++++- 3 files changed, 10 insertions(+), 7 deletions(-) diff --git a/sdk/mx.sdk/suite.py b/sdk/mx.sdk/suite.py index 5ac4a6ba3323..a80151f14fca 100644 --- a/sdk/mx.sdk/suite.py +++ b/sdk/mx.sdk/suite.py @@ -739,12 +739,6 @@ class UniversalDetector { "org.graalvm.word", "org.graalvm.nativeimage", "org.graalvm.collections", - # needed for dynamically loading Truffle - "java.sql", - "java.management", - "jdk.unsupported", - "jdk.management", - "jdk.jfr", ], "exports" : [ "org.graalvm.home", diff --git a/truffle/mx.truffle/suite.py b/truffle/mx.truffle/suite.py index 9e71e6230976..d1a4fa9629d8 100644 --- a/truffle/mx.truffle/suite.py +++ b/truffle/mx.truffle/suite.py @@ -1441,6 +1441,7 @@ "java.logging", "java.management", "static jdk.internal.vm.ci", # JVMCI module is not on the boot layer if not enabled + "static jdk.jfr", # JFR is not included in the J9 JVM ], "exports" : [ # Qualified exports diff --git a/truffle/src/com.oracle.truffle.runtime/src/com/oracle/truffle/runtime/jfr/impl/ProviderImpl.java b/truffle/src/com.oracle.truffle.runtime/src/com/oracle/truffle/runtime/jfr/impl/ProviderImpl.java index 4a34e780bf47..aff3c86bc61b 100644 --- a/truffle/src/com.oracle.truffle.runtime/src/com/oracle/truffle/runtime/jfr/impl/ProviderImpl.java +++ b/truffle/src/com.oracle.truffle.runtime/src/com/oracle/truffle/runtime/jfr/impl/ProviderImpl.java @@ -47,6 +47,14 @@ public final class ProviderImpl implements EventFactory.Provider { @Override public EventFactory getEventFactory() { - return FlightRecorder.isAvailable() ? new EventFactoryImpl() : null; + return hasJFRModule() && supportsJFR() ? new EventFactoryImpl() : null; + } + + private static boolean hasJFRModule() { + return ModuleLayer.boot().findModule("jdk.jfr").isPresent(); + } + + private static boolean supportsJFR() { + return FlightRecorder.isAvailable(); } } From f1eb792cc9cc4651fa76e2e6f8d276a19489e8a9 Mon Sep 17 00:00:00 2001 From: Peter Hofer Date: Mon, 15 Jan 2024 17:13:36 +0100 Subject: [PATCH 547/593] Eliminate (non-chunk) alignment within the image heap. --- .../genscavenge/ChunkedImageHeapLayouter.java | 45 +++----------- .../ChunkedImageHeapPartition.java | 21 ++----- .../posix/linux/LinuxImageHeapProvider.java | 59 +++++++++++-------- .../os/AbstractCommittedMemoryProvider.java | 8 ++- .../os/AbstractCopyingImageHeapProvider.java | 7 +-- .../core/os/AbstractImageHeapProvider.java | 3 + 6 files changed, 56 insertions(+), 87 deletions(-) diff --git a/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/ChunkedImageHeapLayouter.java b/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/ChunkedImageHeapLayouter.java index 62e31ff27342..9f4c5b4c8968 100644 --- a/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/ChunkedImageHeapLayouter.java +++ b/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/ChunkedImageHeapLayouter.java @@ -55,10 +55,7 @@ public class ChunkedImageHeapLayouter implements ImageHeapLayouter { * image heap during image startup, and it means that less of the image heap has to be * copied-on-write if the image heap is relocated in a new process. *

      - * A relocated reference is read-only once relocated, e.g., at runtime. The read-only relocation - * partition does not exist as a separate partition in the generated image. Instead, the - * read-only reference partition is resized to include the read-only relocation partition as - * well. + * A relocated reference is read-only once relocated, e.g., at runtime. */ private static final int READ_ONLY_RELOCATABLE = READ_ONLY_REGULAR + 1; /** A partition holding writable objects. */ @@ -81,12 +78,13 @@ public class ChunkedImageHeapLayouter implements ImageHeapLayouter { /** @param startOffset Offset relative to the heap base. */ @SuppressWarnings("this-escape") public ChunkedImageHeapLayouter(ImageHeapInfo heapInfo, long startOffset) { + int alignment = ConfigurationValues.getObjectLayout().getAlignment(); this.partitions = new ChunkedImageHeapPartition[PARTITION_COUNT]; - this.partitions[READ_ONLY_REGULAR] = new ChunkedImageHeapPartition("readOnly", false, false); - this.partitions[READ_ONLY_RELOCATABLE] = new ChunkedImageHeapPartition("readOnlyRelocatable", false, false); - this.partitions[WRITABLE_REGULAR] = new ChunkedImageHeapPartition("writable", true, false); - this.partitions[WRITABLE_HUGE] = new ChunkedImageHeapPartition("writableHuge", true, true); - this.partitions[READ_ONLY_HUGE] = new ChunkedImageHeapPartition("readOnlyHuge", false, true); + this.partitions[READ_ONLY_REGULAR] = new ChunkedImageHeapPartition("readOnly", false, false, alignment, alignment); + this.partitions[READ_ONLY_RELOCATABLE] = new ChunkedImageHeapPartition("readOnlyRelocatable", false, false, alignment, alignment); + this.partitions[WRITABLE_REGULAR] = new ChunkedImageHeapPartition("writable", true, false, alignment, alignment); + this.partitions[WRITABLE_HUGE] = new ChunkedImageHeapPartition("writableHuge", true, true, alignment, alignment); + this.partitions[READ_ONLY_HUGE] = new ChunkedImageHeapPartition("readOnlyHuge", false, true, alignment, alignment); this.heapInfo = heapInfo; this.startOffset = startOffset; @@ -104,10 +102,6 @@ public ChunkedImageHeapPartition[] getPartitions() { return partitions; } - private ChunkedImageHeapPartition getLastPartition() { - return partitions[PARTITION_COUNT - 1]; - } - @Override public void assignObjectToPartition(ImageHeapObject info, boolean immutable, boolean references, boolean relocatable) { ChunkedImageHeapPartition partition = choosePartition(info, immutable, relocatable); @@ -140,37 +134,12 @@ public ImageHeapLayoutInfo layout(ImageHeap imageHeap, int pageSize) { int objectAlignment = ConfigurationValues.getObjectLayout().getAlignment(); assert pageSize % objectAlignment == 0 : "Page size does not match object alignment"; - for (ChunkedImageHeapPartition partition : getPartitions()) { - int startAlignment = objectAlignment; - int endAlignment = objectAlignment; - if (partition == getReadOnlyRelocatable()) { - startAlignment = pageSize; - endAlignment = pageSize; - } else if (partition == getWritableRegular()) { - startAlignment = pageSize; - } else if (partition == getWritableHuge()) { - endAlignment = pageSize; - } - - /* Make sure the image heap size is a multiple of the page size. */ - if (partition == getLastPartition()) { - endAlignment = pageSize; - } - - partition.setStartAlignment(startAlignment); - partition.setEndAlignment(endAlignment); - } - ImageHeapLayoutInfo layoutInfo = doLayout(imageHeap); for (ChunkedImageHeapPartition partition : getPartitions()) { assert partition.getStartOffset() % partition.getStartAlignment() == 0 : partition; assert (partition.getStartOffset() + partition.getSize()) % partition.getEndAlignment() == 0 : partition; } - - assert layoutInfo.getReadOnlyRelocatableOffset() % pageSize == 0 && layoutInfo.getReadOnlyRelocatableSize() % pageSize == 0 : layoutInfo; - assert layoutInfo.getWritableOffset() % pageSize == 0 && layoutInfo.getWritableSize() % pageSize == 0 : layoutInfo; - return layoutInfo; } diff --git a/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/ChunkedImageHeapPartition.java b/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/ChunkedImageHeapPartition.java index 64ab07defc97..93ba44499e1b 100644 --- a/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/ChunkedImageHeapPartition.java +++ b/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/ChunkedImageHeapPartition.java @@ -49,6 +49,8 @@ public class ChunkedImageHeapPartition implements ImageHeapPartition { private final String name; private final boolean writable; private final boolean hugeObjects; + private final int startAlignment; + private final int endAlignment; private final int minimumObjectSize; private final List objects = new ArrayList<>(); @@ -58,13 +60,12 @@ public class ChunkedImageHeapPartition implements ImageHeapPartition { long startOffset = -1; long endOffset = -1; - private int startAlignment = -1; - private int endAlignment = -1; - - ChunkedImageHeapPartition(String name, boolean writable, boolean hugeObjects) { + ChunkedImageHeapPartition(String name, boolean writable, boolean hugeObjects, int startAlignment, int endAlignment) { this.name = name; this.writable = writable; this.hugeObjects = hugeObjects; + this.startAlignment = startAlignment; + this.endAlignment = endAlignment; /* Cache to prevent frequent lookups of the object layout from ImageSingletons. */ this.minimumObjectSize = ConfigurationValues.getObjectLayout().getMinImageHeapObjectSize(); @@ -196,25 +197,13 @@ boolean usesUnalignedObjects() { } final int getStartAlignment() { - assert startAlignment >= 0 : "Start alignment not yet assigned"; return startAlignment; } - void setStartAlignment(int alignment) { - assert this.startAlignment == -1 : "Start alignment already assigned: " + this.startAlignment; - this.startAlignment = alignment; - } - final int getEndAlignment() { - assert endAlignment >= 0 : "End alignment not yet assigned"; return endAlignment; } - void setEndAlignment(int endAlignment) { - assert this.endAlignment == -1 : "End alignment already assigned: " + this.endAlignment; - this.endAlignment = endAlignment; - } - @Override public long getStartOffset() { assert startOffset >= 0 : "Start offset not yet set"; diff --git a/substratevm/src/com.oracle.svm.core.posix/src/com/oracle/svm/core/posix/linux/LinuxImageHeapProvider.java b/substratevm/src/com.oracle.svm.core.posix/src/com/oracle/svm/core/posix/linux/LinuxImageHeapProvider.java index 70a546c3339a..9c076d5daef7 100644 --- a/substratevm/src/com.oracle.svm.core.posix/src/com/oracle/svm/core/posix/linux/LinuxImageHeapProvider.java +++ b/substratevm/src/com.oracle.svm.core.posix/src/com/oracle/svm/core/posix/linux/LinuxImageHeapProvider.java @@ -32,7 +32,7 @@ import static com.oracle.svm.core.Isolates.IMAGE_HEAP_WRITABLE_BEGIN; import static com.oracle.svm.core.Isolates.IMAGE_HEAP_WRITABLE_END; import static com.oracle.svm.core.posix.linux.ProcFSSupport.findMapping; -import static com.oracle.svm.core.util.UnsignedUtils.isAMultiple; +import static com.oracle.svm.core.util.PointerUtils.roundDown; import static com.oracle.svm.core.util.UnsignedUtils.roundUp; import static org.graalvm.word.WordFactory.signed; @@ -63,6 +63,8 @@ import com.oracle.svm.core.posix.PosixUtils; import com.oracle.svm.core.posix.headers.Fcntl; import com.oracle.svm.core.posix.headers.Unistd; +import com.oracle.svm.core.util.PointerUtils; +import com.oracle.svm.core.util.UnsignedUtils; import com.oracle.svm.core.util.VMError; import jdk.graal.compiler.word.Word; @@ -198,7 +200,7 @@ private int initializeImageHeap(Pointer imageHeap, UnsignedWord reservedSize, Wo * heap must be in pristine condition for that). */ if (fd.equal(CANNOT_OPEN_FD)) { - return initializeImageHeapByCopying(imageHeap, heapBeginSym, heapEndSym, heapWritableSym, heapWritableEndSym, imageHeapSize); + return initializeImageHeapByCopying(imageHeap, imageHeapSize, pageSize, heapBeginSym, heapWritableSym, heapWritableEndSym); } // Create memory mappings from the image file. @@ -212,30 +214,39 @@ private int initializeImageHeap(Pointer imageHeap, UnsignedWord reservedSize, Wo ComparableWord relocatedValue = heapAnyRelocPointer.readWord(0); ComparableWord mappedValue = imageHeap.readWord(heapAnyRelocPointer.subtract(heapBeginSym)); if (relocatedValue.notEqual(mappedValue)) { + Pointer linkedRelocsBoundary = roundDown(heapRelocsSym, pageSize); + UnsignedWord relocsAlignedSize = roundUp(heapRelocsEndSym.subtract(linkedRelocsBoundary), pageSize); + Pointer relocsBoundary = imageHeap.add(linkedRelocsBoundary.subtract(heapBeginSym)); /* * Addresses were relocated by the dynamic linker, so copy them, but first remap the - * pages as anonymous memory to avoid swapping in part of the image from disk. + * pages to avoid swapping them in from disk. We need to round to page boundaries, + * and so we copy some extra data. + * + * NOTE: while objects with relocations are considered read-only, some of them might + * be part of a chunk with writable objects, in which case the chunk header must + * also be writable, and all the chunk's pages will be unprotected below. */ - Pointer relocsBegin = imageHeap.add(heapRelocsSym.subtract(heapBeginSym)); - UnsignedWord relocsSize = heapRelocsEndSym.subtract(heapRelocsSym); - if (!isAMultiple(relocsSize, pageSize)) { + Pointer committedRelocsBegin = VirtualMemoryProvider.get().commit(relocsBoundary, relocsAlignedSize, Access.READ | Access.WRITE); + if (committedRelocsBegin.isNull() || committedRelocsBegin != relocsBoundary) { return CEntryPointErrors.PROTECT_HEAP_FAILED; } - Pointer committedRelocsBegin = VirtualMemoryProvider.get().commit(relocsBegin, relocsSize, Access.READ | Access.WRITE); - if (committedRelocsBegin.isNull() || committedRelocsBegin != relocsBegin) { - return CEntryPointErrors.PROTECT_HEAP_FAILED; - } - LibC.memcpy(relocsBegin, heapRelocsSym, relocsSize); - if (VirtualMemoryProvider.get().protect(relocsBegin, relocsSize, Access.READ) != 0) { + LibC.memcpy(relocsBoundary, linkedRelocsBoundary, relocsAlignedSize); + if (VirtualMemoryProvider.get().protect(relocsBoundary, relocsAlignedSize, Access.READ) != 0) { return CEntryPointErrors.PROTECT_HEAP_FAILED; } } } - // Unprotect writable pages. + /* + * Unprotect writable pages. + * + * The last page might be shared with the subsequent read-only huge objects partition, in + * which case we make some of its data writable, which we consider acceptable. + */ Pointer writableBegin = imageHeap.add(heapWritableSym.subtract(heapBeginSym)); UnsignedWord writableSize = heapWritableEndSym.subtract(heapWritableSym); - if (VirtualMemoryProvider.get().protect(writableBegin, writableSize, Access.READ | Access.WRITE) != 0) { + UnsignedWord alignedWritableSize = roundUp(writableSize, pageSize); + if (VirtualMemoryProvider.get().protect(writableBegin, alignedWritableSize, Access.READ | Access.WRITE) != 0) { return CEntryPointErrors.PROTECT_HEAP_FAILED; } @@ -243,19 +254,22 @@ private int initializeImageHeap(Pointer imageHeap, UnsignedWord reservedSize, Wo } @Uninterruptible(reason = "Called during isolate initialization.") - private static int initializeImageHeapByCopying(Pointer imageHeap, Word heapBeginSym, Word heapEndSym, Word heapWritableSym, Word heapWritableEndSym, UnsignedWord imageHeapSize) { + private static int initializeImageHeapByCopying(Pointer imageHeap, UnsignedWord imageHeapSize, UnsignedWord pageSize, Word heapBeginSym, Word heapWritableSym, Word heapWritableEndSym) { Pointer committedBegin = VirtualMemoryProvider.get().commit(imageHeap, imageHeapSize, Access.READ | Access.WRITE); if (committedBegin.isNull()) { return CEntryPointErrors.MAP_HEAP_FAILED; } LibC.memcpy(imageHeap, heapBeginSym, imageHeapSize); - Word readOnlyBytesAtBegin = heapWritableSym.subtract(heapBeginSym); + UnsignedWord readOnlyBytesAtBegin = heapWritableSym.subtract(heapBeginSym); + readOnlyBytesAtBegin = UnsignedUtils.roundDown(readOnlyBytesAtBegin, pageSize); if (readOnlyBytesAtBegin.aboveThan(0) && VirtualMemoryProvider.get().protect(imageHeap, readOnlyBytesAtBegin, Access.READ) != 0) { return CEntryPointErrors.PROTECT_HEAP_FAILED; } Pointer writableEnd = imageHeap.add(heapWritableEndSym.subtract(heapBeginSym)); - Word readOnlyBytesAtEnd = heapEndSym.subtract(heapWritableEndSym); + writableEnd = PointerUtils.roundUp(writableEnd, pageSize); + UnsignedWord readOnlyBytesAtEnd = imageHeap.add(imageHeapSize).subtract(writableEnd); + readOnlyBytesAtEnd = roundUp(readOnlyBytesAtEnd, pageSize); if (readOnlyBytesAtEnd.aboveThan(0) && VirtualMemoryProvider.get().protect(writableEnd, readOnlyBytesAtEnd, Access.READ) != 0) { return CEntryPointErrors.PROTECT_HEAP_FAILED; } @@ -276,12 +290,9 @@ private static int openImageFile(Word heapBeginSym, Pointer magicAddress, WordPo final int bufferSize = MAX_PATHLEN; CCharPointer buffer = StackValue.get(bufferSize); - // The relocatables partition might stretch over two adjacent mappings due to permission - // differences, so only locate the mapping for the first page of relocatables - UnsignedWord pageSize = VirtualMemoryProvider.get().getGranularity(); WordPointer imageHeapMappingStart = StackValue.get(WordPointer.class); WordPointer imageHeapMappingFileOffset = StackValue.get(WordPointer.class); - boolean found = findMapping(mapfd, buffer, bufferSize, heapBeginSym, heapBeginSym.add(pageSize), imageHeapMappingStart, imageHeapMappingFileOffset, true); + boolean found = findMapping(mapfd, buffer, bufferSize, heapBeginSym, heapBeginSym.add(1), imageHeapMappingStart, imageHeapMappingFileOffset, true); if (!found) { Unistd.NoTransitions.close(mapfd); return failfd; @@ -342,13 +353,11 @@ public int freeImageHeap(PointerBase heapBase) { } VMError.guarantee(heapBase.notEqual(IMAGE_HEAP_BEGIN.get()), "reusing the image heap is no longer supported"); - UnsignedWord totalAddressSpaceSize = getTotalRequiredAddressSpaceSize(); Pointer addressSpaceStart = (Pointer) heapBase; if (DynamicMethodAddressResolutionHeapSupport.isEnabled()) { - UnsignedWord preHeapRequiredBytes = getPreHeapAlignedSizeForDynamicMethodAddressResolver(); - addressSpaceStart = addressSpaceStart.subtract(preHeapRequiredBytes); + addressSpaceStart = addressSpaceStart.subtract(getPreHeapAlignedSizeForDynamicMethodAddressResolver()); } - if (VirtualMemoryProvider.get().free(addressSpaceStart, totalAddressSpaceSize) != 0) { + if (VirtualMemoryProvider.get().free(addressSpaceStart, getTotalRequiredAddressSpaceSize()) != 0) { return CEntryPointErrors.FREE_IMAGE_HEAP_FAILED; } return CEntryPointErrors.NO_ERROR; diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/os/AbstractCommittedMemoryProvider.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/os/AbstractCommittedMemoryProvider.java index fcbdbdf643d5..df23a3d33aef 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/os/AbstractCommittedMemoryProvider.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/os/AbstractCommittedMemoryProvider.java @@ -43,6 +43,7 @@ import com.oracle.svm.core.code.RuntimeCodeCache; import com.oracle.svm.core.config.ConfigurationValues; import com.oracle.svm.core.heap.Heap; +import com.oracle.svm.core.util.PointerUtils; import com.oracle.svm.core.util.UnsignedUtils; import com.oracle.svm.core.util.VMError; @@ -75,9 +76,10 @@ protected static int protectSingleIsolateImageHeap() { if (VirtualMemoryProvider.get().protect(heapBegin, heapSize, VirtualMemoryProvider.Access.READ) != 0) { return CEntryPointErrors.PROTECT_HEAP_FAILED; } - Pointer writableBegin = IMAGE_HEAP_WRITABLE_BEGIN.get(); - UnsignedWord writableSize = IMAGE_HEAP_WRITABLE_END.get().subtract(writableBegin); - if (VirtualMemoryProvider.get().protect(writableBegin, writableSize, VirtualMemoryProvider.Access.READ | VirtualMemoryProvider.Access.WRITE) != 0) { + UnsignedWord pageSize = VirtualMemoryProvider.get().getGranularity(); + Pointer writableBoundary = PointerUtils.roundDown(IMAGE_HEAP_WRITABLE_BEGIN.get(), pageSize); + UnsignedWord writableSize = IMAGE_HEAP_WRITABLE_END.get().subtract(writableBoundary); + if (VirtualMemoryProvider.get().protect(writableBoundary, writableSize, VirtualMemoryProvider.Access.READ | VirtualMemoryProvider.Access.WRITE) != 0) { return CEntryPointErrors.PROTECT_HEAP_FAILED; } } diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/os/AbstractCopyingImageHeapProvider.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/os/AbstractCopyingImageHeapProvider.java index b4842d5d4ec0..a5afcd749809 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/os/AbstractCopyingImageHeapProvider.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/os/AbstractCopyingImageHeapProvider.java @@ -146,15 +146,12 @@ protected int commitAndCopyMemory(Pointer loadedImageHeap, UnsignedWord imageHea @Uninterruptible(reason = "Called during isolate tear-down.") public int freeImageHeap(PointerBase heapBase) { if (heapBase.isNonNull()) { - UnsignedWord totalAddressSpaceSize = getImageHeapAddressSpaceSize(); Pointer addressSpaceStart = (Pointer) heapBase; if (DynamicMethodAddressResolutionHeapSupport.isEnabled()) { - UnsignedWord preHeapRequiredBytes = getPreHeapAlignedSizeForDynamicMethodAddressResolver(); - totalAddressSpaceSize = totalAddressSpaceSize.add(preHeapRequiredBytes); - addressSpaceStart = addressSpaceStart.subtract(preHeapRequiredBytes); + addressSpaceStart = addressSpaceStart.subtract(getPreHeapAlignedSizeForDynamicMethodAddressResolver()); } - if (VirtualMemoryProvider.get().free(addressSpaceStart, totalAddressSpaceSize) != 0) { + if (VirtualMemoryProvider.get().free(addressSpaceStart, getTotalRequiredAddressSpaceSize()) != 0) { return CEntryPointErrors.FREE_IMAGE_HEAP_FAILED; } } diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/os/AbstractImageHeapProvider.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/os/AbstractImageHeapProvider.java index dbfcc8031032..d8fd7bcc5eea 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/os/AbstractImageHeapProvider.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/os/AbstractImageHeapProvider.java @@ -36,6 +36,7 @@ import com.oracle.svm.core.Uninterruptible; import com.oracle.svm.core.code.DynamicMethodAddressResolutionHeapSupport; import com.oracle.svm.core.heap.Heap; +import com.oracle.svm.core.util.UnsignedUtils; import jdk.graal.compiler.word.Word; @@ -51,10 +52,12 @@ protected UnsignedWord getTotalRequiredAddressSpaceSize() { @Uninterruptible(reason = "Called from uninterruptible code.", mayBeInlined = true) protected UnsignedWord getImageHeapAddressSpaceSize() { + UnsignedWord pageSize = VirtualMemoryProvider.get().getGranularity(); int imageHeapOffset = Heap.getHeap().getImageHeapOffsetInAddressSpace(); assert imageHeapOffset >= 0; UnsignedWord size = WordFactory.unsigned(imageHeapOffset); size = size.add(getImageHeapSizeInFile(IMAGE_HEAP_BEGIN.get(), IMAGE_HEAP_END.get())); + size = UnsignedUtils.roundUp(size, pageSize); return size; } From ebc30e9789e6791f0eaf7e4020846f7b466d1bed Mon Sep 17 00:00:00 2001 From: Peter Hofer Date: Tue, 16 Jan 2024 14:16:32 +0100 Subject: [PATCH 548/593] Skip unaligned chunks when gathering Class objects. --- .../com/oracle/svm/core/genscavenge/HeapImpl.java | 2 +- .../svm/core/genscavenge/ImageHeapWalker.java | 13 +++++++++---- .../src/com/oracle/svm/core/MemoryWalker.java | 2 ++ 3 files changed, 12 insertions(+), 5 deletions(-) diff --git a/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/HeapImpl.java b/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/HeapImpl.java index a38f23320dc1..43facdf4d1d9 100644 --- a/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/HeapImpl.java +++ b/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/HeapImpl.java @@ -364,7 +364,7 @@ private static class ClassListBuilderVisitor implements MemoryWalker.ImageHeapRe @Override public boolean visitNativeImageHeapRegion(T region, MemoryWalker.NativeImageHeapRegionAccess access) { - if (!access.isWritable(region)) { + if (!access.isWritable(region) && !access.consistsOfHugeObjects(region)) { access.visitObjects(region, this); } return true; diff --git a/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/ImageHeapWalker.java b/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/ImageHeapWalker.java index adc4aca32c74..9f52bc0ee669 100644 --- a/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/ImageHeapWalker.java +++ b/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/ImageHeapWalker.java @@ -137,13 +137,13 @@ private static boolean visitObjectInline(ObjectVisitor visitor, Object currentOb abstract class MemoryWalkerAccessBase implements MemoryWalker.NativeImageHeapRegionAccess { private final String regionName; private final boolean isWritable; - private final boolean hasHugeObjects; + private final boolean consistsOfHugeObjects; @Platforms(Platform.HOSTED_ONLY.class) - MemoryWalkerAccessBase(String regionName, boolean isWritable, boolean hasHugeObjects) { + MemoryWalkerAccessBase(String regionName, boolean isWritable, boolean consistsOfHugeObjects) { this.regionName = regionName; this.isWritable = isWritable; - this.hasHugeObjects = hasHugeObjects; + this.consistsOfHugeObjects = consistsOfHugeObjects; } @Override @@ -171,10 +171,15 @@ public boolean isWritable(ImageHeapInfo region) { return isWritable; } + @Override + public boolean consistsOfHugeObjects(ImageHeapInfo region) { + return consistsOfHugeObjects; + } + @Override @AlwaysInline("GC performance") public final boolean visitObjects(ImageHeapInfo region, ObjectVisitor visitor) { - boolean alignedChunks = !hasHugeObjects; + boolean alignedChunks = !consistsOfHugeObjects; return ImageHeapWalker.walkPartitionInline(getFirstObject(region), getLastObject(region), visitor, alignedChunks); } diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/MemoryWalker.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/MemoryWalker.java index 468709b3a2c3..28ae293895ab 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/MemoryWalker.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/MemoryWalker.java @@ -48,6 +48,8 @@ public interface NativeImageHeapRegionAccess { boolean isWritable(T region); + boolean consistsOfHugeObjects(T region); + boolean visitObjects(T region, ObjectVisitor visitor); } From fbc8ed37fe5f20bb92cb720e1ac48eab3769b530 Mon Sep 17 00:00:00 2001 From: Peter Hofer Date: Thu, 18 Jan 2024 15:54:34 +0100 Subject: [PATCH 549/593] Skip read-only huge objects in verification. --- .../oracle/svm/core/genscavenge/HeapVerifier.java | 14 +++++++++++--- .../remset/CardTableBasedRememberedSet.java | 11 ++++++++++- .../core/genscavenge/remset/NoRememberedSet.java | 5 +++++ .../svm/core/genscavenge/remset/RememberedSet.java | 13 ++++++++++--- 4 files changed, 36 insertions(+), 7 deletions(-) diff --git a/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/HeapVerifier.java b/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/HeapVerifier.java index df4b460ba43c..c2073f0078f3 100644 --- a/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/HeapVerifier.java +++ b/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/HeapVerifier.java @@ -70,7 +70,7 @@ private static boolean verifyImageHeap() { boolean success = true; for (ImageHeapInfo info = HeapImpl.getFirstImageHeapInfo(); info != null; info = info.next) { success &= verifyAlignedChunks(null, info.getFirstWritableAlignedChunk()); - success &= verifyUnalignedChunks(null, info.getFirstWritableUnalignedChunk()); + success &= verifyUnalignedChunks(null, info.getFirstWritableUnalignedChunk(), info.getLastWritableUnalignedChunk()); } return success; } @@ -148,7 +148,7 @@ private static boolean verifyRememberedSets() { */ for (ImageHeapInfo info = HeapImpl.getFirstImageHeapInfo(); info != null; info = info.next) { success &= rememberedSet.verify(info.getFirstWritableAlignedChunk()); - success &= rememberedSet.verify(info.getFirstWritableUnalignedChunk()); + success &= rememberedSet.verify(info.getFirstWritableUnalignedChunk(), info.getLastWritableUnalignedChunk()); } OldGeneration oldGeneration = HeapImpl.getHeapImpl().getOldGeneration(); @@ -213,6 +213,10 @@ private static boolean verifyAlignedChunks(Space space, AlignedHeader firstAlign } private static boolean verifyUnalignedChunks(Space space, UnalignedHeader firstUnalignedHeapChunk) { + return verifyUnalignedChunks(space, firstUnalignedHeapChunk, WordFactory.nullPointer()); + } + + private static boolean verifyUnalignedChunks(Space space, UnalignedHeader firstUnalignedHeapChunk, UnalignedHeader lastUnalignedHeapChunk) { boolean success = true; UnalignedHeader uChunk = firstUnalignedHeapChunk; while (uChunk.isNonNull()) { @@ -224,8 +228,12 @@ private static boolean verifyUnalignedChunks(Space space, UnalignedHeader firstU OBJECT_VERIFIER.initialize(WordFactory.nullPointer(), uChunk); UnalignedHeapChunk.walkObjects(uChunk, OBJECT_VERIFIER); - uChunk = HeapChunk.getNext(uChunk); success &= OBJECT_VERIFIER.result; + + if (uChunk.equal(lastUnalignedHeapChunk)) { + break; + } + uChunk = HeapChunk.getNext(uChunk); } return success; } diff --git a/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/remset/CardTableBasedRememberedSet.java b/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/remset/CardTableBasedRememberedSet.java index ae7a82282459..3cdde75b7d36 100644 --- a/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/remset/CardTableBasedRememberedSet.java +++ b/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/remset/CardTableBasedRememberedSet.java @@ -26,10 +26,10 @@ import java.util.List; -import jdk.graal.compiler.nodes.gc.BarrierSet; import org.graalvm.nativeimage.Platform; import org.graalvm.nativeimage.Platforms; import org.graalvm.word.UnsignedWord; +import org.graalvm.word.WordFactory; import com.oracle.svm.core.AlwaysInline; import com.oracle.svm.core.Uninterruptible; @@ -47,6 +47,7 @@ import com.oracle.svm.core.image.ImageHeapObject; import com.oracle.svm.core.util.HostedByteBufferPointer; +import jdk.graal.compiler.nodes.gc.BarrierSet; import jdk.vm.ci.meta.MetaAccessProvider; import jdk.vm.ci.meta.ResolvedJavaType; @@ -212,10 +213,18 @@ public boolean verify(AlignedHeader firstAlignedHeapChunk) { @Override public boolean verify(UnalignedHeader firstUnalignedHeapChunk) { + return verify(firstUnalignedHeapChunk, WordFactory.nullPointer()); + } + + @Override + public boolean verify(UnalignedHeader firstUnalignedHeapChunk, UnalignedHeader lastUnalignedHeapChunk) { boolean success = true; UnalignedHeader uChunk = firstUnalignedHeapChunk; while (uChunk.isNonNull()) { success &= UnalignedChunkRememberedSet.verify(uChunk); + if (uChunk.equal(lastUnalignedHeapChunk)) { + break; + } uChunk = HeapChunk.getNext(uChunk); } return success; diff --git a/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/remset/NoRememberedSet.java b/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/remset/NoRememberedSet.java index 16b1d7f0b4bd..bb3a742ceb22 100644 --- a/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/remset/NoRememberedSet.java +++ b/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/remset/NoRememberedSet.java @@ -167,4 +167,9 @@ public boolean verify(AlignedHeader firstAlignedHeapChunk) { public boolean verify(UnalignedHeader firstUnalignedHeapChunk) { return true; } + + @Override + public boolean verify(UnalignedHeader firstUnalignedHeapChunk, UnalignedHeader lastUnalignedHeapChunk) { + return true; + } } diff --git a/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/remset/RememberedSet.java b/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/remset/RememberedSet.java index f04fb43788af..dba9d1815c13 100644 --- a/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/remset/RememberedSet.java +++ b/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/remset/RememberedSet.java @@ -26,7 +26,6 @@ import java.util.List; -import jdk.graal.compiler.api.replacements.Fold; import org.graalvm.nativeimage.ImageSingletons; import org.graalvm.nativeimage.Platform; import org.graalvm.nativeimage.Platforms; @@ -42,6 +41,8 @@ import com.oracle.svm.core.image.ImageHeapObject; import com.oracle.svm.core.util.HostedByteBufferPointer; +import jdk.graal.compiler.api.replacements.Fold; + /** * A remembered set keeps track of references between generations (from the old generation to the * young generation, or from the image heap to the runtime heap). During collections, the remembered @@ -152,12 +153,18 @@ static RememberedSet get() { void walkDirtyObjects(Space space, GreyToBlackObjectVisitor visitor, boolean clean); /** - * Verify the remembered set for an aligned chunk. + * Verify the remembered set for an aligned chunk and all its linked-list successors. */ boolean verify(AlignedHeader firstAlignedHeapChunk); /** - * Verify the remembered set for an unaligned chunk. + * Verify the remembered set for an unaligned chunk and all its linked-list successors. */ boolean verify(UnalignedHeader firstUnalignedHeapChunk); + + /** + * Verify the remembered set for an unaligned chunk and its linked-list successors up until (and + * including) another unaligned chunk. + */ + boolean verify(UnalignedHeader firstUnalignedHeapChunk, UnalignedHeader lastUnalignedHeapChunk); } From dd764a6df306fc92498420db7e6928830aea4688 Mon Sep 17 00:00:00 2001 From: Danilo Ansaloni Date: Mon, 18 Dec 2023 17:28:10 +0100 Subject: [PATCH 550/593] Port jobs to JDK-latest. --- ci/common.jsonnet | 2 ++ vm/ci/ci_common/common.jsonnet | 7 ++----- vm/ci/ci_includes/vm-native.jsonnet | 2 +- vm/ci/ci_includes/vm.jsonnet | 8 ++++---- 4 files changed, 9 insertions(+), 10 deletions(-) diff --git a/ci/common.jsonnet b/ci/common.jsonnet index 81b854e71687..6437e7ea7880 100644 --- a/ci/common.jsonnet +++ b/ci/common.jsonnet @@ -116,6 +116,8 @@ local common_json = import "../common.json"; "linux-jdk19": { packages+: { "devkit:gcc11.2.0-OL6.4+1": "==0" }}, "linux-jdk20": { packages+: { "devkit:gcc11.2.0-OL6.4+1": "==0" }}, "linux-jdk21": { packages+: { "devkit:gcc11.2.0-OL6.4+1": "==0" }}, + "linux-jdk-latest": { packages+: { "devkit:gcc11.2.0-OL6.4+1": "==0" }}, + "linux-jdkLatest": self["linux-jdk-latest"], }, # Dependencies diff --git a/vm/ci/ci_common/common.jsonnet b/vm/ci/ci_common/common.jsonnet index c84478a34d35..8583007d6147 100644 --- a/vm/ci/ci_common/common.jsonnet +++ b/vm/ci/ci_common/common.jsonnet @@ -47,7 +47,6 @@ local devkits = graal_common.devkits; }, }, - common_vm_windows_jdk17: self.common_vm_windows + devkits['windows-jdk17'], common_vm_windows_jdk21: self.common_vm_windows + devkits['windows-jdk21'], common_vm_windows_jdkLatest: self.common_vm_windows + devkits['windows-jdkLatest'], @@ -192,17 +191,15 @@ local devkits = graal_common.devkits; }, vm_windows: self.common_vm_windows + graal_common.windows_server_2016_amd64, - vm_windows_jdk17: self.common_vm_windows_jdk17 + graal_common.windows_server_2016_amd64, vm_windows_jdk21: self.common_vm_windows_jdk21 + graal_common.windows_server_2016_amd64, vm_windows_jdkLatest: self.common_vm_windows_jdkLatest + graal_common.windows_server_2016_amd64, vm_windows_amd64: self.vm_windows, - vm_windows_amd64_jdk17: self.vm_windows_jdk17, vm_windows_amd64_jdk21: self.vm_windows_jdk21, vm_windows_amd64_jdkLatest: self.vm_windows_jdkLatest, vm_base(os, arch, main_target, deploy=false, bench=false, os_distro=null, jdk_hint=null): vm.default_diskspace_required(os, arch, large=deploy) - + self['vm_' + os + '_' + arch + (if (os_distro != null) then '_' + os_distro else '') + (if (jdk_hint != null) then '_jdk' + jdk_hint else '')] # examples: `self.vm_linux_amd64_ubuntu`, `self.vm_windows_amd_jdkLatest` + + self['vm_' + os + '_' + arch + (if (os_distro != null) then '_' + os_distro else '') + (if (jdk_hint != null) then '_jdk' + jdk_hint else '')] # examples: `self.vm_linux_amd64_ubuntu`, `self.vm_windows_amd64_jdkLatest` + { targets+: [main_target] + (if (deploy) then ['deploy'] else []) + (if (bench) then ['bench'] else []) } + (if (bench) then { capabilities+: ['no_frequency_scaling'] } else {}), @@ -289,7 +286,7 @@ local devkits = graal_common.devkits; else if (os == 'windows') then if (arch == 'amd64') then # Windows/AMD64 - java_deps(edition) + self.svm_common_windows_amd64("21") + self.js_windows_common + self.sulong_windows + java_deps(edition) + (if (java_version == 'latest') then self.svm_common_windows_amd64("Latest") else self.svm_common_windows_amd64(java_version)) + self.js_windows_common + self.sulong_windows else error 'Unknown windows arch: ' + arch else diff --git a/vm/ci/ci_includes/vm-native.jsonnet b/vm/ci/ci_includes/vm-native.jsonnet index b6e65a94b4a3..2599c31df717 100644 --- a/vm/ci/ci_includes/vm-native.jsonnet +++ b/vm/ci/ci_includes/vm-native.jsonnet @@ -47,7 +47,7 @@ local vm_common = import '../ci_common/common.jsonnet'; }, local builds = [ - vm.vm_java_21 + vm_common.svm_common_linux_amd64 + vm_common.sulong_linux + vm_common.graalpython_linux_amd64 + vm.custom_vm_linux + vm_common.vm_base('linux', 'amd64', 'gate') + { + vm.vm_java_Latest + vm_common.svm_common_linux_amd64 + vm_common.sulong_linux + vm_common.graalpython_linux_amd64 + vm.custom_vm_linux + vm_common.vm_base('linux', 'amd64', 'gate') + { run+: [ ['export', 'SVM_SUITE=' + vm.svm_suite], ['mx', '--dynamicimports', '$SVM_SUITE,graalpython', '--disable-polyglot', '--disable-libpolyglot', '--force-bash-launchers=lli,native-image', 'gate', '--no-warning-as-error', '--tags', 'build,python'], diff --git a/vm/ci/ci_includes/vm.jsonnet b/vm/ci/ci_includes/vm.jsonnet index 3ef2711f1f1b..e1098d37384d 100644 --- a/vm/ci/ci_includes/vm.jsonnet +++ b/vm/ci/ci_includes/vm.jsonnet @@ -99,21 +99,21 @@ local graal_common = import '../../../ci/ci_common/common.jsonnet'; }, local builds = [ - utils.add_gate_predicate(self.vm_java_21 + vm_common.vm_base('linux', 'amd64', 'gate') + { + utils.add_gate_predicate(self.vm_java_Latest + vm_common.vm_base('linux', 'amd64', 'gate') + { run: [ ['mx', 'build'], ['mx', 'unittest', '--suite', 'vm'], ], name: 'gate-vm-unittest-linux-amd64', }, ['sdk', 'truffle', 'vm']), - utils.add_gate_predicate(self.vm_java_21 + graal_common.devkits['windows-jdk21'] + vm_common.vm_base('windows', 'amd64', 'gate') + { + utils.add_gate_predicate(self.vm_java_Latest + graal_common.devkits['windows-jdkLatest'] + vm_common.vm_base('windows', 'amd64', 'gate') + { run: [ ['mx', 'build'], ['mx', 'unittest', '--suite', 'vm'], ], name: 'gate-vm-unittest-windows-amd64', }, ["sdk", "truffle", "vm"]), - self.vm_java_21 + vm_common.vm_base('linux', 'amd64', 'gate') + vm_common.sulong_linux + { + self.vm_java_Latest + vm_common.vm_base('linux', 'amd64', 'gate') + vm_common.sulong_linux + { environment+: { DYNAMIC_IMPORTS: '/tools,/substratevm,/sulong', NATIVE_IMAGES: 'polyglot', @@ -170,7 +170,7 @@ local graal_common = import '../../../ci/ci_common/common.jsonnet'; name: 'gate-vm-maven-dry-run-windows-amd64', timelimit: '1:00:00', }, - vm_common.graalvm_complete_build_deps('ce', 'windows', 'amd64', java_version='latest') + vm_common.deploy_build + vm_common.vm_base('windows', 'amd64', 'daily', deploy=true, jdk_hint='21') + vm_common.maven_deploy_base_functions.base_object('windows', 'amd64', dry_run=false, remote_mvn_repo=$.maven_deploy_repository, remote_non_mvn_repo=$.binaries_repository, local_repo='local') + { + vm_common.graalvm_complete_build_deps('ce', 'windows', 'amd64', java_version='latest') + vm_common.deploy_build + vm_common.vm_base('windows', 'amd64', 'daily', deploy=true, jdk_hint='Latest') + vm_common.maven_deploy_base_functions.base_object('windows', 'amd64', dry_run=false, remote_mvn_repo=$.maven_deploy_repository, remote_non_mvn_repo=$.binaries_repository, local_repo='local') + { name: 'daily-deploy-vm-maven-windows-amd64', timelimit: '1:00:00', notify_groups:: ['deploy'], From 3a54da8ad165cc0eb789d9428f18d36d47ca20b1 Mon Sep 17 00:00:00 2001 From: Christian Wimmer Date: Fri, 19 Jan 2024 11:32:35 -0800 Subject: [PATCH 551/593] Guarantee that the image heap contains only classes marked as instantiated --- .../src/com/oracle/svm/hosted/image/NativeImageHeap.java | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/NativeImageHeap.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/NativeImageHeap.java index 1eaccf439cf1..bdbe40a3eb03 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/NativeImageHeap.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/NativeImageHeap.java @@ -453,6 +453,15 @@ private void addObjectToImageHeap(final JavaConstant constant, boolean immutable boolean references = false; boolean relocatable = false; /* always false when !spawnIsolates() */ + if (!type.isInstantiated()) { + StringBuilder msg = new StringBuilder(); + msg.append("Image heap writing found an object whose type was not marked as instantiated by the static analysis: "); + msg.append(type.toJavaName(true)).append(" (").append(type).append(")"); + msg.append(System.lineSeparator()).append(" reachable through:").append(System.lineSeparator()); + fillReasonStack(msg, reason); + VMError.shouldNotReachHere(msg.toString()); + } + if (type.isInstanceClass()) { final HostedInstanceClass clazz = (HostedInstanceClass) type; // If the type has a monitor field, it has a reference field that is written. From 15cd067e0e0f90d397f7abb50c6ffdf561738522 Mon Sep 17 00:00:00 2001 From: Christian Wimmer Date: Fri, 19 Jan 2024 11:32:26 -0800 Subject: [PATCH 552/593] Invocation profiles are not needed for JIT compilation --- .../svm/hosted/SubstrateStrengthenGraphs.java | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/SubstrateStrengthenGraphs.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/SubstrateStrengthenGraphs.java index 8e0e1d571573..2698655b66e2 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/SubstrateStrengthenGraphs.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/SubstrateStrengthenGraphs.java @@ -29,6 +29,7 @@ import com.oracle.graal.pointsto.infrastructure.Universe; import com.oracle.graal.pointsto.meta.AnalysisType; import com.oracle.graal.pointsto.results.StrengthenGraphs; +import com.oracle.svm.common.meta.MultiMethod; import com.oracle.svm.core.SubstrateUtil; import com.oracle.svm.core.Uninterruptible; import com.oracle.svm.core.graal.nodes.InlinedInvokeArgumentsNode; @@ -114,11 +115,20 @@ protected FixedNode createUnreachable(StructuredGraph graph, CoreProviders provi @Override protected void setInvokeProfiles(Invoke invoke, JavaTypeProfile typeProfile, JavaMethodProfile methodProfile) { - ((SubstrateMethodCallTargetNode) invoke.callTarget()).setProfiles(typeProfile, methodProfile); + if (needsProfiles(invoke)) { + ((SubstrateMethodCallTargetNode) invoke.callTarget()).setProfiles(typeProfile, methodProfile); + } } protected void setInvokeProfiles(Invoke invoke, JavaTypeProfile typeProfile, JavaMethodProfile methodProfile, JavaTypeProfile staticTypeProfile) { - ((SubstrateMethodCallTargetNode) invoke.callTarget()).setProfiles(typeProfile, methodProfile, staticTypeProfile); + if (needsProfiles(invoke)) { + ((SubstrateMethodCallTargetNode) invoke.callTarget()).setProfiles(typeProfile, methodProfile, staticTypeProfile); + } + } + + private static boolean needsProfiles(Invoke invoke) { + /* We do not need any profiles in methods for JIT compilation at image run time. */ + return ((MultiMethod) invoke.asNode().graph().method()).getMultiMethodKey() != SubstrateCompilationDirectives.RUNTIME_COMPILED_METHOD; } @Override From a4c42ccff1f11d39ac3c70c2d759d88284466d89 Mon Sep 17 00:00:00 2001 From: Christian Wimmer Date: Fri, 19 Jan 2024 11:38:58 -0800 Subject: [PATCH 553/593] Fix the collection of all GC causes at image build time --- .../src/com/oracle/svm/core/heap/GCCause.java | 54 ++++++++++--------- .../svm/core/jfr/JfrGCCauseSerializer.java | 8 +-- 2 files changed, 33 insertions(+), 29 deletions(-) diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/heap/GCCause.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/heap/GCCause.java index c4529f2ade9f..21645d729a49 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/heap/GCCause.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/heap/GCCause.java @@ -24,16 +24,18 @@ */ package com.oracle.svm.core.heap; -import java.util.ArrayList; +import java.util.List; +import org.graalvm.nativeimage.ImageSingletons; import org.graalvm.nativeimage.Platform; import org.graalvm.nativeimage.Platforms; -import com.oracle.svm.core.BuildPhaseProvider.ReadyForCompilation; import com.oracle.svm.core.Uninterruptible; import com.oracle.svm.core.feature.AutomaticallyRegisteredFeature; +import com.oracle.svm.core.feature.AutomaticallyRegisteredImageSingleton; import com.oracle.svm.core.feature.InternalFeature; import com.oracle.svm.core.util.DuplicatedInNativeCode; +import com.oracle.svm.core.util.ImageHeapList; import com.oracle.svm.core.util.VMError; /** @@ -41,7 +43,6 @@ * garbage collector implementations. */ public class GCCause { - @Platforms(Platform.HOSTED_ONLY.class) private static final ArrayList HostedGCCauseList = new ArrayList<>(); @DuplicatedInNativeCode public static final GCCause JavaLangSystemGC = new GCCause("java.lang.System.gc()", 0); @DuplicatedInNativeCode public static final GCCause UnitTest = new GCCause("Forced GC in unit test", 1); @@ -50,28 +51,13 @@ public class GCCause { @DuplicatedInNativeCode public static final GCCause JvmtiForceGC = new GCCause("JvmtiEnv ForceGarbageCollection", 4); @DuplicatedInNativeCode public static final GCCause HeapDump = new GCCause("Heap Dump Initiated GC ", 5); - @UnknownObjectField(availability = ReadyForCompilation.class) protected static GCCause[] GCCauses; - private final int id; private final String name; @Platforms(Platform.HOSTED_ONLY.class) - @SuppressWarnings("this-escape") protected GCCause(String name, int id) { this.id = id; this.name = name; - addGCCauseMapping(); - } - - @Platforms(Platform.HOSTED_ONLY.class) - private void addGCCauseMapping() { - synchronized (HostedGCCauseList) { - while (HostedGCCauseList.size() <= id) { - HostedGCCauseList.add(null); - } - VMError.guarantee(HostedGCCauseList.get(id) == null, "%s and another GCCause have the same id.", name); - HostedGCCauseList.set(id, this); - } } public String getName() { @@ -84,24 +70,40 @@ public int getId() { } public static GCCause fromId(int causeId) { - return GCCauses[causeId]; + return getGCCauses().get(causeId); } - public static GCCause[] getGCCauses() { - return GCCauses; + public static List getGCCauses() { + return ImageSingletons.lookup(GCCauseSupport.class).gcCauses; } +} + +@AutomaticallyRegisteredImageSingleton +class GCCauseSupport { + final List gcCauses = ImageHeapList.create(GCCause.class, null); @Platforms(Platform.HOSTED_ONLY.class) - public static void cacheReverseMapping() { - GCCauses = HostedGCCauseList.toArray(new GCCause[HostedGCCauseList.size()]); + Object collectGCCauses(Object obj) { + if (obj instanceof GCCause gcCause) { + synchronized (gcCauses) { + int id = gcCause.getId(); + while (gcCauses.size() <= id) { + gcCauses.add(null); + } + var existing = gcCauses.set(id, gcCause); + if (existing != null && existing != gcCause) { + throw VMError.shouldNotReachHere("Two GCCause objects have the same id " + id + ": " + gcCause.getName() + ", " + existing.getName()); + } + } + } + return obj; } } @AutomaticallyRegisteredFeature class GCCauseFeature implements InternalFeature { @Override - public void beforeCompilation(BeforeCompilationAccess access) { - GCCause.cacheReverseMapping(); - access.registerAsImmutable(GCCause.GCCauses); + public void duringSetup(DuringSetupAccess access) { + access.registerObjectReplacer(ImageSingletons.lookup(GCCauseSupport.class)::collectGCCauses); } } diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jfr/JfrGCCauseSerializer.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jfr/JfrGCCauseSerializer.java index d01a5e4f4f17..fab40f240072 100755 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jfr/JfrGCCauseSerializer.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jfr/JfrGCCauseSerializer.java @@ -24,6 +24,8 @@ */ package com.oracle.svm.core.jfr; +import java.util.List; + import org.graalvm.nativeimage.Platform; import org.graalvm.nativeimage.Platforms; @@ -37,10 +39,10 @@ public JfrGCCauseSerializer() { @Override public void write(JfrChunkWriter writer) { // GCCauses has null entries - GCCause[] causes = GCCause.getGCCauses(); + List causes = GCCause.getGCCauses(); int nonNullItems = 0; - for (int index = 0; index < causes.length; index++) { - if (causes[index] != null) { + for (GCCause cause : causes) { + if (cause != null) { nonNullItems++; } } From 04dc50eec0d18f7f0d81a000be329838dbe8cae7 Mon Sep 17 00:00:00 2001 From: Christian Wimmer Date: Fri, 19 Jan 2024 11:42:34 -0800 Subject: [PATCH 554/593] Avoid NullPointerException during error reporting --- .../svm/graal/hosted/runtimecompilation/CallTreeInfo.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/substratevm/src/com.oracle.svm.graal/src/com/oracle/svm/graal/hosted/runtimecompilation/CallTreeInfo.java b/substratevm/src/com.oracle.svm.graal/src/com/oracle/svm/graal/hosted/runtimecompilation/CallTreeInfo.java index 9a84a0c8a8ef..d333ad27fd38 100644 --- a/substratevm/src/com.oracle.svm.graal/src/com/oracle/svm/graal/hosted/runtimecompilation/CallTreeInfo.java +++ b/substratevm/src/com.oracle.svm.graal/src/com/oracle/svm/graal/hosted/runtimecompilation/CallTreeInfo.java @@ -67,7 +67,7 @@ public static CallTreeInfo create(AnalysisUniverse aUniverse, Map runtimeCompilations = new HashMap<>(); for (var method : aUniverse.getMethods()) { var rMethod = method.getMultiMethod(RUNTIME_COMPILED_METHOD); - if (rMethod != null && rMethod.isReachable() && !invalidForRuntimeCompilation.containsKey(rMethod)) { + if (rMethod != null && rMethod.isReachable() && !invalidForRuntimeCompilation.containsKey(rMethod) && rMethod.getAnalyzedGraph() != null) { var origInlinedMethods = rMethod.getAnalyzedGraph().getInlinedMethods().stream().map(inlinedMethod -> { AnalysisMethod orig = ((AnalysisMethod) inlinedMethod).getMultiMethod(ORIGINAL_METHOD); assert orig != null; From 7052ef5d3fd1df440517198085c4d5608e5e1cb2 Mon Sep 17 00:00:00 2001 From: Christian Wimmer Date: Fri, 19 Jan 2024 11:56:53 -0800 Subject: [PATCH 555/593] Avoid unncessary marking of ImageHeapList as modified --- .../src/com/oracle/svm/core/util/ImageHeapList.java | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/util/ImageHeapList.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/util/ImageHeapList.java index 0fd75bae3cc8..3a038dc29da0 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/util/ImageHeapList.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/util/ImageHeapList.java @@ -117,8 +117,11 @@ public synchronized E get(int index) { @Override public synchronized E set(int index, E element) { - modified = true; - return hostedList.set(index, element); + E result = hostedList.set(index, element); + if (result != element) { + modified = true; + } + return result; } @Override From 43a4e7ed26184495e3e52926d5c4eb19af7296f3 Mon Sep 17 00:00:00 2001 From: ol-automation_ww Date: Fri, 19 Jan 2024 21:13:20 +0000 Subject: [PATCH 556/593] Update truffleruby import. --- vm/mx.vm/suite.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vm/mx.vm/suite.py b/vm/mx.vm/suite.py index 23b7a2a32edd..16411c0d054e 100644 --- a/vm/mx.vm/suite.py +++ b/vm/mx.vm/suite.py @@ -49,7 +49,7 @@ }, { "name": "truffleruby", - "version": "1f80340cfdfb46bb987738350d541eaf77e3b3ba", + "version": "7100f1cb4ca008aadbc394c617a4d64fa767e073", "dynamic": True, "urls": [ {"url": "https://github.com/oracle/truffleruby.git", "kind": "git"}, From 5c4dc04701cab47c52b5f52d54ca6cf08d10f7ec Mon Sep 17 00:00:00 2001 From: stepan Date: Fri, 19 Jan 2024 22:16:12 +0100 Subject: [PATCH 557/593] Add mx.vm/ce-fastr-native for building FastR native standalone --- vm/mx.vm/ce-fastr-native | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 vm/mx.vm/ce-fastr-native diff --git a/vm/mx.vm/ce-fastr-native b/vm/mx.vm/ce-fastr-native new file mode 100644 index 000000000000..5b2d48dbd3a4 --- /dev/null +++ b/vm/mx.vm/ce-fastr-native @@ -0,0 +1,5 @@ +DYNAMIC_IMPORTS=/compiler,/graal-js,/sdk,/substratevm,/sulong,/tools,/truffle,fastr +COMPONENTS=antlr4,xz,R,cmp,cov,dap,gu,gvm,ins,insight,insightheap,lg,llp,llrc,llrl,llrn,lsp,nfi-libffi,ni,nic,poly,polynative,pro,sdk,sdkl,svmt,svmnfi,tfl,tfla,tflc,tflm,truffle-json +NATIVE_IMAGES=lib:jvmcicompiler,lib:Rvm +NON_REBUILDABLE_IMAGES=lib:jvmcicompiler +DISABLE_INSTALLABLES=False From 43432067d3b75be726193fa5402c5d6960ddf352 Mon Sep 17 00:00:00 2001 From: ol-automation_ww Date: Sat, 20 Jan 2024 09:33:01 +0000 Subject: [PATCH 558/593] [GR-23997] Periodic update of the graal import (2024-01-19). PullRequest: js/3035 --- vm/mx.vm/suite.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/vm/mx.vm/suite.py b/vm/mx.vm/suite.py index 23b7a2a32edd..0a84f0e5dcc4 100644 --- a/vm/mx.vm/suite.py +++ b/vm/mx.vm/suite.py @@ -33,7 +33,7 @@ "name": "graal-nodejs", "subdir": True, "dynamic": True, - "version": "ceb352c9066feee3e58f24f7e1eb4709171d5b08", + "version": "c16857a763fc2a758b0c7d737bca7c9eb5f5e7ac", "urls" : [ {"url" : "https://github.com/graalvm/graaljs.git", "kind" : "git"}, ] @@ -42,7 +42,7 @@ "name": "graal-js", "subdir": True, "dynamic": True, - "version": "ceb352c9066feee3e58f24f7e1eb4709171d5b08", + "version": "c16857a763fc2a758b0c7d737bca7c9eb5f5e7ac", "urls": [ {"url": "https://github.com/graalvm/graaljs.git", "kind" : "git"}, ] From 4f79d8fede1c6d09288f7fcbdc69d764015f65de Mon Sep 17 00:00:00 2001 From: Codrut Stancu Date: Fri, 19 Jan 2024 15:09:31 +0100 Subject: [PATCH 559/593] Create HostedValuesProvider to give ImageHeapScanner access to hosted VM values. --- .../pointsto/standalone/PointsToAnalyzer.java | 3 +- .../heap/StandaloneImageHeapScanner.java | 11 +- .../ConstantReflectionProviderExtension.java | 33 ---- .../oracle/graal/pointsto/ObjectScanner.java | 3 +- .../pointsto/heap/HeapSnapshotVerifier.java | 2 +- .../pointsto/heap/HostedValuesProvider.java | 92 +++++++++++ .../graal/pointsto/heap/ImageHeapScanner.java | 30 ++-- .../RuntimeCompiledMethodSupport.java | 2 +- .../SubstrateRuntimeConfigurationBuilder.java | 2 +- .../svm/hosted/NativeImageGenerator.java | 5 +- .../AnalysisConstantReflectionProvider.java | 92 ++--------- .../hosted/ameta/SVMHostedValueProvider.java | 149 ++++++++++++++++++ .../svm/hosted/heap/SVMImageHeapScanner.java | 20 +-- .../svm/hosted/image/NativeImageHeap.java | 8 +- 14 files changed, 289 insertions(+), 163 deletions(-) delete mode 100644 substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/ConstantReflectionProviderExtension.java create mode 100644 substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/heap/HostedValuesProvider.java create mode 100644 substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/ameta/SVMHostedValueProvider.java diff --git a/substratevm/src/com.oracle.graal.pointsto.standalone/src/com/oracle/graal/pointsto/standalone/PointsToAnalyzer.java b/substratevm/src/com.oracle.graal.pointsto.standalone/src/com/oracle/graal/pointsto/standalone/PointsToAnalyzer.java index bbb53fa0d632..e480627f4917 100644 --- a/substratevm/src/com.oracle.graal.pointsto.standalone/src/com/oracle/graal/pointsto/standalone/PointsToAnalyzer.java +++ b/substratevm/src/com.oracle.graal.pointsto.standalone/src/com/oracle/graal/pointsto/standalone/PointsToAnalyzer.java @@ -46,6 +46,7 @@ import com.oracle.graal.pointsto.api.PointstoOptions; import com.oracle.graal.pointsto.flow.context.bytecode.BytecodeSensitiveAnalysisPolicy; import com.oracle.graal.pointsto.heap.HeapSnapshotVerifier; +import com.oracle.graal.pointsto.heap.HostedValuesProvider; import com.oracle.graal.pointsto.heap.ImageHeap; import com.oracle.graal.pointsto.infrastructure.SubstitutionProcessor; import com.oracle.graal.pointsto.meta.AnalysisMetaAccess; @@ -159,7 +160,7 @@ private PointsToAnalyzer(String mainEntryClass, OptionValues options) { aUniverse.setBigBang(bigbang); ImageHeap heap = new ImageHeap(); StandaloneImageHeapScanner heapScanner = new StandaloneImageHeapScanner(bigbang, heap, aMetaAccess, - snippetReflection, aConstantReflection, new AnalysisObjectScanningObserver(bigbang), analysisClassLoader); + snippetReflection, aConstantReflection, new AnalysisObjectScanningObserver(bigbang), analysisClassLoader, new HostedValuesProvider(aUniverse)); aUniverse.setHeapScanner(heapScanner); HeapSnapshotVerifier heapVerifier = new StandaloneHeapSnapshotVerifier(bigbang, heap, heapScanner); aUniverse.setHeapVerifier(heapVerifier); diff --git a/substratevm/src/com.oracle.graal.pointsto.standalone/src/com/oracle/graal/pointsto/standalone/heap/StandaloneImageHeapScanner.java b/substratevm/src/com.oracle.graal.pointsto.standalone/src/com/oracle/graal/pointsto/standalone/heap/StandaloneImageHeapScanner.java index 64ffb1accd50..4e1674a84469 100644 --- a/substratevm/src/com.oracle.graal.pointsto.standalone/src/com/oracle/graal/pointsto/standalone/heap/StandaloneImageHeapScanner.java +++ b/substratevm/src/com.oracle.graal.pointsto.standalone/src/com/oracle/graal/pointsto/standalone/heap/StandaloneImageHeapScanner.java @@ -26,10 +26,11 @@ package com.oracle.graal.pointsto.standalone.heap; -import jdk.graal.compiler.api.replacements.SnippetReflectionProvider; +import java.util.function.Predicate; import com.oracle.graal.pointsto.BigBang; import com.oracle.graal.pointsto.ObjectScanningObserver; +import com.oracle.graal.pointsto.heap.HostedValuesProvider; import com.oracle.graal.pointsto.heap.ImageHeap; import com.oracle.graal.pointsto.heap.ImageHeapScanner; import com.oracle.graal.pointsto.heap.value.ValueSupplier; @@ -37,22 +38,20 @@ import com.oracle.graal.pointsto.meta.AnalysisMetaAccess; import com.oracle.graal.pointsto.util.AnalysisError; +import jdk.graal.compiler.api.replacements.SnippetReflectionProvider; import jdk.vm.ci.code.BytecodePosition; import jdk.vm.ci.meta.ConstantReflectionProvider; import jdk.vm.ci.meta.JavaConstant; import jdk.vm.ci.meta.ResolvedJavaField; -import java.util.function.Predicate; - public class StandaloneImageHeapScanner extends ImageHeapScanner { private ClassLoader classLoader; private Predicate shouldScanConstant; private Predicate shouldScanField; public StandaloneImageHeapScanner(BigBang bb, ImageHeap heap, AnalysisMetaAccess aMetaAccess, SnippetReflectionProvider aSnippetReflection, ConstantReflectionProvider aConstantReflection, - ObjectScanningObserver aScanningObserver, - ClassLoader classLoader) { - super(bb, heap, aMetaAccess, aSnippetReflection, aConstantReflection, aScanningObserver); + ObjectScanningObserver aScanningObserver, ClassLoader classLoader, HostedValuesProvider hostedValuesProvider) { + super(bb, heap, aMetaAccess, aSnippetReflection, aConstantReflection, aScanningObserver, hostedValuesProvider); this.classLoader = classLoader; shouldScanConstant = constant -> isClassLoaderAllowed(metaAccess.lookupJavaType(constant).getJavaClass().getClassLoader()); shouldScanField = field -> isClassLoaderAllowed(field.getDeclaringClass().getJavaClass().getClassLoader()); diff --git a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/ConstantReflectionProviderExtension.java b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/ConstantReflectionProviderExtension.java deleted file mode 100644 index 23d5b1538060..000000000000 --- a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/ConstantReflectionProviderExtension.java +++ /dev/null @@ -1,33 +0,0 @@ -/* - * Copyright (c) 2023, 2023, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.oracle.graal.pointsto; - -import jdk.vm.ci.meta.ConstantReflectionProvider; -import jdk.vm.ci.meta.JavaConstant; -import jdk.vm.ci.meta.ResolvedJavaField; - -public interface ConstantReflectionProviderExtension extends ConstantReflectionProvider { - JavaConstant readHostedFieldValueWithReplacement(T field, JavaConstant receiver); -} diff --git a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/ObjectScanner.java b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/ObjectScanner.java index 203f7610b87a..aaf64921e0a8 100644 --- a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/ObjectScanner.java +++ b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/ObjectScanner.java @@ -210,11 +210,10 @@ protected void scanField(AnalysisField field, JavaConstant receiver, ScanReason } } - @SuppressWarnings("unchecked") protected JavaConstant readFieldValue(AnalysisField field, JavaConstant receiver) { /* The object scanner processes hosted values. We must not see shadow heap values here. */ AnalysisError.guarantee(!(receiver instanceof ImageHeapConstant)); - return ((ConstantReflectionProviderExtension) bb.getConstantReflectionProvider()).readHostedFieldValueWithReplacement(field, receiver); + return bb.getUniverse().getHeapScanner().getHostedValuesProvider().readFieldValueWithReplacement(field, receiver); } /** diff --git a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/heap/HeapSnapshotVerifier.java b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/heap/HeapSnapshotVerifier.java index b8cb9b49b631..7c5fad923143 100644 --- a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/heap/HeapSnapshotVerifier.java +++ b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/heap/HeapSnapshotVerifier.java @@ -278,7 +278,7 @@ public static boolean patchPrimitiveArrayValue(BigBang bb, JavaConstant snapshot if (!Objects.deepEquals(snapshotArray, newValueArray)) { /* Guarantee that the shadowed constant and the hosted constant are the same. */ AnalysisError.guarantee(bb.getConstantReflectionProvider().constantEquals(snapshot, newValue)); - Integer length = bb.getConstantReflectionProvider().readArrayLength(newValue); + Integer length = bb.getUniverse().getHeapScanner().getHostedValuesProvider().readArrayLength(newValue); /* Since the shadowed constant didn't change, the length should match. */ System.arraycopy(newValueArray, 0, snapshotArray, 0, length); return true; diff --git a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/heap/HostedValuesProvider.java b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/heap/HostedValuesProvider.java new file mode 100644 index 000000000000..b90dccfe0e6f --- /dev/null +++ b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/heap/HostedValuesProvider.java @@ -0,0 +1,92 @@ +/* + * Copyright (c) 2024, 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.graal.pointsto.heap; + +import com.oracle.graal.pointsto.heap.value.ValueSupplier; +import com.oracle.graal.pointsto.meta.AnalysisField; +import com.oracle.graal.pointsto.meta.AnalysisUniverse; +import com.oracle.graal.pointsto.util.GraalAccess; + +import jdk.vm.ci.meta.JavaConstant; +import jdk.vm.ci.meta.JavaKind; + +public class HostedValuesProvider { + protected final AnalysisUniverse universe; + + public HostedValuesProvider(AnalysisUniverse universe) { + this.universe = universe; + } + + public ValueSupplier readFieldValue(AnalysisField field, JavaConstant receiver) { + return ValueSupplier.eagerValue(doReadValue(field, receiver)); + } + + public JavaConstant readFieldValueWithReplacement(AnalysisField field, JavaConstant receiver) { + return replaceObject(doReadValue(field, receiver)); + } + + private JavaConstant doReadValue(AnalysisField field, JavaConstant receiver) { + /* Wrap the hosted constant into a substrate constant */ + field.beforeFieldValueAccess(); + JavaConstant hostedReceiver = universe.toHosted(receiver); + JavaConstant hostedValue = GraalAccess.getOriginalProviders().getConstantReflection().readFieldValue(field.wrapped, hostedReceiver); + return universe.fromHosted(hostedValue); + } + + public Integer readArrayLength(JavaConstant array) { + return GraalAccess.getOriginalProviders().getConstantReflection().readArrayLength(universe.toHosted(array)); + } + + public JavaConstant readArrayElement(JavaConstant array, int index) { + return GraalAccess.getOriginalProviders().getConstantReflection().readArrayElement(universe.toHosted(array), index); + } + + /** + * Run all registered object replacers. + */ + public JavaConstant replaceObject(JavaConstant value) { + if (value == JavaConstant.NULL_POINTER) { + return JavaConstant.NULL_POINTER; + } + if (value instanceof ImageHeapConstant) { + /* The value is replaced when the object is snapshotted. */ + return value; + } + if (value.getJavaKind() == JavaKind.Object) { + Object oldObject = universe.getSnippetReflection().asObject(Object.class, value); + Object newObject = universe.replaceObject(oldObject); + if (newObject != oldObject) { + return validateReplacedConstant(universe.getSnippetReflection().forObject(newObject)); + } + } + return value; + } + + /** Hook to run validation checks on the replaced value. */ + public JavaConstant validateReplacedConstant(JavaConstant value) { + return value; + } + +} diff --git a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/heap/ImageHeapScanner.java b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/heap/ImageHeapScanner.java index 0b7c598105d6..ed069405937f 100644 --- a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/heap/ImageHeapScanner.java +++ b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/heap/ImageHeapScanner.java @@ -46,7 +46,6 @@ import com.oracle.graal.pointsto.constraints.UnsupportedFeatureException; import com.oracle.graal.pointsto.heap.HeapSnapshotVerifier.ScanningObserver; import com.oracle.graal.pointsto.heap.value.ValueSupplier; -import com.oracle.graal.pointsto.infrastructure.UniverseMetaAccess; import com.oracle.graal.pointsto.meta.AnalysisField; import com.oracle.graal.pointsto.meta.AnalysisMetaAccess; import com.oracle.graal.pointsto.meta.AnalysisType; @@ -87,6 +86,7 @@ public abstract class ImageHeapScanner { protected final SnippetReflectionProvider snippetReflection; protected final ConstantReflectionProvider constantReflection; + protected final HostedValuesProvider hostedValuesProvider; protected final ConstantReflectionProvider hostedConstantReflection; protected final SnippetReflectionProvider hostedSnippetReflection; @@ -95,7 +95,7 @@ public abstract class ImageHeapScanner { private boolean sealed; public ImageHeapScanner(BigBang bb, ImageHeap heap, AnalysisMetaAccess aMetaAccess, SnippetReflectionProvider aSnippetReflection, - ConstantReflectionProvider aConstantReflection, ObjectScanningObserver aScanningObserver) { + ConstantReflectionProvider aConstantReflection, ObjectScanningObserver aScanningObserver, HostedValuesProvider aHostedValuesProvider) { this.bb = bb; imageHeap = heap; metaAccess = aMetaAccess; @@ -103,6 +103,7 @@ public ImageHeapScanner(BigBang bb, ImageHeap heap, AnalysisMetaAccess aMetaAcce hostVM = aMetaAccess.getUniverse().hostVM(); snippetReflection = aSnippetReflection; constantReflection = aConstantReflection; + hostedValuesProvider = aHostedValuesProvider; scanningObserver = aScanningObserver; hostedConstantReflection = GraalAccess.getOriginalProviders().getConstantReflection(); hostedSnippetReflection = GraalAccess.getOriginalProviders().getSnippetReflection(); @@ -256,7 +257,7 @@ protected ImageHeapConstant createImageHeapObject(JavaConstant constant, ScanRea AnalysisType type = metaAccess.lookupJavaType(constant); if (type.isArray()) { - Integer length = constantReflection.readArrayLength(constant); + Integer length = hostedValuesProvider.readArrayLength(constant); if (type.getComponentType().isPrimitive()) { return new ImageHeapPrimitiveArray(type, constant, asObject(constant), length); } else { @@ -276,7 +277,7 @@ private ImageHeapArray createImageHeapObjectArray(JavaConstant constant, Analysi ScanReason arrayReason = new ArrayScan(type, array, reason); Object[] elementValues = new Object[length]; for (int idx = 0; idx < length; idx++) { - final JavaConstant rawElementValue = constantReflection.readArrayElement(constant, idx); + final JavaConstant rawElementValue = hostedValuesProvider.readArrayElement(constant, idx); int finalIdx = idx; elementValues[idx] = new AnalysisFuture<>(() -> { JavaConstant arrayElement = createImageHeapConstant(rawElementValue, arrayReason); @@ -307,7 +308,7 @@ private ImageHeapInstance createImageHeapInstance(JavaConstant constant, Analysi AnalysisField field = (AnalysisField) javaField; ValueSupplier rawFieldValue; try { - rawFieldValue = readHostedFieldValue(field, universe.toHosted(constant)); + rawFieldValue = readHostedFieldValue(field, constant); } catch (InternalError | TypeNotPresentException | LinkageError e) { /* Ignore missing type errors. */ continue; @@ -338,9 +339,7 @@ private Optional maybeReplace(JavaConstant constant, ScanReason re try { Object replaced = universe.replaceObject(unwrapped); if (replaced != unwrapped) { - JavaConstant replacedConstant = universe.getSnippetReflection().forObject(replaced); - validateReplacedConstant(metaAccess, replacedConstant); - return Optional.of(replacedConstant); + return Optional.of(hostedValuesProvider.validateReplacedConstant(universe.getSnippetReflection().forObject(replaced))); } } catch (UnsupportedFeatureException e) { /* Enhance the unsupported feature message with the object trace and rethrow. */ @@ -353,11 +352,6 @@ private Optional maybeReplace(JavaConstant constant, ScanReason re return Optional.empty(); } - /** Hook to run validation checks on the replaced value. */ - @SuppressWarnings("unused") - public void validateReplacedConstant(UniverseMetaAccess access, JavaConstant value) { - } - public static void maybeForceHashCodeComputation(Object constant) { if (constant instanceof String stringConstant) { forceHashCodeComputation(stringConstant); @@ -568,9 +562,7 @@ public JavaConstant readStaticFieldValue(AnalysisField field) { } protected ValueSupplier readHostedFieldValue(AnalysisField field, JavaConstant receiver) { - // Wrap the hosted constant into a substrate constant - JavaConstant value = universe.fromHosted(constantReflection.readFieldValue(field, receiver)); - return ValueSupplier.eagerValue(value); + return hostedValuesProvider.readFieldValue(field, receiver); } public void rescanRoot(Field reflectionField) { @@ -610,7 +602,7 @@ public void rescanField(Object receiver, Field reflectionField, ScanReason reaso } receiverConstant = replaced.get(); } - JavaConstant fieldValue = readHostedFieldValue(field, universe.toHosted(receiverConstant)).get(); + JavaConstant fieldValue = readHostedFieldValue(field, receiverConstant).get(); if (fieldValue != null) { ImageHeapInstance receiverObject = (ImageHeapInstance) toImageHeapObject(receiverConstant, reason); JavaConstant fieldSnapshot = receiverObject.readFieldValue(field); @@ -752,6 +744,10 @@ public void cleanupAfterAnalysis() { protected abstract Class getClass(String className); + public HostedValuesProvider getHostedValuesProvider() { + return hostedValuesProvider; + } + protected AnalysisType lookupJavaType(String className) { return metaAccess.lookupJavaType(getClass(className)); } diff --git a/substratevm/src/com.oracle.svm.graal/src/com/oracle/svm/graal/hosted/runtimecompilation/RuntimeCompiledMethodSupport.java b/substratevm/src/com.oracle.svm.graal/src/com/oracle/svm/graal/hosted/runtimecompilation/RuntimeCompiledMethodSupport.java index a5a5749e3788..9ef831f88e4a 100644 --- a/substratevm/src/com.oracle.svm.graal/src/com/oracle/svm/graal/hosted/runtimecompilation/RuntimeCompiledMethodSupport.java +++ b/substratevm/src/com.oracle.svm.graal/src/com/oracle/svm/graal/hosted/runtimecompilation/RuntimeCompiledMethodSupport.java @@ -325,7 +325,7 @@ public boolean isFinalField(ResolvedJavaField f, ConstantFieldTool tool) { static class RuntimeCompilationReflectionProvider extends AnalysisConstantReflectionProvider { RuntimeCompilationReflectionProvider(BigBang bb, ClassInitializationSupport classInitializationSupport) { - super(bb.getUniverse(), bb.getMetaAccess(), classInitializationSupport); + super(bb.getUniverse(), bb.getMetaAccess()); } @Override diff --git a/substratevm/src/com.oracle.svm.graal/src/com/oracle/svm/graal/meta/SubstrateRuntimeConfigurationBuilder.java b/substratevm/src/com.oracle.svm.graal/src/com/oracle/svm/graal/meta/SubstrateRuntimeConfigurationBuilder.java index a4fb2e99bc5d..0a98617836da 100644 --- a/substratevm/src/com.oracle.svm.graal/src/com/oracle/svm/graal/meta/SubstrateRuntimeConfigurationBuilder.java +++ b/substratevm/src/com.oracle.svm.graal/src/com/oracle/svm/graal/meta/SubstrateRuntimeConfigurationBuilder.java @@ -82,7 +82,7 @@ protected Providers createProviders(CodeCacheProvider codeCache, ConstantReflect @Override protected ConstantReflectionProvider createConstantReflectionProvider() { - return new AnalysisConstantReflectionProvider(aUniverse, metaAccess, classInitializationSupport); + return new AnalysisConstantReflectionProvider(aUniverse, metaAccess); } @Override diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/NativeImageGenerator.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/NativeImageGenerator.java index 3e153b31d453..2f70fed908d5 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/NativeImageGenerator.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/NativeImageGenerator.java @@ -195,6 +195,7 @@ import com.oracle.svm.hosted.ProgressReporter.ReporterClosable; import com.oracle.svm.hosted.ameta.AnalysisConstantFieldProvider; import com.oracle.svm.hosted.ameta.AnalysisConstantReflectionProvider; +import com.oracle.svm.hosted.ameta.SVMHostedValueProvider; import com.oracle.svm.hosted.analysis.Inflation; import com.oracle.svm.hosted.analysis.NativeImagePointsToAnalysis; import com.oracle.svm.hosted.analysis.NativeImageReachabilityAnalysisEngine; @@ -949,7 +950,7 @@ protected void setupNativeImage(OptionValues options, Map { +public class AnalysisConstantReflectionProvider extends SharedConstantReflectionProvider { private final AnalysisUniverse universe; protected final UniverseMetaAccess metaAccess; - private final ClassInitializationSupport classInitializationSupport; private final AnalysisMethodHandleAccessProvider methodHandleAccess; private SimulateClassInitializerSupport simulateClassInitializerSupport; private final FieldValueInterceptionSupport fieldValueInterceptionSupport = FieldValueInterceptionSupport.singleton(); - public AnalysisConstantReflectionProvider(AnalysisUniverse universe, UniverseMetaAccess metaAccess, ClassInitializationSupport classInitializationSupport) { + public AnalysisConstantReflectionProvider(AnalysisUniverse universe, UniverseMetaAccess metaAccess) { this.universe = universe; this.metaAccess = metaAccess; - this.classInitializationSupport = classInitializationSupport; this.methodHandleAccess = new AnalysisMethodHandleAccessProvider(universe); } @@ -151,34 +146,36 @@ public JavaConstant readArrayElement(JavaConstant array, int index) { if (array.getJavaKind() != JavaKind.Object || array.isNull()) { return null; } + HostedValuesProvider hostedValuesProvider = universe.getHeapScanner().getHostedValuesProvider(); if (array instanceof ImageHeapConstant) { if (array instanceof ImageHeapArray heapArray) { if (index < 0 || index >= heapArray.getLength()) { return null; } heapArray.ensureReaderInstalled(); - return replaceObject(heapArray.readElementValue(index)); + return hostedValuesProvider.replaceObject(heapArray.readElementValue(index)); } return null; } JavaConstant element = super.readArrayElement(array, index); - return element == null ? null : replaceObject(element); + return element == null ? null : hostedValuesProvider.replaceObject(element); } @Override public void forEachArrayElement(JavaConstant array, ObjIntConsumer consumer) { + HostedValuesProvider hostedValuesProvider = universe.getHeapScanner().getHostedValuesProvider(); if (array instanceof ImageHeapConstant) { if (array instanceof ImageHeapArray heapArray) { heapArray.ensureReaderInstalled(); for (int index = 0; index < heapArray.getLength(); index++) { JavaConstant element = heapArray.readElementValue(index); - consumer.accept(replaceObject(element), index); + consumer.accept(hostedValuesProvider.replaceObject(element), index); } } return; } /* Intercept the original consumer and apply object replacement. */ - super.forEachArrayElement(array, (element, index) -> consumer.accept(replaceObject(element), index)); + super.forEachArrayElement(array, (element, index) -> consumer.accept(hostedValuesProvider.replaceObject(element), index)); } @Override @@ -231,44 +228,13 @@ public JavaConstant readValue(AnalysisField field, JavaConstant receiver, boolea } if (value == null) { VMError.guarantee(!SimulateClassInitializerSupport.singleton().isEnabled()); - value = universe.getHeapScanner().createImageHeapConstant(readHostedFieldValueWithReplacement(field, receiver), ObjectScanner.OtherReason.UNKNOWN); + ImageHeapScanner heapScanner = universe.getHeapScanner(); + HostedValuesProvider hostedValuesProvider = heapScanner.getHostedValuesProvider(); + value = heapScanner.createImageHeapConstant(hostedValuesProvider.readFieldValueWithReplacement(field, receiver), ObjectScanner.OtherReason.UNKNOWN); } return value; } - /** - * Read the field value and wrap it in a value supplier without performing any replacements. The - * shadow heap doesn't directly store simulated values. The simulated values are only accessible - * via {@link SimulateClassInitializerSupport#getSimulatedFieldValue(AnalysisField)}. The shadow - * heap is a snapshot of the hosted state; simulated values are a level above the shadow heap. - */ - public ValueSupplier readHostedFieldValue(AnalysisField field, JavaConstant receiver) { - if (fieldValueInterceptionSupport.isValueAvailable(field)) { - /* Materialize and return the value. */ - return ValueSupplier.eagerValue(doReadValue(field, receiver)); - } - /* - * Return a lazy value. First, this applies to fields annotated with - * RecomputeFieldValue.Kind.FieldOffset and RecomputeFieldValue.Kind.Custom whose value - * becomes available during hosted universe building and is installed by calling - * ComputedValueField.processSubstrate() or ComputedValueField.readValue(). Secondly, this - * applies to fields annotated with @UnknownObjectField whose value is set directly either - * during analysis or in a later phase. Attempts to materialize the value before it becomes - * available will result in an error. - */ - return ValueSupplier.lazyValue(() -> doReadValue(field, receiver), () -> fieldValueInterceptionSupport.isValueAvailable(field)); - } - - /** Returns the hosted field value. The receiver must be a hosted constant. */ - @Override - public JavaConstant readHostedFieldValueWithReplacement(AnalysisField field, JavaConstant receiver) { - return replaceObject(doReadValue(field, universe.toHosted(receiver))); - } - - private JavaConstant doReadValue(AnalysisField field, JavaConstant receiver) { - return universe.fromHosted(fieldValueInterceptionSupport.readFieldValue(classInitializationSupport, field, receiver)); - } - /** * For classes that are simulated as initialized, provide the value of static fields to the * static analysis so that they are seen properly as roots in the image heap. @@ -288,38 +254,6 @@ private JavaConstant readSimulatedValue(AnalysisField field) { return simulateClassInitializerSupport.getSimulatedFieldValue(field); } - /** - * Run all registered object replacers. - */ - private JavaConstant replaceObject(JavaConstant value) { - if (value == JavaConstant.NULL_POINTER) { - return JavaConstant.NULL_POINTER; - } - if (value instanceof ImageHeapConstant) { - /* The value is replaced when the object is snapshotted. */ - return value; - } - if (value.getJavaKind() == JavaKind.Object) { - Object oldObject = universe.getSnippetReflection().asObject(Object.class, value); - Object newObject = universe.replaceObject(oldObject); - if (newObject != oldObject) { - JavaConstant replacedConstant = universe.getSnippetReflection().forObject(newObject); - validateReplacedConstant(metaAccess, replacedConstant); - return replacedConstant; - } - } - return value; - } - - /** - * {@link HostedLookupSnippetReflectionProvider} replaces relocatable pointers with - * {@link RelocatableConstant} and regular {@link WordBase} values with - * {@link PrimitiveConstant}. No other {@link WordBase} values can be reachable at this point. - */ - public static void validateReplacedConstant(UniverseMetaAccess access, JavaConstant value) { - VMError.guarantee(value instanceof RelocatableConstant || !access.isInstanceOf(value, WordBase.class)); - } - @Override public AnalysisType asJavaType(Constant constant) { if (constant instanceof SubstrateObjectConstant substrateConstant) { diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/ameta/SVMHostedValueProvider.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/ameta/SVMHostedValueProvider.java new file mode 100644 index 000000000000..4aa9a6223b0e --- /dev/null +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/ameta/SVMHostedValueProvider.java @@ -0,0 +1,149 @@ +/* + * Copyright (c) 2024, 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.svm.hosted.ameta; + +import java.lang.reflect.Array; + +import org.graalvm.nativeimage.c.function.RelocatedPointer; +import org.graalvm.word.WordBase; + +import com.oracle.graal.pointsto.heap.HostedValuesProvider; +import com.oracle.graal.pointsto.heap.value.ValueSupplier; +import com.oracle.graal.pointsto.meta.AnalysisField; +import com.oracle.graal.pointsto.meta.AnalysisUniverse; +import com.oracle.svm.core.FrameAccess; +import com.oracle.svm.core.meta.SubstrateObjectConstant; +import com.oracle.svm.core.util.VMError; +import com.oracle.svm.hosted.classinitialization.ClassInitializationSupport; +import com.oracle.svm.hosted.classinitialization.SimulateClassInitializerSupport; +import com.oracle.svm.hosted.meta.HostedLookupSnippetReflectionProvider; +import com.oracle.svm.hosted.meta.RelocatableConstant; + +import jdk.vm.ci.meta.JavaConstant; +import jdk.vm.ci.meta.JavaKind; +import jdk.vm.ci.meta.PrimitiveConstant; + +public class SVMHostedValueProvider extends HostedValuesProvider { + + private final FieldValueInterceptionSupport fieldValueInterceptionSupport = FieldValueInterceptionSupport.singleton(); + private final ClassInitializationSupport classInitializationSupport; + + public SVMHostedValueProvider(ClassInitializationSupport classInitializationSupport, AnalysisUniverse universe) { + super(universe); + this.classInitializationSupport = classInitializationSupport; + } + + /** + * Read the field value and wrap it in a value supplier without performing any replacements. The + * replacements are applied when the value is reached in the shadow heap. The shadow heap + * doesn't directly store simulated values. The simulated values are only accessible via + * {@link SimulateClassInitializerSupport#getSimulatedFieldValue(AnalysisField)}. The shadow + * heap is a snapshot of the hosted state; simulated values are a level above the shadow heap. + */ + @Override + public ValueSupplier readFieldValue(AnalysisField field, JavaConstant receiver) { + if (fieldValueInterceptionSupport.isValueAvailable(field)) { + /* Materialize and return the value. */ + return ValueSupplier.eagerValue(doReadValue(field, receiver)); + } + /* + * Return a lazy value. First, this applies to fields annotated with + * RecomputeFieldValue.Kind.FieldOffset and RecomputeFieldValue.Kind.Custom whose value + * becomes available during hosted universe building and is installed by calling + * ComputedValueField.processSubstrate() or ComputedValueField.readValue(). Secondly, this + * applies to fields annotated with @UnknownObjectField whose value is set directly either + * during analysis or in a later phase. Attempts to materialize the value before it becomes + * available will result in an error. + */ + return ValueSupplier.lazyValue(() -> doReadValue(field, receiver), () -> fieldValueInterceptionSupport.isValueAvailable(field)); + } + + /** Returns the hosted field value with replacements applied. */ + @Override + public JavaConstant readFieldValueWithReplacement(AnalysisField field, JavaConstant receiver) { + return replaceObject(doReadValue(field, receiver)); + } + + private JavaConstant doReadValue(AnalysisField field, JavaConstant receiver) { + JavaConstant hostedReceiver = universe.toHosted(receiver); + return universe.fromHosted(fieldValueInterceptionSupport.readFieldValue(classInitializationSupport, field, hostedReceiver)); + } + + /** + * This method returns the hosted array element value without any replacement. The replacements + * are applied when the value is reached in the shadow heap. + */ + @Override + public JavaConstant readArrayElement(JavaConstant array, int index) { + if (array.getJavaKind() != JavaKind.Object || array.isNull()) { + return null; + } + Object a = SubstrateObjectConstant.asObject(array); + + if (!a.getClass().isArray() || index < 0 || index >= Array.getLength(a)) { + return null; + } + + if (a instanceof Object[]) { + Object element = ((Object[]) a)[index]; + return forObject(element); + } else { + return JavaConstant.forBoxedPrimitive(Array.get(a, index)); + } + } + + private JavaConstant forObject(Object object) { + AnalysisConstantReflectionProvider.validateRawObjectConstant(object); + if (object instanceof RelocatedPointer pointer) { + return new RelocatableConstant(pointer); + } else if (object instanceof WordBase word) { + return JavaConstant.forIntegerKind(FrameAccess.getWordKind(), word.rawValue()); + } + return SubstrateObjectConstant.forObject(object); + } + + @Override + public Integer readArrayLength(JavaConstant array) { + if (array.getJavaKind() != JavaKind.Object || array.isNull()) { + return null; + } + Object a = SubstrateObjectConstant.asObject(array); + if (!a.getClass().isArray()) { + return null; + } + return java.lang.reflect.Array.getLength(a); + } + + /** + * {@link HostedLookupSnippetReflectionProvider} replaces relocatable pointers with + * {@link RelocatableConstant} and regular {@link WordBase} values with + * {@link PrimitiveConstant}. No other {@link WordBase} values can be reachable at this point. + */ + @Override + public JavaConstant validateReplacedConstant(JavaConstant value) { + VMError.guarantee(value instanceof RelocatableConstant || !universe.getBigbang().getMetaAccess().isInstanceOf(value, WordBase.class)); + return value; + } +} diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/heap/SVMImageHeapScanner.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/heap/SVMImageHeapScanner.java index 9145cd1689d6..1a8398a0a2e9 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/heap/SVMImageHeapScanner.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/heap/SVMImageHeapScanner.java @@ -39,11 +39,10 @@ import com.oracle.graal.pointsto.ObjectScanner; import com.oracle.graal.pointsto.ObjectScanner.ScanReason; import com.oracle.graal.pointsto.ObjectScanningObserver; +import com.oracle.graal.pointsto.heap.HostedValuesProvider; import com.oracle.graal.pointsto.heap.ImageHeap; import com.oracle.graal.pointsto.heap.ImageHeapConstant; import com.oracle.graal.pointsto.heap.ImageHeapScanner; -import com.oracle.graal.pointsto.heap.value.ValueSupplier; -import com.oracle.graal.pointsto.infrastructure.UniverseMetaAccess; import com.oracle.graal.pointsto.meta.AnalysisField; import com.oracle.graal.pointsto.meta.AnalysisMetaAccess; import com.oracle.svm.core.hub.DynamicHub; @@ -79,9 +78,9 @@ public class SVMImageHeapScanner extends ImageHeapScanner { private final FieldValueInterceptionSupport fieldValueInterceptionSupport; @SuppressWarnings("this-escape") - public SVMImageHeapScanner(BigBang bb, ImageHeap imageHeap, ImageClassLoader loader, AnalysisMetaAccess metaAccess, - SnippetReflectionProvider snippetReflection, ConstantReflectionProvider aConstantReflection, ObjectScanningObserver aScanningObserver) { - super(bb, imageHeap, metaAccess, snippetReflection, aConstantReflection, aScanningObserver); + public SVMImageHeapScanner(BigBang bb, ImageHeap imageHeap, ImageClassLoader loader, AnalysisMetaAccess metaAccess, SnippetReflectionProvider snippetReflection, + ConstantReflectionProvider aConstantReflection, ObjectScanningObserver aScanningObserver, HostedValuesProvider hostedValuesProvider) { + super(bb, imageHeap, metaAccess, snippetReflection, aConstantReflection, aScanningObserver, hostedValuesProvider); this.loader = loader; economicMapImpl = getClass("org.graalvm.collections.EconomicMapImpl"); economicMapImplEntriesField = ReflectionUtil.lookupField(economicMapImpl, "entries"); @@ -139,17 +138,6 @@ public JavaConstant readStaticFieldValue(AnalysisField field) { return constant; } - @Override - protected ValueSupplier readHostedFieldValue(AnalysisField field, JavaConstant receiver) { - AnalysisConstantReflectionProvider aConstantReflection = (AnalysisConstantReflectionProvider) this.constantReflection; - return aConstantReflection.readHostedFieldValue(field, receiver); - } - - @Override - public void validateReplacedConstant(UniverseMetaAccess access, JavaConstant value) { - AnalysisConstantReflectionProvider.validateReplacedConstant(access, value); - } - @Override protected void rescanEconomicMap(EconomicMap map) { super.rescanEconomicMap(map); diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/NativeImageHeap.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/NativeImageHeap.java index b640cf9a25e0..09d0064129fa 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/NativeImageHeap.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/NativeImageHeap.java @@ -48,6 +48,7 @@ import org.graalvm.word.WordBase; import com.oracle.graal.pointsto.ObjectScanner.OtherReason; +import com.oracle.graal.pointsto.heap.HostedValuesProvider; import com.oracle.graal.pointsto.heap.ImageHeapConstant; import com.oracle.graal.pointsto.heap.ImageHeapInstance; import com.oracle.graal.pointsto.heap.ImageHeapScanner; @@ -71,7 +72,6 @@ import com.oracle.svm.core.util.UserError; import com.oracle.svm.core.util.VMError; import com.oracle.svm.hosted.HostedConfiguration; -import com.oracle.svm.hosted.ameta.AnalysisConstantReflectionProvider; import com.oracle.svm.hosted.config.DynamicHubLayout; import com.oracle.svm.hosted.config.HybridLayout; import com.oracle.svm.hosted.meta.HostedArrayClass; @@ -258,9 +258,9 @@ public void addTrailingObjects() { Object readInlinedField(HostedField field, JavaConstant receiver) { VMError.guarantee(HostedConfiguration.isInlinedField(field), "Expected an inlined field, found %s", field); JavaConstant hostedReceiver = ((ImageHeapInstance) receiver).getHostedObject(); - /* Use the AnalysisConstantReflectionProvider to get direct access to hosted values. */ - AnalysisConstantReflectionProvider analysisConstantReflection = hConstantReflection.getWrappedConstantReflection(); - return hUniverse.getSnippetReflection().asObject(Object.class, analysisConstantReflection.readHostedFieldValueWithReplacement(field.getWrapped(), hostedReceiver)); + /* Use the HostedValuesProvider to get direct access to hosted values. */ + HostedValuesProvider hostedValuesProvider = aUniverse.getHeapScanner().getHostedValuesProvider(); + return hUniverse.getSnippetReflection().asObject(Object.class, hostedValuesProvider.readFieldValueWithReplacement(field.getWrapped(), hostedReceiver)); } private JavaConstant readConstantField(HostedField field, JavaConstant receiver) { From 1fc17df5c1c2c47547d8393ebaf8388c350742a8 Mon Sep 17 00:00:00 2001 From: Codrut Stancu Date: Sat, 20 Jan 2024 14:17:44 +0100 Subject: [PATCH 560/593] AnalysisConstantReflection should only deal with ImageHeapConstant and not need any replacement. ImageHeapConstants are replaced when added to the shadow heap. --- .../pointsto/heap/ImageHeapConstant.java | 3 +- .../AnalysisConstantReflectionProvider.java | 51 +++++++++---------- 2 files changed, 25 insertions(+), 29 deletions(-) diff --git a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/heap/ImageHeapConstant.java b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/heap/ImageHeapConstant.java index 2f7f4aa43610..1637e030ea5f 100644 --- a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/heap/ImageHeapConstant.java +++ b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/heap/ImageHeapConstant.java @@ -276,6 +276,7 @@ public int hashCode() { @Override public String toString() { - return "ImageHeapConstant<" + constantData.type.toJavaName() + ", reachable: " + isReachable() + ", reader installed: " + isReaderInstalled() + ", compressed: " + compressed + ">"; + return "ImageHeapConstant<" + constantData.type.toJavaName() + ", reachable: " + isReachable() + ", reader installed: " + isReaderInstalled() + + ", compressed: " + compressed + ", backed: " + isBackedByHostedObject() + ">"; } } diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/ameta/AnalysisConstantReflectionProvider.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/ameta/AnalysisConstantReflectionProvider.java index b2c8bbb2a4ba..fa05c2a4d765 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/ameta/AnalysisConstantReflectionProvider.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/ameta/AnalysisConstantReflectionProvider.java @@ -132,13 +132,11 @@ public Integer readArrayLength(JavaConstant array) { if (array.getJavaKind() != JavaKind.Object || array.isNull()) { return null; } - if (array instanceof ImageHeapConstant) { - if (array instanceof ImageHeapArray heapArray) { - return heapArray.getLength(); - } - return null; + VMError.guarantee(array instanceof ImageHeapConstant); + if (array instanceof ImageHeapArray heapArray) { + return heapArray.getLength(); } - return super.readArrayLength(array); + return null; } @Override @@ -146,36 +144,33 @@ public JavaConstant readArrayElement(JavaConstant array, int index) { if (array.getJavaKind() != JavaKind.Object || array.isNull()) { return null; } - HostedValuesProvider hostedValuesProvider = universe.getHeapScanner().getHostedValuesProvider(); - if (array instanceof ImageHeapConstant) { - if (array instanceof ImageHeapArray heapArray) { - if (index < 0 || index >= heapArray.getLength()) { - return null; - } - heapArray.ensureReaderInstalled(); - return hostedValuesProvider.replaceObject(heapArray.readElementValue(index)); + VMError.guarantee(array instanceof ImageHeapConstant); + if (array instanceof ImageHeapArray heapArray) { + if (index < 0 || index >= heapArray.getLength()) { + return null; } - return null; + heapArray.ensureReaderInstalled(); + JavaConstant element = heapArray.readElementValue(index); + return validateArrayValue(element); } - JavaConstant element = super.readArrayElement(array, index); - return element == null ? null : hostedValuesProvider.replaceObject(element); + return null; } @Override public void forEachArrayElement(JavaConstant array, ObjIntConsumer consumer) { - HostedValuesProvider hostedValuesProvider = universe.getHeapScanner().getHostedValuesProvider(); - if (array instanceof ImageHeapConstant) { - if (array instanceof ImageHeapArray heapArray) { - heapArray.ensureReaderInstalled(); - for (int index = 0; index < heapArray.getLength(); index++) { - JavaConstant element = heapArray.readElementValue(index); - consumer.accept(hostedValuesProvider.replaceObject(element), index); - } + VMError.guarantee(array instanceof ImageHeapConstant); + if (array instanceof ImageHeapArray heapArray) { + heapArray.ensureReaderInstalled(); + for (int index = 0; index < heapArray.getLength(); index++) { + JavaConstant element = heapArray.readElementValue(index); + consumer.accept(validateArrayValue(element), index); } - return; } - /* Intercept the original consumer and apply object replacement. */ - super.forEachArrayElement(array, (element, index) -> consumer.accept(hostedValuesProvider.replaceObject(element), index)); + } + + private static JavaConstant validateArrayValue(JavaConstant value) { + VMError.guarantee(value.isNull() || value.getJavaKind().isPrimitive() || value instanceof RelocatableConstant || value instanceof ImageHeapConstant); + return value; } @Override From 4046ee12747a8b4e68675fb6beabecbe1c352d4b Mon Sep 17 00:00:00 2001 From: Codrut Stancu Date: Fri, 19 Jan 2024 18:05:46 +0100 Subject: [PATCH 561/593] AnalysisConstantReflectionProvider can implement ConstantReflectionProvider directly. --- .../AnalysisConstantReflectionProvider.java | 30 ++++++++++++++----- 1 file changed, 23 insertions(+), 7 deletions(-) diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/ameta/AnalysisConstantReflectionProvider.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/ameta/AnalysisConstantReflectionProvider.java index fa05c2a4d765..4e14f413c5ae 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/ameta/AnalysisConstantReflectionProvider.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/ameta/AnalysisConstantReflectionProvider.java @@ -45,7 +45,6 @@ import com.oracle.graal.pointsto.meta.AnalysisUniverse; import com.oracle.graal.pointsto.util.AnalysisError; import com.oracle.svm.core.FrameAccess; -import com.oracle.svm.core.graal.meta.SharedConstantReflectionProvider; import com.oracle.svm.core.hub.DynamicHub; import com.oracle.svm.core.meta.ObjectConstantEquality; import com.oracle.svm.core.meta.SubstrateObjectConstant; @@ -56,6 +55,7 @@ import jdk.graal.compiler.core.common.type.TypedConstant; import jdk.vm.ci.meta.Constant; +import jdk.vm.ci.meta.ConstantReflectionProvider; import jdk.vm.ci.meta.JavaConstant; import jdk.vm.ci.meta.JavaKind; import jdk.vm.ci.meta.MemoryAccessProvider; @@ -64,7 +64,7 @@ import jdk.vm.ci.meta.ResolvedJavaType; @Platforms(Platform.HOSTED_ONLY.class) -public class AnalysisConstantReflectionProvider extends SharedConstantReflectionProvider { +public class AnalysisConstantReflectionProvider implements ConstantReflectionProvider { private final AnalysisUniverse universe; protected final UniverseMetaAccess metaAccess; private final AnalysisMethodHandleAccessProvider methodHandleAccess; @@ -156,7 +156,6 @@ public JavaConstant readArrayElement(JavaConstant array, int index) { return null; } - @Override public void forEachArrayElement(JavaConstant array, ObjIntConsumer consumer) { VMError.guarantee(array instanceof ImageHeapConstant); if (array instanceof ImageHeapArray heapArray) { @@ -178,6 +177,11 @@ public JavaConstant readFieldValue(ResolvedJavaField field, JavaConstant receive return readValue((AnalysisField) field, receiver, false); } + @Override + public JavaConstant boxPrimitive(JavaConstant source) { + throw VMError.intentionallyUnimplemented(); + } + public JavaConstant readValue(AnalysisField field, JavaConstant receiver, boolean returnSimulatedValues) { if (!field.isStatic()) { if (receiver.isNull() || !field.getDeclaringClass().isAssignableFrom(((TypedConstant) receiver).getType(metaAccess))) { @@ -269,7 +273,16 @@ public AnalysisType asJavaType(Constant constant) { @Override public JavaConstant asJavaClass(ResolvedJavaType type) { - return universe.getHeapScanner().createImageHeapConstant(super.forObject(getHostVM().dynamicHub(type)), ObjectScanner.OtherReason.UNKNOWN); + return universe.getHeapScanner().createImageHeapConstant(asConstant(getHostVM().dynamicHub(type)), ObjectScanner.OtherReason.UNKNOWN); + } + + @Override + public Constant asObjectHub(ResolvedJavaType type) { + /* + * Substrate VM does not distinguish between the hub and the Class, they are both + * represented by the DynamicHub. + */ + return asJavaClass(type); } @Override @@ -277,10 +290,9 @@ public JavaConstant forString(String value) { if (value == null) { return JavaConstant.NULL_POINTER; } - return universe.getHeapScanner().createImageHeapConstant(super.forString(value), ObjectScanner.OtherReason.UNKNOWN); + return universe.getHeapScanner().createImageHeapConstant(asConstant(value), ObjectScanner.OtherReason.UNKNOWN); } - @Override public JavaConstant forObject(Object object) { validateRawObjectConstant(object); if (object instanceof RelocatedPointer pointer) { @@ -289,7 +301,11 @@ public JavaConstant forObject(Object object) { return JavaConstant.forIntegerKind(FrameAccess.getWordKind(), word.rawValue()); } /* Redirect constant lookup through the shadow heap. */ - return universe.getHeapScanner().createImageHeapConstant(super.forObject(object), ObjectScanner.OtherReason.UNKNOWN); + return universe.getHeapScanner().createImageHeapConstant(asConstant(object), ObjectScanner.OtherReason.UNKNOWN); + } + + private JavaConstant asConstant(Object object) { + return SubstrateObjectConstant.forObject(object); } /** From 5cfb68bae7d91c31b4c838fbf67e687591f5832b Mon Sep 17 00:00:00 2001 From: Codrut Stancu Date: Sat, 20 Jan 2024 14:22:02 +0100 Subject: [PATCH 562/593] Make HostedConstantReflectionProvider extend AnalysisConstantReflectionProvider. It was delegating most of its methods to it anyway. --- .../aarch64/SubstrateAArch64Backend.java | 12 ++-- .../amd64/AMD64CalleeSavedRegisters.java | 7 +- .../graal/amd64/SubstrateAMD64Backend.java | 11 +-- .../SharedConstantReflectionProvider.java | 4 +- .../AnalysisConstantReflectionProvider.java | 21 +++--- .../HostedRuntimeConfigurationBuilder.java | 3 +- .../HostedConstantReflectionProvider.java | 70 ++++--------------- 7 files changed, 44 insertions(+), 84 deletions(-) diff --git a/substratevm/src/com.oracle.svm.core.graal.aarch64/src/com/oracle/svm/core/graal/aarch64/SubstrateAArch64Backend.java b/substratevm/src/com.oracle.svm.core.graal.aarch64/src/com/oracle/svm/core/graal/aarch64/SubstrateAArch64Backend.java index 1665ea46e290..bbfc112d8334 100755 --- a/substratevm/src/com.oracle.svm.core.graal.aarch64/src/com/oracle/svm/core/graal/aarch64/SubstrateAArch64Backend.java +++ b/substratevm/src/com.oracle.svm.core.graal.aarch64/src/com/oracle/svm/core/graal/aarch64/SubstrateAArch64Backend.java @@ -170,6 +170,7 @@ import jdk.vm.ci.code.ValueUtil; import jdk.vm.ci.meta.AllocatableValue; import jdk.vm.ci.meta.Constant; +import jdk.vm.ci.meta.ConstantReflectionProvider; import jdk.vm.ci.meta.JavaConstant; import jdk.vm.ci.meta.JavaKind; import jdk.vm.ci.meta.JavaType; @@ -279,11 +280,11 @@ public static class SubstrateAArch64ComputedIndirectCallOp extends AArch64Call.M private final ComputedIndirectCallTargetNode.Computation[] addressComputation; private final LIRKindTool lirKindTool; - private final SharedConstantReflectionProvider constantReflection; + private final ConstantReflectionProvider constantReflection; public SubstrateAArch64ComputedIndirectCallOp(ResolvedJavaMethod callTarget, Value result, Value[] parameters, Value[] temps, Value addressBase, ComputedIndirectCallTargetNode.Computation[] addressComputation, - LIRFrameState state, Value exceptionTemp, LIRKindTool lirKindTool, SharedConstantReflectionProvider constantReflection) { + LIRFrameState state, Value exceptionTemp, LIRKindTool lirKindTool, ConstantReflectionProvider constantReflection) { super(TYPE, callTarget, result, parameters, temps, state); this.addressBase = this.addressBaseTemp = addressBase; this.exceptionTemp = exceptionTemp; @@ -356,8 +357,8 @@ public void emitCode(CompilationResultBuilder crb, AArch64MacroAssembler masm) { masm.add(64, addressScratch, ReservedRegisters.singleton().getHeapBaseRegister(), addressScratch, ShiftType.LSL, compressionShift); memoryAddress = masm.makeAddress(addressBitSize, addressScratch, field.getOffset(), immediateScratch); } else { - memoryAddress = masm.makeAddress(addressBitSize, ReservedRegisters.singleton().getHeapBaseRegister(), field.getOffset() + constantReflection.getImageHeapOffset(object), - immediateScratch); + memoryAddress = masm.makeAddress(addressBitSize, ReservedRegisters.singleton().getHeapBaseRegister(), field.getOffset() + + ((SharedConstantReflectionProvider) constantReflection).getImageHeapOffset(object), immediateScratch); } } else { @@ -778,8 +779,7 @@ protected void emitComputedIndirectCall(ComputedIndirectCallTargetNode callTarge gen.emitMove(addressBase, operand(callTarget.getAddressBase())); ResolvedJavaMethod targetMethod = callTarget.targetMethod(); append(new SubstrateAArch64ComputedIndirectCallOp(targetMethod, result, parameters, temps, addressBase, callTarget.getAddressComputation(), - callState, - getExceptionTemp(callTarget), gen.getLIRKindTool(), (SharedConstantReflectionProvider) getConstantReflection())); + callState, getExceptionTemp(callTarget), gen.getLIRKindTool(), getConstantReflection())); } private AllocatableValue setupJavaFrameAnchor(CallTargetNode callTarget) { diff --git a/substratevm/src/com.oracle.svm.core.graal.amd64/src/com/oracle/svm/core/graal/amd64/AMD64CalleeSavedRegisters.java b/substratevm/src/com.oracle.svm.core.graal.amd64/src/com/oracle/svm/core/graal/amd64/AMD64CalleeSavedRegisters.java index 59651a761efe..4cf3ed21d0f1 100644 --- a/substratevm/src/com.oracle.svm.core.graal.amd64/src/com/oracle/svm/core/graal/amd64/AMD64CalleeSavedRegisters.java +++ b/substratevm/src/com.oracle.svm.core.graal.amd64/src/com/oracle/svm/core/graal/amd64/AMD64CalleeSavedRegisters.java @@ -74,6 +74,7 @@ import jdk.vm.ci.amd64.AMD64Kind; import jdk.vm.ci.code.Register; import jdk.vm.ci.code.Register.RegisterCategory; +import jdk.vm.ci.meta.ConstantReflectionProvider; import jdk.vm.ci.meta.JavaConstant; import jdk.vm.ci.meta.ResolvedJavaField; @@ -460,7 +461,7 @@ private AMD64Address getFeatureMapAddress() { GraalError.guarantee(ConfigurationValues.getTarget().inlineObjects, "Dynamic feature check for callee saved registers requires inlined objects"); Register heapBase = ReservedRegisters.singleton().getHeapBaseRegister(); GraalError.guarantee(heapBase != null, "Heap base register must not be null"); - return new AMD64Address(heapBase, Register.None, Stride.S1, displacement(object, (SharedConstantReflectionProvider) crb.getConstantReflection()) + fieldOffset, + return new AMD64Address(heapBase, Register.None, Stride.S1, displacement(object, crb.getConstantReflection()) + fieldOffset, displacementAnnotation(object)); } @@ -487,7 +488,7 @@ private Object displacementAnnotation(JavaConstant constant) { } @Platforms(Platform.HOSTED_ONLY.class) - private int displacement(JavaConstant constant, SharedConstantReflectionProvider constantReflection) { + private int displacement(JavaConstant constant, ConstantReflectionProvider constantReflection) { if (SubstrateUtil.HOSTED) { return 0; } else { @@ -496,7 +497,7 @@ private int displacement(JavaConstant constant, SharedConstantReflectionProvider * offset of the constant can be emitted immediately. No patching is required later * on. */ - return constantReflection.getImageHeapOffset(constant); + return ((SharedConstantReflectionProvider) constantReflection).getImageHeapOffset(constant); } } } diff --git a/substratevm/src/com.oracle.svm.core.graal.amd64/src/com/oracle/svm/core/graal/amd64/SubstrateAMD64Backend.java b/substratevm/src/com.oracle.svm.core.graal.amd64/src/com/oracle/svm/core/graal/amd64/SubstrateAMD64Backend.java index b9969cbb5cc0..71070a729bef 100644 --- a/substratevm/src/com.oracle.svm.core.graal.amd64/src/com/oracle/svm/core/graal/amd64/SubstrateAMD64Backend.java +++ b/substratevm/src/com.oracle.svm.core.graal.amd64/src/com/oracle/svm/core/graal/amd64/SubstrateAMD64Backend.java @@ -192,6 +192,7 @@ import jdk.vm.ci.code.ValueUtil; import jdk.vm.ci.meta.AllocatableValue; import jdk.vm.ci.meta.Constant; +import jdk.vm.ci.meta.ConstantReflectionProvider; import jdk.vm.ci.meta.JavaConstant; import jdk.vm.ci.meta.JavaKind; import jdk.vm.ci.meta.JavaType; @@ -344,11 +345,11 @@ public static class SubstrateAMD64ComputedIndirectCallOp extends AMD64Call.Metho @Temp({REG, OperandFlag.ILLEGAL}) private AllocatableValue cfiTargetRegister; private final Computation[] addressComputation; private final LIRKindTool lirKindTool; - private final SharedConstantReflectionProvider constantReflection; + private final ConstantReflectionProvider constantReflection; public SubstrateAMD64ComputedIndirectCallOp(ResolvedJavaMethod callTarget, Value result, Value[] parameters, Value[] temps, Value addressBase, Computation[] addressComputation, - LIRFrameState state, Value exceptionTemp, LIRKindTool lirKindTool, SharedConstantReflectionProvider constantReflection) { + LIRFrameState state, Value exceptionTemp, LIRKindTool lirKindTool, ConstantReflectionProvider constantReflection) { super(TYPE, callTarget, result, parameters, temps, state); this.addressBase = this.addressBaseTemp = addressBase; this.exceptionTemp = exceptionTemp; @@ -456,7 +457,7 @@ public static Object addressDisplacementAnnotation(JavaConstant constant) { } } - public static int addressDisplacement(JavaConstant constant, SharedConstantReflectionProvider constantReflection) { + public static int addressDisplacement(JavaConstant constant, ConstantReflectionProvider constantReflection) { if (SubstrateUtil.HOSTED) { return 0; } else { @@ -464,7 +465,7 @@ public static int addressDisplacement(JavaConstant constant, SharedConstantRefle * For JIT compilation at run time, the image heap is known and immutable, so the offset * of the constant can be emitted immediately. No patching is required later on. */ - return constantReflection.getImageHeapOffset(constant); + return ((SharedConstantReflectionProvider) constantReflection).getImageHeapOffset(constant); } } @@ -1017,7 +1018,7 @@ protected void emitComputedIndirectCall(ComputedIndirectCallTargetNode callTarge ResolvedJavaMethod targetMethod = callTarget.targetMethod(); vzeroupperBeforeCall((SubstrateAMD64LIRGenerator) getLIRGeneratorTool(), parameters, callState, (SharedMethod) targetMethod); append(new SubstrateAMD64ComputedIndirectCallOp(targetMethod, result, parameters, temps, addressBase, callTarget.getAddressComputation(), callState, - getExceptionTemp(callTarget), gen.getLIRKindTool(), (SharedConstantReflectionProvider) getConstantReflection())); + getExceptionTemp(callTarget), gen.getLIRKindTool(), getConstantReflection())); } private AllocatableValue setupJavaFrameAnchor(CallTargetNode callTarget) { diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/graal/meta/SharedConstantReflectionProvider.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/graal/meta/SharedConstantReflectionProvider.java index 2d4288ad4899..bdf0f8476d98 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/graal/meta/SharedConstantReflectionProvider.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/graal/meta/SharedConstantReflectionProvider.java @@ -145,7 +145,5 @@ public final Constant asObjectHub(ResolvedJavaType type) { return asJavaClass(type); } - public int getImageHeapOffset(@SuppressWarnings("unused") JavaConstant constant) { - throw VMError.shouldNotReachHere("Can only be used during JIT compilation at run time: " + getClass().getName()); - } + public abstract int getImageHeapOffset(JavaConstant constant); } diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/ameta/AnalysisConstantReflectionProvider.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/ameta/AnalysisConstantReflectionProvider.java index 4e14f413c5ae..f4876cc637bb 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/ameta/AnalysisConstantReflectionProvider.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/ameta/AnalysisConstantReflectionProvider.java @@ -254,23 +254,28 @@ private JavaConstant readSimulatedValue(AnalysisField field) { } @Override - public AnalysisType asJavaType(Constant constant) { + public ResolvedJavaType asJavaType(Constant constant) { if (constant instanceof SubstrateObjectConstant substrateConstant) { - Object obj = universe.getSnippetReflection().asObject(Object.class, substrateConstant); - if (obj instanceof DynamicHub hub) { - return getHostVM().lookupType(hub); - } else if (obj instanceof Class) { - throw VMError.shouldNotReachHere("Must not have java.lang.Class object: " + obj); - } + return extractJavaType(substrateConstant); } else if (constant instanceof ImageHeapConstant imageHeapConstant) { if (metaAccess.isInstanceOf((JavaConstant) constant, Class.class)) { /* All constants of type DynamicHub/java.lang.Class must have a hosted object. */ - return asJavaType(Objects.requireNonNull(imageHeapConstant.getHostedObject())); + return extractJavaType(Objects.requireNonNull(imageHeapConstant.getHostedObject())); } } return null; } + private ResolvedJavaType extractJavaType(JavaConstant constant) { + Object obj = universe.getSnippetReflection().asObject(Object.class, constant); + if (obj instanceof DynamicHub hub) { + return getHostVM().lookupType(hub); + } else if (obj instanceof Class) { + throw VMError.shouldNotReachHere("Must not have java.lang.Class object: " + obj); + } + return null; + } + @Override public JavaConstant asJavaClass(ResolvedJavaType type) { return universe.getHeapScanner().createImageHeapConstant(asConstant(getHostVM().dynamicHub(type)), ObjectScanner.OtherReason.UNKNOWN); diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/code/HostedRuntimeConfigurationBuilder.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/code/HostedRuntimeConfigurationBuilder.java index 24eaaefe2e6c..168bad0e2b3c 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/code/HostedRuntimeConfigurationBuilder.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/code/HostedRuntimeConfigurationBuilder.java @@ -30,7 +30,6 @@ import com.oracle.svm.core.graal.code.SubstratePlatformConfigurationProvider; import com.oracle.svm.core.graal.meta.SubstrateLoweringProvider; import com.oracle.svm.hosted.SVMHost; -import com.oracle.svm.hosted.ameta.AnalysisConstantReflectionProvider; import com.oracle.svm.hosted.classinitialization.ClassInitializationSupport; import com.oracle.svm.hosted.meta.HostedConstantFieldProvider; import com.oracle.svm.hosted.meta.HostedConstantReflectionProvider; @@ -78,7 +77,7 @@ protected Providers createProviders(CodeCacheProvider codeCache, ConstantReflect @Override protected ConstantReflectionProvider createConstantReflectionProvider() { - return new HostedConstantReflectionProvider(hostVM, (AnalysisConstantReflectionProvider) analysisProviders.getConstantReflection(), universe, (HostedMetaAccess) metaAccess); + return new HostedConstantReflectionProvider(universe, (HostedMetaAccess) metaAccess); } @Override diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/meta/HostedConstantReflectionProvider.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/meta/HostedConstantReflectionProvider.java index 76fa3d0cd378..5a1d4dcb3552 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/meta/HostedConstantReflectionProvider.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/meta/HostedConstantReflectionProvider.java @@ -24,104 +24,55 @@ */ package com.oracle.svm.hosted.meta; -import java.util.function.ObjIntConsumer; +import static com.oracle.svm.core.util.VMError.shouldNotReachHereAtRuntime; import org.graalvm.nativeimage.Platform; import org.graalvm.nativeimage.Platforms; -import com.oracle.svm.core.graal.meta.SharedConstantReflectionProvider; import com.oracle.svm.core.hub.DynamicHub; -import com.oracle.svm.hosted.SVMHost; import com.oracle.svm.hosted.ameta.AnalysisConstantReflectionProvider; import jdk.vm.ci.meta.Constant; import jdk.vm.ci.meta.JavaConstant; import jdk.vm.ci.meta.MemoryAccessProvider; +import jdk.vm.ci.meta.MethodHandleAccessProvider; import jdk.vm.ci.meta.ResolvedJavaField; import jdk.vm.ci.meta.ResolvedJavaType; @Platforms(Platform.HOSTED_ONLY.class) -public class HostedConstantReflectionProvider extends SharedConstantReflectionProvider { - private final SVMHost hostVM; - private final AnalysisConstantReflectionProvider aConstantReflection; +public class HostedConstantReflectionProvider extends AnalysisConstantReflectionProvider { private final HostedUniverse hUniverse; private final HostedMetaAccess hMetaAccess; private final HostedMemoryAccessProvider hMemoryAccess; @SuppressWarnings("this-escape") - public HostedConstantReflectionProvider(SVMHost hostVM, AnalysisConstantReflectionProvider aConstantReflection, HostedUniverse hUniverse, HostedMetaAccess hMetaAccess) { - this.hostVM = hostVM; - this.aConstantReflection = aConstantReflection; + public HostedConstantReflectionProvider(HostedUniverse hUniverse, HostedMetaAccess hMetaAccess) { + super(hUniverse.getBigBang().getUniverse(), hUniverse.getBigBang().getMetaAccess()); this.hUniverse = hUniverse; this.hMetaAccess = hMetaAccess; this.hMemoryAccess = new HostedMemoryAccessProvider(hMetaAccess, this); } - @Override - public Boolean constantEquals(Constant x, Constant y) { - /* Delegate to the AnalysisConstantReflectionProvider. */ - return aConstantReflection.constantEquals(x, y); - } - @Override public MemoryAccessProvider getMemoryAccessProvider() { return hMemoryAccess; } - @Override - public JavaConstant unboxPrimitive(JavaConstant source) { - /* Delegate to the AnalysisConstantReflectionProvider. */ - return aConstantReflection.unboxPrimitive(source); - } - @Override public ResolvedJavaType asJavaType(Constant constant) { - /* Delegate to the AnalysisConstantReflectionProvider. */ - return hUniverse.lookup(aConstantReflection.asJavaType(constant)); + return hUniverse.lookup(super.asJavaType(constant)); } @Override public JavaConstant asJavaClass(ResolvedJavaType type) { - return aConstantReflection.asJavaClass(((HostedType) type).wrapped); - } - - @Override - public Integer readArrayLength(JavaConstant array) { - /* Delegate to the AnalysisConstantReflectionProvider. */ - return aConstantReflection.readArrayLength(array); - } - - @Override - public JavaConstant readArrayElement(JavaConstant array, int index) { - /* Delegate to the AnalysisConstantReflectionProvider. */ - return aConstantReflection.readArrayElement(array, index); - } - - @Override - public void forEachArrayElement(JavaConstant array, ObjIntConsumer consumer) { - /* Delegate to the AnalysisConstantReflectionProvider. */ - aConstantReflection.forEachArrayElement(array, consumer); + return super.asJavaClass(((HostedType) type).wrapped); } @Override public JavaConstant readFieldValue(ResolvedJavaField field, JavaConstant receiver) { var hField = (HostedField) field; assert checkHub(receiver) : "Receiver " + receiver + " of field " + hField + " read should not be java.lang.Class. Expecting to see DynamicHub here."; - return aConstantReflection.readValue(hField.getWrapped(), receiver, true); - } - - public AnalysisConstantReflectionProvider getWrappedConstantReflection() { - return aConstantReflection; - } - - @Override - public JavaConstant forString(String value) { - return aConstantReflection.forString(value); - } - - @Override - protected JavaConstant forObject(Object object) { - return aConstantReflection.forObject(object); + return super.readValue(hField.getWrapped(), receiver, true); } private boolean checkHub(JavaConstant constant) { @@ -131,4 +82,9 @@ private boolean checkHub(JavaConstant constant) { } return true; } + + @Override + public MethodHandleAccessProvider getMethodHandleAccess() { + throw shouldNotReachHereAtRuntime(); // ExcludeFromJacocoGeneratedReport + } } From c9bc676d5e5dd98fc91379e1f352f4cb6f4ba9ee Mon Sep 17 00:00:00 2001 From: Codrut Stancu Date: Fri, 19 Jan 2024 22:20:11 +0100 Subject: [PATCH 563/593] AnalysisConstantReflectionProvider doesn't need to deal with SubstrateObjectConstant equality. Refactor expected value check. --- .../pointsto/heap/HeapSnapshotVerifier.java | 2 +- .../AnalysisConstantReflectionProvider.java | 21 +++++++++---------- 2 files changed, 11 insertions(+), 12 deletions(-) diff --git a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/heap/HeapSnapshotVerifier.java b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/heap/HeapSnapshotVerifier.java index 7c5fad923143..cb6f52a5c68a 100644 --- a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/heap/HeapSnapshotVerifier.java +++ b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/heap/HeapSnapshotVerifier.java @@ -277,7 +277,7 @@ public static boolean patchPrimitiveArrayValue(BigBang bb, JavaConstant snapshot Object newValueArray = constantAsObject(bb, newValue); if (!Objects.deepEquals(snapshotArray, newValueArray)) { /* Guarantee that the shadowed constant and the hosted constant are the same. */ - AnalysisError.guarantee(bb.getConstantReflectionProvider().constantEquals(snapshot, newValue)); + AnalysisError.guarantee(((ImageHeapPrimitiveArray) snapshot).getHostedObject().equals(newValue)); Integer length = bb.getUniverse().getHeapScanner().getHostedValuesProvider().readArrayLength(newValue); /* Since the shadowed constant didn't change, the length should match. */ System.arraycopy(newValueArray, 0, snapshotArray, 0, length); diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/ameta/AnalysisConstantReflectionProvider.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/ameta/AnalysisConstantReflectionProvider.java index f4876cc637bb..6c198dd23f1d 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/ameta/AnalysisConstantReflectionProvider.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/ameta/AnalysisConstantReflectionProvider.java @@ -46,7 +46,6 @@ import com.oracle.graal.pointsto.util.AnalysisError; import com.oracle.svm.core.FrameAccess; import com.oracle.svm.core.hub.DynamicHub; -import com.oracle.svm.core.meta.ObjectConstantEquality; import com.oracle.svm.core.meta.SubstrateObjectConstant; import com.oracle.svm.core.util.VMError; import com.oracle.svm.hosted.SVMHost; @@ -79,14 +78,10 @@ public AnalysisConstantReflectionProvider(AnalysisUniverse universe, UniverseMet @Override public Boolean constantEquals(Constant x, Constant y) { + VMError.guarantee(!(x instanceof JavaConstant constant) || isExpectedJavaConstant(constant)); + VMError.guarantee(!(y instanceof JavaConstant constant) || isExpectedJavaConstant(constant)); if (x == y) { return true; - } else if (x instanceof SubstrateObjectConstant && y instanceof SubstrateObjectConstant) { - return ObjectConstantEquality.get().test((SubstrateObjectConstant) x, (SubstrateObjectConstant) y); - } else if (x instanceof ImageHeapConstant cx && cx.isBackedByHostedObject() && y instanceof SubstrateObjectConstant) { - return ObjectConstantEquality.get().test((SubstrateObjectConstant) cx.getHostedObject(), (SubstrateObjectConstant) y); - } else if (y instanceof ImageHeapConstant cy && cy.isBackedByHostedObject() && x instanceof SubstrateObjectConstant) { - return ObjectConstantEquality.get().test((SubstrateObjectConstant) cy.getHostedObject(), (SubstrateObjectConstant) x); } else { return x.equals(y); } @@ -151,7 +146,7 @@ public JavaConstant readArrayElement(JavaConstant array, int index) { } heapArray.ensureReaderInstalled(); JavaConstant element = heapArray.readElementValue(index); - return validateArrayValue(element); + return checkExpectedValue(element); } return null; } @@ -162,16 +157,20 @@ public void forEachArrayElement(JavaConstant array, ObjIntConsumer heapArray.ensureReaderInstalled(); for (int index = 0; index < heapArray.getLength(); index++) { JavaConstant element = heapArray.readElementValue(index); - consumer.accept(validateArrayValue(element), index); + consumer.accept(checkExpectedValue(element), index); } } } - private static JavaConstant validateArrayValue(JavaConstant value) { - VMError.guarantee(value.isNull() || value.getJavaKind().isPrimitive() || value instanceof RelocatableConstant || value instanceof ImageHeapConstant); + private static JavaConstant checkExpectedValue(JavaConstant value) { + VMError.guarantee(isExpectedJavaConstant(value)); return value; } + private static boolean isExpectedJavaConstant(JavaConstant value) { + return value.isNull() || value.getJavaKind().isPrimitive() || value instanceof RelocatableConstant || value instanceof ImageHeapConstant; + } + @Override public JavaConstant readFieldValue(ResolvedJavaField field, JavaConstant receiver) { return readValue((AnalysisField) field, receiver, false); From aa3d125ab5365baf5cf3c540c2c0a7777f29130e Mon Sep 17 00:00:00 2001 From: Codrut Stancu Date: Sat, 20 Jan 2024 12:29:40 +0100 Subject: [PATCH 564/593] Remove HostedLookupReflectionProvider. --- .../pointsto/standalone/PointsToAnalyzer.java | 2 +- .../oracle/graal/pointsto/ObjectScanner.java | 4 +- .../pointsto/heap/HostedValuesProvider.java | 12 +++- .../graal/pointsto/heap/ImageHeapScanner.java | 4 +- .../graal/pointsto/meta/AnalysisUniverse.java | 15 +++-- .../svm/hosted/NativeImageGenerator.java | 4 +- .../AnalysisConstantReflectionProvider.java | 2 +- .../AnalysisMethodHandleAccessProvider.java | 4 +- .../hosted/ameta/SVMHostedValueProvider.java | 37 +++++++---- ...HostedLookupSnippetReflectionProvider.java | 65 ------------------- 10 files changed, 51 insertions(+), 98 deletions(-) delete mode 100644 substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/meta/HostedLookupSnippetReflectionProvider.java diff --git a/substratevm/src/com.oracle.graal.pointsto.standalone/src/com/oracle/graal/pointsto/standalone/PointsToAnalyzer.java b/substratevm/src/com.oracle.graal.pointsto.standalone/src/com/oracle/graal/pointsto/standalone/PointsToAnalyzer.java index e480627f4917..4d4f2eabc187 100644 --- a/substratevm/src/com.oracle.graal.pointsto.standalone/src/com/oracle/graal/pointsto/standalone/PointsToAnalyzer.java +++ b/substratevm/src/com.oracle.graal.pointsto.standalone/src/com/oracle/graal/pointsto/standalone/PointsToAnalyzer.java @@ -142,7 +142,7 @@ private PointsToAnalyzer(String mainEntryClass, OptionValues options) { JavaKind wordKind = JavaKind.fromWordSize(wordSize); AnalysisUniverse aUniverse = new AnalysisUniverse(standaloneHost, wordKind, - analysisPolicy, SubstitutionProcessor.IDENTITY, originalMetaAccess, snippetReflection, new PointsToAnalysisFactory(), new StandaloneAnnotationExtractor()); + analysisPolicy, SubstitutionProcessor.IDENTITY, originalMetaAccess, new PointsToAnalysisFactory(), new StandaloneAnnotationExtractor()); AnalysisMetaAccess aMetaAccess = new StandaloneAnalysisMetaAccess(aUniverse, originalMetaAccess); StandaloneConstantReflectionProvider aConstantReflection = new StandaloneConstantReflectionProvider(aUniverse, HotSpotJVMCIRuntime.runtime()); StandaloneConstantFieldProvider aConstantFieldProvider = new StandaloneConstantFieldProvider(aMetaAccess); diff --git a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/ObjectScanner.java b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/ObjectScanner.java index aaf64921e0a8..34405dfdf7bd 100644 --- a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/ObjectScanner.java +++ b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/ObjectScanner.java @@ -267,10 +267,10 @@ protected final void scanArray(JavaConstant array, ScanReason prevReason) { scanningObserver.forNullArrayElement(array, arrayType, idx, reason); } else { try { - JavaConstant element = bb.getUniverse().getSnippetReflection().forObject(bb.getUniverse().replaceObject(e)); + JavaConstant element = bb.getUniverse().getHostedValuesProvider().forObject(bb.getUniverse().replaceObject(e)); scanArrayElement(array, arrayType, reason, idx, element); } catch (UnsupportedFeatureException | AnalysisError.TypeNotFoundError ex) { - unsupportedFeatureDuringConstantScan(bb, bb.getUniverse().getSnippetReflection().forObject(e), ex, reason); + unsupportedFeatureDuringConstantScan(bb, bb.getUniverse().getHostedValuesProvider().forObject(e), ex, reason); } } } diff --git a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/heap/HostedValuesProvider.java b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/heap/HostedValuesProvider.java index b90dccfe0e6f..84af4ab56eff 100644 --- a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/heap/HostedValuesProvider.java +++ b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/heap/HostedValuesProvider.java @@ -75,10 +75,10 @@ public JavaConstant replaceObject(JavaConstant value) { return value; } if (value.getJavaKind() == JavaKind.Object) { - Object oldObject = universe.getSnippetReflection().asObject(Object.class, value); + Object oldObject = asObject(Object.class, value); Object newObject = universe.replaceObject(oldObject); if (newObject != oldObject) { - return validateReplacedConstant(universe.getSnippetReflection().forObject(newObject)); + return validateReplacedConstant(forObject(newObject)); } } return value; @@ -89,4 +89,12 @@ public JavaConstant validateReplacedConstant(JavaConstant value) { return value; } + public JavaConstant forObject(Object object) { + return GraalAccess.getOriginalProviders().getSnippetReflection().forObject(object); + } + + public T asObject(Class type, JavaConstant constant) { + return GraalAccess.getOriginalProviders().getSnippetReflection().asObject(type, constant); + } + } diff --git a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/heap/ImageHeapScanner.java b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/heap/ImageHeapScanner.java index ed069405937f..73f5b929e27d 100644 --- a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/heap/ImageHeapScanner.java +++ b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/heap/ImageHeapScanner.java @@ -339,7 +339,7 @@ private Optional maybeReplace(JavaConstant constant, ScanReason re try { Object replaced = universe.replaceObject(unwrapped); if (replaced != unwrapped) { - return Optional.of(hostedValuesProvider.validateReplacedConstant(universe.getSnippetReflection().forObject(replaced))); + return Optional.of(hostedValuesProvider.validateReplacedConstant(universe.getHostedValuesProvider().forObject(replaced))); } } catch (UnsupportedFeatureException e) { /* Enhance the unsupported feature message with the object trace and rethrow. */ @@ -735,7 +735,7 @@ protected Object asObject(JavaConstant constant) { } private JavaConstant asConstant(Object object) { - return universe.getSnippetReflection().forObject(object); + return hostedValuesProvider.forObject(object); } public void cleanupAfterAnalysis() { diff --git a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/meta/AnalysisUniverse.java b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/meta/AnalysisUniverse.java index 285b97891da2..beae4a362320 100644 --- a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/meta/AnalysisUniverse.java +++ b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/meta/AnalysisUniverse.java @@ -47,6 +47,7 @@ import com.oracle.graal.pointsto.api.HostVM; import com.oracle.graal.pointsto.constraints.UnsupportedFeatureException; import com.oracle.graal.pointsto.heap.HeapSnapshotVerifier; +import com.oracle.graal.pointsto.heap.HostedValuesProvider; import com.oracle.graal.pointsto.heap.ImageHeapConstant; import com.oracle.graal.pointsto.heap.ImageHeapScanner; import com.oracle.graal.pointsto.infrastructure.AnalysisConstantPool; @@ -115,7 +116,6 @@ public class AnalysisUniverse implements Universe { private SubstitutionProcessor[] featureNativeSubstitutions; private final MetaAccessProvider originalMetaAccess; - private final SnippetReflectionProvider snippetReflection; private final AnalysisFactory analysisFactory; private final AnnotationExtractor annotationExtractor; @@ -136,13 +136,12 @@ public JavaKind getWordKind() { @SuppressWarnings("unchecked") public AnalysisUniverse(HostVM hostVM, JavaKind wordKind, AnalysisPolicy analysisPolicy, SubstitutionProcessor substitutions, MetaAccessProvider originalMetaAccess, - SnippetReflectionProvider snippetReflection, AnalysisFactory analysisFactory, AnnotationExtractor annotationExtractor) { + AnalysisFactory analysisFactory, AnnotationExtractor annotationExtractor) { this.hostVM = hostVM; this.wordKind = wordKind; this.analysisPolicy = analysisPolicy; this.substitutions = substitutions; this.originalMetaAccess = originalMetaAccess; - this.snippetReflection = snippetReflection; this.analysisFactory = analysisFactory; this.annotationExtractor = annotationExtractor; @@ -505,7 +504,7 @@ public JavaConstant fromHosted(JavaConstant constant) { */ return (JavaConstant) original; } - return snippetReflection.forObject(original); + return heapScanner.getHostedValuesProvider().forObject(original); } else { return constant; } @@ -518,7 +517,7 @@ public JavaConstant toHosted(JavaConstant constant) { if (constant == null) { return null; } else if (constant.getJavaKind().isObject() && !constant.isNull()) { - return GraalAccess.getOriginalSnippetReflection().forObject(snippetReflection.asObject(Object.class, constant)); + return GraalAccess.getOriginalSnippetReflection().forObject(heapScanner.getHostedValuesProvider().asObject(Object.class, constant)); } else { return constant; } @@ -672,7 +671,7 @@ public static Set reachableSubtypes(AnalysisType baseType) { @Override public SnippetReflectionProvider getSnippetReflection() { - return snippetReflection; + return bb.getSnippetReflectionProvider(); } @Override @@ -740,6 +739,10 @@ public ImageHeapScanner getHeapScanner() { return heapScanner; } + public HostedValuesProvider getHostedValuesProvider() { + return heapScanner.getHostedValuesProvider(); + } + public void setHeapVerifier(HeapSnapshotVerifier heapVerifier) { this.heapVerifier = heapVerifier; } diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/NativeImageGenerator.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/NativeImageGenerator.java index 2f70fed908d5..d544725bf86d 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/NativeImageGenerator.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/NativeImageGenerator.java @@ -235,7 +235,6 @@ import com.oracle.svm.hosted.meta.HostedConstantReflectionProvider; import com.oracle.svm.hosted.meta.HostedField; import com.oracle.svm.hosted.meta.HostedInterface; -import com.oracle.svm.hosted.meta.HostedLookupSnippetReflectionProvider; import com.oracle.svm.hosted.meta.HostedMetaAccess; import com.oracle.svm.hosted.meta.HostedMethod; import com.oracle.svm.hosted.meta.HostedSnippetReflectionProvider; @@ -1041,8 +1040,7 @@ public static AnalysisUniverse createAnalysisUniverse(OptionValues options, Targ analysisFactory = new PointsToAnalysisFactory(); } SubstrateAnnotationExtractor annotationExtractor = (SubstrateAnnotationExtractor) loader.classLoaderSupport.annotationExtractor; - HostedLookupSnippetReflectionProvider snippetReflection = new HostedLookupSnippetReflectionProvider(new SubstrateWordTypes(originalMetaAccess, FrameAccess.getWordKind())); - return new AnalysisUniverse(hostVM, target.wordJavaKind, analysisPolicy, aSubstitutions, originalMetaAccess, snippetReflection, analysisFactory, annotationExtractor); + return new AnalysisUniverse(hostVM, target.wordJavaKind, analysisPolicy, aSubstitutions, originalMetaAccess, analysisFactory, annotationExtractor); } public static AnnotationSubstitutionProcessor createAnnotationSubstitutionProcessor(MetaAccessProvider originalMetaAccess, ImageClassLoader loader, diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/ameta/AnalysisConstantReflectionProvider.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/ameta/AnalysisConstantReflectionProvider.java index 6c198dd23f1d..b36018acf1cb 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/ameta/AnalysisConstantReflectionProvider.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/ameta/AnalysisConstantReflectionProvider.java @@ -266,7 +266,7 @@ public ResolvedJavaType asJavaType(Constant constant) { } private ResolvedJavaType extractJavaType(JavaConstant constant) { - Object obj = universe.getSnippetReflection().asObject(Object.class, constant); + Object obj = universe.getHostedValuesProvider().asObject(Object.class, constant); if (obj instanceof DynamicHub hub) { return getHostVM().lookupType(hub); } else if (obj instanceof Class) { diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/ameta/AnalysisMethodHandleAccessProvider.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/ameta/AnalysisMethodHandleAccessProvider.java index 7945ff8f4654..963a6c768652 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/ameta/AnalysisMethodHandleAccessProvider.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/ameta/AnalysisMethodHandleAccessProvider.java @@ -24,7 +24,6 @@ */ package com.oracle.svm.hosted.ameta; -import jdk.graal.compiler.api.replacements.SnippetReflectionProvider; import org.graalvm.nativeimage.Platform; import org.graalvm.nativeimage.Platforms; @@ -36,6 +35,7 @@ import com.oracle.graal.pointsto.meta.AnalysisUniverse; import com.oracle.graal.pointsto.util.GraalAccess; +import jdk.graal.compiler.api.replacements.SnippetReflectionProvider; import jdk.vm.ci.meta.JavaConstant; import jdk.vm.ci.meta.MethodHandleAccessProvider; import jdk.vm.ci.meta.ResolvedJavaMethod; @@ -94,7 +94,7 @@ private JavaConstant toOriginalConstant(JavaConstant c) { if (constant == null) { return null; } - Object obj = analysisUniverse.getSnippetReflection().asObject(Object.class, constant); + Object obj = analysisUniverse.getHostedValuesProvider().asObject(Object.class, constant); return originalSnippetReflection.forObject(obj); } } diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/ameta/SVMHostedValueProvider.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/ameta/SVMHostedValueProvider.java index 4aa9a6223b0e..5c153733441a 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/ameta/SVMHostedValueProvider.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/ameta/SVMHostedValueProvider.java @@ -38,7 +38,6 @@ import com.oracle.svm.core.util.VMError; import com.oracle.svm.hosted.classinitialization.ClassInitializationSupport; import com.oracle.svm.hosted.classinitialization.SimulateClassInitializerSupport; -import com.oracle.svm.hosted.meta.HostedLookupSnippetReflectionProvider; import com.oracle.svm.hosted.meta.RelocatableConstant; import jdk.vm.ci.meta.JavaConstant; @@ -114,16 +113,6 @@ public JavaConstant readArrayElement(JavaConstant array, int index) { } } - private JavaConstant forObject(Object object) { - AnalysisConstantReflectionProvider.validateRawObjectConstant(object); - if (object instanceof RelocatedPointer pointer) { - return new RelocatableConstant(pointer); - } else if (object instanceof WordBase word) { - return JavaConstant.forIntegerKind(FrameAccess.getWordKind(), word.rawValue()); - } - return SubstrateObjectConstant.forObject(object); - } - @Override public Integer readArrayLength(JavaConstant array) { if (array.getJavaKind() != JavaKind.Object || array.isNull()) { @@ -137,13 +126,33 @@ public Integer readArrayLength(JavaConstant array) { } /** - * {@link HostedLookupSnippetReflectionProvider} replaces relocatable pointers with - * {@link RelocatableConstant} and regular {@link WordBase} values with - * {@link PrimitiveConstant}. No other {@link WordBase} values can be reachable at this point. + * {@link #forObject} replaces relocatable pointers with {@link RelocatableConstant} and regular + * {@link WordBase} values with {@link PrimitiveConstant}. No other {@link WordBase} values can + * be reachable at this point. */ @Override public JavaConstant validateReplacedConstant(JavaConstant value) { VMError.guarantee(value instanceof RelocatableConstant || !universe.getBigbang().getMetaAccess().isInstanceOf(value, WordBase.class)); return value; } + + @Override + public JavaConstant forObject(Object object) { + if (object instanceof RelocatedPointer pointer) { + return new RelocatableConstant(pointer); + } else if (object instanceof WordBase word) { + return JavaConstant.forIntegerKind(FrameAccess.getWordKind(), word.rawValue()); + } + AnalysisConstantReflectionProvider.validateRawObjectConstant(object); + return SubstrateObjectConstant.forObject(object); + } + + @Override + public T asObject(Class type, JavaConstant constant) { + if (constant instanceof RelocatableConstant relocatable) { + return type.cast(relocatable.getPointer()); + } + return SubstrateObjectConstant.asObject(type, constant); + } + } diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/meta/HostedLookupSnippetReflectionProvider.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/meta/HostedLookupSnippetReflectionProvider.java deleted file mode 100644 index 5de9690835ab..000000000000 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/meta/HostedLookupSnippetReflectionProvider.java +++ /dev/null @@ -1,65 +0,0 @@ -/* - * Copyright (c) 2023, 2023, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.oracle.svm.hosted.meta; - -import jdk.graal.compiler.word.WordTypes; -import org.graalvm.nativeimage.c.function.RelocatedPointer; -import org.graalvm.word.WordBase; - -import com.oracle.svm.core.FrameAccess; -import com.oracle.svm.core.graal.meta.SubstrateSnippetReflectionProvider; -import com.oracle.svm.hosted.ameta.AnalysisConstantReflectionProvider; - -import jdk.vm.ci.meta.JavaConstant; - -/** - * The snippet reflection provider that acts as the interface between the Native Image builder and - * the hosting VM. - */ -public class HostedLookupSnippetReflectionProvider extends SubstrateSnippetReflectionProvider { - - public HostedLookupSnippetReflectionProvider(WordTypes wordTypes) { - super(wordTypes); - } - - @Override - public JavaConstant forObject(Object object) { - if (object instanceof RelocatedPointer pointer) { - return new RelocatableConstant(pointer); - } else if (object instanceof WordBase word) { - return JavaConstant.forIntegerKind(FrameAccess.getWordKind(), word.rawValue()); - } - AnalysisConstantReflectionProvider.validateRawObjectConstant(object); - return super.forObject(object); - } - - @Override - public T asObject(Class type, JavaConstant constant) { - if (constant instanceof RelocatableConstant relocatable) { - return type.cast(relocatable.getPointer()); - } - return super.asObject(type, constant); - } -} From 97eee36574b45860ac3c776b1e953795727920ed Mon Sep 17 00:00:00 2001 From: Codrut Stancu Date: Sat, 20 Jan 2024 21:27:11 +0100 Subject: [PATCH 565/593] Remove AnalysisConstantReflectionProvider#forObject. It's identical with the one in HostedSnippetReflectionProvider. --- .../AnalysisConstantReflectionProvider.java | 25 ------------------- .../hosted/ameta/SVMHostedValueProvider.java | 3 ++- .../meta/HostedSnippetReflectionProvider.java | 15 +++++++++-- .../phases/AnalysisGraphBuilderPhase.java | 4 +-- .../phases/SharedGraphBuilderPhase.java | 8 +++--- 5 files changed, 19 insertions(+), 36 deletions(-) diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/ameta/AnalysisConstantReflectionProvider.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/ameta/AnalysisConstantReflectionProvider.java index b36018acf1cb..b2e5b6fc4a44 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/ameta/AnalysisConstantReflectionProvider.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/ameta/AnalysisConstantReflectionProvider.java @@ -30,8 +30,6 @@ import org.graalvm.nativeimage.Platform; import org.graalvm.nativeimage.Platforms; -import org.graalvm.nativeimage.c.function.RelocatedPointer; -import org.graalvm.word.WordBase; import com.oracle.graal.pointsto.ObjectScanner; import com.oracle.graal.pointsto.heap.HostedValuesProvider; @@ -44,7 +42,6 @@ import com.oracle.graal.pointsto.meta.AnalysisType; import com.oracle.graal.pointsto.meta.AnalysisUniverse; import com.oracle.graal.pointsto.util.AnalysisError; -import com.oracle.svm.core.FrameAccess; import com.oracle.svm.core.hub.DynamicHub; import com.oracle.svm.core.meta.SubstrateObjectConstant; import com.oracle.svm.core.util.VMError; @@ -297,32 +294,10 @@ public JavaConstant forString(String value) { return universe.getHeapScanner().createImageHeapConstant(asConstant(value), ObjectScanner.OtherReason.UNKNOWN); } - public JavaConstant forObject(Object object) { - validateRawObjectConstant(object); - if (object instanceof RelocatedPointer pointer) { - return new RelocatableConstant(pointer); - } else if (object instanceof WordBase word) { - return JavaConstant.forIntegerKind(FrameAccess.getWordKind(), word.rawValue()); - } - /* Redirect constant lookup through the shadow heap. */ - return universe.getHeapScanner().createImageHeapConstant(asConstant(object), ObjectScanner.OtherReason.UNKNOWN); - } - private JavaConstant asConstant(Object object) { return SubstrateObjectConstant.forObject(object); } - /** - * The raw object may never be an {@link ImageHeapConstant}. However, it can be a - * {@link SubstrateObjectConstant} coming from graphs prepared for run time compilation. In that - * case we'll get a double wrapping: the {@link SubstrateObjectConstant} parameter value will be - * wrapped in another {@link SubstrateObjectConstant} which will then be stored in a - * {@link ImageHeapConstant} in the shadow heap. - */ - public static void validateRawObjectConstant(Object object) { - AnalysisError.guarantee(!(object instanceof ImageHeapConstant), "Unexpected ImageHeapConstant %s", object); - } - private SVMHost getHostVM() { return (SVMHost) universe.hostVM(); } diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/ameta/SVMHostedValueProvider.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/ameta/SVMHostedValueProvider.java index 5c153733441a..bb67a7660adf 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/ameta/SVMHostedValueProvider.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/ameta/SVMHostedValueProvider.java @@ -38,6 +38,7 @@ import com.oracle.svm.core.util.VMError; import com.oracle.svm.hosted.classinitialization.ClassInitializationSupport; import com.oracle.svm.hosted.classinitialization.SimulateClassInitializerSupport; +import com.oracle.svm.hosted.meta.HostedSnippetReflectionProvider; import com.oracle.svm.hosted.meta.RelocatableConstant; import jdk.vm.ci.meta.JavaConstant; @@ -143,7 +144,7 @@ public JavaConstant forObject(Object object) { } else if (object instanceof WordBase word) { return JavaConstant.forIntegerKind(FrameAccess.getWordKind(), word.rawValue()); } - AnalysisConstantReflectionProvider.validateRawObjectConstant(object); + HostedSnippetReflectionProvider.validateRawObjectConstant(object); return SubstrateObjectConstant.forObject(object); } diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/meta/HostedSnippetReflectionProvider.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/meta/HostedSnippetReflectionProvider.java index 148b70a1b78c..73f65b61d370 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/meta/HostedSnippetReflectionProvider.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/meta/HostedSnippetReflectionProvider.java @@ -30,11 +30,11 @@ import com.oracle.graal.pointsto.ObjectScanner.OtherReason; import com.oracle.graal.pointsto.heap.ImageHeapConstant; import com.oracle.graal.pointsto.heap.ImageHeapScanner; +import com.oracle.graal.pointsto.util.AnalysisError; import com.oracle.svm.core.FrameAccess; import com.oracle.svm.core.graal.meta.SubstrateSnippetReflectionProvider; import com.oracle.svm.core.hub.DynamicHub; import com.oracle.svm.core.meta.SubstrateObjectConstant; -import com.oracle.svm.hosted.ameta.AnalysisConstantReflectionProvider; import jdk.graal.compiler.word.WordTypes; import jdk.vm.ci.meta.JavaConstant; @@ -60,11 +60,22 @@ public JavaConstant forObject(Object object) { } else if (object instanceof WordBase word) { return JavaConstant.forIntegerKind(FrameAccess.getWordKind(), word.rawValue()); } - AnalysisConstantReflectionProvider.validateRawObjectConstant(object); + validateRawObjectConstant(object); /* Redirect constant lookup through the shadow heap. */ return heapScanner.createImageHeapConstant(super.forObject(object), OtherReason.UNKNOWN); } + /** + * The raw object may never be an {@link ImageHeapConstant}. However, it can be a + * {@link SubstrateObjectConstant} coming from graphs prepared for run time compilation. In that + * case we'll get a double wrapping: the {@link SubstrateObjectConstant} parameter value will be + * wrapped in another {@link SubstrateObjectConstant} which will then be stored in a + * {@link ImageHeapConstant} in the shadow heap. + */ + public static void validateRawObjectConstant(Object object) { + AnalysisError.guarantee(!(object instanceof ImageHeapConstant), "Unexpected ImageHeapConstant %s", object); + } + @Override public JavaConstant forBoxed(JavaKind kind, Object value) { if (kind == JavaKind.Object) { diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/phases/AnalysisGraphBuilderPhase.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/phases/AnalysisGraphBuilderPhase.java index c111b4964515..37771d29a1e4 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/phases/AnalysisGraphBuilderPhase.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/phases/AnalysisGraphBuilderPhase.java @@ -40,7 +40,6 @@ import com.oracle.svm.core.bootstrap.BootstrapMethodConfiguration; import com.oracle.svm.core.meta.DirectSubstrateObjectConstant; import com.oracle.svm.hosted.SVMHost; -import com.oracle.svm.hosted.ameta.AnalysisConstantReflectionProvider; import com.oracle.svm.hosted.code.SubstrateCompilationDirectives; import com.oracle.svm.util.ModuleSupport; @@ -242,8 +241,7 @@ protected void genInvokeDynamic(int cpi, int opcode) { EndNode checkMethodTypeEqualTrueEnd = graph.add(new EndNode()); EndNode checkMethodTypeEqualFalseEnd = graph.add(new EndNode()); - JavaConstant wrongMethodTypeException = ((AnalysisConstantReflectionProvider) getConstantReflection()) - .forObject(new WrongMethodTypeException("CallSite MethodType should be of type " + methodType)); + JavaConstant wrongMethodTypeException = getSnippetReflection().forObject(new WrongMethodTypeException("CallSite MethodType should be of type " + methodType)); ConstantNode wrongMethodTypeExceptionNode = ConstantNode.forConstant(StampFactory.forKind(JavaKind.Object), wrongMethodTypeException, getMetaAccess(), getGraph()); InvokeWithExceptionNode throwWrongMethodTypeNode = bootstrapMethodHandler.throwBootstrapMethodError(bci, wrongMethodTypeExceptionNode); throwWrongMethodTypeNode.setNext(checkMethodTypeEqualFalseEnd); diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/phases/SharedGraphBuilderPhase.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/phases/SharedGraphBuilderPhase.java index b94c1f202b5b..0f0a247b8302 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/phases/SharedGraphBuilderPhase.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/phases/SharedGraphBuilderPhase.java @@ -70,7 +70,6 @@ import com.oracle.svm.core.util.VMError; import com.oracle.svm.hosted.ExceptionSynthesizer; import com.oracle.svm.hosted.LinkAtBuildTimeSupport; -import com.oracle.svm.hosted.ameta.AnalysisConstantReflectionProvider; import com.oracle.svm.hosted.code.FactoryMethodSupport; import com.oracle.svm.hosted.code.SubstrateCompilationDirectives; import com.oracle.svm.hosted.nodes.DeoptProxyNode; @@ -974,7 +973,6 @@ private Object loadConstantDynamic(int cpi, int opcode) { */ protected Object resolveLinkedObject(int bci, int cpi, int opcode, BootstrapMethodIntrospection bootstrap, int parameterLength, List staticArgumentsList, boolean isVarargs, boolean isPrimitiveConstant) { - AnalysisConstantReflectionProvider analysisConstantReflection = (AnalysisConstantReflectionProvider) getConstantReflection(); ResolvedJavaMethod bootstrapMethod = bootstrap.getMethod(); /* Step 1: Initialize the BootstrapMethodInfo. */ @@ -982,7 +980,7 @@ protected Object resolveLinkedObject(int bci, int cpi, int opcode, BootstrapMeth BootstrapMethodRecord bootstrapMethodRecord = new BootstrapMethodRecord(bci, cpi, ((AnalysisMethod) method).getMultiMethod(MultiMethod.ORIGINAL_METHOD)); BootstrapMethodInfo bootstrapMethodInfo = BootstrapMethodConfiguration.singleton().getBootstrapMethodInfoCache().computeIfAbsent(bootstrapMethodRecord, key -> new BootstrapMethodInfo()); - ConstantNode bootstrapMethodInfoNode = ConstantNode.forConstant(analysisConstantReflection.forObject(bootstrapMethodInfo), getMetaAccess(), getGraph()); + ConstantNode bootstrapMethodInfoNode = ConstantNode.forConstant(getSnippetReflection().forObject(bootstrapMethodInfo), getMetaAccess(), getGraph()); /* * Step 2: Check if the call site or the constant is linked or if it previously @@ -1021,7 +1019,7 @@ protected Object resolveLinkedObject(int bci, int cpi, int opcode, BootstrapMeth /* A nested constant dynamic threw. */ return argConstant; } else { - currentNode = ConstantNode.forConstant(analysisConstantReflection.forObject(argConstant), getMetaAccess(), getGraph()); + currentNode = ConstantNode.forConstant(getSnippetReflection().forObject(argConstant), getMetaAccess(), getGraph()); } } else { /* @@ -1054,7 +1052,7 @@ protected Object resolveLinkedObject(int bci, int cpi, int opcode, BootstrapMeth */ addArgument(isVarargs, arguments, 0, lookupNode); - ConstantNode bootstrapName = ConstantNode.forConstant(analysisConstantReflection.forString(bootstrap.getName()), getMetaAccess(), getGraph()); + ConstantNode bootstrapName = ConstantNode.forConstant(getConstantReflection().forString(bootstrap.getName()), getMetaAccess(), getGraph()); addArgument(isVarargs, arguments, 1, bootstrapName); addArgument(isVarargs, arguments, 2, ConstantNode.forConstant(bootstrap.getType(), getMetaAccess(), getGraph())); From 8802fa2f8fb586c296dfa044b6e36169e405c5fa Mon Sep 17 00:00:00 2001 From: Codrut Stancu Date: Fri, 19 Jan 2024 20:08:43 +0100 Subject: [PATCH 566/593] Access `HostedValuesProvider` via `AnalysisUniverse`. It's cleaner than going via the ImageHeapScanner directly and may store it in the universe later after more refactoring. --- .../src/com/oracle/graal/pointsto/ObjectScanner.java | 2 +- .../com/oracle/graal/pointsto/heap/HeapSnapshotVerifier.java | 2 +- .../src/com/oracle/graal/pointsto/meta/AnalysisUniverse.java | 4 ++-- .../svm/hosted/ameta/AnalysisConstantReflectionProvider.java | 2 +- .../src/com/oracle/svm/hosted/image/NativeImageHeap.java | 2 +- 5 files changed, 6 insertions(+), 6 deletions(-) diff --git a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/ObjectScanner.java b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/ObjectScanner.java index 34405dfdf7bd..7f847f141352 100644 --- a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/ObjectScanner.java +++ b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/ObjectScanner.java @@ -213,7 +213,7 @@ protected void scanField(AnalysisField field, JavaConstant receiver, ScanReason protected JavaConstant readFieldValue(AnalysisField field, JavaConstant receiver) { /* The object scanner processes hosted values. We must not see shadow heap values here. */ AnalysisError.guarantee(!(receiver instanceof ImageHeapConstant)); - return bb.getUniverse().getHeapScanner().getHostedValuesProvider().readFieldValueWithReplacement(field, receiver); + return bb.getUniverse().getHostedValuesProvider().readFieldValueWithReplacement(field, receiver); } /** diff --git a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/heap/HeapSnapshotVerifier.java b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/heap/HeapSnapshotVerifier.java index cb6f52a5c68a..711bccf2a853 100644 --- a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/heap/HeapSnapshotVerifier.java +++ b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/heap/HeapSnapshotVerifier.java @@ -278,7 +278,7 @@ public static boolean patchPrimitiveArrayValue(BigBang bb, JavaConstant snapshot if (!Objects.deepEquals(snapshotArray, newValueArray)) { /* Guarantee that the shadowed constant and the hosted constant are the same. */ AnalysisError.guarantee(((ImageHeapPrimitiveArray) snapshot).getHostedObject().equals(newValue)); - Integer length = bb.getUniverse().getHeapScanner().getHostedValuesProvider().readArrayLength(newValue); + Integer length = bb.getUniverse().getHostedValuesProvider().readArrayLength(newValue); /* Since the shadowed constant didn't change, the length should match. */ System.arraycopy(newValueArray, 0, snapshotArray, 0, length); return true; diff --git a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/meta/AnalysisUniverse.java b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/meta/AnalysisUniverse.java index beae4a362320..27e96e99b5a7 100644 --- a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/meta/AnalysisUniverse.java +++ b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/meta/AnalysisUniverse.java @@ -504,7 +504,7 @@ public JavaConstant fromHosted(JavaConstant constant) { */ return (JavaConstant) original; } - return heapScanner.getHostedValuesProvider().forObject(original); + return getHostedValuesProvider().forObject(original); } else { return constant; } @@ -517,7 +517,7 @@ public JavaConstant toHosted(JavaConstant constant) { if (constant == null) { return null; } else if (constant.getJavaKind().isObject() && !constant.isNull()) { - return GraalAccess.getOriginalSnippetReflection().forObject(heapScanner.getHostedValuesProvider().asObject(Object.class, constant)); + return GraalAccess.getOriginalSnippetReflection().forObject(getHostedValuesProvider().asObject(Object.class, constant)); } else { return constant; } diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/ameta/AnalysisConstantReflectionProvider.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/ameta/AnalysisConstantReflectionProvider.java index b2e5b6fc4a44..b1ee9d2b72cc 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/ameta/AnalysisConstantReflectionProvider.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/ameta/AnalysisConstantReflectionProvider.java @@ -224,7 +224,7 @@ public JavaConstant readValue(AnalysisField field, JavaConstant receiver, boolea if (value == null) { VMError.guarantee(!SimulateClassInitializerSupport.singleton().isEnabled()); ImageHeapScanner heapScanner = universe.getHeapScanner(); - HostedValuesProvider hostedValuesProvider = heapScanner.getHostedValuesProvider(); + HostedValuesProvider hostedValuesProvider = universe.getHostedValuesProvider(); value = heapScanner.createImageHeapConstant(hostedValuesProvider.readFieldValueWithReplacement(field, receiver), ObjectScanner.OtherReason.UNKNOWN); } return value; diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/NativeImageHeap.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/NativeImageHeap.java index 09d0064129fa..0a18f71a5cb8 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/NativeImageHeap.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/NativeImageHeap.java @@ -259,7 +259,7 @@ Object readInlinedField(HostedField field, JavaConstant receiver) { VMError.guarantee(HostedConfiguration.isInlinedField(field), "Expected an inlined field, found %s", field); JavaConstant hostedReceiver = ((ImageHeapInstance) receiver).getHostedObject(); /* Use the HostedValuesProvider to get direct access to hosted values. */ - HostedValuesProvider hostedValuesProvider = aUniverse.getHeapScanner().getHostedValuesProvider(); + HostedValuesProvider hostedValuesProvider = aUniverse.getHostedValuesProvider(); return hUniverse.getSnippetReflection().asObject(Object.class, hostedValuesProvider.readFieldValueWithReplacement(field.getWrapped(), hostedReceiver)); } From 97c7336cb24cc9394c093ab2c4822f6617294242 Mon Sep 17 00:00:00 2001 From: Christian Wimmer Date: Tue, 2 Jan 2024 22:00:00 -0800 Subject: [PATCH 567/593] Represent field offsets as a FieldOffsetNode during static analysis --- .../nodes/extended/FieldOffsetProvider.java | 40 ++ .../nodes/extended/UnsafeAccessNode.java | 36 +- substratevm/CHANGELOG.md | 3 + .../graal/pointsto/PointsToAnalysis.java | 2 +- .../pointsto/flow/MethodTypeFlowBuilder.java | 482 ++++++++---------- .../InlineBeforeAnalysisGraphDecoder.java | 109 +--- .../pointsto/results/StrengthenGraphs.java | 9 + .../SimpleInMemoryMethodSummaryProvider.java | 3 + .../ArrayBaseOffsetFieldValueTransformer.java | 4 +- .../ArrayIndexScaleFieldValueTransformer.java | 4 +- .../ArrayIndexShiftFieldValueTransformer.java | 4 +- .../BoxingTransformer.java | 21 +- .../FieldOffsetFieldValueTransformer.java | 15 +- ...FieldValueTransformerWithAvailability.java | 13 + .../StaticFieldBaseFieldValueTransformer.java | 9 + .../svm/core/graal/nodes/FieldOffsetNode.java | 108 ++++ .../core/graal/nodes/LazyConstantNode.java | 99 ---- .../oracle/svm/core/jdk/VarHandleFeature.java | 157 +++--- .../ameta/FieldValueInterceptionSupport.java | 41 ++ .../SimulateClassInitializerGraphDecoder.java | 4 + .../SimulateClassInitializerSupport.java | 2 + .../InlineBeforeAnalysisGraphDecoderImpl.java | 16 +- .../phases/SharedGraphBuilderPhase.java | 12 +- .../SubstrateGraphBuilderPlugins.java | 67 +-- .../AutomaticUnsafeTransformationSupport.java | 10 +- 25 files changed, 613 insertions(+), 657 deletions(-) create mode 100644 compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/nodes/extended/FieldOffsetProvider.java create mode 100644 substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/graal/nodes/FieldOffsetNode.java delete mode 100644 substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/graal/nodes/LazyConstantNode.java diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/nodes/extended/FieldOffsetProvider.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/nodes/extended/FieldOffsetProvider.java new file mode 100644 index 000000000000..5d5428a59a30 --- /dev/null +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/nodes/extended/FieldOffsetProvider.java @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2024, 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 jdk.graal.compiler.nodes.extended; + +import jdk.graal.compiler.nodes.ConstantNode; +import jdk.graal.compiler.nodes.ValueNodeInterface; +import jdk.vm.ci.meta.ResolvedJavaField; + +/** + * Interface that can be implemented by nodes that compute the offset of a field, but cannot expose + * the offset as a {@link ConstantNode} yet. The provided field can be used by the compiler to + * convert low-level memory access nodes to high-level field access nodes. + */ +public interface FieldOffsetProvider extends ValueNodeInterface { + + /** The field whose offset this node is computing. */ + ResolvedJavaField getField(); +} diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/nodes/extended/UnsafeAccessNode.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/nodes/extended/UnsafeAccessNode.java index 3e8049ca5bf9..1e8e7a7008ff 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/nodes/extended/UnsafeAccessNode.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/nodes/extended/UnsafeAccessNode.java @@ -29,6 +29,8 @@ import java.nio.ByteOrder; +import org.graalvm.word.LocationIdentity; + import jdk.graal.compiler.core.common.memory.MemoryOrderMode; import jdk.graal.compiler.core.common.type.Stamp; import jdk.graal.compiler.graph.Node; @@ -43,8 +45,6 @@ import jdk.graal.compiler.nodes.spi.Canonicalizable; import jdk.graal.compiler.nodes.spi.CanonicalizerTool; import jdk.graal.compiler.nodes.type.StampTool; -import org.graalvm.word.LocationIdentity; - import jdk.vm.ci.meta.ConstantReflectionProvider; import jdk.vm.ci.meta.JavaConstant; import jdk.vm.ci.meta.JavaKind; @@ -112,29 +112,31 @@ public MemoryOrderMode getMemoryOrder() { @Override public Node canonical(CanonicalizerTool tool) { if (isCanonicalizable()) { - if (offset().isConstant()) { - long constantOffset = offset().asJavaConstant().asLong(); - - // Try to canonicalize to a field access. - ResolvedJavaType receiverType = StampTool.typeOrNull(object()); - if (receiverType != null) { - ResolvedJavaField field = getStaticFieldUnsafeAccess(tool.getConstantReflection()); + // Try to canonicalize to a field access. + ResolvedJavaType receiverType = StampTool.typeOrNull(object(), tool.getMetaAccess()); + if (receiverType != null) { + ResolvedJavaField field = null; + if (offset().isConstant()) { + field = getStaticFieldUnsafeAccess(tool.getConstantReflection()); if (field == null) { + long constantOffset = offset().asJavaConstant().asLong(); field = receiverType.findInstanceFieldWithOffset(constantOffset, accessKind()); } + } else if (offset() instanceof FieldOffsetProvider fieldOffsetProvider) { + field = fieldOffsetProvider.getField(); + } - // No need for checking that the receiver is non-null. The field access - // includes the null check and if a field is found, the offset is so small that - // this is never a valid access of an arbitrary address. - if ((field != null && field.getJavaKind() == this.accessKind() && - !field.isInternal() /* Ensure this is a true java field. */)) { - return cloneAsFieldAccess(field); - } + // No need for checking that the receiver is non-null. The field access + // includes the null check and if a field is found, the offset is so small that + // this is never a valid access of an arbitrary address. + if ((field != null && field.getJavaKind() == this.accessKind() && + !field.isInternal() /* Ensure this is a true java field. */)) { + return cloneAsFieldAccess(field); } } + if (getLocationIdentity().isAny()) { // If we have a vague one, try to build a better location identity. - ResolvedJavaType receiverType = StampTool.typeOrNull(object()); if (receiverType != null && receiverType.isArray()) { /* * This code might assign a wrong location identity in case the offset is diff --git a/substratevm/CHANGELOG.md b/substratevm/CHANGELOG.md index 9560988d0e20..9123458c185d 100644 --- a/substratevm/CHANGELOG.md +++ b/substratevm/CHANGELOG.md @@ -2,6 +2,9 @@ This changelog summarizes major changes to GraalVM Native Image. +## GraalVM for JDK 23 (Internal Version 24.1.0) +* (GR-51106) Fields that are accessed via a `VarHandle` or `MethodHandle` are no longer marked as "unsafe accessed" when the `VarHandle`/`MethodHandle` can be fully intrinsified. + ## GraalVM for JDK 22 (Internal Version 24.0.0) * (GR-48304) Red Hat added support for the JFR event ThreadAllocationStatistics. * (GR-48343) Red Hat added support for the JFR events AllocationRequiringGC and SystemGC. diff --git a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/PointsToAnalysis.java b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/PointsToAnalysis.java index 9a3e534064e1..13031a1a62d7 100644 --- a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/PointsToAnalysis.java +++ b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/PointsToAnalysis.java @@ -273,7 +273,7 @@ public AnalysisType lookup(JavaType type) { } public AnalysisType getObjectType() { - return metaAccess.lookupJavaType(Object.class); + return universe.objectType(); } public AnalysisType getObjectArrayType() { diff --git a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/flow/MethodTypeFlowBuilder.java b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/flow/MethodTypeFlowBuilder.java index 4776a5ae45ff..93c06f18454c 100644 --- a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/flow/MethodTypeFlowBuilder.java +++ b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/flow/MethodTypeFlowBuilder.java @@ -105,10 +105,12 @@ import jdk.graal.compiler.nodes.extended.BoxNode; import jdk.graal.compiler.nodes.extended.BytecodeExceptionNode; import jdk.graal.compiler.nodes.extended.BytecodeExceptionNode.BytecodeExceptionKind; +import jdk.graal.compiler.nodes.extended.FieldOffsetProvider; import jdk.graal.compiler.nodes.extended.ForeignCall; import jdk.graal.compiler.nodes.extended.GetClassNode; import jdk.graal.compiler.nodes.extended.RawLoadNode; import jdk.graal.compiler.nodes.extended.RawStoreNode; +import jdk.graal.compiler.nodes.java.AtomicReadAndAddNode; import jdk.graal.compiler.nodes.java.AtomicReadAndWriteNode; import jdk.graal.compiler.nodes.java.ClassIsAssignableFromNode; import jdk.graal.compiler.nodes.java.DynamicNewArrayNode; @@ -256,24 +258,6 @@ public static void registerUsedElements(PointsToAnalysis bb, StructuredGraph gra AnalysisType type = (AnalysisType) node.type(); type.registerAsAllocated(AbstractAnalysisEngine.sourcePosition(node)); - } else if (n instanceof CommitAllocationNode) { - CommitAllocationNode node = (CommitAllocationNode) n; - List values = node.getValues(); - int objectStartIndex = 0; - for (VirtualObjectNode virtualObject : node.getVirtualObjects()) { - AnalysisType type = (AnalysisType) virtualObject.type(); - if (!type.isArray()) { - for (int i = 0; i < virtualObject.entryCount(); i++) { - ValueNode value = values.get(objectStartIndex + i); - if (!value.isJavaConstant() || !value.asJavaConstant().isDefaultForKind()) { - AnalysisField field = (AnalysisField) ((VirtualInstanceNode) virtualObject).field(i); - field.registerAsWritten(AbstractAnalysisEngine.sourcePosition(node)); - } - } - } - objectStartIndex += virtualObject.entryCount(); - } - } else if (n instanceof NewArrayNode) { NewArrayNode node = (NewArrayNode) n; AnalysisType type = ((AnalysisType) node.elementType()).getArrayClass(); @@ -314,6 +298,11 @@ public static void registerUsedElements(PointsToAnalysis bb, StructuredGraph gra } } + } else if (n instanceof FieldOffsetProvider node) { + if (needsUnsafeRegistration(node)) { + ((AnalysisField) node.getField()).registerAsUnsafeAccessed(AbstractAnalysisEngine.sourcePosition(node.asNode())); + } + } else if (n instanceof FrameState) { FrameState node = (FrameState) n; AnalysisMethod frameStateMethod = (AnalysisMethod) node.getMethod(); @@ -381,6 +370,31 @@ protected static boolean ignoreConstant(ConstantNode node) { return true; } + /** + * Unsafe access nodes whose offset is a {@link FieldOffsetProvider} are modeled directly as + * field access type flows and therefore do not need unsafe registration. + * + * We do not want that a field is registered as unsafe accessed just so that we have the field + * offset during debugging, so we also ignore {@link FrameState}. {@link StrengthenGraphs} + * removes the node from the {@link FrameState} if it is not registered for unsafe access for + * any other reason. + */ + protected static boolean needsUnsafeRegistration(FieldOffsetProvider node) { + for (var usage : node.asNode().usages()) { + if (usage instanceof RawLoadNode || usage instanceof RawStoreNode || + usage instanceof UnsafeCompareAndSwapNode || usage instanceof UnsafeCompareAndExchangeNode || + usage instanceof AtomicReadAndWriteNode || usage instanceof AtomicReadAndAddNode) { + /* Unsafe usages are modeled as field type flows. */ + } else if (usage instanceof FrameState) { + /* FrameState usages are only for debugging and not necessary for correctness. */ + } else { + return true; + } + } + /* Success, the field does not need to be registered for unsafe access. */ + return false; + } + protected static boolean ignoreInstanceOfType(PointsToAnalysis bb, AnalysisType type) { if (bb.getHostVM().ignoreInstanceOfTypeDisallowed()) { return false; @@ -635,6 +649,17 @@ public boolean contains(ValueNode node) { return flows.containsKey(typeFlowUnproxify(node)); } + public TypeFlowBuilder lookupOrAny(ValueNode n, JavaKind kind) { + if (n != null) { + return lookup(n); + } else if (kind == JavaKind.Int || kind == JavaKind.Long) { + return anyPrimitiveSourceTypeFlowBuilder; + } else { + /* For now, we do not need support JavaKind.Object here. */ + throw AnalysisError.shouldNotReachHere("Unimplemented kind: " + kind); + } + } + public TypeFlowBuilder lookup(ValueNode n) { ValueNode node = typeFlowUnproxify(n); TypeFlowBuilder result = flows.get(node); @@ -978,59 +1003,23 @@ protected void node(FixedNode n) { state.add(node, newArrayBuilder); } else if (n instanceof LoadFieldNode node) { // value = object.field - AnalysisField field = (AnalysisField) node.field(); - assert field.isAccessed() : field; - if (bb.isSupportedJavaKind(node.getStackKind())) { - TypeFlowBuilder loadFieldBuilder; - BytecodePosition loadLocation = AbstractAnalysisEngine.sourcePosition(node); - if (node.isStatic()) { - loadFieldBuilder = TypeFlowBuilder.create(bb, node, LoadStaticFieldTypeFlow.class, () -> { - FieldTypeFlow fieldFlow = field.getStaticFieldFlow(); - LoadStaticFieldTypeFlow loadFieldFLow = new LoadStaticFieldTypeFlow(loadLocation, field, fieldFlow); - flowsGraph.addNodeFlow(node, loadFieldFLow); - return loadFieldFLow; - }); - } else { - TypeFlowBuilder objectBuilder = state.lookup(node.object()); - loadFieldBuilder = TypeFlowBuilder.create(bb, node, LoadInstanceFieldTypeFlow.class, () -> { - LoadInstanceFieldTypeFlow loadFieldFLow = new LoadInstanceFieldTypeFlow(loadLocation, field, objectBuilder.get()); - flowsGraph.addNodeFlow(node, loadFieldFLow); - return loadFieldFLow; - }); - loadFieldBuilder.addObserverDependency(objectBuilder); - } - typeFlowGraphBuilder.registerSinkBuilder(loadFieldBuilder); - state.add(node, loadFieldBuilder); - } + processLoadField(node, (AnalysisField) node.field(), node.object(), state); if (node.object() != null) { processImplicitNonNull(node.object(), state); } } else if (n instanceof StoreFieldNode node) { // object.field = value - processStoreField(node, state); + processStoreField(node, (AnalysisField) node.field(), node.object(), node.value(), node.value().getStackKind(), state); if (node.object() != null) { processImplicitNonNull(node.object(), state); } } else if (n instanceof LoadIndexedNode node) { - TypeFlowBuilder arrayBuilder = state.lookup(node.array()); - if (node.getStackKind() == JavaKind.Object) { - AnalysisType type = (AnalysisType) StampTool.typeOrNull(node.array(), bb.getMetaAccess()); - AnalysisType arrayType = type.isArray() ? type : bb.getObjectArrayType(); - - TypeFlowBuilder loadIndexedBuilder = TypeFlowBuilder.create(bb, node, LoadIndexedTypeFlow.class, () -> { - LoadIndexedTypeFlow loadIndexedFlow = new LoadIndexedTypeFlow(AbstractAnalysisEngine.sourcePosition(node), arrayType, arrayBuilder.get()); - flowsGraph.addNodeFlow(node, loadIndexedFlow); - return loadIndexedFlow; - }); - typeFlowGraphBuilder.registerSinkBuilder(loadIndexedBuilder); - loadIndexedBuilder.addObserverDependency(arrayBuilder); - state.add(node, loadIndexedBuilder); - } + processLoadIndexed(node, node.array(), state); processImplicitNonNull(node.array(), state); } else if (n instanceof StoreIndexedNode node) { - processStoreIndexed(node, state); + processStoreIndexed(node, node.array(), node.value(), node.value().getStackKind(), state); processImplicitNonNull(node.array(), state); } else if (n instanceof UnsafePartitionLoadNode) { @@ -1092,131 +1081,18 @@ protected void node(FixedNode n) { /* Unsafe stores must not be removed. */ typeFlowGraphBuilder.registerSinkBuilder(unsafeStoreBuilder); - } else if (n instanceof RawLoadNode) { - RawLoadNode node = (RawLoadNode) n; - - checkUnsafeOffset(node.object(), node.offset()); - - if (node.object().getStackKind() == JavaKind.Object && node.getStackKind() == JavaKind.Object) { - AnalysisType objectType = (AnalysisType) StampTool.typeOrNull(node.object(), bb.getMetaAccess()); - TypeFlowBuilder objectBuilder = state.lookup(node.object()); - TypeFlowBuilder loadBuilder; - BytecodePosition loadLocation = AbstractAnalysisEngine.sourcePosition(node); - if (objectType != null && objectType.isArray() && objectType.getComponentType().getJavaKind() == JavaKind.Object) { - /* - * Unsafe load from an array object is essentially an array load since we - * don't have separate type flows for different array elements. - */ - loadBuilder = TypeFlowBuilder.create(bb, node, LoadIndexedTypeFlow.class, () -> { - LoadIndexedTypeFlow loadTypeFlow = new LoadIndexedTypeFlow(loadLocation, objectType, objectBuilder.get()); - flowsGraph.addMiscEntryFlow(loadTypeFlow); - return loadTypeFlow; - }); - } else { - /* - * Use the Object type as a conservative approximation for both the receiver - * object type and the loaded values type. - */ - AnalysisType nonNullObjectType = bb.getObjectType(); - loadBuilder = TypeFlowBuilder.create(bb, node, UnsafeLoadTypeFlow.class, () -> { - UnsafeLoadTypeFlow loadTypeFlow = new UnsafeLoadTypeFlow(loadLocation, nonNullObjectType, nonNullObjectType, objectBuilder.get()); - flowsGraph.addMiscEntryFlow(loadTypeFlow); - return loadTypeFlow; - }); - } - - loadBuilder.addObserverDependency(objectBuilder); - state.add(node, loadBuilder); - } - - } else if (n instanceof RawStoreNode) { - RawStoreNode node = (RawStoreNode) n; - - checkUnsafeOffset(node.object(), node.offset()); - - if (node.object().getStackKind() == JavaKind.Object && node.value().getStackKind() == JavaKind.Object) { - AnalysisType objectType = (AnalysisType) StampTool.typeOrNull(node.object(), bb.getMetaAccess()); - TypeFlowBuilder objectBuilder = state.lookup(node.object()); - TypeFlowBuilder valueBuilder = state.lookup(node.value()); - TypeFlowBuilder storeBuilder; - BytecodePosition storeLocation = AbstractAnalysisEngine.sourcePosition(node); - if (objectType != null && objectType.isArray() && objectType.getComponentType().getJavaKind() == JavaKind.Object) { - /* - * Unsafe store to an array object is essentially an array store since we - * don't have separate type flows for different array elements. - */ - storeBuilder = TypeFlowBuilder.create(bb, node, StoreIndexedTypeFlow.class, () -> { - StoreIndexedTypeFlow storeTypeFlow = new StoreIndexedTypeFlow(storeLocation, objectType, objectBuilder.get(), valueBuilder.get()); - flowsGraph.addMiscEntryFlow(storeTypeFlow); - return storeTypeFlow; - }); - } else { - /* - * Use the Object type as a conservative approximation for both the receiver - * object type and the stored values type. - */ - AnalysisType nonNullObjectType = bb.getObjectType(); - storeBuilder = TypeFlowBuilder.create(bb, node, UnsafeStoreTypeFlow.class, () -> { - UnsafeStoreTypeFlow storeTypeFlow = new UnsafeStoreTypeFlow(storeLocation, nonNullObjectType, nonNullObjectType, objectBuilder.get(), valueBuilder.get()); - flowsGraph.addMiscEntryFlow(storeTypeFlow); - return storeTypeFlow; - }); - } - storeBuilder.addUseDependency(valueBuilder); - storeBuilder.addObserverDependency(objectBuilder); - - /* Offset stores must not be removed. */ - typeFlowGraphBuilder.registerSinkBuilder(storeBuilder); - } - } else if (n instanceof UnsafeCompareAndSwapNode) { - UnsafeCompareAndSwapNode node = (UnsafeCompareAndSwapNode) n; - ValueNode object = node.object(); - ValueNode newValue = node.newValue(); - - checkUnsafeOffset(object, node.offset()); - if (object.getStackKind() == JavaKind.Object && newValue.getStackKind() == JavaKind.Object) { - AnalysisType objectType = (AnalysisType) StampTool.typeOrNull(object, bb.getMetaAccess()); - TypeFlowBuilder objectBuilder = state.lookup(object); - TypeFlowBuilder newValueBuilder = state.lookup(newValue); - TypeFlowBuilder storeBuilder; - BytecodePosition storeLocation = AbstractAnalysisEngine.sourcePosition(node); - if (objectType != null && objectType.isArray() && objectType.getComponentType().getJavaKind() == JavaKind.Object) { - /* - * Unsafe compare and swap is essentially unsafe store and unsafe store to - * an array object is essentially an array store since we don't have - * separate type flows for different array elements. - */ - storeBuilder = TypeFlowBuilder.create(bb, node, StoreIndexedTypeFlow.class, () -> { - StoreIndexedTypeFlow storeTypeFlow = new StoreIndexedTypeFlow(storeLocation, objectType, objectBuilder.get(), newValueBuilder.get()); - flowsGraph.addMiscEntryFlow(storeTypeFlow); - return storeTypeFlow; - }); - } else { - /* - * Use the Object type as a conservative approximation for both the receiver - * object type and the swapped values type. - */ - AnalysisType nonNullObjectType = bb.getObjectType(); - storeBuilder = TypeFlowBuilder.create(bb, node, UnsafeStoreTypeFlow.class, () -> { - UnsafeStoreTypeFlow storeTypeFlow = new UnsafeStoreTypeFlow(storeLocation, nonNullObjectType, nonNullObjectType, objectBuilder.get(), newValueBuilder.get()); - flowsGraph.addMiscEntryFlow(storeTypeFlow); - return storeTypeFlow; - }); - } - storeBuilder.addUseDependency(newValueBuilder); - storeBuilder.addObserverDependency(objectBuilder); - - /* Offset stores must not be removed. */ - typeFlowGraphBuilder.registerSinkBuilder(storeBuilder); - } - - } else if (n instanceof UnsafeCompareAndExchangeNode) { - UnsafeCompareAndExchangeNode node = (UnsafeCompareAndExchangeNode) n; - modelUnsafeReadAndWriteFlow(node, node.object(), node.newValue(), node.offset()); - - } else if (n instanceof AtomicReadAndWriteNode) { - AtomicReadAndWriteNode node = (AtomicReadAndWriteNode) n; - modelUnsafeReadAndWriteFlow(node, node.object(), node.newValue(), node.offset()); + } else if (n instanceof RawLoadNode node) { + modelUnsafeReadOnlyFlow(node, node.object(), node.offset()); + } else if (n instanceof RawStoreNode node) { + modelUnsafeWriteOnlyFlow(node, node.object(), node.value(), node.value().getStackKind(), node.offset()); + } else if (n instanceof UnsafeCompareAndSwapNode node) { + modelUnsafeWriteOnlyFlow(node, node.object(), node.newValue(), node.newValue().getStackKind(), node.offset()); + } else if (n instanceof UnsafeCompareAndExchangeNode node) { + modelUnsafeReadAndWriteFlow(node, node.object(), node.newValue(), node.newValue().getStackKind(), node.offset()); + } else if (n instanceof AtomicReadAndWriteNode node) { + modelUnsafeReadAndWriteFlow(node, node.object(), node.newValue(), node.newValue().getStackKind(), node.offset()); + } else if (n instanceof AtomicReadAndAddNode node) { + modelUnsafeReadAndWriteFlow(node, node.object(), null, node.offset().getStackKind(), node.offset()); } else if (n instanceof BasicArrayCopyNode) { BasicArrayCopyNode node = (BasicArrayCopyNode) n; @@ -1295,82 +1171,60 @@ protected void node(FixedNode n) { } } - /** - * Model an unsafe-read-and-write operation. - * - * In the analysis this is used to model both {@link AtomicReadAndWriteNode}, i.e., an - * atomic read-and-write operation like - * {@code sun.misc.Unsafe#getAndSetObject(Object, long, Object)}, and - * {@link UnsafeCompareAndExchangeNode}, i.e., an atomic compare-and-swap operation like - * {@code jdk.internal.misc.Unsafe#compareAndExchangeObject(Object, long, Object, Object)} - * where the result is the current value of the memory location that was compared. + /* + * The various Unsafe access nodes either only read, only write, or write-and-read directly + * based on an offset. All three cases are handled similarly: + * + * 1) If we have precise information about the accessed field, we can model the access using + * proper field access type flows. + * + * 2) If the accessed object is always an array, we ca model the access using array type + * flows. The Unsafe access of an array is essentially an array access because we do not + * have separate type flows for different array elements. * - * The Unsafe.compareAndExchangeObject() operation is similar to the - * Unsafe.compareAndSwapObject() operation which is modeled by the - * {@link UnsafeCompareAndSwapNode} above. However, Unsafe.compareAndSwapObject() returns a - * boolean, which the analysis ignores, whereas Unsafe.compareAndExchangeObject() returns - * the previous value, therefore it is equivalent to the model for Unsafe.getAndSetObject(). + * 3) In the generic case, we use the unsafe access type flows. */ - private void modelUnsafeReadAndWriteFlow(ValueNode node, ValueNode object, ValueNode newValue, ValueNode offset) { - assert node instanceof UnsafeCompareAndExchangeNode || node instanceof AtomicReadAndWriteNode : node; + private void modelUnsafeReadOnlyFlow(RawLoadNode node, ValueNode object, ValueNode offset) { checkUnsafeOffset(object, offset); - - if (object.getStackKind() == JavaKind.Object && newValue.getStackKind() == JavaKind.Object) { - AnalysisType objectType = (AnalysisType) StampTool.typeOrNull(object, bb.getMetaAccess()); - TypeFlowBuilder objectBuilder = state.lookup(object); - TypeFlowBuilder newValueBuilder = state.lookup(newValue); - - TypeFlowBuilder storeBuilder; - TypeFlowBuilder loadBuilder; - - BytecodePosition location = AbstractAnalysisEngine.sourcePosition(node); - if (objectType != null && objectType.isArray() && objectType.getComponentType().getJavaKind() == JavaKind.Object) { - /* - * Atomic read and write is essentially unsafe store and unsafe store to an - * array object is essentially an array store since we don't have separate type - * flows for different array elements. - */ - storeBuilder = TypeFlowBuilder.create(bb, node, StoreIndexedTypeFlow.class, () -> { - StoreIndexedTypeFlow storeTypeFlow = new StoreIndexedTypeFlow(location, objectType, objectBuilder.get(), newValueBuilder.get()); - flowsGraph.addMiscEntryFlow(storeTypeFlow); - return storeTypeFlow; - }); - - loadBuilder = TypeFlowBuilder.create(bb, node, LoadIndexedTypeFlow.class, () -> { - LoadIndexedTypeFlow loadTypeFlow = new LoadIndexedTypeFlow(location, objectType, objectBuilder.get()); - flowsGraph.addMiscEntryFlow(loadTypeFlow); - return loadTypeFlow; - }); - + if (object.getStackKind() == JavaKind.Object) { + if (offset instanceof FieldOffsetProvider fieldOffsetProvider) { + processLoadField(node, (AnalysisField) fieldOffsetProvider.getField(), object, state); + } else if (StampTool.isAlwaysArray(object)) { + processLoadIndexed(node, object, state); } else { - /* - * Use the Object type as a conservative approximation for both the receiver - * object type and the read/written values type. - */ - AnalysisType nonNullObjectType = bb.getObjectType(); - storeBuilder = TypeFlowBuilder.create(bb, node, UnsafeStoreTypeFlow.class, () -> { - UnsafeStoreTypeFlow storeTypeFlow = new UnsafeStoreTypeFlow(location, nonNullObjectType, nonNullObjectType, objectBuilder.get(), newValueBuilder.get()); - flowsGraph.addMiscEntryFlow(storeTypeFlow); - return storeTypeFlow; - }); - - loadBuilder = TypeFlowBuilder.create(bb, node, UnsafeLoadTypeFlow.class, () -> { - UnsafeLoadTypeFlow loadTypeFlow = new UnsafeLoadTypeFlow(location, nonNullObjectType, nonNullObjectType, objectBuilder.get()); - flowsGraph.addMiscEntryFlow(loadTypeFlow); - return loadTypeFlow; - }); - + processUnsafeLoad(node, object, state); } + } + } - storeBuilder.addUseDependency(newValueBuilder); - storeBuilder.addObserverDependency(objectBuilder); - loadBuilder.addObserverDependency(objectBuilder); - - /* Offset stores must not be removed. */ - typeFlowGraphBuilder.registerSinkBuilder(storeBuilder); + private void modelUnsafeWriteOnlyFlow(ValueNode node, ValueNode object, ValueNode newValue, JavaKind newValueKind, ValueNode offset) { + checkUnsafeOffset(object, offset); + if (object.getStackKind() == JavaKind.Object) { + if (offset instanceof FieldOffsetProvider fieldOffsetProvider) { + processStoreField(node, (AnalysisField) fieldOffsetProvider.getField(), object, newValue, newValueKind, state); + } else if (StampTool.isAlwaysArray(object)) { + processStoreIndexed(node, object, newValue, newValueKind, state); + } else { + processUnsafeStore(node, object, newValue, newValueKind, state); + } + } + } - state.add(node, loadBuilder); + private void modelUnsafeReadAndWriteFlow(ValueNode node, ValueNode object, ValueNode newValue, JavaKind newValueKind, ValueNode offset) { + checkUnsafeOffset(object, offset); + if (object.getStackKind() == JavaKind.Object) { + if (offset instanceof FieldOffsetProvider fieldOffsetProvider) { + var field = (AnalysisField) fieldOffsetProvider.getField(); + processStoreField(node, field, object, newValue, newValueKind, state); + processLoadField(node, field, object, state); + } else if (StampTool.isAlwaysArray(object)) { + processStoreIndexed(node, object, newValue, newValueKind, state); + processLoadIndexed(node, object, state); + } else { + processUnsafeStore(node, object, newValue, newValueKind, state); + processUnsafeLoad(node, object, state); + } } } } @@ -1607,10 +1461,10 @@ protected void processCommitAllocation(CommitAllocationNode commitAllocationNode ValueNode value = values.get(objectStartIndex + i); if (!value.isJavaConstant() || !value.asJavaConstant().isDefaultForKind()) { if (type.isArray()) { - processStoreIndexed(commitAllocationNode, object, value, state); + processStoreIndexed(commitAllocationNode, object, value, value.getStackKind(), state); } else { AnalysisField field = (AnalysisField) ((VirtualInstanceNode) virtualObject).field(i); - processStoreField(commitAllocationNode, field, object, value, state); + processStoreField(commitAllocationNode, field, object, value, value.getStackKind(), state); } } } @@ -1639,63 +1493,145 @@ protected void processNewInstance(ValueNode node, AnalysisType type, TypeFlowsOf state.add(node, newInstanceBuilder); } - protected void processStoreField(StoreFieldNode node, TypeFlowsOfNodes state) { - processStoreField(node, (AnalysisField) node.field(), node.object(), node.value(), state); + protected void processLoadField(ValueNode node, AnalysisField field, ValueNode object, TypeFlowsOfNodes state) { + field.registerAsRead(AbstractAnalysisEngine.sourcePosition(node)); + + if (bb.isSupportedJavaKind(node.getStackKind())) { + TypeFlowBuilder loadFieldBuilder; + if (field.isStatic()) { + loadFieldBuilder = TypeFlowBuilder.create(bb, node, LoadStaticFieldTypeFlow.class, () -> { + FieldTypeFlow fieldFlow = field.getStaticFieldFlow(); + LoadStaticFieldTypeFlow loadFieldFLow = new LoadStaticFieldTypeFlow(AbstractAnalysisEngine.sourcePosition(node), field, fieldFlow); + flowsGraph.addNodeFlow(node, loadFieldFLow); + return loadFieldFLow; + }); + } else { + TypeFlowBuilder objectBuilder = state.lookup(object); + loadFieldBuilder = TypeFlowBuilder.create(bb, node, LoadInstanceFieldTypeFlow.class, () -> { + LoadInstanceFieldTypeFlow loadFieldFLow = new LoadInstanceFieldTypeFlow(AbstractAnalysisEngine.sourcePosition(node), field, objectBuilder.get()); + flowsGraph.addNodeFlow(node, loadFieldFLow); + return loadFieldFLow; + }); + loadFieldBuilder.addObserverDependency(objectBuilder); + } + typeFlowGraphBuilder.registerSinkBuilder(loadFieldBuilder); + state.add(node, loadFieldBuilder); + } } - protected void processStoreField(ValueNode node, AnalysisField field, ValueNode object, ValueNode value, TypeFlowsOfNodes state) { - assert field.isWritten() : field; - if (bb.isSupportedJavaKind(value.getStackKind())) { - TypeFlowBuilder valueBuilder = state.lookup(value); + protected void processStoreField(ValueNode node, AnalysisField field, ValueNode object, ValueNode newValue, JavaKind newValueKind, TypeFlowsOfNodes state) { + field.registerAsWritten(AbstractAnalysisEngine.sourcePosition(node)); + + if (bb.isSupportedJavaKind(newValueKind)) { + TypeFlowBuilder valueBuilder = state.lookupOrAny(newValue, newValueKind); - TypeFlowBuilder storeFieldBuilder; - BytecodePosition storeLocation = AbstractAnalysisEngine.sourcePosition(node); + TypeFlowBuilder storeFieldBuilder; if (field.isStatic()) { - storeFieldBuilder = TypeFlowBuilder.create(bb, node, StoreFieldTypeFlow.class, () -> { + storeFieldBuilder = TypeFlowBuilder.create(bb, node, StoreStaticFieldTypeFlow.class, () -> { FieldTypeFlow fieldFlow = field.getStaticFieldFlow(); - StoreStaticFieldTypeFlow storeFieldFlow = new StoreStaticFieldTypeFlow(storeLocation, field, valueBuilder.get(), fieldFlow); + StoreStaticFieldTypeFlow storeFieldFlow = new StoreStaticFieldTypeFlow(AbstractAnalysisEngine.sourcePosition(node), field, valueBuilder.get(), fieldFlow); flowsGraph.addMiscEntryFlow(storeFieldFlow); return storeFieldFlow; }); - storeFieldBuilder.addUseDependency(valueBuilder); } else { TypeFlowBuilder objectBuilder = state.lookup(object); - storeFieldBuilder = TypeFlowBuilder.create(bb, node, StoreFieldTypeFlow.class, () -> { - StoreInstanceFieldTypeFlow storeFieldFlow = new StoreInstanceFieldTypeFlow(storeLocation, field, valueBuilder.get(), objectBuilder.get()); + storeFieldBuilder = TypeFlowBuilder.create(bb, node, StoreInstanceFieldTypeFlow.class, () -> { + StoreInstanceFieldTypeFlow storeFieldFlow = new StoreInstanceFieldTypeFlow(AbstractAnalysisEngine.sourcePosition(node), field, valueBuilder.get(), objectBuilder.get()); flowsGraph.addMiscEntryFlow(storeFieldFlow); return storeFieldFlow; }); - storeFieldBuilder.addUseDependency(valueBuilder); storeFieldBuilder.addObserverDependency(objectBuilder); } + storeFieldBuilder.addUseDependency(valueBuilder); /* Field stores must not be removed. */ typeFlowGraphBuilder.registerSinkBuilder(storeFieldBuilder); } } - private void processStoreIndexed(StoreIndexedNode node, TypeFlowsOfNodes state) { - processStoreIndexed(node, node.array(), node.value(), state); + protected void processLoadIndexed(ValueNode node, ValueNode array, TypeFlowsOfNodes state) { + /* All primitive array loads are always saturated. */ + if (node.getStackKind() == JavaKind.Object) { + TypeFlowBuilder arrayBuilder = state.lookup(array); + AnalysisType type = (AnalysisType) StampTool.typeOrNull(array, bb.getMetaAccess()); + AnalysisType arrayType = type.isArray() ? type : bb.getObjectArrayType(); + + TypeFlowBuilder loadIndexedBuilder = TypeFlowBuilder.create(bb, node, LoadIndexedTypeFlow.class, () -> { + LoadIndexedTypeFlow loadIndexedFlow = new LoadIndexedTypeFlow(AbstractAnalysisEngine.sourcePosition(node), arrayType, arrayBuilder.get()); + flowsGraph.addNodeFlow(node, loadIndexedFlow); + return loadIndexedFlow; + }); + + typeFlowGraphBuilder.registerSinkBuilder(loadIndexedBuilder); + loadIndexedBuilder.addObserverDependency(arrayBuilder); + state.add(node, loadIndexedBuilder); + } } - private void processStoreIndexed(ValueNode node, ValueNode array, ValueNode value, TypeFlowsOfNodes state) { - if (value.getStackKind() == JavaKind.Object) { + protected void processStoreIndexed(ValueNode node, ValueNode array, ValueNode newValue, JavaKind newValueKind, TypeFlowsOfNodes state) { + /* All primitive array loads are always saturated. */ + if (newValueKind == JavaKind.Object) { AnalysisType type = (AnalysisType) StampTool.typeOrNull(array, bb.getMetaAccess()); AnalysisType arrayType = type.isArray() ? type : bb.getObjectArrayType(); TypeFlowBuilder arrayBuilder = state.lookup(array); - TypeFlowBuilder valueBuilder = state.lookup(value); + TypeFlowBuilder valueBuilder = state.lookupOrAny(newValue, newValueKind); + TypeFlowBuilder storeIndexedBuilder = TypeFlowBuilder.create(bb, node, StoreIndexedTypeFlow.class, () -> { StoreIndexedTypeFlow storeIndexedFlow = new StoreIndexedTypeFlow(AbstractAnalysisEngine.sourcePosition(node), arrayType, arrayBuilder.get(), valueBuilder.get()); flowsGraph.addMiscEntryFlow(storeIndexedFlow); return storeIndexedFlow; }); + storeIndexedBuilder.addUseDependency(valueBuilder); storeIndexedBuilder.addObserverDependency(arrayBuilder); - /* Index stores must not be removed. */ typeFlowGraphBuilder.registerSinkBuilder(storeIndexedBuilder); } } + protected void processUnsafeLoad(ValueNode node, ValueNode object, TypeFlowsOfNodes state) { + /* All unsafe accessed primitive fields are always saturated. */ + if (node.getStackKind() == JavaKind.Object) { + TypeFlowBuilder objectBuilder = state.lookup(object); + + /* + * Use the Object type as a conservative approximation for both the receiver object type + * and the loaded values type. + */ + var loadBuilder = TypeFlowBuilder.create(bb, node, UnsafeLoadTypeFlow.class, () -> { + UnsafeLoadTypeFlow loadTypeFlow = new UnsafeLoadTypeFlow(AbstractAnalysisEngine.sourcePosition(node), bb.getObjectType(), bb.getObjectType(), objectBuilder.get()); + flowsGraph.addMiscEntryFlow(loadTypeFlow); + return loadTypeFlow; + }); + + loadBuilder.addObserverDependency(objectBuilder); + state.add(node, loadBuilder); + } + } + + protected void processUnsafeStore(ValueNode node, ValueNode object, ValueNode newValue, JavaKind newValueKind, TypeFlowsOfNodes state) { + /* All unsafe accessed primitive fields are always saturated. */ + if (newValueKind == JavaKind.Object) { + TypeFlowBuilder objectBuilder = state.lookup(object); + TypeFlowBuilder newValueBuilder = state.lookupOrAny(newValue, newValueKind); + + /* + * Use the Object type as a conservative approximation for both the receiver object type + * and the stored values type. + */ + var storeBuilder = TypeFlowBuilder.create(bb, node, UnsafeStoreTypeFlow.class, () -> { + UnsafeStoreTypeFlow storeTypeFlow = new UnsafeStoreTypeFlow(AbstractAnalysisEngine.sourcePosition(node), bb.getObjectType(), bb.getObjectType(), + objectBuilder.get(), newValueBuilder.get()); + flowsGraph.addMiscEntryFlow(storeTypeFlow); + return storeTypeFlow; + }); + + storeBuilder.addUseDependency(newValueBuilder); + storeBuilder.addObserverDependency(objectBuilder); + /* Offset stores must not be removed. */ + typeFlowGraphBuilder.registerSinkBuilder(storeBuilder); + } + } + /** Hook for unsafe offset value checks. */ protected void checkUnsafeOffset(@SuppressWarnings("unused") ValueNode base, @SuppressWarnings("unused") ValueNode offset) { } diff --git a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/phases/InlineBeforeAnalysisGraphDecoder.java b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/phases/InlineBeforeAnalysisGraphDecoder.java index 9857f6fbcf44..86c87c5b4dd7 100644 --- a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/phases/InlineBeforeAnalysisGraphDecoder.java +++ b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/phases/InlineBeforeAnalysisGraphDecoder.java @@ -26,7 +26,6 @@ import static com.oracle.graal.pointsto.phases.InlineBeforeAnalysisGraphDecoder.InlineBeforeAnalysisMethodScope.recordInlined; -import java.lang.reflect.Field; import java.util.ArrayDeque; import java.util.Deque; import java.util.concurrent.ConcurrentHashMap; @@ -35,13 +34,10 @@ import com.oracle.graal.pointsto.BigBang; import com.oracle.graal.pointsto.flow.AnalysisParsedGraph; -import com.oracle.graal.pointsto.meta.AnalysisField; import com.oracle.graal.pointsto.meta.AnalysisMethod; import com.oracle.graal.pointsto.meta.HostedProviders; import com.oracle.graal.pointsto.phases.InlineBeforeAnalysisPolicy.AbstractPolicyScope; import com.oracle.graal.pointsto.util.AnalysisError; -import com.oracle.graal.pointsto.util.GraalAccess; -import com.oracle.svm.util.ReflectionUtil; import jdk.graal.compiler.bytecode.BytecodeProvider; import jdk.graal.compiler.debug.GraalError; @@ -56,25 +52,18 @@ import jdk.graal.compiler.nodes.FixedNode; import jdk.graal.compiler.nodes.FixedWithNextNode; import jdk.graal.compiler.nodes.InvokeWithExceptionNode; -import jdk.graal.compiler.nodes.LogicConstantNode; import jdk.graal.compiler.nodes.StructuredGraph; import jdk.graal.compiler.nodes.ValueNode; -import jdk.graal.compiler.nodes.calc.IsNullNode; -import jdk.graal.compiler.nodes.extended.UnsafeAccessNode; import jdk.graal.compiler.nodes.graphbuilderconf.GraphBuilderContext; import jdk.graal.compiler.nodes.graphbuilderconf.InlineInvokePlugin; import jdk.graal.compiler.nodes.graphbuilderconf.InvocationPlugin; import jdk.graal.compiler.nodes.graphbuilderconf.LoopExplosionPlugin; -import jdk.graal.compiler.nodes.java.LoadFieldNode; import jdk.graal.compiler.nodes.java.MethodCallTargetNode; import jdk.graal.compiler.nodes.util.GraphUtil; import jdk.graal.compiler.replacements.PEGraphDecoder; import jdk.graal.compiler.replacements.nodes.MethodHandleWithExceptionNode; import jdk.graal.compiler.replacements.nodes.ResolvedMethodHandleCallTargetNode; -import jdk.vm.ci.meta.JavaConstant; -import jdk.vm.ci.meta.ResolvedJavaField; import jdk.vm.ci.meta.ResolvedJavaMethod; -import jdk.vm.ci.meta.ResolvedJavaType; public class InlineBeforeAnalysisGraphDecoder extends PEGraphDecoder { @@ -144,11 +133,6 @@ public InlineInfo shouldInlineInvoke(GraphBuilderContext b, ResolvedJavaMethod m } } - private Field dmhStaticAccessorOffsetField; - private Field dmhStaticAccessorBaseField; - private AnalysisField dmhStaticAccessorOffsetAnalysisField; - private AnalysisField dmhStaticAccessorBaseAnalysisField; - protected final BigBang bb; protected final InlineBeforeAnalysisPolicy policy; @@ -207,11 +191,7 @@ protected Node addFloatingNode(MethodScope methodScope, LoopScope loopScope, Nod @Override protected final Node canonicalizeFixedNode(MethodScope methodScope, LoopScope loopScope, Node node) { - Node canonical = node; - if (node instanceof UnsafeAccessNode unsafeAccess) { - canonical = canonicalizeUnsafeAccess(unsafeAccess); - } - canonical = super.canonicalizeFixedNode(methodScope, loopScope, canonical); + Node canonical = super.canonicalizeFixedNode(methodScope, loopScope, node); canonical = doCanonicalizeFixedNode(cast(methodScope), loopScope, canonical); /* * When no canonicalization was done, we check the node that was decoded (which is already @@ -236,93 +216,6 @@ protected Node doCanonicalizeFixedNode(InlineBeforeAnalysisMethodScope methodSco return node; } - /** - * Try to replace unsafe field accesses by offset via {@code DirectMethodHandle$StaticAccessor} - * with accesses to the actual target fields which can be constant-folded. This enables us to - * further simplify and inline through internal usages of {@code StaticAccessor} in method - * handle code itself, such as that generated by {@code InnerClassLambdaMetafactory}. A - * corresponding substitution recomputes the offsets stored in {@code StaticAccessor} objects to - * match those in the image, but it applies only much later. - * - * @see #canonicalizeIsNull - */ - private Node canonicalizeUnsafeAccess(UnsafeAccessNode node) { - if (!(node.isCanonicalizable() && node.offset() instanceof LoadFieldNode offsetLoad && offsetLoad.object() != null && offsetLoad.object().isJavaConstant())) { - return node; - } - ensureDMHStaticAccessorFieldsInitialized(); - if (!offsetLoad.field().equals(dmhStaticAccessorOffsetAnalysisField)) { - return node; - } - JavaConstant accessorConstant = offsetLoad.object().asJavaConstant(); - Object accessor = bb.getSnippetReflectionProvider().asObject(Object.class, accessorConstant); - long offset; - Class clazz; // HotSpot-specific: field holder Class object as Unsafe.staticFieldBase() - try { - offset = dmhStaticAccessorOffsetField.getLong(accessor); - clazz = (Class) dmhStaticAccessorBaseField.get(accessor); - } catch (IllegalAccessException e) { - throw AnalysisError.shouldNotReachHere(e); - } - if (clazz == null) { - return node; - } - ResolvedJavaType type = GraalAccess.getOriginalProviders().getMetaAccess().lookupJavaType(clazz); - ResolvedJavaField hostField = UnsafeAccessNode.findStaticFieldWithOffset(type, offset, node.accessKind()); - if (hostField == null) { - return node; - } - AnalysisField field = bb.getUniverse().lookup(hostField); - if (field.isInternal() || field.getJavaKind() != node.accessKind()) { - return node; - } - return node.cloneAsFieldAccess(field); - } - - @Override - protected Node handleFloatingNodeAfterAdd(MethodScope s, LoopScope loopScope, Node node) { - Node canonical = node; - if (canonical instanceof IsNullNode isNull) { - canonical = canonicalizeIsNull(isNull); - } - if (canonical != node) { - canonical.setNodeSourcePosition(node.getNodeSourcePosition()); - node.replaceAtUsagesAndDelete(canonical); - } - return super.handleFloatingNodeAfterAdd(s, loopScope, canonical); - } - - /** - * Constant-fold null checks of {@code DirectMethodHandle$StaticAccessor.staticBase}. This - * enables us to further simplify and inline through internal usages of {@code StaticAccessor} - * in method handle code itself, such as that generated by {@code InnerClassLambdaMetafactory}. - * A corresponding substitution computes the final value of {@code staticBase} in the image, but - * it applies only much later, and we know that it will never be {@code null}. - * - * @see #canonicalizeUnsafeAccess - */ - private Node canonicalizeIsNull(IsNullNode node) { - if (!(node.getValue() instanceof LoadFieldNode fieldLoad && fieldLoad.object() != null && fieldLoad.object().isJavaConstant())) { - return node; - } - ensureDMHStaticAccessorFieldsInitialized(); - if (!fieldLoad.field().equals(dmhStaticAccessorBaseAnalysisField)) { - return node; - } - // The base is always non-null, which we also assume in our field substitution. - return LogicConstantNode.contradiction(node.graph()); - } - - private void ensureDMHStaticAccessorFieldsInitialized() { - if (dmhStaticAccessorOffsetField == null) { - Class staticAccessorClass = ReflectionUtil.lookupClass(false, "java.lang.invoke.DirectMethodHandle$StaticAccessor"); - dmhStaticAccessorOffsetField = ReflectionUtil.lookupField(staticAccessorClass, "staticOffset"); - dmhStaticAccessorBaseField = ReflectionUtil.lookupField(staticAccessorClass, "staticBase"); - dmhStaticAccessorOffsetAnalysisField = bb.getMetaAccess().lookupJavaField(dmhStaticAccessorOffsetField); - dmhStaticAccessorBaseAnalysisField = bb.getMetaAccess().lookupJavaField(dmhStaticAccessorBaseField); - } - } - @Override protected void handleNonInlinedInvoke(MethodScope ms, LoopScope loopScope, InvokeData invokeData) { InlineBeforeAnalysisMethodScope methodScope = cast(ms); diff --git a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/results/StrengthenGraphs.java b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/results/StrengthenGraphs.java index e04e8a7f5b9a..d3cce8cf4d22 100644 --- a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/results/StrengthenGraphs.java +++ b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/results/StrengthenGraphs.java @@ -47,6 +47,7 @@ import com.oracle.graal.pointsto.flow.TypeFlow; import com.oracle.graal.pointsto.heap.ImageHeapConstant; import com.oracle.graal.pointsto.infrastructure.Universe; +import com.oracle.graal.pointsto.meta.AnalysisField; import com.oracle.graal.pointsto.meta.AnalysisMethod; import com.oracle.graal.pointsto.meta.AnalysisType; import com.oracle.graal.pointsto.meta.PointsToAnalysisMethod; @@ -92,6 +93,7 @@ import jdk.graal.compiler.nodes.calc.ConditionalNode; import jdk.graal.compiler.nodes.calc.IsNullNode; import jdk.graal.compiler.nodes.extended.BytecodeExceptionNode; +import jdk.graal.compiler.nodes.extended.FieldOffsetProvider; import jdk.graal.compiler.nodes.extended.ValueAnchorNode; import jdk.graal.compiler.nodes.java.ClassIsAssignableFromNode; import jdk.graal.compiler.nodes.java.InstanceOfNode; @@ -459,6 +461,13 @@ public void simplify(Node n, SimplifierTool tool) { if (node.values().get(i) instanceof ConstantNode constantNode && constantNode.getValue() instanceof ImageHeapConstant imageHeapConstant && !imageHeapConstant.isReachable()) { node.values().set(i, ConstantNode.defaultForKind(JavaKind.Object, graph)); } + if (node.values().get(i) instanceof FieldOffsetProvider fieldOffsetProvider && !((AnalysisField) fieldOffsetProvider.getField()).isUnsafeAccessed()) { + /* + * We use a unique marker constant as the replacement value, so that a + * search in the code base for the value leads us to here. + */ + node.values().set(i, ConstantNode.forIntegerKind(fieldOffsetProvider.asNode().getStackKind(), 0xDEA51106, graph)); + } } } else if (n instanceof PiNode) { diff --git a/substratevm/src/com.oracle.graal.reachability/src/com/oracle/graal/reachability/SimpleInMemoryMethodSummaryProvider.java b/substratevm/src/com.oracle.graal.reachability/src/com/oracle/graal/reachability/SimpleInMemoryMethodSummaryProvider.java index a8797640f858..68aaa5a8547f 100644 --- a/substratevm/src/com.oracle.graal.reachability/src/com/oracle/graal/reachability/SimpleInMemoryMethodSummaryProvider.java +++ b/substratevm/src/com.oracle.graal.reachability/src/com/oracle/graal/reachability/SimpleInMemoryMethodSummaryProvider.java @@ -45,6 +45,7 @@ import jdk.graal.compiler.nodes.FrameState; import jdk.graal.compiler.nodes.Invoke; import jdk.graal.compiler.nodes.StructuredGraph; +import jdk.graal.compiler.nodes.extended.FieldOffsetProvider; import jdk.graal.compiler.nodes.extended.ForeignCall; import jdk.graal.compiler.nodes.java.InstanceOfNode; import jdk.graal.compiler.nodes.java.LoadFieldNode; @@ -132,6 +133,8 @@ private static MethodSummary createSummaryFromGraph(ReachabilityAnalysisEngine b continue; } embeddedConstants.add(((JavaConstant) node.getValue())); + } else if (n instanceof FieldOffsetProvider node) { + ((AnalysisField) node.getField()).registerAsUnsafeAccessed(AbstractAnalysisEngine.sourcePosition(node.asNode())); } else if (n instanceof InstanceOfNode) { InstanceOfNode node = (InstanceOfNode) n; accessedTypes.add((ReachabilityAnalysisType) node.type().getType()); diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/fieldvaluetransformer/ArrayBaseOffsetFieldValueTransformer.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/fieldvaluetransformer/ArrayBaseOffsetFieldValueTransformer.java index 6438f1436e0a..03943be9e403 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/fieldvaluetransformer/ArrayBaseOffsetFieldValueTransformer.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/fieldvaluetransformer/ArrayBaseOffsetFieldValueTransformer.java @@ -33,8 +33,8 @@ public final class ArrayBaseOffsetFieldValueTransformer extends BoxingTransformer implements FieldValueTransformer { private final Class targetClass; - public ArrayBaseOffsetFieldValueTransformer(Class targetClass, Class returnType) { - super(returnType); + public ArrayBaseOffsetFieldValueTransformer(Class targetClass, JavaKind returnKind) { + super(returnKind); this.targetClass = targetClass; } diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/fieldvaluetransformer/ArrayIndexScaleFieldValueTransformer.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/fieldvaluetransformer/ArrayIndexScaleFieldValueTransformer.java index 265a1cc62f65..a728ddd09a0a 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/fieldvaluetransformer/ArrayIndexScaleFieldValueTransformer.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/fieldvaluetransformer/ArrayIndexScaleFieldValueTransformer.java @@ -33,8 +33,8 @@ public final class ArrayIndexScaleFieldValueTransformer extends BoxingTransformer implements FieldValueTransformer { private final Class targetClass; - public ArrayIndexScaleFieldValueTransformer(Class targetClass, Class returnType) { - super(returnType); + public ArrayIndexScaleFieldValueTransformer(Class targetClass, JavaKind returnKind) { + super(returnKind); this.targetClass = targetClass; } diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/fieldvaluetransformer/ArrayIndexShiftFieldValueTransformer.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/fieldvaluetransformer/ArrayIndexShiftFieldValueTransformer.java index 78b9da2d9bcd..d49314ce127b 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/fieldvaluetransformer/ArrayIndexShiftFieldValueTransformer.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/fieldvaluetransformer/ArrayIndexShiftFieldValueTransformer.java @@ -33,8 +33,8 @@ public final class ArrayIndexShiftFieldValueTransformer extends BoxingTransformer implements FieldValueTransformer { private final Class targetClass; - public ArrayIndexShiftFieldValueTransformer(Class targetClass, Class returnType) { - super(returnType); + public ArrayIndexShiftFieldValueTransformer(Class targetClass, JavaKind returnKind) { + super(returnKind); this.targetClass = targetClass; } diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/fieldvaluetransformer/BoxingTransformer.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/fieldvaluetransformer/BoxingTransformer.java index c64177c8f903..acf5fc962529 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/fieldvaluetransformer/BoxingTransformer.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/fieldvaluetransformer/BoxingTransformer.java @@ -26,20 +26,23 @@ import com.oracle.svm.core.util.VMError; +import jdk.vm.ci.meta.JavaKind; + abstract class BoxingTransformer { - private final Class returnType; + final JavaKind returnKind; - BoxingTransformer(Class returnType) { - this.returnType = returnType; + BoxingTransformer(JavaKind returnKind) { + this.returnKind = returnKind; } Object box(int value) { - if (returnType == int.class || returnType == Integer.class) { - return Integer.valueOf(value); - } else if (returnType == long.class || returnType == Long.class) { - return Long.valueOf(value); - } else { - throw VMError.shouldNotReachHere("Unexpected type: " + returnType); + switch (returnKind) { + case Int: + return Integer.valueOf(value); + case Long: + return Long.valueOf(value); + default: + throw VMError.shouldNotReachHere("Unexpected kind: " + returnKind); } } } diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/fieldvaluetransformer/FieldOffsetFieldValueTransformer.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/fieldvaluetransformer/FieldOffsetFieldValueTransformer.java index bb53ef42e85c..7225be1c2863 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/fieldvaluetransformer/FieldOffsetFieldValueTransformer.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/fieldvaluetransformer/FieldOffsetFieldValueTransformer.java @@ -26,14 +26,20 @@ import java.lang.reflect.Field; +import com.oracle.svm.core.graal.nodes.FieldOffsetNode; import com.oracle.svm.core.reflect.target.ReflectionSubstitutionSupport; import com.oracle.svm.core.util.VMError; +import jdk.graal.compiler.nodes.ValueNode; +import jdk.graal.compiler.nodes.spi.CoreProviders; +import jdk.vm.ci.meta.JavaConstant; +import jdk.vm.ci.meta.JavaKind; + public final class FieldOffsetFieldValueTransformer extends BoxingTransformer implements FieldValueTransformerWithAvailability { private final Field targetField; - public FieldOffsetFieldValueTransformer(Field targetField, Class returnType) { - super(returnType); + public FieldOffsetFieldValueTransformer(Field targetField, JavaKind returnKind) { + super(returnKind); this.targetField = targetField; } @@ -50,4 +56,9 @@ public Object transform(Object receiver, Object originalValue) { } return box(offset); } + + @Override + public ValueNode intrinsify(CoreProviders providers, JavaConstant receiver) { + return FieldOffsetNode.create(returnKind, providers.getMetaAccess().lookupJavaField(targetField)); + } } diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/fieldvaluetransformer/FieldValueTransformerWithAvailability.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/fieldvaluetransformer/FieldValueTransformerWithAvailability.java index ab2fba048d23..4c8cf6701dd4 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/fieldvaluetransformer/FieldValueTransformerWithAvailability.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/fieldvaluetransformer/FieldValueTransformerWithAvailability.java @@ -28,6 +28,10 @@ import org.graalvm.nativeimage.Platforms; import org.graalvm.nativeimage.hosted.FieldValueTransformer; +import jdk.graal.compiler.nodes.ValueNode; +import jdk.graal.compiler.nodes.spi.CoreProviders; +import jdk.vm.ci.meta.JavaConstant; + @Platforms(Platform.HOSTED_ONLY.class) public interface FieldValueTransformerWithAvailability extends FieldValueTransformer { @@ -60,4 +64,13 @@ enum ValueAvailability { * Returns information about when the value for this custom computation is available. */ ValueAvailability valueAvailability(); + + /** + * Optionally provide a Graal IR node to intrinsify the field access before the static analysis. + * This allows the compiler to optimize field values that are not available yet, as long as + * there is a dedicated high-level node available. + */ + default ValueNode intrinsify(CoreProviders providers, JavaConstant receiver) { + return null; + } } diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/fieldvaluetransformer/StaticFieldBaseFieldValueTransformer.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/fieldvaluetransformer/StaticFieldBaseFieldValueTransformer.java index 515a3b50db13..b9d06d6a976a 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/fieldvaluetransformer/StaticFieldBaseFieldValueTransformer.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/fieldvaluetransformer/StaticFieldBaseFieldValueTransformer.java @@ -28,6 +28,10 @@ import com.oracle.svm.core.StaticFieldsSupport; +import jdk.graal.compiler.nodes.ValueNode; +import jdk.graal.compiler.nodes.spi.CoreProviders; +import jdk.vm.ci.meta.JavaConstant; + public final class StaticFieldBaseFieldValueTransformer implements FieldValueTransformerWithAvailability { private final Field targetField; @@ -44,4 +48,9 @@ public ValueAvailability valueAvailability() { public Object transform(Object receiver, Object originalValue) { return targetField.getType().isPrimitive() ? StaticFieldsSupport.getStaticPrimitiveFields() : StaticFieldsSupport.getStaticObjectFields(); } + + @Override + public ValueNode intrinsify(CoreProviders providers, JavaConstant receiver) { + return StaticFieldsSupport.createStaticFieldBaseNode(targetField.getType().isPrimitive()); + } } diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/graal/nodes/FieldOffsetNode.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/graal/nodes/FieldOffsetNode.java new file mode 100644 index 000000000000..be4e20f0fc69 --- /dev/null +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/graal/nodes/FieldOffsetNode.java @@ -0,0 +1,108 @@ +/* + * Copyright (c) 2024, 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.svm.core.graal.nodes; + +import static jdk.graal.compiler.nodeinfo.NodeCycles.CYCLES_0; +import static jdk.graal.compiler.nodeinfo.NodeSize.SIZE_1; + +import com.oracle.svm.core.meta.SharedField; +import com.oracle.svm.core.util.VMError; + +import jdk.graal.compiler.core.common.type.StampFactory; +import jdk.graal.compiler.debug.GraalError; +import jdk.graal.compiler.graph.Node; +import jdk.graal.compiler.graph.NodeClass; +import jdk.graal.compiler.nodeinfo.NodeInfo; +import jdk.graal.compiler.nodes.ConstantNode; +import jdk.graal.compiler.nodes.NodeView; +import jdk.graal.compiler.nodes.ValueNode; +import jdk.graal.compiler.nodes.calc.FloatingNode; +import jdk.graal.compiler.nodes.calc.NarrowNode; +import jdk.graal.compiler.nodes.extended.FieldOffsetProvider; +import jdk.graal.compiler.nodes.spi.Canonicalizable; +import jdk.graal.compiler.nodes.spi.CanonicalizerTool; +import jdk.graal.compiler.nodes.spi.Lowerable; +import jdk.graal.compiler.nodes.spi.LoweringTool; +import jdk.vm.ci.meta.JavaKind; +import jdk.vm.ci.meta.ResolvedJavaField; + +/** + * A node that eventually replaces itself with a {@link ConstantNode} when the actual field offset + * is available. + */ +@NodeInfo(cycles = CYCLES_0, size = SIZE_1) +public final class FieldOffsetNode extends FloatingNode implements FieldOffsetProvider, Canonicalizable, Lowerable { + public static final NodeClass TYPE = NodeClass.create(FieldOffsetNode.class); + + /* + * Not marked as final because transplanting from the analysis to the hosted universe will + * change the value, so we want to make it clear in the field declaration already that the value + * changes over time. + */ + private ResolvedJavaField field; + + public static ValueNode create(JavaKind kind, ResolvedJavaField field) { + var fieldOffset = new FieldOffsetNode(field); + switch (kind) { + case Long: + return fieldOffset; + case Int: + /* + * The Unsafe access nodes that consume the field offset always require the offset + * as a long value, so there must be SignExtendNode in between. Emitting a + * NarrowNode ensures that the SignExtendNode is canonicalized away. + */ + return NarrowNode.create(fieldOffset, kind.getBitCount(), NodeView.DEFAULT); + default: + throw GraalError.shouldNotReachHere("Unsupported kind: " + kind); + } + } + + protected FieldOffsetNode(ResolvedJavaField field) { + super(TYPE, StampFactory.forInteger(JavaKind.Long, 0, Integer.MAX_VALUE)); + this.field = field; + } + + public ResolvedJavaField getField() { + return field; + } + + @Override + public Node canonical(CanonicalizerTool tool) { + if (field instanceof SharedField sharedField) { + long fieldOffset = sharedField.getLocation(); + if (fieldOffset <= 0) { + throw VMError.shouldNotReachHere("No offset for field " + field); + } + return ConstantNode.forIntegerKind(stamp.getStackKind(), fieldOffset); + } + return this; + } + + @Override + public void lower(LoweringTool tool) { + throw GraalError.shouldNotReachHere("Field offset must be available before first lowering: " + field); // ExcludeFromJacocoGeneratedReport + } +} diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/graal/nodes/LazyConstantNode.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/graal/nodes/LazyConstantNode.java deleted file mode 100644 index 1a57c33b0f73..000000000000 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/graal/nodes/LazyConstantNode.java +++ /dev/null @@ -1,99 +0,0 @@ -/* - * Copyright (c) 2021, 2023, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.oracle.svm.core.graal.nodes; - -import static jdk.graal.compiler.nodeinfo.NodeCycles.CYCLES_0; -import static jdk.graal.compiler.nodeinfo.NodeSize.SIZE_1; - -import java.util.function.Function; - -import jdk.graal.compiler.core.common.type.Stamp; -import jdk.graal.compiler.debug.GraalError; -import jdk.graal.compiler.graph.Node; -import jdk.graal.compiler.graph.NodeClass; -import jdk.graal.compiler.nodeinfo.NodeInfo; -import jdk.graal.compiler.nodes.ConstantNode; -import jdk.graal.compiler.nodes.NodeView; -import jdk.graal.compiler.nodes.ValueNode; -import jdk.graal.compiler.nodes.calc.FloatingNode; -import jdk.graal.compiler.nodes.spi.Canonicalizable; -import jdk.graal.compiler.nodes.spi.CanonicalizerTool; -import jdk.graal.compiler.nodes.spi.CoreProviders; -import jdk.graal.compiler.nodes.spi.Lowerable; -import jdk.graal.compiler.nodes.spi.LoweringTool; - -import jdk.vm.ci.meta.JavaConstant; - -/** - * A node that eventually replaces itself with a {@link ConstantNode} when the actual constant value - * is available. That must be before the first lowering. - */ -@NodeInfo(cycles = CYCLES_0, size = SIZE_1) -public final class LazyConstantNode extends FloatingNode implements Canonicalizable, Lowerable { - public static final NodeClass TYPE = NodeClass.create(LazyConstantNode.class); - - private final Function constantSupplier; - - protected LazyConstantNode(Stamp stamp, Function constantSupplier) { - super(TYPE, stamp); - this.constantSupplier = constantSupplier; - } - - public static ValueNode create(Stamp stamp, Function constantSupplier, CoreProviders providers) { - ValueNode result = findSynonym(stamp, constantSupplier, providers); - if (result != null) { - return result; - } - return new LazyConstantNode(stamp, constantSupplier); - } - - @Override - public Node canonical(CanonicalizerTool tool) { - ValueNode result = findSynonym(stamp, constantSupplier, tool); - if (result != null) { - return result; - } - return this; - } - - private static ValueNode findSynonym(Stamp stamp, Function constantSupplier, CoreProviders providers) { - JavaConstant constant = constantSupplier.apply(providers); - if (constant == null) { - /* Constant not available yet. */ - return null; - } - ConstantNode constantNode = ConstantNode.forConstant(constant, providers.getMetaAccess()); - - Stamp newStamp = constantNode.stamp(NodeView.DEFAULT); - GraalError.guarantee(newStamp.join(stamp) == newStamp, "Stamp can only improve"); - - return constantNode; - } - - @Override - public void lower(LoweringTool tool) { - throw GraalError.shouldNotReachHere("Constant value must have been computed before first lowering"); // ExcludeFromJacocoGeneratedReport - } -} diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/VarHandleFeature.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/VarHandleFeature.java index c79167ebf497..b440654fb149 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/VarHandleFeature.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/VarHandleFeature.java @@ -41,18 +41,22 @@ import com.oracle.svm.core.StaticFieldsSupport; import com.oracle.svm.core.annotate.Alias; -import com.oracle.svm.core.annotate.InjectAccessors; import com.oracle.svm.core.annotate.RecomputeFieldValue; import com.oracle.svm.core.annotate.RecomputeFieldValue.Kind; import com.oracle.svm.core.annotate.TargetClass; import com.oracle.svm.core.feature.AutomaticallyRegisteredFeature; import com.oracle.svm.core.feature.InternalFeature; import com.oracle.svm.core.fieldvaluetransformer.FieldValueTransformerWithAvailability; +import com.oracle.svm.core.graal.nodes.FieldOffsetNode; import com.oracle.svm.core.reflect.target.ReflectionSubstitutionSupport; import com.oracle.svm.core.util.VMError; import com.oracle.svm.util.ReflectionUtil; +import jdk.graal.compiler.nodes.ValueNode; +import jdk.graal.compiler.nodes.spi.CoreProviders; import jdk.internal.misc.Unsafe; +import jdk.vm.ci.meta.JavaConstant; +import jdk.vm.ci.meta.JavaKind; /** * This file contains most of the code necessary for supporting VarHandle (and DirectMethodHandle @@ -84,10 +88,7 @@ * same custom field value recomputation handler: {@link VarHandleFieldOffsetComputer}. * * For static fields, also the base of the Unsafe access needs to be changed to the static field - * holder arrays defined in {@link StaticFieldsSupport}. We cannot do a recomputation to the actual - * arrays because the arrays are only available after static analysis. So we inject accessor methods - * instead that read our holder fields: {@link VarHandleFieldStaticBasePrimitiveAccessor} and - * {@link VarHandleFieldStaticBaseObjectAccessor}. + * holder arrays defined in {@link StaticFieldsSupport}: {@link VarHandleStaticBaseComputer}. * * VarHandle access to arrays is the simplest case: we only need field value recomputations for the * array base offset and array index shift. @@ -307,7 +308,14 @@ class VarHandleInfo { } } -class VarHandleFieldOffsetIntComputer implements FieldValueTransformerWithAvailability { +abstract class VarHandleFieldOffsetComputer implements FieldValueTransformerWithAvailability { + + private final JavaKind kind; + + VarHandleFieldOffsetComputer(JavaKind kind) { + this.kind = kind; + } + @Override public ValueAvailability valueAvailability() { return ValueAvailability.AfterAnalysis; @@ -320,37 +328,60 @@ public Object transform(Object receiver, Object originalValue) { if (offset <= 0) { throw VMError.shouldNotReachHere("Field is not marked as unsafe accessed: " + field); } - return offset; + + switch (kind) { + case Int: + return Integer.valueOf(offset); + case Long: + return Long.valueOf(offset); + default: + throw VMError.shouldNotReachHere("Invalid kind: " + kind); + } } -} -class VarHandleFieldOffsetComputer extends VarHandleFieldOffsetIntComputer { @Override - public Object transform(Object receiver, Object originalValue) { - Object offset = super.transform(receiver, originalValue); - return Long.valueOf((Integer) offset); + public ValueNode intrinsify(CoreProviders providers, JavaConstant receiver) { + Object varHandle = providers.getSnippetReflection().asObject(Object.class, receiver); + if (varHandle != null) { + Field field = ImageSingletons.lookup(VarHandleFeature.class).findVarHandleField(varHandle); + return FieldOffsetNode.create(kind, providers.getMetaAccess().lookupJavaField(field)); + } + return null; } } -class VarHandleFieldStaticBasePrimitiveAccessor { - static Object get(@SuppressWarnings("unused") Object varHandle) { - return StaticFieldsSupport.getStaticPrimitiveFields(); +class VarHandleFieldOffsetAsIntComputer extends VarHandleFieldOffsetComputer { + VarHandleFieldOffsetAsIntComputer() { + super(JavaKind.Int); } +} - @SuppressWarnings("unused") - static void set(Object varHandle, Object value) { - assert value == StaticFieldsSupport.getStaticPrimitiveFields(); +class VarHandleFieldOffsetAsLongComputer extends VarHandleFieldOffsetComputer { + VarHandleFieldOffsetAsLongComputer() { + super(JavaKind.Long); } } -class VarHandleFieldStaticBaseObjectAccessor { - static Object get(@SuppressWarnings("unused") Object varHandle) { - return StaticFieldsSupport.getStaticObjectFields(); +class VarHandleStaticBaseComputer implements FieldValueTransformerWithAvailability { + @Override + public ValueAvailability valueAvailability() { + return ValueAvailability.AfterAnalysis; + } + + @Override + public Object transform(Object receiver, Object originalValue) { + Field field = ImageSingletons.lookup(VarHandleFeature.class).findVarHandleField(receiver); + return field.getType().isPrimitive() ? StaticFieldsSupport.getStaticPrimitiveFields() : StaticFieldsSupport.getStaticObjectFields(); } - @SuppressWarnings("unused") - static void set(Object varHandle, Object value) { - assert value == StaticFieldsSupport.getStaticObjectFields(); + @Override + public ValueNode intrinsify(CoreProviders providers, JavaConstant receiver) { + Object varHandle = providers.getSnippetReflection().asObject(Object.class, receiver); + if (varHandle != null) { + Field field = ImageSingletons.lookup(VarHandleFeature.class).findVarHandleField(varHandle); + return StaticFieldsSupport.createStaticFieldBaseNode(field.getType().isPrimitive()); + } + return null; } } @@ -448,55 +479,55 @@ final class Target_java_lang_invoke_VarHandleReferences_Array { @TargetClass(className = "java.lang.invoke.VarHandleBooleans", innerClass = "FieldInstanceReadOnly") final class Target_java_lang_invoke_VarHandleBooleans_FieldInstanceReadOnly { - @Alias @RecomputeFieldValue(kind = Kind.Custom, declClass = VarHandleFieldOffsetComputer.class) // + @Alias @RecomputeFieldValue(kind = Kind.Custom, declClass = VarHandleFieldOffsetAsLongComputer.class) // long fieldOffset; } @TargetClass(className = "java.lang.invoke.VarHandleBytes", innerClass = "FieldInstanceReadOnly") final class Target_java_lang_invoke_VarHandleBytes_FieldInstanceReadOnly { - @Alias @RecomputeFieldValue(kind = Kind.Custom, declClass = VarHandleFieldOffsetComputer.class) // + @Alias @RecomputeFieldValue(kind = Kind.Custom, declClass = VarHandleFieldOffsetAsLongComputer.class) // long fieldOffset; } @TargetClass(className = "java.lang.invoke.VarHandleChars", innerClass = "FieldInstanceReadOnly") final class Target_java_lang_invoke_VarHandleChars_FieldInstanceReadOnly { - @Alias @RecomputeFieldValue(kind = Kind.Custom, declClass = VarHandleFieldOffsetComputer.class) // + @Alias @RecomputeFieldValue(kind = Kind.Custom, declClass = VarHandleFieldOffsetAsLongComputer.class) // long fieldOffset; } @TargetClass(className = "java.lang.invoke.VarHandleDoubles", innerClass = "FieldInstanceReadOnly") final class Target_java_lang_invoke_VarHandleDoubles_FieldInstanceReadOnly { - @Alias @RecomputeFieldValue(kind = Kind.Custom, declClass = VarHandleFieldOffsetComputer.class) // + @Alias @RecomputeFieldValue(kind = Kind.Custom, declClass = VarHandleFieldOffsetAsLongComputer.class) // long fieldOffset; } @TargetClass(className = "java.lang.invoke.VarHandleFloats", innerClass = "FieldInstanceReadOnly") final class Target_java_lang_invoke_VarHandleFloats_FieldInstanceReadOnly { - @Alias @RecomputeFieldValue(kind = Kind.Custom, declClass = VarHandleFieldOffsetComputer.class) // + @Alias @RecomputeFieldValue(kind = Kind.Custom, declClass = VarHandleFieldOffsetAsLongComputer.class) // long fieldOffset; } @TargetClass(className = "java.lang.invoke.VarHandleInts", innerClass = "FieldInstanceReadOnly") final class Target_java_lang_invoke_VarHandleInts_FieldInstanceReadOnly { - @Alias @RecomputeFieldValue(kind = Kind.Custom, declClass = VarHandleFieldOffsetComputer.class) // + @Alias @RecomputeFieldValue(kind = Kind.Custom, declClass = VarHandleFieldOffsetAsLongComputer.class) // long fieldOffset; } @TargetClass(className = "java.lang.invoke.VarHandleLongs", innerClass = "FieldInstanceReadOnly") final class Target_java_lang_invoke_VarHandleLongs_FieldInstanceReadOnly { - @Alias @RecomputeFieldValue(kind = Kind.Custom, declClass = VarHandleFieldOffsetComputer.class) // + @Alias @RecomputeFieldValue(kind = Kind.Custom, declClass = VarHandleFieldOffsetAsLongComputer.class) // long fieldOffset; } @TargetClass(className = "java.lang.invoke.VarHandleShorts", innerClass = "FieldInstanceReadOnly") final class Target_java_lang_invoke_VarHandleShorts_FieldInstanceReadOnly { - @Alias @RecomputeFieldValue(kind = Kind.Custom, declClass = VarHandleFieldOffsetComputer.class) // + @Alias @RecomputeFieldValue(kind = Kind.Custom, declClass = VarHandleFieldOffsetAsLongComputer.class) // long fieldOffset; } @TargetClass(className = "java.lang.invoke.VarHandleReferences", innerClass = "FieldInstanceReadOnly") final class Target_java_lang_invoke_VarHandleReferences_FieldInstanceReadOnly { - @Alias @RecomputeFieldValue(kind = Kind.Custom, declClass = VarHandleFieldOffsetComputer.class) // + @Alias @RecomputeFieldValue(kind = Kind.Custom, declClass = VarHandleFieldOffsetAsLongComputer.class) // long fieldOffset; } @@ -509,73 +540,73 @@ final class Target_java_lang_invoke_VarHandleReferences_FieldInstanceReadOnly { @TargetClass(className = "java.lang.invoke.VarHandleBooleans", innerClass = "FieldStaticReadOnly") final class Target_java_lang_invoke_VarHandleBooleans_FieldStaticReadOnly { - @Alias @InjectAccessors(VarHandleFieldStaticBasePrimitiveAccessor.class) // + @Alias @RecomputeFieldValue(kind = Kind.Custom, declClass = VarHandleStaticBaseComputer.class) // Object base; - @Alias @RecomputeFieldValue(kind = Kind.Custom, declClass = VarHandleFieldOffsetComputer.class) // + @Alias @RecomputeFieldValue(kind = Kind.Custom, declClass = VarHandleFieldOffsetAsLongComputer.class) // long fieldOffset; } @TargetClass(className = "java.lang.invoke.VarHandleBytes", innerClass = "FieldStaticReadOnly") final class Target_java_lang_invoke_VarHandleBytes_FieldStaticReadOnly { - @Alias @InjectAccessors(VarHandleFieldStaticBasePrimitiveAccessor.class) // + @Alias @RecomputeFieldValue(kind = Kind.Custom, declClass = VarHandleStaticBaseComputer.class) // Object base; - @Alias @RecomputeFieldValue(kind = Kind.Custom, declClass = VarHandleFieldOffsetComputer.class) // + @Alias @RecomputeFieldValue(kind = Kind.Custom, declClass = VarHandleFieldOffsetAsLongComputer.class) // long fieldOffset; } @TargetClass(className = "java.lang.invoke.VarHandleChars", innerClass = "FieldStaticReadOnly") final class Target_java_lang_invoke_VarHandleChars_FieldStaticReadOnly { - @Alias @InjectAccessors(VarHandleFieldStaticBasePrimitiveAccessor.class) // + @Alias @RecomputeFieldValue(kind = Kind.Custom, declClass = VarHandleStaticBaseComputer.class) // Object base; - @Alias @RecomputeFieldValue(kind = Kind.Custom, declClass = VarHandleFieldOffsetComputer.class) // + @Alias @RecomputeFieldValue(kind = Kind.Custom, declClass = VarHandleFieldOffsetAsLongComputer.class) // long fieldOffset; } @TargetClass(className = "java.lang.invoke.VarHandleDoubles", innerClass = "FieldStaticReadOnly") final class Target_java_lang_invoke_VarHandleDoubles_FieldStaticReadOnly { - @Alias @InjectAccessors(VarHandleFieldStaticBasePrimitiveAccessor.class) // + @Alias @RecomputeFieldValue(kind = Kind.Custom, declClass = VarHandleStaticBaseComputer.class) // Object base; - @Alias @RecomputeFieldValue(kind = Kind.Custom, declClass = VarHandleFieldOffsetComputer.class) // + @Alias @RecomputeFieldValue(kind = Kind.Custom, declClass = VarHandleFieldOffsetAsLongComputer.class) // long fieldOffset; } @TargetClass(className = "java.lang.invoke.VarHandleFloats", innerClass = "FieldStaticReadOnly") final class Target_java_lang_invoke_VarHandleFloats_FieldStaticReadOnly { - @Alias @InjectAccessors(VarHandleFieldStaticBasePrimitiveAccessor.class) // + @Alias @RecomputeFieldValue(kind = Kind.Custom, declClass = VarHandleStaticBaseComputer.class) // Object base; - @Alias @RecomputeFieldValue(kind = Kind.Custom, declClass = VarHandleFieldOffsetComputer.class) // + @Alias @RecomputeFieldValue(kind = Kind.Custom, declClass = VarHandleFieldOffsetAsLongComputer.class) // long fieldOffset; } @TargetClass(className = "java.lang.invoke.VarHandleInts", innerClass = "FieldStaticReadOnly") final class Target_java_lang_invoke_VarHandleInts_FieldStaticReadOnly { - @Alias @InjectAccessors(VarHandleFieldStaticBasePrimitiveAccessor.class) // + @Alias @RecomputeFieldValue(kind = Kind.Custom, declClass = VarHandleStaticBaseComputer.class) // Object base; - @Alias @RecomputeFieldValue(kind = Kind.Custom, declClass = VarHandleFieldOffsetComputer.class) // + @Alias @RecomputeFieldValue(kind = Kind.Custom, declClass = VarHandleFieldOffsetAsLongComputer.class) // long fieldOffset; } @TargetClass(className = "java.lang.invoke.VarHandleLongs", innerClass = "FieldStaticReadOnly") final class Target_java_lang_invoke_VarHandleLongs_FieldStaticReadOnly { - @Alias @InjectAccessors(VarHandleFieldStaticBasePrimitiveAccessor.class) // + @Alias @RecomputeFieldValue(kind = Kind.Custom, declClass = VarHandleStaticBaseComputer.class) // Object base; - @Alias @RecomputeFieldValue(kind = Kind.Custom, declClass = VarHandleFieldOffsetComputer.class) // + @Alias @RecomputeFieldValue(kind = Kind.Custom, declClass = VarHandleFieldOffsetAsLongComputer.class) // long fieldOffset; } @TargetClass(className = "java.lang.invoke.VarHandleShorts", innerClass = "FieldStaticReadOnly") final class Target_java_lang_invoke_VarHandleShorts_FieldStaticReadOnly { - @Alias @InjectAccessors(VarHandleFieldStaticBasePrimitiveAccessor.class) // + @Alias @RecomputeFieldValue(kind = Kind.Custom, declClass = VarHandleStaticBaseComputer.class) // Object base; - @Alias @RecomputeFieldValue(kind = Kind.Custom, declClass = VarHandleFieldOffsetComputer.class) // + @Alias @RecomputeFieldValue(kind = Kind.Custom, declClass = VarHandleFieldOffsetAsLongComputer.class) // long fieldOffset; } @TargetClass(className = "java.lang.invoke.VarHandleReferences", innerClass = "FieldStaticReadOnly") final class Target_java_lang_invoke_VarHandleReferences_FieldStaticReadOnly { - @Alias @InjectAccessors(VarHandleFieldStaticBaseObjectAccessor.class) // + @Alias @RecomputeFieldValue(kind = Kind.Custom, declClass = VarHandleStaticBaseComputer.class) // Object base; - @Alias @RecomputeFieldValue(kind = Kind.Custom, declClass = VarHandleFieldOffsetComputer.class) // + @Alias @RecomputeFieldValue(kind = Kind.Custom, declClass = VarHandleFieldOffsetAsLongComputer.class) // long fieldOffset; } @@ -586,32 +617,14 @@ final class Target_java_lang_invoke_VarHandleReferences_FieldStaticReadOnly { @TargetClass(className = "java.lang.invoke.DirectMethodHandle", innerClass = "Accessor") final class Target_java_lang_invoke_DirectMethodHandle_Accessor { - @Alias @RecomputeFieldValue(kind = RecomputeFieldValue.Kind.Custom, declClass = VarHandleFieldOffsetIntComputer.class) // + @Alias @RecomputeFieldValue(kind = RecomputeFieldValue.Kind.Custom, declClass = VarHandleFieldOffsetAsIntComputer.class) // int fieldOffset; } @TargetClass(className = "java.lang.invoke.DirectMethodHandle", innerClass = "StaticAccessor") final class Target_java_lang_invoke_DirectMethodHandle_StaticAccessor { - @Alias // - Class fieldType; - @Alias @RecomputeFieldValue(kind = RecomputeFieldValue.Kind.Custom, declClass = StaticAccessorFieldStaticBaseComputer.class) // + @Alias @RecomputeFieldValue(kind = RecomputeFieldValue.Kind.Custom, declClass = VarHandleStaticBaseComputer.class) // Object staticBase; - @Alias @RecomputeFieldValue(kind = RecomputeFieldValue.Kind.Custom, declClass = VarHandleFieldOffsetComputer.class) // + @Alias @RecomputeFieldValue(kind = RecomputeFieldValue.Kind.Custom, declClass = VarHandleFieldOffsetAsLongComputer.class) // long staticOffset; } - -class StaticAccessorFieldStaticBaseComputer implements FieldValueTransformerWithAvailability { - @Override - public FieldValueTransformerWithAvailability.ValueAvailability valueAvailability() { - return FieldValueTransformerWithAvailability.ValueAvailability.AfterAnalysis; - } - - @Override - public Object transform(Object receiver, Object originalValue) { - Field field = ImageSingletons.lookup(VarHandleFeature.class).findVarHandleField(receiver); - if (field.getType().isPrimitive()) { - return StaticFieldsSupport.getStaticPrimitiveFields(); - } - return StaticFieldsSupport.getStaticObjectFields(); - } -} diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/ameta/FieldValueInterceptionSupport.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/ameta/FieldValueInterceptionSupport.java index 0f47e7f47d0d..0500a5a0c95a 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/ameta/FieldValueInterceptionSupport.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/ameta/FieldValueInterceptionSupport.java @@ -36,6 +36,7 @@ import org.graalvm.nativeimage.hosted.Feature.BeforeAnalysisAccess; import org.graalvm.nativeimage.hosted.FieldValueTransformer; +import com.oracle.graal.pointsto.heap.ImageHeapConstant; import com.oracle.graal.pointsto.infrastructure.OriginalClassProvider; import com.oracle.graal.pointsto.infrastructure.OriginalFieldProvider; import com.oracle.graal.pointsto.meta.AnalysisField; @@ -60,6 +61,9 @@ import com.oracle.svm.hosted.substitute.FieldValueTransformation; import com.oracle.svm.util.ReflectionUtil; +import jdk.graal.compiler.nodes.ValueNode; +import jdk.graal.compiler.nodes.java.LoadFieldNode; +import jdk.graal.compiler.nodes.spi.CoreProviders; import jdk.graal.compiler.word.Word; import jdk.vm.ci.hotspot.HotSpotResolvedJavaField; import jdk.vm.ci.meta.JavaConstant; @@ -247,6 +251,43 @@ public boolean hasFieldValueTransformer(AnalysisField field) { return false; } + /** + * Returns the Graal IR node that intrinsifies the provided field load, or null if no + * intrinsification is possible. + */ + public ValueNode tryIntrinsifyFieldLoad(CoreProviders providers, LoadFieldNode node) { + var field = (AnalysisField) node.field(); + + FieldValueTransformer transformer = null; + var interceptor = lookupFieldValueInterceptor(field); + if (interceptor instanceof FieldValueTransformation transformation) { + transformer = transformation.getFieldValueTransformer(); + } else if (field.wrapped instanceof ComputedValueField computedValueField) { + transformer = computedValueField.getFieldValueTransformer(); + } + if (!(transformer instanceof FieldValueTransformerWithAvailability transformerWithAvailability)) { + return null; + } + + JavaConstant receiver; + if (field.isStatic()) { + receiver = null; + } else { + receiver = node.object().asJavaConstant(); + /* + * The receiver constant might not be an instance of the field's declaring class, + * because during optimizations the load can actually be dead code that will be removed + * later. We do not want to burden the field value transformers with such details, so we + * check here. + */ + if (!(receiver instanceof ImageHeapConstant imageHeapConstant) || !field.getDeclaringClass().isAssignableFrom(imageHeapConstant.getType())) { + return null; + } + } + + return transformerWithAvailability.intrinsify(providers, receiver); + } + JavaConstant readFieldValue(ClassInitializationSupport classInitializationSupport, AnalysisField field, JavaConstant receiver) { assert isValueAvailable(field) : field; JavaConstant value; diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/classinitialization/SimulateClassInitializerGraphDecoder.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/classinitialization/SimulateClassInitializerGraphDecoder.java index 9c0fce256baa..5f91af0d4802 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/classinitialization/SimulateClassInitializerGraphDecoder.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/classinitialization/SimulateClassInitializerGraphDecoder.java @@ -294,6 +294,10 @@ private Node handleLoadFieldNode(LoadFieldNode node) { return ConstantNode.forConstant(currentValue, metaAccess); } } + var intrinsified = support.fieldValueInterceptionSupport.tryIntrinsifyFieldLoad(providers, node); + if (intrinsified != null) { + return intrinsified; + } return node; } diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/classinitialization/SimulateClassInitializerSupport.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/classinitialization/SimulateClassInitializerSupport.java index 5d5ca8d5b022..205699b3bce8 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/classinitialization/SimulateClassInitializerSupport.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/classinitialization/SimulateClassInitializerSupport.java @@ -44,6 +44,7 @@ import com.oracle.svm.core.util.VMError; import com.oracle.svm.hosted.SVMHost; import com.oracle.svm.hosted.ameta.AnalysisConstantReflectionProvider; +import com.oracle.svm.hosted.ameta.FieldValueInterceptionSupport; import com.oracle.svm.hosted.fieldfolding.MarkStaticFinalFieldInitializedNode; import com.oracle.svm.hosted.meta.HostedConstantReflectionProvider; import com.oracle.svm.hosted.meta.HostedType; @@ -163,6 +164,7 @@ public class SimulateClassInitializerSupport { protected final ClassInitializationSupport classInitializationSupport = ClassInitializationSupport.singleton(); + protected final FieldValueInterceptionSupport fieldValueInterceptionSupport = FieldValueInterceptionSupport.singleton(); protected final SimulateClassInitializerPolicy simulateClassInitializerPolicy; protected final SimulateClassInitializerConstantFieldProvider simulatedFieldValueConstantFieldProvider; diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/phases/InlineBeforeAnalysisGraphDecoderImpl.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/phases/InlineBeforeAnalysisGraphDecoderImpl.java index fd6bb04e0a5e..d9ee3c359e51 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/phases/InlineBeforeAnalysisGraphDecoderImpl.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/phases/InlineBeforeAnalysisGraphDecoderImpl.java @@ -24,11 +24,6 @@ */ package com.oracle.svm.hosted.phases; -import jdk.graal.compiler.graph.Node; -import jdk.graal.compiler.nodes.ConstantNode; -import jdk.graal.compiler.nodes.StructuredGraph; -import jdk.graal.compiler.nodes.java.LoadFieldNode; - import com.oracle.graal.pointsto.BigBang; import com.oracle.graal.pointsto.meta.AnalysisField; import com.oracle.graal.pointsto.meta.AnalysisType; @@ -36,12 +31,19 @@ import com.oracle.graal.pointsto.phases.InlineBeforeAnalysisGraphDecoder; import com.oracle.graal.pointsto.phases.InlineBeforeAnalysisPolicy; import com.oracle.svm.core.classinitialization.EnsureClassInitializedNode; +import com.oracle.svm.hosted.ameta.FieldValueInterceptionSupport; import com.oracle.svm.hosted.classinitialization.SimulateClassInitializerSupport; import com.oracle.svm.hosted.fieldfolding.IsStaticFinalFieldInitializedNode; +import jdk.graal.compiler.graph.Node; +import jdk.graal.compiler.nodes.ConstantNode; +import jdk.graal.compiler.nodes.StructuredGraph; +import jdk.graal.compiler.nodes.java.LoadFieldNode; + public class InlineBeforeAnalysisGraphDecoderImpl extends InlineBeforeAnalysisGraphDecoder { private final SimulateClassInitializerSupport simulateClassInitializerSupport = SimulateClassInitializerSupport.singleton(); + private final FieldValueInterceptionSupport fieldValueInterceptionSupport = FieldValueInterceptionSupport.singleton(); public InlineBeforeAnalysisGraphDecoderImpl(BigBang bb, InlineBeforeAnalysisPolicy policy, StructuredGraph graph, HostedProviders providers) { super(bb, policy, graph, providers, null); @@ -93,6 +95,10 @@ private Node handleLoadFieldNode(LoadFieldNode node) { if (canonicalized != null) { return canonicalized; } + var intrinsified = fieldValueInterceptionSupport.tryIntrinsifyFieldLoad(providers, node); + if (intrinsified != null) { + return intrinsified; + } return node; } diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/phases/SharedGraphBuilderPhase.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/phases/SharedGraphBuilderPhase.java index b94c1f202b5b..ede2b2748b9f 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/phases/SharedGraphBuilderPhase.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/phases/SharedGraphBuilderPhase.java @@ -60,7 +60,7 @@ import com.oracle.svm.core.graal.nodes.DeoptEntryNode; import com.oracle.svm.core.graal.nodes.DeoptEntrySupport; import com.oracle.svm.core.graal.nodes.DeoptProxyAnchorNode; -import com.oracle.svm.core.graal.nodes.LazyConstantNode; +import com.oracle.svm.core.graal.nodes.FieldOffsetNode; import com.oracle.svm.core.graal.nodes.LoweredDeadEndNode; import com.oracle.svm.core.hub.DynamicHub; import com.oracle.svm.core.meta.DirectSubstrateObjectConstant; @@ -74,7 +74,6 @@ import com.oracle.svm.hosted.code.FactoryMethodSupport; import com.oracle.svm.hosted.code.SubstrateCompilationDirectives; import com.oracle.svm.hosted.nodes.DeoptProxyNode; -import com.oracle.svm.hosted.snippets.SubstrateGraphBuilderPlugins.FieldOffsetConstantProvider; import com.oracle.svm.util.ReflectionUtil; import jdk.graal.compiler.api.replacements.Fold; @@ -86,7 +85,6 @@ import jdk.graal.compiler.core.common.type.TypeReference; import jdk.graal.compiler.debug.GraalError; import jdk.graal.compiler.graph.Node.NodeIntrinsic; -import jdk.graal.compiler.graph.NodeSourcePosition; import jdk.graal.compiler.java.BciBlockMapping; import jdk.graal.compiler.java.BytecodeParser; import jdk.graal.compiler.java.FrameStateBuilder; @@ -1105,18 +1103,12 @@ protected Object resolveLinkedObject(int bci, int cpi, int opcode, BootstrapMeth */ ConstantNode nullConstant = ConstantNode.forConstant(JavaConstant.NULL_POINTER, getMetaAccess(), getGraph()); - ValueNode offset = graph.addOrUniqueWithInputs( - LazyConstantNode.create(StampFactory.forKind(JavaKind.Long), new FieldOffsetConstantProvider(bootstrapObjectField), SharedBytecodeParser.this)); + ValueNode offset = graph.addOrUniqueWithInputs(FieldOffsetNode.create(JavaKind.Long, bootstrapObjectResolvedField)); FieldLocationIdentity fieldLocationIdentity = new FieldLocationIdentity(bootstrapObjectResolvedField); FixedWithNextNode linkBootstrapObject = graph.add( new UnsafeCompareAndSwapNode(bootstrapMethodInfoNode, offset, nullConstant, finalBootstrapObjectNode, JavaKind.Object, fieldLocationIdentity, MemoryOrderMode.RELEASE)); ((StateSplit) linkBootstrapObject).setStateAfter(createFrameState(stream.nextBCI(), (StateSplit) linkBootstrapObject)); - NodeSourcePosition nodeSourcePosition = getGraph().currentNodeSourcePosition(); - Object reason = nodeSourcePosition == null ? "Unknown graph builder location." : nodeSourcePosition; - bootstrapObjectResolvedField.registerAsAccessed(reason); - bootstrapObjectResolvedField.registerAsUnsafeAccessed(reason); - EndNode trueEnd = graph.add(new EndNode()); if (bootstrapMethod.isConstructor()) { diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/snippets/SubstrateGraphBuilderPlugins.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/snippets/SubstrateGraphBuilderPlugins.java index 5fde5424aa10..33cc0673c8a0 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/snippets/SubstrateGraphBuilderPlugins.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/snippets/SubstrateGraphBuilderPlugins.java @@ -36,7 +36,6 @@ import java.util.concurrent.atomic.AtomicIntegerFieldUpdater; import java.util.concurrent.atomic.AtomicLongFieldUpdater; import java.util.concurrent.atomic.AtomicReferenceFieldUpdater; -import java.util.function.Function; import java.util.stream.Stream; import org.graalvm.nativeimage.AnnotationAccess; @@ -56,8 +55,6 @@ import com.oracle.graal.pointsto.AbstractAnalysisEngine; import com.oracle.graal.pointsto.infrastructure.OriginalClassProvider; -import com.oracle.graal.pointsto.infrastructure.OriginalFieldProvider; -import com.oracle.graal.pointsto.meta.AnalysisField; import com.oracle.graal.pointsto.meta.AnalysisType; import com.oracle.graal.pointsto.nodes.UnsafePartitionLoadNode; import com.oracle.graal.pointsto.nodes.UnsafePartitionStoreNode; @@ -75,7 +72,7 @@ import com.oracle.svm.core.graal.jdk.SubstrateObjectCloneWithExceptionNode; import com.oracle.svm.core.graal.nodes.DeoptEntryNode; import com.oracle.svm.core.graal.nodes.FarReturnNode; -import com.oracle.svm.core.graal.nodes.LazyConstantNode; +import com.oracle.svm.core.graal.nodes.FieldOffsetNode; import com.oracle.svm.core.graal.nodes.ReadCallerStackPointerNode; import com.oracle.svm.core.graal.nodes.ReadReservedRegister; import com.oracle.svm.core.graal.nodes.ReadReturnAddressNode; @@ -92,7 +89,6 @@ import com.oracle.svm.core.hub.DynamicHub; import com.oracle.svm.core.identityhashcode.SubstrateIdentityHashCodeNode; import com.oracle.svm.core.jdk.proxy.DynamicProxyRegistry; -import com.oracle.svm.core.meta.SharedField; import com.oracle.svm.core.option.HostedOptionKey; import com.oracle.svm.core.snippets.KnownIntrinsics; import com.oracle.svm.core.util.UserError; @@ -144,7 +140,6 @@ import jdk.graal.compiler.nodes.java.NewArrayNode; import jdk.graal.compiler.nodes.java.StoreIndexedNode; import jdk.graal.compiler.nodes.spi.ArrayLengthProvider; -import jdk.graal.compiler.nodes.spi.CoreProviders; import jdk.graal.compiler.nodes.spi.Replacements; import jdk.graal.compiler.nodes.type.NarrowOopStamp; import jdk.graal.compiler.nodes.type.StampTool; @@ -201,7 +196,7 @@ public static void registerInvocationPlugins(AnnotationSubstitutionProcessor ann registerSerializationPlugins(loader, snippetReflection, plugins, parsingReason); registerAtomicUpdaterPlugins(snippetReflection, plugins); registerObjectPlugins(plugins); - registerUnsafePlugins(plugins, snippetReflection, parsingReason); + registerUnsafePlugins(plugins, snippetReflection); registerKnownIntrinsicsPlugins(plugins); registerStackValuePlugins(snippetReflection, plugins); registerArrayPlugins(plugins, snippetReflection, parsingReason); @@ -732,12 +727,6 @@ private static void interceptUpdaterInvoke(GraphBuilderContext b, SnippetReflect } } - private static void registerAsUnsafeAccessed(GraphBuilderContext b, Field field) { - AnalysisField targetField = (AnalysisField) b.getMetaAccess().lookupJavaField(field); - Object reason = nonNullReason(b.getGraph().currentNodeSourcePosition()); - targetField.registerAsUnsafeAccessed(reason); - } - private static void registerObjectPlugins(InvocationPlugins plugins) { Registration r = new Registration(plugins, Object.class); r.register(new RequiredInvocationPlugin("clone", Receiver.class) { @@ -759,10 +748,10 @@ public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Rec }); } - private static void registerUnsafePlugins(InvocationPlugins plugins, SnippetReflectionProvider snippetReflection, ParsingReason reason) { - registerUnsafePlugins(new Registration(plugins, "sun.misc.Unsafe"), snippetReflection, reason, true); + private static void registerUnsafePlugins(InvocationPlugins plugins, SnippetReflectionProvider snippetReflection) { + registerUnsafePlugins(new Registration(plugins, "sun.misc.Unsafe"), snippetReflection, true); Registration r = new Registration(plugins, "jdk.internal.misc.Unsafe"); - registerUnsafePlugins(r, snippetReflection, reason, false); + registerUnsafePlugins(r, snippetReflection, false); r.register(new RequiredInvocationPlugin("objectFieldOffset", Receiver.class, Class.class, String.class) { @Override @@ -776,7 +765,7 @@ public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Rec String fieldName = snippetReflection.asObject(String.class, nameNode.asJavaConstant()); try { Field targetField = clazz.getDeclaredField(fieldName); - return processFieldOffset(b, targetField, reason, false); + return processFieldOffset(b, targetField, false); } catch (NoSuchFieldException | LinkageError e) { return false; } @@ -792,7 +781,7 @@ public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Rec r.register(new AllocateUninitializedArrayPlugin("allocateUninitializedArray", true)); } - private static void registerUnsafePlugins(Registration r, SnippetReflectionProvider snippetReflection, ParsingReason reason, boolean isSunMiscUnsafe) { + private static void registerUnsafePlugins(Registration r, SnippetReflectionProvider snippetReflection, boolean isSunMiscUnsafe) { r.register(new RequiredInvocationPlugin("staticFieldOffset", Receiver.class, Field.class) { @Override public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode fieldNode) { @@ -801,7 +790,7 @@ public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Rec receiver.get(); Field targetField = snippetReflection.asObject(Field.class, fieldNode.asJavaConstant()); - return processFieldOffset(b, targetField, reason, isSunMiscUnsafe); + return processFieldOffset(b, targetField, isSunMiscUnsafe); } return false; } @@ -828,7 +817,7 @@ public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Rec receiver.get(); Field targetField = snippetReflection.asObject(Field.class, fieldNode.asJavaConstant()); - return processFieldOffset(b, targetField, reason, isSunMiscUnsafe); + return processFieldOffset(b, targetField, isSunMiscUnsafe); } return false; } @@ -853,35 +842,16 @@ public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Rec }); } - public static class FieldOffsetConstantProvider implements Function { - - private final Field javaField; - - public FieldOffsetConstantProvider(Field javaField) { - this.javaField = javaField; - } - - @Override - public JavaConstant apply(CoreProviders providers) { - ResolvedJavaField rField = providers.getMetaAccess().lookupJavaField(javaField); - if (rField instanceof SharedField) { - long fieldOffset = ((SharedField) rField).getLocation(); - assert fieldOffset > 0; - return JavaConstant.forLong(fieldOffset); - } - return null; - } - } - - private static boolean processFieldOffset(GraphBuilderContext b, Field targetField, ParsingReason reason, boolean isSunMiscUnsafe) { - if (!isValidField(targetField, isSunMiscUnsafe) || reason == ParsingReason.JITCompilation) { + private static boolean processFieldOffset(GraphBuilderContext b, Field targetField, boolean isSunMiscUnsafe) { + if (!isValidField(targetField, isSunMiscUnsafe)) { return false; } - /* Register the field for unsafe access. */ - registerAsUnsafeAccessed(b, targetField); - - b.addPush(JavaKind.Long, LazyConstantNode.create(StampFactory.forKind(JavaKind.Long), new FieldOffsetConstantProvider(targetField), b)); + /* + * The static analysis registers the field for unsafe access if the node remains in the + * graph until then. + */ + b.addPush(JavaKind.Long, FieldOffsetNode.create(JavaKind.Long, b.getMetaAccess().lookupJavaField(targetField))); return true; } @@ -1336,10 +1306,7 @@ protected boolean canApply(GraphBuilderContext b) { @Override protected ValueNode getFieldOffset(GraphBuilderContext b, ResolvedJavaField field) { - if (field instanceof AnalysisField) { - ((AnalysisField) field).registerAsUnsafeAccessed(nonNullReason(b.getGraph().currentNodeSourcePosition())); - } - return LazyConstantNode.create(StampFactory.forKind(JavaKind.Long), new FieldOffsetConstantProvider(OriginalFieldProvider.getJavaField(field)), b); + return FieldOffsetNode.create(JavaKind.Long, field); } @Override diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/substitute/AutomaticUnsafeTransformationSupport.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/substitute/AutomaticUnsafeTransformationSupport.java index 047b7029ca8e..a74f88ef7e18 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/substitute/AutomaticUnsafeTransformationSupport.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/substitute/AutomaticUnsafeTransformationSupport.java @@ -276,12 +276,12 @@ public AutomaticUnsafeTransformationSupport(OptionValues options, AnnotationSubs * we can install late while the analysis is already running. */ private void addTransformation(BigBang bb, ResolvedJavaField original, ComputedValueField transformation) { - Class returnType = original.getType().getJavaKind().toJavaClass(); + JavaKind returnKind = original.getType().getJavaKind(); FieldValueTransformer transformer = switch (transformation.getRecomputeValueKind()) { - case ArrayBaseOffset -> new ArrayBaseOffsetFieldValueTransformer(transformation.getTargetClass(), returnType); - case ArrayIndexScale -> new ArrayIndexScaleFieldValueTransformer(transformation.getTargetClass(), returnType); - case ArrayIndexShift -> new ArrayIndexShiftFieldValueTransformer(transformation.getTargetClass(), returnType); + case ArrayBaseOffset -> new ArrayBaseOffsetFieldValueTransformer(transformation.getTargetClass(), returnKind); + case ArrayIndexScale -> new ArrayIndexScaleFieldValueTransformer(transformation.getTargetClass(), returnKind); + case ArrayIndexShift -> new ArrayIndexShiftFieldValueTransformer(transformation.getTargetClass(), returnKind); case FieldOffset -> createFieldOffsetFieldValueTransformer(bb, original, transformation.getTargetField()); case StaticFieldBase -> new StaticFieldBaseFieldValueTransformer(transformation.getTargetField()); default -> throw VMError.shouldNotReachHere("Unexpected kind: " + transformation); @@ -292,7 +292,7 @@ private void addTransformation(BigBang bb, ResolvedJavaField original, ComputedV private static FieldOffsetFieldValueTransformer createFieldOffsetFieldValueTransformer(BigBang bb, ResolvedJavaField original, Field targetField) { bb.postTask(debugContext -> bb.getMetaAccess().lookupJavaField(targetField).registerAsUnsafeAccessed(original)); - return new FieldOffsetFieldValueTransformer(targetField, original.getType().getJavaKind().toJavaClass()); + return new FieldOffsetFieldValueTransformer(targetField, original.getType().getJavaKind()); } @SuppressWarnings("try") From 3cdcf36af8ea6ae29a41e38432e1c6890b24316f Mon Sep 17 00:00:00 2001 From: Codrut Stancu Date: Sun, 21 Jan 2024 11:53:43 +0100 Subject: [PATCH 568/593] Move FrameAccess.getWordKind() to ConfigurationValues. --- .../svm/core/graal/llvm/LLVMGenerator.java | 4 +- .../src/com/oracle/svm/core/FrameAccess.java | 11 ++--- .../svm/core/config/ConfigurationValues.java | 9 +++- .../oracle/svm/core/deopt/Deoptimizer.java | 14 +++--- .../graal/snippets/NonSnippetLowerings.java | 43 ++++++++++--------- .../stackvalue/LoweredStackValueNode.java | 11 ++--- .../thread/AddressOfVMThreadLocalNode.java | 14 +++--- .../core/threadlocal/VMThreadLocalInfo.java | 4 +- .../RuntimeCompilationFeature.java | 3 +- .../oracle/svm/graal/meta/SubstrateType.java | 4 +- .../svm/hosted/NativeImageGenerator.java | 6 +-- .../ameta/FieldValueInterceptionSupport.java | 4 +- .../hosted/ameta/SVMHostedValueProvider.java | 4 +- .../hosted/c/function/CEntryPointSupport.java | 8 ++-- .../SharedRuntimeConfigurationBuilder.java | 3 +- .../hosted/image/NativeImageHeapWriter.java | 13 +++--- .../meta/HostedSnippetReflectionProvider.java | 4 +- .../phases/CInterfaceInvocationPlugin.java | 10 ++--- ...trinsifyMethodHandlesInvocationPlugin.java | 4 +- .../SubstrateGraphBuilderPlugins.java | 4 +- .../svm/truffle/TruffleBaseFeature.java | 3 +- 21 files changed, 90 insertions(+), 90 deletions(-) diff --git a/substratevm/src/com.oracle.svm.core.graal.llvm/src/com/oracle/svm/core/graal/llvm/LLVMGenerator.java b/substratevm/src/com.oracle.svm.core.graal.llvm/src/com/oracle/svm/core/graal/llvm/LLVMGenerator.java index 609d41eb0803..2edd8bc5db68 100644 --- a/substratevm/src/com.oracle.svm.core.graal.llvm/src/com/oracle/svm/core/graal/llvm/LLVMGenerator.java +++ b/substratevm/src/com.oracle.svm.core.graal.llvm/src/com/oracle/svm/core/graal/llvm/LLVMGenerator.java @@ -49,10 +49,10 @@ import org.graalvm.nativeimage.c.constant.CEnum; import org.graalvm.nativeimage.c.function.CEntryPoint; -import com.oracle.svm.core.FrameAccess; import com.oracle.svm.core.ReservedRegisters; import com.oracle.svm.core.SubstrateOptions; import com.oracle.svm.core.SubstrateUtil; +import com.oracle.svm.core.config.ConfigurationValues; import com.oracle.svm.core.graal.code.SubstrateCallingConvention; import com.oracle.svm.core.graal.code.SubstrateCallingConventionType; import com.oracle.svm.core.graal.code.SubstrateDataBuilder; @@ -1000,7 +1000,7 @@ public void emitReturn(JavaKind javaKind, Value input) { if (javaKind == JavaKind.Int) { assert LLVMIRBuilder.isIntegerType(typeOf(retVal)); retVal = arithmetic.emitIntegerConvert(retVal, builder.intType()); - } else if (returnsEnum && javaKind == FrameAccess.getWordKind()) { + } else if (returnsEnum && javaKind == ConfigurationValues.getWordKind()) { /* * An enum value is represented by a long in the function body, but is returned as * an object (CEnum values are returned as an int) diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/FrameAccess.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/FrameAccess.java index c85777e549c8..61083ae5cc3a 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/FrameAccess.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/FrameAccess.java @@ -24,18 +24,17 @@ */ package com.oracle.svm.core; -import jdk.graal.compiler.api.replacements.Fold; -import jdk.graal.compiler.core.common.type.Stamp; -import jdk.graal.compiler.core.common.type.StampFactory; import org.graalvm.nativeimage.ImageSingletons; import org.graalvm.nativeimage.c.function.CodePointer; import org.graalvm.word.Pointer; import com.oracle.svm.core.config.ConfigurationValues; +import jdk.graal.compiler.api.replacements.Fold; +import jdk.graal.compiler.core.common.type.Stamp; +import jdk.graal.compiler.core.common.type.StampFactory; import jdk.vm.ci.aarch64.AArch64; import jdk.vm.ci.code.Architecture; -import jdk.vm.ci.meta.JavaKind; public abstract class FrameAccess { @@ -86,10 +85,6 @@ public static int uncompressedReferenceSize() { return wordSize(); } - public static JavaKind getWordKind() { - return ConfigurationValues.getTarget().wordJavaKind; - } - public static Stamp getWordStamp() { return StampFactory.forKind(ConfigurationValues.getTarget().wordJavaKind); } diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/config/ConfigurationValues.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/config/ConfigurationValues.java index b0b5febc2b07..69b3971f8e89 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/config/ConfigurationValues.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/config/ConfigurationValues.java @@ -24,11 +24,13 @@ */ package com.oracle.svm.core.config; -import jdk.graal.compiler.api.replacements.Fold; import org.graalvm.nativeimage.ImageSingletons; import com.oracle.svm.core.SubstrateTargetDescription; +import jdk.graal.compiler.api.replacements.Fold; +import jdk.vm.ci.meta.JavaKind; + /** * Accessors for important configuration objects that are always accessible via the * {@link ImageSingletons}. @@ -44,4 +46,9 @@ public static SubstrateTargetDescription getTarget() { public static ObjectLayout getObjectLayout() { return ImageSingletons.lookup(ObjectLayout.class); } + + @Fold + public static JavaKind getWordKind() { + return getTarget().wordJavaKind; + } } diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/deopt/Deoptimizer.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/deopt/Deoptimizer.java index ddd18c93344c..852f356aaae7 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/deopt/Deoptimizer.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/deopt/Deoptimizer.java @@ -32,11 +32,6 @@ import java.nio.ByteOrder; import java.util.ArrayList; -import jdk.graal.compiler.core.common.NumUtil; -import jdk.graal.compiler.core.common.util.TypeConversion; -import jdk.graal.compiler.options.Option; -import jdk.graal.compiler.word.BarrieredAccess; -import jdk.graal.compiler.word.Word; import org.graalvm.nativeimage.CurrentIsolate; import org.graalvm.nativeimage.IsolateThread; import org.graalvm.nativeimage.c.function.CodePointer; @@ -87,6 +82,11 @@ import com.oracle.svm.core.util.TimeUtils; import com.oracle.svm.core.util.VMError; +import jdk.graal.compiler.core.common.NumUtil; +import jdk.graal.compiler.core.common.util.TypeConversion; +import jdk.graal.compiler.options.Option; +import jdk.graal.compiler.word.BarrieredAccess; +import jdk.graal.compiler.word.Word; import jdk.internal.misc.Unsafe; import jdk.vm.ci.code.InstalledCode; import jdk.vm.ci.meta.DeoptimizationAction; @@ -971,9 +971,9 @@ private JavaConstant readValue(ValueInfo valueInfo, FrameInfoQueryResult sourceF return readConstant(sourceSp, WordFactory.signed(valueInfo.getData()), valueInfo.getKind(), valueInfo.isCompressedReference(), sourceFrame); case ReservedRegister: if (ReservedRegisters.singleton().getThreadRegister() != null && ReservedRegisters.singleton().getThreadRegister().number == valueInfo.getData()) { - return JavaConstant.forIntegerKind(FrameAccess.getWordKind(), targetThread.rawValue()); + return JavaConstant.forIntegerKind(ConfigurationValues.getWordKind(), targetThread.rawValue()); } else if (ReservedRegisters.singleton().getHeapBaseRegister() != null && ReservedRegisters.singleton().getHeapBaseRegister().number == valueInfo.getData()) { - return JavaConstant.forIntegerKind(FrameAccess.getWordKind(), CurrentIsolate.getIsolate().rawValue()); + return JavaConstant.forIntegerKind(ConfigurationValues.getWordKind(), CurrentIsolate.getIsolate().rawValue()); } else { throw fatalDeoptimizationError("Unexpected reserved register: " + valueInfo.getData(), sourceFrame); } diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/graal/snippets/NonSnippetLowerings.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/graal/snippets/NonSnippetLowerings.java index 5b092a0281ed..269f2c861692 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/graal/snippets/NonSnippetLowerings.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/graal/snippets/NonSnippetLowerings.java @@ -32,6 +32,25 @@ import java.util.Map; import java.util.function.Predicate; +import org.graalvm.word.LocationIdentity; + +import com.oracle.svm.core.FrameAccess; +import com.oracle.svm.core.SubstrateOptions; +import com.oracle.svm.core.SubstrateUtil; +import com.oracle.svm.core.code.CodeInfoTable; +import com.oracle.svm.core.config.ConfigurationValues; +import com.oracle.svm.core.graal.code.SubstrateBackend; +import com.oracle.svm.core.graal.meta.KnownOffsets; +import com.oracle.svm.core.graal.meta.RuntimeConfiguration; +import com.oracle.svm.core.graal.nodes.LoweredDeadEndNode; +import com.oracle.svm.core.graal.nodes.ThrowBytecodeExceptionNode; +import com.oracle.svm.core.meta.SharedMethod; +import com.oracle.svm.core.meta.SubstrateObjectConstant; +import com.oracle.svm.core.snippets.ImplicitExceptions; +import com.oracle.svm.core.snippets.SnippetRuntime; +import com.oracle.svm.core.snippets.SubstrateForeignCallTarget; +import com.oracle.svm.core.util.VMError; + import jdk.graal.compiler.core.common.memory.BarrierType; import jdk.graal.compiler.core.common.memory.MemoryOrderMode; import jdk.graal.compiler.core.common.spi.ForeignCallDescriptor; @@ -79,24 +98,6 @@ import jdk.graal.compiler.nodes.type.StampTool; import jdk.graal.compiler.options.OptionValues; import jdk.graal.compiler.phases.util.Providers; -import org.graalvm.word.LocationIdentity; - -import com.oracle.svm.core.FrameAccess; -import com.oracle.svm.core.SubstrateOptions; -import com.oracle.svm.core.SubstrateUtil; -import com.oracle.svm.core.code.CodeInfoTable; -import com.oracle.svm.core.graal.code.SubstrateBackend; -import com.oracle.svm.core.graal.meta.KnownOffsets; -import com.oracle.svm.core.graal.meta.RuntimeConfiguration; -import com.oracle.svm.core.graal.nodes.LoweredDeadEndNode; -import com.oracle.svm.core.graal.nodes.ThrowBytecodeExceptionNode; -import com.oracle.svm.core.meta.SharedMethod; -import com.oracle.svm.core.meta.SubstrateObjectConstant; -import com.oracle.svm.core.snippets.ImplicitExceptions; -import com.oracle.svm.core.snippets.SnippetRuntime; -import com.oracle.svm.core.snippets.SubstrateForeignCallTarget; -import com.oracle.svm.core.util.VMError; - import jdk.vm.ci.code.CallingConvention; import jdk.vm.ci.meta.DeoptimizationAction; import jdk.vm.ci.meta.DeoptimizationReason; @@ -380,14 +381,14 @@ public void lower(FixedNode node, LoweringTool tool) { */ JavaConstant codeInfo = SubstrateObjectConstant.forObject(CodeInfoTable.getImageCodeCache()); ValueNode codeInfoConstant = ConstantNode.forConstant(codeInfo, tool.getMetaAccess(), graph); - ValueNode codeStartFieldOffset = ConstantNode.forIntegerKind(FrameAccess.getWordKind(), knownOffsets.getImageCodeInfoCodeStartOffset(), graph); + ValueNode codeStartFieldOffset = ConstantNode.forIntegerKind(ConfigurationValues.getWordKind(), knownOffsets.getImageCodeInfoCodeStartOffset(), graph); AddressNode codeStartField = graph.unique(new OffsetAddressNode(codeInfoConstant, codeStartFieldOffset)); /* * Uses ANY_LOCATION because runtime-compiled code can be persisted and * loaded in a process where image code is located elsewhere. */ ReadNode codeStart = graph.add(new ReadNode(codeStartField, LocationIdentity.ANY_LOCATION, FrameAccess.getWordStamp(), BarrierType.NONE, MemoryOrderMode.PLAIN)); - ValueNode offset = ConstantNode.forIntegerKind(FrameAccess.getWordKind(), targetMethod.getCodeOffsetInImage(), graph); + ValueNode offset = ConstantNode.forIntegerKind(ConfigurationValues.getWordKind(), targetMethod.getCodeOffsetInImage(), graph); AddressNode address = graph.unique(new OffsetAddressNode(codeStart, offset)); loweredCallTarget = graph.add(new IndirectCallTargetNode( @@ -410,7 +411,7 @@ public void lower(FixedNode node, LoweringTool tool) { int vtableEntryOffset = knownOffsets.getVTableOffset(method.getVTableIndex()); hub = graph.unique(new LoadHubNode(runtimeConfig.getProviders().getStampProvider(), graph.addOrUnique(PiNode.create(receiver, nullCheck)))); - AddressNode address = graph.unique(new OffsetAddressNode(hub, ConstantNode.forIntegerKind(FrameAccess.getWordKind(), vtableEntryOffset, graph))); + AddressNode address = graph.unique(new OffsetAddressNode(hub, ConstantNode.forIntegerKind(ConfigurationValues.getWordKind(), vtableEntryOffset, graph))); ReadNode entry = graph.add(new ReadNode(address, SubstrateBackend.getVTableIdentity(), FrameAccess.getWordStamp(), BarrierType.NONE, MemoryOrderMode.PLAIN)); loweredCallTarget = createIndirectCall(graph, callTarget, parameters, method, signature, callType, invokeKind, entry); diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/graal/stackvalue/LoweredStackValueNode.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/graal/stackvalue/LoweredStackValueNode.java index faebec384733..0331f02ae7ba 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/graal/stackvalue/LoweredStackValueNode.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/graal/stackvalue/LoweredStackValueNode.java @@ -24,6 +24,11 @@ */ package com.oracle.svm.core.graal.stackvalue; +import org.graalvm.word.WordBase; + +import com.oracle.svm.core.FrameAccess; +import com.oracle.svm.core.config.ConfigurationValues; + import jdk.graal.compiler.graph.NodeClass; import jdk.graal.compiler.lir.ConstantValue; import jdk.graal.compiler.lir.VirtualStackSlot; @@ -32,10 +37,6 @@ import jdk.graal.compiler.nodeinfo.NodeSize; import jdk.graal.compiler.nodes.spi.LIRLowerable; import jdk.graal.compiler.nodes.spi.NodeLIRBuilderTool; -import org.graalvm.word.WordBase; - -import com.oracle.svm.core.FrameAccess; - import jdk.vm.ci.meta.JavaConstant; /** @@ -99,7 +100,7 @@ public void generate(NodeLIRBuilderTool gen) { stackSlotHolder.gen = gen; if (sizeInBytes == 0) { - gen.setResult(this, new ConstantValue(gen.getLIRGeneratorTool().getLIRKind(FrameAccess.getWordStamp()), JavaConstant.forIntegerKind(FrameAccess.getWordKind(), 0))); + gen.setResult(this, new ConstantValue(gen.getLIRGeneratorTool().getLIRKind(FrameAccess.getWordStamp()), JavaConstant.forIntegerKind(ConfigurationValues.getWordKind(), 0))); } else { VirtualStackSlot slot = stackSlotHolder.slot; if (slot == null) { diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/graal/thread/AddressOfVMThreadLocalNode.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/graal/thread/AddressOfVMThreadLocalNode.java index b4fcebb61593..1f263e6c71af 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/graal/thread/AddressOfVMThreadLocalNode.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/graal/thread/AddressOfVMThreadLocalNode.java @@ -24,6 +24,11 @@ */ package com.oracle.svm.core.graal.thread; +import com.oracle.svm.core.FrameAccess; +import com.oracle.svm.core.config.ConfigurationValues; +import com.oracle.svm.core.graal.nodes.FloatingWordCastNode; +import com.oracle.svm.core.threadlocal.VMThreadLocalInfo; + import jdk.graal.compiler.graph.NodeClass; import jdk.graal.compiler.nodeinfo.NodeCycles; import jdk.graal.compiler.nodeinfo.NodeInfo; @@ -34,11 +39,6 @@ import jdk.graal.compiler.nodes.calc.FloatingNode; import jdk.graal.compiler.nodes.spi.Lowerable; import jdk.graal.compiler.nodes.spi.LoweringTool; - -import com.oracle.svm.core.FrameAccess; -import com.oracle.svm.core.graal.nodes.FloatingWordCastNode; -import com.oracle.svm.core.threadlocal.VMThreadLocalInfo; - import jdk.vm.ci.meta.JavaKind; @NodeInfo(cycles = NodeCycles.CYCLES_1, size = NodeSize.SIZE_1) @@ -62,9 +62,9 @@ public void lower(LoweringTool tool) { if (base.getStackKind() == JavaKind.Object) { base = graph().unique(new FloatingWordCastNode(FrameAccess.getWordStamp(), base)); } - assert base.getStackKind() == FrameAccess.getWordKind(); + assert base.getStackKind() == ConfigurationValues.getWordKind(); - ConstantNode offset = ConstantNode.forIntegerKind(FrameAccess.getWordKind(), threadLocalInfo.offset, graph()); + ConstantNode offset = ConstantNode.forIntegerKind(ConfigurationValues.getWordKind(), threadLocalInfo.offset, graph()); ValueNode address = graph().unique(new AddNode(base, offset)); replaceAtUsagesAndDelete(address); } diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/threadlocal/VMThreadLocalInfo.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/threadlocal/VMThreadLocalInfo.java index f0f0369fecb6..7601be3891c7 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/threadlocal/VMThreadLocalInfo.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/threadlocal/VMThreadLocalInfo.java @@ -34,7 +34,7 @@ import org.graalvm.word.WordBase; import com.oracle.svm.core.BuildPhaseProvider.ReadyForCompilation; -import com.oracle.svm.core.FrameAccess; +import com.oracle.svm.core.config.ConfigurationValues; import com.oracle.svm.core.heap.UnknownPrimitiveField; import jdk.vm.ci.meta.JavaKind; @@ -104,7 +104,7 @@ public VMThreadLocalInfo(FastThreadLocal threadLocal) { } else if (threadLocalClass == FastThreadLocalLong.class) { storageKind = JavaKind.Long; } else if (threadLocalClass == FastThreadLocalWord.class) { - storageKind = FrameAccess.getWordKind(); + storageKind = ConfigurationValues.getWordKind(); } else if (threadLocalClass == FastThreadLocalObject.class) { storageKind = JavaKind.Object; } else if (threadLocalClass == FastThreadLocalBytes.class) { diff --git a/substratevm/src/com.oracle.svm.graal/src/com/oracle/svm/graal/hosted/runtimecompilation/RuntimeCompilationFeature.java b/substratevm/src/com.oracle.svm.graal/src/com/oracle/svm/graal/hosted/runtimecompilation/RuntimeCompilationFeature.java index 90698e30ceec..70a51fd40054 100644 --- a/substratevm/src/com.oracle.svm.graal/src/com/oracle/svm/graal/hosted/runtimecompilation/RuntimeCompilationFeature.java +++ b/substratevm/src/com.oracle.svm.graal/src/com/oracle/svm/graal/hosted/runtimecompilation/RuntimeCompilationFeature.java @@ -65,7 +65,6 @@ import com.oracle.graal.pointsto.util.GraalAccess; import com.oracle.graal.pointsto.util.ParallelExecutionException; import com.oracle.svm.common.meta.MultiMethod; -import com.oracle.svm.core.FrameAccess; import com.oracle.svm.core.ParsingReason; import com.oracle.svm.core.SubstrateOptions; import com.oracle.svm.core.config.ConfigurationValues; @@ -363,7 +362,7 @@ public void duringSetup(DuringSetupAccess c) { DuringSetupAccessImpl config = (DuringSetupAccessImpl) c; AnalysisMetaAccess aMetaAccess = config.getMetaAccess(); - SubstrateWordTypes wordTypes = new SubstrateWordTypes(aMetaAccess, FrameAccess.getWordKind()); + SubstrateWordTypes wordTypes = new SubstrateWordTypes(aMetaAccess, ConfigurationValues.getWordKind()); SubstrateProviders substrateProviders = ImageSingletons.lookup(SubstrateGraalCompilerSetup.class).getSubstrateProviders(aMetaAccess, wordTypes); objectReplacer = new GraalGraphObjectReplacer(config.getUniverse(), substrateProviders, universeFactory); config.registerObjectReplacer(objectReplacer); diff --git a/substratevm/src/com.oracle.svm.graal/src/com/oracle/svm/graal/meta/SubstrateType.java b/substratevm/src/com.oracle.svm.graal/src/com/oracle/svm/graal/meta/SubstrateType.java index 97ed0ba205cc..1bea997ff956 100644 --- a/substratevm/src/com.oracle.svm.graal/src/com/oracle/svm/graal/meta/SubstrateType.java +++ b/substratevm/src/com.oracle.svm.graal/src/com/oracle/svm/graal/meta/SubstrateType.java @@ -31,7 +31,7 @@ import org.graalvm.nativeimage.Platforms; import org.graalvm.word.WordBase; -import com.oracle.svm.core.FrameAccess; +import com.oracle.svm.core.config.ConfigurationValues; import com.oracle.svm.core.heap.UnknownObjectField; import com.oracle.svm.core.hub.DynamicHub; import com.oracle.svm.core.meta.SharedType; @@ -98,7 +98,7 @@ public void setTypeCheckData(DynamicHub uniqueConcreteImplementation) { @Override public final JavaKind getStorageKind() { if (WordBase.class.isAssignableFrom(DynamicHub.toClass(hub))) { - return FrameAccess.getWordKind(); + return ConfigurationValues.getWordKind(); } else { return getJavaKind(); } diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/NativeImageGenerator.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/NativeImageGenerator.java index d544725bf86d..fdf177f2d9da 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/NativeImageGenerator.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/NativeImageGenerator.java @@ -123,7 +123,6 @@ import com.oracle.svm.core.BuildArtifacts.ArtifactType; import com.oracle.svm.core.BuildPhaseProvider; import com.oracle.svm.core.ClassLoaderSupport; -import com.oracle.svm.core.FrameAccess; import com.oracle.svm.core.JavaMainWrapper.JavaMainSupport; import com.oracle.svm.core.LinkerInvocation; import com.oracle.svm.core.MissingRegistrationSupport; @@ -1175,7 +1174,7 @@ private static HostedProviders createHostedProviders(TargetDescription target, A AnalysisConstantReflectionProvider aConstantReflection = new AnalysisConstantReflectionProvider(aUniverse, aMetaAccess); - WordTypes aWordTypes = new SubstrateWordTypes(aMetaAccess, FrameAccess.getWordKind()); + WordTypes aWordTypes = new SubstrateWordTypes(aMetaAccess, ConfigurationValues.getWordKind()); HostedSnippetReflectionProvider aSnippetReflection = new HostedSnippetReflectionProvider(null, aWordTypes); @@ -1356,7 +1355,8 @@ public static void registerGraphBuilderPlugins(FeatureHandler featureHandler, Ru TargetDescription target, boolean supportsStubBasedPlugins) { GraphBuilderConfiguration.Plugins plugins = new GraphBuilderConfiguration.Plugins(new SubstitutionInvocationPlugins(annotationSubstitutionProcessor)); - HostedSnippetReflectionProvider hostedSnippetReflection = new HostedSnippetReflectionProvider(aUniverse.getHeapScanner(), new SubstrateWordTypes(aMetaAccess, FrameAccess.getWordKind())); + HostedSnippetReflectionProvider hostedSnippetReflection = new HostedSnippetReflectionProvider(aUniverse.getHeapScanner(), + new SubstrateWordTypes(aMetaAccess, ConfigurationValues.getWordKind())); WordOperationPlugin wordOperationPlugin = new SubstrateWordOperationPlugins(hostedSnippetReflection, providers.getConstantReflection(), providers.getWordTypes(), providers.getPlatformConfigurationProvider().getBarrierSet()); diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/ameta/FieldValueInterceptionSupport.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/ameta/FieldValueInterceptionSupport.java index 0500a5a0c95a..8dc6bd71e51d 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/ameta/FieldValueInterceptionSupport.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/ameta/FieldValueInterceptionSupport.java @@ -43,10 +43,10 @@ import com.oracle.graal.pointsto.meta.AnalysisType; import com.oracle.graal.pointsto.util.GraalAccess; import com.oracle.svm.core.BuildPhaseProvider; -import com.oracle.svm.core.FrameAccess; import com.oracle.svm.core.RuntimeAssertionsSupport; import com.oracle.svm.core.annotate.InjectAccessors; import com.oracle.svm.core.annotate.RecomputeFieldValue; +import com.oracle.svm.core.config.ConfigurationValues; import com.oracle.svm.core.fieldvaluetransformer.FieldValueTransformerWithAvailability; import com.oracle.svm.core.fieldvaluetransformer.FieldValueTransformerWithAvailability.ValueAvailability; import com.oracle.svm.core.heap.UnknownObjectField; @@ -349,7 +349,7 @@ private static JavaConstant interceptAssertionStatus(AnalysisField field, JavaCo */ private static JavaConstant interceptWordField(AnalysisField field, JavaConstant value) { if (value.getJavaKind() == JavaKind.Object && value.isNull() && field.getType().isWordType()) { - return JavaConstant.forIntegerKind(FrameAccess.getWordKind(), 0); + return JavaConstant.forIntegerKind(ConfigurationValues.getWordKind(), 0); } return value; } diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/ameta/SVMHostedValueProvider.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/ameta/SVMHostedValueProvider.java index bb67a7660adf..83e041f1fa48 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/ameta/SVMHostedValueProvider.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/ameta/SVMHostedValueProvider.java @@ -33,7 +33,7 @@ import com.oracle.graal.pointsto.heap.value.ValueSupplier; import com.oracle.graal.pointsto.meta.AnalysisField; import com.oracle.graal.pointsto.meta.AnalysisUniverse; -import com.oracle.svm.core.FrameAccess; +import com.oracle.svm.core.config.ConfigurationValues; import com.oracle.svm.core.meta.SubstrateObjectConstant; import com.oracle.svm.core.util.VMError; import com.oracle.svm.hosted.classinitialization.ClassInitializationSupport; @@ -142,7 +142,7 @@ public JavaConstant forObject(Object object) { if (object instanceof RelocatedPointer pointer) { return new RelocatableConstant(pointer); } else if (object instanceof WordBase word) { - return JavaConstant.forIntegerKind(FrameAccess.getWordKind(), word.rawValue()); + return JavaConstant.forIntegerKind(ConfigurationValues.getWordKind(), word.rawValue()); } HostedSnippetReflectionProvider.validateRawObjectConstant(object); return SubstrateObjectConstant.forObject(object); diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/c/function/CEntryPointSupport.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/c/function/CEntryPointSupport.java index a3cf50162787..f22d26bf26e1 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/c/function/CEntryPointSupport.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/c/function/CEntryPointSupport.java @@ -29,12 +29,12 @@ import org.graalvm.nativeimage.IsolateThread; import org.graalvm.nativeimage.c.type.CCharPointer; -import com.oracle.svm.core.FrameAccess; import com.oracle.svm.core.ParsingReason; import com.oracle.svm.core.SubstrateOptions; import com.oracle.svm.core.c.function.CEntryPointActions; import com.oracle.svm.core.c.function.CEntryPointCreateIsolateParameters; import com.oracle.svm.core.c.function.CEntryPointSetup; +import com.oracle.svm.core.config.ConfigurationValues; import com.oracle.svm.core.feature.AutomaticallyRegisteredFeature; import com.oracle.svm.core.feature.InternalFeature; import com.oracle.svm.core.graal.nodes.CEntryPointEnterNode; @@ -175,10 +175,10 @@ public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Rec b.addPush(JavaKind.Object, ReadReservedRegister.createReadIsolateThreadNode(b.getGraph())); } else if (SubstrateOptions.SpawnIsolates.getValue()) { ValueNode heapBase = b.add(ReadReservedRegister.createReadHeapBaseNode(b.getGraph())); - ConstantNode addend = b.add(ConstantNode.forIntegerKind(FrameAccess.getWordKind(), CEntryPointSetup.SINGLE_ISOLATE_TO_SINGLE_THREAD_ADDEND)); + ConstantNode addend = b.add(ConstantNode.forIntegerKind(ConfigurationValues.getWordKind(), CEntryPointSetup.SINGLE_ISOLATE_TO_SINGLE_THREAD_ADDEND)); b.addPush(JavaKind.Object, new AddNode(heapBase, addend)); } else { - b.addPush(JavaKind.Object, ConstantNode.forIntegerKind(FrameAccess.getWordKind(), CEntryPointSetup.SINGLE_THREAD_SENTINEL.rawValue())); + b.addPush(JavaKind.Object, ConstantNode.forIntegerKind(ConfigurationValues.getWordKind(), CEntryPointSetup.SINGLE_THREAD_SENTINEL.rawValue())); } return true; } @@ -189,7 +189,7 @@ public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Rec if (SubstrateOptions.SpawnIsolates.getValue()) { b.addPush(JavaKind.Object, ReadReservedRegister.createReadHeapBaseNode(b.getGraph())); } else { - b.addPush(JavaKind.Object, ConstantNode.forIntegerKind(FrameAccess.getWordKind(), CEntryPointSetup.SINGLE_ISOLATE_SENTINEL.rawValue())); + b.addPush(JavaKind.Object, ConstantNode.forIntegerKind(ConfigurationValues.getWordKind(), CEntryPointSetup.SINGLE_ISOLATE_SENTINEL.rawValue())); } return true; } diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/code/SharedRuntimeConfigurationBuilder.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/code/SharedRuntimeConfigurationBuilder.java index 27bdbefe72b6..8e01f6c70462 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/code/SharedRuntimeConfigurationBuilder.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/code/SharedRuntimeConfigurationBuilder.java @@ -32,7 +32,6 @@ import org.graalvm.nativeimage.ImageSingletons; import com.oracle.graal.pointsto.infrastructure.UniverseMetaAccess; -import com.oracle.svm.core.FrameAccess; import com.oracle.svm.core.SubstrateOptions; import com.oracle.svm.core.config.ConfigurationValues; import com.oracle.svm.core.graal.GraalConfiguration; @@ -107,7 +106,7 @@ public final RuntimeConfiguration build() { SubstrateOptions.PreserveFramePointer.getValue())); } - WordTypes wordTypes = new SubstrateWordTypes(metaAccess, FrameAccess.getWordKind()); + WordTypes wordTypes = new SubstrateWordTypes(metaAccess, ConfigurationValues.getWordKind()); ForeignCallsProvider foreignCalls = createForeignCallsProvider(registerConfigs.get(ConfigKind.NORMAL)); diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/NativeImageHeapWriter.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/NativeImageHeapWriter.java index fc19798434e0..28dfdfe7e9a4 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/NativeImageHeapWriter.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/NativeImageHeapWriter.java @@ -43,7 +43,6 @@ import com.oracle.graal.pointsto.heap.ImageHeapPrimitiveArray; import com.oracle.graal.pointsto.util.AnalysisError; import com.oracle.objectfile.ObjectFile; -import com.oracle.svm.core.FrameAccess; import com.oracle.svm.core.StaticFieldsSupport; import com.oracle.svm.core.config.ConfigurationValues; import com.oracle.svm.core.config.ObjectLayout; @@ -192,9 +191,9 @@ private void writeConstant(RelocatableBuffer buffer, int index, JavaKind kind, J final JavaConstant con; if (heap.hMetaAccess.isInstanceOf(constant, WordBase.class)) { Object value = snippetReflection().asObject(Object.class, constant); - con = JavaConstant.forIntegerKind(FrameAccess.getWordKind(), ((WordBase) value).rawValue()); - } else if (constant.isNull() && kind == FrameAccess.getWordKind()) { - con = JavaConstant.forIntegerKind(FrameAccess.getWordKind(), 0); + con = JavaConstant.forIntegerKind(ConfigurationValues.getWordKind(), ((WordBase) value).rawValue()); + } else if (constant.isNull() && kind == ConfigurationValues.getWordKind()) { + con = JavaConstant.forIntegerKind(ConfigurationValues.getWordKind(), 0); } else { con = constant; } @@ -219,9 +218,9 @@ private void writeConstant(RelocatableBuffer buffer, int index, JavaKind kind, O final JavaConstant con; if (value instanceof WordBase) { - con = JavaConstant.forIntegerKind(FrameAccess.getWordKind(), ((WordBase) value).rawValue()); - } else if (value == null && kind == FrameAccess.getWordKind()) { - con = JavaConstant.forIntegerKind(FrameAccess.getWordKind(), 0); + con = JavaConstant.forIntegerKind(ConfigurationValues.getWordKind(), ((WordBase) value).rawValue()); + } else if (value == null && kind == ConfigurationValues.getWordKind()) { + con = JavaConstant.forIntegerKind(ConfigurationValues.getWordKind(), 0); } else { assert kind == JavaKind.Object || value != null : "primitive value must not be null"; con = snippetReflection().forBoxed(kind, value); diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/meta/HostedSnippetReflectionProvider.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/meta/HostedSnippetReflectionProvider.java index 73f65b61d370..6a15f8ddadb5 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/meta/HostedSnippetReflectionProvider.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/meta/HostedSnippetReflectionProvider.java @@ -31,7 +31,7 @@ import com.oracle.graal.pointsto.heap.ImageHeapConstant; import com.oracle.graal.pointsto.heap.ImageHeapScanner; import com.oracle.graal.pointsto.util.AnalysisError; -import com.oracle.svm.core.FrameAccess; +import com.oracle.svm.core.config.ConfigurationValues; import com.oracle.svm.core.graal.meta.SubstrateSnippetReflectionProvider; import com.oracle.svm.core.hub.DynamicHub; import com.oracle.svm.core.meta.SubstrateObjectConstant; @@ -58,7 +58,7 @@ public JavaConstant forObject(Object object) { /* Relocated pointers are subject to relocation, so we don't know their value yet. */ return new RelocatableConstant(pointer); } else if (object instanceof WordBase word) { - return JavaConstant.forIntegerKind(FrameAccess.getWordKind(), word.rawValue()); + return JavaConstant.forIntegerKind(ConfigurationValues.getWordKind(), word.rawValue()); } validateRawObjectConstant(object); /* Redirect constant lookup through the shadow heap. */ diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/phases/CInterfaceInvocationPlugin.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/phases/CInterfaceInvocationPlugin.java index 5f5383dd2ff2..696bf2363e04 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/phases/CInterfaceInvocationPlugin.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/phases/CInterfaceInvocationPlugin.java @@ -36,9 +36,9 @@ import com.oracle.graal.pointsto.meta.AnalysisMethod; import com.oracle.graal.pointsto.meta.AnalysisType; -import com.oracle.svm.core.FrameAccess; import com.oracle.svm.core.c.InvokeJavaFunctionPointer; import com.oracle.svm.core.c.struct.CInterfaceLocationIdentity; +import com.oracle.svm.core.config.ConfigurationValues; import com.oracle.svm.core.graal.code.SubstrateCallingConventionKind; import com.oracle.svm.core.graal.nodes.CInterfaceReadNode; import com.oracle.svm.core.graal.nodes.CInterfaceWriteNode; @@ -168,7 +168,7 @@ private boolean replaceAccessor(GraphBuilderContext b, AnalysisMethod method, Va assert args.length == accessorInfo.parameterCount(true); ValueNode base = args[AccessorInfo.baseParameterNumber(true)]; - assert base.getStackKind() == FrameAccess.getWordKind(); + assert base.getStackKind() == ConfigurationValues.getWordKind(); switch (accessorInfo.getAccessorKind()) { case ADDRESS: { @@ -362,13 +362,13 @@ private static String accessName(AccessorInfo accessorInfo) { } private static ValueNode makeOffset(StructuredGraph graph, ValueNode[] args, AccessorInfo accessorInfo, int displacement, int indexScaling) { - ValueNode offset = ConstantNode.forIntegerKind(FrameAccess.getWordKind(), displacement, graph); + ValueNode offset = ConstantNode.forIntegerKind(ConfigurationValues.getWordKind(), displacement, graph); if (accessorInfo.isIndexed()) { ValueNode index = args[accessorInfo.indexParameterNumber(true)]; assert index.getStackKind().isPrimitive(); - ValueNode wordIndex = adaptPrimitiveType(graph, index, index.getStackKind(), FrameAccess.getWordKind(), false); - ValueNode scaledIndex = graph.unique(new MulNode(wordIndex, ConstantNode.forIntegerKind(FrameAccess.getWordKind(), indexScaling, graph))); + ValueNode wordIndex = adaptPrimitiveType(graph, index, index.getStackKind(), ConfigurationValues.getWordKind(), false); + ValueNode scaledIndex = graph.unique(new MulNode(wordIndex, ConstantNode.forIntegerKind(ConfigurationValues.getWordKind(), indexScaling, graph))); offset = graph.unique(new AddNode(scaledIndex, offset)); } diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/phases/IntrinsifyMethodHandlesInvocationPlugin.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/phases/IntrinsifyMethodHandlesInvocationPlugin.java index be055c089ecc..3b040f78f7b7 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/phases/IntrinsifyMethodHandlesInvocationPlugin.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/phases/IntrinsifyMethodHandlesInvocationPlugin.java @@ -46,8 +46,8 @@ import com.oracle.graal.pointsto.meta.HostedProviders; import com.oracle.graal.pointsto.phases.NoClassInitializationPlugin; import com.oracle.graal.pointsto.util.GraalAccess; -import com.oracle.svm.core.FrameAccess; import com.oracle.svm.core.ParsingReason; +import com.oracle.svm.core.config.ConfigurationValues; import com.oracle.svm.core.graal.phases.TrustedInterfaceTypePlugin; import com.oracle.svm.core.graal.word.SubstrateWordTypes; import com.oracle.svm.core.jdk.VarHandleFeature; @@ -532,7 +532,7 @@ private boolean processInvokeWithMethodHandle(GraphBuilderContext b, Replacement SnippetReflectionProvider originalSnippetReflection = GraalAccess.getOriginalSnippetReflection(); ConstantReflectionProvider originalConstantReflection = GraalAccess.getOriginalProviders().getConstantReflection(); WordOperationPlugin wordOperationPlugin = new WordOperationPlugin(originalSnippetReflection, originalConstantReflection, - new SubstrateWordTypes(parsingProviders.getMetaAccess(), FrameAccess.getWordKind()), + new SubstrateWordTypes(parsingProviders.getMetaAccess(), ConfigurationValues.getWordKind()), parsingProviders.getPlatformConfigurationProvider().getBarrierSet()); graphBuilderPlugins.appendInlineInvokePlugin(wordOperationPlugin); graphBuilderPlugins.appendTypePlugin(wordOperationPlugin); diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/snippets/SubstrateGraphBuilderPlugins.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/snippets/SubstrateGraphBuilderPlugins.java index 33cc0673c8a0..d84e2c24ed04 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/snippets/SubstrateGraphBuilderPlugins.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/snippets/SubstrateGraphBuilderPlugins.java @@ -1234,7 +1234,7 @@ public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Rec ValueNode compressedValue = b.add(WordCastNode.narrowOopToUntrackedWord(compressedObj, compressedIntKind)); b.addPush(JavaKind.Object, ZeroExtendNode.convertUnsigned(compressedValue, FrameAccess.getWordStamp(), NodeView.DEFAULT)); } else { - b.addPush(JavaKind.Object, WordCastNode.objectToUntrackedPointer(objectNode, FrameAccess.getWordKind())); + b.addPush(JavaKind.Object, WordCastNode.objectToUntrackedPointer(objectNode, ConfigurationValues.getWordKind())); } return true; } @@ -1251,7 +1251,7 @@ public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Rec WordCastNode compressedObj = b.add(WordCastNode.wordToNarrowObject(narrowNode, compressedStamp)); b.addPush(JavaKind.Object, SubstrateCompressionNode.uncompress(b.getGraph(), compressedObj, encoding)); } else { - b.addPush(JavaKind.Object, WordCastNode.wordToObject(wordNode, FrameAccess.getWordKind())); + b.addPush(JavaKind.Object, WordCastNode.wordToObject(wordNode, ConfigurationValues.getWordKind())); } return true; } diff --git a/substratevm/src/com.oracle.svm.truffle/src/com/oracle/svm/truffle/TruffleBaseFeature.java b/substratevm/src/com.oracle.svm.truffle/src/com/oracle/svm/truffle/TruffleBaseFeature.java index 61b4e13483c6..cd038d4e0b3b 100644 --- a/substratevm/src/com.oracle.svm.truffle/src/com/oracle/svm/truffle/TruffleBaseFeature.java +++ b/substratevm/src/com.oracle.svm.truffle/src/com/oracle/svm/truffle/TruffleBaseFeature.java @@ -79,7 +79,6 @@ import com.oracle.graal.pointsto.meta.AnalysisMetaAccess; import com.oracle.graal.pointsto.meta.AnalysisType; import com.oracle.svm.core.BuildArtifacts; -import com.oracle.svm.core.FrameAccess; import com.oracle.svm.core.NeverInline; import com.oracle.svm.core.ParsingReason; import com.oracle.svm.core.RuntimeAssertionsSupport; @@ -531,7 +530,7 @@ void setGraalGraphObjectReplacer(GraalGraphObjectReplacer graalGraphObjectReplac public void beforeAnalysis(BeforeAnalysisAccess access) { if (graalGraphObjectReplacer == null) { BeforeAnalysisAccessImpl config = (BeforeAnalysisAccessImpl) access; - SubstrateWordTypes wordTypes = new SubstrateWordTypes(config.getMetaAccess(), FrameAccess.getWordKind()); + SubstrateWordTypes wordTypes = new SubstrateWordTypes(config.getMetaAccess(), ConfigurationValues.getWordKind()); SubstrateProviders substrateProviders = ImageSingletons.lookup(SubstrateGraalCompilerSetup.class).getSubstrateProviders(metaAccess, wordTypes); graalGraphObjectReplacer = new GraalGraphObjectReplacer(config.getUniverse(), substrateProviders, new SubstrateUniverseFactory()); graalGraphObjectReplacer.setAnalysisAccess(config); From 537857f45d842af4e6d57f6108a9619ecc4e94d0 Mon Sep 17 00:00:00 2001 From: Codrut Stancu Date: Sun, 21 Jan 2024 11:43:42 +0100 Subject: [PATCH 569/593] Move ClassInitializationSupport to FieldValueInterceptionSupport. SVMHostedValueProvider just passes it through. --- .../src/com/oracle/svm/hosted/NativeImageGenerator.java | 2 +- .../src/com/oracle/svm/hosted/SVMHost.java | 2 +- .../svm/hosted/ameta/FieldValueInterceptionSupport.java | 6 ++++-- .../oracle/svm/hosted/ameta/SVMHostedValueProvider.java | 7 ++----- 4 files changed, 8 insertions(+), 9 deletions(-) diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/NativeImageGenerator.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/NativeImageGenerator.java index fdf177f2d9da..69173ab29279 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/NativeImageGenerator.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/NativeImageGenerator.java @@ -948,7 +948,7 @@ protected void setupNativeImage(OptionValues options, Map fieldValueInterceptors = new ConcurrentHashMap<>(); + private final ClassInitializationSupport classInitializationSupport; public static FieldValueInterceptionSupport singleton() { return ImageSingletons.lookup(FieldValueInterceptionSupport.class); } - public FieldValueInterceptionSupport(AnnotationSubstitutionProcessor annotationSubstitutions) { + public FieldValueInterceptionSupport(AnnotationSubstitutionProcessor annotationSubstitutions, ClassInitializationSupport classInitializationSupport) { this.annotationSubstitutions = annotationSubstitutions; + this.classInitializationSupport = classInitializationSupport; } /** @@ -288,7 +290,7 @@ public ValueNode tryIntrinsifyFieldLoad(CoreProviders providers, LoadFieldNode n return transformerWithAvailability.intrinsify(providers, receiver); } - JavaConstant readFieldValue(ClassInitializationSupport classInitializationSupport, AnalysisField field, JavaConstant receiver) { + JavaConstant readFieldValue(AnalysisField field, JavaConstant receiver) { assert isValueAvailable(field) : field; JavaConstant value; var interceptor = lookupFieldValueInterceptor(field); diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/ameta/SVMHostedValueProvider.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/ameta/SVMHostedValueProvider.java index 83e041f1fa48..86a68f179a8f 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/ameta/SVMHostedValueProvider.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/ameta/SVMHostedValueProvider.java @@ -36,7 +36,6 @@ import com.oracle.svm.core.config.ConfigurationValues; import com.oracle.svm.core.meta.SubstrateObjectConstant; import com.oracle.svm.core.util.VMError; -import com.oracle.svm.hosted.classinitialization.ClassInitializationSupport; import com.oracle.svm.hosted.classinitialization.SimulateClassInitializerSupport; import com.oracle.svm.hosted.meta.HostedSnippetReflectionProvider; import com.oracle.svm.hosted.meta.RelocatableConstant; @@ -48,11 +47,9 @@ public class SVMHostedValueProvider extends HostedValuesProvider { private final FieldValueInterceptionSupport fieldValueInterceptionSupport = FieldValueInterceptionSupport.singleton(); - private final ClassInitializationSupport classInitializationSupport; - public SVMHostedValueProvider(ClassInitializationSupport classInitializationSupport, AnalysisUniverse universe) { + public SVMHostedValueProvider(AnalysisUniverse universe) { super(universe); - this.classInitializationSupport = classInitializationSupport; } /** @@ -88,7 +85,7 @@ public JavaConstant readFieldValueWithReplacement(AnalysisField field, JavaConst private JavaConstant doReadValue(AnalysisField field, JavaConstant receiver) { JavaConstant hostedReceiver = universe.toHosted(receiver); - return universe.fromHosted(fieldValueInterceptionSupport.readFieldValue(classInitializationSupport, field, hostedReceiver)); + return universe.fromHosted(fieldValueInterceptionSupport.readFieldValue(field, hostedReceiver)); } /** From a51140867afea4d21041f123378c273c94defb87 Mon Sep 17 00:00:00 2001 From: Codrut Stancu Date: Sun, 21 Jan 2024 23:21:08 +0100 Subject: [PATCH 570/593] AnalysisConstantReflectionProvider.unboxPrimitive only processes ImageHeapConstant. --- .../AnalysisConstantReflectionProvider.java | 28 +++++++++---------- 1 file changed, 13 insertions(+), 15 deletions(-) diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/ameta/AnalysisConstantReflectionProvider.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/ameta/AnalysisConstantReflectionProvider.java index b1ee9d2b72cc..3ed1d634911d 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/ameta/AnalysisConstantReflectionProvider.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/ameta/AnalysisConstantReflectionProvider.java @@ -96,22 +96,20 @@ public JavaConstant unboxPrimitive(JavaConstant source) { if (!source.getJavaKind().isObject()) { return null; } - if (source instanceof ImageHeapConstant imageHeapConstant) { - /* - * Unbox by reading the known single field "value", which is a primitive field of the - * correct unboxed type. - */ - AnalysisType type = imageHeapConstant.getType(); - if (BOXING_CLASSES.contains(type.getJavaClass())) { - imageHeapConstant.ensureReaderInstalled(); - ResolvedJavaField[] fields = type.getInstanceFields(true); - assert fields.length == 1 && fields[0].getName().equals("value"); - return ((ImageHeapInstance) imageHeapConstant).readFieldValue((AnalysisField) fields[0]); - } - /* Not a valid boxed primitive. */ - return null; + ImageHeapConstant imageHeapConstant = (ImageHeapConstant) source; + /* + * Unbox by reading the known single field "value", which is a primitive field of the + * correct unboxed type. + */ + AnalysisType type = imageHeapConstant.getType(); + if (BOXING_CLASSES.contains(type.getJavaClass())) { + imageHeapConstant.ensureReaderInstalled(); + ResolvedJavaField[] fields = type.getInstanceFields(true); + assert fields.length == 1 && fields[0].getName().equals("value"); + return ((ImageHeapInstance) imageHeapConstant).readFieldValue((AnalysisField) fields[0]); } - return JavaConstant.forBoxedPrimitive(SubstrateObjectConstant.asObject(source)); + /* Not a valid boxed primitive. */ + return null; } @Override From d3dc2913bde9fc505a1c7502d5dd529a55b56f78 Mon Sep 17 00:00:00 2001 From: Codrut Stancu Date: Sun, 21 Jan 2024 16:22:58 +0100 Subject: [PATCH 571/593] Refactor unnecessary usages of ImageHeapConstant#getHostedObject. Will make getting rid of the SubstrateObjectConstant hosted object wrapper easier. --- .../graal/pointsto/heap/ImageHeapScanner.java | 8 ++--- .../svm/hosted/heap/SVMImageHeapScanner.java | 33 +++++++++---------- .../svm/hosted/image/NativeImageHeap.java | 12 +++---- .../phases/AnalysisGraphBuilderPhase.java | 3 +- .../phases/SharedGraphBuilderPhase.java | 6 ++-- 5 files changed, 24 insertions(+), 38 deletions(-) diff --git a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/heap/ImageHeapScanner.java b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/heap/ImageHeapScanner.java index 73f5b929e27d..c890bb3ef20a 100644 --- a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/heap/ImageHeapScanner.java +++ b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/heap/ImageHeapScanner.java @@ -259,7 +259,7 @@ protected ImageHeapConstant createImageHeapObject(JavaConstant constant, ScanRea if (type.isArray()) { Integer length = hostedValuesProvider.readArrayLength(constant); if (type.getComponentType().isPrimitive()) { - return new ImageHeapPrimitiveArray(type, constant, asObject(constant), length); + return new ImageHeapPrimitiveArray(type, constant, snippetReflection.asObject(Object.class, constant), length); } else { return createImageHeapObjectArray(constant, type, length, reason); } @@ -689,7 +689,7 @@ public void rescanObject(Object object, ScanReason reason) { private void rescanCollectionElements(JavaConstant constant) { if (isNonNullObjectConstant(constant)) { - rescanCollectionElements(asObject(((ImageHeapConstant) constant).getHostedObject())); + rescanCollectionElements(snippetReflection.asObject(Object.class, constant)); } } @@ -730,10 +730,6 @@ void doScan(JavaConstant constant, ScanReason reason) { markReachable(value, reason, null); } - protected Object asObject(JavaConstant constant) { - return snippetReflection.asObject(Object.class, constant); - } - private JavaConstant asConstant(Object object) { return hostedValuesProvider.forObject(object); } diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/heap/SVMImageHeapScanner.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/heap/SVMImageHeapScanner.java index 1a8398a0a2e9..98cae252d6c9 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/heap/SVMImageHeapScanner.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/heap/SVMImageHeapScanner.java @@ -154,24 +154,21 @@ protected void rescanEconomicMap(EconomicMap map) { @Override protected void onObjectReachable(ImageHeapConstant imageHeapConstant, ScanReason reason, Consumer onAnalysisModified) { super.onObjectReachable(imageHeapConstant, reason, onAnalysisModified); - JavaConstant hostedObject = imageHeapConstant.getHostedObject(); - if (hostedObject != null) { - Object object = snippetReflection.asObject(Object.class, hostedObject); - if (object instanceof Field field) { - reflectionSupport.registerHeapReflectionField(field, reason); - } else if (object instanceof Executable executable) { - reflectionSupport.registerHeapReflectionExecutable(executable, reason); - } else if (object instanceof DynamicHub hub) { - reflectionSupport.registerHeapDynamicHub(hub, reason); - } else if (object instanceof VarHandle varHandle) { - varHandleSupport.registerHeapVarHandle(varHandle); - } else if (directMethodHandleClass.isInstance(object)) { - varHandleSupport.registerHeapMethodHandle((MethodHandle) object); - } else if (object instanceof MethodType methodType) { - methodHandleSupport.registerHeapMethodType(methodType); - } else if (memberNameClass.isInstance(object)) { - methodHandleSupport.registerHeapMemberName((Member) object); - } + Object object = snippetReflection.asObject(Object.class, imageHeapConstant); + if (object instanceof Field field) { + reflectionSupport.registerHeapReflectionField(field, reason); + } else if (object instanceof Executable executable) { + reflectionSupport.registerHeapReflectionExecutable(executable, reason); + } else if (object instanceof DynamicHub hub) { + reflectionSupport.registerHeapDynamicHub(hub, reason); + } else if (object instanceof VarHandle varHandle) { + varHandleSupport.registerHeapVarHandle(varHandle); + } else if (directMethodHandleClass.isInstance(object)) { + varHandleSupport.registerHeapMethodHandle((MethodHandle) object); + } else if (object instanceof MethodType methodType) { + methodHandleSupport.registerHeapMethodType(methodType); + } else if (memberNameClass.isInstance(object)) { + methodHandleSupport.registerHeapMemberName((Member) object); } } } diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/NativeImageHeap.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/NativeImageHeap.java index e4a35f1ea3c4..619e88bc4ed3 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/NativeImageHeap.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/NativeImageHeap.java @@ -633,15 +633,11 @@ private static StringBuilder fillReasonStack(StringBuilder msg, Object reason) { * Determine if a constant will be immutable in the native image heap. */ private boolean isKnownImmutableConstant(JavaConstant constant) { - JavaConstant hostedConstant = constant; - if (constant instanceof ImageHeapConstant imageHeapConstant) { - hostedConstant = imageHeapConstant.getHostedObject(); - if (hostedConstant == null) { - /* A simulated ImageHeapConstant cannot be marked as immutable. */ - return false; - } + if (constant instanceof ImageHeapConstant imageHeapConstant && !imageHeapConstant.isBackedByHostedObject()) { + /* A simulated ImageHeapConstant cannot be marked as immutable. */ + return false; } - Object obj = hUniverse.getSnippetReflection().asObject(Object.class, hostedConstant); + Object obj = hUniverse.getSnippetReflection().asObject(Object.class, constant); return UniverseBuilder.isKnownImmutableType(obj.getClass()) || knownImmutableObjects.contains(obj); } diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/phases/AnalysisGraphBuilderPhase.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/phases/AnalysisGraphBuilderPhase.java index 37771d29a1e4..70b9dc0b0e54 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/phases/AnalysisGraphBuilderPhase.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/phases/AnalysisGraphBuilderPhase.java @@ -179,8 +179,7 @@ protected void genInvokeDynamic(int cpi, int opcode) { List staticArgumentsList = bootstrap.getStaticArguments(); boolean isVarargs = bootstrap.getMethod().isVarArgs(); int bci = bci(); - JavaConstant type = ((ImageHeapInstance) bootstrap.getType()).getHostedObject(); - MethodType methodType = (MethodType) ((DirectSubstrateObjectConstant) type).getObject(); + MethodType methodType = getSnippetReflection().asObject(MethodType.class, bootstrap.getType()); for (JavaConstant argument : staticArgumentsList) { if (argument instanceof ImageHeapInstance imageHeapInstance) { diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/phases/SharedGraphBuilderPhase.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/phases/SharedGraphBuilderPhase.java index 5ab1e60466fe..13dbcf8e2c05 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/phases/SharedGraphBuilderPhase.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/phases/SharedGraphBuilderPhase.java @@ -63,7 +63,6 @@ import com.oracle.svm.core.graal.nodes.FieldOffsetNode; import com.oracle.svm.core.graal.nodes.LoweredDeadEndNode; import com.oracle.svm.core.hub.DynamicHub; -import com.oracle.svm.core.meta.DirectSubstrateObjectConstant; import com.oracle.svm.core.nodes.SubstrateMethodCallTargetNode; import com.oracle.svm.core.util.UserError; import com.oracle.svm.core.util.UserError.UserException; @@ -909,13 +908,12 @@ private Object loadConstantDynamic(int cpi, int opcode) { int parameterLength = bootstrap.getMethod().getParameters().length; List staticArguments = bootstrap.getStaticArguments(); boolean isVarargs = bootstrap.getMethod().isVarArgs(); - JavaConstant type = ((ImageHeapInstance) bootstrap.getType()).getHostedObject(); - DynamicHub typeClass = (DynamicHub) ((DirectSubstrateObjectConstant) type).getObject(); + DynamicHub typeClass = getSnippetReflection().asObject(DynamicHub.class, bootstrap.getType()); boolean isPrimitive = typeClass.isPrimitive(); for (JavaConstant argument : staticArguments) { if (argument instanceof ImageHeapInstance imageHeapInstance) { - Object arg = ((DirectSubstrateObjectConstant) imageHeapInstance.getHostedObject()).getObject(); + Object arg = getSnippetReflection().asObject(Object.class, imageHeapInstance); if (arg instanceof UnresolvedJavaType) { return arg; } From 813815ecc9b59b483bc27a5576d5564adccd3a05 Mon Sep 17 00:00:00 2001 From: David Leopoldseder Date: Mon, 22 Jan 2024 09:13:38 +0100 Subject: [PATCH 572/593] run test only with correct jdk version --- .../hotspot/test/HotSpotLoopOverflowSpeculationTest.java | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/hotspot/test/HotSpotLoopOverflowSpeculationTest.java b/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/hotspot/test/HotSpotLoopOverflowSpeculationTest.java index eabc2338c8c5..7f5872a3dfa2 100644 --- a/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/hotspot/test/HotSpotLoopOverflowSpeculationTest.java +++ b/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/hotspot/test/HotSpotLoopOverflowSpeculationTest.java @@ -28,6 +28,8 @@ import java.util.Optional; import java.util.concurrent.atomic.AtomicInteger; +import org.junit.Assume; +import org.junit.Before; import org.junit.Test; import jdk.graal.compiler.api.directives.GraalDirectives; @@ -54,6 +56,11 @@ */ public class HotSpotLoopOverflowSpeculationTest extends GraalCompilerTest { + @Before + public void checkJDKVersion() { + Assume.assumeTrue("inconsistent speculation log fixed in 23+5", Runtime.version().compareToIgnoreOptional(Runtime.Version.parse("23+5")) >= 0); + } + public static final boolean LOG_STDOUT = false; // Snippet with a loop that can easily overflow From 8f7ae0d36ceae45fe97f07389e4d8938ea3928f8 Mon Sep 17 00:00:00 2001 From: Josef Eisl Date: Mon, 22 Jan 2024 09:40:53 +0100 Subject: [PATCH 573/593] svm: disable JFR tests affected by "JDK-8322675: JFR: Fail-fast mode when constants cannot be resolved" [GR-51526] --- .../svm/test/jfr/TestJavaLevelVirtualThreadEvents.java | 3 +++ .../src/com/oracle/svm/test/jfr/TestMirrorEvents.java | 3 +++ .../com/oracle/svm/test/jfr/TestVirtualThreadsBasic.java | 9 +++++---- .../svm/test/jfr/TestVirtualThreadsChunkRotation.java | 4 +++- .../svm/test/jfr/TestVirtualThreadsJfrStreaming.java | 4 +++- 5 files changed, 17 insertions(+), 6 deletions(-) diff --git a/substratevm/src/com.oracle.svm.test/src/com/oracle/svm/test/jfr/TestJavaLevelVirtualThreadEvents.java b/substratevm/src/com.oracle.svm.test/src/com/oracle/svm/test/jfr/TestJavaLevelVirtualThreadEvents.java index 1810859671ab..1fc94bdf8207 100644 --- a/substratevm/src/com.oracle.svm.test/src/com/oracle/svm/test/jfr/TestJavaLevelVirtualThreadEvents.java +++ b/substratevm/src/com.oracle.svm.test/src/com/oracle/svm/test/jfr/TestJavaLevelVirtualThreadEvents.java @@ -36,11 +36,13 @@ import java.util.List; import java.util.Map; +import org.junit.Assume; import org.junit.Test; import com.oracle.svm.core.thread.Target_jdk_internal_vm_Continuation; import com.oracle.svm.test.jfr.events.StringEvent; +import jdk.graal.compiler.serviceprovider.JavaVersionUtil; import jdk.jfr.Recording; import jdk.jfr.consumer.RecordedEvent; import jdk.jfr.consumer.RecordedThread; @@ -54,6 +56,7 @@ public class TestJavaLevelVirtualThreadEvents extends JfrRecordingTest { @Test public void test() throws Throwable { + Assume.assumeFalse("Currently broken on JDK 23+ (GR-51526)", JavaVersionUtil.JAVA_SPEC >= 23); String[] events = new String[]{"jdk.ThreadSleep", "jdk.VirtualThreadStart", "jdk.VirtualThreadEnd", "jdk.VirtualThreadPinned", "com.jfr.String"}; Recording recording = startRecording(events); Runnable r = () -> { diff --git a/substratevm/src/com.oracle.svm.test/src/com/oracle/svm/test/jfr/TestMirrorEvents.java b/substratevm/src/com.oracle.svm.test/src/com/oracle/svm/test/jfr/TestMirrorEvents.java index c26c5ed35c4c..9a454c574b1c 100644 --- a/substratevm/src/com.oracle.svm.test/src/com/oracle/svm/test/jfr/TestMirrorEvents.java +++ b/substratevm/src/com.oracle.svm.test/src/com/oracle/svm/test/jfr/TestMirrorEvents.java @@ -30,8 +30,10 @@ import java.util.List; +import org.junit.Assume; import org.junit.Test; +import jdk.graal.compiler.serviceprovider.JavaVersionUtil; import jdk.jfr.EventType; import jdk.jfr.Recording; import jdk.jfr.consumer.RecordedEvent; @@ -45,6 +47,7 @@ public class TestMirrorEvents extends JfrRecordingTest { @Test public void test() throws Throwable { + Assume.assumeFalse("Currently broken on JDK 23+ (GR-51526)", JavaVersionUtil.JAVA_SPEC >= 23); String[] events = new String[]{"jdk.ThreadSleep", "jdk.VirtualThreadStart", "jdk.VirtualThreadEnd"}; Recording recording = startRecording(events); diff --git a/substratevm/src/com.oracle.svm.test/src/com/oracle/svm/test/jfr/TestVirtualThreadsBasic.java b/substratevm/src/com.oracle.svm.test/src/com/oracle/svm/test/jfr/TestVirtualThreadsBasic.java index c8812e4931e5..83cffffe34d6 100644 --- a/substratevm/src/com.oracle.svm.test/src/com/oracle/svm/test/jfr/TestVirtualThreadsBasic.java +++ b/substratevm/src/com.oracle.svm.test/src/com/oracle/svm/test/jfr/TestVirtualThreadsBasic.java @@ -27,8 +27,8 @@ package com.oracle.svm.test.jfr; import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertTrue; import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; import static org.junit.Assume.assumeTrue; import java.util.Collections; @@ -37,14 +37,14 @@ import java.util.Set; import java.util.concurrent.atomic.AtomicInteger; -import jdk.jfr.Recording; -import org.junit.Test; +import org.junit.Assume; import org.junit.Before; +import org.junit.Test; import com.oracle.svm.core.jfr.JfrEvent; import jdk.graal.compiler.serviceprovider.JavaVersionUtil; - +import jdk.jfr.Recording; import jdk.jfr.consumer.RecordedClass; import jdk.jfr.consumer.RecordedEvent; import jdk.jfr.consumer.RecordedThread; @@ -68,6 +68,7 @@ public void checkJavaVersion() { @Test public void test() throws Throwable { + Assume.assumeFalse("Currently broken on JDK 23+ (GR-51526)", JavaVersionUtil.JAVA_SPEC >= 23); String[] events = new String[]{JfrEvent.JavaMonitorWait.getName()}; Recording recording = startRecording(events); diff --git a/substratevm/src/com.oracle.svm.test/src/com/oracle/svm/test/jfr/TestVirtualThreadsChunkRotation.java b/substratevm/src/com.oracle.svm.test/src/com/oracle/svm/test/jfr/TestVirtualThreadsChunkRotation.java index c9d92f52bc40..dffc0ac5b5fa 100644 --- a/substratevm/src/com.oracle.svm.test/src/com/oracle/svm/test/jfr/TestVirtualThreadsChunkRotation.java +++ b/substratevm/src/com.oracle.svm.test/src/com/oracle/svm/test/jfr/TestVirtualThreadsChunkRotation.java @@ -37,12 +37,13 @@ import java.util.Set; import java.util.concurrent.atomic.AtomicInteger; -import jdk.graal.compiler.serviceprovider.JavaVersionUtil; +import org.junit.Assume; import org.junit.Before; import org.junit.Test; import com.oracle.svm.core.jfr.JfrEvent; +import jdk.graal.compiler.serviceprovider.JavaVersionUtil; import jdk.jfr.Recording; import jdk.jfr.consumer.RecordedClass; import jdk.jfr.consumer.RecordedEvent; @@ -70,6 +71,7 @@ public void checkJavaVersion() { @Test public void test() throws Throwable { + Assume.assumeFalse("Currently broken on JDK 23+ (GR-51526)", JavaVersionUtil.JAVA_SPEC >= 23); String[] events = new String[]{JfrEvent.JavaMonitorWait.getName()}; Recording recording = startRecording(events); diff --git a/substratevm/src/com.oracle.svm.test/src/com/oracle/svm/test/jfr/TestVirtualThreadsJfrStreaming.java b/substratevm/src/com.oracle.svm.test/src/com/oracle/svm/test/jfr/TestVirtualThreadsJfrStreaming.java index ca479f2eb6cd..5536c7923f1a 100644 --- a/substratevm/src/com.oracle.svm.test/src/com/oracle/svm/test/jfr/TestVirtualThreadsJfrStreaming.java +++ b/substratevm/src/com.oracle.svm.test/src/com/oracle/svm/test/jfr/TestVirtualThreadsJfrStreaming.java @@ -34,12 +34,13 @@ import java.util.Set; import java.util.concurrent.atomic.AtomicInteger; -import jdk.graal.compiler.serviceprovider.JavaVersionUtil; +import org.junit.Assume; import org.junit.Before; import org.junit.Test; import com.oracle.svm.core.jfr.JfrEvent; +import jdk.graal.compiler.serviceprovider.JavaVersionUtil; import jdk.jfr.consumer.RecordedClass; import jdk.jfr.consumer.RecordedThread; import jdk.jfr.consumer.RecordingStream; @@ -64,6 +65,7 @@ public void checkJavaVersion() { @Test public void test() throws Throwable { + Assume.assumeFalse("Currently broken on JDK 23+ (GR-51526)", JavaVersionUtil.JAVA_SPEC >= 23); String[] events = new String[]{JfrEvent.JavaMonitorWait.getName()}; RecordingStream stream = startStream(events); From de66c40df6d0e32070483d5e848a397c6ac581b5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Paul=20W=C3=B6gerer?= Date: Thu, 18 Jan 2024 13:22:48 +0100 Subject: [PATCH 574/593] Make -jar only implicitly set image name if not already defined previously --- .../svm/driver/DefaultOptionHandler.java | 2 +- .../com/oracle/svm/driver/NativeImage.java | 27 ++++++++++++++++++- 2 files changed, 27 insertions(+), 2 deletions(-) diff --git a/substratevm/src/com.oracle.svm.driver/src/com/oracle/svm/driver/DefaultOptionHandler.java b/substratevm/src/com.oracle.svm.driver/src/com/oracle/svm/driver/DefaultOptionHandler.java index 5f277a36a631..555b4c2efdc0 100644 --- a/substratevm/src/com.oracle.svm.driver/src/com/oracle/svm/driver/DefaultOptionHandler.java +++ b/substratevm/src/com.oracle.svm.driver/src/com/oracle/svm/driver/DefaultOptionHandler.java @@ -251,7 +251,7 @@ private void handleJarFileArg(Path jarFilePath) { } if (!jarFileNameBase.isEmpty()) { String origin = "manifest from " + jarFilePath.toUri(); - nativeImage.addPlainImageBuilderArg(nativeImage.oHName + jarFileNameBase, origin); + nativeImage.addPlainImageBuilderArg(nativeImage.oHName + jarFileNameBase, origin, false); } Path finalFilePath = nativeImage.useBundle() ? nativeImage.bundleSupport.substituteClassPath(jarFilePath) : jarFilePath; if (!NativeImage.processJarManifestMainAttributes(finalFilePath, nativeImage::handleManifestFileAttributes)) { diff --git a/substratevm/src/com.oracle.svm.driver/src/com/oracle/svm/driver/NativeImage.java b/substratevm/src/com.oracle.svm.driver/src/com/oracle/svm/driver/NativeImage.java index 3a804ec153e3..ca29093938f8 100644 --- a/substratevm/src/com.oracle.svm.driver/src/com/oracle/svm/driver/NativeImage.java +++ b/substratevm/src/com.oracle.svm.driver/src/com/oracle/svm/driver/NativeImage.java @@ -2007,11 +2007,36 @@ List apply(boolean strict) { } void addPlainImageBuilderArg(String plainArg, String origin) { - addPlainImageBuilderArg(injectHostedOptionOrigin(plainArg, origin)); + addPlainImageBuilderArg(plainArg, origin, true); + } + + void addPlainImageBuilderArg(String plainArg, String origin, boolean override) { + addPlainImageBuilderArg(injectHostedOptionOrigin(plainArg, origin), override); } void addPlainImageBuilderArg(String plainArg) { + addPlainImageBuilderArg(plainArg, true); + } + + void addPlainImageBuilderArg(String plainArg, boolean override) { assert plainArg.startsWith(NativeImage.oH) || plainArg.startsWith(NativeImage.oR); + if (!override) { + int posValueSeparator = plainArg.indexOf('='); + if (posValueSeparator > 0) { + String argPrefix = plainArg.substring(0, posValueSeparator); + int posOriginSeparator = plainArg.indexOf('@'); + if (posOriginSeparator > 0) { + argPrefix = argPrefix.substring(0, posOriginSeparator); + } + String existingValue = getHostedOptionFinalArgumentValue(imageBuilderArgs, argPrefix + '='); + if (existingValue != null) { + /* Respect the existing value. Do not append overriding value. */ + return; + } + } else { + VMError.shouldNotReachHere("override=false currently only works for non-boolean options"); + } + } imageBuilderArgs.add(plainArg); } From f9496e373daadeb21f9f9fea153290757e1b8a3f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Paul=20W=C3=B6gerer?= Date: Thu, 18 Jan 2024 13:28:36 +0100 Subject: [PATCH 575/593] Rename helper-methods to better reflect their intended use --- .../com/oracle/svm/driver/NativeImage.java | 38 +++++++++---------- 1 file changed, 19 insertions(+), 19 deletions(-) diff --git a/substratevm/src/com.oracle.svm.driver/src/com/oracle/svm/driver/NativeImage.java b/substratevm/src/com.oracle.svm.driver/src/com/oracle/svm/driver/NativeImage.java index ca29093938f8..d072815b12cb 100644 --- a/substratevm/src/com.oracle.svm.driver/src/com/oracle/svm/driver/NativeImage.java +++ b/substratevm/src/com.oracle.svm.driver/src/com/oracle/svm/driver/NativeImage.java @@ -1091,7 +1091,7 @@ private int completeImageBuild() { addTargetArguments(); String defaultLibC = OS.getCurrent() == OS.LINUX ? "glibc" : null; - targetLibC = getHostedOptionFinalArgument(imageBuilderArgs, oHUseLibC).map(ArgumentEntry::value).orElse(System.getProperty("substratevm.HostLibC", defaultLibC)); + targetLibC = getHostedOptionArgument(imageBuilderArgs, oHUseLibC).map(ArgumentEntry::value).orElse(System.getProperty("substratevm.HostLibC", defaultLibC)); String clibrariesBuilderArg = config.getBuilderCLibrariesPaths().stream() .flatMap(this::resolveTargetSpecificPaths) @@ -1166,7 +1166,7 @@ private int completeImageBuild() { imageBuilderJavaArgs.addAll(getAgentArguments()); - mainClass = getHostedOptionFinalArgumentValue(imageBuilderArgs, oHClass); + mainClass = getHostedOptionArgumentValue(imageBuilderArgs, oHClass); buildExecutable = imageBuilderArgs.stream().noneMatch(arg -> arg.startsWith(oHEnableSharedLibraryFlagPrefix)); staticExecutable = imageBuilderArgs.stream().anyMatch(arg -> arg.contains(oHEnableStaticExecutable)); boolean listModules = imageBuilderArgs.stream().anyMatch(arg -> arg.contains(oH + "+" + "ListModules")); @@ -1188,8 +1188,8 @@ private int completeImageBuild() { if (!jarOptionMode) { /* Main-class from customImageBuilderArgs counts as explicitMainClass */ - boolean explicitMainClass = getHostedOptionFinalArgumentValue(imageBuilderArgs, oHClass) != null; - mainClassModule = getHostedOptionFinalArgumentValue(imageBuilderArgs, oHModule); + boolean explicitMainClass = getHostedOptionArgumentValue(imageBuilderArgs, oHClass) != null; + mainClassModule = getHostedOptionArgumentValue(imageBuilderArgs, oHModule); boolean hasMainClassModule = mainClassModule != null && !mainClassModule.isEmpty(); boolean hasMainClass = mainClass != null && !mainClass.isEmpty(); @@ -1207,11 +1207,11 @@ private int completeImageBuild() { if (extraImageArgs.isEmpty()) { /* No explicit image name, define image name by other means */ - if (getHostedOptionFinalArgumentValue(imageBuilderArgs, oHName) == null) { + if (getHostedOptionArgumentValue(imageBuilderArgs, oHName) == null) { /* Also no explicit image name given as customImageBuilderArgs */ if (explicitMainClass) { imageBuilderArgs.add(oH(SubstrateOptions.Name, "main-class lower case as image name") + mainClass.toLowerCase()); - } else if (getHostedOptionFinalArgumentValue(imageBuilderArgs, oHName) == null) { + } else if (getHostedOptionArgumentValue(imageBuilderArgs, oHName) == null) { if (hasMainClassModule) { imageBuilderArgs.add(oH(SubstrateOptions.Name, "image-name from module-name") + mainClassModule.toLowerCase()); } else if (!listModules) { @@ -1236,9 +1236,9 @@ private int completeImageBuild() { } } - ArgumentEntry imageNameEntry = getHostedOptionFinalArgument(imageBuilderArgs, oHName).orElseThrow(); + ArgumentEntry imageNameEntry = getHostedOptionArgument(imageBuilderArgs, oHName).orElseThrow(); imageName = imageNameEntry.value; - ArgumentEntry imagePathEntry = getHostedOptionFinalArgument(imageBuilderArgs, oHPath).orElseThrow(); + ArgumentEntry imagePathEntry = getHostedOptionArgument(imageBuilderArgs, oHPath).orElseThrow(); imagePath = Path.of(imagePathEntry.value); Path imageNamePath = Path.of(imageName); Path imageNamePathParent = imageNamePath.getParent(); @@ -1307,7 +1307,7 @@ private int completeImageBuild() { imageProvidedJars.forEach(this::processClasspathNativeImageMetaInf); if (!config.buildFallbackImage()) { - Optional fallbackThresholdEntry = getHostedOptionFinalArgument(imageBuilderArgs, oHFallbackThreshold); + Optional fallbackThresholdEntry = getHostedOptionArgument(imageBuilderArgs, oHFallbackThreshold); if (fallbackThresholdEntry.isPresent() && fallbackThresholdEntry.get().value.equals("" + SubstrateOptions.ForceFallback)) { /* Bypass regular build and proceed with fallback image building */ return ExitStatus.FALLBACK_IMAGE.getValue(); @@ -1344,11 +1344,11 @@ private static String getLocationAgnosticArgPrefix(String argPrefix) { return "^" + argPrefix.substring(0, argPrefix.length() - 1) + "(@[^=]*)?="; } - private static String getHostedOptionFinalArgumentValue(List args, String argPrefix) { - return getHostedOptionFinalArgument(args, argPrefix).map(entry -> entry.value).orElse(null); + private static String getHostedOptionArgumentValue(List args, String argPrefix) { + return getHostedOptionArgument(args, argPrefix).map(entry -> entry.value).orElse(null); } - private static Optional getHostedOptionFinalArgument(List args, String argPrefix) { + private static Optional getHostedOptionArgument(List args, String argPrefix) { List values = getHostedOptionArgumentValues(args, argPrefix); return values.isEmpty() ? Optional.empty() : Optional.of(values.get(values.size() - 1)); } @@ -1371,7 +1371,7 @@ private static List getHostedOptionArgumentValues(List ar private record ArgumentEntry(int index, String value) { } - private static Boolean getHostedOptionFinalBooleanArgumentValue(List args, OptionKey option) { + private static Boolean getHostedOptionBooleanArgumentValue(List args, OptionKey option) { String locationAgnosticBooleanPattern = "^" + oH + "[+-]" + option.getName() + "(@[^=]*)?$"; Pattern pattern = Pattern.compile(locationAgnosticBooleanPattern); Boolean result = null; @@ -1442,7 +1442,7 @@ private void addTargetArguments() { * process (see comments for NativeImageGenerator.getTargetPlatform), we are parsing the * --target argument here, and generating required internal arguments. */ - targetPlatform = getHostedOptionFinalArgumentValue(imageBuilderArgs, oHTargetPlatform); + targetPlatform = getHostedOptionArgumentValue(imageBuilderArgs, oHTargetPlatform); if (targetPlatform == null) { return; } @@ -2028,7 +2028,7 @@ void addPlainImageBuilderArg(String plainArg, boolean override) { if (posOriginSeparator > 0) { argPrefix = argPrefix.substring(0, posOriginSeparator); } - String existingValue = getHostedOptionFinalArgumentValue(imageBuilderArgs, argPrefix + '='); + String existingValue = getHostedOptionArgumentValue(imageBuilderArgs, argPrefix + '='); if (existingValue != null) { /* Respect the existing value. Do not append overriding value. */ return; @@ -2369,7 +2369,7 @@ private static boolean logRedirectedToFile() { private boolean configureBuildOutput() { boolean useColorfulOutput = false; - String colorValue = getHostedOptionFinalArgumentValue(imageBuilderArgs, oHColor); + String colorValue = getHostedOptionArgumentValue(imageBuilderArgs, oHColor); if (colorValue != null) { // use value set by user if ("always".equals(colorValue)) { useColorfulOutput = true; @@ -2378,7 +2378,7 @@ private boolean configureBuildOutput() { addPlainImageBuilderArg(oHColor + (useColorfulOutput ? "always" : "never"), OptionOrigin.originDriver); } } else { - Boolean buildOutputColorfulValue = getHostedOptionFinalBooleanArgumentValue(imageBuilderArgs, SubstrateOptions.BuildOutputColorful); + Boolean buildOutputColorfulValue = getHostedOptionBooleanArgumentValue(imageBuilderArgs, SubstrateOptions.BuildOutputColorful); if (buildOutputColorfulValue != null) { useColorfulOutput = buildOutputColorfulValue; // use value set by user } else if (hasColorSupport()) { @@ -2386,10 +2386,10 @@ private boolean configureBuildOutput() { addPlainImageBuilderArg(oHColor + "always", OptionOrigin.originDriver); } } - if (getHostedOptionFinalBooleanArgumentValue(imageBuilderArgs, SubstrateOptions.BuildOutputProgress) == null && hasProgressSupport(imageBuilderArgs)) { + if (getHostedOptionBooleanArgumentValue(imageBuilderArgs, SubstrateOptions.BuildOutputProgress) == null && hasProgressSupport(imageBuilderArgs)) { addPlainImageBuilderArg(oHEnableBuildOutputProgress); } - if (getHostedOptionFinalBooleanArgumentValue(imageBuilderArgs, SubstrateOptions.BuildOutputLinks) == null && (colorValue == null || "auto".equals(colorValue)) && useColorfulOutput) { + if (getHostedOptionBooleanArgumentValue(imageBuilderArgs, SubstrateOptions.BuildOutputLinks) == null && (colorValue == null || "auto".equals(colorValue)) && useColorfulOutput) { addPlainImageBuilderArg(oHEnableBuildOutputLinks); } return useColorfulOutput; From b402c9aaa2105df40aa95765deef09b0d13b9ab1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Paul=20W=C3=B6gerer?= Date: Thu, 18 Jan 2024 13:46:35 +0100 Subject: [PATCH 576/593] Update documentation to reflect -jar option behaviour change --- .../native-image/guides/build-native-executable-from-jar.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/docs/reference-manual/native-image/guides/build-native-executable-from-jar.md b/docs/reference-manual/native-image/guides/build-native-executable-from-jar.md index e7fe0739cbba..5170c0a11a76 100644 --- a/docs/reference-manual/native-image/guides/build-native-executable-from-jar.md +++ b/docs/reference-manual/native-image/guides/build-native-executable-from-jar.md @@ -71,7 +71,8 @@ For other installation options, visit the [Downloads section](https://www.graalv native-image -jar App.jar ``` - It will produce a native executable in the project root directory. + It will produce a native executable in the project root directory. The default name of the image will be the basename of the jarfile (`App` in our example). + This can be customized by either providing a custom image name as last argument or by using `-o imagename` before or after `-jar jarfile`. 6. Run the native executable: ```shell From 167abaccbc50d90c5349a7b1c76604c489d1013c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Paul=20W=C3=B6gerer?= Date: Thu, 18 Jan 2024 14:09:20 +0100 Subject: [PATCH 577/593] Update CHANGELOG --- substratevm/CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/substratevm/CHANGELOG.md b/substratevm/CHANGELOG.md index 9123458c185d..1f2b6be012d8 100644 --- a/substratevm/CHANGELOG.md +++ b/substratevm/CHANGELOG.md @@ -4,6 +4,7 @@ This changelog summarizes major changes to GraalVM Native Image. ## GraalVM for JDK 23 (Internal Version 24.1.0) * (GR-51106) Fields that are accessed via a `VarHandle` or `MethodHandle` are no longer marked as "unsafe accessed" when the `VarHandle`/`MethodHandle` can be fully intrinsified. +* (GR-49996) Make `-jar jarfile` only implicitly set image name if not already defined previously (with e.g. `-o imagename`). ## GraalVM for JDK 22 (Internal Version 24.0.0) * (GR-48304) Red Hat added support for the JFR event ThreadAllocationStatistics. From ffceb299935c2afc50bf232ec8e255101f5158fa Mon Sep 17 00:00:00 2001 From: Fabio Niephaus Date: Mon, 22 Jan 2024 08:32:09 +0000 Subject: [PATCH 578/593] Reword CHANGELOG entry --- substratevm/CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/substratevm/CHANGELOG.md b/substratevm/CHANGELOG.md index 1f2b6be012d8..26e64e3f6ab4 100644 --- a/substratevm/CHANGELOG.md +++ b/substratevm/CHANGELOG.md @@ -4,7 +4,7 @@ This changelog summarizes major changes to GraalVM Native Image. ## GraalVM for JDK 23 (Internal Version 24.1.0) * (GR-51106) Fields that are accessed via a `VarHandle` or `MethodHandle` are no longer marked as "unsafe accessed" when the `VarHandle`/`MethodHandle` can be fully intrinsified. -* (GR-49996) Make `-jar jarfile` only implicitly set image name if not already defined previously (with e.g. `-o imagename`). +* (GR-49996) Ensure explicitly set image name (e.g., via `-o imagename`) is not accidentally overwritten by `-jar jarfile` option. ## GraalVM for JDK 22 (Internal Version 24.0.0) * (GR-48304) Red Hat added support for the JFR event ThreadAllocationStatistics. From a5b2ec71e8eb1a914c225e6bfb24a0c4e1197f86 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Paul=20W=C3=B6gerer?= Date: Mon, 22 Jan 2024 09:43:21 +0100 Subject: [PATCH 579/593] Tweak documentation change --- .../native-image/guides/build-native-executable-from-jar.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/docs/reference-manual/native-image/guides/build-native-executable-from-jar.md b/docs/reference-manual/native-image/guides/build-native-executable-from-jar.md index 5170c0a11a76..ca32b121fcc2 100644 --- a/docs/reference-manual/native-image/guides/build-native-executable-from-jar.md +++ b/docs/reference-manual/native-image/guides/build-native-executable-from-jar.md @@ -71,8 +71,9 @@ For other installation options, visit the [Downloads section](https://www.graalv native-image -jar App.jar ``` - It will produce a native executable in the project root directory. The default name of the image will be the basename of the jarfile (`App` in our example). - This can be customized by either providing a custom image name as last argument or by using `-o imagename` before or after `-jar jarfile`. + It will produce a native executable in the project root directory. + The default name of the image will be the name of the JAR file (`App` in this case). + It can be customized by either providing a custom name as a last argument (for example, `native-image -jar App.jar imagename`), or by using `-o imagename` before or after `-jar jarfile`, for example: `native-image -jar App.jar -o imagename`. 6. Run the native executable: ```shell From 4dcd7bdb8207eb5b0c8cc780043d0b4cf27803ef Mon Sep 17 00:00:00 2001 From: Fabio Niephaus Date: Mon, 22 Jan 2024 09:40:23 +0100 Subject: [PATCH 580/593] Ensure `InterruptImageBuilding` is not wrapped as user or vm error. --- .../src/com/oracle/svm/hosted/FeatureHandler.java | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/FeatureHandler.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/FeatureHandler.java index cc2f781df7fa..d3732680440e 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/FeatureHandler.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/FeatureHandler.java @@ -51,6 +51,7 @@ import com.oracle.svm.core.option.HostedOptionKey; import com.oracle.svm.core.option.LocatableMultiOptionValue; import com.oracle.svm.core.option.SubstrateOptionsParser; +import com.oracle.svm.core.util.InterruptImageBuilding; import com.oracle.svm.core.util.UserError; import com.oracle.svm.core.util.UserError.UserException; import com.oracle.svm.core.util.VMError; @@ -275,13 +276,16 @@ public void dumpAllFeatures(PrintWriter out) { } private static UserException handleFeatureError(Feature feature, Throwable throwable) { - /* Avoid wrapping UserErrors and VMErrors. */ + /* Avoid wrapping UserError, VMError, and InterruptImageBuilding throwables. */ if (throwable instanceof UserException userError) { throw userError; } if (throwable instanceof HostedError vmError) { throw vmError; } + if (throwable instanceof InterruptImageBuilding iib) { + throw iib; + } String featureClassName = feature.getClass().getName(); String throwableClassName = throwable.getClass().getName(); From 8708b351aa5f688b7aacff27c04e37fb7026c096 Mon Sep 17 00:00:00 2001 From: Fabio Niephaus Date: Mon, 22 Jan 2024 09:41:26 +0100 Subject: [PATCH 581/593] Introduce `UserError.invalidOptionValue()`. --- .../com/oracle/svm/core/SubstrateOptions.java | 20 ++++++------- .../com/oracle/svm/core/util/UserError.java | 29 +++++++++++++++++++ 2 files changed, 39 insertions(+), 10 deletions(-) diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/SubstrateOptions.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/SubstrateOptions.java index 62f139a15cb3..bbc73d7fe7eb 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/SubstrateOptions.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/SubstrateOptions.java @@ -57,7 +57,6 @@ import com.oracle.svm.core.option.RuntimeOptionKey; import com.oracle.svm.core.option.SubstrateOptionsParser; import com.oracle.svm.core.thread.VMOperationControl; -import com.oracle.svm.core.util.InterruptImageBuilding; import com.oracle.svm.core.util.UserError; import com.oracle.svm.util.LogUtils; import com.oracle.svm.util.ModuleSupport; @@ -107,7 +106,7 @@ public class SubstrateOptions { @Option(help = "Build statically linked executable (requires static libc and zlib)")// public static final HostedOptionKey StaticExecutable = new HostedOptionKey<>(false, key -> { if (!Platform.includedIn(Platform.LINUX.class)) { - throw new InterruptImageBuilding("Building static executable images is currently only supported on Linux. Remove the '--static' option or build on a Linux machine."); + throw UserError.invalidOptionValue(key, key.getValue(), "Building static executable images is currently only supported on Linux. Remove the '--static' option or build on a Linux machine"); } }); @@ -291,7 +290,7 @@ private static OptimizationLevel parseOptimizationLevel(String value) { // We allow all positive numbers, and treat that as our current highest supported level. return OptimizationLevel.O3; } else { - throw UserError.abort("Invalid value '%s' provided for option Optimize (expected 'b' or numeric value >= 0)", value); + throw UserError.invalidOptionValue(Optimize, value, "Accepted values are 'b' or numeric value >= 0"); } } @@ -489,7 +488,7 @@ public static final boolean hasColorsEnabled(OptionValues values) { yield false; } case "never" -> false; - default -> throw UserError.abort("Unsupported value '%s' for '--color' option. Only 'always', 'never', and 'auto' are accepted.", value); + default -> throw UserError.invalidOptionValue(Color, value, "Only 'always', 'never', and 'auto' are accepted values"); }; } return false; @@ -563,7 +562,7 @@ public static final boolean hasColorsEnabled(OptionValues values) { private static void validateAdditionalHeaderBytes(HostedOptionKey optionKey) { int value = optionKey.getValue(); if (value < 0 || value % 4 != 0) { - throw UserError.abort("The option '%s' must be 0 or a multiple of 4.", optionKey.getName()); + throw UserError.invalidOptionValue(optionKey, value, "The value must be 0 or a positive multiple of 4."); } } @@ -639,8 +638,8 @@ protected void onValueUpdate(EconomicMap, Object> values, String ol isLLVMBackendMissing = ReflectionUtil.lookupClass(true, "com.oracle.svm.core.graal.llvm.LLVMFeature") == null; } if (isLLVMBackendMissing) { - throw UserError.abort( - "The LLVM backend for GraalVM Native Image is missing and needs to be build from source. " + + throw UserError.invalidOptionValue(CompilerBackend, newValue, + "The LLVM backend for GraalVM Native Image is missing and needs to be built from source. " + "For instructions, please see https://github.com/oracle/graal/blob/master/docs/reference-manual/native-image/LLVMBackend.md."); } @@ -772,7 +771,7 @@ public static Path getDebugInfoSourceCacheRoot() { try { return Paths.get(Path.getValue()).resolve(DebugInfoSourceCacheRoot.getValue()); } catch (InvalidPathException ipe) { - throw UserError.abort("Invalid path provided for option DebugInfoSourceCacheRoot %s", DebugInfoSourceCacheRoot.getValue()); + throw UserError.invalidOptionValue(DebugInfoSourceCacheRoot, DebugInfoSourceCacheRoot.getValue(), "The path is invalid"); } } @@ -780,11 +779,12 @@ public static Path getDebugInfoSourceCacheRoot() { public static final HostedOptionKey StripDebugInfo = new HostedOptionKey<>(OS.getCurrent() != OS.DARWIN, SubstrateOptions::validateStripDebugInfo); private static void validateStripDebugInfo(HostedOptionKey optionKey) { + Boolean optionValue = optionKey.getValue(); if (OS.getCurrent() == OS.DARWIN && optionKey.hasBeenSet() && optionKey.getValue()) { - throw UserError.abort("Using %s is not supported on macOS", SubstrateOptionsParser.commandArgument(SubstrateOptions.StripDebugInfo, "+")); + throw UserError.invalidOptionValue(optionKey, optionValue, "The option is not supported on macOS"); } if (OS.getCurrent() == OS.WINDOWS && optionKey.hasBeenSet() && !optionKey.getValue()) { - throw UserError.abort("Using %s is not supported on Windows: debug info is always generated in a separate file", SubstrateOptionsParser.commandArgument(optionKey, "-")); + throw UserError.invalidOptionValue(optionKey, optionValue, "The option is not supported on Windows (debug info is always generated in a separate file)"); } } diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/util/UserError.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/util/UserError.java index 5b66261674e1..166316a92599 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/util/UserError.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/util/UserError.java @@ -29,6 +29,9 @@ import org.graalvm.nativeimage.Platform; import org.graalvm.nativeimage.Platforms; +import com.oracle.svm.core.option.SubstrateOptionsParser; + +import jdk.graal.compiler.options.OptionKey; import jdk.vm.ci.meta.ResolvedJavaField; import jdk.vm.ci.meta.ResolvedJavaMethod; import jdk.vm.ci.meta.ResolvedJavaType; @@ -134,4 +137,30 @@ static Object[] formatArguments(Object... args) { public static UserException abort(Iterable messages) { throw new UserException(messages); } + + /** + * Stop compilation immediately and report the invalid use of an option to the user. + * + * @param option the option incorrectly used. + * @param value the value passed to the option, possibly invalid. + * @param reason the reason why the option-value pair is rejected that can be understood by the + * user. + */ + public static UserException invalidOptionValue(OptionKey option, String value, String reason) { + return abort("Invalid option '%s'. %s.", SubstrateOptionsParser.commandArgument(option, value), reason); + } + + /** + * @see #invalidOptionValue(OptionKey, String, String) + */ + public static UserException invalidOptionValue(OptionKey option, Boolean value, String reason) { + return invalidOptionValue(option, value ? "+" : "-", reason); + } + + /** + * @see #invalidOptionValue(OptionKey, String, String) + */ + public static UserException invalidOptionValue(OptionKey option, Number value, String reason) { + return invalidOptionValue(option, String.valueOf(value), reason); + } } From 39546dd4572574b54a3696d7bc42bdab6973ddab Mon Sep 17 00:00:00 2001 From: Fabio Niephaus Date: Mon, 22 Jan 2024 09:45:04 +0100 Subject: [PATCH 582/593] Report invalid options with `UserError`. `InterruptImageBuilding` prints an info message and is also used for other purposes. --- .../core/genscavenge/SerialAndEpsilonGCOptions.java | 11 +++++------ .../oracle/svm/core/genscavenge/SerialGCOptions.java | 3 +-- 2 files changed, 6 insertions(+), 8 deletions(-) diff --git a/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/SerialAndEpsilonGCOptions.java b/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/SerialAndEpsilonGCOptions.java index baca15acf971..70cb3e574180 100644 --- a/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/SerialAndEpsilonGCOptions.java +++ b/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/SerialAndEpsilonGCOptions.java @@ -25,17 +25,17 @@ package com.oracle.svm.core.genscavenge; import org.graalvm.collections.EconomicMap; -import jdk.graal.compiler.options.Option; -import jdk.graal.compiler.options.OptionKey; -import jdk.graal.compiler.options.OptionType; import com.oracle.svm.core.SubstrateOptions; import com.oracle.svm.core.option.HostedOptionKey; import com.oracle.svm.core.option.NotifyGCRuntimeOptionKey; import com.oracle.svm.core.option.RuntimeOptionKey; -import com.oracle.svm.core.util.InterruptImageBuilding; import com.oracle.svm.core.util.UserError; +import jdk.graal.compiler.options.Option; +import jdk.graal.compiler.options.OptionKey; +import jdk.graal.compiler.options.OptionType; + /** Common options that can be specified for both the serial and the epsilon GC. */ public final class SerialAndEpsilonGCOptions { @Option(help = "The maximum heap size as percent of physical memory. Serial and epsilon GC only.", type = OptionType.User) // @@ -77,8 +77,7 @@ private SerialAndEpsilonGCOptions() { public static void serialOrEpsilonGCOnly(OptionKey optionKey) { if (!SubstrateOptions.UseSerialGC.getValue() && !SubstrateOptions.UseEpsilonGC.getValue()) { - throw new InterruptImageBuilding( - "The option '" + optionKey.getName() + "' can only be used together with the serial ('--gc=serial') or the epsilon garbage collector ('--gc=epsilon')."); + throw UserError.abort("The option '" + optionKey.getName() + "' can only be used together with the serial ('--gc=serial') or the epsilon garbage collector ('--gc=epsilon')."); } } } diff --git a/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/SerialGCOptions.java b/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/SerialGCOptions.java index 1301903073e8..12ffc94209cb 100644 --- a/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/SerialGCOptions.java +++ b/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/SerialGCOptions.java @@ -29,7 +29,6 @@ import com.oracle.svm.core.SubstrateOptions; import com.oracle.svm.core.option.HostedOptionKey; import com.oracle.svm.core.option.RuntimeOptionKey; -import com.oracle.svm.core.util.InterruptImageBuilding; import com.oracle.svm.core.util.UserError; import jdk.graal.compiler.options.Option; @@ -112,7 +111,7 @@ private SerialGCOptions() { private static void serialGCOnly(OptionKey optionKey) { if (!SubstrateOptions.UseSerialGC.getValue()) { - throw new InterruptImageBuilding("The option '" + optionKey.getName() + "' can only be used together with the serial garbage collector ('--gc=serial')."); + throw UserError.abort("The option '" + optionKey.getName() + "' can only be used together with the serial garbage collector ('--gc=serial')."); } } } From 20908e0e190ca2273a2bfd2ee8993728ab5d42f3 Mon Sep 17 00:00:00 2001 From: Fabio Niephaus Date: Mon, 22 Jan 2024 10:05:00 +0100 Subject: [PATCH 583/593] Fix reported build status. --- .../src/com/oracle/svm/hosted/ProgressReporter.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/ProgressReporter.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/ProgressReporter.java index acad1a7a38dc..947ae0370f20 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/ProgressReporter.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/ProgressReporter.java @@ -723,8 +723,8 @@ public void printEpilog(Optional optionalImageName, Optional Date: Mon, 22 Jan 2024 10:09:48 +0100 Subject: [PATCH 584/593] Improve naming. --- .../hosted/NativeImageGeneratorRunner.java | 10 ++++----- .../oracle/svm/hosted/ProgressReporter.java | 21 ++++++++++--------- 2 files changed, 16 insertions(+), 15 deletions(-) diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/NativeImageGeneratorRunner.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/NativeImageGeneratorRunner.java index bdcd24397eed..6ba7a931bff9 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/NativeImageGeneratorRunner.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/NativeImageGeneratorRunner.java @@ -379,7 +379,7 @@ private int buildImage(ImageClassLoader classLoader) { } ProgressReporter reporter = new ProgressReporter(parsedHostedOptions); - Throwable vmError = null; + Throwable unhandledThrowable = null; boolean wasSuccessfulBuild = false; try (StopTimer ignored = totalTimer.start()) { Timer classlistTimer = timerCollection.get(TimerCollection.Registry.CLASSLIST); @@ -571,18 +571,18 @@ private int buildImage(ImageClassLoader classLoader) { } return ExitStatus.BUILDER_ERROR.getValue(); } catch (Throwable e) { - vmError = e; + unhandledThrowable = e; return ExitStatus.BUILDER_ERROR.getValue(); } finally { - reportEpilog(imageName, reporter, classLoader, wasSuccessfulBuild, vmError, parsedHostedOptions); + reportEpilog(imageName, reporter, classLoader, wasSuccessfulBuild, unhandledThrowable, parsedHostedOptions); NativeImageGenerator.clearSystemPropertiesForImage(); ImageSingletonsSupportImpl.HostedManagement.clear(); } return ExitStatus.OK.getValue(); } - protected void reportEpilog(String imageName, ProgressReporter reporter, ImageClassLoader classLoader, boolean wasSuccessfulBuild, Throwable vmError, OptionValues parsedHostedOptions) { - reporter.printEpilog(Optional.ofNullable(imageName), Optional.ofNullable(generator), classLoader, wasSuccessfulBuild, Optional.ofNullable(vmError), parsedHostedOptions); + protected void reportEpilog(String imageName, ProgressReporter reporter, ImageClassLoader classLoader, boolean wasSuccessfulBuild, Throwable unhandledThrowable, OptionValues parsedHostedOptions) { + reporter.printEpilog(Optional.ofNullable(imageName), Optional.ofNullable(generator), classLoader, wasSuccessfulBuild, Optional.ofNullable(unhandledThrowable), parsedHostedOptions); } protected NativeImageGenerator createImageGenerator(ImageClassLoader classLoader, HostedOptionParser optionParser, Pair mainEntryPointData, ProgressReporter reporter) { diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/ProgressReporter.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/ProgressReporter.java index 947ae0370f20..b61004f2c439 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/ProgressReporter.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/ProgressReporter.java @@ -686,13 +686,14 @@ private void printRecommendations() { } public void printEpilog(Optional optionalImageName, Optional optionalGenerator, ImageClassLoader classLoader, boolean wasSuccessfulBuild, - Optional optionalError, OptionValues parsedHostedOptions) { + Optional optionalUnhandledThrowable, OptionValues parsedHostedOptions) { executor.shutdown(); - if (optionalError.isPresent()) { + if (optionalUnhandledThrowable.isPresent()) { Path errorReportPath = NativeImageOptions.getErrorFilePath(parsedHostedOptions); Optional featureHandler = optionalGenerator.map(nativeImageGenerator -> nativeImageGenerator.featureHandler); - ReportUtils.report("GraalVM Native Image Error Report", errorReportPath, p -> VMErrorReporter.generateErrorReport(p, buildOutputLog, classLoader, featureHandler, optionalError.get()), + ReportUtils.report("GraalVM Native Image Error Report", errorReportPath, + p -> VMErrorReporter.generateErrorReport(p, buildOutputLog, classLoader, featureHandler, optionalUnhandledThrowable.get()), false); if (ImageSingletonsSupport.isInstalled()) { BuildArtifacts.singleton().add(ArtifactType.BUILD_INFO, errorReportPath); @@ -700,7 +701,7 @@ public void printEpilog(Optional optionalImageName, Optional optionalImageName, Optional optionalError, OptionValues parsedHostedOptions) { - if (optionalError.isEmpty()) { + private void printErrorMessage(Optional optionalUnhandledThrowable, OptionValues parsedHostedOptions) { + if (optionalUnhandledThrowable.isEmpty()) { return; } - Throwable error = optionalError.get(); + Throwable unhandledThrowable = optionalUnhandledThrowable.get(); l().println(); l().redBold().a("The build process encountered an unexpected error:").reset().println(); if (NativeImageOptions.ReportExceptionStackTraces.getValue(parsedHostedOptions)) { l().dim().println(); - error.printStackTrace(builderIO.getOut()); + unhandledThrowable.printStackTrace(builderIO.getOut()); l().reset().println(); } else { l().println(); - l().dim().a("> %s", error).reset().println(); + l().dim().a("> %s", unhandledThrowable).reset().println(); l().println(); l().a("Please inspect the generated error report at:").println(); l().link(NativeImageOptions.getErrorFilePath(parsedHostedOptions)).println(); From 8908d5386af5c42530b16e774eb4cde0ebf38e3a Mon Sep 17 00:00:00 2001 From: Roland Schatz Date: Mon, 22 Jan 2024 11:25:02 +0100 Subject: [PATCH 585/593] Stop testing on ancient LLVM versions. --- sulong/ci/ci.jsonnet | 5 --- sulong/ci/ci_common/sulong-common.jsonnet | 54 ----------------------- 2 files changed, 59 deletions(-) diff --git a/sulong/ci/ci.jsonnet b/sulong/ci/ci.jsonnet index 4af99fa9a846..89d687d724ad 100644 --- a/sulong/ci/ci.jsonnet +++ b/sulong/ci/ci.jsonnet @@ -34,11 +34,6 @@ local sc = (import "ci_common/sulong-common.jsonnet"); sc.gate + $.sulong + sc.labsjdkLatest + sc.linux_amd64 + sc.llvmBundled + sc.requireGMP + sc.gateTags("build,gcc_cpp") + { name: "gate-sulong-gcc_cpp-jdk-latest-linux-amd64", timelimit: "45:00" }, sc.gate + $.sulong + sc.labsjdkLatest + sc.linux_amd64 + sc.llvmBundled + sc.requireGMP + sc.requireGCC + sc.gateTags("build,gcc_fortran") + { name: "gate-sulong-gcc_fortran-jdk-latest-linux-amd64" }, - sc.weekly + $.sulong + sc.labsjdkLatest + sc.linux_amd64 + sc.llvm4 + sc.requireGMP + sc.requireGCC + sc.gateTags(basicTags) + { name: "weekly-sulong-basic-nwcc-llvm-v40-jdk-latest-linux-amd64" }, - sc.weekly + $.sulong + sc.labsjdkLatest + sc.linux_amd64 + sc.llvm6 + sc.requireGMP + sc.requireGCC + sc.gateTags(basicTags) + { name: "weekly-sulong-basic-nwcc-llvm-v60-jdk-latest-linux-amd64" }, - sc.weekly + $.sulong + sc.labsjdkLatest + sc.linux_amd64 + sc.llvm8 + sc.requireGMP + sc.requireGCC + sc.gateTags(basicTags) + { name: "weekly-sulong-basic-nwcc-llvm-v80-jdk-latest-linux-amd64" }, - - sc.weekly + $.sulong + sc.labsjdkLatest + sc.darwin_amd64 + sc.llvm4 + sc.gateTags(basicTags) + { name: "weekly-sulong-basic-nwcc-llvm-v40-jdk-latest-darwin-amd64", timelimit: "0:45:00" }, sc.gate + $.sulong + sc.labsjdkLatest + sc.darwin_amd64 + sc.llvmBundled + sc.gateTags(basicTags) + { name: "gate-sulong-basic-nwcc-llvm-jdk-latest-darwin-amd64", timelimit: "0:45:00", capabilities+: ["ram16gb"] }, sc.gate + $.sulong + sc.labsjdkLatest + sc.linux_amd64 + sc.llvmBundled + sc.requireGMP + sc.requireGCC + sc.gateTags(basicTags) + { name: "gate-sulong-basic-nwcc-llvm-jdk-latest-linux-amd64" }, diff --git a/sulong/ci/ci_common/sulong-common.jsonnet b/sulong/ci/ci_common/sulong-common.jsonnet index bef5b36e1924..c335c3c472dc 100644 --- a/sulong/ci/ci_common/sulong-common.jsonnet +++ b/sulong/ci/ci_common/sulong-common.jsonnet @@ -182,60 +182,6 @@ local sulong_deps = common.deps.sulong; }, }, - - llvm38:: $.sulong_gateTest_default_tools { - packages+: { - llvm: "==3.8", - }, - environment+: { - NO_FEMBED_BITCODE: "true", - CLANG_CC: "clang-3.8", - CLANG_CXX: "clang-3.8 --driver-mode=g++", - CLANG_LLVM_OBJCOPY: "objcopy", - CLANG_LLVM_CONFIG: "llvm-config", - CLANG_NO_OPTNONE: "1", - CFLAGS: "-Wno-error", - }, - }, - - llvm4:: $.sulong_gateTest_default_tools { - bitcode_config +:: ["v40"], - packages+: { - llvm: "==4.0.1", - }, - environment+: { - CLANG_CC: "clang-4.0", - CLANG_CXX: "clang-4.0 --driver-mode=g++", - CLANG_LLVM_OBJCOPY: "objcopy", - CLANG_NO_OPTNONE: "1", - CFLAGS: "-Wno-error", - }, - }, - - llvm6:: $.sulong_gateTest_default_tools { - bitcode_config +:: ["v60"], - packages+: { - llvm: "==6.0.1", - }, - environment+: { - CLANG_CC: "clang-6.0", - CLANG_CXX: "clang-6.0 --driver-mode=g++", - CFLAGS: "-Wno-error", - }, - }, - - llvm8: $.sulong_gateTest_default_tools { - bitcode_config +:: ["v80"], - packages+: { - llvm: "==8.0.0", - }, - environment+: { - CLANG_CC: "clang-8", - CLANG_CXX: "clang-8 --driver-mode=g++", - CFLAGS: "-Wno-error", - }, - }, - llvmBundled:: {}, requireGCC:: { From 5d8f344325109d5050313103805c4740de83cb49 Mon Sep 17 00:00:00 2001 From: Loic Ottet Date: Thu, 18 Jan 2024 11:09:40 +0100 Subject: [PATCH 586/593] Register Class.forName substituions as caller-sensitive --- .../src/com/oracle/svm/core/hub/DynamicHub.java | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/hub/DynamicHub.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/hub/DynamicHub.java index 83de69f9fe13..c79385444b7a 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/hub/DynamicHub.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/hub/DynamicHub.java @@ -125,6 +125,7 @@ import jdk.internal.access.JavaLangReflectAccess; import jdk.internal.misc.Unsafe; import jdk.internal.reflect.CallerSensitive; +import jdk.internal.reflect.CallerSensitiveAdapter; import jdk.internal.reflect.FieldAccessor; import jdk.internal.reflect.Reflection; import jdk.internal.reflect.ReflectionFactory; @@ -1345,24 +1346,28 @@ private static Constructor[] copyConstructors(Constructor[] original) { @Substitute @Platforms(InternalPlatform.NATIVE_ONLY.class) + @CallerSensitive private static Class forName(String className) throws Throwable { return forName(className, Reflection.getCallerClass()); } @Substitute @Platforms(InternalPlatform.NATIVE_ONLY.class) + @CallerSensitiveAdapter private static Class forName(String className, Class caller) throws Throwable { return forName(className, true, caller.getClassLoader(), caller); } @Substitute @Platforms(InternalPlatform.NATIVE_ONLY.class) + @CallerSensitive private static Class forName(Module module, String className) throws Throwable { return forName(module, className, Reflection.getCallerClass()); } @Substitute @Platforms(InternalPlatform.NATIVE_ONLY.class) + @CallerSensitiveAdapter private static Class forName(@SuppressWarnings("unused") Module module, String className, Class caller) throws Throwable { /* * The module system is not supported for now, therefore the module parameter is ignored and @@ -1376,11 +1381,13 @@ private static Class forName(@SuppressWarnings("unused") Module module, Strin } @Substitute + @CallerSensitive private static Class forName(String name, boolean initialize, ClassLoader loader) throws Throwable { return forName(name, initialize, loader, Reflection.getCallerClass()); } @Substitute + @CallerSensitiveAdapter private static Class forName(String name, boolean initialize, ClassLoader loader, @SuppressWarnings("unused") Class caller) throws Throwable { if (name == null) { throw new NullPointerException(); From 02a02c5395caf218040bcb58a05100de1fa644eb Mon Sep 17 00:00:00 2001 From: Olya Gupalo Date: Wed, 25 Oct 2023 13:47:01 +0200 Subject: [PATCH 587/593] Update overlay import. --- graal-common.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/graal-common.json b/graal-common.json index c1c0a6470476..15cd90545818 100644 --- a/graal-common.json +++ b/graal-common.json @@ -1,6 +1,6 @@ { "README": "This file contains definitions that are useful for the jsonnet CI files of the graal and graal-enterprise repositories.", "ci": { - "overlay": "ad801a5f7147561be19dd164003600bd31a43075" + "overlay": "d8a5237997a4baf1710059843cd32f4b238c9849" } } From 3010d75f0741ff049e6dbc18dd47e5e463a4b2f7 Mon Sep 17 00:00:00 2001 From: Tom Shull Date: Mon, 22 Jan 2024 16:29:21 +0100 Subject: [PATCH 588/593] Make calltrace calculation more resilient to null values. --- .../svm/graal/hosted/runtimecompilation/CallTreeInfo.java | 2 +- .../runtimecompilation/RuntimeCompilationFeature.java | 6 ------ 2 files changed, 1 insertion(+), 7 deletions(-) diff --git a/substratevm/src/com.oracle.svm.graal/src/com/oracle/svm/graal/hosted/runtimecompilation/CallTreeInfo.java b/substratevm/src/com.oracle.svm.graal/src/com/oracle/svm/graal/hosted/runtimecompilation/CallTreeInfo.java index d333ad27fd38..55a4eccfe4ba 100644 --- a/substratevm/src/com.oracle.svm.graal/src/com/oracle/svm/graal/hosted/runtimecompilation/CallTreeInfo.java +++ b/substratevm/src/com.oracle.svm.graal/src/com/oracle/svm/graal/hosted/runtimecompilation/CallTreeInfo.java @@ -162,7 +162,7 @@ public void initialize(Set registeredRoots) { for (AnalysisMethod callee : invokeInfo.getAllCallees()) { if (SubstrateCompilationDirectives.isRuntimeCompiledMethod(callee)) { MethodNode calleeMethodNode = analysisMethodMap.get(callee); - if (calleeMethodNode.trace == null) { + if (calleeMethodNode != null && calleeMethodNode.trace == null) { /* * If this was the first time this node was reached, then add to * worklist. diff --git a/substratevm/src/com.oracle.svm.graal/src/com/oracle/svm/graal/hosted/runtimecompilation/RuntimeCompilationFeature.java b/substratevm/src/com.oracle.svm.graal/src/com/oracle/svm/graal/hosted/runtimecompilation/RuntimeCompilationFeature.java index 70a51fd40054..5bf2b9f3abc8 100644 --- a/substratevm/src/com.oracle.svm.graal/src/com/oracle/svm/graal/hosted/runtimecompilation/RuntimeCompilationFeature.java +++ b/substratevm/src/com.oracle.svm.graal/src/com/oracle/svm/graal/hosted/runtimecompilation/RuntimeCompilationFeature.java @@ -568,13 +568,11 @@ public void reportAnalysisError(AnalysisUniverse aUniverse, Throwable t) { checkMaxRuntimeCompiledMethods(treeInfo); - boolean foundError = false; if (t instanceof ParallelExecutionException exception) { for (var e : exception.getExceptions()) { if (e instanceof AnalysisError.ParsingError parsingError) { AnalysisMethod errorMethod = parsingError.getMethod(); if (errorMethod.isDeoptTarget() || SubstrateCompilationDirectives.isRuntimeCompiledMethod(errorMethod)) { - foundError = true; AnalysisMethod failingRuntimeMethod = null; if (SubstrateCompilationDirectives.isRuntimeCompiledMethod(errorMethod)) { failingRuntimeMethod = errorMethod; @@ -593,10 +591,6 @@ public void reportAnalysisError(AnalysisUniverse aUniverse, Throwable t) { } } } - - if (foundError) { - throw VMError.shouldNotReachHere("Analysis failed while parsing deopt and/or runtime methods"); - } } private class RuntimeCompilationParsingSupport implements SVMParsingSupport { From 28ef7e1683e354b07532e997e3fcd895f8d15442 Mon Sep 17 00:00:00 2001 From: Tom Rodriguez Date: Mon, 22 Jan 2024 10:23:13 -0800 Subject: [PATCH 589/593] Fix comment --- .../jdk/graal/compiler/core/test/TestGraphBuilderPhase.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/core/test/TestGraphBuilderPhase.java b/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/core/test/TestGraphBuilderPhase.java index 86ca81ae2a47..4e4fa738e527 100644 --- a/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/core/test/TestGraphBuilderPhase.java +++ b/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/core/test/TestGraphBuilderPhase.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2023, 2024, 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 @@ -65,7 +65,7 @@ protected BytecodeParser createBytecodeParser(StructuredGraph graph, BytecodePar } /** - * A non-abstract subclass of {@link BytecodeParser} + * A non-abstract subclass of {@link BytecodeParser} for testing purposes. */ static class DefaultBytecodeParser extends BytecodeParser { protected DefaultBytecodeParser(GraphBuilderPhase.Instance graphBuilderInstance, StructuredGraph graph, BytecodeParser parent, ResolvedJavaMethod method, int entryBCI, From a66ad4600f408b968c3df3457ad6f128d18a7116 Mon Sep 17 00:00:00 2001 From: Tom Rodriguez Date: Mon, 22 Jan 2024 11:25:22 -0800 Subject: [PATCH 590/593] Style fix --- .../jdk/graal/compiler/core/test/TestGraphBuilderPhase.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/core/test/TestGraphBuilderPhase.java b/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/core/test/TestGraphBuilderPhase.java index 4e4fa738e527..03d67950e2ba 100644 --- a/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/core/test/TestGraphBuilderPhase.java +++ b/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/core/test/TestGraphBuilderPhase.java @@ -60,15 +60,15 @@ public Instance(CoreProviders providers, GraphBuilderConfiguration graphBuilderC @Override protected BytecodeParser createBytecodeParser(StructuredGraph graph, BytecodeParser parent, ResolvedJavaMethod method, int entryBCI, IntrinsicContext intrinsicContext) { - return new DefaultBytecodeParser(this, graph, parent, method, entryBCI, intrinsicContext); + return new TestBytecodeParser(this, graph, parent, method, entryBCI, intrinsicContext); } } /** * A non-abstract subclass of {@link BytecodeParser} for testing purposes. */ - static class DefaultBytecodeParser extends BytecodeParser { - protected DefaultBytecodeParser(GraphBuilderPhase.Instance graphBuilderInstance, StructuredGraph graph, BytecodeParser parent, ResolvedJavaMethod method, int entryBCI, + static class TestBytecodeParser extends BytecodeParser { + protected TestBytecodeParser(GraphBuilderPhase.Instance graphBuilderInstance, StructuredGraph graph, BytecodeParser parent, ResolvedJavaMethod method, int entryBCI, IntrinsicContext intrinsicContext) { super(graphBuilderInstance, graph, parent, method, entryBCI, intrinsicContext); } From 433b90a318293d446cb913ce1c59d77721c16f98 Mon Sep 17 00:00:00 2001 From: Tomas Zezula Date: Mon, 22 Jan 2024 09:53:09 +0100 Subject: [PATCH 591/593] [GR-51529] FileSystemsTest#testSetAttribute() fails on JDK-23-linux. --- .../api/test/polyglot/FileSystemsTest.java | 24 +++++++++++++++---- 1 file changed, 20 insertions(+), 4 deletions(-) diff --git a/truffle/src/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/polyglot/FileSystemsTest.java b/truffle/src/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/polyglot/FileSystemsTest.java index 32adfe0011b4..c7fd137dbe37 100644 --- a/truffle/src/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/polyglot/FileSystemsTest.java +++ b/truffle/src/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/polyglot/FileSystemsTest.java @@ -2044,7 +2044,7 @@ public void testSetAttribute() throws IOException { boolean canRead = cfg.canRead(); boolean canWrite = cfg.canWrite(); AbstractExecutableTestLanguage.evalTestLanguage(ctx, TestSetAttributeLanguage.class, "", configuration, path, usePublicFile, canRead, canWrite, supportsUnixAttributes(), - supportsSetLastAccessTime()); + supportsSetLastAccessTime(), supportsSetCreationTime()); } @Registration @@ -2059,6 +2059,7 @@ protected Object execute(RootNode node, Env env, Object[] contextArguments, Obje boolean canWrite = (boolean) contextArguments[4]; boolean supportsUnixAttributes = (boolean) contextArguments[5]; boolean supportsSetLastAccessTime = (boolean) contextArguments[6]; + boolean supportsSetCreationTime = (boolean) contextArguments[7]; TruffleFile root = resolve(env, usePublicFile, path); try { TruffleFile file = root.resolve(FILE_CHANGE_ATTRS); @@ -2067,14 +2068,18 @@ protected Object execute(RootNode node, Env env, Object[] contextArguments, Obje Assert.assertTrue(formatErrorMessage("Expected SecurityException", configurationName, path), canWrite); Assert.assertEquals(time, file.getAttribute(TruffleFile.LAST_MODIFIED_TIME)); Assert.assertTrue(formatErrorMessage("Expected SecurityException", configurationName, path), canRead); + file.setAttribute(TruffleFile.LAST_ACCESS_TIME, time); + FileTime lastAccessTime = file.getAttribute(TruffleFile.LAST_ACCESS_TIME); // Workaround for issue JDK-8298187: The file last access time does not work on // JDK-20 on macOS with the hfs file system. if (supportsSetLastAccessTime) { - file.setAttribute(TruffleFile.LAST_ACCESS_TIME, time); - Assert.assertEquals(time, file.getAttribute(TruffleFile.LAST_ACCESS_TIME)); + Assert.assertEquals(time, lastAccessTime); } file.setAttribute(TruffleFile.CREATION_TIME, time); - Assert.assertEquals(time, file.getAttribute(TruffleFile.CREATION_TIME)); + FileTime creationTime = file.getAttribute(TruffleFile.CREATION_TIME); + if (supportsSetCreationTime) { + Assert.assertEquals(time, creationTime); + } file.setAttribute(TruffleFile.UNIX_PERMISSIONS, EnumSet.of(PosixFilePermission.OWNER_READ)); Assert.assertEquals(EnumSet.of(PosixFilePermission.OWNER_READ), file.getAttribute(TruffleFile.UNIX_PERMISSIONS)); file.setAttribute(TruffleFile.UNIX_PERMISSIONS, EnumSet.of(PosixFilePermission.OWNER_READ)); @@ -2106,6 +2111,17 @@ private boolean supportsSetLastAccessTime() throws IOException { return true; } + /** + * Returns {@code true} if the operating system supports file creation time modification. Note: + * Posix does not support setting a file's creation time directly. MacOS and BSD Unix, however, + * provide an additional system call {@code fsetattrlist} utilized by Java NIO to set the + * creation time. On Linux, the Posix functions {@code utimes}, {@code futimens}, or + * {@code utimensat} are employed, allowing modification only of access and modification times. + */ + private static boolean supportsSetCreationTime() { + return OSUtils.isWindows() || OSUtils.getCurrent() == OSUtils.OS.Darwin; + } + @Test public void testGetAttributes() throws IOException { Context ctx = cfg.getContext(); From 06fb0c60e6255e72c7ab4f5ddf02d21dc339ecb9 Mon Sep 17 00:00:00 2001 From: Boris Spasojevic Date: Wed, 24 Jan 2024 11:04:55 +0100 Subject: [PATCH 592/593] Multi line comments and simpler conditional checks. --- .../tools/coverage/impl/CoverageInstrument.java | 15 ++++++++------- .../tools/profiler/impl/CPUSamplerInstrument.java | 13 +++++++------ .../truffle/tools/profiler/impl/CPUTracerCLI.java | 2 +- .../tools/profiler/impl/CPUTracerInstrument.java | 13 +++++++------ 4 files changed, 23 insertions(+), 20 deletions(-) diff --git a/tools/src/com.oracle.truffle.tools.coverage/src/com/oracle/truffle/tools/coverage/impl/CoverageInstrument.java b/tools/src/com.oracle.truffle.tools.coverage/src/com/oracle/truffle/tools/coverage/impl/CoverageInstrument.java index 33222654376b..7063264ce371 100644 --- a/tools/src/com.oracle.truffle.tools.coverage/src/com/oracle/truffle/tools/coverage/impl/CoverageInstrument.java +++ b/tools/src/com.oracle.truffle.tools.coverage/src/com/oracle/truffle/tools/coverage/impl/CoverageInstrument.java @@ -108,12 +108,13 @@ public Output apply(String s) { private CoverageTracker tracker; private Boolean enabled; - // Guest languages could change the working directory of the current process, - // The JVM assumes that the working directory does not change. - // When this assumption is broken relative file paths no longer work correctly. - // For this reason we save the absolute path to the output file at the very start so that we - // avoid issues of broken relative paths - // See GR-36526 for more context. + /* + * Guest languages could change the working directory of the current process, The JVM assumes + * that the working directory does not change. When this assumption is broken relative file + * paths no longer work correctly. For this reason we save the absolute path to the output file + * at the very start so that we avoid issues of broken relative paths See GR-36526 for more + * context. + */ private String absoluteOutputPath; public static CoverageTracker getTracker(Engine engine) { @@ -133,7 +134,7 @@ public static void setFactory(Function factory) { protected static PrintStream chooseOutputStream(Env env, String absoluteOutputPath) { try { - if (CoverageInstrument.OUTPUT_FILE.hasBeenSet(env.getOptions())) { + if (absoluteOutputPath != null) { final File file = new File(absoluteOutputPath); new PrintStream(env.out()).println("Printing output to " + file.getAbsolutePath()); return new PrintStream(new FileOutputStream(file)); diff --git a/tools/src/com.oracle.truffle.tools.profiler/src/com/oracle/truffle/tools/profiler/impl/CPUSamplerInstrument.java b/tools/src/com.oracle.truffle.tools.profiler/src/com/oracle/truffle/tools/profiler/impl/CPUSamplerInstrument.java index 20e85fb2fce3..e34bb21da328 100644 --- a/tools/src/com.oracle.truffle.tools.profiler/src/com/oracle/truffle/tools/profiler/impl/CPUSamplerInstrument.java +++ b/tools/src/com.oracle.truffle.tools.profiler/src/com/oracle/truffle/tools/profiler/impl/CPUSamplerInstrument.java @@ -66,12 +66,13 @@ public CPUSamplerInstrument() { static final String VERSION = "0.5.0"; private CPUSampler sampler; - // Guest languages could change the working directory of the current process, - // The JVM assumes that the working directory does not change. - // When this assumption is broken relative file paths no longer work correctly. - // For this reason we save the absolute path to the output file at the very start so that we - // avoid issues of broken relative paths - // See GR-36526 for more context. + /* + * Guest languages could change the working directory of the current process, The JVM assumes + * that the working directory does not change. When this assumption is broken relative file + * paths no longer work correctly. For this reason we save the absolute path to the output file + * at the very start so that we avoid issues of broken relative paths See GR-36526 for more + * context. + */ private String absoluteOutputPath; @SuppressWarnings("unchecked") diff --git a/tools/src/com.oracle.truffle.tools.profiler/src/com/oracle/truffle/tools/profiler/impl/CPUTracerCLI.java b/tools/src/com.oracle.truffle.tools.profiler/src/com/oracle/truffle/tools/profiler/impl/CPUTracerCLI.java index ad5f0291cd0f..e4f5c57ba26e 100644 --- a/tools/src/com.oracle.truffle.tools.profiler/src/com/oracle/truffle/tools/profiler/impl/CPUTracerCLI.java +++ b/tools/src/com.oracle.truffle.tools.profiler/src/com/oracle/truffle/tools/profiler/impl/CPUTracerCLI.java @@ -118,7 +118,7 @@ public static void handleOutput(TruffleInstrument.Env env, CPUTracer tracer, Str protected static PrintStream chooseOutputStream(TruffleInstrument.Env env, String absoluteOutputPath) { try { - if (CPUTracerCLI.OUTPUT_FILE.hasBeenSet(env.getOptions())) { + if (absoluteOutputPath != null) { final File file = new File(absoluteOutputPath); return new PrintStream(new FileOutputStream(file)); } else { diff --git a/tools/src/com.oracle.truffle.tools.profiler/src/com/oracle/truffle/tools/profiler/impl/CPUTracerInstrument.java b/tools/src/com.oracle.truffle.tools.profiler/src/com/oracle/truffle/tools/profiler/impl/CPUTracerInstrument.java index b42b975e3327..9205593b0179 100644 --- a/tools/src/com.oracle.truffle.tools.profiler/src/com/oracle/truffle/tools/profiler/impl/CPUTracerInstrument.java +++ b/tools/src/com.oracle.truffle.tools.profiler/src/com/oracle/truffle/tools/profiler/impl/CPUTracerInstrument.java @@ -64,12 +64,13 @@ public CPUTracerInstrument() { static final String VERSION = "0.3.0"; private boolean enabled; private CPUTracer tracer; - // Guest languages could change the working directory of the current process, - // The JVM assumes that the working directory does not change. - // When this assumption is broken relative file paths no longer work correctly. - // For this reason we save the absolute path to the output file at the very start so that we - // avoid issues of broken relative paths - // See GR-36526 for more context. + /* + * Guest languages could change the working directory of the current process, The JVM assumes + * that the working directory does not change. When this assumption is broken relative file + * paths no longer work correctly. For this reason we save the absolute path to the output file + * at the very start so that we avoid issues of broken relative paths See GR-36526 for more + * context. + */ String absoluteOutputPath; @SuppressWarnings("unchecked") From 8db3d5ae6544e8fce2da73385967ba4a5d7ef219 Mon Sep 17 00:00:00 2001 From: Benoit Daloze Date: Wed, 24 Jan 2024 11:44:12 +0100 Subject: [PATCH 593/593] Update truffleruby import in vm --- vm/mx.vm/suite.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vm/mx.vm/suite.py b/vm/mx.vm/suite.py index 8c5b8a8ea02b..543421abace0 100644 --- a/vm/mx.vm/suite.py +++ b/vm/mx.vm/suite.py @@ -49,7 +49,7 @@ }, { "name": "truffleruby", - "version": "7100f1cb4ca008aadbc394c617a4d64fa767e073", + "version": "eedda8504b30bd7e023d6d4aba1a49530985cb2e", "dynamic": True, "urls": [ {"url": "https://github.com/oracle/truffleruby.git", "kind": "git"},