diff --git a/ci/ci_common/common.jsonnet b/ci/ci_common/common.jsonnet index 13c5ad1b7515..4d4aad12589c 100644 --- a/ci/ci_common/common.jsonnet +++ b/ci/ci_common/common.jsonnet @@ -6,7 +6,7 @@ local repo_config = import '../repo-configuration.libsonnet'; common + common.frequencies + { build_base:: { // holds location of CI resources that can easily be overwritten in an overlay - ci_resources:: (import "ci/ci_common/ci-resources.libsonnet"), + ci_resources:: (import "ci-resources.libsonnet"), }, # Add a guard to `build` that prevents it from running in the gate diff --git a/substratevm/ci/ci_common/include.libsonnet b/ci/ci_common/musl-common.libsonnet similarity index 100% rename from substratevm/ci/ci_common/include.libsonnet rename to ci/ci_common/musl-common.libsonnet diff --git a/common.json b/common.json index 5ab6f36d00f2..09caa721d5c1 100644 --- a/common.json +++ b/common.json @@ -4,19 +4,19 @@ "Jsonnet files should not include this file directly but use ci/common.jsonnet instead." ], - "mx_version": "6.17.0", + "mx_version": "6.18.0", "COMMENT.jdks": "When adding or removing JDKs keep in sync with JDKs in ci/common.jsonnet", "jdks": { "oraclejdk11": {"name": "jpg-jdk", "version": "11.0.11", "build_id": "9", "release": true, "platformspecific": true, "extrabundles": ["static-libs"] }, "oraclejdk17": {"name": "jpg-jdk", "version": "17.0.1", "build_id": "12", "release": true, "platformspecific": true, "extrabundles": ["static-libs"]}, - "labsjdk-ce-17": {"name": "labsjdk", "version": "ce-17.0.7+4-jvmci-23.0-b09", "platformspecific": true }, - "labsjdk-ce-17Debug": {"name": "labsjdk", "version": "ce-17.0.7+4-jvmci-23.0-b09-debug", "platformspecific": true }, - "labsjdk-ce-17-llvm": {"name": "labsjdk", "version": "ce-17.0.7+4-jvmci-23.0-b09-sulong", "platformspecific": true }, - "labsjdk-ee-17": {"name": "labsjdk", "version": "ee-17.0.7+8-jvmci-23.0-b09", "platformspecific": true }, - "labsjdk-ee-17Debug": {"name": "labsjdk", "version": "ee-17.0.7+8-jvmci-23.0-b09-debug", "platformspecific": true }, - "labsjdk-ee-17-llvm": {"name": "labsjdk", "version": "ee-17.0.7+8-jvmci-23.0-b09-sulong", "platformspecific": true }, + "labsjdk-ce-17": {"name": "labsjdk", "version": "ce-17.0.7+4-jvmci-23.0-b10", "platformspecific": true }, + "labsjdk-ce-17Debug": {"name": "labsjdk", "version": "ce-17.0.7+4-jvmci-23.0-b10-debug", "platformspecific": true }, + "labsjdk-ce-17-llvm": {"name": "labsjdk", "version": "ce-17.0.7+4-jvmci-23.0-b10-sulong", "platformspecific": true }, + "labsjdk-ee-17": {"name": "labsjdk", "version": "ee-17.0.7+8-jvmci-23.0-b10", "platformspecific": true }, + "labsjdk-ee-17Debug": {"name": "labsjdk", "version": "ee-17.0.7+8-jvmci-23.0-b10-debug", "platformspecific": true }, + "labsjdk-ee-17-llvm": {"name": "labsjdk", "version": "ee-17.0.7+8-jvmci-23.0-b10-sulong", "platformspecific": true }, "oraclejdk19": {"name": "jpg-jdk", "version": "19", "build_id": "26", "release": true, "platformspecific": true, "extrabundles": ["static-libs"]}, "labsjdk-ce-19": {"name": "labsjdk", "version": "ce-19.0.1+10-jvmci-23.0-b04", "platformspecific": true }, @@ -27,12 +27,12 @@ "labsjdk-ee-19-llvm": {"name": "labsjdk", "version": "ee-19.0.2+7-jvmci-23.0-b05-sulong", "platformspecific": true }, "oraclejdk20": {"name": "jpg-jdk", "version": "20", "build_id": "24", "release": true, "platformspecific": true, "extrabundles": ["static-libs"]}, - "labsjdk-ce-20": {"name": "labsjdk", "version": "ce-20+34-jvmci-23.0-b09", "platformspecific": true }, - "labsjdk-ce-20Debug": {"name": "labsjdk", "version": "ce-20+34-jvmci-23.0-b09-debug", "platformspecific": true }, - "labsjdk-ce-20-llvm": {"name": "labsjdk", "version": "ce-20+34-jvmci-23.0-b09-sulong", "platformspecific": true }, - "labsjdk-ee-20": {"name": "labsjdk", "version": "ee-20.0.1+8-jvmci-23.0-b09", "platformspecific": true }, - "labsjdk-ee-20Debug": {"name": "labsjdk", "version": "ee-20.0.1+8-jvmci-23.0-b09-debug", "platformspecific": true }, - "labsjdk-ee-20-llvm": {"name": "labsjdk", "version": "ee-20.0.1+8-jvmci-23.0-b09-sulong", "platformspecific": true } + "labsjdk-ce-20": {"name": "labsjdk", "version": "ce-20+34-jvmci-23.0-b10", "platformspecific": true }, + "labsjdk-ce-20Debug": {"name": "labsjdk", "version": "ce-20+34-jvmci-23.0-b10-debug", "platformspecific": true }, + "labsjdk-ce-20-llvm": {"name": "labsjdk", "version": "ce-20+34-jvmci-23.0-b10-sulong", "platformspecific": true }, + "labsjdk-ee-20": {"name": "labsjdk", "version": "ee-20.0.1+9-jvmci-23.0-b10", "platformspecific": true }, + "labsjdk-ee-20Debug": {"name": "labsjdk", "version": "ee-20.0.1+9-jvmci-23.0-b10-debug", "platformspecific": true }, + "labsjdk-ee-20-llvm": {"name": "labsjdk", "version": "ee-20.0.1+9-jvmci-23.0-b10-sulong", "platformspecific": true } }, "eclipse": { diff --git a/compiler/mx.compiler/mx_compiler.py b/compiler/mx.compiler/mx_compiler.py index 760caf4ee56e..38d608d69e44 100644 --- a/compiler/mx.compiler/mx_compiler.py +++ b/compiler/mx.compiler/mx_compiler.py @@ -632,6 +632,10 @@ def compiler_gate_benchmark_runner(tasks, extraVMarguments=None, prefix='', task with Task(prefix + 'DaCapo_pmd:PreserveFramePointer', tasks, tags=GraalTags.test, report=task_report_component) as t: if t: _gate_dacapo('pmd', default_iterations, benchVmArgs + ['-Xmx256M', '-XX:+PreserveFramePointer'], threads=4, force_serial_gc=False, set_start_heap_size=False) + # stress entry barrier deopt + with Task(prefix + 'DaCapo_pmd:DeoptimizeNMethodBarriersALot', tasks, tags=GraalTags.test, report=task_report_component) as t: + if t: _gate_dacapo('pmd', default_iterations, benchVmArgs + ['-Xmx256M', '-XX:+UnlockDiagnosticVMOptions', '-XX:+DeoptimizeNMethodBarriersALot'], threads=4, force_serial_gc=False, set_start_heap_size=False) + graal_unit_test_runs = [ UnitTestRun('UnitTests', [], tags=GraalTags.unittest + GraalTags.coverage), ] diff --git a/compiler/mx.compiler/suite.py b/compiler/mx.compiler/suite.py index bfcd0a688fb2..5f96e76328a3 100644 --- a/compiler/mx.compiler/suite.py +++ b/compiler/mx.compiler/suite.py @@ -4,7 +4,7 @@ "sourceinprojectwhitelist" : [], "groupId" : "org.graalvm.compiler", - "version" : "23.0.0", + "version" : "23.1.0", "release" : False, "url" : "http://www.graalvm.org/", "developer" : { @@ -24,9 +24,6 @@ { "name" : "truffle", "subdir": True, - "urls" : [ - {"url" : "https://curio.ssw.jku.at/nexus/content/repositories/snapshots", "kind" : "binary"}, - ] }, { "name" : "regex", diff --git a/compiler/src/org.graalvm.compiler.asm.aarch64.test/src/org/graalvm/compiler/asm/aarch64/test/TestProtectedAssembler.java b/compiler/src/org.graalvm.compiler.asm.aarch64.test/src/org/graalvm/compiler/asm/aarch64/test/TestProtectedAssembler.java index 5351b71f0f6e..9f468ac39808 100644 --- a/compiler/src/org.graalvm.compiler.asm.aarch64.test/src/org/graalvm/compiler/asm/aarch64/test/TestProtectedAssembler.java +++ b/compiler/src/org.graalvm.compiler.asm.aarch64.test/src/org/graalvm/compiler/asm/aarch64/test/TestProtectedAssembler.java @@ -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 @@ -195,11 +195,6 @@ protected void hlt(int uimm16) { super.hlt(uimm16); } - @Override - protected void brk(int uimm16) { - super.brk(uimm16); - } - @Override protected void hint(SystemHint hint) { super.hint(hint); diff --git a/compiler/src/org.graalvm.compiler.asm.aarch64/src/org/graalvm/compiler/asm/aarch64/AArch64Assembler.java b/compiler/src/org.graalvm.compiler.asm.aarch64/src/org/graalvm/compiler/asm/aarch64/AArch64Assembler.java index 3e47e1596f5a..ef70b2a1f9e3 100644 --- a/compiler/src/org.graalvm.compiler.asm.aarch64/src/org/graalvm/compiler/asm/aarch64/AArch64Assembler.java +++ b/compiler/src/org.graalvm.compiler.asm.aarch64/src/org/graalvm/compiler/asm/aarch64/AArch64Assembler.java @@ -3864,7 +3864,7 @@ protected void hlt(int uimm16) { * * @param uimm16 Arbitrary 16-bit unsigned payload. */ - protected void brk(int uimm16) { + public void brk(int uimm16) { exceptionInstruction(BRK, uimm16); } diff --git a/compiler/src/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/GraalOptions.java b/compiler/src/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/GraalOptions.java index 0f12909a5a3e..e3ab40ecffa9 100644 --- a/compiler/src/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/GraalOptions.java +++ b/compiler/src/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/GraalOptions.java @@ -208,9 +208,6 @@ public final class GraalOptions { @Option(help = "", type = OptionType.Expert) public static final OptionKey AlwaysInlineVTableStubs = new OptionKey<>(false); - @Option(help = "", type = OptionType.Debug) - public static final OptionKey CanOmitFrame = new OptionKey<>(true); - // Runtime settings @Option(help = "", type = OptionType.Expert) public static final OptionKey SupportJsrBytecodes = new OptionKey<>(true); diff --git a/compiler/src/org.graalvm.compiler.core/src/org/graalvm/compiler/core/CompilationWrapper.java b/compiler/src/org.graalvm.compiler.core/src/org/graalvm/compiler/core/CompilationWrapper.java index 7f884029ae26..0e3bfe4eaea6 100644 --- a/compiler/src/org.graalvm.compiler.core/src/org/graalvm/compiler/core/CompilationWrapper.java +++ b/compiler/src/org.graalvm.compiler.core/src/org/graalvm/compiler/core/CompilationWrapper.java @@ -27,7 +27,7 @@ import static org.graalvm.compiler.core.CompilationWrapper.ExceptionAction.ExitVM; import static org.graalvm.compiler.core.GraalCompilerOptions.CompilationBailoutAsFailure; import static org.graalvm.compiler.core.GraalCompilerOptions.CompilationFailureAction; -import static org.graalvm.compiler.core.GraalCompilerOptions.ExitVMOnException; +import static org.graalvm.compiler.core.GraalCompilerOptions.ExitVMCompilationFailureRate; import static org.graalvm.compiler.core.GraalCompilerOptions.MaxCompilationProblemsPerAction; import static org.graalvm.compiler.core.common.GraalOptions.TrackNodeSourcePosition; import static org.graalvm.compiler.debug.DebugOptions.Dump; @@ -48,6 +48,7 @@ import org.graalvm.compiler.debug.PathUtilities; import org.graalvm.compiler.debug.TTY; import org.graalvm.compiler.options.OptionValues; +import org.graalvm.compiler.serviceprovider.GlobalAtomicLong; import org.graalvm.compiler.serviceprovider.GraalServices; import jdk.vm.ci.code.BailoutException; @@ -128,31 +129,24 @@ public CompilationWrapper(DiagnosticsOutputDirectory outputDirectory, Map COMPILATION_FAILURE_DETECTION_PERIOD_MS; + + // Wait for period to expire or some minimum amount of compilations + // before detecting systemic failure. + if (rate > maxRate && (periodExpired || total > MIN_COMPILATIONS_FOR_FAILURE_DETECTION)) { + TTY.printf("Warning: Systemic Graal compilation failure detected: %d of %d (%d%%) of compilations failed during last %d ms [max rate set by %s is %d%%]%n", + failed, total, rate, period, ExitVMCompilationFailureRate.getName(), maxRate); + return true; + } + + if (periodExpired) { + + if (compilationPeriodStart.compareAndSet(start, now)) { + // Reset compilation counters for new period + failedCompilations.set(0); + totalCompilations.set(0); + } + } + + return false; + } + /** * Adjusts {@code initialAction} if necessary based on * {@link GraalCompilerOptions#MaxCompilationProblemsPerAction}. */ - private ExceptionAction adjustAction(OptionValues initialOptions, ExceptionAction initialAction) { + private ExceptionAction adjustAction(OptionValues initialOptions, ExceptionAction initialAction, Throwable cause) { ExceptionAction action = initialAction; int maxProblems = MaxCompilationProblemsPerAction.getValue(initialOptions); if (action != ExceptionAction.ExitVM) { + if (isCompilationFailureRateTooHigh(initialOptions, cause)) { + return ExceptionAction.ExitVM; + } synchronized (problemsHandledPerAction) { while (action != ExceptionAction.Silent) { int problems = problemsHandledPerAction.getOrDefault(action, 0); diff --git a/compiler/src/org.graalvm.compiler.core/src/org/graalvm/compiler/core/GraalCompilerOptions.java b/compiler/src/org.graalvm.compiler.core/src/org/graalvm/compiler/core/GraalCompilerOptions.java index 46d8e5937618..6ebd46b4cb23 100644 --- a/compiler/src/org.graalvm.compiler.core/src/org/graalvm/compiler/core/GraalCompilerOptions.java +++ b/compiler/src/org.graalvm.compiler.core/src/org/graalvm/compiler/core/GraalCompilerOptions.java @@ -53,8 +53,10 @@ public class GraalCompilerOptions { "by CompilationFailureAction before changing to a less verbose action. " + "This does not apply to the ExitVM action.", type = OptionType.User) public static final OptionKey MaxCompilationProblemsPerAction = new OptionKey<>(2); - @Option(help = "Alias for CompilationFailureAction=ExitVM.", type = OptionType.User) - public static final OptionKey ExitVMOnException = new OptionKey<>(false); + @Option(help = "Compilation failure rate indicating a systemic compilation problem and causing the VM to exit. " + + "The value is the percent of compilations that failed during a sliding time window. " + + "Set to 0 to disable systemic compilation problem detection.", type = OptionType.User) + public static final OptionKey ExitVMCompilationFailureRate = new OptionKey<>(1); @Option(help = "The number of seconds by which to slow down each compilation. The compilations slowed down " + "can be restricted with MethodFilter. This option exists to test the compilation watchdog.", type = OptionType.Debug) public static final OptionKey InjectedCompilationDelay = new OptionKey<>(0); diff --git a/compiler/src/org.graalvm.compiler.core/src/org/graalvm/compiler/core/phases/CEOptimization.java b/compiler/src/org.graalvm.compiler.core/src/org/graalvm/compiler/core/phases/CEOptimization.java index aa2cff1b18d3..45a874e79d25 100644 --- a/compiler/src/org.graalvm.compiler.core/src/org/graalvm/compiler/core/phases/CEOptimization.java +++ b/compiler/src/org.graalvm.compiler.core/src/org/graalvm/compiler/core/phases/CEOptimization.java @@ -172,7 +172,7 @@ public enum CEOptimization { * This phase is enabled by default and can be disabled with * {@link GraalOptions#PartialEscapeAnalysis}. */ - PartialEscapeAnanylsis(GraalOptions.PartialEscapeAnalysis, PartialEscapePhase.class), + PartialEscapeAnalysis(GraalOptions.PartialEscapeAnalysis, PartialEscapePhase.class), /** * {@link LockEliminationPhase} tries to reduce Java monitor enter/exit overhead of an diff --git a/compiler/src/org.graalvm.compiler.graph.test/src/org/graalvm/compiler/graph/test/NodeUsagesTests.java b/compiler/src/org.graalvm.compiler.graph.test/src/org/graalvm/compiler/graph/test/NodeUsagesTests.java index 595813d4f6b4..f313953a3fa2 100644 --- a/compiler/src/org.graalvm.compiler.graph.test/src/org/graalvm/compiler/graph/test/NodeUsagesTests.java +++ b/compiler/src/org.graalvm.compiler.graph.test/src/org/graalvm/compiler/graph/test/NodeUsagesTests.java @@ -484,13 +484,14 @@ public void testGraphVerify() { graph.add(new TestVerifyNode(b)); graph.verify(); + Object booleanTrue = Boolean.TRUE; for (Position p : a.successorPositions()) { Assert.assertEquals(p.hashCode(), p.hashCode()); Assert.assertTrue(p.equals(p)); Assert.assertFalse(p.equals(null)); - Assert.assertFalse(p.equals(Boolean.TRUE)); + Assert.assertFalse(p.equals(booleanTrue)); Assert.assertFalse(p.equals(new Position(null, p.getIndex(), p.getSubIndex()))); Assert.assertFalse(p.equals(new Position(null, p.getIndex() + 1, p.getSubIndex()))); diff --git a/compiler/src/org.graalvm.compiler.hotspot.aarch64/src/org/graalvm/compiler/hotspot/aarch64/AArch64HotSpotBackend.java b/compiler/src/org.graalvm.compiler.hotspot.aarch64/src/org/graalvm/compiler/hotspot/aarch64/AArch64HotSpotBackend.java index e0a38e7e62c7..f185ef770712 100644 --- a/compiler/src/org.graalvm.compiler.hotspot.aarch64/src/org/graalvm/compiler/hotspot/aarch64/AArch64HotSpotBackend.java +++ b/compiler/src/org.graalvm.compiler.hotspot.aarch64/src/org/graalvm/compiler/hotspot/aarch64/AArch64HotSpotBackend.java @@ -315,11 +315,6 @@ public void returned(CompilationResultBuilder crb) { // nothing to do } - @Override - public boolean hasFrame() { - return true; - } - } @Override diff --git a/compiler/src/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64HotSpotBackend.java b/compiler/src/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64HotSpotBackend.java index cbaa5bed6f48..1ca870febe2d 100644 --- a/compiler/src/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64HotSpotBackend.java +++ b/compiler/src/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64HotSpotBackend.java @@ -29,7 +29,6 @@ import static jdk.vm.ci.amd64.AMD64.rbp; import static jdk.vm.ci.amd64.AMD64.rsp; import static jdk.vm.ci.code.ValueUtil.asRegister; -import static org.graalvm.compiler.core.common.GraalOptions.CanOmitFrame; import static org.graalvm.compiler.core.common.GraalOptions.ZapStackOnMethodEntry; import static org.graalvm.compiler.hotspot.meta.HotSpotHostForeignCallsProvider.NMETHOD_ENTRY_BARRIER; @@ -59,7 +58,6 @@ import org.graalvm.compiler.lir.LIR; import org.graalvm.compiler.lir.amd64.AMD64Call; import org.graalvm.compiler.lir.amd64.AMD64FrameMap; -import org.graalvm.compiler.lir.amd64.AMD64FrameMapBuilder; import org.graalvm.compiler.lir.asm.CompilationResultBuilder; import org.graalvm.compiler.lir.asm.CompilationResultBuilderFactory; import org.graalvm.compiler.lir.asm.DataBuilder; @@ -96,8 +94,8 @@ public AMD64HotSpotBackend(GraalHotSpotVMConfig config, HotSpotGraalRuntimeProvi @Override protected FrameMapBuilder newFrameMapBuilder(RegisterConfig registerConfig) { RegisterConfig registerConfigNonNull = registerConfig == null ? getCodeCache().getRegisterConfig() : registerConfig; - FrameMap frameMap = new AMD64FrameMap(getCodeCache(), registerConfigNonNull, this, config.preserveFramePointer); - return new AMD64FrameMapBuilder(frameMap, getCodeCache(), registerConfigNonNull); + AMD64FrameMap frameMap = new AMD64HotSpotFrameMap(getCodeCache(), registerConfigNonNull, this, config); + return new AMD64HotSpotFrameMapBuilder(frameMap, getCodeCache(), registerConfigNonNull); } @Override @@ -129,65 +127,50 @@ protected void bangStackWithOffset(CompilationResultBuilder crb, int bangOffset) /** * Emits code at the verified entry point and return point(s) of a method. */ - class HotSpotFrameContext implements FrameContext { + public class HotSpotFrameContext implements FrameContext { final boolean isStub; - final boolean omitFrame; - final boolean useStandardFrameProlog; - HotSpotFrameContext(boolean isStub, boolean omitFrame, boolean useStandardFrameProlog) { + HotSpotFrameContext(boolean isStub) { this.isStub = isStub; - this.omitFrame = omitFrame; - this.useStandardFrameProlog = useStandardFrameProlog; - } - - @Override - public boolean hasFrame() { - return !omitFrame; } @Override public void enter(CompilationResultBuilder crb) { - FrameMap frameMap = crb.frameMap; + AMD64FrameMap frameMap = (AMD64FrameMap) crb.frameMap; int frameSize = frameMap.frameSize(); AMD64HotSpotMacroAssembler asm = (AMD64HotSpotMacroAssembler) crb.asm; - if (omitFrame) { - if (!isStub) { - GraalError.guarantee(config.nmethodEntryBarrier == 0, "can't omit frames when using nmethod entry barrier"); - asm.nop(PATCHED_VERIFIED_ENTRY_POINT_INSTRUCTION_SIZE); - } + + int verifiedEntryPointOffset = asm.position(); + if (!isStub) { + emitStackOverflowCheck(crb); + // assert asm.position() - verifiedEntryPointOffset >= + // PATCHED_VERIFIED_ENTRY_POINT_INSTRUCTION_SIZE; + } + if (frameMap.preserveFramePointer()) { + // Stack-walking friendly instructions + asm.push(rbp); + asm.movq(rbp, rsp); + } + if (!isStub && asm.position() == verifiedEntryPointOffset) { + asm.subqWide(rsp, frameSize); + assert asm.position() - verifiedEntryPointOffset >= PATCHED_VERIFIED_ENTRY_POINT_INSTRUCTION_SIZE; } else { - int verifiedEntryPointOffset = asm.position(); - if (!isStub) { - emitStackOverflowCheck(crb); - // assert asm.position() - verifiedEntryPointOffset >= - // PATCHED_VERIFIED_ENTRY_POINT_INSTRUCTION_SIZE; - } - if (useStandardFrameProlog) { - // Stack-walking friendly instructions - asm.push(rbp); - asm.movq(rbp, rsp); - } - if (!isStub && asm.position() == verifiedEntryPointOffset) { - asm.subqWide(rsp, frameSize); - assert asm.position() - verifiedEntryPointOffset >= PATCHED_VERIFIED_ENTRY_POINT_INSTRUCTION_SIZE; - } else { - asm.decrementq(rsp, frameSize); - } + asm.decrementq(rsp, frameSize); + } - assert frameMap.getRegisterConfig().getCalleeSaveRegisters() == null; + assert frameMap.getRegisterConfig().getCalleeSaveRegisters() == null; - if (!isStub && config.nmethodEntryBarrier != 0) { - emitNmethodEntryBarrier(crb, asm); - } else { - crb.recordMark(HotSpotMarkId.FRAME_COMPLETE); - } + if (!isStub && config.nmethodEntryBarrier != 0) { + emitNmethodEntryBarrier(crb, asm); + } else { + crb.recordMark(HotSpotMarkId.FRAME_COMPLETE); + } - if (ZapStackOnMethodEntry.getValue(crb.getOptions())) { - final int intSize = 4; - for (int i = 0; i < frameSize / intSize; ++i) { - asm.movl(new AMD64Address(rsp, i * intSize), 0xC1C1C1C1); - } + if (ZapStackOnMethodEntry.getValue(crb.getOptions())) { + final int intSize = 4; + for (int i = 0; i < frameSize / intSize; ++i) { + asm.movl(new AMD64Address(rsp, i * intSize), 0xC1C1C1C1); } } } @@ -211,6 +194,20 @@ private void emitNmethodEntryBarrier(CompilationResultBuilder crb, AMD64HotSpotM asm.jcc(ConditionFlag.NotEqual, entryPoint); crb.getLIR().addSlowPath(null, () -> { asm.bind(entryPoint); + /* + * The nmethod entry barrier can deoptimize by manually removing this frame. It + * makes some assumptions about the frame layout that aren't always true for Graal. + * In particular it assumes the caller`s rbp is always saved in the standard + * location. With -XX:+PreserveFramePointer this has been done by the frame setup. + * Otherwise it is only saved lazily (i.e. if rbp is actually used by the register + * allocator). Since nmethod entry barriers are enabled, the space for rbp has been + * reserved in the frame and here we ensure it is properly saved before calling the + * nmethod entry barrier. + */ + AMD64HotSpotFrameMap frameMap = (AMD64HotSpotFrameMap) crb.frameMap; + if (!frameMap.preserveFramePointer()) { + asm.movq(new AMD64Address(rsp, frameMap.offsetForStackSlot(frameMap.getRBPSpillSlot())), rbp); + } // This is always a near call int beforeCall = asm.position(); asm.call(); @@ -224,17 +221,15 @@ private void emitNmethodEntryBarrier(CompilationResultBuilder crb, AMD64HotSpotM @Override public void leave(CompilationResultBuilder crb) { - if (!omitFrame) { - AMD64MacroAssembler asm = (AMD64MacroAssembler) crb.asm; - assert crb.frameMap.getRegisterConfig().getCalleeSaveRegisters() == null; - - int frameSize = crb.frameMap.frameSize(); - if (useStandardFrameProlog) { - asm.movq(rsp, rbp); - asm.pop(rbp); - } else { - asm.incrementq(rsp, frameSize); - } + AMD64HotSpotFrameMap frameMap = (AMD64HotSpotFrameMap) crb.frameMap; + AMD64MacroAssembler asm = (AMD64MacroAssembler) crb.asm; + assert frameMap.getRegisterConfig().getCalleeSaveRegisters() == null; + + if (frameMap.preserveFramePointer()) { + asm.movq(rsp, rbp); + asm.pop(rbp); + } else { + asm.incrementq(rsp, frameMap.frameSize()); } } @@ -242,6 +237,22 @@ public void leave(CompilationResultBuilder crb) { public void returned(CompilationResultBuilder crb) { // nothing to do } + + public void rawEnter(CompilationResultBuilder crb) { + AMD64MacroAssembler asm = (AMD64MacroAssembler) crb.asm; + AMD64FrameMap frameMap = (AMD64FrameMap) crb.frameMap; + + if (frameMap.preserveFramePointer()) { + // Stack-walking friendly instructions + asm.push(rbp); + asm.movq(rbp, rsp); + } + asm.decrementq(rsp, frameMap.frameSize()); + } + + public void rawLeave(CompilationResultBuilder crb) { + leave(crb); + } } @Override @@ -257,12 +268,10 @@ public CompilationResultBuilder newCompilationResultBuilder(LIRGenerationResult assert gen.getDeoptimizationRescueSlot() == null || frameMap.frameNeedsAllocating() : "method that can deoptimize must have a frame"; OptionValues options = lir.getOptions(); DebugContext debug = lir.getDebug(); - boolean omitFrame = CanOmitFrame.getValue(options) && !frameMap.frameNeedsAllocating() && !lir.hasArgInCallerFrame() && !gen.hasForeignCall() && - !((AMD64FrameMap) frameMap).useStandardFrameProlog() && config.nmethodEntryBarrier == 0; Stub stub = gen.getStub(); AMD64MacroAssembler masm = new AMD64HotSpotMacroAssembler(config, getTarget(), options, config.CPU_HAS_INTEL_JCC_ERRATUM); - HotSpotFrameContext frameContext = new HotSpotFrameContext(stub != null, omitFrame, config.preserveFramePointer); + HotSpotFrameContext frameContext = new HotSpotFrameContext(stub != null); DataBuilder dataBuilder = new HotSpotDataBuilder(getCodeCache().getTarget()); CompilationResultBuilder crb = factory.createBuilder(getProviders(), frameMap, masm, dataBuilder, frameContext, options, debug, compilationResult, Register.None, lir); crb.setTotalFrameSize(frameMap.totalFrameSize()); @@ -297,7 +306,7 @@ public void emitCode(CompilationResultBuilder crb, ResolvedJavaMethod installedC crb.emitLIR(); // Emit the suffix - emitCodeSuffix(crb, asm, frameMap); + emitCodeSuffix(crb, asm); } /** @@ -339,7 +348,7 @@ public void emitCodePrefix(ResolvedJavaMethod installedCodeOwner, CompilationRes crb.recordMark(crb.compilationResult.getEntryBCI() != -1 ? HotSpotMarkId.OSR_ENTRY : HotSpotMarkId.VERIFIED_ENTRY); } - public void emitCodeSuffix(CompilationResultBuilder crb, AMD64MacroAssembler asm, FrameMap frameMap) { + public void emitCodeSuffix(CompilationResultBuilder crb, AMD64MacroAssembler asm) { HotSpotProviders providers = getProviders(); HotSpotFrameContext frameContext = (HotSpotFrameContext) crb.frameContext; if (!frameContext.isStub) { @@ -385,14 +394,6 @@ public void emitCodeSuffix(CompilationResultBuilder crb, AMD64MacroAssembler asm if (config.supportsMethodHandleDeoptimizationEntry() && crb.needsMHDeoptHandler()) { crb.recordMark(AMD64Call.directCall(crb, asm, foreignCalls.lookupForeignCall(DEOPT_BLOB_UNPACK), null, false, null), HotSpotMarkId.DEOPT_MH_HANDLER_ENTRY); } - } else { - // No need to emit the stubs for entries back into the method since - // it has no calls that can cause such "return" entries - - if (frameContext.omitFrame) { - // Cannot access slots in caller's frame if my frame is omitted - assert !frameMap.accessesCallerFrame(); - } } } diff --git a/compiler/src/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64HotSpotEpilogueBlockEndOp.java b/compiler/src/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64HotSpotEpilogueBlockEndOp.java index 2549eb6eaaea..8ad72dcd104a 100644 --- a/compiler/src/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64HotSpotEpilogueBlockEndOp.java +++ b/compiler/src/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64HotSpotEpilogueBlockEndOp.java @@ -24,20 +24,26 @@ */ package org.graalvm.compiler.hotspot.amd64; +import static jdk.vm.ci.amd64.AMD64.rbp; +import static jdk.vm.ci.code.ValueUtil.asRegister; +import static jdk.vm.ci.code.ValueUtil.isStackSlot; import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.ILLEGAL; import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.REG; import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.STACK; +import org.graalvm.compiler.asm.amd64.AMD64Address; import org.graalvm.compiler.asm.amd64.AMD64MacroAssembler; import org.graalvm.compiler.lir.LIRInstructionClass; import org.graalvm.compiler.lir.amd64.AMD64BlockEndOp; +import org.graalvm.compiler.lir.amd64.AMD64FrameMap; import org.graalvm.compiler.lir.asm.CompilationResultBuilder; +import jdk.vm.ci.code.Register; import jdk.vm.ci.meta.AllocatableValue; import jdk.vm.ci.meta.Value; /** - * @see AMD64HotSpotEpilogueOp + * Superclass for operations that use the value of RBP saved in a method's prologue. */ abstract class AMD64HotSpotEpilogueBlockEndOp extends AMD64BlockEndOp implements AMD64HotSpotRestoreRbpOp { @@ -48,7 +54,19 @@ protected AMD64HotSpotEpilogueBlockEndOp(LIRInstructionClass c) { - super(c); - } - - @Use({REG, STACK, ILLEGAL}) private AllocatableValue savedRbp = Value.ILLEGAL; - - protected void leaveFrameAndRestoreRbp(CompilationResultBuilder crb, AMD64MacroAssembler masm) { - leaveFrameAndRestoreRbp(savedRbp, crb, masm); - } - - static void leaveFrameAndRestoreRbp(AllocatableValue savedRbp, CompilationResultBuilder crb, AMD64MacroAssembler masm) { - if (Value.ILLEGAL.equals(savedRbp)) { - // RBP will be restored in FrameContext.leave(..). Nothing to do here. - assert ((AMD64FrameMap) crb.frameMap).useStandardFrameProlog() : "savedRbp is not initialized."; - } else if (isStackSlot(savedRbp)) { - // Restoring RBP from the stack must be done before the frame is removed - masm.movq(rbp, (AMD64Address) crb.asAddress(savedRbp)); - } else { - Register framePointer = asRegister(savedRbp); - if (!framePointer.equals(rbp)) { - masm.movq(rbp, framePointer); - } - } - crb.frameContext.leave(crb); - } - - @Override - public void setSavedRbp(AllocatableValue value) { - savedRbp = value; - } -} diff --git a/compiler/src/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64HotSpotFrameMap.java b/compiler/src/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64HotSpotFrameMap.java new file mode 100644 index 000000000000..c9ca18ddec04 --- /dev/null +++ b/compiler/src/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64HotSpotFrameMap.java @@ -0,0 +1,125 @@ +/* + * 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 org.graalvm.compiler.hotspot.amd64; + +import static jdk.vm.ci.code.ValueUtil.asStackSlot; + +import org.graalvm.compiler.core.common.LIRKind; +import org.graalvm.compiler.hotspot.GraalHotSpotVMConfig; +import org.graalvm.compiler.lir.amd64.AMD64FrameMap; + +import jdk.vm.ci.amd64.AMD64Kind; +import jdk.vm.ci.code.CodeCacheProvider; +import jdk.vm.ci.code.RegisterConfig; +import jdk.vm.ci.code.StackSlot; + +/** + * AMD64 HotSpot specific frame map. + *

+ * The layout is basically the same as {@link AMD64FrameMap} except that space for rbp is reserved + * at the standard location if {@link #preserveFramePointer} is false and a + * {@link #deoptimizationRescueSlot} is always allocated. This is done to be consistent with + * assumptions on HotSpot about frame layout. In particular, the nmethod entry barrier deoptimize + * function in barrierSetNMethod_x86.cpp will manually tear down this frame so it needs to know the + * location of the saved rbp. The extra spill slot for rbp is only written to if rbp is actually + * used by the register allocator. + * + *

+ *   Base       Contents
+ *
+ *            :                                :  -----
+ *   caller   | incoming overflow argument n   |    ^
+ *   frame    :     ...                        :    | positive
+ *            | incoming overflow argument 0   |    | offsets
+ *   ---------+--------------------------------+---------------------
+ *   current  | return address                 |    |            ^
+ *   frame    +--------------------------------+    |            |
+ *            | preserved rbp                  |    |            |
+ *            | iff preserveFramePointer       |    |            |
+ *            +--------------------------------+    |            |    -----
+ *            | preserved rbp                  |    |            |      ^
+ *            | iff not preserveFramePointer   |    |            |      |
+ *            +--------------------------------+    |            |      |
+ *            | deopt rescue slot              |    |            |      |
+ *            +--------------------------------+    |            |      |
+ *            |                                |    |            |      |
+ *            : callee save area               :    |            |      |
+ *            |                                |    |            |      |
+ *            +--------------------------------+    |            |      |
+ *            | spill slot 0                   |    | negative   |      |
+ *            :     ...                        :    v offsets    |      |
+ *            | spill slot n                   |  -----        total  frame
+ *            +--------------------------------+               frame  size
+ *            | alignment padding              |               size     |
+ *            +--------------------------------+  -----          |      |
+ *            | outgoing overflow argument n   |    ^            |      |
+ *            :     ...                        :    | positive   |      |
+ *            | outgoing overflow argument 0   |    | offsets    v      v
+ *    %sp-->  +--------------------------------+---------------------------
+ *
+ * 
+ */ +public class AMD64HotSpotFrameMap extends AMD64FrameMap { + /** + * The spill slot for rbp if {@link #preserveFramePointer} )is false. + */ + private StackSlot rbpSpillSlot; + + /** + * The deoptimization rescue slot. + */ + private StackSlot deoptimizationRescueSlot; + + public AMD64HotSpotFrameMap(CodeCacheProvider codeCache, RegisterConfig registerConfig, ReferenceMapBuilderFactory referenceMapFactory, GraalHotSpotVMConfig config) { + super(codeCache, registerConfig, referenceMapFactory, config.preserveFramePointer); + // HotSpot is picky about the frame layout in the presence of nmethod entry barriers, so + // always allocate the space for rbp and the deoptimization rescue slot. If we don't + // allocate rbp the rbp spill slot will never be written. + if (!preserveFramePointer()) { + assert spillSize == initialSpillSize : "RBP spill slot must be the first allocated stack slots"; + rbpSpillSlot = allocateSpillSlot(LIRKind.value(AMD64Kind.QWORD)); + assert asStackSlot(rbpSpillSlot).getRawOffset() == -16 : asStackSlot(rbpSpillSlot).getRawOffset(); + } + deoptimizationRescueSlot = allocateSpillSlot(LIRKind.value(AMD64Kind.QWORD)); + } + + @Override + public int offsetForStackSlot(StackSlot slot) { + int offset = super.offsetForStackSlot(slot); + // rbp is always saved in the standard location if it is saved + assert !slot.equals(rbpSpillSlot) || offset - totalFrameSize() == -16; + return offset; + } + + public StackSlot getRBPSpillSlot() { + assert rbpSpillSlot != null; + return rbpSpillSlot; + } + + public StackSlot getDeoptimizationRescueSlot() { + assert deoptimizationRescueSlot != null; + return deoptimizationRescueSlot; + } +} diff --git a/compiler/src/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64HotSpotFrameMapBuilder.java b/compiler/src/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64HotSpotFrameMapBuilder.java new file mode 100644 index 000000000000..7e5d890b20cd --- /dev/null +++ b/compiler/src/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64HotSpotFrameMapBuilder.java @@ -0,0 +1,55 @@ +/* + * 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 org.graalvm.compiler.hotspot.amd64; + +import org.graalvm.compiler.lir.amd64.AMD64FrameMapBuilder; +import org.graalvm.compiler.lir.framemap.FrameMap; + +import jdk.vm.ci.code.CodeCacheProvider; +import jdk.vm.ci.code.RegisterConfig; +import jdk.vm.ci.code.StackSlot; + +public class AMD64HotSpotFrameMapBuilder extends AMD64FrameMapBuilder { + public AMD64HotSpotFrameMapBuilder(FrameMap frameMap, CodeCacheProvider codeCache, RegisterConfig registerConfig) { + super(frameMap, codeCache, registerConfig); + } + + @Override + public AMD64HotSpotFrameMap getFrameMap() { + return (AMD64HotSpotFrameMap) super.getFrameMap(); + } + + /** + * For non-leaf methods, RBP is preserved in the special stack slot required by the HotSpot + * runtime for walking/inspecting frames of such methods. + */ + public StackSlot getRBPSpillSlot() { + return getFrameMap().getRBPSpillSlot(); + } + + public StackSlot getDeoptimizationRescueSlot() { + return getFrameMap().getDeoptimizationRescueSlot(); + } +} diff --git a/compiler/src/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64HotSpotLIRGenerator.java b/compiler/src/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64HotSpotLIRGenerator.java index 07148d79827e..46f557652fda 100644 --- a/compiler/src/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64HotSpotLIRGenerator.java +++ b/compiler/src/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64HotSpotLIRGenerator.java @@ -66,7 +66,6 @@ import org.graalvm.compiler.lir.VirtualStackSlot; import org.graalvm.compiler.lir.amd64.AMD64AddressValue; import org.graalvm.compiler.lir.amd64.AMD64ControlFlow.StrategySwitchOp; -import org.graalvm.compiler.lir.amd64.AMD64FrameMapBuilder; import org.graalvm.compiler.lir.amd64.AMD64Move; import org.graalvm.compiler.lir.amd64.AMD64Move.MoveFromRegOp; import org.graalvm.compiler.lir.amd64.AMD64PrefetchOp; @@ -90,7 +89,6 @@ import jdk.vm.ci.code.RegisterArray; import jdk.vm.ci.code.RegisterConfig; import jdk.vm.ci.code.RegisterValue; -import jdk.vm.ci.code.StackSlot; import jdk.vm.ci.meta.AllocatableValue; import jdk.vm.ci.meta.DeoptimizationAction; import jdk.vm.ci.meta.DeoptimizationReason; @@ -163,15 +161,8 @@ class SaveRbp { final NoOp placeholder; - /** - * The slot reserved for saving RBP. - */ - final StackSlot reservedSlot; - SaveRbp(NoOp placeholder) { this.placeholder = placeholder; - AMD64FrameMapBuilder frameMapBuilder = (AMD64FrameMapBuilder) getResult().getFrameMapBuilder(); - this.reservedSlot = config.preserveFramePointer ? null : frameMapBuilder.allocateRBPSpillSlot(); } /** @@ -183,12 +174,10 @@ public AllocatableValue finalize(boolean useStack) { assert !config.preserveFramePointer : "rbp has been pushed onto the stack"; AllocatableValue dst; if (useStack) { - dst = reservedSlot; + dst = ((AMD64HotSpotFrameMapBuilder) getResult().getFrameMapBuilder()).getRBPSpillSlot(); } else { - ((AMD64FrameMapBuilder) getResult().getFrameMapBuilder()).freeRBPSpillSlot(); dst = newVariable(LIRKind.value(AMD64Kind.QWORD)); } - placeholder.replace(getResult().getLIR(), new MoveFromRegOp(AMD64Kind.QWORD, dst, rbp.asValue(LIRKind.value(AMD64Kind.QWORD)))); return dst; } @@ -503,7 +492,7 @@ public void beforeRegisterAllocation() { } if (hasDebugInfo) { - getResult().setDeoptimizationRescueSlot(((AMD64FrameMapBuilder) getResult().getFrameMapBuilder()).allocateDeoptimizationRescueSlot()); + getResult().setDeoptimizationRescueSlot(((AMD64HotSpotFrameMapBuilder) getResult().getFrameMapBuilder()).getDeoptimizationRescueSlot()); } getResult().setMaxInterpreterFrameSize(debugInfoBuilder.maxInterpreterFrameSize()); diff --git a/compiler/src/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64HotSpotLeaveCurrentStackFrameOp.java b/compiler/src/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64HotSpotLeaveCurrentStackFrameOp.java deleted file mode 100644 index d937a748823a..000000000000 --- a/compiler/src/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64HotSpotLeaveCurrentStackFrameOp.java +++ /dev/null @@ -1,84 +0,0 @@ -/* - * Copyright (c) 2013, 2018, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package org.graalvm.compiler.hotspot.amd64; - -import static jdk.vm.ci.amd64.AMD64.rdx; - -import org.graalvm.compiler.asm.amd64.AMD64Address; -import org.graalvm.compiler.asm.amd64.AMD64MacroAssembler; -import org.graalvm.compiler.lir.LIRInstructionClass; -import org.graalvm.compiler.lir.Opcode; -import org.graalvm.compiler.lir.StandardOp.SaveRegistersOp; -import org.graalvm.compiler.lir.asm.CompilationResultBuilder; -import org.graalvm.compiler.lir.framemap.FrameMap; - -import jdk.vm.ci.code.Register; -import jdk.vm.ci.code.RegisterConfig; -import jdk.vm.ci.code.RegisterSaveLayout; -import jdk.vm.ci.meta.JavaKind; - -/** - * Pops the current frame off the stack including the return address and restores the return - * registers stored on the stack. - */ -@Opcode("LEAVE_CURRENT_STACK_FRAME") -final class AMD64HotSpotLeaveCurrentStackFrameOp extends AMD64HotSpotEpilogueOp { - - public static final LIRInstructionClass TYPE = LIRInstructionClass.create(AMD64HotSpotLeaveCurrentStackFrameOp.class); - - private final SaveRegistersOp saveRegisterOp; - - AMD64HotSpotLeaveCurrentStackFrameOp(SaveRegistersOp saveRegisterOp) { - super(TYPE); - this.saveRegisterOp = saveRegisterOp; - } - - @Override - public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) { - FrameMap frameMap = crb.frameMap; - RegisterConfig registerConfig = frameMap.getRegisterConfig(); - RegisterSaveLayout registerSaveLayout = saveRegisterOp.getMap(frameMap); - Register stackPointer = registerConfig.getFrameRegister(); - - // Restore integer result register. - final int stackSlotSize = frameMap.getTarget().wordSize; - Register integerResultRegister = registerConfig.getReturnRegister(JavaKind.Long); - masm.movptr(integerResultRegister, new AMD64Address(stackPointer, registerSaveLayout.registerToSlot(integerResultRegister) * stackSlotSize)); - masm.movptr(rdx, new AMD64Address(stackPointer, registerSaveLayout.registerToSlot(rdx) * stackSlotSize)); - - // Restore float result register. - Register floatResultRegister = registerConfig.getReturnRegister(JavaKind.Double); - masm.movdbl(floatResultRegister, new AMD64Address(stackPointer, registerSaveLayout.registerToSlot(floatResultRegister) * stackSlotSize)); - - /* - * All of the register save area will be popped of the stack. Only the return address - * remains. - */ - leaveFrameAndRestoreRbp(crb, masm); - - // Remove return address. - masm.addq(stackPointer, crb.target.arch.getReturnAddressSize()); - } -} diff --git a/compiler/src/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64HotSpotLeaveDeoptimizedStackFrameOp.java b/compiler/src/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64HotSpotLeaveDeoptimizedStackFrameOp.java deleted file mode 100644 index a5778f41eeba..000000000000 --- a/compiler/src/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64HotSpotLeaveDeoptimizedStackFrameOp.java +++ /dev/null @@ -1,66 +0,0 @@ -/* - * Copyright (c) 2013, 2018, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package org.graalvm.compiler.hotspot.amd64; - -import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.REG; -import static jdk.vm.ci.amd64.AMD64.rbp; -import static jdk.vm.ci.code.ValueUtil.asRegister; - -import org.graalvm.compiler.asm.amd64.AMD64MacroAssembler; -import org.graalvm.compiler.lir.LIRInstructionClass; -import org.graalvm.compiler.lir.Opcode; -import org.graalvm.compiler.lir.asm.CompilationResultBuilder; - -import jdk.vm.ci.code.Register; -import jdk.vm.ci.meta.AllocatableValue; - -/** - * Pops a deoptimized stack frame off the stack including the return address. - */ -@Opcode("LEAVE_DEOPTIMIZED_STACK_FRAME") -final class AMD64HotSpotLeaveDeoptimizedStackFrameOp extends AMD64HotSpotEpilogueOp { - - public static final LIRInstructionClass TYPE = LIRInstructionClass.create(AMD64HotSpotLeaveDeoptimizedStackFrameOp.class); - @Use(REG) AllocatableValue frameSize; - @Use(REG) AllocatableValue framePointer; - - AMD64HotSpotLeaveDeoptimizedStackFrameOp(AllocatableValue frameSize, AllocatableValue initialInfo) { - super(TYPE); - this.frameSize = frameSize; - this.framePointer = initialInfo; - } - - @Override - public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) { - Register stackPointer = crb.frameMap.getRegisterConfig().getFrameRegister(); - masm.addq(stackPointer, asRegister(frameSize)); - - /* - * Restore the frame pointer before stack bang because if a stack overflow is thrown it - * needs to be pushed (and preserved). - */ - masm.movq(rbp, asRegister(framePointer)); - } -} diff --git a/compiler/src/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64HotSpotMacroAssembler.java b/compiler/src/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64HotSpotMacroAssembler.java index 6fcf1bce63ba..1ecf19ba9f73 100644 --- a/compiler/src/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64HotSpotMacroAssembler.java +++ b/compiler/src/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64HotSpotMacroAssembler.java @@ -26,6 +26,7 @@ import org.graalvm.compiler.asm.amd64.AMD64MacroAssembler; import org.graalvm.compiler.core.common.NumUtil; +import org.graalvm.compiler.debug.GraalError; import org.graalvm.compiler.hotspot.GraalHotSpotVMConfig; import org.graalvm.compiler.options.OptionValues; @@ -71,9 +72,9 @@ public void nmethodEntryCompare(int displacement) { emitByte(0x41); emitByte(0x81); emitByte(0x7f); - assert NumUtil.isByte(displacement) : "expected byte sized displacement"; + GraalError.guarantee(NumUtil.isByte(displacement), "expected byte sized displacement"); emitByte(displacement & 0xff); - assert position() % 4 == 0 : "must be aligned"; + GraalError.guarantee(position() % 4 == 0, "must be aligned"); emitInt(0); } } diff --git a/compiler/src/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64HotSpotRegisterAllocationConfig.java b/compiler/src/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64HotSpotRegisterAllocationConfig.java index 6686dfc72c99..18deaf3393ab 100644 --- a/compiler/src/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64HotSpotRegisterAllocationConfig.java +++ b/compiler/src/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64HotSpotRegisterAllocationConfig.java @@ -91,11 +91,11 @@ class AMD64HotSpotRegisterAllocationConfig extends RegisterAllocationConfig { }; // @formatter:on - private final boolean useStandardFrameProlog; + private final boolean preserveFramePointer; - AMD64HotSpotRegisterAllocationConfig(RegisterConfig registerConfig, String[] allocationRestrictedTo, boolean useStandardFrameProlog) { + AMD64HotSpotRegisterAllocationConfig(RegisterConfig registerConfig, String[] allocationRestrictedTo, boolean preserveFramePointer) { super(registerConfig, allocationRestrictedTo); - this.useStandardFrameProlog = useStandardFrameProlog; + this.preserveFramePointer = preserveFramePointer; } @Override @@ -104,7 +104,7 @@ protected RegisterArray initAllocatable(RegisterArray registers) { for (Register reg : registers) { regMap.set(reg.number); } - if (useStandardFrameProlog) { + if (preserveFramePointer) { regMap.clear(rbp.number); } diff --git a/compiler/src/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64HotSpotZBarrierSetLIRGenerator.java b/compiler/src/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64HotSpotZBarrierSetLIRGenerator.java index ae87bef4386b..2c8ed39d98e4 100644 --- a/compiler/src/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64HotSpotZBarrierSetLIRGenerator.java +++ b/compiler/src/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64HotSpotZBarrierSetLIRGenerator.java @@ -25,8 +25,6 @@ package org.graalvm.compiler.hotspot.amd64; import static jdk.vm.ci.amd64.AMD64.r15; -import static jdk.vm.ci.amd64.AMD64.rbp; -import static jdk.vm.ci.amd64.AMD64.rsp; import static org.graalvm.compiler.hotspot.meta.HotSpotHostForeignCallsProvider.Z_ARRAY_BARRIER; import static org.graalvm.compiler.hotspot.meta.HotSpotHostForeignCallsProvider.Z_FIELD_BARRIER; import static org.graalvm.compiler.hotspot.meta.HotSpotHostForeignCallsProvider.Z_PHANTOM_REFERS_TO_BARRIER; @@ -94,7 +92,7 @@ public ForeignCallsProvider getForeignCalls() { * required. */ public static void emitBarrier(CompilationResultBuilder crb, AMD64MacroAssembler masm, Label success, Register resultReg, GraalHotSpotVMConfig config, ForeignCallLinkage callTarget, - AMD64Address address, LIRInstruction op, AMD64FrameMap frameMap) { + AMD64Address address, LIRInstruction op, AMD64HotSpotBackend.HotSpotFrameContext frameContext) { assert !resultReg.equals(address.getBase()) && !resultReg.equals(address.getIndex()); final Label entryPoint = new Label(); @@ -110,13 +108,8 @@ public static void emitBarrier(CompilationResultBuilder crb, AMD64MacroAssembler crb.getLIR().addSlowPath(op, () -> { masm.bind(entryPoint); - if (frameMap != null) { - if (frameMap.useStandardFrameProlog()) { - // Stack-walking friendly instructions - masm.push(rbp); - masm.movq(rbp, rsp); - } - masm.decrementq(rsp, frameMap.frameSize()); + if (frameContext != null) { + frameContext.rawEnter(crb); } CallingConvention cc = callTarget.getOutgoingCallingConvention(); @@ -129,13 +122,8 @@ public static void emitBarrier(CompilationResultBuilder crb, AMD64MacroAssembler AMD64Call.directCall(crb, masm, callTarget, null, false, null); masm.movq(resultReg, cArg0); - if (frameMap != null) { - if (frameMap.useStandardFrameProlog()) { - masm.movq(rsp, rbp); - masm.pop(rbp); - } else { - masm.incrementq(rsp, frameMap.frameSize()); - } + if (frameContext != null) { + frameContext.rawLeave(crb); } // Return to inline code diff --git a/compiler/src/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/CompilationWrapperTest.java b/compiler/src/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/CompilationWrapperTest.java index 34827e358d7c..466c52a8e1b4 100644 --- a/compiler/src/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/CompilationWrapperTest.java +++ b/compiler/src/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/CompilationWrapperTest.java @@ -70,23 +70,6 @@ public void testVMCompilation1() throws IOException, InterruptedException { TestProgram.class.getName())); } - /** - * Tests that {@code -Dgraal.ExitVMOnException=true} works as an alias for - * {@code -Dgraal.CompilationFailureAction=ExitVM}. - */ - @Test - public void testVMCompilation2() throws IOException, InterruptedException { - assumeManagementLibraryIsLoadable(); - testHelper(Collections.emptyList(), Arrays.asList("-XX:-TieredCompilation", - "-XX:+UseJVMCICompiler", - "-XX:JVMCIThreads=1", - "-Dgraal.ExitVMOnException=true", - "-Dgraal.CrashAt=TestProgram.*", - "-Xcomp", - "-XX:CompileCommand=compileonly,*/TestProgram.print*", - TestProgram.class.getName())); - } - static class Probe { final String substring; final int expectedOccurrences; @@ -151,6 +134,7 @@ String test() { testHelper(Arrays.asList(probes), Arrays.asList("-XX:-TieredCompilation", "-XX:+UseJVMCICompiler", "-XX:JVMCIThreads=1", + "-Dgraal.ExitVMCompilationFailureRate=0", "-Dgraal.CompilationFailureAction=Diagnose", "-Dgraal.MaxCompilationProblemsPerAction=" + maxProblems, "-Dgraal.CrashAt=TestProgram.*", diff --git a/compiler/src/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/CompilationTask.java b/compiler/src/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/CompilationTask.java index 8b0cf5ca8e90..abc864c24c17 100644 --- a/compiler/src/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/CompilationTask.java +++ b/compiler/src/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/CompilationTask.java @@ -198,24 +198,21 @@ protected HotSpotCompilationRequestResult performCompilation(DebugContext debug) throw debug.handle(e); } - if (result != null) { - try (DebugCloseable b = CodeInstallationTime.start(debug)) { - installMethod(debug, graph, result); - } - // Installation is included in compilation time and memory usage reported by printer - printer.finish(result, installedCode); + try (DebugCloseable b = CodeInstallationTime.start(debug)) { + installMethod(debug, graph, result); } + // Installation is included in compilation time and memory usage reported by printer + printer.finish(result, installedCode); + stats.finish(method, installedCode); - if (result != null) { - // For compilation of substitutions the method in the compilation request might be - // different than the actual method parsed. The root of the compilation will always - // be the first method in the methods list, so use that instead. - ResolvedJavaMethod rootMethod = result.getMethods()[0]; - int inlinedBytecodes = result.getBytecodeSize() - rootMethod.getCodeSize(); - assert inlinedBytecodes >= 0 : rootMethod + " " + method; - return HotSpotCompilationRequestResult.success(inlinedBytecodes); - } - return null; + + // For compilation of substitutions the method in the compilation request might be + // different than the actual method parsed. The root of the compilation will always + // be the first method in the methods list, so use that instead. + ResolvedJavaMethod rootMethod = result.getMethods()[0]; + int inlinedBytecodes = result.getBytecodeSize() - rootMethod.getCodeSize(); + assert inlinedBytecodes >= 0 : rootMethod + " " + method; + return HotSpotCompilationRequestResult.success(inlinedBytecodes); } } diff --git a/compiler/src/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotTTYStreamProvider.java b/compiler/src/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotTTYStreamProvider.java index 87466e5323a7..3a2902b11c73 100644 --- a/compiler/src/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotTTYStreamProvider.java +++ b/compiler/src/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotTTYStreamProvider.java @@ -26,7 +26,6 @@ import static org.graalvm.compiler.hotspot.HotSpotGraalOptionValues.GRAAL_OPTION_PROPERTY_PREFIX; import static org.graalvm.compiler.hotspot.HotSpotGraalOptionValues.defaultOptions; -import static org.graalvm.word.LocationIdentity.ANY_LOCATION; import java.io.File; import java.io.FileOutputStream; @@ -40,12 +39,11 @@ import org.graalvm.compiler.options.Option; import org.graalvm.compiler.options.OptionKey; import org.graalvm.compiler.options.OptionType; +import org.graalvm.compiler.serviceprovider.GlobalAtomicLong; import org.graalvm.compiler.serviceprovider.GraalServices; import org.graalvm.compiler.serviceprovider.IsolateUtil; import org.graalvm.compiler.serviceprovider.ServiceProvider; import org.graalvm.compiler.word.Word; -import org.graalvm.word.Pointer; -import org.graalvm.word.WordFactory; import jdk.vm.ci.common.NativeImageReinitialize; import jdk.vm.ci.hotspot.HotSpotJVMCIRuntime; @@ -79,33 +77,24 @@ public PrintStream getStream() { /** * Gets a pointer to a global word initialized to 0. */ - private static Pointer getBarrierPointer() { - // Substituted by Target_org_graalvm_compiler_hotspot_HotSpotTTYStreamProvider - return WordFactory.nullPointer(); - } + private static final GlobalAtomicLong BARRIER = new GlobalAtomicLong(0L); /** - * Executes {@code action}. If {@code barrier.isNonNull()}, then {@code barrier} is used to - * ensure the action is executed exactly once in the process (i.e. synchronized across all - * threads and isolates) and that threads will block here until the action is guaranteed to have - * been executed. Note that each {@code barrier} is specific to a specific {@code action} and - * cannot be used for any other action. + * Executes {@code action}. {@link #BARRIER} is used to ensure the action is executed exactly + * once in the process (i.e. synchronized across all threads and isolates) and that threads will + * block here until the action is guaranteed to have been executed. */ - private static boolean execute(Runnable action, Pointer barrier) { - if (barrier.isNull()) { - action.run(); - return true; - } + private static boolean execute(Runnable action) { final long initial = 0L; final long executing = 1L; final long executed = 2L; while (true) { - long value = barrier.readLong(0); + long value = BARRIER.get(); if (value == initial) { - if (barrier.compareAndSwapLong(0, value, executing, ANY_LOCATION) == value) { + if (BARRIER.compareAndSet(value, executing)) { action.run(); - barrier.writeLong(0, executed); + BARRIER.set(executed); return true; } } else { @@ -116,7 +105,6 @@ private static boolean execute(Runnable action, Pointer barrier) { Thread.sleep(5); } catch (InterruptedException e) { } - value = barrier.readLong(0); } } } @@ -192,7 +180,7 @@ private OutputStream lazy() { if (file.exists()) { file.delete(); } - }, getBarrierPointer()); + }); final boolean enableAutoflush = true; FileOutputStream result = new FileOutputStream(name, true); if (executed) { @@ -209,7 +197,7 @@ private OutputStream lazy() { ps.printf("[Use -D%sLogFile= to redirect Graal log output to a file.]%n", GRAAL_OPTION_PROPERTY_PREFIX); ps.flush(); - }, getBarrierPointer()); + }); } catch (Throwable t) { /* * Since this will typically happen on a compiler thread, the diff --git a/compiler/src/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotZBarrierSet.java b/compiler/src/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotZBarrierSet.java index 601f0513d90e..9d5ff098a383 100644 --- a/compiler/src/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotZBarrierSet.java +++ b/compiler/src/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotZBarrierSet.java @@ -24,14 +24,10 @@ */ package org.graalvm.compiler.hotspot; -import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.HOTSPOT_CARRIER_THREAD_OOP_HANDLE_LOCATION; -import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.HOTSPOT_CURRENT_THREAD_OOP_HANDLE_LOCATION; -import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.HOTSPOT_JAVA_THREAD_SCOPED_VALUE_CACHE_HANDLE_LOCATION; -import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.HOTSPOT_OOP_HANDLE_LOCATION; - import org.graalvm.compiler.core.common.memory.BarrierType; import org.graalvm.compiler.core.common.type.AbstractObjectStamp; import org.graalvm.compiler.core.common.type.Stamp; +import org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil; import org.graalvm.compiler.nodes.ValueNode; import org.graalvm.compiler.nodes.gc.ZBarrierSet; import org.graalvm.word.LocationIdentity; @@ -49,8 +45,7 @@ public HotSpotZBarrierSet(ResolvedJavaField referentField) { @Override protected BarrierType barrierForLocation(BarrierType currentBarrier, LocationIdentity location, JavaKind storageKind) { - if (location.equals(HOTSPOT_OOP_HANDLE_LOCATION) || location.equals(HOTSPOT_CURRENT_THREAD_OOP_HANDLE_LOCATION) || location.equals(HOTSPOT_CARRIER_THREAD_OOP_HANDLE_LOCATION) || - location.equals(HOTSPOT_JAVA_THREAD_SCOPED_VALUE_CACHE_HANDLE_LOCATION)) { + if (location instanceof HotSpotReplacementsUtil.OopHandleLocationIdentity) { return BarrierType.READ; } return super.barrierForLocation(currentBarrier, location, storageKind); @@ -58,8 +53,7 @@ protected BarrierType barrierForLocation(BarrierType currentBarrier, LocationIde @Override public BarrierType readBarrierType(LocationIdentity location, ValueNode address, Stamp loadStamp) { - if (location.equals(HOTSPOT_OOP_HANDLE_LOCATION) || location.equals(HOTSPOT_CURRENT_THREAD_OOP_HANDLE_LOCATION) || location.equals(HOTSPOT_CARRIER_THREAD_OOP_HANDLE_LOCATION) || - location.equals(HOTSPOT_JAVA_THREAD_SCOPED_VALUE_CACHE_HANDLE_LOCATION)) { + if (location instanceof HotSpotReplacementsUtil.OopHandleLocationIdentity) { assert loadStamp instanceof AbstractObjectStamp : loadStamp; return BarrierType.READ; } diff --git a/compiler/src/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/HotSpotReplacementsUtil.java b/compiler/src/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/HotSpotReplacementsUtil.java index 9c9a129754d7..bca7c0d3c4d6 100644 --- a/compiler/src/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/HotSpotReplacementsUtil.java +++ b/compiler/src/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/HotSpotReplacementsUtil.java @@ -862,24 +862,47 @@ public static int arrayKlassOffset(@InjectedParameter GraalHotSpotVMConfig confi return config.arrayKlassOffset; } + /** + * HotSpot oop handle memory locations. + */ + public static class OopHandleLocationIdentity extends NamedLocationIdentity { + public OopHandleLocationIdentity(String name, boolean immutable) { + super(name, immutable); + } + + /** + * @see NamedLocationIdentity#immutable(String) + */ + public static NamedLocationIdentity immutable(String name) { + return new OopHandleLocationIdentity(name, true); + } + + /** + * @see NamedLocationIdentity#mutable(String) + */ + public static NamedLocationIdentity mutable(String name) { + return new OopHandleLocationIdentity(name, false); + } + } + public static final LocationIdentity CLASS_MIRROR_LOCATION = NamedLocationIdentity.immutable("Klass::_java_mirror"); /** * This represents the contents of OopHandles used for some internal fields. */ - public static final LocationIdentity HOTSPOT_OOP_HANDLE_LOCATION = NamedLocationIdentity.immutable("OopHandle contents"); + public static final LocationIdentity HOTSPOT_OOP_HANDLE_LOCATION = OopHandleLocationIdentity.immutable("OopHandle contents"); /** * 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 - : NamedLocationIdentity.mutable("_vthread OopHandle contents"); + : OopHandleLocationIdentity.mutable("_vthread OopHandle contents"); public static final LocationIdentity HOTSPOT_CARRIER_THREAD_OOP_HANDLE_LOCATION = JavaVersionUtil.JAVA_SPEC < 19 ? HOTSPOT_OOP_HANDLE_LOCATION - : NamedLocationIdentity.mutable("_threadObj OopHandle contents"); + : OopHandleLocationIdentity.mutable("_threadObj OopHandle contents"); - public static final LocationIdentity HOTSPOT_JAVA_THREAD_SCOPED_VALUE_CACHE_HANDLE_LOCATION = NamedLocationIdentity.mutable("_scopedValueCache OopHandle contents"); + public static final LocationIdentity HOTSPOT_JAVA_THREAD_SCOPED_VALUE_CACHE_HANDLE_LOCATION = OopHandleLocationIdentity.mutable("_scopedValueCache OopHandle contents"); @Fold public static int layoutHelperHeaderSizeShift(@InjectedParameter GraalHotSpotVMConfig config) { diff --git a/compiler/src/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/VirtualThreadUpdateJFRSnippets.java b/compiler/src/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/VirtualThreadUpdateJFRSnippets.java index 245101059a01..c34e55e908e1 100644 --- a/compiler/src/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/VirtualThreadUpdateJFRSnippets.java +++ b/compiler/src/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/VirtualThreadUpdateJFRSnippets.java @@ -156,7 +156,7 @@ public Templates(OptionValues options, HotSpotProviders providers) { public void lower(VirtualThreadUpdateJFRNode virtualThreadUpdateJFRNode, HotSpotRegistersProvider registers, LoweringTool tool) { Arguments args = new Arguments(virtualThreadUpdateJFR, virtualThreadUpdateJFRNode.graph().getGuardsStage(), tool.getLoweringStage()); args.addConst("javaThreadRegister", registers.getThreadRegister()); - args.add("thread", virtualThreadUpdateJFRNode.getThread()); + args.add("threadObj", virtualThreadUpdateJFRNode.getThread()); template(tool, virtualThreadUpdateJFRNode, args).instantiate(tool.getMetaAccess(), virtualThreadUpdateJFRNode, DEFAULT_REPLACER, args); } diff --git a/compiler/src/org.graalvm.compiler.java/src/org/graalvm/compiler/java/BytecodeParser.java b/compiler/src/org.graalvm.compiler.java/src/org/graalvm/compiler/java/BytecodeParser.java index 105cd6bf3333..6c7b972246eb 100644 --- a/compiler/src/org.graalvm.compiler.java/src/org/graalvm/compiler/java/BytecodeParser.java +++ b/compiler/src/org.graalvm.compiler.java/src/org/graalvm/compiler/java/BytecodeParser.java @@ -2148,7 +2148,8 @@ boolean check(boolean pluginResult) { * doesn't return a value, it probably throws an exception. */ int expectedStackSize = beforeStackSize + resultType.getSlotCount(); - assert lastInstr == null || expectedStackSize == frameState.stackSize() : error("plugin manipulated the stack incorrectly: expected=%d, actual=%d", expectedStackSize, + assert lastInstr == null || plugin.isDecorator() || expectedStackSize == frameState.stackSize() : error("plugin manipulated the stack incorrectly: expected=%d, actual=%d", + expectedStackSize, frameState.stackSize()); NodeIterable newNodes = graph.getNewNodes(mark); diff --git a/compiler/src/org.graalvm.compiler.lir.amd64/src/org/graalvm/compiler/lir/amd64/AMD64FrameMap.java b/compiler/src/org.graalvm.compiler.lir.amd64/src/org/graalvm/compiler/lir/amd64/AMD64FrameMap.java index 4bc0d9997b06..6f1422564a72 100644 --- a/compiler/src/org.graalvm.compiler.lir.amd64/src/org/graalvm/compiler/lir/amd64/AMD64FrameMap.java +++ b/compiler/src/org.graalvm.compiler.lir.amd64/src/org/graalvm/compiler/lir/amd64/AMD64FrameMap.java @@ -24,13 +24,9 @@ */ package org.graalvm.compiler.lir.amd64; -import static jdk.vm.ci.code.ValueUtil.asStackSlot; - -import org.graalvm.compiler.core.common.LIRKind; import org.graalvm.compiler.core.common.NumUtil; import org.graalvm.compiler.lir.framemap.FrameMap; -import jdk.vm.ci.amd64.AMD64Kind; import jdk.vm.ci.code.CodeCacheProvider; import jdk.vm.ci.code.RegisterConfig; import jdk.vm.ci.code.StackSlot; @@ -51,9 +47,9 @@ * current | return address | | ^ * frame +--------------------------------+ | | * | preserved rbp | | | - * | (iff {@link #useStandardFrameProlog}) | | | + * | iff preserveFramePointer | | | * +--------------------------------+ | | ----- - * | | | | ^ + * | | | | | * : callee save area : | | | * | | | | | * +--------------------------------+ | | | @@ -81,14 +77,16 @@ */ public class AMD64FrameMap extends FrameMap { - private final boolean useStandardFrameProlog; - private StackSlot rbpSpillSlot; + /** + * If true then the frame setup always pushes and pops rbp. + */ + protected final boolean preserveFramePointer; - public AMD64FrameMap(CodeCacheProvider codeCache, RegisterConfig registerConfig, ReferenceMapBuilderFactory referenceMapFactory, boolean useStandardFrameProlog) { + public AMD64FrameMap(CodeCacheProvider codeCache, RegisterConfig registerConfig, ReferenceMapBuilderFactory referenceMapFactory, boolean preserveFramePointer) { super(codeCache, registerConfig, referenceMapFactory); // (negative) offset relative to sp + total frame size - this.useStandardFrameProlog = useStandardFrameProlog; - this.initialSpillSize = returnAddressSize() + (useStandardFrameProlog ? getTarget().arch.getWordSize() : 0); + this.preserveFramePointer = preserveFramePointer; + this.initialSpillSize = returnAddressSize() + (preserveFramePointer ? getTarget().arch.getWordSize() : 0); this.spillSize = initialSpillSize; } @@ -120,30 +118,7 @@ public int offsetForStackSlot(StackSlot slot) { return super.offsetForStackSlot(slot); } - /** - * For non-leaf methods, RBP is preserved in the special stack slot required by the HotSpot - * runtime for walking/inspecting frames of such methods. - */ - StackSlot allocateRBPSpillSlot() { - assert spillSize == initialSpillSize : "RBP spill slot must be the first allocated stack slots"; - rbpSpillSlot = allocateSpillSlot(LIRKind.value(AMD64Kind.QWORD)); - assert asStackSlot(rbpSpillSlot).getRawOffset() == -16 : asStackSlot(rbpSpillSlot).getRawOffset(); - return rbpSpillSlot; - } - - void freeRBPSpillSlot() { - int size = spillSlotSize(LIRKind.value(AMD64Kind.QWORD)); - assert spillSize == NumUtil.roundUp(initialSpillSize + size, size) : "RBP spill slot can not be freed after allocation other stack slots"; - spillSize = initialSpillSize; - } - - public StackSlot allocateDeoptimizationRescueSlot() { - assert spillSize == initialSpillSize || spillSize == initialSpillSize + - spillSlotSize(LIRKind.value(AMD64Kind.QWORD)) : "Deoptimization rescue slot must be the first or second (if there is an RBP spill slot) stack slot"; - return allocateSpillSlot(LIRKind.value(AMD64Kind.QWORD)); - } - - public boolean useStandardFrameProlog() { - return useStandardFrameProlog; + public boolean preserveFramePointer() { + return preserveFramePointer; } } diff --git a/compiler/src/org.graalvm.compiler.lir.amd64/src/org/graalvm/compiler/lir/amd64/AMD64FrameMapBuilder.java b/compiler/src/org.graalvm.compiler.lir.amd64/src/org/graalvm/compiler/lir/amd64/AMD64FrameMapBuilder.java index 212e6e96f3fe..f62a07323c9b 100644 --- a/compiler/src/org.graalvm.compiler.lir.amd64/src/org/graalvm/compiler/lir/amd64/AMD64FrameMapBuilder.java +++ b/compiler/src/org.graalvm.compiler.lir.amd64/src/org/graalvm/compiler/lir/amd64/AMD64FrameMapBuilder.java @@ -29,27 +29,10 @@ import jdk.vm.ci.code.CodeCacheProvider; import jdk.vm.ci.code.RegisterConfig; -import jdk.vm.ci.code.StackSlot; public class AMD64FrameMapBuilder extends FrameMapBuilderImpl { public AMD64FrameMapBuilder(FrameMap frameMap, CodeCacheProvider codeCache, RegisterConfig registerConfig) { super(frameMap, codeCache, registerConfig); } - - /** - * For non-leaf methods, RBP is preserved in the special stack slot required by the HotSpot - * runtime for walking/inspecting frames of such methods. - */ - public StackSlot allocateRBPSpillSlot() { - return ((AMD64FrameMap) getFrameMap()).allocateRBPSpillSlot(); - } - - public void freeRBPSpillSlot() { - ((AMD64FrameMap) getFrameMap()).freeRBPSpillSlot(); - } - - public StackSlot allocateDeoptimizationRescueSlot() { - return ((AMD64FrameMap) getFrameMap()).allocateDeoptimizationRescueSlot(); - } } diff --git a/compiler/src/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/asm/FrameContext.java b/compiler/src/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/asm/FrameContext.java index 90673328bd5d..c44317c7c741 100644 --- a/compiler/src/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/asm/FrameContext.java +++ b/compiler/src/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/asm/FrameContext.java @@ -60,9 +60,4 @@ public interface FrameContext { * */ void returned(CompilationResultBuilder crb); - - /** - * Determines if a frame is set up and torn down by this object. - */ - boolean hasFrame(); } diff --git a/compiler/src/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/LoopBeginNode.java b/compiler/src/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/LoopBeginNode.java index bfe12805f6b5..c25e4bfd001f 100644 --- a/compiler/src/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/LoopBeginNode.java +++ b/compiler/src/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/LoopBeginNode.java @@ -577,4 +577,18 @@ public boolean isOsrLoop() { protected boolean verifyState() { return !this.graph().getGraphState().getFrameStateVerification().implies(GraphState.FrameStateVerificationFeature.LOOP_BEGINS) || super.verifyState(); } + + @Override + public void setStateAfter(FrameState x) { + super.setStateAfter(x); + if (x != null && graph() != null) { + /* + * We disable counted loop checking for loops whose overflow guard failed. Some + * optimizations can change the loop begin's frame state and thus the associated BCI. In + * this case we need to check the speculation log again to see if the new BCI is + * associated with a failed overflow guard. + */ + checkDisableCountedBySpeculation(x.bci, graph()); + } + } } diff --git a/compiler/src/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/spi/CoreProviders.java b/compiler/src/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/spi/CoreProviders.java index 7339eb0d7287..c5d4ec3fce0d 100644 --- a/compiler/src/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/spi/CoreProviders.java +++ b/compiler/src/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/spi/CoreProviders.java @@ -24,6 +24,7 @@ */ package org.graalvm.compiler.nodes.spi; +import org.graalvm.compiler.api.replacements.SnippetReflectionProvider; import org.graalvm.compiler.core.common.spi.ConstantFieldProvider; import org.graalvm.compiler.core.common.spi.ForeignCallsProvider; import org.graalvm.compiler.core.common.spi.MetaAccessExtensionProvider; @@ -55,4 +56,5 @@ public interface CoreProviders { WordVerification getWordVerification(); + SnippetReflectionProvider getSnippetReflection(); } diff --git a/compiler/src/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/spi/CoreProvidersDelegate.java b/compiler/src/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/spi/CoreProvidersDelegate.java index 152251fb5da4..eef082e9f039 100644 --- a/compiler/src/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/spi/CoreProvidersDelegate.java +++ b/compiler/src/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/spi/CoreProvidersDelegate.java @@ -24,6 +24,7 @@ */ package org.graalvm.compiler.nodes.spi; +import org.graalvm.compiler.api.replacements.SnippetReflectionProvider; import org.graalvm.compiler.core.common.spi.ConstantFieldProvider; import org.graalvm.compiler.core.common.spi.ForeignCallsProvider; import org.graalvm.compiler.core.common.spi.MetaAccessExtensionProvider; @@ -97,4 +98,9 @@ public LoopsDataProvider getLoopsDataProvider() { public WordVerification getWordVerification() { return providers.getWordVerification(); } + + @Override + public SnippetReflectionProvider getSnippetReflection() { + return providers.getSnippetReflection(); + } } diff --git a/compiler/src/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/spi/CoreProvidersImpl.java b/compiler/src/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/spi/CoreProvidersImpl.java deleted file mode 100644 index 35fe9122483f..000000000000 --- a/compiler/src/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/spi/CoreProvidersImpl.java +++ /dev/null @@ -1,135 +0,0 @@ -/* - * Copyright (c) 2019, 2021, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package org.graalvm.compiler.nodes.spi; - -import org.graalvm.compiler.core.common.spi.ConstantFieldProvider; -import org.graalvm.compiler.core.common.spi.ForeignCallsProvider; -import org.graalvm.compiler.core.common.spi.MetaAccessExtensionProvider; - -import jdk.vm.ci.meta.ConstantReflectionProvider; -import jdk.vm.ci.meta.MetaAccessProvider; - -public class CoreProvidersImpl implements CoreProviders { - protected final MetaAccessProvider metaAccess; - protected final ConstantReflectionProvider constantReflection; - protected final ConstantFieldProvider constantFieldProvider; - protected final LoweringProvider lowerer; - protected final Replacements replacements; - protected final StampProvider stampProvider; - protected final ForeignCallsProvider foreignCalls; - protected final PlatformConfigurationProvider platformConfigurationProvider; - protected final MetaAccessExtensionProvider metaAccessExtensionProvider; - protected final LoopsDataProvider loopsDataProvider; - protected final WordVerification wordVerification; - - protected CoreProvidersImpl(MetaAccessProvider metaAccess, ConstantReflectionProvider constantReflection, ConstantFieldProvider constantFieldProvider, LoweringProvider lowerer, - Replacements replacements, StampProvider stampProvider, ForeignCallsProvider foreignCalls, PlatformConfigurationProvider platformConfigurationProvider, - MetaAccessExtensionProvider metaAccessExtensionProvider, LoopsDataProvider loopsDataProvider, WordVerification wordVerification) { - this.metaAccess = metaAccess; - this.constantReflection = constantReflection; - this.constantFieldProvider = constantFieldProvider; - this.lowerer = lowerer; - this.replacements = replacements; - this.stampProvider = stampProvider; - this.foreignCalls = foreignCalls; - this.platformConfigurationProvider = platformConfigurationProvider; - this.metaAccessExtensionProvider = metaAccessExtensionProvider; - this.loopsDataProvider = loopsDataProvider; - this.wordVerification = wordVerification; - } - - @Override - public MetaAccessProvider getMetaAccess() { - return metaAccess; - } - - @Override - public ConstantReflectionProvider getConstantReflection() { - return constantReflection; - } - - @Override - public ConstantFieldProvider getConstantFieldProvider() { - return constantFieldProvider; - } - - @Override - public LoweringProvider getLowerer() { - return lowerer; - } - - @Override - public Replacements getReplacements() { - return replacements; - } - - @Override - public StampProvider getStampProvider() { - return stampProvider; - } - - @Override - public ForeignCallsProvider getForeignCalls() { - return foreignCalls; - } - - @Override - public PlatformConfigurationProvider getPlatformConfigurationProvider() { - return platformConfigurationProvider; - } - - @Override - public MetaAccessExtensionProvider getMetaAccessExtensionProvider() { - return metaAccessExtensionProvider; - } - - @Override - public LoopsDataProvider getLoopsDataProvider() { - return loopsDataProvider; - } - - @Override - public WordVerification getWordVerification() { - return wordVerification; - } - - public CoreProvidersImpl copyWith(ConstantReflectionProvider substitution) { - assert this.getClass() == CoreProvidersImpl.class : "must override in " + getClass(); - return new CoreProvidersImpl(metaAccess, substitution, constantFieldProvider, lowerer, replacements, stampProvider, foreignCalls, platformConfigurationProvider, metaAccessExtensionProvider, - loopsDataProvider, wordVerification); - } - - public CoreProvidersImpl copyWith(ConstantFieldProvider substitution) { - assert this.getClass() == CoreProvidersImpl.class : "must override in " + getClass(); - return new CoreProvidersImpl(metaAccess, constantReflection, substitution, lowerer, replacements, stampProvider, foreignCalls, platformConfigurationProvider, metaAccessExtensionProvider, - loopsDataProvider, wordVerification); - } - - public CoreProvidersImpl copyWith(Replacements substitution) { - assert this.getClass() == CoreProvidersImpl.class : "must override in " + getClass(); - return new CoreProvidersImpl(metaAccess, constantReflection, constantFieldProvider, lowerer, substitution, stampProvider, foreignCalls, platformConfigurationProvider, - metaAccessExtensionProvider, loopsDataProvider, wordVerification); - } -} diff --git a/compiler/src/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/inlining/InliningUtil.java b/compiler/src/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/inlining/InliningUtil.java index ba9466137fa4..a7ef1f68faa4 100644 --- a/compiler/src/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/inlining/InliningUtil.java +++ b/compiler/src/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/inlining/InliningUtil.java @@ -34,6 +34,7 @@ import java.util.Objects; import java.util.function.Consumer; +import jdk.vm.ci.services.Services; import org.graalvm.collections.EconomicMap; import org.graalvm.collections.EconomicSet; import org.graalvm.collections.Equivalence; @@ -120,6 +121,7 @@ import jdk.vm.ci.meta.SpeculationLog; import jdk.vm.ci.meta.SpeculationLog.Speculation; import jdk.vm.ci.meta.TriState; +import org.graalvm.nativeimage.ImageInfo; public class InliningUtil extends ValueMergeUtil { @@ -520,7 +522,19 @@ public static EconomicSet inlineForCanonicalization(Invoke invoke, Structu @SuppressWarnings("try") public static EconomicSet inlineForCanonicalization(Invoke invoke, StructuredGraph inlineGraph, boolean receiverNullCheck, ResolvedJavaMethod inlineeMethod, Consumer> duplicatesConsumer, String reason, String phase, InlineeReturnAction action) { - assert inlineGraph.isSubstitution() || invoke.asNode().graph().getSpeculationLog() == inlineGraph.getSpeculationLog(); + if (!inlineGraph.isSubstitution() && invoke.asNode().graph().getSpeculationLog() != inlineGraph.getSpeculationLog()) { + String message = String.format("caller (%s) speculation log (%s) != callee (%s) speculation log (%s)", + invoke.asNode().graph(), + invoke.asNode().graph().getSpeculationLog(), + inlineGraph, + inlineGraph.getSpeculationLog()); + if (!ImageInfo.inImageCode() || Services.IS_IN_NATIVE_IMAGE) { + GraalError.shouldNotReachHere(message); + } else { + // Workaround for GR-45129 - disable this check for non-libgraal SVM runtime + // compilations + } + } EconomicSetNodeEventListener listener = new EconomicSetNodeEventListener(); /* * This code relies on the fact that Graph.addDuplicates doesn't trigger the diff --git a/compiler/src/org.graalvm.compiler.phases/src/org/graalvm/compiler/phases/util/Providers.java b/compiler/src/org.graalvm.compiler.phases/src/org/graalvm/compiler/phases/util/Providers.java index a727d746db51..b8b544031f83 100644 --- a/compiler/src/org.graalvm.compiler.phases/src/org/graalvm/compiler/phases/util/Providers.java +++ b/compiler/src/org.graalvm.compiler.phases/src/org/graalvm/compiler/phases/util/Providers.java @@ -29,14 +29,15 @@ import org.graalvm.compiler.core.common.spi.ConstantFieldProvider; import org.graalvm.compiler.core.common.spi.ForeignCallsProvider; import org.graalvm.compiler.core.common.spi.MetaAccessExtensionProvider; -import org.graalvm.compiler.nodes.spi.CoreProvidersImpl; +import org.graalvm.compiler.nodes.spi.CoreProviders; import org.graalvm.compiler.nodes.spi.LoopsDataProvider; import org.graalvm.compiler.nodes.spi.LoweringProvider; import org.graalvm.compiler.nodes.spi.PlatformConfigurationProvider; import org.graalvm.compiler.nodes.spi.Replacements; import org.graalvm.compiler.nodes.spi.StampProvider; -import org.graalvm.compiler.word.WordVerificationImpl; +import org.graalvm.compiler.nodes.spi.WordVerification; import org.graalvm.compiler.word.WordTypes; +import org.graalvm.compiler.word.WordVerificationImpl; import jdk.vm.ci.code.CodeCacheProvider; import jdk.vm.ci.meta.ConstantReflectionProvider; @@ -45,18 +46,37 @@ /** * A set of providers, some of which may not be present (i.e., null). */ -public class Providers extends CoreProvidersImpl implements CodeGenProviders { - - private final CodeCacheProvider codeCache; +public class Providers implements CoreProviders, CodeGenProviders { - private final SnippetReflectionProvider snippetReflection; - private final WordTypes wordTypes; + protected final MetaAccessProvider metaAccess; + protected final ConstantReflectionProvider constantReflection; + protected final ConstantFieldProvider constantFieldProvider; + protected final LoweringProvider lowerer; + protected final Replacements replacements; + protected final StampProvider stampProvider; + protected final ForeignCallsProvider foreignCalls; + 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; public Providers(MetaAccessProvider metaAccess, CodeCacheProvider codeCache, ConstantReflectionProvider constantReflection, ConstantFieldProvider constantFieldProvider, ForeignCallsProvider foreignCalls, LoweringProvider lowerer, Replacements replacements, StampProvider stampProvider, PlatformConfigurationProvider platformConfigurationProvider, MetaAccessExtensionProvider metaAccessExtensionProvider, SnippetReflectionProvider snippetReflection, WordTypes wordTypes, LoopsDataProvider loopsDataProvider) { - super(metaAccess, constantReflection, constantFieldProvider, lowerer, replacements, stampProvider, foreignCalls, platformConfigurationProvider, metaAccessExtensionProvider, loopsDataProvider, - new WordVerificationImpl(wordTypes)); + this.metaAccess = metaAccess; + this.constantReflection = constantReflection; + this.constantFieldProvider = constantFieldProvider; + this.lowerer = lowerer; + this.replacements = replacements; + this.stampProvider = stampProvider; + this.foreignCalls = foreignCalls; + this.platformConfigurationProvider = platformConfigurationProvider; + this.metaAccessExtensionProvider = metaAccessExtensionProvider; + this.loopsDataProvider = loopsDataProvider; + this.wordVerification = new WordVerificationImpl(wordTypes); this.codeCache = codeCache; this.snippetReflection = snippetReflection; this.wordTypes = wordTypes; @@ -68,11 +88,67 @@ public Providers(Providers copyFrom) { copyFrom.getSnippetReflection(), copyFrom.getWordTypes(), copyFrom.getLoopsDataProvider()); } + @Override + public MetaAccessProvider getMetaAccess() { + return metaAccess; + } + + @Override + public ConstantReflectionProvider getConstantReflection() { + return constantReflection; + } + + @Override + public ConstantFieldProvider getConstantFieldProvider() { + return constantFieldProvider; + } + + @Override + public LoweringProvider getLowerer() { + return lowerer; + } + + @Override + public Replacements getReplacements() { + return replacements; + } + + @Override + public StampProvider getStampProvider() { + return stampProvider; + } + + @Override + public ForeignCallsProvider getForeignCalls() { + return foreignCalls; + } + + @Override + public PlatformConfigurationProvider getPlatformConfigurationProvider() { + return platformConfigurationProvider; + } + + @Override + public MetaAccessExtensionProvider getMetaAccessExtensionProvider() { + return metaAccessExtensionProvider; + } + + @Override + public LoopsDataProvider getLoopsDataProvider() { + return loopsDataProvider; + } + + @Override + public WordVerification getWordVerification() { + return wordVerification; + } + @Override public CodeCacheProvider getCodeCache() { return codeCache; } + @Override public SnippetReflectionProvider getSnippetReflection() { return snippetReflection; } @@ -81,21 +157,18 @@ public WordTypes getWordTypes() { return wordTypes; } - @Override public Providers copyWith(ConstantReflectionProvider substitution) { assert this.getClass() == Providers.class : "must override"; return new Providers(metaAccess, codeCache, substitution, constantFieldProvider, foreignCalls, lowerer, replacements, stampProvider, platformConfigurationProvider, metaAccessExtensionProvider, snippetReflection, wordTypes, loopsDataProvider); } - @Override public Providers copyWith(ConstantFieldProvider substitution) { assert this.getClass() == Providers.class : "must override"; return new Providers(metaAccess, codeCache, constantReflection, substitution, foreignCalls, lowerer, replacements, stampProvider, platformConfigurationProvider, metaAccessExtensionProvider, snippetReflection, wordTypes, loopsDataProvider); } - @Override public Providers copyWith(Replacements substitution) { assert this.getClass() == Providers.class : "must override in " + getClass(); return new Providers(metaAccess, codeCache, constantReflection, constantFieldProvider, foreignCalls, lowerer, substitution, stampProvider, platformConfigurationProvider, diff --git a/compiler/src/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/PEGraphDecoder.java b/compiler/src/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/PEGraphDecoder.java index 456c372ba8df..36c20fdf3c0e 100644 --- a/compiler/src/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/PEGraphDecoder.java +++ b/compiler/src/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/PEGraphDecoder.java @@ -1105,6 +1105,10 @@ protected boolean tryInvocationPlugin(PEMethodScope methodScope, LoopScope loopS InvocationPluginReceiver invocationPluginReceiver = new InvocationPluginReceiver(graphBuilderContext); if (invocationPlugin.execute(graphBuilderContext, targetMethod, invocationPluginReceiver.init(targetMethod, arguments), arguments)) { + if (invocationPlugin.isDecorator()) { + graphBuilderContext.lastInstr.setNext(invoke.asFixedNode()); + return false; + } if (graphBuilderContext.invokeConsumed) { /* Nothing to do. */ @@ -1127,7 +1131,6 @@ protected boolean tryInvocationPlugin(PEMethodScope methodScope, LoopScope loopS deleteInvoke(invoke); } return true; - } else { /* Intrinsification failed, restore original state: invoke is in Graph. */ invokePredecessor.setNext(invoke.asFixedNode()); @@ -1138,7 +1141,7 @@ protected boolean tryInvocationPlugin(PEMethodScope methodScope, LoopScope loopS protected InvocationPlugin getInvocationPlugin(ResolvedJavaMethod targetMethod) { Object invocationPlugin = invocationPluginCache.computeIfAbsent(targetMethod, method -> { - Object plugin = invocationPlugins.lookupInvocation(targetMethod, options); + Object plugin = invocationPlugins.lookupInvocation(targetMethod, true, true, options); if (plugin == null) { plugin = CACHED_NULL_VALUE; } diff --git a/compiler/src/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/SnippetTemplate.java b/compiler/src/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/SnippetTemplate.java index 1510c026a67e..4d748ebf4390 100644 --- a/compiler/src/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/SnippetTemplate.java +++ b/compiler/src/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/SnippetTemplate.java @@ -854,7 +854,7 @@ static class Options { public abstract static class AbstractTemplates implements org.graalvm.compiler.api.replacements.SnippetTemplateCache { protected final OptionValues options; - private final SnippetReflectionProvider snippetReflection; + protected final SnippetReflectionProvider snippetReflection; private final Map templates; private final boolean shouldTrackNodeSourcePosition; diff --git a/compiler/src/org.graalvm.compiler.serviceprovider/src/org/graalvm/compiler/serviceprovider/GlobalAtomicLong.java b/compiler/src/org.graalvm.compiler.serviceprovider/src/org/graalvm/compiler/serviceprovider/GlobalAtomicLong.java new file mode 100644 index 000000000000..c59d95771d57 --- /dev/null +++ b/compiler/src/org.graalvm.compiler.serviceprovider/src/org/graalvm/compiler/serviceprovider/GlobalAtomicLong.java @@ -0,0 +1,171 @@ +/* + * 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 org.graalvm.compiler.serviceprovider; + +import java.lang.ref.Cleaner; +import java.util.concurrent.atomic.AtomicLong; + +import sun.misc.Unsafe; + +/** + * A shareable long value in the JVM process that is updated atomically. The long value is stored in + * native memory so that it is accessible across multiple libgraal isolates. + *

+ * Objects of this type cannot be created during native image runtime. + * + * @see AtomicLong + */ +public class GlobalAtomicLong { + + private static final Unsafe UNSAFE = GraalUnsafeAccess.getUnsafe(); + + /** + * Cleaner for freeing {@link #address}. + */ + private static Cleaner cleaner; + + /** + * Address of native memory storing the long value. + */ + private volatile long address; + + /** + * Value to which the value will be initialized. + */ + private final long initialValue; + + /** + * Creates a global long value that is atomically updated. + * + * @param initialValue initial value to which the long is set when its memory is allocated + */ + public GlobalAtomicLong(long initialValue) { + this.initialValue = initialValue; + } + + public long getInitialValue() { + return initialValue; + } + + @Override + public String toString() { + long addr = getAddress(); + if (addr == 0L) { + return String.valueOf(initialValue); + } else { + return String.format("%d (@0x%x)", get(), addr); + } + } + + // Substituted by Target_org_graalvm_compiler_serviceprovider_GlobalAtomicLong + private long getAddress() { + if (address == 0L) { + synchronized (this) { + if (address == 0L) { + long addr = UNSAFE.allocateMemory(Long.BYTES); + synchronized (GlobalAtomicLong.class) { + if (cleaner == null) { + cleaner = Cleaner.create(); + } + cleaner.register(this, () -> UNSAFE.freeMemory(addr)); + } + UNSAFE.putLongVolatile(null, addr, initialValue); + address = addr; + } + } + } + return address; + } + + /** + * @see AtomicLong#get() + */ + public long get() { + return UNSAFE.getLongVolatile(null, getAddress()); + } + + /** + * @see AtomicLong#set(long) + */ + public void set(long newValue) { + UNSAFE.putLongVolatile(null, getAddress(), newValue); + } + + /** + * @see AtomicLong#getAndSet(long) + */ + public long getAndSet(long newValue) { + return UNSAFE.getAndSetLong(null, getAddress(), newValue); + } + + /** + * @see AtomicLong#getAndAdd(long) + */ + public long getAndAdd(long delta) { + return UNSAFE.getAndAddLong(null, getAddress(), delta); + } + + /** + * @see AtomicLong#addAndGet(long) + */ + public long addAndGet(long delta) { + return getAndAdd(delta) + delta; + } + + /** + * @see AtomicLong#incrementAndGet() + */ + public long incrementAndGet() { + return addAndGet(1); + } + + /** + * @see AtomicLong#getAndIncrement() + */ + public long getAndIncrement() { + return getAndAdd(1); + } + + /** + * @see AtomicLong#decrementAndGet() + */ + public long decrementAndGet() { + return addAndGet(-1); + } + + /** + * @see AtomicLong#getAndDecrement() + */ + public long getAndDecrement() { + return getAndAdd(-1); + } + + /** + * @see AtomicLong#compareAndSet(long, long) + */ + public boolean compareAndSet(long expectedValue, long newValue) { + return UNSAFE.compareAndSwapLong(null, getAddress(), expectedValue, newValue); + } +} diff --git a/compiler/src/org.graalvm.compiler.serviceprovider/src/org/graalvm/compiler/serviceprovider/GraalServices.java b/compiler/src/org.graalvm.compiler.serviceprovider/src/org/graalvm/compiler/serviceprovider/GraalServices.java index b38d84e9b9eb..b5ee27876a60 100644 --- a/compiler/src/org.graalvm.compiler.serviceprovider/src/org/graalvm/compiler/serviceprovider/GraalServices.java +++ b/compiler/src/org.graalvm.compiler.serviceprovider/src/org/graalvm/compiler/serviceprovider/GraalServices.java @@ -40,7 +40,6 @@ import java.util.Map; import java.util.ServiceConfigurationError; import java.util.ServiceLoader; -import java.util.concurrent.atomic.AtomicLong; import jdk.vm.ci.code.DebugInfo; import jdk.vm.ci.code.VirtualObject; @@ -324,15 +323,15 @@ public static String getExecutionID() { return Long.toString(ProcessHandle.current().pid()); } - private static final AtomicLong globalTimeStamp = new AtomicLong(); + private static final GlobalAtomicLong globalTimeStamp = new GlobalAtomicLong(0L); /** * Gets a time stamp for the current process. This method will always return the same value for * the current VM execution. */ public static long getGlobalTimeStamp() { - if (globalTimeStamp.get() == 0) { - globalTimeStamp.compareAndSet(0, System.currentTimeMillis()); + if (globalTimeStamp.get() == 0L) { + globalTimeStamp.compareAndSet(0L, System.currentTimeMillis()); } return globalTimeStamp.get(); } diff --git a/compiler/src/org.graalvm.compiler.truffle.compiler.hotspot.amd64/src/org/graalvm/compiler/truffle/compiler/hotspot/amd64/AMD64TruffleCallBoundaryInstrumentationFactory.java b/compiler/src/org.graalvm.compiler.truffle.compiler.hotspot.amd64/src/org/graalvm/compiler/truffle/compiler/hotspot/amd64/AMD64TruffleCallBoundaryInstrumentationFactory.java index cef853953ddb..541d49fbe50e 100644 --- a/compiler/src/org.graalvm.compiler.truffle.compiler.hotspot.amd64/src/org/graalvm/compiler/truffle/compiler/hotspot/amd64/AMD64TruffleCallBoundaryInstrumentationFactory.java +++ b/compiler/src/org.graalvm.compiler.truffle.compiler.hotspot.amd64/src/org/graalvm/compiler/truffle/compiler/hotspot/amd64/AMD64TruffleCallBoundaryInstrumentationFactory.java @@ -38,7 +38,6 @@ import org.graalvm.compiler.hotspot.amd64.AMD64HotSpotBackend; import org.graalvm.compiler.hotspot.amd64.AMD64HotSpotZBarrierSetLIRGenerator; import org.graalvm.compiler.hotspot.meta.HotSpotRegistersProvider; -import org.graalvm.compiler.lir.amd64.AMD64FrameMap; import org.graalvm.compiler.lir.amd64.AMD64Move; import org.graalvm.compiler.lir.asm.CompilationResultBuilder; import org.graalvm.compiler.lir.asm.EntryPointDecorator; @@ -81,8 +80,8 @@ public void emitEntryPoint(CompilationResultBuilder crb) { assert masm.position() - pos >= AMD64HotSpotBackend.PATCHED_VERIFIED_ENTRY_POINT_INSTRUCTION_SIZE; if (config.gc == HotSpotGraalRuntime.HotSpotGC.Z) { ForeignCallLinkage callTarget = crb.providers.getForeignCalls().lookupForeignCall(Z_FIELD_BARRIER); - AMD64FrameMap frameMap = (AMD64FrameMap) crb.frameMap; - AMD64HotSpotZBarrierSetLIRGenerator.emitBarrier(crb, masm, null, spillRegister, config, callTarget, address, null, frameMap); + AMD64HotSpotZBarrierSetLIRGenerator.emitBarrier(crb, masm, null, spillRegister, config, callTarget, address, null, + (AMD64HotSpotBackend.HotSpotFrameContext) crb.frameContext); } } masm.movq(spillRegister, new AMD64Address(spillRegister, entryPointOffset)); diff --git a/compiler/src/org.graalvm.compiler.truffle.runtime/src/org/graalvm/compiler/truffle/runtime/GraalTruffleRuntime.java b/compiler/src/org.graalvm.compiler.truffle.runtime/src/org/graalvm/compiler/truffle/runtime/GraalTruffleRuntime.java index c77da53676a4..8ee041fcad09 100644 --- a/compiler/src/org.graalvm.compiler.truffle.runtime/src/org/graalvm/compiler/truffle/runtime/GraalTruffleRuntime.java +++ b/compiler/src/org.graalvm.compiler.truffle.runtime/src/org/graalvm/compiler/truffle/runtime/GraalTruffleRuntime.java @@ -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 @@ -197,20 +197,15 @@ public boolean isLatestJVMCI() { @Override public String getName() { - String compilerConfigurationName = getCompilerConfigurationName(); - assert compilerConfigurationName != null; - String suffix; - if (compilerConfigurationName == null) { - suffix = "Unknown"; - } else if (compilerConfigurationName.equals("community")) { - suffix = "CE"; - } else if (compilerConfigurationName.equals("enterprise")) { - suffix = "EE"; - } else { - assert false : "unexpected compiler configuration name: " + compilerConfigurationName; - suffix = compilerConfigurationName; - } - return "GraalVM " + suffix; + String compilerConfigurationName = String.valueOf(getCompilerConfigurationName()); + return switch (compilerConfigurationName) { + case "community" -> "GraalVM CE"; + case "enterprise" -> "Oracle GraalVM"; + default -> { + assert false : "unexpected compiler configuration name: " + compilerConfigurationName; + yield "GraalVM " + compilerConfigurationName; + } + }; } /** diff --git a/docs/reference-manual/native-image/BuildOutput.md b/docs/reference-manual/native-image/BuildOutput.md index 110c0f6321ad..33709fd5507f 100644 --- a/docs/reference-manual/native-image/BuildOutput.md +++ b/docs/reference-manual/native-image/BuildOutput.md @@ -20,55 +20,55 @@ Below is the example output when building a native executable of the `HelloWorld ================================================================================ GraalVM Native Image: Generating 'helloworld' (executable)... ================================================================================ -[1/8] Initializing... (3.3s @ 0.25GB) - Version info: 'GraalVM dev Java 19+36-jvmci-23.0-b01 CE' - Java version info: '19+36-jvmci-23.0-b01' - Graal compiler: optimization level: '0', target machine: 'x86-64-v3' - C compiler: gcc (linux, x86_64, 11.3.0) +[1/8] Initializing... (3.3s @ 0.15GB) + Java version: 17.0.7+4, vendor: GraalVM Community + Graal compiler: optimization level: '2', target machine: 'x86-64-v3' + C compiler: gcc (linux, x86_64, 12.2.0) Garbage collector: Serial GC (max heap size: 80% of RAM) -[2/8] Performing analysis... [****] (6.2s @ 0.47GB) - 2,880 (71.50%) of 4,028 types reachable - 3,519 (51.06%) of 6,892 fields reachable - 13,339 (45.11%) of 29,570 methods reachable - 879 types, 0 fields, and 356 methods registered for reflection - 57 types, 56 fields, and 52 methods registered for JNI access +[2/8] Performing analysis... [***] (6.4s @ 0.83GB) + 2,905 (71.75%) of 4,049 types reachable + 3,534 (51.13%) of 6,912 fields reachable + 13,234 (43.97%) of 30,095 methods reachable + 901 types, 0 fields, and 344 methods registered for reflection + 58 types, 58 fields, and 52 methods registered for JNI access 4 native libraries: dl, pthread, rt, z -[3/8] Building universe... (1.1s @ 2.26GB) -[4/8] Parsing methods... [*] (1.0s @ 2.76GB) -[5/8] Inlining methods... [***] (0.8s @ 0.99GB) -[6/8] Compiling methods... [***] (6.4s @ 4.86GB) -[7/8] Layouting methods... [**] (4.2s @ 3.98GB) -[8/8] Creating image... [*] (4.0s @ 2.04GB) - 4.52MB (22.97%) for code area: 7,470 compilation units - 7.06MB (35.87%) for image heap: 101,764 objects and 5 resources - 7.52MB (38.24%) for debug info generated in 1.8s - 590.19KB ( 2.93%) for other data - 19.68MB in total +[3/8] Building universe... (1.2s @ 0.34GB) +[4/8] Parsing methods... [*] (0.8s @ 0.84GB) +[5/8] Inlining methods... [***] (0.5s @ 1.19GB) +[6/8] Compiling methods... [***] (5.6s @ 0.84GB) +[7/8] Layouting methods... [*] (1.1s @ 1.03GB) +[8/8] Creating image... [**] (3.9s @ 2.14GB) + 4.42MB (23.20%) for code area: 7,526 compilation units + 8.18MB (42.92%) for image heap: 107,049 objects and 5 resources + 5.87MB (30.78%) for debug info generated in 1.2s + 605.20KB ( 3.10%) for other data + 19.06MB in total -------------------------------------------------------------------------------- Top 10 origins of code area: Top 10 object types in image heap: - 3.43MB java.base 1.01MB byte[] for code metadata - 760.98KB svm.jar (Native Image) 1000.72KB java.lang.String - 102.06KB java.logging 884.18KB byte[] for general heap data - 48.03KB org.graalvm.nativeimage.base 686.91KB byte[] for java.lang.String - 40.49KB jdk.proxy1 659.87KB java.lang.Class - 38.23KB jdk.proxy3 247.50KB c.o.s.c.h.DynamicHubCompanion - 25.73KB jdk.internal.vm.ci 239.25KB java.lang.Object[] - 23.55KB org.graalvm.sdk 226.08KB java.util.HashMap$Node - 11.10KB jdk.proxy2 173.15KB java.lang.String[] - 8.10KB jdk.internal.vm.compiler 163.22KB j.u.c.ConcurrentHashMap$Node - 1.39KB for 2 more origins 1.70MB for 808 more object types + 3.37MB java.base 1008.75KB byte[] for code metadata + 792.12KB svm.jar (Native Image) 995.63KB java.lang.String + 112.32KB java.logging 887.47KB byte[] for general heap data + 62.07KB org.graalvm.nativeimage.base 685.47KB byte[] for java.lang.String + 24.15KB jdk.internal.vm.ci 670.38KB java.lang.Class + 23.14KB org.graalvm.sdk 490.13KB java.util.HashMap$Node + 6.11KB jdk.internal.vm.compiler 297.43KB byte[] for embedded resources + 1.35KB jdk.proxy1 249.65KB c.o.s.c.h.DynamicHubCompanion + 1.27KB jdk.proxy3 195.52KB java.util.HashMap$Node[] + 1.18KB jdk.localedata 171.84KB java.lang.String[] + 594.00B for 2 more packages 1.68MB for 824 more object types -------------------------------------------------------------------------------- Recommendations: HEAP: Set max heap for improved and more predictable memory usage. CPU: Enable more CPU features with '-march=native' for improved performance. -------------------------------------------------------------------------------- - 0.5s (1.8% of total time) in 24 GCs | Peak RSS: 5.62GB | CPU load: 8.92 + 0.5s (2.0% of total time) in 17 GCs | Peak RSS: 3.29GB | CPU load: 10.97 -------------------------------------------------------------------------------- Produced artifacts: - /home/janedoe/helloworld/helloworld (executable, debug_info) + /home/janedoe/helloworld/helloworld (executable) + /home/janedoe/helloworld/helloworld.debug (debug_info) /home/janedoe/helloworld/sources (debug_info) ================================================================================ -Finished generating 'helloworld' in 27.4s. +Finished generating 'helloworld' in 23.3s. ``` ## Build Stages @@ -79,14 +79,10 @@ In this stage, the Native Image build process is set up and [`Features`](https:/ #### Native Image Kind By default, Native Image generates *executables* but it can also generate [*native shared libraries*](InteropWithNativeCode.md) and [*static executables*](guides/build-static-and-mostly-static-executable.md). -#### Version Info -The version info of the Native Image process. -This string is also used for the `java.vm.version` property within the generated native binary. -Please report this version info when you [file issues](https://github.com/oracle/graal/issues/new). - -#### Java Version Info -The Java version info (`java.runtime.version` property) of the Native Image build process. -Please report this version info when you [file issues](https://github.com/oracle/graal/issues/new). +#### Java Version Info +The Java version and vendor of the Native Image process. +Both are also used for the `java.vm.version` and `java.vm.vendor` properties within the generated native binary. +Please report version and vendor when you [file issues](https://github.com/oracle/graal/issues/new). #### Graal Compiler The selected optimization level and targeted machine type used by the Graal compiler. diff --git a/docs/reference-manual/native-image/ReachabilityMetadata.md b/docs/reference-manual/native-image/ReachabilityMetadata.md index 397129fbe875..e298778e0302 100644 --- a/docs/reference-manual/native-image/ReachabilityMetadata.md +++ b/docs/reference-manual/native-image/ReachabilityMetadata.md @@ -1,4 +1,3 @@ - --- layout: ni-docs toc_group: metadata diff --git a/docs/reference-manual/native-image/assets/build-output-schema-v0.9.1.json b/docs/reference-manual/native-image/assets/build-output-schema-v0.9.1.json index 161ba80c9c37..c3c2f01492e0 100644 --- a/docs/reference-manual/native-image/assets/build-output-schema-v0.9.1.json +++ b/docs/reference-manual/native-image/assets/build-output-schema-v0.9.1.json @@ -19,6 +19,7 @@ "name", "graalvm_version", "java_version", + "vendor", "graal_compiler", "c_compiler", "garbage_collector" @@ -32,12 +33,17 @@ "graalvm_version": { "type": "string", "default": "", - "title": "The GraalVM Native Image version. This value is also used for the 'java.vm.version' property within the generated image" + "title": "The GraalVM Native Image version. Deprecated: Please use java_version and vendor instead." }, "java_version": { - "type": ["string", "null"], + "type": "string", + "default": null, + "title": "The Java version of the Native Image build process. This value is also used for the 'java.vm.version' property within the generated image" + }, + "vendor": { + "type": "string", "default": null, - "title": "The Java version of the Native Image build process (or null if not available)" + "title": "The vendor of the VM of the generated image. This value is also used for the 'java.vm.vendor' property within the generated image" }, "graal_compiler": { "type": "object", @@ -76,13 +82,14 @@ "examples": [ { "name": "helloworld", - "graalvm_version": "GraalVM 22.2.0-dev Java 17 EE", + "graalvm_version": "GraalVM CE 17.0.7+4", "graal_compiler": { "pgo": false, "march": "x86-64-v3", "optimization_level": "0" }, - "java_version": "17.0.4+5-jvmci-22.2-b03", + "java_version": "17.0.7+4", + "vendor": "GraalVM Community", "c_compiler": "gcc (linux, x86_64, 9.3.0)", "garbage_collector": "Serial GC" } @@ -506,12 +513,13 @@ { "general_info": { "name": "helloworld", - "graalvm_version": "GraalVM 22.2.0-dev Java 17 CE", + "graalvm_version": "GraalVM CE 17.0.7+4", "graal_compiler": { "march": "x86-64-v3", "optimization_level": "0" }, - "java_version": "17.0.4+5-jvmci-22.2-b03", + "java_version": "17.0.7+4", + "vendor": "GraalVM Community", "c_compiler": "gcc (linux, x86_64, 9.3.0)", "garbage_collector": "Serial GC" }, @@ -574,12 +582,13 @@ { "general_info": { "name": "helloworld", - "graalvm_version": "GraalVM 22.2.0-dev Java 17 CE", + "graalvm_version": "GraalVM CE 17.0.7+4", "graal_compiler": { "march": "x86-64-v3", "optimization_level": "0" }, - "java_version": null, + "java_version": "17.0.7+4", + "vendor": "GraalVM Community", "c_compiler": null, "garbage_collector": "Serial GC" }, diff --git a/espresso/mx.espresso/suite.py b/espresso/mx.espresso/suite.py index 933b0ce7906e..1572c50a28ae 100644 --- a/espresso/mx.espresso/suite.py +++ b/espresso/mx.espresso/suite.py @@ -23,7 +23,7 @@ suite = { "mxversion": "6.17.0", "name": "espresso", - "version" : "23.0.0", + "version" : "23.1.0", "release" : False, "groupId" : "org.graalvm.espresso", "url" : "https://www.graalvm.org/reference-manual/java-on-truffle/", @@ -60,23 +60,14 @@ { "name": "truffle", "subdir": True, - "urls": [ - {"url": "https://curio.ssw.jku.at/nexus/content/repositories/snapshots", "kind": "binary"}, - ] }, { "name": "tools", "subdir": True, - "urls": [ - {"url": "https://curio.ssw.jku.at/nexus/content/repositories/snapshots", "kind": "binary"}, - ] }, { "name": "sulong", "subdir": True, - "urls": [ - {"url": "https://curio.ssw.jku.at/nexus/content/repositories/snapshots", "kind": "binary"}, - ], "os_arch": { "windows": { "": { @@ -93,9 +84,6 @@ { "name" : "java-benchmarks", "subdir": True, - "urls": [ - {"url": "https://curio.ssw.jku.at/nexus/content/repositories/snapshots", "kind": "binary"}, - ] }, ], }, diff --git a/graal-common.json b/graal-common.json index 2de804af43ee..3593617838ce 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": "7613333303c6a3c64716b2d067a3ba05824cc4fd" + "overlay": "2a0851326f1dfd487b05e5e54dec4e6736b901ed" } } diff --git a/regex/mx.regex/suite.py b/regex/mx.regex/suite.py index 00e76abae9e8..b262df19c896 100644 --- a/regex/mx.regex/suite.py +++ b/regex/mx.regex/suite.py @@ -43,7 +43,7 @@ "name" : "regex", - "version" : "23.0.0", + "version" : "23.1.0", "release" : False, "groupId" : "org.graalvm.regex", "url" : "http://www.graalvm.org/", @@ -64,9 +64,6 @@ { "name" : "truffle", "subdir": True, - "urls" : [ - {"url" : "https://curio.ssw.jku.at/nexus/content/repositories/snapshots", "kind" : "binary"}, - ] }, ] }, diff --git a/regex/src/com.oracle.truffle.regex.test/src/com/oracle/truffle/regex/tregex/test/PythonByteTests.java b/regex/src/com.oracle.truffle.regex.test/src/com/oracle/truffle/regex/tregex/test/PythonByteTests.java index 47b617d4bed5..34ef66239506 100644 --- a/regex/src/com.oracle.truffle.regex.test/src/com/oracle/truffle/regex/tregex/test/PythonByteTests.java +++ b/regex/src/com.oracle.truffle.regex.test/src/com/oracle/truffle/regex/tregex/test/PythonByteTests.java @@ -112,4 +112,12 @@ public void localeSensitive() { test("\u00fd", "iL", "PythonLocale=tr_TR.ISO-8859-9", "\u00dd", 0, false); test("\u00fd", "iL", "PythonLocale=tr_TR.ISO-8859-9", "I", 0, true, 0, 1, -1); } + + @Test + public void unsupportedLocale() { + expectUnsupported("foo", "iL", "PythonLocale=foo"); + expectUnsupported("foo", "iL", "PythonLocale=foo."); + expectUnsupported("foo", "iL", "PythonLocale=foo.!"); + expectUnsupported("foo", "iL", "PythonLocale=ab_XY.ISO-8859-42"); + } } diff --git a/regex/src/com.oracle.truffle.regex.test/src/com/oracle/truffle/regex/tregex/test/RegexTestBase.java b/regex/src/com.oracle.truffle.regex.test/src/com/oracle/truffle/regex/tregex/test/RegexTestBase.java index f4b094f14152..f2784cc2dc17 100644 --- a/regex/src/com.oracle.truffle.regex.test/src/com/oracle/truffle/regex/tregex/test/RegexTestBase.java +++ b/regex/src/com.oracle.truffle.regex.test/src/com/oracle/truffle/regex/tregex/test/RegexTestBase.java @@ -143,8 +143,12 @@ private static void validateResult(Value result, int groupCount, boolean isMatch } } - void testUnsupported(String pattern, String flags) { - Assert.assertTrue(compileRegex(pattern, flags).isNull()); + void expectUnsupported(String pattern, String flags) { + expectUnsupported(pattern, flags, ""); + } + + void expectUnsupported(String pattern, String flags, String options) { + Assert.assertTrue(compileRegex(pattern, flags, options).isNull()); } void expectSyntaxError(String pattern, String flags, String expectedMessage) { diff --git a/regex/src/com.oracle.truffle.regex.test/src/com/oracle/truffle/regex/tregex/test/RubyTests.java b/regex/src/com.oracle.truffle.regex.test/src/com/oracle/truffle/regex/tregex/test/RubyTests.java index 0ddb7f1bdd71..e4c155f7dd00 100644 --- a/regex/src/com.oracle.truffle.regex.test/src/com/oracle/truffle/regex/tregex/test/RubyTests.java +++ b/regex/src/com.oracle.truffle.regex.test/src/com/oracle/truffle/regex/tregex/test/RubyTests.java @@ -417,9 +417,9 @@ public void nonRecursiveSubexpressionCalls() { @Test public void recursiveSubexpressionCalls() { - testUnsupported("(a\\g<1>?)(b\\g<2>?)", ""); - testUnsupported("(?a\\g?)(?b\\g?)", ""); - testUnsupported("a\\g<0>?", ""); + expectUnsupported("(a\\g<1>?)(b\\g<2>?)", ""); + expectUnsupported("(?a\\g?)(?b\\g?)", ""); + expectUnsupported("a\\g<0>?", ""); } @Test @@ -535,7 +535,7 @@ public void gr39214() { @Test public void gr41489() { - testUnsupported("\\((?>[^)(]+|\\g<0>)*\\)", ""); + expectUnsupported("\\((?>[^)(]+|\\g<0>)*\\)", ""); } @Test diff --git a/regex/src/com.oracle.truffle.regex/src/com/oracle/truffle/regex/tregex/parser/flavors/PythonLocaleData.java b/regex/src/com.oracle.truffle.regex/src/com/oracle/truffle/regex/tregex/parser/flavors/PythonLocaleData.java index c0ea387a4563..88ff822d2f80 100644 --- a/regex/src/com.oracle.truffle.regex/src/com/oracle/truffle/regex/tregex/parser/flavors/PythonLocaleData.java +++ b/regex/src/com.oracle.truffle.regex/src/com/oracle/truffle/regex/tregex/parser/flavors/PythonLocaleData.java @@ -53,6 +53,8 @@ import java.nio.charset.Charset; import java.nio.charset.CharsetDecoder; import java.nio.charset.CodingErrorAction; +import java.nio.charset.IllegalCharsetNameException; +import java.nio.charset.UnsupportedCharsetException; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; @@ -80,7 +82,11 @@ public static PythonLocaleData getLocaleData(String locale) { } String language = locale.substring(0, dot); String encoding = locale.substring(dot + 1); - return createCachedLocaleData(language.startsWith("tr_"), Charset.forName(encoding)); + try { + return createCachedLocaleData(language.startsWith("tr_"), Charset.forName(encoding)); + } catch (UnsupportedCharsetException | IllegalCharsetNameException e) { + throw new IllegalArgumentException("unsupported locale: " + locale); + } } } diff --git a/regex/src/com.oracle.truffle.regex/src/com/oracle/truffle/regex/tregex/parser/flavors/PythonRegexLexer.java b/regex/src/com.oracle.truffle.regex/src/com/oracle/truffle/regex/tregex/parser/flavors/PythonRegexLexer.java index 8043ecc8b59a..6ebc3b887585 100644 --- a/regex/src/com.oracle.truffle.regex/src/com/oracle/truffle/regex/tregex/parser/flavors/PythonRegexLexer.java +++ b/regex/src/com.oracle.truffle.regex/src/com/oracle/truffle/regex/tregex/parser/flavors/PythonRegexLexer.java @@ -50,6 +50,7 @@ import com.oracle.truffle.api.CompilerDirectives; import com.oracle.truffle.regex.RegexSource; import com.oracle.truffle.regex.RegexSyntaxException; +import com.oracle.truffle.regex.UnsupportedRegexException; import com.oracle.truffle.regex.chardata.UnicodeCharacterAliases; import com.oracle.truffle.regex.charset.CodePointSet; import com.oracle.truffle.regex.charset.CodePointSetAccumulator; @@ -192,7 +193,11 @@ private static int lookupCharacterByName(String characterName) { public PythonLocaleData getLocaleData() { if (localeData == null) { - localeData = PythonLocaleData.getLocaleData(source.getOptions().getPythonLocale()); + try { + localeData = PythonLocaleData.getLocaleData(source.getOptions().getPythonLocale()); + } catch (IllegalArgumentException e) { + throw new UnsupportedRegexException(e.getMessage(), source); + } } return localeData; } diff --git a/sdk/mx.sdk/mx_sdk_vm.py b/sdk/mx.sdk/mx_sdk_vm.py index 0122b072de3c..e0e76257e019 100644 --- a/sdk/mx.sdk/mx_sdk_vm.py +++ b/sdk/mx.sdk/mx_sdk_vm.py @@ -77,7 +77,7 @@ class AbstractNativeImageConfig(object, metaclass=ABCMeta): - def __init__(self, destination, jar_distributions, build_args, use_modules=None, links=None, is_polyglot=False, dir_jars=False, home_finder=False, build_time=1, build_args_enterprise=None, rebuildable=True): # pylint: disable=super-init-not-called + def __init__(self, destination, jar_distributions, build_args, use_modules=None, links=None, is_polyglot=False, dir_jars=False, home_finder=False, build_time=1, build_args_enterprise=None): # pylint: disable=super-init-not-called """ :type destination: str :type jar_distributions: list[str] @@ -89,7 +89,6 @@ def __init__(self, destination, jar_distributions, build_args, use_modules=None, :type home_finder: bool :type build_time: int :type build_args_enterprise: list[str] | None - :param bool rebuildable: Whether the GraalVM should include macros and support files (e.g., profiles) to rebuild """ self.destination = mx_subst.path_substitutions.substitute(destination) self.jar_distributions = jar_distributions @@ -101,13 +100,11 @@ def __init__(self, destination, jar_distributions, build_args, use_modules=None, self.home_finder = home_finder self.build_time = build_time self.build_args_enterprise = build_args_enterprise or [] - self.rebuildable = rebuildable self.relative_home_paths = {} assert isinstance(self.jar_distributions, list) assert isinstance(self.build_args, (list, types.GeneratorType)) assert isinstance(self.build_args_enterprise, list) - assert isinstance(self.rebuildable, bool) def __str__(self): return self.destination diff --git a/sdk/mx.sdk/mx_sdk_vm_impl.py b/sdk/mx.sdk/mx_sdk_vm_impl.py index 1996131251e4..09bf2a30875f 100644 --- a/sdk/mx.sdk/mx_sdk_vm_impl.py +++ b/sdk/mx.sdk/mx_sdk_vm_impl.py @@ -100,16 +100,11 @@ def unicode_utf8(string): _graalvm_base_name = 'GraalVM' - +_registered_graalvm_components = {} +_project_name = 'graal' default_components = [] -graalvm_version_regex = re.compile(r'.*\n.*\n[0-9a-zA-Z()\- ]+GraalVM[a-zA-Z_ ]+(?P[0-9a-z_\-.+]+) \(build [0-9a-zA-Z\-.+]+, mixed mode[a-z, ]*\)') - -_registered_graalvm_components = {} -_env_tests = [] - -_project_name = 'graal' mx.add_argument('--base-dist-name', help='Sets the name of the GraalVM base image ( for complete, ruby ... images), default to "base"', default='base') @@ -494,7 +489,7 @@ def _add_link(_dest, _target, _component=None, _dest_base_name=None): if stage1: # 1. we do not want a GraalVM to be used as base-JDK # 2. we don't need to check if the base JDK is JVMCI-enabled, since JVMCIVersionCheck takes care of that when the GraalVM compiler is a registered component - check_versions(_src_jdk, graalvm_version_regex=graalvm_version_regex, expect_graalvm=False, check_jvmci=False) + check_versions(_src_jdk, expect_graalvm=False, check_jvmci=False) # Add base JDK if mx.get_os() == 'darwin': @@ -644,12 +639,12 @@ def _add_link(_dest, _target, _component=None, _dest_base_name=None): if _launcher_config.default_symlinks: _link_path = _add_link(_jdk_jre_bin, _link_dest, _component) _jre_bin_names.append(basename(_link_path)) - if stage1 or _launcher_config.rebuildable: + if stage1 or _rebuildable_image(_launcher_config): _add_native_image_macro(_launcher_config, _component) if isinstance(_launcher_config, mx_sdk.LanguageLauncherConfig): _add(layout, _component_base, 'dependency:{}/polyglot.config'.format(launcher_project), _component) for _library_config in sorted(_get_library_configs(_component), key=lambda c: c.destination): - if stage1 or _library_config.rebuildable or isinstance(_library_config, mx_sdk_vm.LanguageLibraryConfig): + if stage1 or _rebuildable_image(_library_config) or isinstance(_library_config, mx_sdk_vm.LanguageLibraryConfig): # language libraries can run in `--jvm` mode graalvm_dists.update(_library_config.jar_distributions) self.jimage_ignore_jars.update(_library_config.jar_distributions) @@ -679,7 +674,7 @@ def _add_link(_dest, _target, _component=None, _dest_base_name=None): _add(layout, join(_component_base, _executable), 'dependency:{}'.format(NativeLibraryLauncherProject.library_launcher_project_name(_library_config)), _component) _link_path = _add_link(_jdk_jre_bin, _component_base + _executable) _jre_bin_names.append(basename(_link_path)) - if stage1 or _library_config.rebuildable: + if stage1 or _rebuildable_image(_library_config): _add_native_image_macro(_library_config, _component) graalvm_dists.update(_component.polyglot_lib_jar_dependencies) @@ -904,11 +899,17 @@ def _components_set(components=None, stage1=False): # forced bash launchers and skipped libraries only make a difference if Native Image is involved in the build for component in components: for launcher_config in _get_launcher_configs(component): + simple_name = remove_exe_suffix(basename(launcher_config.destination)) if _force_bash_launchers(launcher_config): - components_set.add('b' + remove_exe_suffix(basename(launcher_config.destination))) + components_set.add('b' + simple_name) + if not _rebuildable_image(launcher_config): + components_set.add('nr_lau_' + simple_name) for library_config in _get_library_configs(component): + simple_name = remove_lib_prefix_suffix(basename(library_config.destination)) if _skip_libraries(library_config): - components_set.add('s' + remove_lib_prefix_suffix(basename(library_config.destination))) + components_set.add('s' + simple_name) + if not _rebuildable_image(library_config): + components_set.add('nr_lib_' + simple_name) if _no_licenses(): components_set.add('nolic') return components_set @@ -1037,7 +1038,7 @@ def _add(dep_names, layout): source_type = 'skip' if isinstance(image_config, mx_sdk.LibraryConfig) and _skip_libraries(image_config) else 'dependency' root_contents += [source_type + ':{}:{}/*{}'.format(dep.suite.name, dep.name, _get_svm_support().separate_debuginfo_ext())] layout[dep.native_image_name + '-sources/'] = source_type + ':{}:{}/sources'.format(dep.suite.name, dep.name) - if not image_config.rebuildable: + if not _rebuildable_image(image_config): macro_dir = GraalVmNativeProperties.macro_name(image_config) + '/' layout.setdefault(macro_dir, []).append('dependency:{}'.format(GraalVmNativeProperties.project_name(image_config))) for profile in _image_profiles(GraalVmNativeProperties.canonical_image_name(image_config)): @@ -1229,7 +1230,7 @@ def __init__(self, subject, args): super(NativePropertiesBuildTask, self).__init__(args, 1, subject) self._contents = None self._location_classpath = None - graalvm_dist = get_final_graalvm_distribution() if self.subject.image_config.rebuildable else get_stage1_graalvm_distribution() + graalvm_dist = get_final_graalvm_distribution() if _rebuildable_image(self.subject.image_config) else get_stage1_graalvm_distribution() self._graalvm_location = graalvm_dist.find_single_source_location('dependency:' + self.subject.name) def newestOutput(self): @@ -1241,7 +1242,7 @@ def __str__(self): def _get_location_classpath(self): if self._location_classpath is None: image_config = self.subject.image_config - graalvm_dist = get_final_graalvm_distribution() if image_config.rebuildable else get_stage1_graalvm_distribution() + graalvm_dist = get_final_graalvm_distribution() if _rebuildable_image(image_config) else get_stage1_graalvm_distribution() self._location_classpath = NativePropertiesBuildTask.get_launcher_classpath(graalvm_dist, dirname(self._graalvm_location), image_config, self.subject.component, exclude_implicit=True) return self._location_classpath @@ -2572,6 +2573,11 @@ def create_archive(path, **_kw_args): if extra_installable_qualifiers: name += '_' + '_'.join(sorted(q.upper() for q in extra_installable_qualifiers)) name += '_JAVA{}'.format(_src_jdk_version) + + for component_ in [component] + extra_components: + for boot_jar in component_.boot_jars: + mx.warn("Component '{}' declares '{}' as 'boot_jar', which is ignored by the build process of the '{}' installable".format(component_.name, boot_jar, name)) + self.maven = _graalvm_maven_attributes(tag='installable') components = [component] if extra_components: @@ -3043,14 +3049,14 @@ def mx_register_dynamic_suite_constituents(register_project, register_distributi needs_stage1 = True if with_svm: register_project(GraalVmNativeProperties(component, launcher_config)) - if not launcher_config.rebuildable: + if not _rebuildable_image(launcher_config): with_non_rebuildable_configs = True for library_config in _get_library_configs(component): if with_svm: library_project = GraalVmLibrary(component, GraalVmNativeImage.project_name(library_config), [], library_config) register_project(library_project) register_project(GraalVmNativeProperties(component, library_config)) - if not library_config.rebuildable: + if not _rebuildable_image(library_config): with_non_rebuildable_configs = True if library_config.add_to_module: jmod_file = library_config.add_to_module + ('' if library_config.add_to_module.endswith('.jmod') else '.jmod') @@ -3491,7 +3497,12 @@ def graalvm_show(args, forced_graalvm_dist=None): profile_cnt = len(_image_profiles(GraalVmNativeProperties.canonical_image_name(launcher.native_image_config))) if profile_cnt > 0: suffix += " ({} pgo profile file{})".format(profile_cnt, 's' if profile_cnt > 1 else '') - print(" - {} ({}){}".format(launcher.native_image_name, "native" if launcher.is_native() else "bash", suffix)) + print(" - {name} ({native}, {rebuildable}){suffix}".format( + name=launcher.native_image_name, + native="native" if launcher.is_native() else "bash", + rebuildable="rebuildable" if _rebuildable_image(launcher.native_image_config) else "non-rebuildable", + suffix=suffix + )) else: print("No launcher") @@ -3499,13 +3510,21 @@ def graalvm_show(args, forced_graalvm_dist=None): if libraries and not args.stage1: print("Libraries:") for library in libraries: - suffix = '' + suffix = ' (' if library.is_skipped(): - suffix += " (skipped)" + suffix += "skipped, " + else: + suffix += "native, " + if _rebuildable_image(library.native_image_config): + suffix += "rebuildable)" + else: + suffix += "non-rebuildable)" profile_cnt = len(_image_profiles(GraalVmNativeProperties.canonical_image_name(library.native_image_config))) if profile_cnt > 0: suffix += " ({} pgo profile file{})".format(profile_cnt, 's' if profile_cnt > 1 else '') - print(" - {}{}".format(library.native_image_name, suffix)) + print(" - {name}{suffix}".format( + name=library.native_image_name, + suffix=suffix)) else: print("No library") @@ -3576,10 +3595,9 @@ def _str_to_bool(val): return val -def check_versions(jdk, graalvm_version_regex, expect_graalvm, check_jvmci): +def check_versions(jdk, expect_graalvm, check_jvmci): """ :type jdk: mx.JDKConfig | str - :type graalvm_version_regex: typing.Pattern :type expect_graalvm: bool :type check_jvmci: bool """ @@ -3599,14 +3617,8 @@ def check_versions(jdk, graalvm_version_regex, expect_graalvm, check_jvmci): if os.environ.get('JDK_VERSION_CHECK', None) != 'ignore' and (jdk_version <= mx.VersionSpec('1.8') or mx.VersionSpec('9') <= jdk_version < mx.VersionSpec('11')): mx.abort("GraalVM requires >=JDK11 as base-JDK, while the selected JDK ('{}') is '{}':\n{}\n\n{}.".format(jdk.home, jdk_version, out, check_env)) - if os.environ.get('GRAALVM_VERSION_CHECK', None) != 'ignore': - match = graalvm_version_regex.match(out) - if expect_graalvm and match is None: - mx.abort("'{}' is not a GraalVM. Its version string:\n{}\ndoes not match:\n{}".format(jdk.home, out, graalvm_version_regex.pattern)) - elif expect_graalvm and match.group('graalvm_version') != _suite.release_version(): - mx.abort("'{}' has a wrong GraalVM version:\n{}\nexpected:\n{}".format(jdk.home, match.group('graalvm_version'), _suite.release_version())) - elif not expect_graalvm and match: - mx.abort("GraalVM cannot be built using a GraalVM as base-JDK ('{}').\n{}.".format(jdk.home, check_env)) + if not expect_graalvm and "GraalVM" in out: + mx.abort("GraalVM cannot be built using a GraalVM as base-JDK ('{}').\n{}.".format(jdk.home, check_env)) def print_graalvm_vm_name(args): @@ -3630,9 +3642,7 @@ def graalvm_vendor_version(graalvm_dist): :type jdk_home: str :rtype str: """ - vendor_version = '{} {}'.format(graalvm_dist.base_name, graalvm_dist.vm_config_name.upper()) if graalvm_dist.vm_config_name else graalvm_dist.base_name - vendor_version += ' {}'.format(graalvm_version()) - return vendor_version + return 'Oracle GraalVM' if get_graalvm_edition() == 'ee' else 'GraalVM CE' # GR-37542 current debug info on darwin bloats binary (stripping to a separate .dSYM folder is not implemented) and @@ -3647,6 +3657,7 @@ def graalvm_vendor_version(graalvm_dist): 'This can be a comma-separated list of disabled components short names or `true` to disable all installables.', default=None) mx.add_argument('--debug-images', action='store_true', help='Build native images in debug mode: \'-O0\' and with \'-ea\'.') mx.add_argument('--native-images', action='store', help='Comma-separated list of launchers and libraries (syntax: LAUNCHER_NAME or lib:polyglot or suite:NAME) to build with Native Image.') +mx.add_argument('--non-rebuildable-images', action='store', help='Comma-separated list of launchers and libraries (syntax: LAUNCHER_NAME or lib:polyglot or suite:NAME) in the final GraalVM that cannot be rebuilt using Native Image.') mx.add_argument('--force-bash-launchers', action='store', help='Force the use of bash launchers instead of native images.' 'This can be a comma-separated list of disabled launchers or `true` to disable all native launchers.', default=None) mx.add_argument('--skip-libraries', action='store', help='Do not build native images for these libraries.' @@ -3967,12 +3978,34 @@ def _generate_debuginfo(image_config): return name in generate_debuginfo +def _rebuildable_image(image_config): + """ + :type image_config: mx_sdk.AbstractNativeImageConfig + :rtype: bool + """ + if isinstance(image_config, mx_sdk_vm.LauncherConfig): + name = _get_launcher_name(image_config) + elif isinstance(image_config, mx_sdk_vm.LibraryConfig): + name = 'lib:' + _get_library_name(image_config) + else: + raise mx.abort('Unknown image config type: {}'.format(type(image_config))) + + non_rebuildable = _parse_cmd_arg('non_rebuildable_images', default_value=str(False)) + non_rebuildable = _expand_native_images_list(non_rebuildable) + if isinstance(non_rebuildable, bool): + return not non_rebuildable + else: + return name not in non_rebuildable + + def _snapshot_catalog(): return mx.get_opts().snapshot_catalog or mx.get_env('SNAPSHOT_CATALOG') + def _gds_snapshot_catalog(): return mx.get_opts().gds_snapshot_catalog or mx.get_env('GDS_SNAPSHOT_CATALOG') + def _snapshot_product_id(): return mx.get_opts().snapshot_product_id or mx.get_env('SNAPSHOT_PRODUCT_ID') @@ -3980,6 +4013,7 @@ def _snapshot_product_id(): def _release_catalog(): return mx.get_opts().release_catalog or mx.get_env('RELEASE_CATALOG') + def _release_product_id(): return mx.get_opts().release_product_id or mx.get_env('RELEASE_PRODUCT_ID') diff --git a/sdk/mx.sdk/suite.py b/sdk/mx.sdk/suite.py index f70eb543fb80..6a020119f8b0 100644 --- a/sdk/mx.sdk/suite.py +++ b/sdk/mx.sdk/suite.py @@ -41,7 +41,7 @@ suite = { "mxversion": "6.17.0", "name" : "sdk", - "version" : "23.0.0", + "version" : "23.1.0", "release" : False, "sourceinprojectwhitelist" : [], "url" : "https://github.com/oracle/graal", diff --git a/sdk/src/org.graalvm.collections/snapshot.sigtest b/sdk/src/org.graalvm.collections/snapshot.sigtest index 31207e000f23..0eb31ba1f380 100644 --- a/sdk/src/org.graalvm.collections/snapshot.sigtest +++ b/sdk/src/org.graalvm.collections/snapshot.sigtest @@ -121,6 +121,7 @@ meth public {org.graalvm.collections.EconomicMapWrap%1} get({org.graalvm.collect meth public {org.graalvm.collections.EconomicMapWrap%1} put({org.graalvm.collections.EconomicMapWrap%0},{org.graalvm.collections.EconomicMapWrap%1}) meth public {org.graalvm.collections.EconomicMapWrap%1} putIfAbsent({org.graalvm.collections.EconomicMapWrap%0},{org.graalvm.collections.EconomicMapWrap%1}) meth public {org.graalvm.collections.EconomicMapWrap%1} removeKey({org.graalvm.collections.EconomicMapWrap%0}) +meth public java.lang.String toString() supr java.lang.Object hfds map @@ -169,6 +170,7 @@ innr public static ObjectPoolingAllocator meth public <%0 extends java.lang.Object> void topDown({%%0},java.util.function.BiFunction<{%%0},java.lang.Long,{%%0}>,java.util.function.BiConsumer<{%%0},java.lang.Long>) meth public org.graalvm.collections.LockFreePrefixTree$Allocator allocator() meth public org.graalvm.collections.LockFreePrefixTree$Node root() +meth public void reset() supr java.lang.Object hfds allocator,root hcls FailedAllocationException diff --git a/sdk/src/org.graalvm.collections/src/org/graalvm/collections/EconomicMapImpl.java b/sdk/src/org.graalvm.collections/src/org/graalvm/collections/EconomicMapImpl.java index 45103580a548..1595317f6512 100644 --- a/sdk/src/org.graalvm.collections/src/org/graalvm/collections/EconomicMapImpl.java +++ b/sdk/src/org.graalvm.collections/src/org/graalvm/collections/EconomicMapImpl.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 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 @@ -832,10 +832,13 @@ private Object getValue(int index) { @Override public String toString() { + return toString(isSet, size(), getEntries()); + } + + static String toString(boolean isSet, int size, MapCursor cursor) { StringBuilder builder = new StringBuilder(); - builder.append(isSet ? "set(size=" : "map(size=").append(size()).append(", {"); + builder.append(isSet ? "set(size=" : "map(size=").append(size).append(", {"); String sep = ""; - MapCursor cursor = getEntries(); while (cursor.advance()) { builder.append(sep); if (isSet) { diff --git a/sdk/src/org.graalvm.collections/src/org/graalvm/collections/EconomicMapWrap.java b/sdk/src/org.graalvm.collections/src/org/graalvm/collections/EconomicMapWrap.java index 57a7b9a3ec45..2a73e1987aea 100644 --- a/sdk/src/org.graalvm.collections/src/org/graalvm/collections/EconomicMapWrap.java +++ b/sdk/src/org.graalvm.collections/src/org/graalvm/collections/EconomicMapWrap.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. * * The Universal Permissive License (UPL), Version 1.0 @@ -168,4 +168,10 @@ public V setValue(V newValue) { public void replaceAll(BiFunction function) { map.replaceAll(function); } + + /** @since 23.1 */ + @Override + public String toString() { + return EconomicMapImpl.toString(false, size(), getEntries()); + } } diff --git a/sdk/src/org.graalvm.collections/src/org/graalvm/collections/LockFreePrefixTree.java b/sdk/src/org.graalvm.collections/src/org/graalvm/collections/LockFreePrefixTree.java index 8818bef39c7e..df45f0a63636 100644 --- a/sdk/src/org.graalvm.collections/src/org/graalvm/collections/LockFreePrefixTree.java +++ b/sdk/src/org.graalvm.collections/src/org/graalvm/collections/LockFreePrefixTree.java @@ -407,8 +407,8 @@ public String toString() { } } - private Allocator allocator; - private Node root; + private final Allocator allocator; + private volatile Node root; /** * Create new {@link LockFreePrefixTree} with root being a Node with key 0. @@ -435,6 +435,15 @@ public Node root() { return root; } + /** + * Resets the tree. + * + * @since 23.0 + */ + public void reset() { + root = allocator.newNode(0); + } + /** * Traverse the tree top-down while maintaining a context. * diff --git a/sdk/src/org.graalvm.launcher/src/org/graalvm/launcher/Launcher.java b/sdk/src/org.graalvm.launcher/src/org/graalvm/launcher/Launcher.java index 25b0cd5a1b32..417735ddd698 100644 --- a/sdk/src/org.graalvm.launcher/src/org/graalvm/launcher/Launcher.java +++ b/sdk/src/org.graalvm.launcher/src/org/graalvm/launcher/Launcher.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 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 @@ -852,7 +852,8 @@ void parsePolyglotOption(String defaultOptionPrefix, Map polyglo OptionDescriptor descriptor = findOptionDescriptor(group, key); if (descriptor == null) { if (defaultOptionPrefix != null) { - descriptor = findOptionDescriptor(defaultOptionPrefix, defaultOptionPrefix + "." + key); + key = defaultOptionPrefix + "." + key; + descriptor = findOptionDescriptor(defaultOptionPrefix, key); } if (descriptor == null) { throw abortUnrecognizedArgument(arg); @@ -878,8 +879,7 @@ void parsePolyglotOption(String defaultOptionPrefix, Map polyglo throw abort(String.format("Option '%s' is experimental and must be enabled via '--experimental-options'%n" + "Do not use experimental options in production environments.", arg)); } - // use the full name of the found descriptor - polyglotOptions.put(descriptor.getName(), value); + polyglotOptions.put(key, value); } private Set collectAllArguments() { diff --git a/substratevm/CHANGELOG.md b/substratevm/CHANGELOG.md index d71afc078b39..20102cd7c5fc 100644 --- a/substratevm/CHANGELOG.md +++ b/substratevm/CHANGELOG.md @@ -2,6 +2,9 @@ This changelog summarizes major changes to GraalVM Native Image. +## 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. + ## Version 23.0.0 * (GR-40187) Report invalid use of SVM specific classes on image class- or module-path as error. As a temporary workaround, `-H:+AllowDeprecatedBuilderClassesOnImageClasspath` allows turning the error into a warning. * (GR-41196) Provide `.debug.svm.imagebuild.*` sections that contain build options and properties used in the build of the image. @@ -29,6 +32,7 @@ This changelog summarizes major changes to GraalVM Native Image. * (GR-44110) Native Image now targets `x86-64-v3` by default on AMD64 and supports a new `-march` option. Use `-march=compatibility` for best compatibility (previous default) or `-march=native` for best performance if the native executable is deployed on the same machine or on a machine with the same CPU features. To list all available machine types, use `-march=list`. * (GR-43971) Add native-image option `-E[=]` and support environment variable capturing in bundles. Previously almost all environment variables were available in the builder. To temporarily revert back to the old behaviour, env setting `NATIVE_IMAGE_DEPRECATED_BUILDER_SANITATION=true` can be used. The old behaviour will be removed in a future release. * (GR-43382) The build output now includes a section with recommendations that help you get the best out of Native Image. +* (GR-44722) The output of `native-image --version` and various Java properties (e.g. `java.vm.version`) have been aligned with the OpenJDK. To distinguish between GraalVM CE, Oracle GraalVM, and GraalVM distributions from other vendors, please refer to `java.vm.vendor`. ## Version 22.3.0 * (GR-35721) Remove old build output style and the `-H:±BuildOutputUseNewStyle` option. diff --git a/substratevm/ci/ci.jsonnet b/substratevm/ci/ci.jsonnet index 199dd5acf3e7..4b8f3156610b 100644 --- a/substratevm/ci/ci.jsonnet +++ b/substratevm/ci/ci.jsonnet @@ -1,9 +1,10 @@ { + local gate_triggering_suites = ["sdk", "substratevm", "compiler", "truffle"], + local common = import "../../ci/ci_common/common.jsonnet", local util = import "../../ci/ci_common/common-utils.libsonnet", local tools = import "ci_common/tools.libsonnet", local sg = import "ci_common/svm-gate.libsonnet", - local inc = import "ci_common/include.libsonnet", local run_spec = import "../../ci/ci_common/run-spec.libsonnet", local exclude = run_spec.exclude, @@ -43,8 +44,6 @@ }, }), - local musl_toolchain = task_spec(inc.musl_dependency), - local mx_build_exploded = task_spec({ environment+: { MX_BUILD_EXPLODED: "true", # test native-image MX_BUILD_EXPLODED compatibility @@ -129,6 +128,6 @@ }, // END MAIN BUILD DEFINITION processed_builds::run_spec.process(task_dict), - builds: [{'defined_in': std.thisFile} + util.add_gate_predicate(b, sg.gate_triggering_suites) for b in self.processed_builds.list], + builds: [{'defined_in': std.thisFile} + util.add_gate_predicate(b, gate_triggering_suites) for b in self.processed_builds.list], assert tools.check_names($.builds), } diff --git a/substratevm/ci/ci_common/reports.jsonnet b/substratevm/ci/ci_common/reports.jsonnet index 7984d1dd895c..173b042d7f1c 100644 --- a/substratevm/ci/ci_common/reports.jsonnet +++ b/substratevm/ci/ci_common/reports.jsonnet @@ -1,10 +1,14 @@ local run_spec_tools = import "../../../ci/ci_common/run-spec-tools.libsonnet"; local ci = import "../ci.jsonnet"; +local std_get = (import "../../../ci/ci_common/common-utils.libsonnet").std_get; { + local get_gate_tags(spec) = + std.join(" ", std_get(spec, "mxgate_tags", [""])) + , // return a table of the target, convert to CSV using `jq -r ".[] | @csv"` // // convert to CSV: // jsonnet -e '(import "reports.jsonnet").targets' | jq -r ".[] | @csv" - targets::run_spec_tools.target_table(ci.processed_builds), - targets_with_variants::run_spec_tools.target_table(ci.processed_builds, with_variants=true), -} \ No newline at end of file + targets::run_spec_tools.target_table(ci.processed_builds, task_details_title="gate tags", task_details_factory=get_gate_tags), + targets_with_variants::run_spec_tools.target_table(ci.processed_builds, with_variants=true, task_details_title="gate tags", task_details_factory=get_gate_tags), +} diff --git a/substratevm/ci/ci_common/svm-gate.libsonnet b/substratevm/ci/ci_common/svm-gate.libsonnet index 03db9287c63a..bd8bf3a70e33 100644 --- a/substratevm/ci/ci_common/svm-gate.libsonnet +++ b/substratevm/ci/ci_common/svm-gate.libsonnet @@ -1,25 +1,23 @@ { local common = import "../../../ci/ci_common/common.jsonnet", - local tools = import "tools.libsonnet", local run_spec = import "../../../ci/ci_common/run-spec.libsonnet", local task_spec = run_spec.task_spec, local evaluate_late = run_spec.evaluate_late, - local _make_visible = tools._make_visible, + local make_visible = (import "../../../common-utils.libsonnet").make_visible, local t(limit) = task_spec({timelimit: limit}), - local require_musl = task_spec((import 'include.libsonnet').musl_dependency), + local require_musl = task_spec((import '../../../ci/ci_common/musl-common.libsonnet').musl_dependency), - local std_get = tools.std_get, - - gate_triggering_suites:: ["sdk", "substratevm", "compiler", "truffle"], + local std_get = (import "../../../common-utils.libsonnet").std_get, // mx gate build config - mxgate(tags, suite, suite_short=suite):: task_spec(common.disable_proxies + { + mxgate(tags, suite, suite_short=suite, enable_proxies=false):: task_spec((if !enable_proxies then common.disable_proxies else {}) + { mxgate_batch:: null, mxgate_tags:: std.split(tags, ","), mxgate_config:: [], mxgate_extra_args:: [], mxgate_dy:: [], + mxgate_target_arch:: null, setup+: [ ["cd", "./" + suite], ["mx", "hsdis", "||", "true"], @@ -30,6 +28,8 @@ local batch = outer.mxgate_batch, local config = outer.mxgate_config, local batch_suffix = if batch == null then "" else "_" + batch, + local target_arch = outer.mxgate_target_arch, + local target_arch_suffix = if target_arch == null then [] else [target_arch, "cross"], local dynamic_imports = if std.length(outer.mxgate_dy) == 0 then [] else ["--dy", std.join(",", outer.mxgate_dy)], // the outer assert just ensures that the expression is evaluated assert @@ -37,13 +37,12 @@ local _context = [outer[f] for f in ["build_name"] + _fields if std.objectHasAll(outer, f)]; _fields == [ // here is the actual check - assert std.objectHasAll(outer, f): "build object is missing field '%s' (context: %s) object:\n%s" % [f, _context, std.manifestJsonEx(_make_visible(outer), indent=" ")]; + assert std.objectHasAll(outer, f): "build object is missing field '%s' (context: %s) object:\n%s" % [f, _context, std.manifestJsonEx(make_visible(outer), indent=" ")]; f for f in _fields ], mxgate_name:: outer.task_name, - name: std.join("-", [outer.target, suite_short, self.mxgate_name] + config + ["jdk" + outer.jdk_version, outer.os, outer.arch]) + batch_suffix, - environment+: if batch == null then {} else {MX_SVMTEST_BATCH: batch}, + name: std.join("-", [outer.target, suite_short, self.mxgate_name] + config + ["jdk" + outer.jdk_version] + target_arch_suffix + [outer.os, outer.arch]) + batch_suffix, run+: [["mx", "--kill-with-sigquit", "--strict-compliance"] + dynamic_imports + ["gate", "--strict-mode", "--tags", std.join(",", outer.mxgate_tags)] + outer.mxgate_extra_args], } })), @@ -94,4 +93,25 @@ clone_js_benchmarks:: task_spec({ setup+: [["git", "clone", "--depth", "1", ["mx", "urlrewrite", "https://github.com/graalvm/js-benchmarks.git"], "../../js-benchmarks"]], }), + + riscv64_cross_compile:: task_spec({ + mxgate_target_arch:: "riscv64", + environment+: {CAPCACHE: "$HOME/capcache"}, + packages+: { + "git": ">=1.8.3", + "python": "==3.4.1", + "make": ">=3.83", + "zlib": ">=1.2.11", + "riscv-gnu-toolchain": "==8.3.0", + "qemu": ">=4.0.0", + "glib": "==2.56.1", + "pcre": "==8.43", + "sshpass": "==1.05" + }, + downloads+: { + QEMU_HOME : {name : "qemu-riscv64", version : "1.0"}, + C_LIBRARY_PATH : {name : "riscv-static-libraries", version : "1.0"}, + JAVA_HOME_RISCV : {name : "labsjdk", version : "ce-20+24-jvmci-23.0-b02-linux-riscv64" } + }, + }), } diff --git a/substratevm/mx.substratevm/mx_substratevm.py b/substratevm/mx.substratevm/mx_substratevm.py index c37cda06cbb5..c1248f1453d4 100644 --- a/substratevm/mx.substratevm/mx_substratevm.py +++ b/substratevm/mx.substratevm/mx_substratevm.py @@ -87,16 +87,6 @@ def adjusted_exports(line): return [adjusted_exports(line) for line in compiler_flags[str(version_tag)]] -def svm_unittest_config_participant(config): - vmArgs, mainClass, mainClassArgs = config - # Run the VM in a mode where application/test classes can - # access JVMCI loaded classes. - vmArgs = graal_compiler_flags() + vmArgs - return (vmArgs, mainClass, mainClassArgs) - -if mx.primary_suite() == suite: - mx_unittest.add_config_participant(svm_unittest_config_participant) - def classpath(args): if not args: return [] # safeguard against mx.classpath(None) behaviour @@ -1171,7 +1161,6 @@ def _native_image_launcher_extra_jvm_args(): build_args=libgraal_build_args + ['--features=com.oracle.svm.graal.hotspot.libgraal.LibGraalFeature'], add_to_module='java.base', headers=False, - rebuildable=False, ), ], stability="supported", @@ -1481,9 +1470,19 @@ def collector(line): else: mx.abort('gen_fallbacks not supported on ' + sys.platform) + seen_gnu_property_type_5_warnings = False + def suppress_gnu_property_type_5_warnings(line): + nonlocal seen_gnu_property_type_5_warnings + if 'unsupported GNU_PROPERTY_TYPE (5)' not in line: + mx.log_error(line.rstrip()) + elif not seen_gnu_property_type_5_warnings: + mx.log_error(line.rstrip()) + mx.log_error('(suppressing all further warnings about "unsupported GNU_PROPERTY_TYPE (5)")') + seen_gnu_property_type_5_warnings = True + for staticlib_path in self.staticlibs: mx.logv('Collect from : ' + staticlib_path) - mx.run(symbol_dump_command.split() + [staticlib_path], out=collect_symbols_fn('JVM_')) + mx.run(symbol_dump_command.split() + [staticlib_path], out=collect_symbols_fn('JVM_'), err=suppress_gnu_property_type_5_warnings) if len(symbols) == 0: mx.abort('Could not find any unresolved JVM_* symbols in static JDK libraries') diff --git a/substratevm/mx.substratevm/suite.py b/substratevm/mx.substratevm/suite.py index 2767facca013..5a400a0ff3c1 100644 --- a/substratevm/mx.substratevm/suite.py +++ b/substratevm/mx.substratevm/suite.py @@ -2,7 +2,7 @@ suite = { "mxversion": "6.17.0", "name": "substratevm", - "version" : "23.0.0", + "version" : "23.1.0", "release" : False, "url" : "https://github.com/oracle/graal/tree/master/substratevm", @@ -30,9 +30,6 @@ { "name": "compiler", "subdir": True, - "urls" : [ - {"url" : "https://curio.ssw.jku.at/nexus/content/repositories/snapshots", "kind" : "binary"}, - ] }, ] }, @@ -621,6 +618,7 @@ ], "requiresConcealed" : { "java.base" : [ + "jdk.internal", "jdk.internal.event", "jdk.internal.misc", "jdk.internal.vm.annotation", 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 6060d6824814..30a396a061fa 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 @@ -499,7 +499,7 @@ public static class OtherReason extends ScanReason { final String reason; - protected OtherReason(String reason) { + public OtherReason(String reason) { super(null, null); this.reason = reason; } 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 0e2fd499e9a4..36d3840b398c 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 @@ -113,6 +113,7 @@ import org.graalvm.nativeimage.AnnotationAccess; import com.oracle.graal.pointsto.AbstractAnalysisEngine; +import com.oracle.graal.pointsto.ObjectScanner.EmbeddedRootScan; import com.oracle.graal.pointsto.PointsToAnalysis; import com.oracle.graal.pointsto.api.PointstoOptions; import com.oracle.graal.pointsto.flow.LoadFieldTypeFlow.LoadInstanceFieldTypeFlow; @@ -546,8 +547,10 @@ private void createTypeFlow() { AnalysisType type = (AnalysisType) StampTool.typeOrNull(node, bb.getMetaAccess()); assert type.isInstantiated(); TypeFlowBuilder sourceBuilder = TypeFlowBuilder.create(bb, node, ConstantTypeFlow.class, () -> { - JavaConstant heapConstant = bb.getUniverse().getHeapScanner().toImageHeapObject(node.asJavaConstant()); - ConstantTypeFlow constantSource = new ConstantTypeFlow(AbstractAnalysisEngine.sourcePosition(node), type, TypeState.forConstant(this.bb, heapConstant, type)); + JavaConstant constantValue = node.asJavaConstant(); + BytecodePosition position = AbstractAnalysisEngine.sourcePosition(node); + JavaConstant heapConstant = bb.getUniverse().getHeapScanner().toImageHeapObject(constantValue, new EmbeddedRootScan(position, constantValue)); + ConstantTypeFlow constantSource = new ConstantTypeFlow(position, type, TypeState.forConstant(this.bb, heapConstant, type)); flowsGraph.addMiscEntryFlow(constantSource); return constantSource; }); 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 1019c5a42fb3..7bf3258c850b 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 @@ -206,7 +206,7 @@ public boolean forNullArrayElement(JavaConstant array, AnalysisType arrayType, i @Override public boolean forNonNullArrayElement(JavaConstant array, AnalysisType arrayType, JavaConstant elementValue, AnalysisType elementType, int index, ScanReason reason) { - ImageHeapArray arrayObject = (ImageHeapArray) getReceiverObject(array, reason); + ImageHeapObjectArray arrayObject = (ImageHeapObjectArray) getReceiverObject(array, reason); Object elementValueTask = arrayObject.getElement(index); if (elementValueTask instanceof JavaConstant elementSnapshot) { verifyArrayElementValue(elementValue, index, reason, arrayObject, elementSnapshot); @@ -226,7 +226,7 @@ public boolean forNonNullArrayElement(JavaConstant array, AnalysisType arrayType return false; } - private void verifyArrayElementValue(JavaConstant elementValue, int index, ScanReason reason, ImageHeapArray arrayObject, JavaConstant elementSnapshot) { + private void verifyArrayElementValue(JavaConstant elementValue, int index, ScanReason reason, ImageHeapObjectArray arrayObject, JavaConstant elementSnapshot) { if (!Objects.equals(maybeUnwrapSnapshot(elementSnapshot, elementValue instanceof ImageHeapConstant), elementValue)) { Consumer onAnalysisModified = (deepReason) -> onArrayElementMismatch(elementSnapshot, elementValue, deepReason); scanner.patchArrayElement(arrayObject, index, elementValue, reason, onAnalysisModified).ensureDone(); @@ -236,6 +236,10 @@ private void verifyArrayElementValue(JavaConstant elementValue, int index, ScanR @SuppressWarnings({"unchecked", "rawtypes"}) private ImageHeapConstant getReceiverObject(JavaConstant constant, ScanReason reason) { + if (constant instanceof ImageHeapConstant) { + /* This is a simulated constant. */ + return (ImageHeapConstant) constant; + } Object task = imageHeap.getSnapshot(constant); if (task == null) { throw error(reason, "Task is null for constant %s.", constant); @@ -275,10 +279,6 @@ public void forEmbeddedRoot(JavaConstant root, ScanReason reason) { * Since embedded constants or constants reachable when scanning from roots can also be * 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. - * Moreover, since embedded ImageHeapObject can reference JavaConstant values directly (see - * the comment in - * {@link ImageHeapScanner#convertInjectedConstant(ImageHeapConstant, ScanReason)} for - * details why that happens), then the 'snapshot' itself can be a JavaConstant. */ private JavaConstant maybeUnwrapSnapshot(JavaConstant snapshot, boolean asImageHeapObject) { if (snapshot instanceof ImageHeapConstant) { diff --git a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/heap/ImageHeapArray.java b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/heap/ImageHeapArray.java index 7a45a8552154..d6c0b065dcf6 100644 --- a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/heap/ImageHeapArray.java +++ b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/heap/ImageHeapArray.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,100 +24,19 @@ */ package com.oracle.graal.pointsto.heap; -import java.lang.invoke.MethodHandles; -import java.lang.invoke.VarHandle; -import java.util.function.Consumer; - -import com.oracle.graal.pointsto.ObjectScanner; -import com.oracle.graal.pointsto.meta.AnalysisType; -import com.oracle.graal.pointsto.util.AnalysisFuture; - import jdk.vm.ci.meta.JavaConstant; import jdk.vm.ci.meta.ResolvedJavaType; -public final class ImageHeapArray extends ImageHeapConstant { - - private static final VarHandle arrayHandle = MethodHandles.arrayElementVarHandle(Object[].class); - - /** - * Stores either an {@link AnalysisFuture} of {@link JavaConstant} or its result, a - * {@link JavaConstant}, indexed by array index. - */ - private final Object[] arrayElementValues; +public abstract class ImageHeapArray extends ImageHeapConstant { - public ImageHeapArray(ResolvedJavaType type, int length) { - this(type, null, new Object[length]); - } - - public ImageHeapArray(ResolvedJavaType type, JavaConstant object, int length) { - this(type, object, new Object[length]); - } - - ImageHeapArray(ResolvedJavaType type, JavaConstant object, Object[] arrayElementValues) { - this(type, object, arrayElementValues, createIdentityHashCode(object), false); - } - - private ImageHeapArray(ResolvedJavaType type, JavaConstant object, Object[] arrayElementValues, int identityHashCode, boolean compressed) { + protected ImageHeapArray(ResolvedJavaType type, JavaConstant object, int identityHashCode, boolean compressed) { super(type, object, identityHashCode, compressed); assert type.isArray(); - this.arrayElementValues = arrayElementValues; } - /** - * Return the value of the element at the specified index as computed by - * {@link ImageHeapScanner#onArrayElementReachable(ImageHeapArray, AnalysisType, JavaConstant, int, ObjectScanner.ScanReason, Consumer)}. - */ - public Object getElement(int idx) { - return arrayHandle.getVolatile(this.arrayElementValues, idx); - } + public abstract Object getElement(int idx); - /** - * Returns the element value, i.e., a {@link JavaConstant}. If the value is not yet materialized - * then the future is executed on the current thread. - */ - @SuppressWarnings({"unchecked", "rawtypes"}) - public JavaConstant readElementValue(int index) { - Object value = getElement(index); - return value instanceof JavaConstant ? (JavaConstant) value : ((AnalysisFuture) value).ensureDone(); - } + public abstract JavaConstant readElementValue(int index); - public void setElement(int idx, JavaConstant value) { - arrayHandle.setVolatile(this.arrayElementValues, idx, value); - } - - public void setElementTask(int idx, AnalysisFuture task) { - arrayHandle.setVolatile(this.arrayElementValues, idx, task); - } - - public int getLength() { - return arrayElementValues.length; - } - - @Override - public JavaConstant compress() { - assert !compressed; - return new ImageHeapArray(type, hostedObject, arrayElementValues, identityHashCode, true); - } - - @Override - public JavaConstant uncompress() { - assert compressed; - return new ImageHeapArray(type, hostedObject, arrayElementValues, identityHashCode, false); - } - - @Override - public boolean equals(Object o) { - if (o instanceof ImageHeapArray) { - return super.equals(o) && this.arrayElementValues == ((ImageHeapArray) o).arrayElementValues; - } - return false; - } - - @Override - public int hashCode() { - final int prime = 31; - int result = super.hashCode(); - result = prime * result + System.identityHashCode(arrayElementValues); - return result; - } + public abstract int getLength(); } diff --git a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/heap/ImageHeapObjectArray.java b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/heap/ImageHeapObjectArray.java new file mode 100644 index 000000000000..a13581d9ae0a --- /dev/null +++ b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/heap/ImageHeapObjectArray.java @@ -0,0 +1,126 @@ +/* + * 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.graal.pointsto.heap; + +import java.lang.invoke.MethodHandles; +import java.lang.invoke.VarHandle; +import java.util.function.Consumer; + +import com.oracle.graal.pointsto.ObjectScanner; +import com.oracle.graal.pointsto.meta.AnalysisType; +import com.oracle.graal.pointsto.util.AnalysisFuture; + +import jdk.vm.ci.meta.JavaConstant; +import jdk.vm.ci.meta.ResolvedJavaType; + +public final class ImageHeapObjectArray extends ImageHeapArray { + + private static final VarHandle arrayHandle = MethodHandles.arrayElementVarHandle(Object[].class); + + /** + * Stores either an {@link AnalysisFuture} of {@link JavaConstant} or its result, a + * {@link JavaConstant}, indexed by array index. + */ + private final Object[] arrayElementValues; + + public ImageHeapObjectArray(ResolvedJavaType type, int length) { + this(type, null, new Object[length]); + } + + public ImageHeapObjectArray(ResolvedJavaType type, JavaConstant object, int length) { + this(type, object, new Object[length]); + } + + ImageHeapObjectArray(ResolvedJavaType type, JavaConstant object, Object[] arrayElementValues) { + this(type, object, arrayElementValues, createIdentityHashCode(object), false); + } + + private ImageHeapObjectArray(ResolvedJavaType type, JavaConstant object, Object[] arrayElementValues, int identityHashCode, boolean compressed) { + super(type, object, identityHashCode, compressed); + assert type.isArray(); + this.arrayElementValues = arrayElementValues; + } + + /** + * Return the value of the element at the specified index as computed by + * {@link ImageHeapScanner#onArrayElementReachable(ImageHeapArray, AnalysisType, JavaConstant, int, ObjectScanner.ScanReason, Consumer)}. + */ + @Override + public Object getElement(int idx) { + return arrayHandle.getVolatile(this.arrayElementValues, idx); + } + + /** + * Returns the element value, i.e., a {@link JavaConstant}. If the value is not yet materialized + * then the future is executed on the current thread. + */ + @Override + @SuppressWarnings({"unchecked", "rawtypes"}) + public JavaConstant readElementValue(int index) { + Object value = getElement(index); + return value instanceof JavaConstant ? (JavaConstant) value : ((AnalysisFuture) value).ensureDone(); + } + + public void setElement(int idx, JavaConstant value) { + arrayHandle.setVolatile(this.arrayElementValues, idx, value); + } + + public void setElementTask(int idx, AnalysisFuture task) { + arrayHandle.setVolatile(this.arrayElementValues, idx, task); + } + + @Override + public int getLength() { + return arrayElementValues.length; + } + + @Override + public JavaConstant compress() { + assert !compressed; + return new ImageHeapObjectArray(type, hostedObject, arrayElementValues, identityHashCode, true); + } + + @Override + public JavaConstant uncompress() { + assert compressed; + return new ImageHeapObjectArray(type, hostedObject, arrayElementValues, identityHashCode, false); + } + + @Override + public boolean equals(Object o) { + if (o instanceof ImageHeapObjectArray) { + return super.equals(o) && this.arrayElementValues == ((ImageHeapObjectArray) o).arrayElementValues; + } + return false; + } + + @Override + public int hashCode() { + final int prime = 31; + int result = super.hashCode(); + result = prime * result + System.identityHashCode(arrayElementValues); + return result; + } +} diff --git a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/heap/ImageHeapPrimitiveArray.java b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/heap/ImageHeapPrimitiveArray.java new file mode 100644 index 000000000000..f7ac93b8b1ae --- /dev/null +++ b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/heap/ImageHeapPrimitiveArray.java @@ -0,0 +1,117 @@ +/* + * 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.heap; + +import java.lang.reflect.Array; +import java.util.function.Consumer; + +import com.oracle.graal.pointsto.ObjectScanner; +import com.oracle.graal.pointsto.meta.AnalysisType; + +import jdk.vm.ci.meta.JavaConstant; +import jdk.vm.ci.meta.JavaKind; +import jdk.vm.ci.meta.ResolvedJavaType; + +public final class ImageHeapPrimitiveArray extends ImageHeapArray { + + private final Object array; + private final int length; + + ImageHeapPrimitiveArray(ResolvedJavaType type, JavaConstant object, Object array, int length) { + this(type, object, array, createIdentityHashCode(object), false, length); + } + + private ImageHeapPrimitiveArray(ResolvedJavaType type, JavaConstant object, Object arrayObject, int identityHashCode, boolean compressed, int length) { + super(type, object, identityHashCode, compressed); + assert type.isArray() && type.getComponentType().isPrimitive(); + this.array = getClone(type.getComponentType().getJavaKind(), arrayObject); + this.length = length; + } + + private static Object getClone(JavaKind kind, Object arrayObject) { + return switch (kind) { + case Boolean -> ((boolean[]) arrayObject).clone(); + case Byte -> ((byte[]) arrayObject).clone(); + case Short -> ((short[]) arrayObject).clone(); + case Char -> ((char[]) arrayObject).clone(); + case Int -> ((int[]) arrayObject).clone(); + case Long -> ((long[]) arrayObject).clone(); + case Float -> ((float[]) arrayObject).clone(); + case Double -> ((double[]) arrayObject).clone(); + default -> throw new IllegalArgumentException("Unsupported kind: " + kind); + }; + } + + public Object getArray() { + return array; + } + + /** + * Return the value of the element at the specified index as computed by + * {@link ImageHeapScanner#onArrayElementReachable(ImageHeapArray, AnalysisType, JavaConstant, int, ObjectScanner.ScanReason, Consumer)}. + */ + @Override + public Object getElement(int idx) { + return Array.get(array, idx); + } + + @Override + public JavaConstant readElementValue(int idx) { + return JavaConstant.forBoxedPrimitive(getElement(idx)); + } + + @Override + public int getLength() { + return length; + } + + @Override + public JavaConstant compress() { + assert !compressed; + return new ImageHeapPrimitiveArray(type, hostedObject, array, identityHashCode, true, length); + } + + @Override + public JavaConstant uncompress() { + assert compressed; + return new ImageHeapPrimitiveArray(type, hostedObject, array, identityHashCode, false, length); + } + + @Override + public boolean equals(Object o) { + if (o instanceof ImageHeapPrimitiveArray) { + return super.equals(o) && this.array == ((ImageHeapPrimitiveArray) o).array; + } + return false; + } + + @Override + public int hashCode() { + final int prime = 31; + int result = super.hashCode(); + result = prime * result + System.identityHashCode(array); + return result; + } +} 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 f9884525978a..0bb6433dc647 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 @@ -48,6 +48,7 @@ import com.oracle.graal.pointsto.api.HostVM; import com.oracle.graal.pointsto.constraints.UnsupportedFeatureException; 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; @@ -76,8 +77,6 @@ */ public abstract class ImageHeapScanner { - private static final JavaConstant[] emptyConstantArray = new JavaConstant[0]; - protected final BigBang bb; protected final ImageHeap imageHeap; protected final AnalysisMetaAccess metaAccess; @@ -138,7 +137,7 @@ private void onInstanceFieldRead(AnalysisField field, AnalysisType type, FieldSc for (ImageHeapConstant imageHeapConstant : imageHeap.getReachableObjects(subtype)) { ImageHeapInstance imageHeapInstance = (ImageHeapInstance) imageHeapConstant; JavaConstant fieldValue = imageHeapInstance.readFieldValue(field); - markFieldReachable(fieldValue, reason); + markReachable(fieldValue, reason); notifyAnalysis(field, imageHeapInstance, fieldValue, reason); } /* Subtypes include this type itself. */ @@ -189,11 +188,7 @@ JavaConstant createImageHeapConstant(JavaConstant constant, ScanReason reason) { return constant; } - public ImageHeapConstant toImageHeapObject(JavaConstant constant) { - return toImageHeapObject(constant, OtherReason.RESCAN); - } - - protected ImageHeapConstant toImageHeapObject(JavaConstant constant, ScanReason reason) { + public ImageHeapConstant toImageHeapObject(JavaConstant constant, ScanReason reason) { assert constant != null && isNonNullObjectConstant(constant); return markReachable(getOrCreateImageHeapConstant(constant, reason), reason, null); } @@ -209,7 +204,6 @@ protected ImageHeapConstant getOrCreateImageHeapConstant(JavaConstant javaConsta if (javaConstant instanceof ImageHeapConstant imageHeapConstant) { /* This must be a simulated constant. */ assert imageHeapConstant.getHostedObject() == null; - convertInjectedConstant(imageHeapConstant, reason); imageHeap.setValue(javaConstant, imageHeapConstant); existingTask = javaConstant; } else { @@ -228,84 +222,6 @@ protected ImageHeapConstant getOrCreateImageHeapConstant(JavaConstant javaConsta return existingTask instanceof ImageHeapConstant ? (ImageHeapConstant) existingTask : ((AnalysisFuture) existingTask).ensureDone(); } - /** - * Convert injected heap objects, i.e., heap objects that do not originate from scanning - * underlying hosted constants. Replace the raw array and field values with futures that create - * {@link ImageHeapConstant}s on demand. - */ - protected void convertInjectedConstant(ImageHeapConstant object, ScanReason reason) { - assert object.getJavaKind() == JavaKind.Object && !object.isNull(); - - AnalysisType type = (AnalysisType) object.getType(metaAccess); - - if (type.isArray()) { - if (!type.getComponentType().isPrimitive()) { - ImageHeapArray array = (ImageHeapArray) object; - ScanReason arrayReason = new ArrayScan(type, object, reason); - for (int idx = 0; idx < array.getLength(); idx++) { - final JavaConstant elementValue = (JavaConstant) array.getElement(idx); - int finalIdx = idx; - array.setElementTask(idx, new AnalysisFuture<>(() -> { - createImageHeapConstant(elementValue, arrayReason); - array.setElement(finalIdx, elementValue); - return elementValue; - })); - } - } - } else { - ImageHeapInstance instance = (ImageHeapInstance) object; - /* We are about to query the type's fields, the type must be marked as reachable. */ - type.registerAsReachable(reason); - for (ResolvedJavaField javaField : type.getInstanceFields(true)) { - AnalysisField field = (AnalysisField) javaField; - /* - * Replace the constant value a future that will scan it when the field is marked as - * reachable. - */ - final JavaConstant originalFieldValue = (JavaConstant) instance.getFieldValue(field); - if (isNonNullObjectConstant(originalFieldValue)) { - instance.setFieldTask(field, new AnalysisFuture<>(() -> { - /* - * After scanning a field of an injected ImageHeapInstance that references a - * regular JavaConstant object, should the field value be replaced with the - * snapshot version, i.e., an ImageHeapInstance, or should it keep pointing - * to the original value? In the long term it should be replaced, but that's - * not yet generally possible. First ImageHeapInstance needs to have - * complete support for all use cases, it needs to be a complete replacement - * for JavaConstant. For example, it needs to be able to efficiently - * represent string values and be able to extract the String object. - * - * So for now we just reinstall the original JavaConstant value when the - * future is completed. When the field is marked as read the - * ImageHeapConstant is accessed via the image heap cache and scanned (see - * markFieldReachable()). - * - * More specifically, the long term plan is that after scanning - * instance.field will refer to the `scannedFieldValue`, so any future read - * of `instance.field` will return an ImageHeapInstance. Moreover, - * `instance` is also reached when scanning from roots for verification. In - * that case, if we do set the field to the value returned by - * `createFieldValue()`, i.e., an ImageHeapInstance, then we also need to - * register a mapping in the heap for the snapshot: scannedFieldValue -> - * scannedFieldValue. Otherwise, we only have the originalFieldValue -> - * scannedFieldValue mapping and a lookup of scannedFieldValue will fail - * during verification. See the snippet below for details. - */ - // @formatter:off - // JavaConstant value = createFieldValue(field, instance, ValueSupplier.eagerValue(originalFieldValue), fieldReason); - // instance.setFieldValue(field, value); - // imageHeap.setValue(originalFieldValue, (ImageHeapConstant) value); - // @formatter:on - ScanReason fieldReason = new FieldScan(field, instance, reason); - createFieldValue(field, instance, ValueSupplier.eagerValue(originalFieldValue), fieldReason); - instance.setFieldValue(field, originalFieldValue); - return originalFieldValue; - })); - } - } - } - } - /** * Create the ImageHeapConstant object wrapper, capture the hosted state of fields and arrays, * and install a future that can process them. @@ -335,17 +251,14 @@ protected ImageHeapConstant createImageHeapObject(JavaConstant constant, ScanRea ImageHeapConstant newImageHeapConstant; if (type.isArray()) { + Integer length = constantReflection.readArrayLength(constant); if (type.getComponentType().isPrimitive()) { - /* - * The shadow heap is only used for points-to analysis currently, we don't need to - * track individual elements for primitive arrays. - */ - newImageHeapConstant = new ImageHeapArray(type, constant, emptyConstantArray); + newImageHeapConstant = new ImageHeapPrimitiveArray(type, constant, asObject(constant), length); } else { - newImageHeapConstant = createImageHeapArray(constant, reason, type); + newImageHeapConstant = createImageHeapObjectArray(constant, type, length, reason); } } else { - newImageHeapConstant = createImageHeapInstance(constant, reason, type); + newImageHeapConstant = createImageHeapInstance(constant, type, reason); AnalysisType typeFromClassConstant = (AnalysisType) constantReflection.asJavaType(constant); if (typeFromClassConstant != null) { typeFromClassConstant.registerAsReachable(reason); @@ -354,9 +267,8 @@ protected ImageHeapConstant createImageHeapObject(JavaConstant constant, ScanRea return newImageHeapConstant; } - private ImageHeapArray createImageHeapArray(JavaConstant constant, ScanReason reason, AnalysisType type) { - int length = constantReflection.readArrayLength(constant); - ImageHeapArray array = new ImageHeapArray(type, constant, length); + private ImageHeapArray createImageHeapObjectArray(JavaConstant constant, AnalysisType type, int length, ScanReason reason) { + ImageHeapObjectArray array = new ImageHeapObjectArray(type, constant, length); ScanReason arrayReason = new ArrayScan(type, constant, reason); for (int idx = 0; idx < length; idx++) { final JavaConstant rawElementValue = constantReflection.readArrayElement(constant, idx); @@ -370,7 +282,7 @@ private ImageHeapArray createImageHeapArray(JavaConstant constant, ScanReason re return array; } - private ImageHeapInstance createImageHeapInstance(JavaConstant constant, ScanReason reason, AnalysisType type) { + private ImageHeapInstance createImageHeapInstance(JavaConstant constant, AnalysisType type, ScanReason reason) { /* We are about to query the type's fields, the type must be marked as reachable. */ type.registerAsReachable(reason); ResolvedJavaField[] instanceFields = type.getInstanceFields(true); @@ -395,7 +307,7 @@ private ImageHeapInstance createImageHeapInstance(JavaConstant constant, ScanRea } private Optional maybeReplace(JavaConstant constant, ScanReason reason) { - Object unwrapped = unwrapObject(constant); + Object unwrapped = snippetReflection.asObject(Object.class, constant); if (unwrapped == null) { throw GraalError.shouldNotReachHere(formatReason("Could not unwrap constant", reason)); // ExcludeFromJacocoGeneratedReport } else if (unwrapped instanceof ImageHeapConstant) { @@ -419,10 +331,6 @@ private Optional maybeReplace(JavaConstant constant, ScanReason re return Optional.empty(); } - protected Object unwrapObject(JavaConstant constant) { - return snippetReflection.asObject(Object.class, constant); - } - JavaConstant onFieldValueReachable(AnalysisField field, JavaConstant fieldValue, ScanReason reason, Consumer onAnalysisModified) { return onFieldValueReachable(field, null, ValueSupplier.eagerValue(fieldValue), reason, onAnalysisModified); } @@ -512,10 +420,10 @@ private void notifyAnalysis(ImageHeapArray array, AnalysisType arrayType, int el } private boolean isNonNullObjectConstant(JavaConstant constant) { - return constant.getJavaKind() == JavaKind.Object && constant.isNonNull() && !isWordType(constant); + return constant.getJavaKind() == JavaKind.Object && constant.isNonNull() && !isWordType(constant, metaAccess); } - private boolean isWordType(JavaConstant rawElementValue) { + public static boolean isWordType(JavaConstant rawElementValue, UniverseMetaAccess metaAccess) { return metaAccess.isInstanceOf(rawElementValue, WordBase.class); } @@ -524,7 +432,7 @@ private boolean notifyAnalysis(JavaConstant array, AnalysisType arrayType, JavaC if (elementValue.isNull()) { analysisModified = scanningObserver.forNullArrayElement(array, arrayType, elementIndex, reason); } else { - if (isWordType(elementValue)) { + if (isWordType(elementValue, metaAccess)) { return false; } AnalysisType elementType = metaAccess.lookupJavaType(elementValue); @@ -557,7 +465,7 @@ protected void onObjectReachable(ImageHeapConstant imageHeapConstant, ScanReason imageHeap.addReachableObject(objectType, imageHeapConstant); markTypeInstantiated(objectType, reason); - if (imageHeapConstant instanceof ImageHeapArray imageHeapArray) { + if (imageHeapConstant instanceof ImageHeapObjectArray imageHeapArray) { for (int idx = 0; idx < imageHeapArray.getLength(); idx++) { JavaConstant elementValue = imageHeapArray.readElementValue(idx); markReachable(elementValue, reason, onAnalysisModified); @@ -568,38 +476,13 @@ protected void onObjectReachable(ImageHeapConstant imageHeapConstant, ScanReason AnalysisField field = (AnalysisField) javaField; if (field.isRead() && isValueAvailable(field)) { JavaConstant fieldValue = imageHeapInstance.readFieldValue(field); - markFieldReachable(fieldValue, reason, onAnalysisModified); + markReachable(fieldValue, reason, onAnalysisModified); notifyAnalysis(field, imageHeapInstance, fieldValue, reason, onAnalysisModified); } } } } - private void markFieldReachable(JavaConstant fieldValue, ScanReason reason) { - markFieldReachable(fieldValue, reason, null); - } - - private void markFieldReachable(JavaConstant fieldValue, ScanReason reason, Consumer onAnalysisModified) { - if (isNonNullObjectConstant(fieldValue)) { - if (fieldValue instanceof ImageHeapConstant) { - markReachable(fieldValue, reason, onAnalysisModified); - } else { - /* - * This is a field of an injected constant which points to the original - * JavaConstant. Since this object is already injected in the graphs it survives - * after the analysis, so it needs to support features not yet implemented by - * ImageHeapConstant, e.g., primitive arrays and efficient String representation. - * For more details see the comments in convertInjectedConstant(). Here we just get - * the snapshot value from the image heap cache and scan it. - */ - Object snapshot = imageHeap.getSnapshot(fieldValue); - if (snapshot != null) { - markReachable((JavaConstant) snapshot, reason, onAnalysisModified); - } - } - } - } - public boolean isValueAvailable(@SuppressWarnings("unused") AnalysisField field) { return true; } @@ -625,7 +508,7 @@ protected boolean skipScanning() { * triggered the re-scanning. * * In the (legacy) Feature.duringAnalysis state, the executor is not running and we must not - * schedule new tasks, because that would be treated as "the analysis has not finsihed yet". So + * schedule new tasks, because that would be treated as "the analysis has not finished yet". So * in that case we execute the task directly. */ private void maybeRunInExecutor(CompletionExecutor.DebugContextRunnable task) { @@ -675,7 +558,7 @@ public void rescanField(Object receiver, Field reflectionField) { } JavaConstant fieldValue = readHostedFieldValue(field, universe.toHosted(receiverConstant)).get(); if (fieldValue != null) { - ImageHeapInstance receiverObject = (ImageHeapInstance) toImageHeapObject(receiverConstant); + ImageHeapInstance receiverObject = (ImageHeapInstance) toImageHeapObject(receiverConstant, OtherReason.RESCAN); AnalysisFuture fieldTask = patchInstanceField(receiverObject, field, fieldValue, OtherReason.RESCAN, null); if (field.isRead() || field.isFolded()) { rescanCollectionElements(fieldTask.ensureDone()); @@ -706,7 +589,7 @@ protected AnalysisFuture patchInstanceField(ImageHeapInstance rece return task; } - protected AnalysisFuture patchArrayElement(ImageHeapArray arrayObject, int index, JavaConstant elementValue, ScanReason reason, + protected AnalysisFuture patchArrayElement(ImageHeapObjectArray arrayObject, int index, JavaConstant elementValue, ScanReason reason, Consumer onAnalysisModified) { AnalysisFuture task = new AnalysisFuture<>(() -> { JavaConstant value = onArrayElementReachable(arrayObject, (AnalysisType) arrayObject.getType(metaAccess), elementValue, index, reason, onAnalysisModified); 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 c651b13a41c7..aafe9a94c9c2 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 @@ -55,7 +55,7 @@ public ResolvedJavaType apply(Class clazz) { } }; protected final Universe universe; - private final MetaAccessProvider wrapped; + protected final MetaAccessProvider wrapped; public UniverseMetaAccess(Universe universe, MetaAccessProvider wrapped) { this.universe = universe; 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 4dc96f62894c..27317b42499c 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 @@ -45,7 +45,7 @@ public final class SerialAndEpsilonGCOptions { public static final RuntimeOptionKey MaximumYoungGenerationSizePercent = new NotifyGCRuntimeOptionKey<>(10, SerialAndEpsilonGCOptions::serialOrEpsilonGCOnly); @Option(help = "The size of an aligned chunk. Serial and epsilon GC only.", type = OptionType.Expert) // - public static final HostedOptionKey AlignedHeapChunkSize = new HostedOptionKey<>(1L * 1024L * 1024L, SerialAndEpsilonGCOptions::serialOrEpsilonGCOnly) { + public static final HostedOptionKey AlignedHeapChunkSize = new HostedOptionKey<>(512 * 1024L, SerialAndEpsilonGCOptions::serialOrEpsilonGCOnly) { @Override protected void onValueUpdate(EconomicMap, Object> values, Long oldValue, Long newValue) { int multiple = 4096; @@ -57,7 +57,7 @@ protected void onValueUpdate(EconomicMap, Object> values, Long oldV * This should be a fraction of the size of an aligned chunk, else large small arrays will not * fit in an aligned chunk. */ - @Option(help = "The size at or above which an array will be allocated in its own unaligned chunk. 0 implies (AlignedHeapChunkSize / 8). Serial and epsilon GC only.", type = OptionType.Expert) // + @Option(help = "The size at or above which an array will be allocated in its own unaligned chunk. Serial and epsilon GC only.", type = OptionType.Expert) // public static final HostedOptionKey LargeArrayThreshold = new HostedOptionKey<>(0L, SerialAndEpsilonGCOptions::serialOrEpsilonGCOnly); @Option(help = "Fill unused memory chunks with a sentinel value. Serial and epsilon GC only.", type = OptionType.Debug) // 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 5265faea3326..e8acc824eb4f 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 @@ -913,10 +913,6 @@ public void returned(CompilationResultBuilder crb) { crb.recordMark(SubstrateMarkId.EPILOGUE_END); } - @Override - public boolean hasFrame() { - 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 76262e88a13c..daadc2f1be0e 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 @@ -35,6 +35,7 @@ import java.util.function.BiConsumer; import org.graalvm.compiler.api.replacements.Fold; +import org.graalvm.compiler.api.replacements.SnippetReflectionProvider; import org.graalvm.compiler.asm.Label; import org.graalvm.compiler.asm.amd64.AMD64Address; import org.graalvm.compiler.asm.amd64.AMD64Assembler; @@ -43,6 +44,7 @@ import org.graalvm.compiler.core.common.Stride; import org.graalvm.compiler.debug.GraalError; import org.graalvm.compiler.lir.asm.CompilationResultBuilder; +import org.graalvm.compiler.phases.util.Providers; import org.graalvm.nativeimage.ImageSingletons; import org.graalvm.nativeimage.Platform; import org.graalvm.nativeimage.Platforms; @@ -64,7 +66,6 @@ import com.oracle.svm.core.graal.meta.SubstrateRegisterConfig; import com.oracle.svm.core.log.Log; import com.oracle.svm.core.meta.SharedField; -import com.oracle.svm.core.meta.SubstrateObjectConstant; import com.oracle.svm.core.util.VMError; import jdk.vm.ci.amd64.AMD64; @@ -72,6 +73,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.JavaConstant; import jdk.vm.ci.meta.ResolvedJavaField; final class AMD64CalleeSavedRegisters extends CalleeSavedRegisters { @@ -431,7 +433,8 @@ private AMD64BaseAssembler.OperandSize getSize() { @Platforms(Platform.HOSTED_ONLY.class) private AMD64Address getFeatureMapAddress() { - SubstrateObjectConstant object = (SubstrateObjectConstant) SubstrateObjectConstant.forObject(RuntimeCPUFeatureCheckImpl.instance()); + SnippetReflectionProvider snippetReflection = ((Providers) crb.providers).getSnippetReflection(); + JavaConstant object = snippetReflection.forObject(RuntimeCPUFeatureCheckImpl.instance()); int fieldOffset = fieldOffset(RuntimeCPUFeatureCheckImpl.getMaskField(crb.providers.getMetaAccess())); GraalError.guarantee(ConfigurationValues.getTarget().inlineObjects, "Dynamic feature check for callee saved registers requires inlined objects"); Register heapBase = ReservedRegisters.singleton().getHeapBaseRegister(); @@ -448,7 +451,7 @@ private int fieldOffset(ResolvedJavaField f) { } @Platforms(Platform.HOSTED_ONLY.class) - private Object displacementAnnotation(SubstrateObjectConstant constant) { + private Object displacementAnnotation(JavaConstant constant) { if (SubstrateUtil.HOSTED) { /* * AOT compilation during image generation happens before the image heap objects are @@ -463,7 +466,7 @@ private Object displacementAnnotation(SubstrateObjectConstant constant) { } @Platforms(Platform.HOSTED_ONLY.class) - private int displacement(SubstrateObjectConstant constant, SharedConstantReflectionProvider constantReflection) { + private int displacement(JavaConstant constant, SharedConstantReflectionProvider constantReflection) { if (SubstrateUtil.HOSTED) { return 0; } else { 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 f11c9c5cd96e..39a9ccdbb6bc 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 @@ -1025,10 +1025,6 @@ public void returned(CompilationResultBuilder crb) { crb.recordMark(SubstrateMarkId.EPILOGUE_END); } - @Override - public boolean hasFrame() { - return true; - } } /** diff --git a/substratevm/src/com.oracle.svm.core.posix/src/com/oracle/svm/core/posix/PosixRawFileOperationSupport.java b/substratevm/src/com.oracle.svm.core.posix/src/com/oracle/svm/core/posix/PosixRawFileOperationSupport.java index 7fe1c3aae1f1..5c80e7de39b5 100644 --- a/substratevm/src/com.oracle.svm.core.posix/src/com/oracle/svm/core/posix/PosixRawFileOperationSupport.java +++ b/substratevm/src/com.oracle.svm.core.posix/src/com/oracle/svm/core/posix/PosixRawFileOperationSupport.java @@ -48,8 +48,6 @@ import com.oracle.svm.core.util.VMError; public class PosixRawFileOperationSupport extends AbstractRawFileOperationSupport { - private static final int DEFAULT_PERMISSIONS = 0666; - @Platforms(Platform.HOSTED_ONLY.class) public PosixRawFileOperationSupport(boolean useNativeByteOrder) { super(useNativeByteOrder); @@ -59,19 +57,20 @@ public PosixRawFileOperationSupport(boolean useNativeByteOrder) { public RawFileDescriptor create(File file, FileCreationMode creationMode, FileAccessMode accessMode) { String path = file.getPath(); int flags = parseMode(creationMode) | parseMode(accessMode); - - try (CTypeConversion.CCharPointerHolder cPath = CTypeConversion.toCString(path)) { - return WordFactory.signed(Fcntl.NoTransitions.open(cPath.get(), flags, DEFAULT_PERMISSIONS)); - } + return open0(path, flags); } @Override public RawFileDescriptor open(File file, FileAccessMode mode) { String path = file.getPath(); int flags = parseMode(mode); + return open0(path, flags); + } + private static RawFileDescriptor open0(String path, int flags) { + int permissions = PosixStat.S_IRUSR() | PosixStat.S_IWUSR(); try (CTypeConversion.CCharPointerHolder cPath = CTypeConversion.toCString(path)) { - return WordFactory.signed(Fcntl.NoTransitions.open(cPath.get(), flags, DEFAULT_PERMISSIONS)); + return WordFactory.signed(Fcntl.NoTransitions.open(cPath.get(), flags, permissions)); } } diff --git a/substratevm/src/com.oracle.svm.core.posix/src/com/oracle/svm/core/posix/PosixStat.java b/substratevm/src/com.oracle.svm.core.posix/src/com/oracle/svm/core/posix/PosixStat.java index 5120ba660ef4..dacbd156b2e5 100644 --- a/substratevm/src/com.oracle.svm.core.posix/src/com/oracle/svm/core/posix/PosixStat.java +++ b/substratevm/src/com.oracle.svm.core.posix/src/com/oracle/svm/core/posix/PosixStat.java @@ -26,16 +26,54 @@ import org.graalvm.nativeimage.Platform; import org.graalvm.nativeimage.Platforms; +import org.graalvm.nativeimage.c.CContext; +import org.graalvm.nativeimage.c.constant.CConstant; import com.oracle.svm.core.Uninterruptible; import com.oracle.svm.core.graal.stackvalue.UnsafeStackValue; import com.oracle.svm.core.headers.LibC; import com.oracle.svm.core.posix.headers.Errno; +import com.oracle.svm.core.posix.headers.PosixDirectives; import com.oracle.svm.core.posix.headers.darwin.DarwinStat; import com.oracle.svm.core.posix.headers.linux.LinuxStat; import com.oracle.svm.core.util.VMError; +// Checkstyle: stop +@CContext(PosixDirectives.class) public final class PosixStat { + @CConstant + public static native int S_IFLNK(); + + @CConstant + public static native int S_IFDIR(); + + @CConstant + public static native int S_IRUSR(); + + @CConstant + public static native int S_IRGRP(); + + @CConstant + public static native int S_IROTH(); + + @CConstant + public static native int S_IWUSR(); + + @CConstant + public static native int S_IWGRP(); + + @CConstant + public static native int S_IWOTH(); + + @CConstant + public static native int S_IRWXU(); + + @CConstant + public static native int S_IXGRP(); + + @CConstant + public static native int S_IXOTH(); + public static boolean isOpen(int fd) { int result; if (Platform.includedIn(Platform.LINUX.class)) { diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/StaticFieldsSupport.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/StaticFieldsSupport.java index f390af8d1b69..bab36c95dc5b 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/StaticFieldsSupport.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/StaticFieldsSupport.java @@ -47,11 +47,10 @@ import org.graalvm.nativeimage.Platforms; import org.graalvm.word.LocationIdentity; -import com.oracle.svm.core.feature.InternalFeature; -import com.oracle.svm.core.meta.SharedField; -import com.oracle.svm.core.meta.SubstrateObjectConstant; 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.meta.SharedField; import com.oracle.svm.core.util.VMError; import jdk.vm.ci.meta.JavaConstant; @@ -159,7 +158,7 @@ public void lower(LoweringTool tool) { return; } - JavaConstant constant = SubstrateObjectConstant.forObject(primitive ? StaticFieldsSupport.getStaticPrimitiveFields() : StaticFieldsSupport.getStaticObjectFields()); + JavaConstant constant = tool.getSnippetReflection().forObject(primitive ? StaticFieldsSupport.getStaticPrimitiveFields() : StaticFieldsSupport.getStaticObjectFields()); assert constant.isNonNull(); replaceAndDelete(ConstantNode.forConstant(constant, tool.getMetaAccess(), graph())); } 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 caf7e0bb0f0d..8fd81421c09d 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 @@ -178,7 +178,7 @@ private static void dumpInterruptibly(PointerBase signalInfo, RegisterDumper.Con PointerBase ip = RegisterDumper.singleton().getIP(context); boolean printedDiagnostics = SubstrateDiagnostics.printFatalError(log, (Pointer) sp, (CodePointer) ip, context, false); if (printedDiagnostics) { - log.string("Segfault detected, aborting process.").newline() + log.string("Segfault detected, aborting process. ") .string("Use '-XX:-InstallSegfaultHandler' to disable the segfault handler at run time and create a core dump instead. ") .string("Rebuild with '-R:-InstallSegfaultHandler' to disable the handler permanently at build time.") // .newline().newline(); 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 a1c29eba71ea..b25e942309eb 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 @@ -212,6 +212,7 @@ public static CCharPointer strchr(CCharPointer str, int c) { * are actually the same class. */ @SuppressWarnings({"unused", "unchecked"}) + @AlwaysInline("Some callers rely on this never becoming an actual method call.") @Uninterruptible(reason = "Called from uninterruptible code.", mayBeInlined = true) public static T cast(Object obj, Class toType) { return (T) obj; diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/VM.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/VM.java index 75fd31a6d12e..14d1965340e2 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/VM.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/VM.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2022, 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. * * This code is free software; you can redistribute it and/or modify it @@ -24,25 +24,47 @@ */ package com.oracle.svm.core; +import org.graalvm.nativeimage.ImageSingletons; import org.graalvm.nativeimage.Platform; import org.graalvm.nativeimage.Platforms; +import org.graalvm.nativeimage.impl.ImageSingletonsSupport; public final class VM { + public final String info; public final String version; public final String vendor; public final String vendorUrl; - public final String runtimeName; + public final String vendorVersion; public final String supportURL; @Platforms(Platform.HOSTED_ONLY.class) - public VM() { - String versionStr = System.getProperty("org.graalvm.version", "Unknown Version"); - String edition = System.getProperty("org.graalvm.config", "CE"); - version = String.format("GraalVM %s Java %s %s", versionStr, Runtime.version(), edition); - vendor = System.getProperty("org.graalvm.vendor", "Oracle Corporation"); - vendorUrl = System.getProperty("org.graalvm.vendorurl", "https://www.graalvm.org/"); - runtimeName = System.getProperty("java.runtime.name", "Unknown Runtime Environment"); + public VM(String vmInfo) { + info = vmInfo; supportURL = System.getProperty("org.graalvm.supporturl", "https://graalvm.org/native-image/error-report/"); + version = stripJVMCISuffix(System.getProperty("java.runtime.version")); + vendor = System.getProperty("org.graalvm.vendor", "GraalVM Community"); + vendorUrl = System.getProperty("org.graalvm.vendorurl", "https://www.graalvm.org/"); + vendorVersion = System.getProperty("org.graalvm.vendorversion", "GraalVM CE"); + } + + @Platforms(Platform.HOSTED_ONLY.class) + public static VM getErrorReportingInstance() { + if (ImageSingletonsSupport.isInstalled() && ImageSingletons.contains(VM.class)) { + return ImageSingletons.lookup(VM.class); + } else { + // create a fall back instance + return new VM(System.getProperty("java.vm.info", "")); + } + } + + @Platforms(Platform.HOSTED_ONLY.class) + private static String stripJVMCISuffix(String javaRuntimeVersion) { + int jvmciIndex = javaRuntimeVersion.indexOf("-jvmci"); + if (jvmciIndex >= 0) { + return javaRuntimeVersion.substring(0, jvmciIndex); + } else { + return javaRuntimeVersion; + } } } diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/code/AbstractRuntimeCodeInstaller.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/code/AbstractRuntimeCodeInstaller.java index f745ac0f495b..0328055c7bb2 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/code/AbstractRuntimeCodeInstaller.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/code/AbstractRuntimeCodeInstaller.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, 2020, 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 @@ -99,8 +99,8 @@ protected void operate() { try { assert !installedCode.isValid() && !installedCode.isAlive(); CodePointer codeStart = CodeInfoAccess.getCodeStart(codeInfo); - installedCode.setAddress(codeStart.rawValue(), method); - + UnsignedWord offset = CodeInfoAccess.getCodeEntryPointOffset(codeInfo); + installedCode.setAddress(codeStart.rawValue(), codeStart.rawValue() + offset.rawValue(), method); CodeInfoTable.getRuntimeCodeCache().addMethod(codeInfo); platformHelper().performCodeSynchronization(codeInfo); VMError.guarantee(CodeInfoAccess.getState(codeInfo) == CodeInfo.STATE_CODE_CONSTANTS_LIVE && installedCode.isValid(), "The code can't be invalidated before the VM operation finishes"); 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 330962dda3b1..69b9fec81580 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 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 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. * * This code is free software; you can redistribute it and/or modify it @@ -182,6 +182,11 @@ public static CodePointer getCodeStart(CodeInfo info) { return cast(info).getCodeStart(); } + @Uninterruptible(reason = "Called from uninterruptible code.", mayBeInlined = true) + public static UnsignedWord getCodeEntryPointOffset(CodeInfo info) { + return cast(info).getCodeEntryPointOffset(); + } + /** @see CodeInfoImpl#getCodeSize */ @Uninterruptible(reason = "Called from uninterruptible code.", mayBeInlined = true) public static UnsignedWord getCodeSize(CodeInfo info) { 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 0b169eb9a1bf..7c209ff717d1 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 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2019, 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. * * This code is free software; you can redistribute it and/or modify it @@ -31,12 +31,12 @@ import org.graalvm.nativeimage.c.struct.RawStructure; import org.graalvm.word.UnsignedWord; -import com.oracle.svm.core.util.DuplicatedInNativeCode; import com.oracle.svm.core.c.NonmovableArray; import com.oracle.svm.core.c.NonmovableObjectArray; import com.oracle.svm.core.code.InstalledCodeObserver.InstalledCodeObserverHandle; import com.oracle.svm.core.deopt.SubstrateInstalledCode; import com.oracle.svm.core.heap.RuntimeCodeInfoGCSupport; +import com.oracle.svm.core.util.DuplicatedInNativeCode; import com.oracle.svm.core.util.VMError; import jdk.vm.ci.code.InstalledCode; @@ -122,6 +122,9 @@ interface CodeInfoImpl extends CodeInfo { @RawField void setCodeStart(CodePointer codeStart); + @RawField + UnsignedWord getCodeEntryPointOffset(); + /** The size of the instructions of this compiled code. */ @RawField UnsignedWord getCodeSize(); @@ -151,6 +154,9 @@ interface CodeInfoImpl extends CodeInfo { @RawField void setCodeSize(UnsignedWord codeSize); + @RawField + void setCodeEntryPointOffset(UnsignedWord offset); + @RawField void setDataOffset(UnsignedWord dataOffset); diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/code/FrameInfoQueryResult.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/code/FrameInfoQueryResult.java index 50a8f784364b..9894c6945885 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/code/FrameInfoQueryResult.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/code/FrameInfoQueryResult.java @@ -33,7 +33,6 @@ import com.oracle.svm.core.ReservedRegisters; import com.oracle.svm.core.Uninterruptible; import com.oracle.svm.core.hub.DynamicHub; -import com.oracle.svm.core.jdk.JavaLangSubstitutions; import com.oracle.svm.core.log.Log; import com.oracle.svm.core.meta.SharedMethod; @@ -377,15 +376,6 @@ public boolean isNativeMethod() { return sourceLineNumber == -2; } - @Override - @Uninterruptible(reason = "Called from uninterruptible code.", mayBeInlined = true) - public int hashCode() { - int result = 31 * sourceClass.hashCode() + JavaLangSubstitutions.StringUtil.hashCode(sourceMethodName); - result = 31 * result + JavaLangSubstitutions.StringUtil.hashCode(getSourceFileName()); - result = 31 * result + sourceLineNumber; - return result; - } - public Log log(Log log) { String className = sourceClass != null ? sourceClass.getName() : ""; String methodName = sourceMethodName != null ? sourceMethodName : ""; 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 45caa1f2a1d8..013ad76161a3 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 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2017, 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. * * This code is free software; you can redistribute it and/or modify it @@ -35,11 +35,11 @@ import com.oracle.svm.core.MemoryWalker; import com.oracle.svm.core.Uninterruptible; -import com.oracle.svm.core.heap.UnknownObjectField; -import com.oracle.svm.core.heap.UnknownPrimitiveField; import com.oracle.svm.core.c.NonmovableArray; import com.oracle.svm.core.c.NonmovableArrays; import com.oracle.svm.core.c.NonmovableObjectArray; +import com.oracle.svm.core.heap.UnknownObjectField; +import com.oracle.svm.core.heap.UnknownPrimitiveField; import com.oracle.svm.core.util.VMError; public class ImageCodeInfo { @@ -52,6 +52,7 @@ public class ImageCodeInfo { private final HostedImageCodeInfo hostedImageCodeInfo = new HostedImageCodeInfo(); @UnknownPrimitiveField private CodePointer codeStart; + @UnknownPrimitiveField private UnsignedWord entryPointOffset; @UnknownPrimitiveField private UnsignedWord codeSize; @UnknownPrimitiveField private UnsignedWord dataOffset; @UnknownPrimitiveField private UnsignedWord dataSize; @@ -174,11 +175,21 @@ public void setCodeStart(CodePointer value) { codeStart = value; } + @Override + public UnsignedWord getCodeEntryPointOffset() { + return entryPointOffset; + } + @Override public void setCodeSize(UnsignedWord value) { codeSize = value; } + @Override + public void setCodeEntryPointOffset(UnsignedWord offset) { + entryPointOffset = offset; + } + @Override public void setDataOffset(UnsignedWord value) { dataOffset = value; 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 b89bd301fb4e..996f1089c4a0 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 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 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. * * This code is free software; you can redistribute it and/or modify it @@ -66,11 +66,12 @@ public static NonmovableArray getCodeObserverHandle return cast(info).getCodeObserverHandles(); } - public static void initialize(CodeInfo info, Pointer codeStart, int codeSize, int dataOffset, int dataSize, int codeAndDataMemorySize, + public static void initialize(CodeInfo info, Pointer codeStart, int entryPointOffset, int codeSize, int dataOffset, int dataSize, int codeAndDataMemorySize, int tier, NonmovableArray observerHandles, boolean allObjectsAreInImageHeap) { CodeInfoImpl impl = cast(info); impl.setCodeStart((CodePointer) codeStart); + impl.setCodeEntryPointOffset(WordFactory.unsigned(entryPointOffset)); impl.setCodeSize(WordFactory.unsigned(codeSize)); impl.setDataOffset(WordFactory.unsigned(dataOffset)); impl.setDataSize(WordFactory.unsigned(dataSize)); diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/deopt/SubstrateInstalledCode.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/deopt/SubstrateInstalledCode.java index 2204ec9d6be2..640b2448a4e4 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/deopt/SubstrateInstalledCode.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/deopt/SubstrateInstalledCode.java @@ -69,11 +69,12 @@ public interface SubstrateInstalledCode { /** * Called during code installation: initialize this instance with the given address where its - * instructions are, and the method it was compiled from. Afterwards, {@link #getAddress()} and - * {@link #getEntryPoint()} return the given address, and {@link #isValid()} and - * {@link #isAlive()} return {@code true}. + * instructions are, and the method it was compiled from. The entry point sets the address of + * the first instruction to be executed. Afterwards, {@link #getAddress()} returns the given + * address, and {@link #isAlive()} returns {@code true}. Also {@link #getEntryPoint()} returns + * the given address, and {@link #isValid()} returns true. */ - void setAddress(long address, ResolvedJavaMethod method); + void setAddress(long address, long entryPoint, ResolvedJavaMethod method); /** * This method is called during code uninstallation. Consider {@link #invalidate()} instead. diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/graal/code/SubstrateBackend.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/graal/code/SubstrateBackend.java index f002b5e5e98f..0e58e8ea8c94 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/graal/code/SubstrateBackend.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/graal/code/SubstrateBackend.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 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 @@ -65,6 +65,11 @@ public abstract class SubstrateBackend extends Backend { private static final LocationIdentity JIT_VTABLE_IDENTITY = NamedLocationIdentity.mutable("DynamicHub.vtable@jit"); public enum SubstrateMarkId implements CompilationResult.MarkId { + /** + * Marks the start of the prologue in case the prologue instructions are not the first + * instructions in the compilation. + */ + PROLOGUE_START(true), PROLOGUE_DECD_RSP(true), PROLOGUE_SAVED_REGS(true), PROLOGUE_END(true), 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 1d17be47b364..ffd2c504d8b4 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,6 +27,7 @@ import java.util.ArrayList; import java.util.List; +import org.graalvm.compiler.api.replacements.SnippetReflectionProvider; import org.graalvm.compiler.core.common.CompilationIdentifier; import org.graalvm.compiler.core.common.type.Stamp; import org.graalvm.compiler.core.common.type.StampFactory; @@ -75,7 +76,6 @@ import com.oracle.svm.core.graal.code.SubstrateCallingConventionKind; import com.oracle.svm.core.graal.meta.SubstrateLoweringProvider; import com.oracle.svm.core.graal.nodes.DeoptEntryNode; -import com.oracle.svm.core.meta.SubstrateObjectConstant; import com.oracle.svm.core.nodes.CFunctionEpilogueNode; import com.oracle.svm.core.nodes.CFunctionPrologueNode; import com.oracle.svm.core.nodes.SubstrateMethodCallTargetNode; @@ -268,7 +268,8 @@ public ConstantNode createInt(int value) { } public ConstantNode createObject(Object value) { - return ConstantNode.forConstant(SubstrateObjectConstant.forObject(value), getMetaAccess(), graph); + SnippetReflectionProvider snippetReflection = getProviders().getSnippetReflection(); + return ConstantNode.forConstant(snippetReflection.forObject(value), getMetaAccess(), graph); } public ValueNode createBoxing(ValueNode value, JavaKind kind, ResolvedJavaType targetType) { diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/graal/snippets/SubstrateAllocationSnippets.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/graal/snippets/SubstrateAllocationSnippets.java index 26e8f7df3cef..b54cc67c097c 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/graal/snippets/SubstrateAllocationSnippets.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/graal/snippets/SubstrateAllocationSnippets.java @@ -96,7 +96,6 @@ import com.oracle.svm.core.hub.LayoutEncoding; import com.oracle.svm.core.identityhashcode.IdentityHashCodeSupport; import com.oracle.svm.core.meta.SharedType; -import com.oracle.svm.core.meta.SubstrateObjectConstant; import com.oracle.svm.core.option.HostedOptionValues; import com.oracle.svm.core.snippets.SnippetRuntime; import com.oracle.svm.core.snippets.SnippetRuntime.SubstrateForeignCallDescriptor; @@ -680,7 +679,7 @@ public void lower(NewInstanceNode node, LoweringTool tool) { SharedType type = (SharedType) node.instanceClass(); DynamicHub hub = ensureMarkedAsInstantiated(type.getHub()); - ConstantNode hubConstant = ConstantNode.forConstant(SubstrateObjectConstant.forObject(hub), tool.getMetaAccess(), graph); + ConstantNode hubConstant = ConstantNode.forConstant(snippetReflection.forObject(hub), tool.getMetaAccess(), graph); long size = LayoutEncoding.getPureInstanceAllocationSize(hub.getLayoutEncoding()).rawValue(); Arguments args = new Arguments(allocateInstance, graph.getGuardsStage(), tool.getLoweringStage()); @@ -711,7 +710,7 @@ public void lower(SubstrateNewHybridInstanceNode node, LoweringTool tool) { boolean fillContents = node.fillContents(); assert fillContents : "fillContents must be true for hybrid allocations"; - ConstantNode hubConstant = ConstantNode.forConstant(SubstrateObjectConstant.forObject(hub), tool.getMetaAccess(), graph); + ConstantNode hubConstant = ConstantNode.forConstant(snippetReflection.forObject(hub), tool.getMetaAccess(), graph); Arguments args = new Arguments(allocateArray, graph.getGuardsStage(), tool.getLoweringStage()); args.add("hub", hubConstant); @@ -744,7 +743,7 @@ public void lower(NewStoredContinuationNode node, LoweringTool tool) { int arrayBaseOffset = LayoutEncoding.getArrayBaseOffsetAsInt(layoutEncoding); int log2ElementSize = LayoutEncoding.getArrayIndexShift(layoutEncoding); - ConstantNode hubConstant = ConstantNode.forConstant(SubstrateObjectConstant.forObject(hub), tool.getMetaAccess(), graph); + ConstantNode hubConstant = ConstantNode.forConstant(snippetReflection.forObject(hub), tool.getMetaAccess(), graph); Arguments args = new Arguments(allocateStoredContinuation, graph.getGuardsStage(), tool.getLoweringStage()); args.add("hub", hubConstant); @@ -773,7 +772,7 @@ public void lower(NewArrayNode node, LoweringTool tool) { int layoutEncoding = hub.getLayoutEncoding(); int arrayBaseOffset = getArrayBaseOffset(layoutEncoding); int log2ElementSize = LayoutEncoding.getArrayIndexShift(layoutEncoding); - ConstantNode hubConstant = ConstantNode.forConstant(SubstrateObjectConstant.forObject(hub), tool.getMetaAccess(), graph); + ConstantNode hubConstant = ConstantNode.forConstant(snippetReflection.forObject(hub), tool.getMetaAccess(), graph); Arguments args = new Arguments(allocateArray, graph.getGuardsStage(), tool.getLoweringStage()); args.add("hub", hubConstant); @@ -806,7 +805,7 @@ public void lower(NewMultiArrayNode node, LoweringTool tool) { } SharedType type = (SharedType) node.type(); - ConstantNode hubConstant = ConstantNode.forConstant(SubstrateObjectConstant.forObject(type.getHub()), tool.getMetaAccess(), graph); + ConstantNode hubConstant = ConstantNode.forConstant(snippetReflection.forObject(type.getHub()), tool.getMetaAccess(), graph); Arguments args = new Arguments(newmultiarray, graph.getGuardsStage(), tool.getLoweringStage()); args.add("hub", hubConstant); 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 b8ccd41b199a..cbe68f80a21f 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,7 @@ */ package com.oracle.svm.core.graal.thread; +import org.graalvm.compiler.api.replacements.SnippetReflectionProvider; import org.graalvm.compiler.core.common.LIRKind; import org.graalvm.compiler.core.common.type.StampFactory; import org.graalvm.compiler.graph.NodeClass; @@ -34,9 +35,9 @@ import org.graalvm.compiler.nodes.NodeView; import org.graalvm.compiler.nodes.spi.LIRLowerable; import org.graalvm.compiler.nodes.spi.NodeLIRBuilderTool; +import org.graalvm.compiler.phases.util.Providers; import org.graalvm.nativeimage.ImageSingletons; -import com.oracle.svm.core.meta.SubstrateObjectConstant; import com.oracle.svm.core.threadlocal.VMThreadLocalInfo; import com.oracle.svm.core.threadlocal.VMThreadLocalSTSupport; @@ -63,7 +64,8 @@ public void generate(NodeLIRBuilderTool gen) { } else { holder = ImageSingletons.lookup(VMThreadLocalSTSupport.class).primitiveThreadLocals; } + SnippetReflectionProvider snippetReflection = ((Providers) gen.getLIRGeneratorTool().getProviders()).getSnippetReflection(); LIRKind kind = gen.getLIRGeneratorTool().getLIRKind(stamp(NodeView.DEFAULT)); - gen.setResult(this, gen.getLIRGeneratorTool().emitLoadConstant(kind, SubstrateObjectConstant.forObject(holder))); + gen.setResult(this, gen.getLIRGeneratorTool().emitLoadConstant(kind, snippetReflection.forObject(holder))); } } 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 c57180df150a..0ec974eef205 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 @@ -107,13 +107,6 @@ private int hashCodeSubst() { @Substitute @TargetElement(name = "wait") private void waitSubst(long timeoutMillis) throws InterruptedException { - /* - * JDK 19 and later: our monitor implementation does not pin virtual threads, so avoid - * jdk.internal.misc.Blocker which expects and asserts that a virtual thread is pinned. - * Also, we get interrupted on the virtual thread instead of the carrier thread, which - * clears the carrier thread's interrupt status too, so we don't have to intercept an - * InterruptedException from the carrier thread to clear the virtual thread interrupt. - */ MonitorSupport.singleton().wait(this, timeoutMillis); } @@ -276,10 +269,6 @@ final class Target_java_lang_StringLatin1 { @AnnotateOriginal @Uninterruptible(reason = "Called from uninterruptible code.", mayBeInlined = true) static native char getChar(byte[] val, int index); - - @AnnotateOriginal - @Uninterruptible(reason = "Called from uninterruptible code.", mayBeInlined = true) - static native int hashCode(byte[] value); } @TargetClass(className = "java.lang.StringUTF16") @@ -288,10 +277,6 @@ final class Target_java_lang_StringUTF16 { @AnnotateOriginal @Uninterruptible(reason = "Called from uninterruptible code.", mayBeInlined = true) static native char getChar(byte[] val, int index); - - @AnnotateOriginal - @Uninterruptible(reason = "Called from uninterruptible code.", mayBeInlined = true) - static native int hashCode(byte[] value); } @TargetClass(java.lang.Throwable.class) @@ -854,26 +839,6 @@ public static char charAt(String string, int index) { public static byte coder(String string) { return SubstrateUtil.cast(string, Target_java_lang_String.class).coder(); } - - @Uninterruptible(reason = "Called from uninterruptible code.", mayBeInlined = true) - public static int hashCode(java.lang.String string) { - return string != null ? hashCode0(string) : 0; - } - - @Uninterruptible(reason = "Called from uninterruptible code.", mayBeInlined = true) - private static int hashCode0(java.lang.String string) { - Target_java_lang_String str = SubstrateUtil.cast(string, Target_java_lang_String.class); - byte[] value = str.value; - if (str.hash == 0 && value.length > 0) { - boolean isLatin1 = str.isLatin1(); - if (isLatin1) { - str.hash = Target_java_lang_StringLatin1.hashCode(value); - } else { - str.hash = Target_java_lang_StringUTF16.hashCode(value); - } - } - return str.hash; - } } public static final class ClassValueSupport { diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/SystemPropertiesSupport.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/SystemPropertiesSupport.java index 6647f941dad9..84981ca5f668 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/SystemPropertiesSupport.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/SystemPropertiesSupport.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2017, 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. * * This code is free software; you can redistribute it and/or modify it @@ -56,6 +56,7 @@ public abstract class SystemPropertiesSupport implements RuntimeSystemProperties /** System properties that are taken from the VM hosting the image generator. */ private static final String[] HOSTED_PROPERTIES = { "java.version", + "java.version.date", ImageInfo.PROPERTY_IMAGE_KIND_KEY, /* * We do not support cross-compilation for now. Separator might also be cached @@ -65,6 +66,7 @@ public abstract class SystemPropertiesSupport implements RuntimeSystemProperties /* For our convenience for now. */ "file.encoding", "sun.jnu.encoding", "native.encoding", "stdout.encoding", "stderr.encoding", "java.class.version", + "java.runtime.version", "java.specification.name", "java.specification.vendor", "java.specification.version", @@ -109,13 +111,17 @@ protected SystemPropertiesSupport() { } } + initializeProperty("java.runtime.name", "GraalVM Runtime Environment"); + + VM vm = ImageSingletons.lookup(VM.class); + initializeProperty("java.vendor", vm.vendor); + initializeProperty("java.vendor.url", vm.vendorUrl); + initializeProperty("java.vendor.version", vm.vendorVersion); + assert vm.info.equals(vm.info.toLowerCase()) : "java.vm.info should not contain uppercase characters"; + initializeProperty("java.vm.info", vm.info); initializeProperty("java.vm.name", "Substrate VM"); - initializeProperty("java.runtime.name", ImageSingletons.lookup(VM.class).runtimeName); - initializeProperty("java.vm.vendor", ImageSingletons.lookup(VM.class).vendor); - initializeProperty("java.vm.version", ImageSingletons.lookup(VM.class).version); - initializeProperty("java.runtime.version", ImageSingletons.lookup(VM.class).version); - initializeProperty("java.vendor", ImageSingletons.lookup(VM.class).vendor); - initializeProperty("java.vendor.url", ImageSingletons.lookup(VM.class).vendorUrl); + initializeProperty("java.vm.vendor", vm.vendor); + initializeProperty("java.vm.version", vm.version); initializeProperty("java.class.path", ""); initializeProperty("java.endorsed.dirs", ""); diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/Target_java_util_Collections.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/Target_java_util_Collections.java new file mode 100644 index 000000000000..50b656635e81 --- /dev/null +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/Target_java_util_Collections.java @@ -0,0 +1,38 @@ +/* + * 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 com.oracle.svm.core.annotate.Alias; +import com.oracle.svm.core.annotate.RecomputeFieldValue; +import com.oracle.svm.core.annotate.TargetClass; + +import java.util.Collections; +import java.util.Random; + +@TargetClass(Collections.class) +public final class Target_java_util_Collections { + /* This field is lazily initialized and cached by the Collections.shuffle method. */ + @Alias @RecomputeFieldValue(kind = RecomputeFieldValue.Kind.Reset) static Random r; +} diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/Target_sun_rmi_transport_GC.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/Target_sun_rmi_transport_GC.java index 6436feb1b700..73eef6313ea5 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/Target_sun_rmi_transport_GC.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/Target_sun_rmi_transport_GC.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. * Copyright (c) 2022, 2022, Red Hat Inc. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * @@ -26,12 +26,22 @@ package com.oracle.svm.core.jdk; +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.heap.Heap; +/** + * Note that sun.rmi.transport.GC is initialized at build-time to avoid including the rmi library, + * which is not needed as it only implements the native maxObjectInspectionAge() method, which in + * turn is {@link Target_sun_rmi_transport_GC#maxObjectInspectionAge substituted in here}. + */ @TargetClass(className = "sun.rmi.transport.GC") final class Target_sun_rmi_transport_GC { + @Alias @RecomputeFieldValue(kind = RecomputeFieldValue.Kind.Reset)// + private static Thread daemon = null; + @Substitute public static long maxObjectInspectionAge() { return Heap.getHeap().getMillisSinceLastWholeHeapExamined(); diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/monitor/MultiThreadedMonitorSupport.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/monitor/MultiThreadedMonitorSupport.java index cf1844f26a5b..3d551fcffc6a 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/monitor/MultiThreadedMonitorSupport.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/monitor/MultiThreadedMonitorSupport.java @@ -42,12 +42,14 @@ import com.oracle.svm.core.Uninterruptible; import com.oracle.svm.core.WeakIdentityHashMap; +import com.oracle.svm.core.annotate.Alias; import com.oracle.svm.core.annotate.TargetClass; import com.oracle.svm.core.heap.RestrictHeapAccess; import com.oracle.svm.core.heap.RestrictHeapAccess.Access; import com.oracle.svm.core.hub.DynamicHub; import com.oracle.svm.core.hub.DynamicHubCompanion; import com.oracle.svm.core.jdk.JDK17OrEarlier; +import com.oracle.svm.core.jdk.JDK19OrLater; import com.oracle.svm.core.jfr.JfrTicks; import com.oracle.svm.core.jfr.events.JavaMonitorInflateEvent; import com.oracle.svm.core.monitor.JavaMonitorQueuedSynchronizer.JavaMonitorConditionObject; @@ -55,6 +57,7 @@ import com.oracle.svm.core.stack.StackOverflowCheck; import com.oracle.svm.core.thread.ThreadStatus; import com.oracle.svm.core.thread.VMOperationControl; +import com.oracle.svm.core.thread.VirtualThreads; import com.oracle.svm.core.util.VMError; import jdk.internal.misc.Unsafe; @@ -328,15 +331,35 @@ public boolean isLockedByAnyThread(Object obj) { @Override protected void doWait(Object obj, long timeoutMillis) throws InterruptedException { /* - * Ensure that the current thread holds the lock. Required by the specification of - * Object.wait, and also required for our implementation. + * JDK 19 and later: our monitor implementation does not pin virtual threads, so avoid + * jdk.internal.misc.Blocker which expects and asserts that a virtual thread is pinned + * unless the thread is pinned for other reasons. Also, we get interrupted on the virtual + * thread instead of the carrier thread, which clears the carrier thread's interrupt status + * too, so we don't have to intercept an InterruptedException from the carrier thread to + * clear the virtual thread interrupt. */ - JavaMonitor lock = ensureLocked(obj, MonitorInflationCause.WAIT); - JavaMonitorConditionObject condition = lock.getOrCreateCondition(true); - if (timeoutMillis == 0L) { - condition.await(obj); - } else { - condition.await(obj, timeoutMillis, TimeUnit.MILLISECONDS); + long compensation = -1; + boolean pinned = JavaVersionUtil.JAVA_SPEC >= 19 && VirtualThreads.isSupported() && + VirtualThreads.singleton().isVirtual(Thread.currentThread()) && VirtualThreads.singleton().isCurrentPinned(); + if (pinned) { + compensation = Target_jdk_internal_misc_Blocker.begin(); + } + try { + /* + * Ensure that the current thread holds the lock. Required by the specification of + * Object.wait, and also required for our implementation. + */ + JavaMonitor lock = ensureLocked(obj, MonitorInflationCause.WAIT); + JavaMonitorConditionObject condition = lock.getOrCreateCondition(true); + if (timeoutMillis == 0L) { + condition.await(obj); + } else { + condition.await(obj, timeoutMillis, TimeUnit.MILLISECONDS); + } + } finally { + if (pinned) { + Target_jdk_internal_misc_Blocker.end(compensation); + } } } @@ -462,3 +485,12 @@ protected JavaMonitor newMonitorLock() { @TargetClass(value = ReferenceQueue.class, innerClass = "Lock", onlyWith = JDK17OrEarlier.class) final class Target_java_lang_ref_ReferenceQueue_Lock { } + +@TargetClass(className = "jdk.internal.misc.Blocker", onlyWith = JDK19OrLater.class) +final class Target_jdk_internal_misc_Blocker { + @Alias + public static native long begin(); + + @Alias + public static native void end(long compensateReturn); +} diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/sampler/ProfilingSampler.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/sampler/ProfilingSampler.java index b1a340602372..bd02d3b60e28 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/sampler/ProfilingSampler.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/sampler/ProfilingSampler.java @@ -28,4 +28,6 @@ public interface ProfilingSampler { LockFreePrefixTree prefixTree(); + + void reset(); } 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 541ecb9519e9..673eb452852a 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 @@ -60,6 +60,11 @@ public LockFreePrefixTree prefixTree() { return prefixTree; } + @Override + public void reset() { + prefixTree.reset(); + } + @RestrictHeapAccess(access = RestrictHeapAccess.Access.NO_ALLOCATION, reason = "Must not allocate inside the safepoint sampler.") private void sampleThreadStack(SamplingStackVisitor.StackTrace stackTrace) { stackTrace.reset(); diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/thread/JavaThreadsFeature.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/thread/JavaThreadsFeature.java index e8e7f946b49f..73ab558fd5bb 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/thread/JavaThreadsFeature.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/thread/JavaThreadsFeature.java @@ -30,6 +30,7 @@ import org.graalvm.nativeimage.ImageSingletons; import org.graalvm.nativeimage.Platform; import org.graalvm.nativeimage.Platforms; +import org.graalvm.nativeimage.hosted.RuntimeClassInitialization; import com.oracle.svm.core.feature.InternalFeature; import com.oracle.svm.core.feature.AutomaticallyRegisteredFeature; @@ -61,6 +62,12 @@ static JavaThreadsFeature singleton() { @Override public void duringSetup(DuringSetupAccess access) { access.registerObjectReplacer(this::collectReachableObjects); + + /* + * This currently only means that we don't support setting custom values for + * jdk.incubator.concurrent.ScopedValue.cacheSize at runtime. + */ + RuntimeClassInitialization.initializeAtBuildTime("jdk.incubator.concurrent"); } private Object collectReachableObjects(Object original) { diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/thread/LoomVirtualThreads.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/thread/LoomVirtualThreads.java index 61eec90c7831..6462334e5b43 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/thread/LoomVirtualThreads.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/thread/LoomVirtualThreads.java @@ -131,6 +131,13 @@ public void unpinCurrent() { Target_jdk_internal_vm_Continuation.unpin(); } + @Override + public boolean isCurrentPinned() { + Target_java_lang_Thread carrier = JavaThreads.toTarget(Target_java_lang_Thread.currentCarrierThread()); + Target_jdk_internal_vm_ContinuationScope scope = carrier.cont.getScope(); + return Target_jdk_internal_vm_Continuation.isPinned(scope); + } + @Override public Executor getScheduler(Thread thread) { return cast(thread).scheduler; diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/thread/SubstrateVirtualThread.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/thread/SubstrateVirtualThread.java index 12260400e20a..72b066101160 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/thread/SubstrateVirtualThread.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/thread/SubstrateVirtualThread.java @@ -197,11 +197,7 @@ private void unmount() { private boolean yieldContinuation() { assert this == Thread.currentThread(); - if (pins > 0) { - return false; - } - JavaFrameAnchor anchor = JavaFrameAnchors.getFrameAnchor(); - if (anchor.isNonNull() && cont.getBaseSP().aboveThan(anchor.getLastJavaSP())) { + if (isPinned()) { return false; } @@ -675,6 +671,15 @@ void unpin() { pins--; } + boolean isPinned() { + assert currentThread() == this; + if (pins > 0) { + return true; + } + JavaFrameAnchor anchor = JavaFrameAnchors.getFrameAnchor(); + return anchor.isNonNull() && cont.getBaseSP().aboveThan(anchor.getLastJavaSP()); + } + @Override public void run() { } diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/thread/SubstrateVirtualThreads.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/thread/SubstrateVirtualThreads.java index 339fac8a4f27..1e98199ea31d 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/thread/SubstrateVirtualThreads.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/thread/SubstrateVirtualThreads.java @@ -217,6 +217,11 @@ public void unpinCurrent() { current().unpin(); } + @Override + public boolean isCurrentPinned() { + return current().isPinned(); + } + @Override public Executor getScheduler(Thread thread) { return cast(thread).getScheduler(); 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 d1d4c8cd27f7..8fd02487833b 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,7 +31,6 @@ import java.util.Map; import java.util.Objects; import java.util.concurrent.ThreadFactory; -import java.util.function.BooleanSupplier; import org.graalvm.compiler.api.directives.GraalDirectives; import org.graalvm.compiler.replacements.ReplacementsUtil; @@ -59,11 +58,11 @@ import com.oracle.svm.core.jdk.JDK17OrLater; import com.oracle.svm.core.jdk.JDK19OrEarlier; import com.oracle.svm.core.jdk.JDK19OrLater; +import com.oracle.svm.core.jdk.JDK20OrLater; import com.oracle.svm.core.jdk.LoomJDK; import com.oracle.svm.core.jdk.NotLoomJDK; import com.oracle.svm.core.monitor.MonitorSupport; import com.oracle.svm.core.util.VMError; -import com.oracle.svm.util.ReflectionUtil; @TargetClass(Thread.class) @SuppressWarnings({"unused"}) @@ -80,6 +79,10 @@ public final class Target_java_lang_Thread { @Alias // @TargetElement(onlyWith = JDK19OrLater.class) // static int NO_INHERIT_THREAD_LOCALS; + + @Alias // + @TargetElement(onlyWith = JDK20OrLater.class) // + static Object NEW_THREAD_BINDINGS; // Checkstyle: resume /** This field is initialized when the thread actually starts executing. */ @@ -190,10 +193,13 @@ public final class Target_java_lang_Thread { @RecomputeFieldValue(kind = RecomputeFieldValue.Kind.Reset) // Object lockHelper; - @Inject @TargetElement(onlyWith = {HasScopedValueCache.class, HasExtentLocalCache.class, LoomJDK.class}) // + @Inject @TargetElement(onlyWith = JDK19OrLater.class) // @RecomputeFieldValue(kind = RecomputeFieldValue.Kind.Reset) // Object[] scopedValueCache; + @Alias @TargetElement(onlyWith = JDK20OrLater.class) // + Object scopedValueBindings; + @Alias @Platforms(InternalPlatform.NATIVE_ONLY.class) native void setPriority(int newPriority); @@ -370,6 +376,10 @@ private Target_java_lang_Thread( boolean allowThreadLocals = (characteristics & NO_THREAD_LOCALS) == 0; boolean inheritThreadLocals = (characteristics & NO_INHERIT_THREAD_LOCALS) == 0; JavaThreads.initializeNewThread(this, g, target, nameLocal, stackSize, acc, allowThreadLocals, inheritThreadLocals); + + if (JavaVersionUtil.JAVA_SPEC >= 20) { + this.scopedValueBindings = NEW_THREAD_BINDINGS; + } } @Substitute @@ -394,6 +404,10 @@ private Target_java_lang_Thread(String name, int characteristics, boolean bound) boolean allowThreadLocals = (characteristics & NO_THREAD_LOCALS) == 0; boolean inheritThreadLocals = (characteristics & NO_INHERIT_THREAD_LOCALS) == 0; JavaThreads.initNewThreadLocalsAndLoader(this, allowThreadLocals, inheritThreadLocals, Thread.currentThread()); + + if (JavaVersionUtil.JAVA_SPEC >= 20) { + this.scopedValueBindings = NEW_THREAD_BINDINGS; + } } @SuppressWarnings("hiding") @@ -665,29 +679,77 @@ static Thread startVirtualThreadWithoutLoom(Runnable task) { } @Substitute - @TargetElement(onlyWith = HasExtentLocalCache.class) + @TargetElement(onlyWith = {JDK19OrLater.class, JDK19OrEarlier.class}) static Object[] extentLocalCache() { return JavaThreads.toTarget(currentCarrierThread()).scopedValueCache; } @Substitute - @TargetElement(onlyWith = HasExtentLocalCache.class) + @TargetElement(onlyWith = {JDK19OrLater.class, JDK19OrEarlier.class}) static void setExtentLocalCache(Object[] cache) { JavaThreads.toTarget(currentCarrierThread()).scopedValueCache = cache; } @Substitute - @TargetElement(onlyWith = HasScopedValueCache.class) + @TargetElement(onlyWith = JDK20OrLater.class) static Object[] scopedValueCache() { return JavaThreads.toTarget(currentCarrierThread()).scopedValueCache; } @Substitute - @TargetElement(onlyWith = HasScopedValueCache.class) + @TargetElement(onlyWith = JDK20OrLater.class) static void setScopedValueCache(Object[] cache) { JavaThreads.toTarget(currentCarrierThread()).scopedValueCache = cache; } + @Alias + @TargetElement(onlyWith = JDK20OrLater.class) + static native Object scopedValueBindings(); + + /** + * This method is used to set and revert {@code ScopedValue} bindings as follows: + * + * {@code setScopedValueBindings(b); try { work(); } finally { setScopedValueBindings(previous); + * }} + * + * If a stack overflow or a throwing safepoint action (e.g. recurring callback) disrupts the + * second call, ScopedValue bindings can leak out of their scope. Therefore, we require this + * method and its direct callers to be uninterruptible. Both calls should be in a single same + * caller, which is the case for the usages in the JDK, and those are expected to remain the + * only direct usages. Because turning methods uninterruptible prevents inlining through them, + * we would prefer another approach such as force-inlining this method instead, but that would + * not prevent a throwing safepoint action in the {@code finally} block of the above pattern. + * + * {@code ScopedValue.Carrier} calls this method through the implementation of + * {@code JavaLangAccess}, which is an anonymous class that we cannot substitute, so we also + * substitute the calling class to invoke this method directly in + * {@link Target_jdk_incubator_concurrent_ScopedValue_Carrier}. + */ + @Substitute + @Uninterruptible(reason = "Must not call other methods which can trigger a stack overflow.", callerMustBe = true) + @TargetElement(onlyWith = JDK20OrLater.class) + static void setScopedValueBindings(Object bindings) { + Target_java_lang_Thread thread = SubstrateUtil.cast(PlatformThreads.currentThread.get(), Target_java_lang_Thread.class); + if (LoomSupport.isEnabled() && thread.vthread != null) { + thread = SubstrateUtil.cast(thread.vthread, Target_java_lang_Thread.class); + } + thread.scopedValueBindings = bindings; + } + + /** + * On HotSpot, this method determines the correct ScopedValue bindings for the current context + * by finding the top {@code runWith} invocation on the stack and extracting the bindings object + * parameter from the frame. It is used following stack overflows and other situations that + * could result in bindings leaking to another scope, during which {@link #scopedValueBindings} + * is cleared as a precaution. We don't have the means to extract the bindings object from the + * stack, but we ensure that {@link #setScopedValueBindings} does not trigger stack overflows + * and substitute {@link Target_jdk_incubator_concurrent_ScopedValue#scopedValueBindings} to + * never call this method. + */ + @Delete + @TargetElement(onlyWith = JDK20OrLater.class) + static native Object findScopedValueBindings(); + @Substitute static void blockedOn(Target_sun_nio_ch_Interruptible b) { JavaThreads.blockedOn(b); @@ -725,22 +787,6 @@ boolean isTerminated() { @Alias @TargetElement(onlyWith = JDK19OrLater.class) native long threadId(); - - private static class HasExtentLocalCache implements BooleanSupplier { - @Override - public boolean getAsBoolean() { - boolean result = ReflectionUtil.lookupMethod(true, Thread.class, "extentLocalCache") != null; - assert !result || JavaVersionUtil.JAVA_SPEC == 19 : "extentLocalCache should not exist as of JDK 20"; - return result; - } - } - - public static class HasScopedValueCache implements BooleanSupplier { - @Override - public boolean getAsBoolean() { - return ReflectionUtil.lookupMethod(true, Thread.class, "scopedValueCache") != null; - } - } } @TargetClass(value = Thread.class, innerClass = "Builder", onlyWith = JDK19OrLater.class) diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/thread/Target_jdk_incubator_concurrent_ScopedValue.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/thread/Target_jdk_incubator_concurrent_ScopedValue.java new file mode 100644 index 000000000000..a435799a74c9 --- /dev/null +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/thread/Target_jdk_incubator_concurrent_ScopedValue.java @@ -0,0 +1,120 @@ +/* + * 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.thread; + +import java.util.concurrent.Callable; +import java.util.function.BooleanSupplier; + +import org.graalvm.compiler.serviceprovider.JavaVersionUtil; +import org.graalvm.nativeimage.Platform; +import org.graalvm.nativeimage.Platforms; + +import com.oracle.svm.core.Uninterruptible; +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; +import com.oracle.svm.core.jdk.JDK20OrLater; +import com.oracle.svm.core.jdk.ModuleUtil; + +@Platforms(Platform.HOSTED_ONLY.class) +final class IncubatorConcurrentModule implements BooleanSupplier { + @Override + public boolean getAsBoolean() { + return JavaVersionUtil.JAVA_SPEC >= 20 && ModuleUtil.bootLayerContainsModule("jdk.incubator.concurrent"); + } +} + +@TargetClass(className = "jdk.incubator.concurrent.ScopedValue", onlyWith = IncubatorConcurrentModule.class) +final class Target_jdk_incubator_concurrent_ScopedValue { + @Substitute + static Target_jdk_incubator_concurrent_ScopedValue_Snapshot scopedValueBindings() { + Object bindings = Target_java_lang_Thread.scopedValueBindings(); + if (bindings == Target_java_lang_Thread.NEW_THREAD_BINDINGS) { + return Target_jdk_incubator_concurrent_ScopedValue_Snapshot.EMPTY_SNAPSHOT; + } + assert bindings != null; + return (Target_jdk_incubator_concurrent_ScopedValue_Snapshot) bindings; + } +} + +/** + * Substituted to directly call {@link Target_java_lang_Thread#setScopedValueBindings} for forced + * inlining. + */ +@TargetClass(className = "jdk.incubator.concurrent.ScopedValue", innerClass = "Carrier", onlyWith = IncubatorConcurrentModule.class) +final class Target_jdk_incubator_concurrent_ScopedValue_Carrier { + @Alias int bitmask; + + @Substitute + @Uninterruptible(reason = "Ensure no safepoint actions can disrupt reverting scoped value bindings.", calleeMustBe = false) + private R runWith(Target_jdk_incubator_concurrent_ScopedValue_Snapshot newSnapshot, Callable op) throws Exception { + Target_java_lang_Thread.setScopedValueBindings(newSnapshot); + try { + return Target_jdk_internal_vm_ScopedValueContainer.call(op); + } finally { + Target_java_lang_Thread.setScopedValueBindings(newSnapshot.prev); + Target_jdk_incubator_concurrent_ScopedValue_Cache.invalidate(bitmask); + } + } + + @Substitute + @Uninterruptible(reason = "Ensure no safepoint actions can disrupt reverting scoped value bindings.", calleeMustBe = false) + private void runWith(Target_jdk_incubator_concurrent_ScopedValue_Snapshot newSnapshot, Runnable op) { + Target_java_lang_Thread.setScopedValueBindings(newSnapshot); + try { + Target_jdk_internal_vm_ScopedValueContainer.run(op); + } finally { + Target_java_lang_Thread.setScopedValueBindings(newSnapshot.prev); + Target_jdk_incubator_concurrent_ScopedValue_Cache.invalidate(bitmask); + } + } +} + +@TargetClass(className = "jdk.internal.vm.ScopedValueContainer", onlyWith = IncubatorConcurrentModule.class) +final class Target_jdk_internal_vm_ScopedValueContainer { + @Alias + static native V call(Callable op) throws Exception; + + @Alias + static native void run(Runnable op); +} + +@TargetClass(className = "jdk.incubator.concurrent.ScopedValue", innerClass = "Snapshot", onlyWith = IncubatorConcurrentModule.class) +final class Target_jdk_incubator_concurrent_ScopedValue_Snapshot { + // Checkstyle: stop + @Alias @TargetElement(onlyWith = JDK20OrLater.class) // + static Target_jdk_incubator_concurrent_ScopedValue_Snapshot EMPTY_SNAPSHOT; + // Checkstyle: resume + + @Alias // + Target_jdk_incubator_concurrent_ScopedValue_Snapshot prev; +} + +@TargetClass(className = "jdk.incubator.concurrent.ScopedValue", innerClass = "Cache", onlyWith = IncubatorConcurrentModule.class) +final class Target_jdk_incubator_concurrent_ScopedValue_Cache { + @Alias + static native void invalidate(int toClearBits); +} diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/thread/Target_jdk_internal_vm_Continuation.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/thread/Target_jdk_internal_vm_Continuation.java index c30e41a29eb1..4f0416e8e276 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/thread/Target_jdk_internal_vm_Continuation.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/thread/Target_jdk_internal_vm_Continuation.java @@ -203,4 +203,7 @@ static void unpin() { carrier.cont.pinCount--; } } + + @Alias + static native boolean isPinned(Target_jdk_internal_vm_ContinuationScope scope); } diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/thread/Target_jdk_internal_vm_ThreadContainers.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/thread/Target_jdk_internal_vm_ThreadContainers.java index ba2fb38e9ea0..b9901913fb7c 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/thread/Target_jdk_internal_vm_ThreadContainers.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/thread/Target_jdk_internal_vm_ThreadContainers.java @@ -24,20 +24,27 @@ */ package com.oracle.svm.core.thread; -import com.oracle.svm.core.annotate.KeepOriginal; +import java.lang.ref.ReferenceQueue; +import java.lang.ref.WeakReference; +import java.util.Set; +import java.util.stream.Stream; + +import com.oracle.svm.core.annotate.Delete; import com.oracle.svm.core.annotate.Substitute; import com.oracle.svm.core.annotate.TargetClass; import com.oracle.svm.core.jdk.JDK19OrLater; /** - * The purpose of the target class is to support debugging and monitoring of threads. Because we - * currently don't provide/expose means for doing so, we replace it with an almost empty - * implementation. + * We currently don't provide/expose means for debugging and monitoring of threads, so we replace + * these methods with an empty implementation. */ @TargetClass(className = "jdk.internal.vm.ThreadContainers", onlyWith = JDK19OrLater.class) -@Substitute @SuppressWarnings("unused") final class Target_jdk_internal_vm_ThreadContainers { + // Checkstyle: stop + @Delete static Set> CONTAINER_REGISTRY; + @Delete static ReferenceQueue QUEUE; + // Checkstyle: resume @Substitute public static Object registerContainer(Target_jdk_internal_vm_ThreadContainer container) { @@ -48,8 +55,10 @@ public static Object registerContainer(Target_jdk_internal_vm_ThreadContainer co public static void deregisterContainer(Object key) { } - @KeepOriginal - public static native Target_jdk_internal_vm_ThreadContainer root(); + @Substitute + static Stream children(Target_jdk_internal_vm_ThreadContainer container) { + return Stream.empty(); + } } @TargetClass(className = "jdk.internal.vm.ThreadContainer", onlyWith = JDK19OrLater.class) diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/thread/VirtualThreads.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/thread/VirtualThreads.java index 8bdb4027fa8b..1c70c54b5221 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/thread/VirtualThreads.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/thread/VirtualThreads.java @@ -70,6 +70,8 @@ static boolean isSupported() { void unpinCurrent(); + boolean isCurrentPinned(); + Executor getScheduler(Thread thread); void blockedOn(Target_sun_nio_ch_Interruptible b); 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 72a9da22c0c5..ad1011edb3de 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 @@ -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 @@ -88,6 +88,7 @@ final class BundleSupport { Map pathCanonicalizations = new HashMap<>(); Map pathSubstitutions = new HashMap<>(); + private final boolean forceBuilderOnClasspath; private final List nativeImageArgs; private List updatedNativeImageArgs; @@ -97,7 +98,7 @@ final class BundleSupport { private static final int BUNDLE_FILE_FORMAT_VERSION_MAJOR = 0; private static final int BUNDLE_FILE_FORMAT_VERSION_MINOR = 9; - private static final String BUNDLE_INFO_MESSAGE_PREFIX = "GraalVM Native Image Bundle Support: "; + private static final String BUNDLE_INFO_MESSAGE_PREFIX = "Native Image Bundles: "; private static final String BUNDLE_TEMP_DIR_PREFIX = "bundleRoot-"; private static final String ORIGINAL_DIR_EXTENSION = ".orig"; @@ -106,9 +107,6 @@ final class BundleSupport { private final BundleProperties bundleProperties; - static boolean allowBundleSupport; - static final String UNLOCK_BUNDLE_SUPPORT_OPTION = "--enable-experimental-bundle-support"; - static final String BUNDLE_OPTION = "--bundle"; static final String BUNDLE_FILE_EXTENSION = ".nib"; @@ -122,11 +120,6 @@ String optionName() { } static BundleSupport create(NativeImage nativeImage, String bundleArg, NativeImage.ArgumentQueue args) { - if (!allowBundleSupport) { - throw NativeImage.showError( - "Bundle support is still experimental and needs to be unlocked with '" + UNLOCK_BUNDLE_SUPPORT_OPTION + "'. The unlock option must precede '" + bundleArg + "'."); - } - try { String variant = bundleArg.substring(BUNDLE_OPTION.length() + 1); String bundleFilename = null; @@ -211,7 +204,8 @@ private BundleSupport(NativeImage nativeImage) { } catch (IOException e) { throw NativeImage.showError("Unable to create bundle directory layout", e); } - this.nativeImageArgs = nativeImage.getNativeImageArgs(); + forceBuilderOnClasspath = !nativeImage.config.modulePathBuild; + nativeImageArgs = nativeImage.getNativeImageArgs(); } private BundleSupport(NativeImage nativeImage, String bundleFilenameArg) { @@ -262,6 +256,8 @@ private BundleSupport(NativeImage nativeImage, String bundleFilenameArg) { } bundleProperties.loadAndVerify(); + forceBuilderOnClasspath = bundleProperties.forceBuilderOnClasspath(); + nativeImage.config.modulePathBuild = !forceBuilderOnClasspath; try { Path inputDir = rootDir.resolve("input"); @@ -615,7 +611,7 @@ private Path writeBundle() { Path buildArgsFile = stageDir.resolve("build.json"); try (JsonWriter writer = new JsonWriter(buildArgsFile)) { - List equalsNonBundleOptions = List.of(UNLOCK_BUNDLE_SUPPORT_OPTION, CmdLineOptionHandler.VERBOSE_OPTION, CmdLineOptionHandler.DRY_RUN_OPTION); + List equalsNonBundleOptions = List.of(CmdLineOptionHandler.VERBOSE_OPTION, CmdLineOptionHandler.DRY_RUN_OPTION); List startsWithNonBundleOptions = List.of(BUNDLE_OPTION, DefaultOptionHandler.ADD_ENV_VAR_OPTION, nativeImage.oHPath); ArrayList bundleArgs = new ArrayList<>(updatedNativeImageArgs != null ? updatedNativeImageArgs : nativeImageArgs); ListIterator bundleArgsIterator = bundleArgs.listIterator(); @@ -772,9 +768,11 @@ private final class BundleProperties { private static final String PROPERTY_KEY_BUNDLE_FILE_VERSION_MAJOR = "BundleFileVersionMajor"; private static final String PROPERTY_KEY_BUNDLE_FILE_VERSION_MINOR = "BundleFileVersionMinor"; private static final String PROPERTY_KEY_BUNDLE_FILE_CREATION_TIMESTAMP = "BundleFileCreationTimestamp"; + private static final String PROPERTY_KEY_BUILDER_ON_CLASSPATH = "BuilderOnClasspath"; private static final String PROPERTY_KEY_IMAGE_BUILT = "ImageBuilt"; private static final String PROPERTY_KEY_BUILT_WITH_CONTAINER = "BuiltWithContainer"; private static final String PROPERTY_KEY_NATIVE_IMAGE_PLATFORM = "NativeImagePlatform"; + private static final String PROPERTY_KEY_NATIVE_IMAGE_VENDOR = "NativeImageVendor"; private static final String PROPERTY_KEY_NATIVE_IMAGE_VERSION = "NativeImageVersion"; private final Path bundlePropertiesFile; @@ -814,8 +812,12 @@ private void loadAndVerify() { } catch (NumberFormatException e) { throw NativeImage.showError(fileVersionKey + " in " + bundlePropertiesFileName + " is missing or ill-defined", e); } + String bundleVendor = properties.getOrDefault(PROPERTY_KEY_NATIVE_IMAGE_VENDOR, "unknown"); + String javaVmVendor = System.getProperty("java.vm.vendor"); + String currentVendor = bundleVendor.equals(javaVmVendor) ? "" : " != '" + javaVmVendor + "'"; String bundleVersion = properties.getOrDefault(PROPERTY_KEY_NATIVE_IMAGE_VERSION, "unknown"); - String currentVersion = bundleVersion.equals(NativeImage.getNativeImageVersion()) ? "" : " != '" + NativeImage.getNativeImageVersion() + "'"; + String javaVmVersion = System.getProperty("java.vm.version"); + String currentVersion = bundleVersion.equals(javaVmVersion) ? "" : " != '" + javaVmVersion + "'"; String bundlePlatform = properties.getOrDefault(PROPERTY_KEY_NATIVE_IMAGE_PLATFORM, "unknown"); String currentPlatform = bundlePlatform.equals(NativeImage.platform) ? "" : " != '" + NativeImage.platform + "'"; String bundleCreationTimestamp = properties.getOrDefault(PROPERTY_KEY_BUNDLE_FILE_CREATION_TIMESTAMP, ""); @@ -827,22 +829,32 @@ private void loadAndVerify() { localDateStr = "unknown time"; } nativeImage.showNewline(); - nativeImage.showMessage(String.format("%sLoaded Bundle from %s", BUNDLE_INFO_MESSAGE_PREFIX, bundleFileName)); - nativeImage.showMessage(String.format("%sBundle created at '%s'", BUNDLE_INFO_MESSAGE_PREFIX, localDateStr)); - nativeImage.showMessage(String.format("%sUsing version: '%s'%s on platform: '%s'%s", BUNDLE_INFO_MESSAGE_PREFIX, bundleVersion, currentVersion, bundlePlatform, currentPlatform)); + nativeImage.showMessage("%sLoaded Bundle from %s", BUNDLE_INFO_MESSAGE_PREFIX, bundleFileName); + nativeImage.showMessage("%sBundle created at '%s'", BUNDLE_INFO_MESSAGE_PREFIX, localDateStr); + nativeImage.showMessage("%sUsing version: '%s'%s (vendor '%s'%s) on platform: '%s'%s", BUNDLE_INFO_MESSAGE_PREFIX, + bundleVersion, currentVersion, + bundleVendor, currentVendor, + bundlePlatform, currentPlatform); + } + + private boolean forceBuilderOnClasspath() { + assert !properties.isEmpty() : "Needs to be called after loadAndVerify()"; + return Boolean.parseBoolean(properties.getOrDefault(PROPERTY_KEY_BUILDER_ON_CLASSPATH, Boolean.FALSE.toString())); } private void write() { properties.put(PROPERTY_KEY_BUNDLE_FILE_VERSION_MAJOR, String.valueOf(BUNDLE_FILE_FORMAT_VERSION_MAJOR)); properties.put(PROPERTY_KEY_BUNDLE_FILE_VERSION_MINOR, String.valueOf(BUNDLE_FILE_FORMAT_VERSION_MINOR)); properties.put(PROPERTY_KEY_BUNDLE_FILE_CREATION_TIMESTAMP, ZonedDateTime.now().format(DateTimeFormatter.ISO_DATE_TIME)); + properties.put(PROPERTY_KEY_BUILDER_ON_CLASSPATH, String.valueOf(forceBuilderOnClasspath)); boolean imageBuilt = !nativeImage.isDryRun(); properties.put(PROPERTY_KEY_IMAGE_BUILT, String.valueOf(imageBuilt)); if (imageBuilt) { properties.put(PROPERTY_KEY_BUILT_WITH_CONTAINER, String.valueOf(false)); } properties.put(PROPERTY_KEY_NATIVE_IMAGE_PLATFORM, NativeImage.platform); - properties.put(PROPERTY_KEY_NATIVE_IMAGE_VERSION, NativeImage.getNativeImageVersion()); + properties.put(PROPERTY_KEY_NATIVE_IMAGE_VENDOR, System.getProperty("java.vm.vendor")); + properties.put(PROPERTY_KEY_NATIVE_IMAGE_VERSION, System.getProperty("java.vm.version")); NativeImage.ensureDirectoryExists(bundlePropertiesFile.getParent()); try (OutputStream outputStream = Files.newOutputStream(bundlePropertiesFile)) { Properties p = new Properties(); 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 2a7aaaeae4b1..309cfde89a85 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 @@ -27,6 +27,7 @@ import java.io.File; import java.nio.file.Paths; import java.util.List; +import java.util.Optional; import java.util.regex.Pattern; import org.graalvm.compiler.options.OptionType; @@ -48,7 +49,7 @@ class CmdLineOptionHandler extends NativeImage.OptionHandler { private static final String VERBOSE_SERVER_OPTION = "--verbose-server"; private static final String SERVER_OPTION_PREFIX = "--server-"; - private static final String JAVA_RUNTIME_VERSION = System.getProperty("java.runtime.version"); + private static final String LAUNCHER_NAME = "native-image"; boolean useDebugAttach = false; @@ -84,9 +85,7 @@ private boolean consume(ArgumentQueue args, String headArg) { case "--version": args.poll(); singleArgumentCheck(args, headArg); - String message = NativeImage.getNativeImageVersion(); - message += " (Java Version " + JAVA_RUNTIME_VERSION + ")"; - nativeImage.showMessage(message); + printVersion(); System.exit(ExitStatus.OK.getValue()); return true; case "--help-extra": @@ -142,10 +141,6 @@ private boolean consume(ArgumentQueue args, String headArg) { String optionNames = args.poll(); nativeImage.setPrintFlagsWithExtraHelpOptionQuery(optionNames); return true; - case BundleSupport.UNLOCK_BUNDLE_SUPPORT_OPTION: - args.poll(); - BundleSupport.allowBundleSupport = true; - return true; case VERBOSE_SERVER_OPTION: args.poll(); NativeImage.showWarning("Ignoring server-mode native-image argument " + headArg + "."); @@ -189,6 +184,40 @@ private boolean consume(ArgumentQueue args, String headArg) { return false; } + /** + * Prints version output following + * "src/java.base/share/classes/java/lang/VersionProps.java.template#print(boolean)". + */ + private void printVersion() { + /* First line: platform version. */ + String javaVersion = System.getProperty("java.version"); + String javaVersionDate = System.getProperty("java.version.date"); + Optional versionOpt = Runtime.version().optional(); + boolean isLTS = versionOpt.isPresent() && versionOpt.get().startsWith("LTS"); + nativeImage.showMessage("%s %s %s", LAUNCHER_NAME, javaVersion, javaVersionDate, isLTS ? " LTS" : ""); + + /* Second line: runtime version (ie, libraries). */ + String javaRuntimeVersion = System.getProperty("java.runtime.version"); + + String jdkDebugLevel = System.getProperty("jdk.debug", "release"); + if ("release".equals(jdkDebugLevel)) { + /* Do not show debug level "release" builds */ + jdkDebugLevel = ""; + } else { + jdkDebugLevel = jdkDebugLevel + " "; + } + + String javaRuntimeName = System.getProperty("java.runtime.name"); + String vendorVersion = System.getProperty("java.vendor.version"); + nativeImage.showMessage("%s %s (%sbuild %s)", javaRuntimeName, vendorVersion, jdkDebugLevel, javaRuntimeVersion); + + /* Third line: VM information. */ + String javaVMName = System.getProperty("java.vm.name"); + String javaVMVersion = System.getProperty("java.vm.version"); + String javaVMInfo = System.getProperty("java.vm.info"); + nativeImage.showMessage("%s %s (%sbuild %s, %s)", javaVMName, vendorVersion, jdkDebugLevel, javaVMVersion, javaVMInfo); + } + private static void singleArgumentCheck(ArgumentQueue args, String arg) { if (!args.isEmpty()) { NativeImage.showError("Option " + arg + " cannot be combined with other options."); diff --git a/substratevm/src/com.oracle.svm.driver/src/com/oracle/svm/driver/NativeImage.java b/substratevm/src/com.oracle.svm.driver/src/com/oracle/svm/driver/NativeImage.java index cd9002b9ebd1..627c2707c459 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 @@ -112,20 +112,9 @@ private static String getPlatform() { return (OS.getCurrent().className + "-" + SubstrateUtil.getArchitectureName()).toLowerCase(); } - static String getNativeImageVersion() { - String message; - if (IS_AOT) { - message = System.getProperty("java.vm.version"); - } else { - message = "native-image " + graalvmVersion + " " + graalvmConfig; - } - return message; - } - - static final String graalvmVersion = System.getProperty("org.graalvm.version", "dev"); - static final String graalvmConfig = System.getProperty("org.graalvm.config", "CE"); - static final String graalvmVendor = System.getProperty("org.graalvm.vendor", "Oracle Corporation"); + static final String graalvmVendor = System.getProperty("org.graalvm.vendor", "GraalVM Community"); static final String graalvmVendorUrl = System.getProperty("org.graalvm.vendorurl", "https://www.graalvm.org/"); + static final String graalvmVendorVersion = System.getProperty("org.graalvm.vendorversion", "GraalVM CE"); private static Map getCompilerFlags() { Map result = new HashMap<>(); @@ -827,12 +816,9 @@ private void prepareImageBuildArgs() { /* Prevent JVM that runs the image builder to steal focus. */ addImageBuilderJavaArgs("-Djava.awt.headless=true"); - addImageBuilderJavaArgs("-Dorg.graalvm.version=" + graalvmVersion); addImageBuilderJavaArgs("-Dorg.graalvm.vendor=" + graalvmVendor); addImageBuilderJavaArgs("-Dorg.graalvm.vendorurl=" + graalvmVendorUrl); - if (!NativeImage.IS_AOT) { - addImageBuilderJavaArgs("-Dorg.graalvm.config=" + graalvmConfig); - } + addImageBuilderJavaArgs("-Dorg.graalvm.vendorversion=" + graalvmVendorVersion); addImageBuilderJavaArgs("-Dcom.oracle.graalvm.isaot=true"); addImageBuilderJavaArgs("-Djava.system.class.loader=" + CUSTOM_SYSTEM_CLASS_LOADER); @@ -1079,7 +1065,7 @@ private int completeImageBuild() { mainClass = getHostedOptionFinalArgumentValue(imageBuilderArgs, oHClass); boolean buildExecutable = imageBuilderArgs.stream().noneMatch(arg -> arg.contains(oHEnableSharedLibraryFlag)); boolean listModules = imageBuilderArgs.stream().anyMatch(arg -> arg.contains(oH + "+" + "ListModules")); - printFlags |= imageBuilderArgs.stream().anyMatch(arg -> arg.contains("-march=list")); + printFlags |= imageBuilderArgs.stream().anyMatch(arg -> arg.contains("-H:MicroArchitecture=list")); if (printFlags) { /* Ensure name for bundle support */ @@ -1454,6 +1440,10 @@ protected int buildImage(List javaArgs, LinkedHashSet cp, LinkedHa arguments.addAll(Arrays.asList(SubstrateOptions.WATCHPID_PREFIX, "" + ProcessProperties.getProcessID())); } + if (useBundle()) { + showWarning("Native Image Bundles are an experimental feature."); + } + BiFunction substituteAuxiliaryPath = useBundle() ? bundleSupport::substituteAuxiliaryPath : (a, b) -> a; Function imageArgsTransformer = rawArg -> apiOptionHandler.transformBuilderArgument(rawArg, substituteAuxiliaryPath); List finalImageArgs = imageArgs.stream().map(imageArgsTransformer).collect(Collectors.toList()); @@ -1515,6 +1505,7 @@ protected int buildImage(List javaArgs, LinkedHashSet cp, LinkedHa try { p = pb.inheritIO().start(); imageBuilderPid = p.pid(); + installImageBuilderCleanupHook(p); return p.waitFor(); } catch (IOException | InterruptedException e) { throw showError(e.getMessage()); @@ -1525,6 +1516,23 @@ protected int buildImage(List javaArgs, LinkedHashSet cp, LinkedHa } } + /** + * Adds a shutdown hook to kill the image builder process if it's still alive. + * + * @param p image builder process + */ + private static void installImageBuilderCleanupHook(Process p) { + Runtime.getRuntime().addShutdownHook(new Thread() { + @Override + public void run() { + if (p.isAlive()) { + System.out.println("DESTROYING " + p.pid()); + p.destroy(); + } + } + }); + } + boolean useBundle() { return bundleSupport != null; } @@ -1972,6 +1980,10 @@ void showMessage(String message) { show(System.out::println, message); } + void showMessage(String format, Object... args) { + showMessage(String.format(format, args)); + } + void showNewline() { System.out.println(); } @@ -1992,8 +2004,7 @@ void showOutOfMemoryWarning() { } String maxHeapText = lastMaxHeapValue == null ? "" : " (The maximum heap size of the process was set to '" + lastMaxHeapValue + "'.)"; String additionalAction = lastMaxHeapValue == null ? "" : " or increase the maximum heap size using the '" + oXmx + "' option"; - showMessage(String.format("The Native Image build process ran out of memory.%s%nPlease make sure your build system has more memory available%s.", - maxHeapText, additionalAction)); + showMessage("The Native Image build process ran out of memory.%s%nPlease make sure your build system has more memory available%s.", maxHeapText, additionalAction); } public static void showWarning(String message) { @@ -2093,21 +2104,18 @@ protected String getXmxValue(int maxInstances) { return Long.toUnsignedString(memMax); } - private static final boolean IS_CI = SubstrateUtil.isRunningInCI(); - private static final boolean IS_DUMB_TERM = isDumbTerm(); - private static boolean isDumbTerm() { String term = System.getenv().getOrDefault("TERM", ""); return term.isEmpty() || term.equals("dumb") || term.equals("unknown"); } private static boolean hasColorSupport() { - return !IS_DUMB_TERM && !IS_CI && OS.getCurrent() != OS.WINDOWS && + return !isDumbTerm() && !SubstrateUtil.isRunningInCI() && OS.getCurrent() != OS.WINDOWS && System.getenv("NO_COLOR") == null /* https://no-color.org/ */; } private static boolean hasProgressSupport(List imageBuilderArgs) { - return !IS_DUMB_TERM && !IS_CI && + return !isDumbTerm() && !SubstrateUtil.isRunningInCI() && /* * When DebugOptions.Log is used, progress cannot be reported as logging * works around NativeImageSystemIOWrappers to access stdio handles. 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 3da43a2790c2..69df667f3e9b 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 @@ -74,7 +74,6 @@ import org.graalvm.word.WordFactory; import com.oracle.svm.core.c.CGlobalData; -import com.oracle.svm.core.c.CGlobalDataFactory; import com.oracle.svm.core.heap.Heap; import com.sun.management.ThreadMXBean; @@ -100,13 +99,6 @@ */ public final class LibGraalEntryPoints { - /** - * @see org.graalvm.compiler.hotspot.HotSpotTTYStreamProvider#execute - */ - static final CGlobalData LOG_FILE_BARRIER = CGlobalDataFactory.createWord((Pointer) WordFactory.zero()); - - static final CGlobalData GLOBAL_TIMESTAMP = CGlobalDataFactory.createBytes(() -> 8); - /** * Map from a foreign call signature to a C global word that is the address of a pointer to a * {@link RuntimeStubInfo} struct. 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 d1ea5f1b4240..ae3fb54a1d0b 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 @@ -109,7 +109,6 @@ import org.graalvm.nativeimage.hosted.Feature; import org.graalvm.nativeimage.hosted.RuntimeJNIAccess; import org.graalvm.nativeimage.hosted.RuntimeReflection; -import org.graalvm.word.LocationIdentity; import org.graalvm.word.Pointer; import org.graalvm.word.WordFactory; @@ -738,27 +737,9 @@ private static void shutdownLibGraal(HotSpotGraalRuntime runtime) { } } -@TargetClass(className = "org.graalvm.compiler.hotspot.HotSpotTTYStreamProvider", onlyWith = LibGraalFeature.IsEnabled.class) -final class Target_org_graalvm_compiler_hotspot_HotSpotTTYStreamProvider { - - @Substitute - private static Pointer getBarrierPointer() { - return LibGraalEntryPoints.LOG_FILE_BARRIER.get(); - } -} - @TargetClass(className = "org.graalvm.compiler.serviceprovider.GraalServices", onlyWith = LibGraalFeature.IsEnabled.class) final class Target_org_graalvm_compiler_serviceprovider_GraalServices { - @Substitute - public static long getGlobalTimeStamp() { - Pointer timestamp = LibGraalEntryPoints.GLOBAL_TIMESTAMP.get(); - if (timestamp.readLong(0) == 0) { - timestamp.compareAndSwapLong(0, 0, System.currentTimeMillis(), LocationIdentity.ANY_LOCATION); - } - return timestamp.readLong(0); - } - @Substitute private static void notifyLowMemoryPoint(boolean fullGC) { Heap.getHeap().getGC().maybeCauseUserRequestedCollection(GCCause.HintedGC, fullGC); @@ -829,9 +810,11 @@ private static String removePrefix(String value, String prefix) { @TargetClass(className = "org.graalvm.compiler.truffle.common.TruffleCompilerRuntimeInstance", onlyWith = LibGraalFeature.IsEnabled.class) final class Target_org_graalvm_compiler_truffle_common_TruffleCompilerRuntimeInstance { // Checkstyle: stop - @Alias @RecomputeFieldValue(kind = Kind.Reset, isFinal = true) static Object TRUFFLE_RUNTIME; + @Alias// + @RecomputeFieldValue(kind = Kind.Reset, isFinal = true) static Object TRUFFLE_RUNTIME; // Checkstyle: resume - @Alias @RecomputeFieldValue(kind = Kind.Reset) static TruffleCompilerRuntime truffleCompilerRuntime; + @Alias// + @RecomputeFieldValue(kind = Kind.Reset) static TruffleCompilerRuntime truffleCompilerRuntime; } @TargetClass(className = "org.graalvm.compiler.core.GraalServiceThread", onlyWith = LibGraalFeature.IsEnabled.class) diff --git a/substratevm/src/com.oracle.svm.graal/src/com/oracle/svm/graal/GraalSubstitutions.java b/substratevm/src/com.oracle.svm.graal/src/com/oracle/svm/graal/GraalSubstitutions.java index 786bfb0dbe51..0f1fc0b92abd 100644 --- a/substratevm/src/com.oracle.svm.graal/src/com/oracle/svm/graal/GraalSubstitutions.java +++ b/substratevm/src/com.oracle.svm.graal/src/com/oracle/svm/graal/GraalSubstitutions.java @@ -28,6 +28,7 @@ import static com.oracle.svm.core.annotate.RecomputeFieldValue.Kind.FromAlias; import java.io.PrintStream; +import java.lang.ref.Cleaner; import java.util.ArrayList; import java.util.List; import java.util.Map; @@ -60,18 +61,25 @@ import org.graalvm.compiler.phases.common.CanonicalizerPhase; import org.graalvm.compiler.phases.tiers.HighTierContext; import org.graalvm.compiler.printer.NoDeadCodeVerifyHandler; +import org.graalvm.compiler.serviceprovider.GlobalAtomicLong; import org.graalvm.nativeimage.CurrentIsolate; import org.graalvm.nativeimage.ImageSingletons; import org.graalvm.nativeimage.hosted.FieldValueTransformer; +import org.graalvm.word.Pointer; +import org.graalvm.word.WordFactory; import com.oracle.svm.core.SubstrateTargetDescription; import com.oracle.svm.core.annotate.Alias; +import com.oracle.svm.core.annotate.Delete; import com.oracle.svm.core.annotate.Inject; 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.Substitute; 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.config.ConfigurationValues; import com.oracle.svm.core.log.Log; import com.oracle.svm.core.option.HostedOptionValues; @@ -159,7 +167,8 @@ public Object transform(Object receiver, Object originalValue) { * The cache in {@link DebugContext}.Immutable can hold onto {@link HostedOptionValues} so must * be cleared. */ - @Alias @RecomputeFieldValue(kind = Custom, declClass = ClearImmutableCache.class)// + @Alias// + @RecomputeFieldValue(kind = Custom, declClass = ClearImmutableCache.class)// private static Target_org_graalvm_compiler_debug_DebugContext_Immutable[] CACHE; } @@ -176,14 +185,16 @@ public Object transform(Object receiver, Object originalValue) { * Cannot do service loading at runtime so cache the loaded service providers in the native * image. */ - @Alias @RecomputeFieldValue(kind = Custom, declClass = CachedFactories.class)// + @Alias// + @RecomputeFieldValue(kind = Custom, declClass = CachedFactories.class)// private static Iterable LOADER; } @TargetClass(value = TimeSource.class, onlyWith = RuntimeCompilationFeature.IsEnabled.class) final class Target_org_graalvm_compiler_debug_TimeSource { // Checkstyle: stop - @Alias @RecomputeFieldValue(kind = FromAlias)// + @Alias// + @RecomputeFieldValue(kind = FromAlias)// private static boolean USING_THREAD_CPU_TIME = false; // Checkstyle: resume } @@ -191,7 +202,8 @@ final class Target_org_graalvm_compiler_debug_TimeSource { @TargetClass(value = org.graalvm.compiler.debug.TTY.class, onlyWith = RuntimeCompilationFeature.IsEnabledAndNotLibgraal.class) final class Target_org_graalvm_compiler_debug_TTY { - @Alias @RecomputeFieldValue(kind = FromAlias)// + @Alias// + @RecomputeFieldValue(kind = FromAlias)// private static PrintStream out = Log.logStream(); } @@ -209,6 +221,42 @@ public static long getIsolateID() { } } +class GlobalAtomicLongAddressProvider implements FieldValueTransformer { + @Override + public Object transform(Object receiver, Object originalValue) { + long initialValue = ((GlobalAtomicLong) receiver).getInitialValue(); + return CGlobalDataFactory.createWord((Pointer) WordFactory.unsigned(initialValue), null, true); + } +} + +@TargetClass(className = "org.graalvm.compiler.serviceprovider.GlobalAtomicLong", onlyWith = RuntimeCompilationFeature.IsEnabled.class) +final class Target_org_graalvm_compiler_serviceprovider_GlobalAtomicLong { + + @Inject// + @RecomputeFieldValue(kind = Kind.Custom, declClass = GlobalAtomicLongAddressProvider.class) // + private CGlobalData addressSupplier; + + @Delete private long address; + + @Delete private static Cleaner cleaner; + + /** + * Delete the constructor to ensure instances of {@link GlobalAtomicLong} cannot be created at + * runtime. + */ + @Substitute + @TargetElement(name = TargetElement.CONSTRUCTOR_NAME) + @SuppressWarnings({"unused", "static-method"}) + public void constructor(long initialValue) { + throw VMError.unsupportedFeature("Cannot create " + GlobalAtomicLong.class.getName() + " objects in native image runtime"); + } + + @Substitute + private long getAddress() { + return addressSupplier.get().rawValue(); + } +} + /* * The following substitutions replace methods where reflection is used in the Graal code. */ @@ -216,10 +264,12 @@ public static long getIsolateID() { @TargetClass(value = org.graalvm.compiler.debug.KeyRegistry.class, onlyWith = RuntimeCompilationFeature.IsEnabled.class) final class Target_org_graalvm_compiler_debug_KeyRegistry { - @Alias @RecomputeFieldValue(kind = FromAlias)// + @Alias// + @RecomputeFieldValue(kind = FromAlias)// private static EconomicMap keyMap = EconomicMap.create(); - @Alias @RecomputeFieldValue(kind = FromAlias)// + @Alias// + @RecomputeFieldValue(kind = FromAlias)// private static List keys = new ArrayList<>(); } @@ -292,10 +342,12 @@ static LIRPhase.LIRPhaseStatistics getLIRPhaseStatistics(Class clazz) { @TargetClass(value = org.graalvm.compiler.graph.NodeClass.class, onlyWith = RuntimeCompilationFeature.IsEnabled.class) final class Target_org_graalvm_compiler_graph_NodeClass { - @Alias @RecomputeFieldValue(kind = RecomputeFieldValue.Kind.Custom, declClass = FieldsOffsetsFeature.InputsIterationMaskRecomputation.class)// + @Alias// + @RecomputeFieldValue(kind = RecomputeFieldValue.Kind.Custom, declClass = FieldsOffsetsFeature.InputsIterationMaskRecomputation.class)// private long inputsIteration; - @Alias @RecomputeFieldValue(kind = RecomputeFieldValue.Kind.Custom, declClass = FieldsOffsetsFeature.SuccessorsIterationMaskRecomputation.class)// + @Alias// + @RecomputeFieldValue(kind = RecomputeFieldValue.Kind.Custom, declClass = FieldsOffsetsFeature.SuccessorsIterationMaskRecomputation.class)// private long successorIteration; @Substitute @@ -371,10 +423,12 @@ final class Target_org_graalvm_compiler_nodes_NamedLocationIdentity_DB { */ @TargetClass(value = TargetDescription.class, onlyWith = RuntimeCompilationFeature.IsEnabled.class) final class Target_jdk_vm_ci_code_TargetDescription { - @Alias @InjectAccessors(value = InlineObjectsAccessor.class) // + @Alias// + @InjectAccessors(value = InlineObjectsAccessor.class) // boolean inlineObjects; - @Inject @RecomputeFieldValue(kind = RecomputeFieldValue.Kind.Reset) // + @Inject// + @RecomputeFieldValue(kind = RecomputeFieldValue.Kind.Reset) // Boolean inlineObjectsValue; @SuppressWarnings("unused") diff --git a/substratevm/src/com.oracle.svm.graal/src/com/oracle/svm/graal/isolated/DisableSnippetCountersFeature.java b/substratevm/src/com.oracle.svm.graal/src/com/oracle/svm/graal/isolated/DisableSnippetCountersFeature.java index e754d85460b9..08dc95d8c4a0 100644 --- a/substratevm/src/com.oracle.svm.graal/src/com/oracle/svm/graal/isolated/DisableSnippetCountersFeature.java +++ b/substratevm/src/com.oracle.svm.graal/src/com/oracle/svm/graal/isolated/DisableSnippetCountersFeature.java @@ -36,9 +36,8 @@ import com.oracle.svm.core.ParsingReason; import com.oracle.svm.core.SubstrateOptions; -import com.oracle.svm.core.feature.InternalFeature; -import com.oracle.svm.core.meta.SubstrateObjectConstant; import com.oracle.svm.core.feature.AutomaticallyRegisteredFeature; +import com.oracle.svm.core.feature.InternalFeature; import jdk.vm.ci.meta.JavaConstant; import jdk.vm.ci.meta.JavaKind; @@ -58,11 +57,11 @@ public boolean handleLoadField(GraphBuilderContext b, ValueNode object, Resolved return true; } if (field.getType().getName().equals(snippetCounterName)) { - b.addPush(JavaKind.Object, ConstantNode.forConstant(SubstrateObjectConstant.forObject(SnippetCounter.DISABLED_COUNTER), b.getMetaAccess())); + b.addPush(JavaKind.Object, ConstantNode.forConstant(b.getSnippetReflection().forObject(SnippetCounter.DISABLED_COUNTER), b.getMetaAccess())); return true; } if (field.getType().getName().equals(snippetIntegerHistogramName)) { - b.addPush(JavaKind.Object, ConstantNode.forConstant(SubstrateObjectConstant.forObject(SnippetIntegerHistogram.DISABLED_COUNTER), b.getMetaAccess())); + b.addPush(JavaKind.Object, ConstantNode.forConstant(b.getSnippetReflection().forObject(SnippetIntegerHistogram.DISABLED_COUNTER), b.getMetaAccess())); return true; } return false; diff --git a/substratevm/src/com.oracle.svm.graal/src/com/oracle/svm/graal/meta/RuntimeCodeInstaller.java b/substratevm/src/com.oracle.svm.graal/src/com/oracle/svm/graal/meta/RuntimeCodeInstaller.java index 22bac376d67a..97025eb2b4c0 100644 --- a/substratevm/src/com.oracle.svm.graal/src/com/oracle/svm/graal/meta/RuntimeCodeInstaller.java +++ b/substratevm/src/com.oracle.svm.graal/src/com/oracle/svm/graal/meta/RuntimeCodeInstaller.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, 2020, 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 @@ -60,6 +60,7 @@ import com.oracle.svm.core.config.ConfigurationValues; import com.oracle.svm.core.deopt.SubstrateInstalledCode; import com.oracle.svm.core.graal.code.NativeImagePatcher; +import com.oracle.svm.core.graal.code.SubstrateBackend; import com.oracle.svm.core.graal.code.SubstrateCompilationResult; import com.oracle.svm.core.graal.meta.SharedRuntimeMethod; import com.oracle.svm.core.heap.CodeReferenceMapEncoder; @@ -224,8 +225,18 @@ protected void doPrepareInstall(ReferenceAdjuster adjuster, CodeInfo codeInfo) { (SubstrateObjectConstant) constant); }); + int entryPointOffset = 0; + + /* If the code starts after an offset, adjust the entry point accordingly */ + for (CompilationResult.CodeMark mark : compilation.getMarks()) { + if (mark.id == SubstrateBackend.SubstrateMarkId.PROLOGUE_START) { + assert entryPointOffset == 0; + entryPointOffset = mark.pcOffset; + } + } + NonmovableArray observerHandles = InstalledCodeObserverSupport.installObservers(codeObservers); - RuntimeCodeInfoAccess.initialize(codeInfo, code, codeSize, dataOffset, dataSize, codeAndDataMemorySize, tier, observerHandles, false); + RuntimeCodeInfoAccess.initialize(codeInfo, code, entryPointOffset, codeSize, dataOffset, dataSize, codeAndDataMemorySize, tier, observerHandles, false); CodeReferenceMapEncoder encoder = new CodeReferenceMapEncoder(); encoder.add(objectConstants.referenceMap); diff --git a/substratevm/src/com.oracle.svm.graal/src/com/oracle/svm/graal/meta/SubstrateInstalledCodeImpl.java b/substratevm/src/com.oracle.svm.graal/src/com/oracle/svm/graal/meta/SubstrateInstalledCodeImpl.java index e37eaa25d05d..3877dd463be8 100644 --- a/substratevm/src/com.oracle.svm.graal/src/com/oracle/svm/graal/meta/SubstrateInstalledCodeImpl.java +++ b/substratevm/src/com.oracle.svm.graal/src/com/oracle/svm/graal/meta/SubstrateInstalledCodeImpl.java @@ -81,10 +81,10 @@ public boolean isAlive() { } @Override - public void setAddress(long address, ResolvedJavaMethod method) { + public void setAddress(long address, long entryPoint, ResolvedJavaMethod method) { assert VMOperation.isInProgressAtSafepoint(); this.address = address; - this.entryPoint = address; + this.entryPoint = entryPoint; } @Override diff --git a/substratevm/src/com.oracle.svm.hosted.jdk17/src/com/oracle/svm/hosted/jdk17/JNIRegistrationSupport_JDK17OrLater.java b/substratevm/src/com.oracle.svm.hosted.jdk17/src/com/oracle/svm/hosted/jdk17/JNIRegistrationSupport_JDK17OrLater.java index c2c09df37063..95a2e9b72cc7 100644 --- a/substratevm/src/com.oracle.svm.hosted.jdk17/src/com/oracle/svm/hosted/jdk17/JNIRegistrationSupport_JDK17OrLater.java +++ b/substratevm/src/com.oracle.svm.hosted.jdk17/src/com/oracle/svm/hosted/jdk17/JNIRegistrationSupport_JDK17OrLater.java @@ -51,6 +51,6 @@ public boolean isInConfiguration(IsInConfigurationAccess access) { @Override public void registerGraphBuilderPlugins(Providers providers, Plugins plugins, ParsingReason reason) { - JNIRegistrationSupport.singleton().registerLoadLibraryPlugin(plugins, BootLoader.class); + JNIRegistrationSupport.singleton().registerLoadLibraryPlugin(providers, plugins, BootLoader.class); } } diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/FallbackFeature.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/FallbackFeature.java index 5c6f16cdfd19..cf4b3e554134 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/FallbackFeature.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/FallbackFeature.java @@ -43,8 +43,8 @@ import com.oracle.graal.pointsto.meta.AnalysisMethod; import com.oracle.svm.core.FallbackExecutor; import com.oracle.svm.core.SubstrateOptions; -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.UserError; import com.oracle.svm.core.util.VMError; import com.oracle.svm.hosted.FeatureImpl.AfterAnalysisAccessImpl; @@ -283,6 +283,7 @@ public void beforeAnalysis(BeforeAnalysisAccess a) { } public FallbackImageRequest reflectionFallback = null; + public boolean ignoreReflectionFallback = false; public FallbackImageRequest resourceFallback = null; public FallbackImageRequest jniFallback = null; public FallbackImageRequest proxyFallback = null; @@ -313,7 +314,9 @@ public void afterAnalysis(AfterAnalysisAccess a) { if (!reflectionCalls.isEmpty()) { reflectionCalls.add(ABORT_MSG_PREFIX + " due to reflection use without configuration."); - reflectionFallback = new FallbackImageRequest(reflectionCalls); + if (!ignoreReflectionFallback) { + reflectionFallback = new FallbackImageRequest(reflectionCalls); + } } if (!resourceCalls.isEmpty()) { resourceCalls.add(ABORT_MSG_PREFIX + " due to accessing resources without configuration."); 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 af174d6c60d6..7050151fa4ef 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 @@ -73,7 +73,6 @@ import com.oracle.svm.core.meta.SharedField; import com.oracle.svm.core.meta.SharedMethod; import com.oracle.svm.core.meta.SharedType; -import com.oracle.svm.core.meta.SubstrateObjectConstant; import com.oracle.svm.core.option.SubstrateOptionsParser; import com.oracle.svm.core.util.VMError; import com.oracle.svm.hosted.analysis.Inflation; @@ -588,10 +587,10 @@ public void registerAsImmutable(Object root, Predicate includeObject) { addToWorklist(aUniverse.replaceObject(element), includeObject, worklist, registeredObjects); } } else { - JavaConstant constant = SubstrateObjectConstant.forObject(cur); + JavaConstant constant = aUniverse.getSnippetReflection().forObject(cur); for (HostedField field : getMetaAccess().lookupJavaType(constant).getInstanceFields(true)) { if (field.isAccessed() && field.getStorageKind() == JavaKind.Object) { - Object fieldValue = SubstrateObjectConstant.asObject(field.readValue(constant)); + Object fieldValue = aUniverse.getSnippetReflection().asObject(Object.class, field.readValue(constant)); addToWorklist(fieldValue, includeObject, worklist, registeredObjects); } } 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 38c9362fc31c..c110cc0c8867 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 @@ -24,7 +24,6 @@ */ package com.oracle.svm.hosted; -import java.lang.annotation.Annotation; import java.nio.file.Path; import java.util.ArrayList; import java.util.HashSet; @@ -75,15 +74,13 @@ 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.util.ReflectionUtil; +import jdk.internal.ValueBased; import jdk.vm.ci.meta.JavaKind; import jdk.vm.ci.meta.MetaAccessProvider; import jdk.vm.ci.meta.ResolvedJavaField; public class HostedConfiguration { - @SuppressWarnings("unchecked") private static final Class VALUE_BASED_ANNOTATION = // - (Class) ReflectionUtil.lookupClass(false, "jdk.internal.ValueBased"); public HostedConfiguration() { } @@ -269,7 +266,7 @@ protected void processedSynchronizedTypes(BigBang bb, HostedUniverse hUniverse, * Types that must be immutable cannot have a monitor field. */ protected static void maybeSetMonitorField(HostedUniverse hUniverse, Set immutableTypes, AnalysisType type) { - if (!type.isArray() && !immutableTypes.contains(type) && !type.isAnnotationPresent(VALUE_BASED_ANNOTATION)) { + if (!type.isArray() && !immutableTypes.contains(type) && !type.isAnnotationPresent(ValueBased.class)) { setMonitorField(hUniverse, type); } } 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 b15ee608bc26..6223703e5c41 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 @@ -246,6 +246,7 @@ import com.oracle.svm.hosted.analysis.SVMAnalysisMetaAccess; import com.oracle.svm.hosted.analysis.SubstrateUnsupportedFeatures; import com.oracle.svm.hosted.annotation.AnnotationSupport; +import com.oracle.svm.hosted.annotation.SubstrateAnnotationExtractor; import com.oracle.svm.hosted.c.CAnnotationProcessorCache; import com.oracle.svm.hosted.c.CConstantValueSupportImpl; import com.oracle.svm.hosted.c.NativeLibraries; @@ -993,8 +994,10 @@ public static AnalysisUniverse createAnalysisUniverse(OptionValues options, Targ } else { analysisFactory = new PointsToAnalysisFactory(); } - return new AnalysisUniverse(hostVM, target.wordJavaKind, analysisPolicy, aSubstitutions, originalMetaAccess, - new SubstrateSnippetReflectionProvider(new SubstrateWordTypes(originalMetaAccess, FrameAccess.getWordKind())), analysisFactory, loader.classLoaderSupport.annotationExtractor); + SubstrateAnnotationExtractor annotationExtractor = (SubstrateAnnotationExtractor) loader.classLoaderSupport.annotationExtractor; + SubstrateSnippetReflectionProvider snippetReflection = new SubstrateSnippetReflectionProvider(new SubstrateWordTypes(originalMetaAccess, FrameAccess.getWordKind())); + annotationExtractor.setSnippetReflection(snippetReflection); + return new AnalysisUniverse(hostVM, target.wordJavaKind, analysisPolicy, aSubstitutions, originalMetaAccess, snippetReflection, analysisFactory, annotationExtractor); } public static AnnotationSubstitutionProcessor createAnnotationSubstitutionProcessor(MetaAccessProvider originalMetaAccess, ImageClassLoader loader, @@ -1291,7 +1294,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(), providers.getWordTypes(), nativeLibs)); + plugins.appendNodePlugin(new CInterfaceInvocationPlugin(providers.getMetaAccess(), providers.getSnippetReflection(), providers.getWordTypes(), nativeLibs)); plugins.appendNodePlugin(new LocalizationFeature.CharsetNodePlugin()); plugins.appendInlineInvokePlugin(wordOperationPlugin); @@ -1709,7 +1712,7 @@ protected void processNativeLibraryImports(NativeLibraries nativeLibs, MetaAcces } nativeLibs.processCLibraryAnnotations(loader); - nativeLibs.finish(); + nativeLibs.finish(loader); nativeLibs.reportErrors(); } 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 f62e1c346031..15f61d66594b 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 @@ -77,7 +77,6 @@ import com.oracle.svm.core.hub.ClassForNameSupport; import com.oracle.svm.core.jdk.Resources; import com.oracle.svm.core.jdk.resources.ResourceStorageEntry; -import com.oracle.svm.core.meta.SubstrateObjectConstant; import com.oracle.svm.core.option.HostedOptionValues; import com.oracle.svm.core.reflect.ReflectionMetadataDecoder; import com.oracle.svm.core.util.VMError; @@ -247,14 +246,11 @@ public void printUnsuccessfulInitializeEnd() { public void printInitializeEnd() { stagePrinter.end(getTimer(TimerCollection.Registry.CLASSLIST).getTotalTime() + getTimer(TimerCollection.Registry.SETUP).getTotalTime()); - String version = ImageSingletons.lookup(VM.class).version; - recordJsonMetric(GeneralInfo.GRAALVM_VERSION, version); - l().a(" ").doclink("Version info", "#glossary-version-info").a(": '").a(version).a("'").println(); - String javaVersion = System.getProperty("java.runtime.version"); - recordJsonMetric(GeneralInfo.JAVA_VERSION, javaVersion); - if (javaVersion != null) { - l().a(" ").doclink("Java version info", "#glossary-java-version-info").a(": '").a(javaVersion).a("'").println(); - } + VM vm = ImageSingletons.lookup(VM.class); + recordJsonMetric(GeneralInfo.JAVA_VERSION, vm.version); + recordJsonMetric(GeneralInfo.VENDOR, vm.vendor); + recordJsonMetric(GeneralInfo.GRAALVM_VERSION, vm.vendorVersion + " " + vm.version); // deprecated + l().a(" ").doclink("Java version", "#glossary-java-info").a(": ").a(vm.version).a(", ").doclink("vendor", "#glossary-java-info").a(": ").a(vm.vendor).println(); String optimizationLevel = SubstrateOptions.Optimize.getValue(); recordJsonMetric(GeneralInfo.GRAAL_COMPILER_OPTIMIZATION_LEVEL, optimizationLevel); String march = CPUType.getSelectedOrDefaultMArch(); @@ -517,7 +513,7 @@ public static void calculateHeapBreakdown(Map heapBreakdown, LinkS heapBreakdown.merge(o.getClazz().toJavaName(true), o.getSize(), Long::sum); JavaConstant javaObject = o.getConstant(); if (reportStringBytes && metaAccess.isInstanceOf(javaObject, String.class)) { - stringByteLength += Utils.getInternalByteArrayLength((String) SubstrateObjectConstant.asObject(javaObject)); + stringByteLength += Utils.getInternalByteArrayLength(metaAccess.getUniverse().getSnippetReflection().asObject(String.class, javaObject)); } } @@ -696,7 +692,7 @@ private void printErrorMessage(Optional optionalError, OptionValues p l().link(NativeImageOptions.getErrorFilePath(parsedHostedOptions)).println(); l().println(); l().a("If you are unable to resolve this problem, please file an issue with the error report at:").println(); - var supportURL = ImageSingletonsSupport.isInstalled() ? ImageSingletons.lookup(VM.class).supportURL : new VM().supportURL; + var supportURL = VM.getErrorReportingInstance().supportURL; l().link(supportURL, supportURL).println(); } } diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/ProgressReporterJsonHelper.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/ProgressReporterJsonHelper.java index 1a0e2432ad4f..3066d3415df2 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/ProgressReporterJsonHelper.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/ProgressReporterJsonHelper.java @@ -225,6 +225,7 @@ public void record(ProgressReporterJsonHelper helper, Object value) { public enum GeneralInfo implements JsonMetric { IMAGE_NAME("name", null), JAVA_VERSION("java_version", null), + VENDOR("vendor", null), GRAALVM_VERSION("graalvm_version", null), GRAAL_COMPILER_OPTIMIZATION_LEVEL("optimization_level", "graal_compiler"), GRAAL_COMPILER_MARCH("march", "graal_compiler"), diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/ReachabilityRegistrationNode.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/ReachabilityRegistrationNode.java new file mode 100644 index 000000000000..1b5e4ea4aa7c --- /dev/null +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/ReachabilityRegistrationNode.java @@ -0,0 +1,89 @@ +/* + * 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; + +import org.graalvm.compiler.core.common.type.StampFactory; +import org.graalvm.compiler.graph.Node; +import org.graalvm.compiler.graph.NodeClass; +import org.graalvm.compiler.nodeinfo.NodeCycles; +import org.graalvm.compiler.nodeinfo.NodeInfo; +import org.graalvm.compiler.nodeinfo.NodeSize; +import org.graalvm.compiler.nodes.FixedWithNextNode; +import org.graalvm.compiler.nodes.spi.Canonicalizable; +import org.graalvm.compiler.nodes.spi.CanonicalizerTool; + +import com.oracle.graal.pointsto.util.AnalysisFuture; +import com.oracle.svm.core.BuildPhaseProvider; + +/** + * Allows a custom callback to be executed when this node is reachable. + * + * Native Image is able to automatically deduce usages of dynamic Java features such as reflection, + * proxies, etc. Usually, this is done in an invocation plugin. This plugin can do one of two + * things: + * + *
    + *
  1. Fold the invocation, leaving behind for example a Method object.
  2. + *
  3. Leave the invocation as is and based on the arguments to the invoke register additional + * metadata.
  4. + *
+ * + * Registering the metadata directly in the invocation plugin can lead to over-registration: + * invocation plugins are processed during inlining before analysis and the invoke for which they + * are executed may not exist in the final graph. Use this node for such registrations instead. + * + * To use: + *
    + *
  1. Create a subclass of + * {@link org.graalvm.compiler.nodes.graphbuilderconf.InvocationPlugin.RequiredInvocationPlugin} + * that is also a decorator + * (override @{@link org.graalvm.compiler.nodes.graphbuilderconf.InvocationPlugin.RequiredInvocationPlugin#isDecorator()})
  2. + *
  3. When applying the plugin, add this node to the graph with a @{link {@link Runnable} that + * registers the metadata.}
  4. + *
+ */ +@NodeInfo(cycles = NodeCycles.CYCLES_0, size = NodeSize.SIZE_0) +public class ReachabilityRegistrationNode extends FixedWithNextNode implements Canonicalizable { + public static final NodeClass TYPE = NodeClass.create(ReachabilityRegistrationNode.class); + + private final AnalysisFuture registrationTask; + + public ReachabilityRegistrationNode(Runnable registrationHandler) { + super(TYPE, StampFactory.forVoid()); + this.registrationTask = new AnalysisFuture<>(registrationHandler, null); + } + + public AnalysisFuture getRegistrationTask() { + return registrationTask; + } + + @Override + public Node canonical(CanonicalizerTool tool) { + if (BuildPhaseProvider.isAnalysisFinished()) { + return null; + } + return this; + } +} diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/ResourcesFeature.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/ResourcesFeature.java index 19b045391f6a..6939b4a8ac90 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/ResourcesFeature.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/ResourcesFeature.java @@ -446,6 +446,11 @@ private void registerResourceRegistrationPlugin(InvocationPlugins plugins, Metho parameterTypes.addAll(Arrays.asList(method.getParameterTypes())); plugins.register(method.getDeclaringClass(), new InvocationPlugin.RequiredInvocationPlugin(method.getName(), parameterTypes.toArray(new Class[0])) { + @Override + public boolean isDecorator() { + return true; + } + @Override public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode arg) { try { @@ -453,7 +458,8 @@ public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Rec String resource = snippetReflectionProvider.asObject(String.class, arg.asJavaConstant()); Class clazz = snippetReflectionProvider.asObject(Class.class, receiver.get().asJavaConstant()); String resourceName = (String) resolveResourceName.invoke(clazz, resource); - RuntimeResourceAccess.addResource(clazz.getModule(), resourceName); + b.add(new ReachabilityRegistrationNode(() -> RuntimeResourceAccess.addResource(clazz.getModule(), resourceName))); + return true; } } catch (IllegalAccessException | InvocationTargetException e) { throw VMError.shouldNotReachHere(e); 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 bffe3ec4d30c..a22a6b90d0fe 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 @@ -646,6 +646,8 @@ public void methodBeforeTypeFlowCreationHook(BigBang bb, AnalysisMethod method, for (Node n : graph.getNodes()) { if (n instanceof StackValueNode) { containsStackValueNode.put(method, true); + } else if (n instanceof ReachabilityRegistrationNode node) { + bb.postTask(debug -> node.getRegistrationTask().ensureDone()); } checkClassInitializerSideEffect(method, n); } diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/VMFeature.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/VMFeature.java index f47d625e1768..7ccebf38e94d 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/VMFeature.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/VMFeature.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2022, 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. * * This code is free software; you can redistribute it and/or modify it @@ -54,7 +54,21 @@ public class VMFeature implements InternalFeature { @Override public void afterRegistration(AfterRegistrationAccess access) { - ImageSingletons.add(VM.class, new VM()); + ImageSingletons.add(VM.class, new VM(determineVMInfo())); + } + + protected String determineVMInfo() { + return getSelectedGCName(); + } + + protected static final String getSelectedGCName() { + if (SubstrateOptions.UseSerialGC.getValue()) { + return "serial gc"; + } else if (SubstrateOptions.UseEpsilonGC.getValue()) { + return "epsilon gc"; + } else { + return "unknown gc"; + } } @Override 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 d227d3d86da6..9c947a660828 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 @@ -26,6 +26,7 @@ import java.util.function.ObjIntConsumer; +import org.graalvm.compiler.core.common.type.TypedConstant; import org.graalvm.compiler.word.Word; import org.graalvm.nativeimage.Platform; import org.graalvm.nativeimage.Platforms; @@ -37,6 +38,7 @@ 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.AnalysisType; import com.oracle.graal.pointsto.meta.AnalysisUniverse; import com.oracle.svm.core.RuntimeAssertionsSupport; import com.oracle.svm.core.annotate.InjectAccessors; @@ -72,6 +74,25 @@ public MemoryAccessProvider getMemoryAccessProvider() { return EmptyMemoryAcessProvider.SINGLETON; } + @Override + public JavaConstant boxPrimitive(JavaConstant source) { + if (!source.getJavaKind().isPrimitive()) { + return null; + } + return SubstrateObjectConstant.forObject(source.asBoxedPrimitive()); + } + + @Override + public JavaConstant unboxPrimitive(JavaConstant source) { + if (!source.getJavaKind().isObject()) { + return null; + } + if (source instanceof ImageHeapConstant heapConstant) { + return JavaConstant.forBoxedPrimitive(SubstrateObjectConstant.asObject(heapConstant.getHostedObject())); + } + return JavaConstant.forBoxedPrimitive(SubstrateObjectConstant.asObject(source)); + } + @Override public Integer readArrayLength(JavaConstant array) { if (array.getJavaKind() != JavaKind.Object || array.isNull()) { @@ -125,6 +146,21 @@ public final JavaConstant readFieldValue(ResolvedJavaField field, JavaConstant r } public JavaConstant readValue(UniverseMetaAccess suppliedMetaAccess, AnalysisField field, JavaConstant receiver) { + if (!field.isStatic()) { + if (receiver.isNull() || !field.getDeclaringClass().isAssignableFrom(((TypedConstant) receiver).getType(metaAccess))) { + /* + * During compiler optimizations, it is possible to see field loads with a constant + * receiver of a wrong type. The code will later be removed as dead code, and in + * most cases the field read would also be rejected as illegal by the HotSpot + * constant reflection provider doing the actual field load. But there are several + * other ways how a field can be accessed, e.g., our ReadableJavaField mechanism or + * fields of classes that are initialized at image run time. To avoid any surprises, + * we abort the field reading here early. + */ + return null; + } + } + JavaConstant value; if (receiver instanceof ImageHeapConstant) { ImageHeapInstance heapObject = (ImageHeapInstance) receiver; @@ -243,11 +279,11 @@ private JavaConstant interceptWordType(UniverseMetaAccess suppliedMetaAccess, An } @Override - public ResolvedJavaType asJavaType(Constant constant) { - if (constant instanceof SubstrateObjectConstant) { - Object obj = SubstrateObjectConstant.asObject(constant); - if (obj instanceof DynamicHub) { - return getHostVM().lookupType((DynamicHub) obj); + public AnalysisType 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); } diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/analysis/DynamicHubInitializer.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/analysis/DynamicHubInitializer.java index 91b53c1e20bd..ff4e3c68f4ed 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/analysis/DynamicHubInitializer.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/analysis/DynamicHubInitializer.java @@ -46,7 +46,6 @@ import com.oracle.svm.core.classinitialization.ClassInitializationInfo; import com.oracle.svm.core.hub.DynamicHub; import com.oracle.svm.core.meta.MethodPointer; -import com.oracle.svm.core.meta.SubstrateObjectConstant; import com.oracle.svm.hosted.ExceptionSynthesizer; import com.oracle.svm.hosted.SVMHost; import com.oracle.svm.util.ReflectionUtil; @@ -157,7 +156,7 @@ private Enum[] retrieveEnumConstantArray(AnalysisType type, Class javaClas */ enumConstants = (Enum[]) javaClass.getEnumConstants(); } else { - enumConstants = (Enum[]) SubstrateObjectConstant.asObject(constantReflection.readFieldValue(found, null)); + enumConstants = metaAccess.getUniverse().getSnippetReflection().asObject(Enum[].class, constantReflection.readFieldValue(found, null)); assert enumConstants != null; } return enumConstants; 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 2a97b6a94c73..d72156716b39 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 @@ -48,7 +48,6 @@ import com.oracle.graal.pointsto.meta.PointsToAnalysisMethod; import com.oracle.svm.core.graal.thread.CompareAndSetVMThreadLocalNode; import com.oracle.svm.core.graal.thread.StoreVMThreadLocalNode; -import com.oracle.svm.core.meta.SubstrateObjectConstant; import com.oracle.svm.core.util.UserError.UserException; import com.oracle.svm.hosted.NativeImageOptions; import com.oracle.svm.hosted.SVMHost; @@ -91,7 +90,7 @@ public static void registerUsedElements(PointsToAnalysis bb, StructuredGraph gra * object replacers really see all objects that are embedded into compiled * code. */ - Object value = SubstrateObjectConstant.asObject(constant); + 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: " + diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/annotation/AnnotationArrayValue.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/annotation/AnnotationArrayValue.java index 5bc6a1902333..a1cdf1024dfe 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/annotation/AnnotationArrayValue.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/annotation/AnnotationArrayValue.java @@ -31,6 +31,8 @@ import java.util.List; import java.util.function.Consumer; +import org.graalvm.compiler.api.replacements.SnippetReflectionProvider; + import jdk.internal.reflect.ConstantPool; import jdk.vm.ci.meta.JavaConstant; import sun.reflect.annotation.ExceptionProxy; @@ -40,14 +42,14 @@ public final class AnnotationArrayValue extends AnnotationMemberValue { private final AnnotationMemberValue[] elements; - static AnnotationArrayValue extract(ByteBuffer buf, ConstantPool cp, Class container, boolean skip) { + static AnnotationArrayValue extract(SnippetReflectionProvider snippetReflection, ByteBuffer buf, ConstantPool cp, Class container, boolean skip) { int length = buf.getShort() & 0xFFFF; if (length == 0) { return EMPTY_ARRAY_VALUE; } AnnotationMemberValue[] elements = new AnnotationMemberValue[length]; for (int i = 0; i < length; ++i) { - elements[i] = AnnotationMemberValue.extract(buf, cp, container, skip); + elements[i] = AnnotationMemberValue.extract(snippetReflection, buf, cp, container, skip); } return skip ? null : new AnnotationArrayValue(elements); } diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/annotation/AnnotationClassValue.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/annotation/AnnotationClassValue.java index a39bbfb07359..27f275b7d037 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/annotation/AnnotationClassValue.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/annotation/AnnotationClassValue.java @@ -29,19 +29,21 @@ import java.util.List; import java.util.Objects; +import org.graalvm.compiler.api.replacements.SnippetReflectionProvider; + import jdk.internal.reflect.ConstantPool; import sun.reflect.annotation.ExceptionProxy; public final class AnnotationClassValue extends AnnotationMemberValue { private final Class value; - static AnnotationMemberValue extract(ByteBuffer buf, ConstantPool cp, Class container, boolean skip) { + static AnnotationMemberValue extract(SnippetReflectionProvider snippetReflection, ByteBuffer buf, ConstantPool cp, Class container, boolean skip) { Object typeOrException = AnnotationMetadata.extractType(buf, cp, container, skip); if (skip) { return null; } if (typeOrException instanceof ExceptionProxy) { - return new AnnotationExceptionProxyValue((ExceptionProxy) typeOrException); + return new AnnotationExceptionProxyValue(snippetReflection, (ExceptionProxy) typeOrException); } return new AnnotationClassValue((Class) typeOrException); } diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/annotation/AnnotationEnumValue.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/annotation/AnnotationEnumValue.java index 1759b6bc0a3c..d769fbf0f515 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/annotation/AnnotationEnumValue.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/annotation/AnnotationEnumValue.java @@ -29,6 +29,8 @@ import java.util.List; import java.util.Objects; +import org.graalvm.compiler.api.replacements.SnippetReflectionProvider; + import jdk.internal.reflect.ConstantPool; import sun.reflect.annotation.ExceptionProxy; @@ -37,14 +39,14 @@ public final class AnnotationEnumValue extends AnnotationMemberValue { private final String name; @SuppressWarnings({"unchecked"}) - static AnnotationMemberValue extract(ByteBuffer buf, ConstantPool cp, Class container, boolean skip) { + static AnnotationMemberValue extract(SnippetReflectionProvider snippetReflection, ByteBuffer buf, ConstantPool cp, Class container, boolean skip) { Object typeOrException = AnnotationMetadata.extractType(buf, cp, container, skip); String constName = AnnotationMetadata.extractString(buf, cp, skip); if (skip) { return null; } if (typeOrException instanceof ExceptionProxy) { - return new AnnotationExceptionProxyValue((ExceptionProxy) typeOrException); + return new AnnotationExceptionProxyValue(snippetReflection, (ExceptionProxy) typeOrException); } Class> type = (Class>) typeOrException; return new AnnotationEnumValue(type, constName); diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/annotation/AnnotationExceptionProxyValue.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/annotation/AnnotationExceptionProxyValue.java index c676fed6cdb1..c293e5b39d2b 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/annotation/AnnotationExceptionProxyValue.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/annotation/AnnotationExceptionProxyValue.java @@ -27,7 +27,7 @@ import java.util.Collections; import java.util.List; -import com.oracle.svm.core.meta.SubstrateObjectConstant; +import org.graalvm.compiler.api.replacements.SnippetReflectionProvider; import jdk.vm.ci.meta.JavaConstant; import sun.reflect.annotation.ExceptionProxy; @@ -36,9 +36,9 @@ public final class AnnotationExceptionProxyValue extends AnnotationMemberValue { private final ExceptionProxy exceptionProxy; private final JavaConstant objectConstant; - AnnotationExceptionProxyValue(ExceptionProxy exceptionProxy) { + AnnotationExceptionProxyValue(SnippetReflectionProvider snippetReflection, ExceptionProxy exceptionProxy) { this.exceptionProxy = exceptionProxy; - this.objectConstant = SubstrateObjectConstant.forObject(exceptionProxy); + this.objectConstant = snippetReflection.forObject(exceptionProxy); } public JavaConstant getObjectConstant() { diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/annotation/AnnotationMemberValue.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/annotation/AnnotationMemberValue.java index 5072b91857ad..d2809313c89d 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/annotation/AnnotationMemberValue.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/annotation/AnnotationMemberValue.java @@ -29,23 +29,25 @@ import java.util.Collections; import java.util.List; +import org.graalvm.compiler.api.replacements.SnippetReflectionProvider; + import jdk.internal.reflect.ConstantPool; import jdk.vm.ci.meta.JavaConstant; public abstract class AnnotationMemberValue { - static AnnotationMemberValue extract(ByteBuffer buf, ConstantPool cp, Class container, boolean skip) { + static AnnotationMemberValue extract(SnippetReflectionProvider snippetReflection, ByteBuffer buf, ConstantPool cp, Class container, boolean skip) { char tag = (char) buf.get(); switch (tag) { case 'e': - return AnnotationEnumValue.extract(buf, cp, container, skip); + return AnnotationEnumValue.extract(snippetReflection, buf, cp, container, skip); case 'c': - return AnnotationClassValue.extract(buf, cp, container, skip); + return AnnotationClassValue.extract(snippetReflection, buf, cp, container, skip); case 's': return AnnotationStringValue.extract(buf, cp, skip); case '@': - return AnnotationValue.extract(buf, cp, container, true, skip); + return AnnotationValue.extract(snippetReflection, buf, cp, container, true, skip); case '[': - return AnnotationArrayValue.extract(buf, cp, container, skip); + return AnnotationArrayValue.extract(snippetReflection, buf, cp, container, skip); default: return AnnotationPrimitiveValue.extract(buf, cp, tag, skip); } diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/annotation/AnnotationSupport.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/annotation/AnnotationSupport.java index afa8719b5c05..56dde3b98842 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/annotation/AnnotationSupport.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/annotation/AnnotationSupport.java @@ -69,7 +69,6 @@ import com.oracle.svm.core.feature.InternalFeature; import com.oracle.svm.core.graal.jdk.SubstrateObjectCloneWithExceptionNode; import com.oracle.svm.core.jdk.AnnotationSupportConfig; -import com.oracle.svm.core.meta.SubstrateObjectConstant; import com.oracle.svm.core.util.VMError; import com.oracle.svm.hosted.analysis.NativeImagePointsToAnalysis; import com.oracle.svm.hosted.phases.HostedGraphKit; @@ -597,7 +596,7 @@ public StructuredGraph buildGraph(DebugContext debug, ResolvedJavaMethod method, } else { returnValue = "@" + annotationInterfaceType.toJavaName(true); } - ValueNode returnConstant = kit.unique(ConstantNode.forConstant(SubstrateObjectConstant.forObject(returnValue), providers.getMetaAccess())); + ValueNode returnConstant = kit.unique(ConstantNode.forConstant(providers.getSnippetReflection().forObject(returnValue), providers.getMetaAccess())); kit.append(new ReturnNode(returnConstant)); return kit.finalizeGraph(); diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/annotation/AnnotationValue.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/annotation/AnnotationValue.java index d16c402d445c..e4237194d1ff 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/annotation/AnnotationValue.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/annotation/AnnotationValue.java @@ -35,6 +35,8 @@ import java.util.Objects; import java.util.function.BiConsumer; +import org.graalvm.compiler.api.replacements.SnippetReflectionProvider; + import jdk.internal.reflect.ConstantPool; import jdk.vm.ci.meta.JavaConstant; import sun.reflect.annotation.AnnotationParser; @@ -46,7 +48,7 @@ public final class AnnotationValue extends AnnotationMemberValue { final Map members; @SuppressWarnings("unchecked") - static AnnotationValue extract(ByteBuffer buf, ConstantPool cp, Class container, boolean exceptionOnMissingAnnotationClass, boolean skip) { + static AnnotationValue extract(SnippetReflectionProvider snippetReflection, ByteBuffer buf, ConstantPool cp, Class container, boolean exceptionOnMissingAnnotationClass, boolean skip) { boolean skipMembers = skip; Object typeOrException = AnnotationMetadata.extractType(buf, cp, container, skip); if (typeOrException instanceof TypeNotPresentExceptionProxy) { @@ -61,7 +63,7 @@ static AnnotationValue extract(ByteBuffer buf, ConstantPool cp, Class contain Map memberValues = new LinkedHashMap<>(); for (int i = 0; i < numMembers; i++) { String memberName = AnnotationMetadata.extractString(buf, cp, skipMembers); - AnnotationMemberValue memberValue = AnnotationMemberValue.extract(buf, cp, container, skipMembers); + AnnotationMemberValue memberValue = AnnotationMemberValue.extract(snippetReflection, buf, cp, container, skipMembers); if (!skipMembers) { memberValues.put(memberName, memberValue); } diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/annotation/SubstrateAnnotationExtractor.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/annotation/SubstrateAnnotationExtractor.java index 3eeb2ce548e4..127bf4b18940 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/annotation/SubstrateAnnotationExtractor.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/annotation/SubstrateAnnotationExtractor.java @@ -42,6 +42,7 @@ import java.util.Objects; import java.util.concurrent.ConcurrentHashMap; +import org.graalvm.compiler.api.replacements.SnippetReflectionProvider; import org.graalvm.nativeimage.AnnotationAccess; import org.graalvm.nativeimage.impl.AnnotationExtractor; @@ -104,6 +105,7 @@ public class SubstrateAnnotationExtractor implements AnnotationExtractor { private static final Field recordComponentTypeAnnotations = recordComponentClass == null ? null : ReflectionUtil.lookupField(recordComponentClass, "typeAnnotations"); private static final Method recordComponentGetDeclaringRecord = recordComponentClass == null ? null : ReflectionUtil.lookupMethod(recordComponentClass, "getDeclaringRecord"); private static final Method packageGetPackageInfo = ReflectionUtil.lookupMethod(Package.class, "getPackageInfo"); + private SnippetReflectionProvider snippetReflection; public static AnnotationValue[] prepareInjectedAnnotations(Annotation... annotations) { if (annotations == null || annotations.length == 0) { @@ -253,7 +255,7 @@ private AnnotationValue[] getDeclaredAnnotationDataFromRoot(AnnotatedElement roo List annotations = new ArrayList<>(); int numAnnotations = buf.getShort() & 0xFFFF; for (int i = 0; i < numAnnotations; i++) { - AnnotationValue annotation = AnnotationValue.extract(buf, getConstantPool(element), getContainer(element), false, false); + AnnotationValue annotation = AnnotationValue.extract(snippetReflection, buf, getConstantPool(element), getContainer(element), false, false); if (annotation != null) { annotations.add(annotation); } @@ -284,7 +286,7 @@ private AnnotationValue[][] getParameterAnnotationDataFromRoot(Executable rootEl List parameterAnnotationList = new ArrayList<>(); int numAnnotations = buf.getShort() & 0xFFFF; for (int j = 0; j < numAnnotations; j++) { - AnnotationValue parameterAnnotation = AnnotationValue.extract(buf, getConstantPool(element), getContainer(element), false, false); + AnnotationValue parameterAnnotation = AnnotationValue.extract(snippetReflection, buf, getConstantPool(element), getContainer(element), false, false); if (parameterAnnotation != null) { parameterAnnotationList.add(parameterAnnotation); } @@ -314,7 +316,7 @@ private TypeAnnotationValue[] getTypeAnnotationDataFromRoot(AnnotatedElement roo int annotationCount = buf.getShort() & 0xFFFF; TypeAnnotationValue[] typeAnnotationValues = new TypeAnnotationValue[annotationCount]; for (int i = 0; i < annotationCount; i++) { - typeAnnotationValues[i] = TypeAnnotationValue.extract(buf, getConstantPool(element), getContainer(element)); + typeAnnotationValues[i] = TypeAnnotationValue.extract(snippetReflection, buf, getConstantPool(element), getContainer(element)); } return typeAnnotationValues; } catch (IllegalArgumentException | BufferUnderflowException ex) { @@ -341,7 +343,7 @@ private AnnotationMemberValue getAnnotationDefaultDataFromRoot(Method accessorMe } ByteBuffer buf = ByteBuffer.wrap(rawAnnotationDefault); try { - return AnnotationMemberValue.extract(buf, getConstantPool(method), getContainer(method), false); + return AnnotationMemberValue.extract(snippetReflection, buf, getConstantPool(method), getContainer(method), false); } catch (IllegalArgumentException | BufferUnderflowException ex) { return AnnotationValue.forAnnotationFormatException(); } @@ -468,4 +470,8 @@ private static AnnotatedElement findRoot(AnnotatedElement element) { throw new AnnotationExtractionError(e); } } + + public void setSnippetReflection(SnippetReflectionProvider snippetReflection) { + this.snippetReflection = snippetReflection; + } } diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/annotation/TypeAnnotationValue.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/annotation/TypeAnnotationValue.java index 5dbccfa154b4..9888ec375252 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/annotation/TypeAnnotationValue.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/annotation/TypeAnnotationValue.java @@ -29,6 +29,7 @@ import java.util.Objects; import jdk.internal.reflect.ConstantPool; +import org.graalvm.compiler.api.replacements.SnippetReflectionProvider; public final class TypeAnnotationValue { private final byte[] targetInfo; @@ -128,10 +129,10 @@ private static byte[] extractLocationInfo(ByteBuffer buf) { return locationInfo; } - static TypeAnnotationValue extract(ByteBuffer buf, ConstantPool cp, Class container) { + static TypeAnnotationValue extract(SnippetReflectionProvider snippetReflection, ByteBuffer buf, ConstantPool cp, Class container) { byte[] targetInfo = extractTargetInfo(buf); byte[] locationInfo = extractLocationInfo(buf); - AnnotationValue annotation = AnnotationValue.extract(buf, cp, container, false, false); + AnnotationValue annotation = AnnotationValue.extract(snippetReflection, buf, cp, container, false, false); return new TypeAnnotationValue(targetInfo, locationInfo, annotation); } diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/c/CAnnotationProcessor.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/c/CAnnotationProcessor.java index 1816b91dd5a3..85464a3367d7 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/c/CAnnotationProcessor.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/c/CAnnotationProcessor.java @@ -34,7 +34,6 @@ import java.util.ArrayList; import java.util.List; -import com.oracle.svm.hosted.c.libc.HostedLibCBase; import org.graalvm.nativeimage.ImageSingletons; import org.graalvm.nativeimage.Platform; @@ -43,10 +42,12 @@ 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.ImageClassLoader; import com.oracle.svm.hosted.c.codegen.CCompilerInvoker; import com.oracle.svm.hosted.c.codegen.QueryCodeWriter; import com.oracle.svm.hosted.c.info.InfoTreeBuilder; import com.oracle.svm.hosted.c.info.NativeCodeInfo; +import com.oracle.svm.hosted.c.libc.HostedLibCBase; import com.oracle.svm.hosted.c.query.QueryResultParser; import com.oracle.svm.hosted.c.query.RawStructureLayoutPlanner; import com.oracle.svm.hosted.c.query.SizeAndSignednessVerifier; @@ -83,7 +84,7 @@ public CAnnotationProcessor(NativeLibraries nativeLibs, NativeCodeContext codeCt } } - public NativeCodeInfo process(CAnnotationProcessorCache cache) { + public NativeCodeInfo process(CAnnotationProcessorCache cache, ImageClassLoader loader) { InfoTreeBuilder constructor = new InfoTreeBuilder(nativeLibs, codeCtx); codeInfo = constructor.construct(); if (nativeLibs.getErrors().size() > 0) { @@ -108,8 +109,8 @@ public NativeCodeInfo process(CAnnotationProcessorCache cache) { // Only output query code and exit return codeInfo; } - Path binary = compileQueryCode(queryFile); + loader.watchdog.recordActivity(); if (nativeLibs.getErrors().size() > 0) { return codeInfo; } diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/c/CGlobalDataFeature.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/c/CGlobalDataFeature.java index 0bad5ad1abf5..231861dc271b 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/c/CGlobalDataFeature.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/c/CGlobalDataFeature.java @@ -79,8 +79,8 @@ import com.oracle.svm.core.feature.InternalFeature; import com.oracle.svm.core.graal.code.CGlobalDataInfo; import com.oracle.svm.core.graal.nodes.CGlobalDataLoadAddressNode; -import com.oracle.svm.core.meta.SubstrateObjectConstant; import com.oracle.svm.core.util.VMError; +import com.oracle.svm.hosted.FeatureImpl.DuringSetupAccessImpl; import com.oracle.svm.hosted.image.RelocatableBuffer; import com.oracle.svm.util.ReflectionUtil; @@ -96,7 +96,7 @@ public class CGlobalDataFeature implements InternalFeature { private final Field isSymbolReferenceField = ReflectionUtil.lookupField(CGlobalDataInfo.class, "isSymbolReference"); private final CGlobalDataNonConstantRegistry nonConstantRegistry = new CGlobalDataNonConstantRegistry(); - private final JavaConstant nonConstantRegistryJavaConstant = SubstrateObjectConstant.forObject(nonConstantRegistry); + private JavaConstant nonConstantRegistryJavaConstant; private final Map, CGlobalDataInfo> map = new ConcurrentHashMap<>(); private CGlobalDataInfo cGlobalDataBaseAddress; @@ -111,9 +111,11 @@ private boolean isLayouted() { } @Override - public void duringSetup(DuringSetupAccess access) { - access.registerObjectReplacer(this::replaceObject); + public void duringSetup(DuringSetupAccess a) { + DuringSetupAccessImpl access = (DuringSetupAccessImpl) a; + a.registerObjectReplacer(this::replaceObject); cGlobalDataBaseAddress = registerAsAccessedOrGet(CGlobalDataInfo.CGLOBALDATA_RUNTIME_BASE_ADDRESS); + nonConstantRegistryJavaConstant = access.getMetaAccess().getUniverse().getSnippetReflection().forObject(nonConstantRegistry); } @Override @@ -129,7 +131,7 @@ public void registerInvocationPlugins(Providers providers, SnippetReflectionProv public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver) { ValueNode cGlobalDataNode = receiver.get(); if (cGlobalDataNode.isConstant()) { - CGlobalDataImpl data = (CGlobalDataImpl) SubstrateObjectConstant.asObject(cGlobalDataNode.asConstant()); + CGlobalDataImpl data = providers.getSnippetReflection().asObject(CGlobalDataImpl.class, cGlobalDataNode.asJavaConstant()); CGlobalDataInfo info = CGlobalDataFeature.this.map.get(data); b.addPush(targetMethod.getSignature().getReturnKind(), new CGlobalDataLoadAddressNode(info)); } else { diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/c/NativeLibraries.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/c/NativeLibraries.java index fd81b9c67349..3bce1d89608d 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/c/NativeLibraries.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/c/NativeLibraries.java @@ -550,13 +550,13 @@ private Class getDirectives(ResolvedJavaType type } } - public void finish() { + public void finish(ImageClassLoader loader) { libraryPaths.addAll(SubstrateOptions.CLibraryPath.getValue().values().stream().map(Path::toString).collect(Collectors.toList())); for (NativeCodeContext context : compilationUnitToContext.values()) { if (context.isInConfiguration()) { libraries.addAll(context.getDirectives().getLibraries()); libraryPaths.addAll(context.getDirectives().getLibraryPaths()); - new CAnnotationProcessor(this, context).process(cache); + new CAnnotationProcessor(this, context).process(cache, loader); } } } 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 783059f37376..d53f78e4e220 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 @@ -187,7 +187,7 @@ protected void verify() { int minimumMinorVersion = 31; if (compilerInfo.versionMajor < minimumMajorVersion || compilerInfo.versionMinor0 < minimumMinorVersion) { 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); + 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 " : ""; diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/classinitialization/EarlyClassInitializerAnalysis.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/classinitialization/EarlyClassInitializerAnalysis.java index 557d78148236..f3ea57041bba 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/classinitialization/EarlyClassInitializerAnalysis.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/classinitialization/EarlyClassInitializerAnalysis.java @@ -69,6 +69,7 @@ import com.oracle.svm.core.graal.thread.VMThreadLocalAccess; import com.oracle.svm.core.option.HostedOptionValues; import com.oracle.svm.core.util.VMError; +import com.oracle.svm.hosted.FallbackFeature; import com.oracle.svm.hosted.phases.EarlyConstantFoldLoadFieldPlugin; import com.oracle.svm.hosted.snippets.ReflectionPlugins; import com.oracle.svm.hosted.snippets.SubstrateGraphBuilderPlugins; @@ -174,8 +175,9 @@ private boolean canInitializeWithoutSideEffects(ResolvedJavaMethod clinit, Set hostedImageHeapMap : allInstances) { if (needsUpdate(hostedImageHeapMap)) { - throw VMError.shouldNotReachHere("ImageHeapMap modified after static analysis: " + hostedImageHeapMap + System.lineSeparator() + hostedImageHeapMap.runtimeMap); + throw VMError.shouldNotReachHere("ImageHeapMap modified after static analysis:%n%s%n%s", + hostedImageHeapMap, hostedImageHeapMap.runtimeMap); } } } 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 52bc9bc48b82..f623770bf266 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 @@ -44,7 +44,6 @@ import com.oracle.graal.pointsto.meta.AnalysisMetaAccess; import com.oracle.svm.core.BuildPhaseProvider; import com.oracle.svm.core.hub.DynamicHub; -import com.oracle.svm.core.meta.SubstrateObjectConstant; import com.oracle.svm.core.util.VMError; import com.oracle.svm.hosted.ImageClassLoader; import com.oracle.svm.hosted.ameta.AnalysisConstantReflectionProvider; @@ -95,18 +94,6 @@ protected ImageHeapConstant getOrCreateImageHeapConstant(JavaConstant javaConsta return super.getOrCreateImageHeapConstant(javaConstant, reason); } - @Override - protected Object unwrapObject(JavaConstant constant) { - /* - * Unwrap the original object from the constant. Unlike HostedSnippetReflectionProvider this - * will just return the wrapped object, without any transformation. This is important during - * scanning: when scanning a java.lang.Class it will be replaced by a DynamicHub which is - * then actually scanned. The HostedSnippetReflectionProvider returns the original Class for - * a DynamicHub, which would lead to a deadlock during scanning. - */ - return SubstrateObjectConstant.asObject(Object.class, constant); - } - @Override public boolean isValueAvailable(AnalysisField field) { if (field.wrapped instanceof ReadableJavaField) { @@ -146,13 +133,16 @@ protected void rescanEconomicMap(EconomicMap map) { @Override protected void onObjectReachable(ImageHeapConstant imageHeapConstant, ScanReason reason, Consumer onAnalysisModified) { super.onObjectReachable(imageHeapConstant, reason, onAnalysisModified); - - if (metaAccess.isInstanceOf(imageHeapConstant, Field.class)) { - reflectionSupport.registerHeapReflectionField((Field) SubstrateObjectConstant.asObject(imageHeapConstant.getHostedObject()), reason); - } else if (metaAccess.isInstanceOf(imageHeapConstant, Executable.class)) { - reflectionSupport.registerHeapReflectionExecutable((Executable) SubstrateObjectConstant.asObject(imageHeapConstant.getHostedObject()), reason); - } else if (metaAccess.isInstanceOf(imageHeapConstant, DynamicHub.class)) { - reflectionSupport.registerHeapDynamicHub(SubstrateObjectConstant.asObject(imageHeapConstant.getHostedObject()), reason); + 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); + } } } } 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 e02619850bd0..96ffa7677ba5 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 @@ -33,7 +33,6 @@ import com.oracle.graal.pointsto.heap.ImageHeapScanner; import com.oracle.graal.pointsto.meta.AnalysisType; import com.oracle.graal.pointsto.util.CompletionExecutor; -import com.oracle.svm.core.meta.SubstrateObjectConstant; import com.oracle.svm.hosted.SVMHost; import jdk.vm.ci.meta.JavaConstant; @@ -71,8 +70,8 @@ protected void scanTypes(ObjectScanner objectScanner) { bb.getUniverse().getTypes().stream().filter(AnalysisType::isReachable).forEach(t -> verifyHub(svmHost, objectScanner, t)); } - private static void verifyHub(SVMHost svmHost, ObjectScanner objectScanner, AnalysisType type) { - JavaConstant hubConstant = SubstrateObjectConstant.forObject(svmHost.dynamicHub(type)); + private void verifyHub(SVMHost svmHost, ObjectScanner objectScanner, AnalysisType type) { + JavaConstant hubConstant = bb.getSnippetReflectionProvider().forObject(svmHost.dynamicHub(type)); objectScanner.scanConstant(hubConstant, ObjectScanner.OtherReason.HUB); } 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 2ec6df5486d7..556d9644c3a9 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 @@ -48,6 +48,7 @@ import java.util.stream.Collectors; import org.graalvm.collections.Pair; +import org.graalvm.compiler.api.replacements.SnippetReflectionProvider; import org.graalvm.compiler.code.CompilationResult; import org.graalvm.compiler.code.DataSection; import org.graalvm.compiler.debug.DebugContext; @@ -409,7 +410,7 @@ public void buildRuntimeMetadata(CFunctionPointer firstMethod, UnsignedWord code protected HostedImageCodeInfo installCodeInfo(CFunctionPointer firstMethod, UnsignedWord codeSize, CodeInfoEncoder codeInfoEncoder, ReflectionMetadataEncoder reflectionMetadataEncoder) { HostedImageCodeInfo imageCodeInfo = CodeInfoTable.getImageCodeCache().getHostedImageCodeInfo(); codeInfoEncoder.encodeAllAndInstall(imageCodeInfo, new InstantReferenceAdjuster()); - reflectionMetadataEncoder.encodeAllAndInstall(); + reflectionMetadataEncoder.encodeAllAndInstall(getSnippetReflection()); imageCodeInfo.setCodeStart(firstMethod); imageCodeInfo.setCodeSize(codeSize); imageCodeInfo.setDataOffset(codeSize); @@ -418,6 +419,10 @@ protected HostedImageCodeInfo installCodeInfo(CFunctionPointer firstMethod, Unsi return imageCodeInfo; } + protected SnippetReflectionProvider getSnippetReflection() { + return imageHeap.getUniverse().getSnippetReflection(); + } + protected void encodeMethod(CodeInfoEncoder codeInfoEncoder, Pair pair) { final HostedMethod method = pair.getLeft(); final CompilationResult compilation = pair.getRight(); @@ -692,7 +697,7 @@ public interface ReflectionMetadataEncoder extends EncodedReflectionMetadataSupp void addNegativeConstructorQueryMetadata(HostedType declaringClass, HostedType[] parameterTypes); - void encodeAllAndInstall(); + void encodeAllAndInstall(SnippetReflectionProvider snippetReflection); Method getRoot = ReflectionUtil.lookupMethod(AccessibleObject.class, "getRoot"); 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 1fb1c6ad4705..6cce909432ac 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 @@ -69,7 +69,6 @@ import com.oracle.svm.core.image.ImageHeapObject; import com.oracle.svm.core.image.ImageHeapPartition; import com.oracle.svm.core.jdk.StringInternSupport; -import com.oracle.svm.core.meta.SubstrateObjectConstant; import com.oracle.svm.core.util.HostedStringDeduplication; import com.oracle.svm.core.util.UserError; import com.oracle.svm.core.util.VMError; @@ -157,7 +156,7 @@ public int getObjectCount() { } public ObjectInfo getObjectInfo(Object obj) { - return objects.get(SubstrateObjectConstant.forObject(obj)); + return objects.get(universe.getSnippetReflection().forObject(obj)); } public ObjectInfo getConstantInfo(JavaConstant constant) { @@ -246,8 +245,8 @@ public void addTrailingObjects() { assert addObjectWorklist.isEmpty(); } - private static Object readObjectField(HostedField field, JavaConstant receiver) { - return SubstrateObjectConstant.asObject(field.readStorageValue(receiver)); + private Object readObjectField(HostedField field, JavaConstant receiver) { + return universe.getSnippetReflection().asObject(Object.class, field.readStorageValue(receiver)); } private static JavaConstant readConstantField(HostedField field, JavaConstant receiver) { @@ -282,7 +281,7 @@ public void registerAsImmutable(Object object) { * Not every object is added to the heap, for various reasons. */ public void addObject(final Object original, boolean immutableFromParent, final Object reason) { - addConstant(SubstrateObjectConstant.forObject(original), immutableFromParent, reason); + addConstant(universe.getSnippetReflection().forObject(original), immutableFromParent, reason); } public void addConstant(final JavaConstant constant, boolean immutableFromParent, final Object reason) { @@ -293,12 +292,8 @@ public void addConstant(final JavaConstant constant, boolean immutableFromParent } if (metaAccess.isInstanceOf(constant, Class.class)) { - Object original = SubstrateObjectConstant.asObject(constant); - if (original instanceof Class) { - throw VMError.shouldNotReachHere("Must not have Class in native image heap: " + original); - } - assert original instanceof DynamicHub; - if (((DynamicHub) original).getClassInitializationInfo() == null) { + DynamicHub hub = universe.getSnippetReflection().asObject(DynamicHub.class, constant); + if (hub.getClassInitializationInfo() == null) { /* * All DynamicHub instances written into the image heap must have a * ClassInitializationInfo, otherwise we can get a NullPointerException at run time. @@ -308,7 +303,7 @@ public void addConstant(final JavaConstant constant, boolean immutableFromParent * image that the static analysis has not seen - so this check actually protects * against much more than just missing class initialization information. */ - throw reportIllegalType(original, reason); + throw reportIllegalType(universe.getSnippetReflection().asObject(Object.class, constant), reason); } } @@ -318,7 +313,7 @@ public void addConstant(final JavaConstant constant, boolean immutableFromParent VMError.guarantee(identityHashCode != 0, "0 is used as a marker value for 'hash code not yet computed'"); if (metaAccess.isInstanceOf(uncompressed, String.class)) { - handleImageString((String) SubstrateObjectConstant.asObject(uncompressed)); + handleImageString(universe.getSnippetReflection().asObject(String.class, uncompressed)); } final ObjectInfo existing = objects.get(uncompressed); @@ -531,7 +526,7 @@ private void addObjectToImageHeap(final JavaConstant constant, boolean immutable if (constant instanceof ImageHeapConstant) { relocatable = addConstantArrayElements(constant, length, false, info); } else { - Object object = SubstrateObjectConstant.asObject(constant); + Object object = universe.getSnippetReflection().asObject(Object.class, constant); relocatable = addArrayElements((Object[]) object, false, info); } references = true; @@ -546,7 +541,7 @@ private void addObjectToImageHeap(final JavaConstant constant, boolean immutable } if (relocatable && !isKnownImmutableConstant(constant)) { - VMError.shouldNotReachHere("Object with relocatable pointers must be explicitly immutable: " + SubstrateObjectConstant.asObject(constant)); + VMError.shouldNotReachHere("Object with relocatable pointers must be explicitly immutable: " + universe.getSnippetReflection().asObject(Object.class, constant)); } heapLayouter.assignObjectToPartition(info, !written || immutable, references, relocatable); } @@ -592,7 +587,7 @@ private boolean isKnownImmutableConstant(final JavaConstant constant) { /* Currently injected ImageHeapObject cannot be marked as immutable. */ return false; } - return isKnownImmutable(SubstrateObjectConstant.asObject(constant)); + return isKnownImmutable(universe.getSnippetReflection().asObject(Object.class, constant)); } /** Determine if an object in the host heap will be immutable in the native image heap. */ @@ -608,7 +603,7 @@ private boolean isKnownImmutable(final Object obj) { /** Add an object to the model of the native image heap. */ private ObjectInfo addToImageHeap(Object object, HostedClass clazz, long size, int identityHashCode, Object reason) { - return addToImageHeap(SubstrateObjectConstant.forObject(object), clazz, size, identityHashCode, reason); + return addToImageHeap(universe.getSnippetReflection().forObject(object), clazz, size, identityHashCode, reason); } private ObjectInfo addToImageHeap(JavaConstant constant, HostedClass clazz, long size, int identityHashCode, Object reason) { @@ -677,7 +672,7 @@ private boolean addConstantArrayElements(JavaConstant array, int length, boolean */ private void recursiveAddObject(Object original, boolean immutableFromParent, Object reason) { if (original != null) { - addObjectWorklist.push(new AddObjectData(SubstrateObjectConstant.forObject(original), immutableFromParent, reason)); + addObjectWorklist.push(new AddObjectData(universe.getSnippetReflection().forObject(original), immutableFromParent, reason)); } } @@ -742,7 +737,7 @@ public final class ObjectInfo implements ImageHeapObject { @Override public Object getObject() { - return SubstrateObjectConstant.asObject(constant); + return universe.getSnippetReflection().asObject(Object.class, constant); } @Override 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 2f3d015df53b..68561c605fe0 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,7 +30,7 @@ import java.lang.reflect.Modifier; import java.nio.ByteBuffer; -import com.oracle.graal.pointsto.heap.ImageHeapConstant; +import org.graalvm.compiler.api.replacements.SnippetReflectionProvider; import org.graalvm.compiler.core.common.CompressEncoding; import org.graalvm.compiler.core.common.NumUtil; import org.graalvm.compiler.debug.DebugContext; @@ -40,6 +40,8 @@ import org.graalvm.nativeimage.c.function.RelocatedPointer; import org.graalvm.word.WordBase; +import com.oracle.graal.pointsto.heap.ImageHeapConstant; +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; @@ -52,7 +54,6 @@ import com.oracle.svm.core.image.ImageHeapLayoutInfo; import com.oracle.svm.core.meta.MethodPointer; import com.oracle.svm.core.meta.SubstrateObjectConstant; -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.image.NativeImageHeap.ObjectInfo; @@ -119,8 +120,8 @@ private void writeStaticFields(RelocatableBuffer buffer) { } } - private static Object readObjectField(HostedField field, JavaConstant receiver) { - return SubstrateObjectConstant.asObject(field.readStorageValue(receiver)); + private Object readObjectField(HostedField field, JavaConstant receiver) { + return snippetReflection().asObject(Object.class, field.readStorageValue(receiver)); } private int referenceSize() { @@ -147,7 +148,7 @@ private void writeField(RelocatableBuffer buffer, ObjectInfo fields, HostedField } if (value.getJavaKind() == JavaKind.Object && heap.getMetaAccess().isInstanceOf(value, RelocatedPointer.class)) { - addNonDataRelocation(buffer, index, (RelocatedPointer) SubstrateObjectConstant.asObject(value)); + addNonDataRelocation(buffer, index, snippetReflection().asObject(RelocatedPointer.class, value)); } else { write(buffer, index, value, info != null ? info : field); } @@ -174,20 +175,20 @@ void writeReference(RelocatableBuffer buffer, int index, JavaConstant target, Ob int shift = compressEncoding.getShift(); writeReferenceValue(buffer, index, targetInfo.getAddress() >>> shift); } else { - addDirectRelocationWithoutAddend(buffer, index, referenceSize(), SubstrateObjectConstant.asObject(target)); + addDirectRelocationWithoutAddend(buffer, index, referenceSize(), snippetReflection().asObject(Object.class, target)); } } } private void writeConstant(RelocatableBuffer buffer, int index, JavaKind kind, JavaConstant constant, ObjectInfo info) { if (heap.getMetaAccess().isInstanceOf(constant, RelocatedPointer.class)) { - addNonDataRelocation(buffer, index, (RelocatedPointer) SubstrateObjectConstant.asObject(constant)); + addNonDataRelocation(buffer, index, snippetReflection().asObject(RelocatedPointer.class, constant)); return; } final JavaConstant con; if (heap.getMetaAccess().isInstanceOf(constant, WordBase.class)) { - Object value = heap.getUniverse().getSnippetReflection().asObject(Object.class, constant); + 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); @@ -210,7 +211,7 @@ private void writeConstant(RelocatableBuffer buffer, int index, JavaKind kind, O con = JavaConstant.forIntegerKind(FrameAccess.getWordKind(), 0); } else { assert kind == JavaKind.Object || value != null : "primitive value must not be null"; - con = SubstrateObjectConstant.forBoxedValue(kind, value); + con = snippetReflection().forBoxed(kind, value); } write(buffer, index, con, info); } @@ -385,7 +386,10 @@ private void writeObject(ObjectInfo info, RelocatableBuffer buffer) { JavaKind kind = clazz.getComponentType().getStorageKind(); JavaConstant constant = info.getConstant(); if (constant instanceof ImageHeapConstant) { - if (!clazz.getComponentType().isPrimitive()) { + if (clazz.getComponentType().isPrimitive()) { + ImageHeapPrimitiveArray imageHeapArray = (ImageHeapPrimitiveArray) constant; + writePrimitiveArray(info, buffer, objectLayout, kind, imageHeapArray.getArray(), imageHeapArray.getLength()); + } else { AnalysisConstantReflectionProvider constantReflection = heap.getUniverse().getConstantReflectionProvider(); int length = constantReflection.readArrayLength(constant); bufferBytes.putInt(info.getIndexInBuffer(objectLayout.getArrayLengthOffset()), length); @@ -394,8 +398,6 @@ private void writeObject(ObjectInfo info, RelocatableBuffer buffer) { final int elementIndex = info.getIndexInBuffer(objectLayout.getArrayElementOffset(kind, index)); writeConstant(buffer, elementIndex, kind, element, info); }); - } else { - throw VMError.shouldNotReachHere("Heap writing for primitive type ImageHeapArray not yet implemented."); } } else { Object array = info.getObject(); @@ -412,11 +414,7 @@ private void writeObject(ObjectInfo info, RelocatableBuffer buffer) { writeConstant(buffer, elementIndex, kind, element, info); } } else { - int elementIndex = info.getIndexInBuffer(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(), - Unsafe.ARRAY_BYTE_BASE_OFFSET + elementIndex, length * elementTypeSize); + writePrimitiveArray(info, buffer, objectLayout, kind, array, length); } } } else { @@ -424,6 +422,14 @@ 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)); + int elementTypeSize = Unsafe.getUnsafe().arrayIndexScale(array.getClass()); + assert elementTypeSize == kind.getByteCount(); + Unsafe.getUnsafe().copyMemory(array, Unsafe.getUnsafe().arrayBaseOffset(array.getClass()), buffer.getBackingArray(), + Unsafe.ARRAY_BYTE_BASE_OFFSET + elementIndex, length * elementTypeSize); + } + private Object maybeReplace(Object object, Object reason) { try { return heap.getAnalysisUniverse().replaceObject(object); @@ -431,4 +437,9 @@ private Object maybeReplace(Object object, Object reason) { throw NativeImageHeap.reportIllegalType(ex.getType(), reason); } } + + private SnippetReflectionProvider snippetReflection() { + return heap.getUniverse().getSnippetReflection(); + } + } 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 9b8a4c788bc2..3b0033ac85ea 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 @@ -177,7 +177,7 @@ private void processObject(ObjectInfo info, String group, boolean addObject, int } } if (info.getClazz().isInstanceClass()) { - JavaConstant con = SubstrateObjectConstant.forObject(info.getObject()); + JavaConstant con = heap.getUniverse().getSnippetReflection().forObject(info.getObject()); for (HostedField field : info.getClazz().getInstanceFields(true)) { if (field.getType().getStorageKind() == JavaKind.Object && !HybridLayout.isHybridField(field) && field.isAccessed()) { if (fieldFilter == null || fieldFilter.test(info, field)) { diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/sources/SourceCache.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/sources/SourceCache.java index 2893c9b4a8a3..de66ab8b90e2 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/sources/SourceCache.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/sources/SourceCache.java @@ -39,6 +39,8 @@ import java.util.HashMap; import java.util.List; +import org.graalvm.nativeimage.ImageSingletons; + import com.oracle.svm.core.SubstrateOptions; import com.oracle.svm.core.feature.AutomaticallyRegisteredFeature; import com.oracle.svm.core.feature.InternalFeature; @@ -57,196 +59,176 @@ public class SourceCache { - /** - * A list of all entries in the classpath used by the native image classloader. - */ - protected static final List classPathEntries = new ArrayList<>(); - /** - * A list of all entries in the module path used by the native image classloader. - */ - protected static final List modulePathEntries = new ArrayList<>(); - /** - * A list of all entries in the source search path specified by the user on the command line. - */ - protected static final List sourcePathEntries = new ArrayList<>(); - - /** - * A list of root directories which may contain source files from which this cache can be - * populated. - */ - protected List srcRoots; - - /** - * Modules needing special case root processing. - */ - private static final String[] specialRootModules = { - "jdk.internal.vm.ci", - "jdk.internal.vm.compiler", - }; + private static class SourceRoots { + /** + * A list of root directories which may contain source files from which this cache can be + * populated. + */ + private static final List srcRoots = new ArrayList<>(); - /** - * Extra root directories for files in the jdk.internal.vm.ci/compiler modules. - */ - private HashMap> specialSrcRoots; + /** + * Modules needing special case root processing. + */ + private static final String[] specialRootModules = { + "jdk.internal.vm.ci", + "jdk.internal.vm.compiler", + }; - /** - * Create the source cache. - */ - protected SourceCache() { - basePath = SubstrateOptions.getDebugInfoSourceCacheRoot(); - srcRoots = new ArrayList<>(); - specialSrcRoots = new HashMap<>(); - addJDKSources(); - addGraalSources(); - addApplicationSources(); - } + /** + * Extra root directories for files in the jdk.internal.vm.ci/compiler modules. + */ + private static final HashMap> specialSrcRoots = new HashMap<>(); - private void addJDKSources() { - String javaHome = System.getProperty("java.home"); - assert javaHome != null; - Path javaHomePath = Paths.get("", javaHome); - Path srcZipPath = javaHomePath.resolve("lib").resolve("src.zip"); - if (!srcZipPath.toFile().exists()) { - return; + static { + addJDKSources(); + addGraalSources(); + addApplicationSources(); } - try { - FileSystem srcFileSystem = FileSystems.newFileSystem(srcZipPath, (ClassLoader) null); - for (Path root : srcFileSystem.getRootDirectories()) { - srcRoots.add(new SourceRoot(root, true)); - // add dirs named "src" as extra roots for special modules - for (String specialRootModule : specialRootModules) { - ArrayList rootsList = new ArrayList<>(); - specialSrcRoots.put(specialRootModule, rootsList); - Path specialModuleRoot = root.resolve(specialRootModule); - Files.find(specialModuleRoot, 2, (path, attributes) -> path.endsWith("src")).forEach(rootsList::add); + + private static void addJDKSources() { + String javaHome = System.getProperty("java.home"); + assert javaHome != null; + Path javaHomePath = Paths.get("", javaHome); + Path srcZipPath = javaHomePath.resolve("lib").resolve("src.zip"); + if (!srcZipPath.toFile().exists()) { + return; + } + try { + FileSystem srcFileSystem = FileSystems.newFileSystem(srcZipPath, (ClassLoader) null); + for (Path root : srcFileSystem.getRootDirectories()) { + srcRoots.add(new SourceRoot(root, true)); + // add dirs named "src" as extra roots for special modules + for (String specialRootModule : specialRootModules) { + ArrayList rootsList = new ArrayList<>(); + specialSrcRoots.put(specialRootModule, rootsList); + Path specialModuleRoot = root.resolve(specialRootModule); + Files.find(specialModuleRoot, 2, (path, attributes) -> path.endsWith("src")).forEach(rootsList::add); + } } + } catch (IOException | FileSystemNotFoundException ioe) { + /* ignore this entry */ } - } catch (IOException | FileSystemNotFoundException ioe) { - /* ignore this entry */ } - } - private void addGraalSources() { - classPathEntries.stream() - .forEach(classPathEntry -> addGraalSourceRoot(classPathEntry, true)); - modulePathEntries.stream() - .forEach(modulePathEntry -> addGraalSourceRoot(modulePathEntry, true)); - sourcePathEntries.stream() - .forEach(sourcePathEntry -> addGraalSourceRoot(sourcePathEntry, false)); - } + private static void addGraalSources() { + SourceCacheFeature.getClassPath().forEach(classPathEntry -> addGraalSourceRoot(classPathEntry, true)); + SourceCacheFeature.getModulePath().forEach(modulePathEntry -> addGraalSourceRoot(modulePathEntry, true)); + SourceCacheFeature.getSourceSearchPath().forEach(sourcePathEntry -> addGraalSourceRoot(sourcePathEntry, false)); + } - private void addGraalSourceRoot(Path sourcePath, boolean fromClassPath) { - try { - String fileNameString = sourcePath.getFileName().toString(); - if (fileNameString.endsWith(".jar") || fileNameString.endsWith(".src.zip")) { - if (fromClassPath && fileNameString.endsWith(".jar")) { - /* - * GraalVM jar /path/to/xxx.jar in classpath should have sources - * /path/to/xxx.src.zip - */ - int length = fileNameString.length(); - fileNameString = fileNameString.substring(0, length - 3) + "src.zip"; - } - Path srcPath = sourcePath.getParent().resolve(fileNameString); - File srcFile = srcPath.toFile(); - if (srcFile.exists()) { - if (srcFile.isFile()) { - try { - FileSystem fileSystem = FileSystems.newFileSystem(srcPath, (ClassLoader) null); - for (Path root : fileSystem.getRootDirectories()) { - srcRoots.add(new SourceRoot(root)); + private static void addGraalSourceRoot(Path sourcePath, boolean fromClassPath) { + try { + String fileNameString = sourcePath.getFileName().toString(); + if (fileNameString.endsWith(".jar") || fileNameString.endsWith(".src.zip")) { + if (fromClassPath && fileNameString.endsWith(".jar")) { + /* + * GraalVM jar /path/to/xxx.jar in classpath should have sources + * /path/to/xxx.src.zip + */ + int length = fileNameString.length(); + fileNameString = fileNameString.substring(0, length - 3) + "src.zip"; + } + Path srcPath = sourcePath.getParent().resolve(fileNameString); + File srcFile = srcPath.toFile(); + if (srcFile.exists()) { + if (srcFile.isFile()) { + try { + FileSystem fileSystem = FileSystems.newFileSystem(srcPath, (ClassLoader) null); + for (Path root : fileSystem.getRootDirectories()) { + srcRoots.add(new SourceRoot(root)); + } + } catch (IOException | FileSystemNotFoundException ioe) { + /* ignore this entry */ } - } catch (IOException | FileSystemNotFoundException ioe) { - /* ignore this entry */ + } else if (srcFile.isDirectory()) { // Support for `MX_BUILD_EXPLODED=true` + srcRoots.add(new SourceRoot(srcPath)); + } else { + throw VMError.shouldNotReachHere(); } - } else if (srcFile.isDirectory()) { /* Support for `MX_BUILD_EXPLODED=true` */ + } + } else { + if (fromClassPath) { + /* + * graal classpath dir entries should have a src and/or src_gen subdirectory + */ + Path srcPath = sourcePath.resolve("src"); + srcRoots.add(new SourceRoot(srcPath)); + srcPath = sourcePath.resolve("src_gen"); srcRoots.add(new SourceRoot(srcPath)); } else { - throw VMError.shouldNotReachHere(); + srcRoots.add(new SourceRoot(sourcePath)); } } - } else { - if (fromClassPath) { - /* graal classpath dir entries should have a src and/or src_gen subdirectory */ - Path srcPath = sourcePath.resolve("src"); - srcRoots.add(new SourceRoot(srcPath)); - srcPath = sourcePath.resolve("src_gen"); - srcRoots.add(new SourceRoot(srcPath)); - } else { - srcRoots.add(new SourceRoot(sourcePath)); - } + } catch (NullPointerException npe) { + // do nothing } - } catch (NullPointerException npe) { - // do nothing } - } - private void addApplicationSources() { - classPathEntries.stream() - .forEach(classPathEntry -> addApplicationSourceRoot(classPathEntry, true)); - modulePathEntries.stream() - .forEach(modulePathEntry -> addApplicationSourceRoot(modulePathEntry, true)); - sourcePathEntries.stream() - .forEach(sourcePathEntry -> addApplicationSourceRoot(sourcePathEntry, false)); - } + private static void addApplicationSources() { + SourceCacheFeature.getClassPath().forEach(classPathEntry -> addApplicationSourceRoot(classPathEntry, true)); + SourceCacheFeature.getModulePath().forEach(modulePathEntry -> addApplicationSourceRoot(modulePathEntry, true)); + SourceCacheFeature.getSourceSearchPath().forEach(sourcePathEntry -> addApplicationSourceRoot(sourcePathEntry, false)); + } - protected void addApplicationSourceRoot(Path sourceRoot, boolean fromClassPath) { - try { - Path sourcePath = sourceRoot; - String fileNameString = sourcePath.getFileName().toString(); - if (fileNameString.endsWith(".jar") || fileNameString.endsWith(".zip")) { - if (fromClassPath && fileNameString.endsWith(".jar")) { - /* - * application jar /path/to/xxx.jar should have sources /path/to/xxx-sources.jar - */ - int length = fileNameString.length(); - fileNameString = fileNameString.substring(0, length - 4) + "-sources.jar"; - } - sourcePath = sourcePath.getParent().resolve(fileNameString); - if (sourcePath.toFile().exists()) { - try { - FileSystem fileSystem = FileSystems.newFileSystem(sourcePath, (ClassLoader) null); - for (Path root : fileSystem.getRootDirectories()) { - srcRoots.add(new SourceRoot(root)); + private static void addApplicationSourceRoot(Path sourceRoot, boolean fromClassPath) { + try { + Path sourcePath = sourceRoot; + String fileNameString = sourcePath.getFileName().toString(); + if (fileNameString.endsWith(".jar") || fileNameString.endsWith(".zip")) { + if (fromClassPath && fileNameString.endsWith(".jar")) { + /* + * application jar /path/to/xxx.jar should have sources + * /path/to/xxx-sources.jar + */ + int length = fileNameString.length(); + fileNameString = fileNameString.substring(0, length - 4) + "-sources.jar"; + } + sourcePath = sourcePath.getParent().resolve(fileNameString); + if (sourcePath.toFile().exists()) { + try { + FileSystem fileSystem = FileSystems.newFileSystem(sourcePath, (ClassLoader) null); + for (Path root : fileSystem.getRootDirectories()) { + srcRoots.add(new SourceRoot(root)); + } + } catch (IOException | FileSystemNotFoundException ioe) { + /* ignore this entry */ } - } catch (IOException | FileSystemNotFoundException ioe) { - /* ignore this entry */ } - } - } else { - if (fromClassPath) { - /* - * for dir entries ending in classes or target/classes translate to a parallel - * src tree - */ - if (sourcePath.endsWith("classes")) { - Path parent = sourcePath.getParent(); - if (parent.endsWith("target")) { - parent = parent.getParent(); + } else { + if (fromClassPath) { + /* + * for dir entries ending in classes or target/classes translate to a + * parallel src tree + */ + if (sourcePath.endsWith("classes")) { + Path parent = sourcePath.getParent(); + if (parent.endsWith("target")) { + parent = parent.getParent(); + } + sourcePath = (parent.resolve("src")); } - sourcePath = (parent.resolve("src")); } - } - // try the path as provided - File file = sourcePath.toFile(); - if (file.exists() && file.isDirectory()) { - // see if we have src/main/java or src/java - Path subPath = sourcePath.resolve("main").resolve("java"); - file = subPath.toFile(); + // try the path as provided + File file = sourcePath.toFile(); if (file.exists() && file.isDirectory()) { - sourcePath = subPath; - } else { - subPath = sourcePath.resolve("java"); + // see if we have src/main/java or src/java + Path subPath = sourcePath.resolve("main").resolve("java"); file = subPath.toFile(); if (file.exists() && file.isDirectory()) { sourcePath = subPath; + } else { + subPath = sourcePath.resolve("java"); + file = subPath.toFile(); + if (file.exists() && file.isDirectory()) { + sourcePath = subPath; + } } + srcRoots.add(new SourceRoot(sourcePath)); } - srcRoots.add(new SourceRoot(sourcePath)); } + } catch (NullPointerException npe) { + // do nothing } - } catch (NullPointerException npe) { - // do nothing } } @@ -254,7 +236,7 @@ protected void addApplicationSourceRoot(Path sourceRoot, boolean fromClassPath) * The top level path relative to the root directory under which files belonging to this * specific cache are located. */ - private final Path basePath; + private final Path basePath = SubstrateOptions.getDebugInfoSourceCacheRoot(); /** * Cache the source file identified by the supplied prototype path if a legitimate candidate for @@ -313,9 +295,9 @@ protected Path tryCacheFile(Path filePath, Class clazz) { } if (moduleName != null) { - for (String specialRootModule : specialRootModules) { + for (String specialRootModule : SourceRoots.specialRootModules) { if (moduleName.equals(specialRootModule)) { - for (Path srcRoot : specialSrcRoots.get(specialRootModule)) { + for (Path srcRoot : SourceRoots.specialSrcRoots.get(specialRootModule)) { String srcRootGroup = srcRoot.subpath(1, 2).toString().replace(".", filePath.getFileSystem().getSeparator()); if (filePath.toString().startsWith(srcRootGroup)) { Path sourcePath = extendPath(srcRoot, filePath); @@ -329,7 +311,7 @@ protected Path tryCacheFile(Path filePath, Class clazz) { } } - for (SourceRoot root : srcRoots) { + for (SourceRoot root : SourceRoots.srcRoots) { final Path scopedFilePath; if (moduleName != null && root.isJDK) { scopedFilePath = Paths.get(moduleName, filePath.toString()); @@ -377,10 +359,10 @@ protected Path checkCacheFile(Path filePath, Class clazz) { } if (moduleName != null) { - for (String specialRootModule : specialRootModules) { + for (String specialRootModule : SourceRoots.specialRootModules) { if (moduleName.equals(specialRootModule)) { // handle this module specially as it has intermediate dirs - for (Path srcRoot : specialSrcRoots.get(specialRootModule)) { + for (Path srcRoot : SourceRoots.specialSrcRoots.get(specialRootModule)) { String srcRootGroup = srcRoot.subpath(1, 2).toString().replace(".", filePath.getFileSystem().getSeparator()); if (filePath.toString().startsWith(srcRootGroup)) { Path sourcePath = extendPath(srcRoot, filePath); @@ -401,7 +383,7 @@ protected Path checkCacheFile(Path filePath, Class clazz) { } } - for (SourceRoot root : srcRoots) { + for (SourceRoot root : SourceRoots.srcRoots) { final Path scopedFilePath; if (moduleName != null && root.isJDK) { scopedFilePath = Paths.get(moduleName, filePath.toString()); @@ -500,33 +482,6 @@ protected static void ensureTargetDirs(Path targetDir) { } } } - - /** - * Add a path to the list of classpath entries. - * - * @param path The path to add. - */ - static void addClassPathEntry(Path path) { - classPathEntries.add(path); - } - - /** - * Add a path to the list of module path entries. - * - * @param path The path to add. - */ - static void addModulePathEntry(Path path) { - modulePathEntries.add(path); - } - - /** - * Add a path to the list of source path entries. - * - * @param path The path to add. - */ - static void addSourcePathEntry(Path path) { - sourcePathEntries.add(path); - } } /** @@ -536,22 +491,23 @@ static void addSourcePathEntry(Path path) { @AutomaticallyRegisteredFeature @SuppressWarnings("unused") class SourceCacheFeature implements InternalFeature { + ImageClassLoader imageClassLoader; + @Override public void afterAnalysis(AfterAnalysisAccess access) { - FeatureImpl.AfterAnalysisAccessImpl accessImpl = (FeatureImpl.AfterAnalysisAccessImpl) access; - ImageClassLoader loader = accessImpl.getImageClassLoader(); - for (Path entry : loader.classpath()) { - SourceCache.addClassPathEntry(entry); - } - for (Path entry : loader.modulepath()) { - SourceCache.addModulePathEntry(entry); - } - // also add any necessary source path entries - if (SubstrateOptions.DebugInfoSourceSearchPath.getValue() != null) { - for (Path searchPathEntry : SubstrateOptions.DebugInfoSourceSearchPath.getValue().values()) { - SourceCache.addSourcePathEntry(searchPathEntry); - } - } + imageClassLoader = ((FeatureImpl.AfterAnalysisAccessImpl) access).getImageClassLoader(); + } + + static List getClassPath() { + return ImageSingletons.lookup(SourceCacheFeature.class).imageClassLoader.classpath(); + } + + static List getModulePath() { + return ImageSingletons.lookup(SourceCacheFeature.class).imageClassLoader.modulepath(); + } + + static List getSourceSearchPath() { + return SubstrateOptions.DebugInfoSourceSearchPath.getValue().values(); } } 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 30b2a94a9541..e5f4d9947207 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 @@ -159,6 +159,8 @@ public void afterRegistration(AfterRegistrationAccess access) { rci.initializeAtBuildTime("apple.security", JDK_CLASS_REASON); } + rci.initializeAtBuildTime("sun.rmi.transport.GC", "Loaded an unneeded library (rmi) in static initializer."); + rci.rerunInitialization("com.sun.jndi.dns.DnsClient", "Contains Random references, therefore can't be included in the image heap."); rci.rerunInitialization("sun.net.www.protocol.http.DigestAuthentication$Parameters", "Contains Random references, therefore can't be included in the image heap."); rci.rerunInitialization("sun.security.krb5.KrbServiceLocator", "Contains Random references, therefore can't be included in the image heap."); diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/jdk/JNIRegistrationSupport.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/jdk/JNIRegistrationSupport.java index a55b2f8cd1cd..a3a99e44c3fe 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/jdk/JNIRegistrationSupport.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/jdk/JNIRegistrationSupport.java @@ -63,7 +63,6 @@ import com.oracle.svm.core.feature.InternalFeature; import com.oracle.svm.core.jdk.JNIRegistrationUtil; import com.oracle.svm.core.jdk.NativeLibrarySupport; -import com.oracle.svm.core.meta.SubstrateObjectConstant; import com.oracle.svm.core.option.HostedOptionKey; import com.oracle.svm.core.util.InterruptImageBuilding; import com.oracle.svm.core.util.VMError; @@ -108,10 +107,10 @@ public void afterAnalysis(AfterAnalysisAccess access) { @Override public void registerGraphBuilderPlugins(Providers providers, Plugins plugins, ParsingReason reason) { - registerLoadLibraryPlugin(plugins, System.class); + registerLoadLibraryPlugin(providers, plugins, System.class); } - public void registerLoadLibraryPlugin(Plugins plugins, Class clazz) { + public void registerLoadLibraryPlugin(Providers providers, Plugins plugins, Class clazz) { Registration r = new Registration(plugins.getInvocationPlugins(), clazz); r.register(new RequiredInvocationPlugin("loadLibrary", String.class) { @Override @@ -122,7 +121,7 @@ public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Rec * String arguments. */ if (libnameNode.isConstant()) { - registerLibrary((String) SubstrateObjectConstant.asObject(libnameNode.asConstant())); + registerLibrary(providers.getSnippetReflection().asObject(String.class, libnameNode.asJavaConstant())); } /* We never want to do any actual intrinsification, process the original invoke. */ return false; diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/jdk/JmxClientFeature.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/jdk/JmxClientFeature.java index 3889021e42b8..86431033db23 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/jdk/JmxClientFeature.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/jdk/JmxClientFeature.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. * Copyright (c) 2022, 2022, Red Hat Inc. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * @@ -25,18 +25,14 @@ */ package com.oracle.svm.hosted.jdk; -import com.oracle.svm.core.feature.InternalFeature; import org.graalvm.nativeimage.hosted.RuntimeReflection; +import com.oracle.svm.core.VMInspectionOptions; +import com.oracle.svm.core.feature.AutomaticallyRegisteredFeature; +import com.oracle.svm.core.feature.InternalFeature; import com.oracle.svm.core.jdk.JNIRegistrationUtil; -import com.oracle.svm.core.util.VMError; - -import com.oracle.svm.core.jdk.NativeLibrarySupport; -import com.oracle.svm.hosted.FeatureImpl.BeforeAnalysisAccessImpl; -import com.oracle.svm.core.jdk.PlatformNativeLibrarySupport; import com.oracle.svm.core.jni.JNIRuntimeAccess; -import com.oracle.svm.core.feature.AutomaticallyRegisteredFeature; -import com.oracle.svm.core.VMInspectionOptions; +import com.oracle.svm.core.util.VMError; import com.oracle.svm.util.ReflectionUtil; @AutomaticallyRegisteredFeature @@ -46,22 +42,11 @@ public boolean isInConfiguration(IsInConfigurationAccess access) { return VMInspectionOptions.hasJmxClientSupport(); } - private static void handleNativeLibraries(BeforeAnalysisAccess access) { - BeforeAnalysisAccessImpl a = (BeforeAnalysisAccessImpl) access; - NativeLibrarySupport.singleton().preregisterUninitializedBuiltinLibrary("rmi"); - a.getNativeLibraries().addStaticJniLibrary("rmi"); - - // Resolve calls to sun_rmi_transport* as builtIn. For calls to native method - // maxObjectInspectionAge() - PlatformNativeLibrarySupport.singleton().addBuiltinPkgNativePrefix("sun_rmi_transport"); - } - @Override public void beforeAnalysis(BeforeAnalysisAccess access) { try { configureJNI(); configureReflection(access); - handleNativeLibraries(access); } catch (Exception e) { throw VMError.shouldNotReachHere("ManagementClientFeature configuration failed: " + e); } diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/jdk/JmxCommonFeature.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/jdk/JmxCommonFeature.java index 3e152c3ac53e..d61e319fba95 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/jdk/JmxCommonFeature.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/jdk/JmxCommonFeature.java @@ -94,7 +94,6 @@ public void afterRegistration(AfterRegistrationAccess access) { rci.initializeAtRunTime("com.sun.jmx.remote.security.JMXPluggableAuthenticator$FileLoginConfig", "JMX support"); rci.initializeAtRunTime("sun.rmi.transport.DGCImpl", "JMX support"); rci.initializeAtRunTime("sun.rmi.transport.DGCAckHandler", "JMX support"); - rci.initializeAtRunTime("sun.rmi.transport.GC", "JMX support"); rci.initializeAtRunTime("sun.rmi.transport.DGCClient", "JMX support"); rci.initializeAtRunTime("sun.rmi.transport.ObjectTable", "JMX support"); rci.initializeAtRunTime("sun.rmi.transport.tcp.TCPEndpoint", "JMX support"); 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 6b3b8a1d5f48..73a1b9d320e1 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 @@ -44,11 +44,9 @@ import com.oracle.svm.core.c.CGlobalDataFactory; import com.oracle.svm.core.graal.code.CGlobalDataInfo; import com.oracle.svm.core.graal.nodes.CGlobalDataLoadAddressNode; -import com.oracle.svm.core.hub.DynamicHub; import com.oracle.svm.core.jni.access.JNINativeLinkage; import com.oracle.svm.core.jni.headers.JNIEnvironment; import com.oracle.svm.core.jni.headers.JNIObjectHandle; -import com.oracle.svm.core.meta.SubstrateObjectConstant; import com.oracle.svm.core.thread.VMThreads.StatusSupport; import com.oracle.svm.hosted.annotation.CustomSubstitutionMethod; import com.oracle.svm.hosted.c.CGlobalDataFeature; @@ -56,7 +54,6 @@ import com.oracle.svm.hosted.heap.SVMImageHeapScanner; import com.oracle.svm.util.ReflectionUtil; -import jdk.vm.ci.meta.Constant; import jdk.vm.ci.meta.JavaConstant; import jdk.vm.ci.meta.JavaType; import jdk.vm.ci.meta.LineNumberTable; @@ -165,9 +162,8 @@ public StructuredGraph buildGraph(DebugContext debug, ResolvedJavaMethod method, if (getOriginal().isSynchronized()) { ValueNode monitorObject; if (method.isStatic()) { - Constant hubConstant = providers.getConstantReflection().asObjectHub(method.getDeclaringClass()); - DynamicHub hub = (DynamicHub) SubstrateObjectConstant.asObject(hubConstant); - monitorObject = ConstantNode.forConstant(SubstrateObjectConstant.forObject(hub), providers.getMetaAccess(), graph); + JavaConstant hubConstant = (JavaConstant) providers.getConstantReflection().asObjectHub(method.getDeclaringClass()); + monitorObject = ConstantNode.forConstant(hubConstant, providers.getMetaAccess(), graph); } else { monitorObject = kit.maybeCreateExplicitNullCheck(javaArguments.get(0)); } 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 465659f7276a..d47f3ac7afba 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 @@ -29,12 +29,8 @@ import org.graalvm.nativeimage.Platform; import org.graalvm.nativeimage.Platforms; -import com.oracle.graal.pointsto.heap.ImageHeapConstant; -import com.oracle.graal.pointsto.infrastructure.UniverseMetaAccess; import com.oracle.svm.core.graal.meta.SharedConstantReflectionProvider; -import com.oracle.svm.core.hub.DynamicHub; import com.oracle.svm.core.meta.SubstrateObjectConstant; -import com.oracle.svm.core.util.VMError; import com.oracle.svm.hosted.SVMHost; import jdk.vm.ci.meta.Constant; @@ -47,13 +43,11 @@ public class HostedConstantReflectionProvider extends SharedConstantReflectionProvider { private final SVMHost hostVM; private final HostedUniverse universe; - private final UniverseMetaAccess metaAccess; private final HostedMemoryAccessProvider memoryAccess; - public HostedConstantReflectionProvider(SVMHost hostVM, HostedUniverse universe, UniverseMetaAccess metaAccess, HostedMemoryAccessProvider memoryAccess) { + public HostedConstantReflectionProvider(SVMHost hostVM, HostedUniverse universe, HostedMemoryAccessProvider memoryAccess) { this.hostVM = hostVM; this.universe = universe; - this.metaAccess = metaAccess; this.memoryAccess = memoryAccess; } @@ -62,22 +56,22 @@ public MemoryAccessProvider getMemoryAccessProvider() { return memoryAccess; } + @Override + public JavaConstant boxPrimitive(JavaConstant source) { + /* Delegate to the AnalysisConstantReflectionProvider. */ + return universe.getConstantReflectionProvider().boxPrimitive(source); + } + + @Override + public JavaConstant unboxPrimitive(JavaConstant source) { + /* Delegate to the AnalysisConstantReflectionProvider. */ + return universe.getConstantReflectionProvider().unboxPrimitive(source); + } + @Override public ResolvedJavaType asJavaType(Constant constant) { - if (constant instanceof SubstrateObjectConstant) { - Object obj = SubstrateObjectConstant.asObject(constant); - if (obj instanceof DynamicHub) { - return universe.lookup(hostVM.lookupType((DynamicHub) obj)); - } else if (obj instanceof Class) { - throw VMError.shouldNotReachHere("Must not have java.lang.Class object: " + obj); - } - } - if (constant instanceof ImageHeapConstant) { - if (metaAccess.isInstanceOf((JavaConstant) constant, Class.class)) { - throw VMError.shouldNotReachHere("ConstantReflectionProvider.asJavaType(Constant) not yet implemented for ImageHeapObject"); - } - } - return null; + /* Delegate to the AnalysisConstantReflectionProvider. */ + return universe.lookup(universe.getConstantReflectionProvider().asJavaType(constant)); } @Override 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 e56705882668..8bde016f03a5 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 @@ -31,8 +31,6 @@ import com.oracle.graal.pointsto.meta.AnalysisField; import com.oracle.svm.core.hub.DynamicHub; import com.oracle.svm.core.meta.SharedField; -import com.oracle.svm.core.meta.SubstrateObjectConstant; -import com.oracle.svm.core.util.VMError; import jdk.vm.ci.meta.JavaConstant; import jdk.vm.ci.meta.JavaKind; @@ -151,19 +149,16 @@ public int hashCode() { } public JavaConstant readValue(JavaConstant receiver) { - JavaConstant wrappedReceiver; - if (metaAccess.isInstanceOf(receiver, Class.class)) { - Object classObject = SubstrateObjectConstant.asObject(receiver); - if (classObject instanceof Class) { - throw VMError.shouldNotReachHere("Receiver " + receiver + " of field " + this + " read should not be java.lang.Class. Expecting to see DynamicHub here."); - } else { - VMError.guarantee(classObject instanceof DynamicHub); - wrappedReceiver = receiver; - } - } else { - wrappedReceiver = receiver; + assert checkHub(receiver) : "Receiver " + receiver + " of field " + this + " read should not be java.lang.Class. Expecting to see DynamicHub here."; + return universe.lookup(universe.getConstantReflectionProvider().readValue(metaAccess, wrapped, receiver)); + } + + private boolean checkHub(JavaConstant constant) { + if (metaAccess.isInstanceOf(constant, Class.class)) { + Object classObject = universe.getSnippetReflection().asObject(Object.class, constant); + return classObject instanceof DynamicHub; } - return universe.lookup(universe.getConstantReflectionProvider().readValue(metaAccess, wrapped, wrappedReceiver)); + return true; } public JavaConstant readStorageValue(JavaConstant receiver) { 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 74f6ee8ee5fb..305506a6877a 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 @@ -33,8 +33,12 @@ import java.util.stream.Collectors; import java.util.stream.Stream; +import org.graalvm.compiler.core.common.type.TypedConstant; + +import com.oracle.graal.pointsto.heap.ImageHeapConstant; import com.oracle.graal.pointsto.infrastructure.UniverseMetaAccess; import com.oracle.graal.pointsto.meta.AnalysisMetaAccess; +import com.oracle.graal.pointsto.meta.AnalysisType; import com.oracle.svm.core.deopt.Deoptimizer; import jdk.vm.ci.meta.DeoptimizationAction; @@ -56,6 +60,11 @@ public HostedType lookupJavaType(Class clazz) { @Override public HostedType lookupJavaType(JavaConstant constant) { + if (constant instanceof ImageHeapConstant) { + ResolvedJavaType type = ((TypedConstant) constant).getType(this); + assert type == null || type instanceof AnalysisType : type; + return (HostedType) universe.lookup(type); + } return (HostedType) super.lookupJavaType(constant); } 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 3346c60d3cb1..a7bebcc05649 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 @@ -25,8 +25,11 @@ package com.oracle.svm.hosted.meta; import org.graalvm.compiler.word.WordTypes; +import org.graalvm.nativeimage.c.function.RelocatedPointer; import org.graalvm.word.WordBase; +import com.oracle.graal.pointsto.heap.ImageHeapConstant; +import com.oracle.graal.pointsto.heap.ImageHeapPrimitiveArray; import com.oracle.svm.core.FrameAccess; import com.oracle.svm.core.graal.meta.SubstrateSnippetReflectionProvider; import com.oracle.svm.core.hub.DynamicHub; @@ -42,20 +45,28 @@ public HostedSnippetReflectionProvider(WordTypes wordTypes) { @Override public JavaConstant forObject(Object object) { - if (object instanceof WordBase) { - return JavaConstant.forIntegerKind(FrameAccess.getWordKind(), ((WordBase) object).rawValue()); + if (object instanceof WordBase word && !(object instanceof RelocatedPointer)) { + /* Relocated pointers are subject to relocation, so we don't know their value yet. */ + return JavaConstant.forIntegerKind(FrameAccess.getWordKind(), word.rawValue()); } return super.forObject(object); } @Override public T asObject(Class type, JavaConstant constant) { - if ((type == Class.class || type == Object.class) && constant instanceof SubstrateObjectConstant) { - Object objectValue = SubstrateObjectConstant.asObject(constant); - if (objectValue instanceof DynamicHub) { - return type.cast(((DynamicHub) objectValue).getHostedJavaClass()); + if (type == Class.class && constant instanceof SubstrateObjectConstant) { + /* Only unwrap the DynamicHub if a Class object is required explicitly. */ + if (SubstrateObjectConstant.asObject(constant) instanceof DynamicHub hub) { + return type.cast(hub.getHostedJavaClass()); } } + if (constant instanceof ImageHeapPrimitiveArray heapArray) { + return type.cast(heapArray.getArray()); + } + if (constant instanceof ImageHeapConstant heapConstant) { + return super.asObject(type, heapConstant.getHostedObject()); + } return super.asObject(type, constant); } + } 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 47ecf853a181..75e091aeb9c9 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 @@ -28,6 +28,7 @@ import java.util.Arrays; +import org.graalvm.compiler.api.replacements.SnippetReflectionProvider; import org.graalvm.compiler.core.common.calc.FloatConvert; import org.graalvm.compiler.core.common.memory.BarrierType; import org.graalvm.compiler.core.common.memory.MemoryOrderMode; @@ -73,7 +74,6 @@ 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.meta.SubstrateObjectConstant; import com.oracle.svm.core.util.UserError; import com.oracle.svm.hosted.c.CInterfaceError; import com.oracle.svm.hosted.c.NativeLibraries; @@ -104,11 +104,13 @@ public class CInterfaceInvocationPlugin implements NodePlugin { private final NativeLibraries nativeLibs; private final ResolvedJavaType functionPointerType; + private final SnippetReflectionProvider snippetReflection; - public CInterfaceInvocationPlugin(MetaAccessProvider metaAccess, WordTypes wordTypes, NativeLibraries nativeLibs) { + public CInterfaceInvocationPlugin(MetaAccessProvider metaAccess, SnippetReflectionProvider snippetReflection, WordTypes wordTypes, NativeLibraries nativeLibs) { this.wordTypes = wordTypes; this.nativeLibs = nativeLibs; this.functionPointerType = metaAccess.lookupJavaType(CFunctionPointer.class); + this.snippetReflection = snippetReflection; } @Override @@ -191,7 +193,7 @@ private boolean replaceAccessor(GraphBuilderContext b, ResolvedJavaMethod method readKind = resultKind; } AddressNode offsetAddress = makeOffsetAddress(graph, args, accessorInfo, base, displacement, elementSize); - LocationIdentity locationIdentity = makeLocationIdentity(b, method, args, accessorInfo); + LocationIdentity locationIdentity = makeLocationIdentity(b, snippetReflection, method, args, accessorInfo); final Stamp stamp; if (readKind == JavaKind.Object) { stamp = b.getInvokeReturnStamp(null).getTrustedStamp(); @@ -215,7 +217,7 @@ private boolean replaceAccessor(GraphBuilderContext b, ResolvedJavaMethod method JavaKind valueKind = value.getStackKind(); JavaKind writeKind = kindFromSize(elementSize, valueKind); AddressNode offsetAddress = makeOffsetAddress(graph, args, accessorInfo, base, displacement, elementSize); - LocationIdentity locationIdentity = makeLocationIdentity(b, method, args, accessorInfo); + LocationIdentity locationIdentity = makeLocationIdentity(b, snippetReflection, method, args, accessorInfo); if (isPinnedObject) { b.add(new JavaWriteNode(writeKind, offsetAddress, locationIdentity, value, BarrierType.NONE, true)); } else { @@ -290,7 +292,7 @@ private boolean replaceBitfieldAccessor(GraphBuilderContext b, ResolvedJavaMetho * bits around the written bitfield unchanged. */ AddressNode address = makeOffsetAddress(graph, args, accessorInfo, base, byteOffset, -1); - LocationIdentity locationIdentity = makeLocationIdentity(b, method, args, accessorInfo); + LocationIdentity locationIdentity = makeLocationIdentity(b, snippetReflection, method, args, accessorInfo); Stamp stamp = IntegerStamp.create(memoryKind.getBitCount()); ValueNode cur = readPrimitive(b, address, locationIdentity, stamp, accessorInfo); cur = adaptPrimitiveType(graph, cur, memoryKind, computeKind, true); @@ -386,7 +388,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, ResolvedJavaMethod method, ValueNode[] args, AccessorInfo accessorInfo) { + private static LocationIdentity makeLocationIdentity(GraphBuilderContext b, SnippetReflectionProvider snippetReflection, ResolvedJavaMethod method, ValueNode[] args, AccessorInfo accessorInfo) { LocationIdentity locationIdentity; if (accessorInfo.hasLocationIdentityParameter()) { ValueNode locationIdentityNode = args[accessorInfo.locationIdentityParameterNumber(true)]; @@ -395,7 +397,7 @@ private static LocationIdentity makeLocationIdentity(GraphBuilderContext b, Reso "locationIdentity is not a compile time constant for call to " + method.format("%H.%n(%p)") + " in " + b.getMethod().asStackTraceElement(b.bci()), method).getMessage()); } - locationIdentity = (LocationIdentity) SubstrateObjectConstant.asObject(locationIdentityNode.asConstant()); + locationIdentity = snippetReflection.asObject(LocationIdentity.class, locationIdentityNode.asJavaConstant()); } else if (accessorInfo.hasUniqueLocationIdentity()) { StructFieldInfo fieldInfo = (StructFieldInfo) accessorInfo.getParent(); assert fieldInfo.getLocationIdentity() != null; @@ -487,7 +489,7 @@ private boolean replaceConstant(GraphBuilderContext b, ResolvedJavaMethod method break; case STRING: case BYTEARRAY: - valueNode = ConstantNode.forConstant(SubstrateObjectConstant.forObject(value), b.getMetaAccess(), b.getGraph()); + valueNode = ConstantNode.forConstant(snippetReflection.forObject(value), b.getMetaAccess(), b.getGraph()); break; default: throw shouldNotReachHere("Unexpected constant kind " + constantInfo); 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 44f44b257822..3beb257b33f6 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 @@ -61,6 +61,7 @@ import com.oracle.svm.core.heap.RestrictHeapAccess; 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 jdk.vm.ci.meta.ResolvedJavaMethod; @@ -234,6 +235,14 @@ protected boolean processNode(AnalysisMetaAccess metaAccess, ResolvedJavaMethod return true; } + if (node instanceof ReachabilityRegistrationNode) { + /* + * These nodes do not affect compilation and are only used to execute handlers depending + * on their reachability. + */ + return true; + } + if (alwaysInlineInvoke(metaAccess, method)) { return true; } 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 e67ac282e45e..bbc52e1038c8 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 @@ -121,7 +121,6 @@ import com.oracle.svm.core.graal.phases.TrustedInterfaceTypePlugin; import com.oracle.svm.core.graal.word.SubstrateWordTypes; import com.oracle.svm.core.jdk.VarHandleFeature; -import com.oracle.svm.core.meta.SubstrateObjectConstant; import com.oracle.svm.core.util.VMError; import com.oracle.svm.hosted.SVMHost; import com.oracle.svm.hosted.meta.HostedMethod; @@ -332,7 +331,7 @@ private boolean isVarHandleMethod(ResolvedJavaMethod method, ValueNode[] args) { * initialization has happened. We force initialization by invoking the method * VarHandle.vform.getMethodType_V(0). */ - VarHandle varHandle = (VarHandle) SubstrateObjectConstant.asObject(args[0].asJavaConstant()); + VarHandle varHandle = aUniverse.getSnippetReflection().asObject(VarHandle.class, args[0].asJavaConstant()); Object varForm = varHandleVFormField.get(varHandle); varFormInitMethod.invoke(varForm, 0); diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/phases/SubstrateClassInitializationPlugin.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/phases/SubstrateClassInitializationPlugin.java index 056a7da1c649..f32431a9b61e 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/phases/SubstrateClassInitializationPlugin.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/phases/SubstrateClassInitializationPlugin.java @@ -26,6 +26,7 @@ import java.util.function.Supplier; +import org.graalvm.compiler.api.replacements.SnippetReflectionProvider; import org.graalvm.compiler.nodes.ConstantNode; import org.graalvm.compiler.nodes.FrameState; import org.graalvm.compiler.nodes.ValueNode; @@ -33,7 +34,6 @@ import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderContext; import com.oracle.svm.core.classinitialization.EnsureClassInitializedNode; -import com.oracle.svm.core.meta.SubstrateObjectConstant; import com.oracle.svm.hosted.SVMHost; import jdk.vm.ci.meta.ConstantPool; @@ -61,7 +61,8 @@ public void loadReferencedType(GraphBuilderContext builder, ConstantPool constan @Override public boolean apply(GraphBuilderContext builder, ResolvedJavaType type, Supplier frameState, ValueNode[] classInit) { if (EnsureClassInitializedNode.needsRuntimeInitialization(builder.getMethod().getDeclaringClass(), type)) { - emitEnsureClassInitialized(builder, SubstrateObjectConstant.forObject(host.dynamicHub(type)), frameState.get()); + SnippetReflectionProvider snippetReflection = builder.getSnippetReflection(); + emitEnsureClassInitialized(builder, snippetReflection.forObject(host.dynamicHub(type)), frameState.get()); /* * The classInit value is only registered with Invoke nodes. Since we do not need that, * we ensure it is null. 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 78bcae55c2f9..2036e72bcaf3 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 @@ -339,8 +339,9 @@ public String getDeletionReason(Field reflectionField) { @Override public void registerInvocationPlugins(Providers providers, SnippetReflectionProvider snippetReflection, Plugins plugins, ParsingReason reason) { + FallbackFeature fallbackFeature = ImageSingletons.contains(FallbackFeature.class) ? ImageSingletons.lookup(FallbackFeature.class) : null; ReflectionPlugins.registerInvocationPlugins(loader, snippetReflection, annotationSubstitutions, - plugins.getClassInitializationPlugin(), plugins.getInvocationPlugins(), aUniverse, reason); + plugins.getClassInitializationPlugin(), plugins.getInvocationPlugins(), aUniverse, reason, fallbackFeature); } } 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 581d319f0268..dfbe87883a93 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 @@ -65,6 +65,7 @@ import java.util.function.Consumer; import org.graalvm.collections.Pair; +import org.graalvm.compiler.api.replacements.SnippetReflectionProvider; import org.graalvm.compiler.core.common.util.TypeConversion; import org.graalvm.compiler.core.common.util.UnsafeArrayTypeWriter; import org.graalvm.compiler.serviceprovider.JavaVersionUtil; @@ -81,7 +82,6 @@ import com.oracle.svm.core.feature.AutomaticallyRegisteredImageSingleton; import com.oracle.svm.core.hub.DynamicHub; import com.oracle.svm.core.meta.SharedField; -import com.oracle.svm.core.meta.SubstrateObjectConstant; import com.oracle.svm.core.reflect.Target_jdk_internal_reflect_ConstantPool; import com.oracle.svm.core.reflect.target.EncodedReflectionMetadataSupplier; import com.oracle.svm.core.reflect.target.ReflectionMetadataDecoderImpl; @@ -122,7 +122,8 @@ * * Emitting the metadata happens in two phases. In the first phase, the string and class encoders * are filled with the necessary values (in the {@code #add*Metadata} functions). In a second phase, - * the values are encoded into their intended byte arrays (see {@link #encodeAllAndInstall()}). + * the values are encoded into their intended byte arrays (see + * {@link ReflectionMetadataEncoder#encodeAllAndInstall(SnippetReflectionProvider)}). * * The metadata encoding format is detailed in {@link ReflectionMetadataDecoderImpl}. */ @@ -253,6 +254,7 @@ public byte[] getReflectParametersEncoding(Executable object) { @Override public void addClassMetadata(MetaAccessProvider metaAccess, HostedType type, Class[] innerClasses) { + SnippetReflectionProvider snippetReflection = ((HostedMetaAccess) metaAccess).getUniverse().getSnippetReflection(); Class javaClass = type.getHub().getHostedJavaClass(); Object enclosingMethodInfo = getEnclosingMethodInfo(javaClass); RecordComponentMetadata[] recordComponents = getRecordComponents(metaAccess, type, javaClass); @@ -267,7 +269,7 @@ public void addClassMetadata(MetaAccessProvider metaAccess, HostedType type, Cla /* Register string and class values in annotations */ encoders.sourceClasses.addObject(javaClass); if (enclosingMethodInfo instanceof Throwable) { - registerError((Throwable) enclosingMethodInfo); + registerError(snippetReflection, (Throwable) enclosingMethodInfo); } else { registerEnclosingMethodInfo((Object[]) enclosingMethodInfo); } @@ -278,7 +280,7 @@ public void addClassMetadata(MetaAccessProvider metaAccess, HostedType type, Cla if (signers != null) { signerConstants = new JavaConstant[signers.length]; for (int i = 0; i < signers.length; ++i) { - signerConstants[i] = SubstrateObjectConstant.forObject(signers[i]); + signerConstants[i] = snippetReflection.forObject(signers[i]); encoders.objectConstants.addObject(signerConstants[i]); } } @@ -289,8 +291,8 @@ public void addClassMetadata(MetaAccessProvider metaAccess, HostedType type, Cla registerClass(type, new ClassMetadata(innerTypes, enclosingMethodInfo, recordComponents, permittedSubtypes, nestMemberTypes, signerConstants, flags, annotations, typeAnnotations)); } - private void registerError(Throwable error) { - encoders.objectConstants.addObject(SubstrateObjectConstant.forObject(error)); + private void registerError(SnippetReflectionProvider snippetReflection, Throwable error) { + encoders.objectConstants.addObject(snippetReflection.forObject(error)); } private static final Method getEnclosingMethod0 = ReflectionUtil.lookupMethod(Class.class, "getEnclosingMethod0"); @@ -382,6 +384,7 @@ public void addReflectionFieldMetadata(MetaAccessProvider metaAccess, HostedFiel @Override public void addReflectionExecutableMetadata(MetaAccessProvider metaAccess, HostedMethod hostedMethod, Executable reflectMethod, Object accessor) { + SnippetReflectionProvider snippetReflection = ((HostedMetaAccess) metaAccess).getUniverse().getSnippetReflection(); boolean isMethod = !hostedMethod.isConstructor(); HostedType declaringType = hostedMethod.getDeclaringClass(); String name = isMethod ? hostedMethod.getName() : null; @@ -413,7 +416,7 @@ public void addReflectionExecutableMetadata(MetaAccessProvider metaAccess, Hoste ReflectParameterMetadata[] reflectParameters = registerReflectParameters(reflectMethod); JavaConstant accessorConstant = null; if (accessor != null) { - accessorConstant = SubstrateObjectConstant.forObject(accessor); + accessorConstant = snippetReflection.forObject(accessor); encoders.objectConstants.addObject(accessorConstant); } @@ -443,6 +446,7 @@ private static boolean isTrustedFinal(Field field) { public void addHeapAccessibleObjectMetadata(MetaAccessProvider metaAccess, WrappedElement hostedObject, AccessibleObject object, boolean registered) { boolean isExecutable = object instanceof Executable; boolean isMethod = object instanceof Method; + SnippetReflectionProvider snippetReflection = ((HostedMetaAccess) metaAccess).getUniverse().getSnippetReflection(); /* Register string and class values in annotations */ AnnotatedElement analysisObject = hostedObject.getWrapped(); @@ -452,7 +456,7 @@ public void addHeapAccessibleObjectMetadata(MetaAccessProvider metaAccess, Wrapp AnnotationMemberValue annotationDefault = isMethod ? registerAnnotationDefaultValues((AnalysisMethod) analysisObject) : null; ReflectParameterMetadata[] reflectParameters = isExecutable ? registerReflectParameters((Executable) object) : null; AccessibleObject holder = ReflectionMetadataEncoder.getHolder(object); - JavaConstant heapObjectConstant = SubstrateObjectConstant.forObject(holder); + JavaConstant heapObjectConstant = snippetReflection.forObject(holder); encoders.objectConstants.addObject(heapObjectConstant); AccessibleObjectMetadata metadata; @@ -725,7 +729,7 @@ private static String getRecordComponentSignature(Object recordComponent) { * See {@link ReflectionMetadataDecoderImpl} for the encoding format description. */ @Override - public void encodeAllAndInstall() { + public void encodeAllAndInstall(SnippetReflectionProvider snippetReflection) { UnsafeArrayTypeWriter buf = UnsafeArrayTypeWriter.create(ByteArrayReader.supportsUnalignedMemoryAccess()); int typesIndex = encodeAndAddCollection(buf, sortedTypes.toArray(new HostedType[0]), this::encodeType, false); assert typesIndex == 0; @@ -734,7 +738,7 @@ public void encodeAllAndInstall() { ClassMetadata classMetadata = classData.get(declaringType); int enclosingMethodInfoIndex = classMetadata.enclosingMethodInfo instanceof Throwable - ? encodeErrorIndex((Throwable) classMetadata.enclosingMethodInfo) + ? encodeErrorIndex(snippetReflection, (Throwable) classMetadata.enclosingMethodInfo) : addElement(buf, encodeEnclosingMethodInfo((Object[]) classMetadata.enclosingMethodInfo)); int annotationsIndex = addEncodedElement(buf, encodeAnnotations(classMetadata.annotations)); int typeAnnotationsIndex = addEncodedElement(buf, encodeTypeAnnotations(classMetadata.typeAnnotations)); @@ -756,7 +760,7 @@ public void encodeAllAndInstall() { } } for (AccessibleObjectMetadata metadata : heapData) { - AccessibleObject heapObject = (AccessibleObject) SubstrateObjectConstant.asObject(metadata.heapObject); + AccessibleObject heapObject = snippetReflection.asObject(AccessibleObject.class, metadata.heapObject); annotationsEncodings.put(heapObject, encodeAnnotations(metadata.annotations)); typeAnnotationsEncodings.put(heapObject, encodeTypeAnnotations(metadata.typeAnnotations)); if (metadata instanceof ExecutableMetadata) { @@ -774,8 +778,8 @@ public void encodeAllAndInstall() { ImageSingletons.add(EncodedReflectionMetadataSupplier.class, this); } - private int encodeErrorIndex(Throwable error) { - int index = encoders.objectConstants.getIndex(SubstrateObjectConstant.forObject(error)); + private int encodeErrorIndex(SnippetReflectionProvider snippetReflection, Throwable error) { + int index = encoders.objectConstants.getIndex(snippetReflection.forObject(error)); int encodedIndex = FIRST_ERROR_INDEX - index; VMError.guarantee(ReflectionMetadataDecoderImpl.isErrorIndex(encodedIndex)); return encodedIndex; 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 1378fdff35d0..d15e2a218b03 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 @@ -42,6 +42,7 @@ import java.util.List; import java.util.Objects; import java.util.Set; +import java.util.function.Consumer; import java.util.function.Predicate; import java.util.function.Supplier; import java.util.stream.Collectors; @@ -71,9 +72,12 @@ import com.oracle.svm.core.hub.PredefinedClassesSupport; import com.oracle.svm.core.jdk.StackTraceUtils; import com.oracle.svm.core.option.HostedOptionKey; +import com.oracle.svm.core.reflect.MissingReflectionRegistrationUtils; import com.oracle.svm.core.util.VMError; import com.oracle.svm.hosted.ExceptionSynthesizer; +import com.oracle.svm.hosted.FallbackFeature; import com.oracle.svm.hosted.ImageClassLoader; +import com.oracle.svm.hosted.ReachabilityRegistrationNode; import com.oracle.svm.hosted.classinitialization.ClassInitializationSupport; import com.oracle.svm.hosted.substitute.AnnotationSubstitutionProcessor; import com.oracle.svm.hosted.substitute.DeletedElementException; @@ -118,19 +122,21 @@ static class Options { private final ClassInitializationPlugin classInitializationPlugin; private final AnalysisUniverse aUniverse; private final ParsingReason reason; + private final FallbackFeature fallbackFeature; private ReflectionPlugins(ImageClassLoader imageClassLoader, SnippetReflectionProvider snippetReflection, AnnotationSubstitutionProcessor annotationSubstitutions, - ClassInitializationPlugin classInitializationPlugin, AnalysisUniverse aUniverse, ParsingReason reason) { + ClassInitializationPlugin classInitializationPlugin, AnalysisUniverse aUniverse, ParsingReason reason, FallbackFeature fallbackFeature) { this.imageClassLoader = imageClassLoader; this.snippetReflection = snippetReflection; this.annotationSubstitutions = annotationSubstitutions; this.classInitializationPlugin = classInitializationPlugin; this.aUniverse = aUniverse; this.reason = reason; + this.fallbackFeature = fallbackFeature; } public static void registerInvocationPlugins(ImageClassLoader imageClassLoader, SnippetReflectionProvider snippetReflection, AnnotationSubstitutionProcessor annotationSubstitutions, - ClassInitializationPlugin classInitializationPlugin, InvocationPlugins plugins, AnalysisUniverse aUniverse, ParsingReason reason) { + ClassInitializationPlugin classInitializationPlugin, InvocationPlugins plugins, AnalysisUniverse aUniverse, ParsingReason reason, FallbackFeature fallbackFeature) { /* * Initialize the registry if we are during analysis. If hosted is false, i.e., we are * analyzing the static initializers, then we always intrinsify, so don't need a registry. @@ -141,7 +147,7 @@ public static void registerInvocationPlugins(ImageClassLoader imageClassLoader, } } - ReflectionPlugins rp = new ReflectionPlugins(imageClassLoader, snippetReflection, annotationSubstitutions, classInitializationPlugin, aUniverse, reason); + ReflectionPlugins rp = new ReflectionPlugins(imageClassLoader, snippetReflection, annotationSubstitutions, classInitializationPlugin, aUniverse, reason, fallbackFeature); rp.registerMethodHandlesPlugins(plugins); rp.registerClassPlugins(plugins); } @@ -255,6 +261,21 @@ private void registerClassPlugins(InvocationPlugins plugins) { "getField", "getMethod", "getConstructor", "getDeclaredField", "getDeclaredMethod", "getDeclaredConstructor"); + if (MissingReflectionRegistrationUtils.throwMissingRegistrationErrors()) { + registerBulkInvocationPlugin(plugins, Class.class, "getClasses", RuntimeReflection::registerAllClasses); + registerBulkInvocationPlugin(plugins, Class.class, "getDeclaredClasses", RuntimeReflection::registerAllDeclaredClasses); + registerBulkInvocationPlugin(plugins, Class.class, "getConstructors", RuntimeReflection::registerAllConstructors); + registerBulkInvocationPlugin(plugins, Class.class, "getDeclaredConstructors", RuntimeReflection::registerAllDeclaredConstructors); + registerBulkInvocationPlugin(plugins, Class.class, "getFields", RuntimeReflection::registerAllFields); + registerBulkInvocationPlugin(plugins, Class.class, "getDeclaredFields", RuntimeReflection::registerAllDeclaredFields); + registerBulkInvocationPlugin(plugins, Class.class, "getMethods", RuntimeReflection::registerAllMethods); + registerBulkInvocationPlugin(plugins, Class.class, "getDeclaredMethods", RuntimeReflection::registerAllDeclaredMethods); + registerBulkInvocationPlugin(plugins, Class.class, "getNestMembers", RuntimeReflection::registerAllNestMembers); + registerBulkInvocationPlugin(plugins, Class.class, "getPermittedSubclasses", RuntimeReflection::registerAllPermittedSubclasses); + registerBulkInvocationPlugin(plugins, Class.class, "getRecordComponents", RuntimeReflection::registerAllRecordComponents); + registerBulkInvocationPlugin(plugins, Class.class, "getSigners", RuntimeReflection::registerAllSigners); + } + Registration r = new Registration(plugins, Class.class); r.register(new RequiredInvocationPlugin("forName", String.class) { @Override @@ -390,7 +411,7 @@ private void registerFoldInvocationPlugin(InvocationPlugins plugins, Method refl } private void registerFoldInvocationPlugin(InvocationPlugins plugins, Method reflectionMethod, Predicate allowConstantFolding) { - if (!ALLOWED_CONSTANT_CLASSES.contains(reflectionMethod.getReturnType()) && !reflectionMethod.getReturnType().isPrimitive()) { + if (!isAllowedReturnType(reflectionMethod.getReturnType())) { throw VMError.shouldNotReachHere("Return type of method " + reflectionMethod + " is not on the allow-list for types that are immutable"); } reflectionMethod.setAccessible(true); @@ -409,6 +430,10 @@ public boolean defaultHandler(GraphBuilderContext b, ResolvedJavaMethod targetMe }); } + private static boolean isAllowedReturnType(Class returnType) { + return ALLOWED_CONSTANT_CLASSES.contains(returnType) || returnType.isPrimitive(); + } + private boolean foldInvocationUsingReflection(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Method reflectionMethod, Receiver receiver, ValueNode[] args, Predicate allowConstantFolding) { assert b.getMetaAccess().lookupJavaMethod(reflectionMethod).equals(targetMethod) : "Fold method mismatch: " + reflectionMethod + " != " + targetMethod; @@ -469,6 +494,48 @@ private boolean foldInvocationUsingReflection(GraphBuilderContext b, ResolvedJav return pushConstant(b, targetMethod, targetParameters, returnKind, returnValue, false) != null; } + private void registerBulkInvocationPlugin(InvocationPlugins plugins, Class declaringClass, String methodName, Consumer registrationCallback) { + plugins.register(declaringClass, new RequiredInvocationPlugin(methodName, new Class[]{Receiver.class}) { + @Override + public boolean isDecorator() { + return true; + } + + @Override + public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver) { + VMError.guarantee(!targetMethod.isStatic(), "Bulk reflection queries are not static"); + return registerConstantBulkReflectionQuery(b, receiver, registrationCallback); + } + }); + } + + @SuppressWarnings("unchecked") + private boolean registerConstantBulkReflectionQuery(GraphBuilderContext b, Receiver receiver, Consumer registrationCallback) { + /* + * Calling receiver.get(true) can add a null check guard, i.e., modifying the graph in the + * process. It is an error for invocation plugins that do not replace the call to modify the + * graph. + */ + Object receiverValue = unbox(b, receiver.get(false), JavaKind.Object); + if (receiverValue == null || receiverValue == NULL_MARKER) { + return false; + } + + b.add(new ReachabilityRegistrationNode(() -> registerForRuntimeReflection((T) receiverValue, registrationCallback))); + return true; + } + + private void registerForRuntimeReflection(T receiver, Consumer registrationCallback) { + try { + registrationCallback.accept(receiver); + if (fallbackFeature != null) { + fallbackFeature.ignoreReflectionFallback = true; + } + } catch (LinkageError e) { + // Ignore, the call should be registered manually + } + } + private static boolean shouldInitializeAtRuntime(Class classArg) { ClassInitializationSupport classInitializationSupport = (ClassInitializationSupport) ImageSingletons.lookup(RuntimeClassInitializationSupport.class); return classInitializationSupport.shouldInitializeAtRuntime(classArg); 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 f0fad7cf0e3d..43e385d3fa83 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 @@ -148,12 +148,12 @@ import com.oracle.svm.core.jdk.proxy.DynamicProxyRegistry; import com.oracle.svm.core.meta.SharedField; import com.oracle.svm.core.meta.SharedMethod; -import com.oracle.svm.core.meta.SubstrateObjectConstant; import com.oracle.svm.core.option.HostedOptionKey; import com.oracle.svm.core.snippets.KnownIntrinsics; import com.oracle.svm.core.util.UserError; import com.oracle.svm.core.util.VMError; import com.oracle.svm.hosted.FallbackFeature; +import com.oracle.svm.hosted.ReachabilityRegistrationNode; import com.oracle.svm.hosted.meta.HostedField; import com.oracle.svm.hosted.meta.HostedMetaAccess; import com.oracle.svm.hosted.nodes.DeoptProxyNode; @@ -178,6 +178,9 @@ public class SubstrateGraphBuilderPlugins { public static class Options { @Option(help = "Enable trace logging for dynamic proxy.")// public static final HostedOptionKey DynamicProxyTracing = new HostedOptionKey<>(false); + + @Option(help = "Check reachability before automatically registering proxies observed in the code.")// + public static final HostedOptionKey StrictProxyAutoRegistration = new HostedOptionKey<>(false); } public static void registerInvocationPlugins(AnnotationSubstitutionProcessor annotationSubstitutions, @@ -190,7 +193,7 @@ public static void registerInvocationPlugins(AnnotationSubstitutionProcessor ann boolean supportsStubBasedPlugins) { // register the substratevm plugins - registerSystemPlugins(metaAccess, plugins); + registerSystemPlugins(metaAccess, snippetReflection, plugins); registerReflectionPlugins(plugins, replacements); registerImageInfoPlugins(metaAccess, plugins); registerProxyPlugins(snippetReflection, annotationSubstitutions, plugins, parsingReason); @@ -217,11 +220,17 @@ private static void registerSerializationPlugins(SnippetReflectionProvider snipp if (reason.duringAnalysis()) { Registration serializationFilter = new Registration(plugins, ObjectInputFilter.Config.class); serializationFilter.register(new RequiredInvocationPlugin("createFilter", String.class) { + @Override + public boolean isDecorator() { + return true; + } + @Override public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode patternNode) { if (nonNullJavaConstants(patternNode)) { String pattern = snippetReflection.asObject(String.class, patternNode.asJavaConstant()); - parsePatternAndRegister(pattern); + b.add(new ReachabilityRegistrationNode(() -> parsePatternAndRegister(pattern))); + return true; } return false; } @@ -229,22 +238,34 @@ public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Rec Registration customConstructor = new Registration(plugins, ReflectionFactory.class); customConstructor.register(new RequiredInvocationPlugin("newConstructorForSerialization", Receiver.class, Class.class) { + @Override + public boolean isDecorator() { + return true; + } + @Override public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode clazz) { if (nonNullJavaConstants(receiver.get(), clazz)) { - RuntimeSerialization.register(snippetReflection.asObject(Class.class, clazz.asJavaConstant())); + b.add(new ReachabilityRegistrationNode(() -> RuntimeSerialization.register(snippetReflection.asObject(Class.class, clazz.asJavaConstant())))); + return true; } return false; } }); customConstructor.register(new RequiredInvocationPlugin("newConstructorForSerialization", Receiver.class, Class.class, Constructor.class) { + @Override + public boolean isDecorator() { + return true; + } + @Override public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode clazz, ValueNode constructor) { if (nonNullJavaConstants(receiver.get(), clazz, constructor)) { var constructorDeclaringClass = snippetReflection.asObject(Constructor.class, constructor.asJavaConstant()).getDeclaringClass(); - RuntimeSerialization.registerWithTargetConstructorClass(snippetReflection.asObject(Class.class, clazz.asJavaConstant()), - constructorDeclaringClass); + b.add(new ReachabilityRegistrationNode(() -> RuntimeSerialization.registerWithTargetConstructorClass(snippetReflection.asObject(Class.class, clazz.asJavaConstant()), + constructorDeclaringClass))); + return true; } return false; } @@ -331,14 +352,14 @@ private static void parsePatternAndRegister(String pattern) { } } - private static void registerSystemPlugins(MetaAccessProvider metaAccess, InvocationPlugins plugins) { + private static void registerSystemPlugins(MetaAccessProvider metaAccess, SnippetReflectionProvider snippetReflection, InvocationPlugins plugins) { Registration r = new Registration(plugins, System.class); if (SubstrateOptions.FoldSecurityManagerGetter.getValue()) { r.register(new RequiredInvocationPlugin("getSecurityManager") { @Override public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver) { /* System.getSecurityManager() always returns null. */ - b.addPush(JavaKind.Object, ConstantNode.forConstant(SubstrateObjectConstant.forObject(null), metaAccess, b.getGraph())); + b.addPush(JavaKind.Object, ConstantNode.forConstant(snippetReflection.forObject(null), metaAccess, b.getGraph())); return true; } }); @@ -398,18 +419,26 @@ private static void registerProxyPlugins(SnippetReflectionProvider snippetReflec if (SubstrateOptions.parseOnce() || reason.duringAnalysis()) { Registration proxyRegistration = new Registration(plugins, Proxy.class); proxyRegistration.register(new RequiredInvocationPlugin("getProxyClass", ClassLoader.class, Class[].class) { + @Override + public boolean isDecorator() { + return Options.StrictProxyAutoRegistration.getValue(); + } + @Override public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode classLoaderNode, ValueNode interfacesNode) { - interceptProxyInterfaces(b, targetMethod, snippetReflection, annotationSubstitutions, interfacesNode); - return false; + return interceptProxyInterfaces(b, targetMethod, snippetReflection, annotationSubstitutions, interfacesNode); } }); proxyRegistration.register(new RequiredInvocationPlugin("newProxyInstance", ClassLoader.class, Class[].class, InvocationHandler.class) { + @Override + public boolean isDecorator() { + return Options.StrictProxyAutoRegistration.getValue(); + } + @Override public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode classLoaderNode, ValueNode interfacesNode, ValueNode invocationHandlerNode) { - interceptProxyInterfaces(b, targetMethod, snippetReflection, annotationSubstitutions, interfacesNode); - return false; + return interceptProxyInterfaces(b, targetMethod, snippetReflection, annotationSubstitutions, interfacesNode); } }); } @@ -419,25 +448,38 @@ public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Rec * Try to intercept proxy interfaces passed in as literal constants, and register the interfaces * in the {@link DynamicProxyRegistry}. */ - private static void interceptProxyInterfaces(GraphBuilderContext b, ResolvedJavaMethod targetMethod, SnippetReflectionProvider snippetReflection, + private static boolean interceptProxyInterfaces(GraphBuilderContext b, ResolvedJavaMethod targetMethod, SnippetReflectionProvider snippetReflection, AnnotationSubstitutionProcessor annotationSubstitutions, ValueNode interfacesNode) { Class[] interfaces = extractClassArray(b, snippetReflection, annotationSubstitutions, interfacesNode); if (interfaces != null) { - /* The interfaces array can be empty. The java.lang.reflect.Proxy API allows it. */ - RuntimeProxyCreation.register(interfaces); - if (ImageSingletons.contains(FallbackFeature.class)) { - ImageSingletons.lookup(FallbackFeature.class).addAutoProxyInvoke(b.getMethod(), b.bci()); - } - if (Options.DynamicProxyTracing.getValue()) { - System.out.println("Successfully determined constant value for interfaces argument of call to " + targetMethod.format("%H.%n(%p)") + - " reached from " + b.getGraph().method().format("%H.%n(%p)") + ". " + "Registered proxy class for " + Arrays.toString(interfaces) + "."); - } - } else { - if (Options.DynamicProxyTracing.getValue() && !b.parsingIntrinsic()) { - System.out.println("Could not determine constant value for interfaces argument of call to " + targetMethod.format("%H.%n(%p)") + - " reached from " + b.getGraph().method().format("%H.%n(%p)") + "."); + var caller = b.getGraph().method(); + var method = b.getMethod(); + var bci = b.bci(); + Runnable registerProxy = () -> { + /* The interfaces array can be empty. The java.lang.reflect.Proxy API allows it. */ + RuntimeProxyCreation.register(interfaces); + if (ImageSingletons.contains(FallbackFeature.class)) { + ImageSingletons.lookup(FallbackFeature.class).addAutoProxyInvoke(method, bci); + } + if (Options.DynamicProxyTracing.getValue()) { + System.out.println("Successfully determined constant value for interfaces argument of call to " + targetMethod.format("%H.%n(%p)") + + " reached from " + caller.format("%H.%n(%p)") + ". " + "Registered proxy class for " + Arrays.toString(interfaces) + "."); + } + }; + + if (Options.StrictProxyAutoRegistration.getValue()) { + b.add(new ReachabilityRegistrationNode(registerProxy)); + return true; } + + registerProxy.run(); + return false; + } + if (Options.DynamicProxyTracing.getValue() && !b.parsingIntrinsic()) { + System.out.println("Could not determine constant value for interfaces argument of call to " + targetMethod.format("%H.%n(%p)") + + " reached from " + b.getGraph().method().format("%H.%n(%p)") + "."); } + return false; } /** diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/substitute/DeletedFieldsPlugin.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/substitute/DeletedFieldsPlugin.java index 1a4dd67be3bd..831447b96bd4 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/substitute/DeletedFieldsPlugin.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/substitute/DeletedFieldsPlugin.java @@ -32,7 +32,6 @@ import org.graalvm.compiler.nodes.graphbuilderconf.NodePlugin; import com.oracle.svm.core.annotate.Delete; -import com.oracle.svm.core.meta.SubstrateObjectConstant; import jdk.vm.ci.meta.ResolvedJavaField; import jdk.vm.ci.meta.ResolvedJavaMethod; @@ -66,7 +65,7 @@ private static boolean handleField(GraphBuilderContext b, ResolvedJavaField fiel } String msg = AnnotationSubstitutionProcessor.deleteErrorMessage(field, deleteAnnotation, false); - ValueNode msgNode = ConstantNode.forConstant(SubstrateObjectConstant.forObject(msg), b.getMetaAccess(), b.getGraph()); + ValueNode msgNode = ConstantNode.forConstant(b.getConstantReflection().forString(msg), b.getMetaAccess(), b.getGraph()); ResolvedJavaMethod reportErrorMethod = b.getMetaAccess().lookupJavaMethod(DeletedMethod.reportErrorMethod); b.handleReplacedInvoke(InvokeKind.Static, reportErrorMethod, new ValueNode[]{msgNode}, false); // reportErrorMethod always throws an exception, e.g. never returns. 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 34004df326a3..4b3b7ef49775 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 @@ -37,7 +37,6 @@ import com.oracle.graal.pointsto.meta.HostedProviders; import com.oracle.svm.core.annotate.Delete; -import com.oracle.svm.core.meta.SubstrateObjectConstant; import com.oracle.svm.core.option.SubstrateOptionsParser; import com.oracle.svm.core.util.VMError; import com.oracle.svm.hosted.annotation.AnnotationValue; @@ -98,7 +97,7 @@ public static StructuredGraph buildGraph(DebugContext debug, ResolvedJavaMethod graph.start().setStateAfter(state.create(bci++, graph.start())); String msg = AnnotationSubstitutionProcessor.deleteErrorMessage(method, message, false); - ValueNode msgNode = ConstantNode.forConstant(SubstrateObjectConstant.forObject(msg), providers.getMetaAccess(), graph); + ValueNode msgNode = ConstantNode.forConstant(providers.getConstantReflection().forString(msg), providers.getMetaAccess(), graph); ValueNode exceptionNode = kit.createInvokeWithExceptionAndUnwind(providers.getMetaAccess().lookupJavaMethod(reportErrorMethod), InvokeKind.Static, state, bci++, msgNode); kit.append(new UnwindNode(exceptionNode)); diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/substitute/UnsafeAutomaticSubstitutionProcessor.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/substitute/UnsafeAutomaticSubstitutionProcessor.java index a4a9f4ea5807..edc794ad80d9 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/substitute/UnsafeAutomaticSubstitutionProcessor.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/substitute/UnsafeAutomaticSubstitutionProcessor.java @@ -73,6 +73,7 @@ import org.graalvm.compiler.phases.tiers.HighTierContext; import org.graalvm.compiler.phases.util.Providers; import org.graalvm.compiler.serviceprovider.JavaVersionUtil; +import org.graalvm.nativeimage.ImageSingletons; import com.oracle.graal.pointsto.infrastructure.SubstitutionProcessor; import com.oracle.graal.pointsto.meta.AnalysisType; @@ -87,6 +88,7 @@ import com.oracle.svm.core.jdk.RecordSupport; import com.oracle.svm.core.option.HostedOptionKey; 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; @@ -284,8 +286,9 @@ public void init(ImageClassLoader loader, MetaAccessProvider originalMetaAccess) NoClassInitializationPlugin classInitializationPlugin = new NoClassInitializationPlugin(); 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); + ParsingReason.UnsafeSubstitutionAnalysis, fallbackFeature); /* * Note: ConstantFoldLoadFieldPlugin should not be installed because it will disrupt 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 e8def23fd180..2f68e1cf0256 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 @@ -33,13 +33,13 @@ import java.util.concurrent.ConcurrentHashMap; import java.util.function.Function; +import org.graalvm.compiler.api.replacements.SnippetReflectionProvider; import org.graalvm.compiler.core.common.NumUtil; import org.graalvm.compiler.nodes.PiNode; import org.graalvm.compiler.nodes.ValueNode; import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderContext; import com.oracle.svm.core.config.ConfigurationValues; -import com.oracle.svm.core.meta.SubstrateObjectConstant; import com.oracle.svm.core.threadlocal.FastThreadLocal; import com.oracle.svm.core.threadlocal.VMThreadLocalInfo; import com.oracle.svm.core.threadlocal.VMThreadLocalInfos; @@ -78,12 +78,12 @@ public VMThreadLocalInfo getInfo(FastThreadLocal threadLocal) { return result; } - public VMThreadLocalInfo findInfo(GraphBuilderContext b, ValueNode threadLocalNode) { + public VMThreadLocalInfo findInfo(GraphBuilderContext b, SnippetReflectionProvider snippetReflection, ValueNode threadLocalNode) { if (!threadLocalNode.isConstant()) { throw shouldNotReachHere("Accessed VMThreadLocal is not a compile time constant: " + b.getMethod().asStackTraceElement(b.bci()) + " - node " + unPi(threadLocalNode)); } - FastThreadLocal threadLocal = (FastThreadLocal) SubstrateObjectConstant.asObject(threadLocalNode.asConstant()); + FastThreadLocal threadLocal = snippetReflection.asObject(FastThreadLocal.class, threadLocalNode.asJavaConstant()); VMThreadLocalInfo result = threadLocals.get(threadLocal); assert result != null; return result; diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/thread/VMThreadMTFeature.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/thread/VMThreadMTFeature.java index ece738095542..741a36ccbd2f 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 @@ -104,22 +104,22 @@ public void registerInvocationPlugins(Providers providers, SnippetReflectionProv for (Class threadLocalClass : VMThreadLocalInfo.THREAD_LOCAL_CLASSES) { Registration r = new Registration(plugins.getInvocationPlugins(), threadLocalClass); Class valueClass = VMThreadLocalInfo.getValueClass(threadLocalClass); - registerAccessors(r, valueClass, false); - registerAccessors(r, valueClass, true); + 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) { ValueNode threadNode = currentThread(b); - return handleCompareAndSet(b, targetMethod, receiver, threadNode, expect, update); + return handleCompareAndSet(b, snippetReflection, targetMethod, receiver, threadNode, 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, targetMethod, receiver, threadNode, expect, update); + return handleCompareAndSet(b, snippetReflection, targetMethod, receiver, threadNode, expect, update); } }); } @@ -132,20 +132,20 @@ public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Rec @Override public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver) { ValueNode threadNode = currentThread(b); - return handleGetAddress(b, targetMethod, receiver, threadNode); + return handleGetAddress(b, snippetReflection, targetMethod, receiver, threadNode); } }); /* 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, targetMethod, receiver, threadNode); + return handleGetAddress(b, snippetReflection, targetMethod, receiver, threadNode); } }); } } - private void registerAccessors(Registration r, Class valueClass, boolean isVolatile) { + private void registerAccessors(Registration r, SnippetReflectionProvider snippetReflection, Class valueClass, boolean isVolatile) { String suffix = isVolatile ? "Volatile" : ""; /* get() method without the VMThread parameter. */ @@ -153,14 +153,14 @@ private void registerAccessors(Registration r, Class valueClass, boolean isVo @Override public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver) { ValueNode threadNode = currentThread(b); - return handleGet(b, targetMethod, receiver, threadNode, isVolatile); + return handleGet(b, snippetReflection, targetMethod, receiver, threadNode, isVolatile); } }); /* 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, targetMethod, receiver, threadNode, isVolatile); + return handleGet(b, snippetReflection, targetMethod, receiver, threadNode, isVolatile); } }); /* set() method without the VMThread parameter. */ @@ -168,14 +168,14 @@ public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Rec @Override public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode valueNode) { ValueNode threadNode = currentThread(b); - return handleSet(b, receiver, threadNode, valueNode, isVolatile); + return handleSet(b, snippetReflection, receiver, threadNode, valueNode, isVolatile); } }); /* 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, receiver, threadNode, valueNode, isVolatile); + return handleSet(b, snippetReflection, receiver, threadNode, valueNode, isVolatile); } }); } @@ -184,8 +184,8 @@ private static ValueNode currentThread(GraphBuilderContext b) { return b.add(ReadReservedRegister.createReadIsolateThreadNode(b.getGraph())); } - private boolean handleGet(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode threadNode, boolean isVolatile) { - VMThreadLocalInfo threadLocalInfo = threadLocalCollector.findInfo(b, receiver.get()); + private boolean handleGet(GraphBuilderContext b, SnippetReflectionProvider snippetReflection, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode threadNode, boolean isVolatile) { + VMThreadLocalInfo threadLocalInfo = threadLocalCollector.findInfo(b, snippetReflection, receiver.get()); LoadVMThreadLocalNode node = new LoadVMThreadLocalNode(b.getMetaAccess(), threadLocalInfo, threadNode, BarrierType.NONE, isVolatile ? MemoryOrderMode.VOLATILE : MemoryOrderMode.PLAIN); b.addPush(targetMethod.getSignature().getReturnKind(), node); @@ -193,24 +193,25 @@ private boolean handleGet(GraphBuilderContext b, ResolvedJavaMethod targetMethod return true; } - private boolean handleSet(GraphBuilderContext b, Receiver receiver, ValueNode threadNode, ValueNode valueNode, boolean isVolatile) { - VMThreadLocalInfo threadLocalInfo = threadLocalCollector.findInfo(b, receiver.get()); + private boolean handleSet(GraphBuilderContext b, SnippetReflectionProvider snippetReflection, Receiver receiver, ValueNode threadNode, ValueNode valueNode, boolean isVolatile) { + VMThreadLocalInfo threadLocalInfo = threadLocalCollector.findInfo(b, snippetReflection, receiver.get()); StoreVMThreadLocalNode store = b.add(new StoreVMThreadLocalNode(threadLocalInfo, threadNode, valueNode, BarrierType.NONE, isVolatile ? MemoryOrderMode.VOLATILE : MemoryOrderMode.PLAIN)); assert store.stateAfter() != null : store + " has no state after with graph builder context " + b; return true; } - private boolean handleCompareAndSet(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode threadNode, ValueNode expect, ValueNode update) { - VMThreadLocalInfo threadLocalInfo = threadLocalCollector.findInfo(b, receiver.get()); + private boolean handleCompareAndSet(GraphBuilderContext b, SnippetReflectionProvider snippetReflection, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode threadNode, ValueNode expect, + ValueNode update) { + VMThreadLocalInfo threadLocalInfo = threadLocalCollector.findInfo(b, snippetReflection, receiver.get()); CompareAndSetVMThreadLocalNode cas = new CompareAndSetVMThreadLocalNode(threadLocalInfo, threadNode, 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, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode threadNode) { - VMThreadLocalInfo threadLocalInfo = threadLocalCollector.findInfo(b, receiver.get()); + private boolean handleGetAddress(GraphBuilderContext b, SnippetReflectionProvider snippetReflection, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode threadNode) { + VMThreadLocalInfo threadLocalInfo = threadLocalCollector.findInfo(b, snippetReflection, receiver.get()); b.addPush(targetMethod.getSignature().getReturnKind(), new AddressOfVMThreadLocalNode(threadLocalInfo, threadNode)); return true; } diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/thread/VMThreadSTFeature.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/thread/VMThreadSTFeature.java index e0d13b76591e..c1e324ef0964 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/thread/VMThreadSTFeature.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/thread/VMThreadSTFeature.java @@ -101,21 +101,21 @@ public void registerInvocationPlugins(Providers providers, SnippetReflectionProv Registration r = new Registration(plugins.getInvocationPlugins(), threadLocalClass); Class valueClass = VMThreadLocalInfo.getValueClass(threadLocalClass); - registerAccessors(r, valueClass, false); - registerAccessors(r, valueClass, true); + 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, targetMethod, receiver, expect, 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, targetMethod, receiver, expect, update); + return handleCompareAndSet(b, snippetReflection, targetMethod, receiver, expect, update); } }); } @@ -127,20 +127,20 @@ public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Rec r.register(new RequiredInvocationPlugin("getAddress", Receiver.class) { @Override public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver) { - return handleGetAddress(b, targetMethod, 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, targetMethod, receiver); + return handleGetAddress(b, snippetReflection, targetMethod, receiver); } }); } } - private void registerAccessors(Registration r, Class valueClass, boolean isVolatile) { + 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. @@ -151,41 +151,41 @@ private void registerAccessors(Registration r, Class valueClass, boolean isVo r.register(new RequiredInvocationPlugin("get" + suffix, Receiver.class) { @Override public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver) { - return handleGet(b, targetMethod, 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, targetMethod, receiver); + 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, receiver, 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, receiver, valueNode); + return handleSet(b, snippetReflection, receiver, valueNode); } }); } - private boolean handleGet(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver) { - VMThreadLocalInfo info = threadLocalCollector.findInfo(b, receiver.get()); + 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, Receiver receiver, ValueNode valueNode) { - VMThreadLocalInfo info = threadLocalCollector.findInfo(b, receiver.get()); + 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); @@ -193,8 +193,8 @@ private boolean handleSet(GraphBuilderContext b, Receiver receiver, ValueNode va return true; } - private boolean handleCompareAndSet(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode expect, ValueNode update) { - VMThreadLocalInfo threadLocalInfo = threadLocalCollector.findInfo(b, receiver.get()); + 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); @@ -202,8 +202,8 @@ private boolean handleCompareAndSet(GraphBuilderContext b, ResolvedJavaMethod ta return true; } - private boolean handleGetAddress(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver) { - VMThreadLocalInfo threadLocalInfo = threadLocalCollector.findInfo(b, receiver.get()); + 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; diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/util/CPUType.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/util/CPUType.java index 12938b483296..9901a92390f6 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/util/CPUType.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/util/CPUType.java @@ -29,6 +29,7 @@ import org.graalvm.nativeimage.Platform; +import com.oracle.svm.core.SubstrateUtil; import com.oracle.svm.hosted.NativeImageOptions; public interface CPUType { @@ -40,13 +41,14 @@ public interface CPUType { CPUType getParent(); static void printList() { - if (Platform.includedIn(Platform.AMD64.class)) { - print("AMD64", CPUTypeAMD64.values()); - } else if (Platform.includedIn(Platform.AARCH64.class)) { - print("AArch64", CPUTypeAArch64.values()); - CPUTypeAArch64.printFeatureModifiers(); - } else { - throw new UnsupportedOperationException(""); + String arch = SubstrateUtil.getArchitectureName(); + switch (arch) { + case "amd64" -> print("AMD64", CPUTypeAMD64.values()); + case "aarch64" -> { + print("AArch64", CPUTypeAArch64.values()); + CPUTypeAArch64.printFeatureModifiers(); + } + default -> throw new UnsupportedOperationException("Unsupported platform: " + arch); } } diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/util/VMErrorReporter.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/util/VMErrorReporter.java index bb636047be8f..53115625fe0c 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/util/VMErrorReporter.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/util/VMErrorReporter.java @@ -80,14 +80,12 @@ private static void reportStackTrace(PrintWriter pw, Throwable t) { private static void reportGraalVMSetup(PrintWriter pw) { pw.println("## GraalVM Setup"); pw.println(); - boolean isImageSingletonsInstalled = ImageSingletonsSupport.isInstalled(); - String version = isImageSingletonsInstalled && ImageSingletons.contains(VM.class) ? ImageSingletons.lookup(VM.class).version : new VM().version; - String javaVersion = System.getProperty("java.runtime.version"); pw.println("| Name | Value |"); pw.println("| ---- | ----- |"); - pw.printf("| GraalVM version | `%s` |%n", version); - pw.printf("| Java version | `%s` |%n", javaVersion); - if (isImageSingletonsInstalled && ImageSingletons.contains(CCompilerInvoker.class)) { + VM vm = VM.getErrorReportingInstance(); + pw.printf("| Java version and vendor | `%s` (%s) |%n", vm.version, vm.vendor); + pw.printf("| Runtime version | `%s` |%n", System.getProperty("java.runtime.version")); + if (ImageSingletonsSupport.isInstalled() && ImageSingletons.contains(CCompilerInvoker.class)) { pw.printf("| C compiler | `%s` |%n", ImageSingletons.lookup(CCompilerInvoker.class).compilerInfo.getShortDescription()); } 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 08127b9c890a..ccad45416b93 100644 --- a/substratevm/src/com.oracle.svm.native.libchelper/src/cpuid.c +++ b/substratevm/src/com.oracle.svm.native.libchelper/src/cpuid.c @@ -606,7 +606,7 @@ void determineCPUFeatures(CPUFeatures *features) #elif defined(__aarch64__) /* - * The corresponding HotSpot code can be found in vm_version_bsd_aarch64. + * The corresponding HotSpot code can be found in vm_version_bsd_aarch64.cpp (218223e4a31d485935655cb3f186a752defd8fa8). */ #if defined(__APPLE__) @@ -623,29 +623,31 @@ static uint32_t cpu_has(const char* optional) { } void determineCPUFeatures(CPUFeatures* features) { - /* - * Note that Apple HW detection code is not accurate on older processors. - * All Apple devices have FP and ASIMD. - */ + // All Apple devices have FP and ASIMD. features->fFP = 1; features->fASIMD = 1; - features->fEVTSTRM = 0; - features->fAES = 0; - features->fPMULL = 0; - features->fSHA1 = 0; - features->fSHA2 = 0; - features->fCRC32 = !!(cpu_has("hw.optional.armv8_crc32")); - features->fLSE = !!(cpu_has("hw.optional.armv8_1_atomics")); + // All Apple-darwin Arm processors have AES, PMULL, SHA1, and SHA2. + // For backward compatibility, do not check these CPU features as the + // corresponding string names are not available before xnu-8019. + features->fAES = 1; + features->fPMULL = 1; + features->fSHA1 = 1; + features->fSHA2 = 1; + // Checked in the Hotspot code. + features->fCRC32 = !!(cpu_has("hw.optional.armv8_crc32")); + features->fLSE = !!(cpu_has("hw.optional.arm.FEAT_LSE")) | !!(cpu_has("hw.optional.armv8_1_atomics")); + features->fSHA512 = !!(cpu_has("hw.optional.arm.FEAT_SHA512")) | !!(cpu_has("hw.optional.armv8_2_sha512")); + features->fSHA3 = !!(cpu_has("hw.optional.arm.FEAT_SHA3")) | !!(cpu_has("hw.optional.armv8_2_sha3")); + // Not (yet) checked in the Hotspot code. features->fDCPOP = 0; - features->fSHA3 = 0; - features->fSHA512 = 0; features->fSVE = 0; + features->fSVEBITPERM = 0; features->fSVE2 = 0; + features->fEVTSTRM = 0; features->fSTXR_PREFETCH = 0; features->fA53MAC = 0; features->fDMB_ATOMICS = 0; features->fPACA = 0; - features->fSVEBITPERM = 0; } /* diff --git a/substratevm/src/com.oracle.svm.test/src/com/oracle/svm/test/jfr/TestObjectAllocationInNewTLABEvent.java b/substratevm/src/com.oracle.svm.test/src/com/oracle/svm/test/jfr/TestObjectAllocationInNewTLABEvent.java index 7d5d69ab8705..85a0a2224c4d 100644 --- a/substratevm/src/com.oracle.svm.test/src/com/oracle/svm/test/jfr/TestObjectAllocationInNewTLABEvent.java +++ b/substratevm/src/com.oracle.svm.test/src/com/oracle/svm/test/jfr/TestObjectAllocationInNewTLABEvent.java @@ -33,7 +33,9 @@ import org.junit.Test; import com.oracle.svm.core.NeverInline; +import com.oracle.svm.core.genscavenge.HeapParameters; import com.oracle.svm.core.jfr.JfrEvent; +import com.oracle.svm.core.util.UnsignedUtils; import jdk.jfr.consumer.RecordedClass; import jdk.jfr.consumer.RecordedEvent; @@ -41,7 +43,6 @@ public class TestObjectAllocationInNewTLABEvent extends JfrRecordingTest { private static final int K = 1024; - private static final int DEFAULT_ALIGNED_HEAP_CHUNK_SIZE = 1024 * K; @Override public String[] getTestedEvents() { @@ -50,6 +51,8 @@ public String[] getTestedEvents() { @Override protected void validateEvents(List events) throws Throwable { + final int alignedHeapChunkSize = UnsignedUtils.safeToInt(HeapParameters.getAlignedHeapChunkSize()); + boolean foundBigByteArray = false; boolean foundSmallByteArray = false; boolean foundBigCharArray = false; @@ -66,16 +69,16 @@ protected void validateEvents(List events) throws Throwable { String className = event. getValue("objectClass").getName(); // >= To account for size of reference - if (allocationSize >= 2 * DEFAULT_ALIGNED_HEAP_CHUNK_SIZE && tlabSize >= 2 * DEFAULT_ALIGNED_HEAP_CHUNK_SIZE) { + if (allocationSize >= 2 * alignedHeapChunkSize && tlabSize >= 2 * alignedHeapChunkSize) { // verify previous owner if (className.equals(char[].class.getName())) { foundBigCharArray = true; } else if (className.equals(byte[].class.getName())) { foundBigByteArray = true; } - } else if (allocationSize >= K && tlabSize == DEFAULT_ALIGNED_HEAP_CHUNK_SIZE && className.equals(byte[].class.getName())) { + } else if (allocationSize >= K && tlabSize == alignedHeapChunkSize && className.equals(byte[].class.getName())) { foundSmallByteArray = true; - } else if (tlabSize == DEFAULT_ALIGNED_HEAP_CHUNK_SIZE && className.equals(Helper.class.getName())) { + } else if (tlabSize == alignedHeapChunkSize && className.equals(Helper.class.getName())) { foundInstance = true; } } @@ -88,17 +91,19 @@ protected void validateEvents(List events) throws Throwable { @Test public void test() throws Exception { + final int alignedHeapChunkSize = UnsignedUtils.safeToInt(HeapParameters.getAlignedHeapChunkSize()); + // Allocate large arrays (always need a new TLAB). - allocateByteArray(2 * DEFAULT_ALIGNED_HEAP_CHUNK_SIZE); - allocateCharArray(DEFAULT_ALIGNED_HEAP_CHUNK_SIZE); + allocateByteArray(2 * alignedHeapChunkSize); + allocateCharArray(alignedHeapChunkSize); // Exhaust TLAB with small arrays. - for (int i = 0; i < DEFAULT_ALIGNED_HEAP_CHUNK_SIZE / K; i++) { + for (int i = 0; i < alignedHeapChunkSize / K; i++) { allocateByteArray(K); } // Exhaust TLAB with instances. - for (int i = 0; i < DEFAULT_ALIGNED_HEAP_CHUNK_SIZE; i++) { + for (int i = 0; i < alignedHeapChunkSize; i++) { allocateInstance(); } } 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 25e3d117688b..c4e54bc17b17 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 @@ -1349,7 +1349,7 @@ public Object transform(Object receiver, Object originalValue) { } } -@TargetClass(className = "com.oracle.truffle.api.dsl.InlineSupport$UnsafeField", onlyWith = TruffleFeature.IsEnabled.class) +@TargetClass(className = "com.oracle.truffle.api.dsl.InlineSupport$UnsafeField", onlyWith = TruffleBaseFeature.IsEnabled.class) final class Target_com_oracle_truffle_api_dsl_InlineSupport_UnsafeField { @Alias @RecomputeFieldValue(kind = Kind.Custom, declClass = OffsetComputer.class, isFinal = true) // diff --git a/substratevm/src/com.oracle.svm.truffle/src/com/oracle/svm/truffle/api/SubstrateOptimizedCallTargetInstalledCode.java b/substratevm/src/com.oracle.svm.truffle/src/com/oracle/svm/truffle/api/SubstrateOptimizedCallTargetInstalledCode.java index 19e4fb37d23e..9eeced969ea2 100644 --- a/substratevm/src/com.oracle.svm.truffle/src/com/oracle/svm/truffle/api/SubstrateOptimizedCallTargetInstalledCode.java +++ b/substratevm/src/com.oracle.svm.truffle/src/com/oracle/svm/truffle/api/SubstrateOptimizedCallTargetInstalledCode.java @@ -133,10 +133,10 @@ public ResolvedJavaMethod getMethod() { } @Override - public void setAddress(long address, ResolvedJavaMethod method) { + public void setAddress(long address, long entryPoint, ResolvedJavaMethod method) { assert VMOperation.isInProgressAtSafepoint(); - this.entryPoint = address; this.address = address; + this.entryPoint = entryPoint; callTarget.onCodeInstalled(this); } diff --git a/sulong/mx.sulong/suite.py b/sulong/mx.sulong/suite.py index 5d59e9c8035c..0ce2e4ca7f0c 100644 --- a/sulong/mx.sulong/suite.py +++ b/sulong/mx.sulong/suite.py @@ -8,9 +8,6 @@ { "name" : "truffle", "subdir" : True, - "urls" : [ - {"url" : "https://curio.ssw.jku.at/nexus/content/repositories/snapshots", "kind" : "binary"}, - ] }, ], }, @@ -899,6 +896,7 @@ "ninja_install_targets" : ["install-cxxabi"], "results" : ["native"], "cmakeConfig" : { + "CMAKE_INSTALL_RPATH" : "\\$ORIGIN", "LLVM_ENABLE_RUNTIMES" : "libcxx;libcxxabi", }, }, @@ -907,6 +905,7 @@ "ninja_install_targets" : ["install-cxxabi"], "results" : ["native"], "cmakeConfig" : { + "CMAKE_INSTALL_RPATH" : "\\$ORIGIN", "LLVM_ENABLE_RUNTIMES" : "libcxx;libcxxabi", "LIBCXX_HAS_MUSL_LIBC" : "YES", }, @@ -916,7 +915,7 @@ "ninja_install_targets" : ["install-cxxabi"], "results" : ["native"], "cmakeConfig" : { - "CMAKE_INSTALL_RPATH" : "\\$ORIGIN", + "CMAKE_INSTALL_RPATH" : "@loader_path/", "LLVM_ENABLE_RUNTIMES" : "libcxx;libcxxabi", "CMAKE_LIBTOOL" : "/bin/llvm-libtool-darwin", }, diff --git a/sulong/projects/com.oracle.truffle.llvm.runtime/src/com/oracle/truffle/llvm/runtime/memory/LLVMStack.java b/sulong/projects/com.oracle.truffle.llvm.runtime/src/com/oracle/truffle/llvm/runtime/memory/LLVMStack.java index 582798bc2ef8..4551c5da1824 100644 --- a/sulong/projects/com.oracle.truffle.llvm.runtime/src/com/oracle/truffle/llvm/runtime/memory/LLVMStack.java +++ b/sulong/projects/com.oracle.truffle.llvm.runtime/src/com/oracle/truffle/llvm/runtime/memory/LLVMStack.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2022, Oracle and/or its affiliates. + * Copyright (c) 2016, 2023, Oracle and/or its affiliates. * * All rights reserved. * @@ -238,13 +238,24 @@ public void prepareForAOT(TruffleLanguage language, RootNode root) { noBasePointerAssumption.invalidate(); } - protected void ensureBasePointerSlot(LLVMStack llvmStack) { - // whenever we access the base pointer, we ensure that the stack was allocated + protected void ensureStackAllocated(LLVMStack llvmStack) { if (!llvmStack.isAllocated()) { + /* + * Setting hasAllocatedStack to true means we include a check in the method prologue + * that allocates the stack eagerly. That means we can keep the deopt here. It will + * not lead to a deopt loop except possibly as a race condition. That is, in the + * worst case, we deopt once for every thread that's currently in this method if + * they all enter this branch concurrently. + */ CompilerDirectives.transferToInterpreterAndInvalidate(); hasAllocatedStack = true; llvmStack.allocate(this, memory); } + } + + protected void ensureBasePointerSlot(LLVMStack llvmStack) { + // whenever we access the base pointer, we ensure that the stack was allocated + ensureStackAllocated(llvmStack); if (noBasePointerAssumption.isValid()) { CompilerDirectives.transferToInterpreterAndInvalidate(); noBasePointerAssumption.invalidate(); @@ -262,10 +273,9 @@ public void executeEnter(VirtualFrame frame, LLVMStack llvmStack) { if (hasAllocatedStack && !llvmStack.isAllocated()) { /* * If we've ever seen a stack being allocated in this method, then we do an explicit - * check on entry. This way, all other checks can remain - * transferToInterpreterAndInvalidate. + * check on entry, and allocate the stack behind a TruffleBoundary. This way, all + * other checks can remain deopts without creating a deopt loop. */ - CompilerDirectives.transferToInterpreter(); llvmStack.allocate(this, memory); } if (noBasePointerAssumption.isValid()) { @@ -304,11 +314,7 @@ public void executeExit(VirtualFrame frame) { private LLVMStack getStack(VirtualFrame frame) { try { LLVMStack llvmStack = (LLVMStack) frame.getObject(STACK_ID); - if (!llvmStack.isAllocated()) { - CompilerDirectives.transferToInterpreterAndInvalidate(); - hasAllocatedStack = true; - llvmStack.allocate(this, memory); - } + ensureStackAllocated(llvmStack); return llvmStack; } catch (FrameSlotTypeException e) { throw new LLVMMemoryException(this, e); diff --git a/tools/mx.tools/suite.py b/tools/mx.tools/suite.py index 0540f18b01b3..584b8ba617a8 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" : "23.0.0", + "version" : "23.1.0", "release" : False, "url" : "http://openjdk.java.net/projects/graal", "developer" : { @@ -46,9 +46,6 @@ { "name" : "truffle", "subdir" : True, - "urls" : [ - {"url" : "https://curio.ssw.jku.at/nexus/content/repositories/snapshots", "kind" : "binary"}, - ] }, ] }, diff --git a/truffle/CHANGELOG.md b/truffle/CHANGELOG.md index e95005150de3..ff126692972e 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. +## 23.1.0 + +* GR-45123 Added `GenerateInline#inlineByDefault` to force usage of inlined node variant even when the node has also a cached variant (`@GenerateCached(true)`). ## Version 23.0.0 @@ -61,6 +64,7 @@ This changelog summarizes major changes between Truffle versions relevant to lan * GR-44053 (change of behavior) The default implementation of `InteropLibrary.getExceptionStackTrace()` will now include host stack trace elements if [public host access is allowed](https://www.graalvm.org/sdk/javadoc/org/graalvm/polyglot/HostAccess.Builder.html#allowPublicAccess-boolean-). * GR-44053 (change of behavior) Truffle stack trace information is now attached to host and internal exceptions via suppressed exceptions. The cause of an exception is never modified anymore. * GR-44053 (change of behavior) A `StackOverflowError` or `OutOfMemoryError` crossing a Truffle call boundary will not be injected guest stack trace information anymore. +* GR-44723 `Truffle.getRuntime().getName()` and consequently `Engine.getImplementationName()` have been adjusted to return "Oracle GraalVM" instead of "GraalVM EE". ## Version 22.3.0 diff --git a/truffle/external_repos/simplelanguage/pom.xml b/truffle/external_repos/simplelanguage/pom.xml index d0be7c78b777..38524e2509ba 100644 --- a/truffle/external_repos/simplelanguage/pom.xml +++ b/truffle/external_repos/simplelanguage/pom.xml @@ -48,7 +48,7 @@ UTF-8 jdt_apt - 23.0.0-dev + 23.1.0-dev 11 11 diff --git a/truffle/external_repos/simplelanguage/sl b/truffle/external_repos/simplelanguage/sl index 4fd2369748b5..821e709844fd 100755 --- a/truffle/external_repos/simplelanguage/sl +++ b/truffle/external_repos/simplelanguage/sl @@ -41,7 +41,7 @@ # # If you update this number make sure the graalvm.version value in ./pom.xml matches -VERSION="23.0.0-dev" +VERSION="23.1.0-dev" MAIN_CLASS="com.oracle.truffle.sl.launcher.SLMain" SCRIPT_HOME="$(cd "$(dirname "$0")" && pwd -P)" diff --git a/truffle/external_repos/simpletool/pom.xml b/truffle/external_repos/simpletool/pom.xml index 08ccece2b76a..fba587f8f8eb 100644 --- a/truffle/external_repos/simpletool/pom.xml +++ b/truffle/external_repos/simpletool/pom.xml @@ -49,7 +49,7 @@ UTF-8 1.8 1.8 - 23.0.0-dev + 23.1.0-dev diff --git a/truffle/mx.truffle/suite.py b/truffle/mx.truffle/suite.py index 9a105dec696e..f9b3886ac81c 100644 --- a/truffle/mx.truffle/suite.py +++ b/truffle/mx.truffle/suite.py @@ -41,7 +41,7 @@ suite = { "mxversion": "6.17.0", "name" : "truffle", - "version" : "23.0.0", + "version" : "23.1.0", "release" : False, "groupId" : "org.graalvm.truffle", "sourceinprojectwhitelist" : [], @@ -63,9 +63,6 @@ { "name" : "sdk", "subdir": True, - "urls" : [ - {"url" : "https://curio.ssw.jku.at/nexus/content/repositories/snapshots", "kind" : "binary"}, - ] }, ] }, @@ -1015,7 +1012,7 @@ ], "exports" : [ # Qualified exports - "com.oracle.truffle.api* to jdk.internal.vm.compiler, jdk.internal.vm.compiler.truffle.jfr, com.oracle.graal.graal_enterprise, org.graalvm.nativeimage.builder", + "com.oracle.truffle.api* to jdk.internal.vm.compiler, jdk.internal.vm.compiler.truffle.jfr, com.oracle.graal.graal_enterprise, com.oracle.svm.svm_enterprise, org.graalvm.nativeimage.builder", "com.oracle.truffle.api.impl to org.graalvm.locator", "com.oracle.truffle.api to org.graalvm.locator, org.graalvm.nativeimage.builder", "com.oracle.truffle.object to jdk.internal.vm.compiler, com.oracle.graal.graal_enterprise", diff --git a/truffle/src/com.oracle.truffle.api.dsl.test/src/com/oracle/truffle/api/dsl/test/GenerateInlineTest.java b/truffle/src/com.oracle.truffle.api.dsl.test/src/com/oracle/truffle/api/dsl/test/GenerateInlineTest.java index 2d47ab84c880..bc401ac866b5 100644 --- a/truffle/src/com.oracle.truffle.api.dsl.test/src/com/oracle/truffle/api/dsl/test/GenerateInlineTest.java +++ b/truffle/src/com.oracle.truffle.api.dsl.test/src/com/oracle/truffle/api/dsl/test/GenerateInlineTest.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. * * The Universal Permissive License (UPL), Version 1.0 @@ -81,6 +81,7 @@ import com.oracle.truffle.api.dsl.test.GenerateInlineTestFactory.ErrorRuntimeUsageNodeGen; import com.oracle.truffle.api.dsl.test.GenerateInlineTestFactory.InlineReplaceNodeGen; import com.oracle.truffle.api.dsl.test.GenerateInlineTestFactory.InlineRewriteOnNodeGen; +import com.oracle.truffle.api.dsl.test.GenerateInlineTestFactory.InlinedByDefaultCachedNodeGen; import com.oracle.truffle.api.dsl.test.GenerateInlineTestFactory.InlinedUsageNodeGen; import com.oracle.truffle.api.dsl.test.GenerateInlineTestFactory.MultiInstanceInlineWithGenericNodeGen; import com.oracle.truffle.api.dsl.test.GenerateInlineTestFactory.MultiInstanceInliningNodeGen; @@ -101,9 +102,17 @@ import com.oracle.truffle.api.dsl.test.GenerateInlineTestFactory.UseCustomInlineNodeGen; import com.oracle.truffle.api.dsl.test.GenerateInlineTestFactory.UseDoNotInlineInlinableNodeNodeGen; import com.oracle.truffle.api.dsl.test.GenerateInlineTestFactory.UseFailEarlyNodeGen; +import com.oracle.truffle.api.dsl.test.GenerateInlineTestFactory.UseInheritedInlinedByDefaultInCachedNodeGen; import com.oracle.truffle.api.dsl.test.GenerateInlineTestFactory.UseInlineInlineCacheNodeGen; import com.oracle.truffle.api.dsl.test.GenerateInlineTestFactory.UseInlineSharedWithSpecializationClassNodeGen; import com.oracle.truffle.api.dsl.test.GenerateInlineTestFactory.UseInlinedAdoptNodeGen; +import com.oracle.truffle.api.dsl.test.GenerateInlineTestFactory.UseInlinedByDefaultAndForceCachedVersionNodeGen; +import com.oracle.truffle.api.dsl.test.GenerateInlineTestFactory.UseInlinedByDefaultAndForceInlineVersionNodeGen; +import com.oracle.truffle.api.dsl.test.GenerateInlineTestFactory.UseInlinedByDefaultInCachedNodeGen; +import com.oracle.truffle.api.dsl.test.GenerateInlineTestFactory.UseInlinedByDefaultInCachedWithAlwaysInlineCachedAndGenerateInlineNodeGen; +import com.oracle.truffle.api.dsl.test.GenerateInlineTestFactory.UseInlinedByDefaultInCachedWithAlwaysInlineCachedAndGenerateInlineUserNodeGen; +import com.oracle.truffle.api.dsl.test.GenerateInlineTestFactory.UseInlinedByDefaultInCachedWithAlwaysInlineCachedNodeGen; +import com.oracle.truffle.api.dsl.test.GenerateInlineTestFactory.UseInlinedByDefaultInInlineOnlyUserNodeGen; import com.oracle.truffle.api.dsl.test.GenerateInlineTestFactory.UseInlinedNodeInGuardNodeGen; import com.oracle.truffle.api.dsl.test.GenerateInlineTestFactory.UseIntrospectionNodeGen; import com.oracle.truffle.api.dsl.test.GenerateInlineTestFactory.UseMixedAndInlinedNodeGen; @@ -2467,4 +2476,166 @@ static String s0(Node node, int value, } + @GenerateCached(inherit = true) + @GenerateInline(inlineByDefault = true, inherit = true) + public abstract static class InlinedByDefaultCachedNode extends Node { + abstract String execute(Node n, Object arg); + + @Specialization + String doInt(@SuppressWarnings("unused") int i) { + return "int"; + } + + @Specialization + String doDouble(@SuppressWarnings("unused") double i) { + return "double"; + } + } + + public abstract static class UseInlinedByDefaultInlineUser extends UseInlinedByDefaultUser { + abstract String execute(Node inliningTarget, Object arg, boolean useCorrectNode); + + @Override + final String execute(Object arg, boolean useCorrectNode) { + // Shortcut for when the node is not inlined, but invalid operation if the node is + // inlined! + return execute(null, arg, useCorrectNode); + } + } + + public abstract static class UseInlinedByDefaultUser extends Node { + abstract String execute(Object arg, boolean useCorrectNode); + } + + @GenerateCached + @GenerateInline(false) + public abstract static class UseInlinedByDefaultInCached extends UseInlinedByDefaultUser { + @Specialization + String doInt(Object arg, boolean useCorrectNode, + @Cached InlinedByDefaultCachedNode node) { + return node.execute(useCorrectNode ? this : node, arg); + } + } + + @GenerateCached(alwaysInlineCached = true) + @GenerateInline(false) + public abstract static class UseInlinedByDefaultInCachedWithAlwaysInlineCached extends UseInlinedByDefaultUser { + @Specialization + String doInt(Object arg, boolean useCorrectNode, + @Cached InlinedByDefaultCachedNode node) { + return node.execute(useCorrectNode ? this : node, arg); + } + } + + @GenerateInline + @GenerateCached(alwaysInlineCached = true) + public abstract static class UseInlinedByDefaultInCachedWithAlwaysInlineCachedAndGenerateInline extends UseInlinedByDefaultInlineUser { + @Specialization + static String doInt(Node inlineTarget, Object arg, boolean useCorrectNode, + @Cached InlinedByDefaultCachedNode node) { + return node.execute(useCorrectNode ? inlineTarget : node, arg); + } + } + + @GenerateInline(false) + public abstract static class UseInlinedByDefaultInCachedWithAlwaysInlineCachedAndGenerateInlineUser extends UseInlinedByDefaultUser { + @Specialization + String doInt(Object arg, boolean useCorrectNode, + @Cached(inline = true) UseInlinedByDefaultInCachedWithAlwaysInlineCachedAndGenerateInline node) { + return node.execute(this, arg, useCorrectNode); + } + } + + @GenerateInline + @GenerateCached(false) + public abstract static class UseInlinedByDefaultInInlineOnly extends UseInlinedByDefaultInlineUser { + @Specialization + static String doInt(Node inlineTarget, Object arg, boolean useCorrectNode, + @Cached InlinedByDefaultCachedNode node) { + return node.execute(useCorrectNode ? inlineTarget : node, arg); + } + } + + @GenerateInline(false) + public abstract static class UseInlinedByDefaultInInlineOnlyUser extends UseInlinedByDefaultUser { + @Specialization + String doInt(Object arg, boolean useCorrectNode, + @Cached UseInlinedByDefaultInInlineOnly node) { + return node.execute(this, arg, useCorrectNode); + } + } + + @GenerateInline(false) + public abstract static class UseInlinedByDefaultAndForceInlineVersion extends UseInlinedByDefaultUser { + @Specialization + String doInt(Object arg, boolean useCorrectNode, + @SuppressWarnings("truffle-unused") // forcing inline is redundant + @Cached(inline = true) InlinedByDefaultCachedNode node) { + return node.execute(useCorrectNode ? this : node, arg); + } + } + + @GenerateInline(false) + public abstract static class UseInlinedByDefaultAndForceCachedVersion extends Node { + abstract String execute(Object arg); + + @Specialization + String doInt(Object arg, + @Cached(inline = false) InlinedByDefaultCachedNode node) { + // If 'node' were wrongly inlined, this would have to fail, + // because it does not get any inlining target argument + return node.execute(null, arg); + } + } + + public abstract static class InheritedInlinedByDefaultCachedNode extends InlinedByDefaultCachedNode { + @Specialization + String doString(@SuppressWarnings("unused") String s) { + return "string"; + } + } + + @GenerateCached + @GenerateInline(false) + public abstract static class UseInheritedInlinedByDefaultInCached extends UseInlinedByDefaultUser { + @Specialization + String doInt(Object arg, boolean useCorrectNode, + @Cached InheritedInlinedByDefaultCachedNode node) { + return node.execute(useCorrectNode ? this : node, arg); + } + } + + @Test + public void testInlineByDefaultInCached() { + testInlineByDefaultCachedUser(UseInlinedByDefaultInCachedNodeGen.create()); + testInlineByDefaultCachedUser(UseInlinedByDefaultInCachedWithAlwaysInlineCachedNodeGen.create()); + testInlineByDefaultCachedUser(UseInlinedByDefaultInCachedWithAlwaysInlineCachedAndGenerateInlineNodeGen.create()); + testInlineByDefaultCachedUser(UseInlinedByDefaultAndForceInlineVersionNodeGen.create()); + testInlineByDefaultCachedUser(UseInheritedInlinedByDefaultInCachedNodeGen.create()); + // inline users are tested through another cached entry point: + testInlineByDefaultCachedUser(UseInlinedByDefaultInCachedWithAlwaysInlineCachedAndGenerateInlineUserNodeGen.create()); + testInlineByDefaultCachedUser(UseInlinedByDefaultInInlineOnlyUserNodeGen.create()); + + var forceCached = UseInlinedByDefaultAndForceCachedVersionNodeGen.create(); + assertEquals("int", forceCached.execute(42)); + assertEquals("double", forceCached.execute(3.14)); + + var manuallyCreatedCachedVersion = InlinedByDefaultCachedNodeGen.create(); + assertEquals("int", manuallyCreatedCachedVersion.execute(null, 42)); + assertEquals("double", manuallyCreatedCachedVersion.execute(null, 3.14)); + } + + private static void testInlineByDefaultCachedUser(UseInlinedByDefaultUser userNode) { + String testCaseName = userNode.getClass().getSimpleName(); + assertEquals(testCaseName, "int", userNode.execute(42, true)); + assertEquals(testCaseName, "double", userNode.execute(3.14, true)); + boolean thrown = false; + try { + userNode.execute(1, false); + } catch (ClassCastException e) { + assertTrue(e.getMessage(), e.getMessage().contains("Invalid parameter type passed to updater")); + thrown = true; + } + assertTrue(String.format("Node %s did not throw when it used wrong inlineTarget. Is the UseInlinedByDefault really inlined?", testCaseName), thrown); + } } diff --git a/truffle/src/com.oracle.truffle.api.dsl/snapshot.sigtest b/truffle/src/com.oracle.truffle.api.dsl/snapshot.sigtest index ca6188cea744..008c5276ed8f 100644 --- a/truffle/src/com.oracle.truffle.api.dsl/snapshot.sigtest +++ b/truffle/src/com.oracle.truffle.api.dsl/snapshot.sigtest @@ -103,6 +103,7 @@ CLSS public abstract interface !annotation com.oracle.truffle.api.dsl.GenerateIn anno 0 java.lang.annotation.Target(java.lang.annotation.ElementType[] value=[TYPE]) intf java.lang.annotation.Annotation meth public abstract !hasdefault boolean inherit() +meth public abstract !hasdefault boolean inlineByDefault() meth public abstract !hasdefault boolean value() CLSS public abstract interface !annotation com.oracle.truffle.api.dsl.GenerateNodeFactory diff --git a/truffle/src/com.oracle.truffle.api.dsl/src/com/oracle/truffle/api/dsl/GenerateInline.java b/truffle/src/com.oracle.truffle.api.dsl/src/com/oracle/truffle/api/dsl/GenerateInline.java index ad8c1dfc9cb5..c15312cd16a5 100644 --- a/truffle/src/com.oracle.truffle.api.dsl/src/com/oracle/truffle/api/dsl/GenerateInline.java +++ b/truffle/src/com.oracle.truffle.api.dsl/src/com/oracle/truffle/api/dsl/GenerateInline.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2018, 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. * * The Universal Permissive License (UPL), Version 1.0 @@ -86,11 +86,23 @@ boolean value() default true; /** - * If true enables inheritance of {@link #value()} to subclasses. It is - * false by default. + * If true enables inheritance of {@link #value()} and {@link #inlineByDefault()} + * to subclasses. It is false by default. * * @since 23.0 */ boolean inherit() default false; + /** + * If true the inlined version is used by default when the node is used as a + * {@link Cached cached} argument. + * + * Changing this value on an existing node class with existing and already compiled usages will + * not force the recompilation of the usages. One has to manually force recompilation of all the + * affected code. If the node class is part of supported public API, changing this value is a + * source incompatible change! + * + * @since 23.0 + */ + boolean inlineByDefault() default false; } diff --git a/truffle/src/com.oracle.truffle.api.strings/snapshot.sigtest b/truffle/src/com.oracle.truffle.api.strings/snapshot.sigtest index 318c5427a454..2d4f08eddfb7 100644 --- a/truffle/src/com.oracle.truffle.api.strings/snapshot.sigtest +++ b/truffle/src/com.oracle.truffle.api.strings/snapshot.sigtest @@ -14,6 +14,7 @@ CLSS public abstract interface !annotation com.oracle.truffle.api.dsl.GenerateIn anno 0 java.lang.annotation.Target(java.lang.annotation.ElementType[] value=[TYPE]) intf java.lang.annotation.Annotation meth public abstract !hasdefault boolean inherit() +meth public abstract !hasdefault boolean inlineByDefault() meth public abstract !hasdefault boolean value() CLSS public abstract interface !annotation com.oracle.truffle.api.dsl.GeneratePackagePrivate diff --git a/truffle/src/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/polyglot/EngineAPITest.java b/truffle/src/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/polyglot/EngineAPITest.java index 42cd64550ec0..46141a35509f 100644 --- a/truffle/src/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/polyglot/EngineAPITest.java +++ b/truffle/src/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/polyglot/EngineAPITest.java @@ -300,7 +300,7 @@ public void testEngineName() { if (name.equals("DefaultCallTarget")) { assertEquals(implName, "Interpreted"); } else if (name.endsWith("OptimizedCallTarget")) { - assertTrue(implName, implName.equals("GraalVM EE" + suffix) || implName.equals("GraalVM CE")); + assertTrue(implName, implName.equals("Oracle GraalVM" + suffix) || implName.equals("GraalVM CE")); } } diff --git a/truffle/src/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/polyglot/ValueHostConversionTest.java b/truffle/src/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/polyglot/ValueHostConversionTest.java index 589a26b2f4da..df2d0b5fff3a 100644 --- a/truffle/src/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/polyglot/ValueHostConversionTest.java +++ b/truffle/src/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/polyglot/ValueHostConversionTest.java @@ -76,7 +76,6 @@ import org.graalvm.polyglot.Value; import org.graalvm.polyglot.proxy.Proxy; import org.junit.Assert; -import org.junit.Assume; import org.junit.Before; import org.junit.Test; @@ -1319,7 +1318,6 @@ public static class TestExceptionFramesCallerSensitive { // Methods annotated with @CallerSensitive use reflection, even on JVM, so we test that case. @Test public void testExceptionFramesCallerSensitive() throws NoSuchFieldException { - Assume.assumeTrue("GR-40767", Runtime.version().feature() < 19); // We cannot easily mark a method as @CallerSensitive (the annotation moved between JDK 8 // and 9), so we use an existing method marked as @CallerSensitive, Field#get(). Field field = TestExceptionFramesCallerSensitive.class.getField("testField"); @@ -1339,6 +1337,11 @@ public void testExceptionFramesCallerSensitive() throws NoSuchFieldException { assertTrue(frame.isHostFrame()); assertEquals("get", frame.toHostFrame().getMethodName()); frame = frameIterator.next(); + if (Runtime.version().feature() >= 19 && frame.toHostFrame().getMethodName().startsWith("invoke")) { + // Skip DirectMethodHandleAccessor.invoke used by Method.invoke on JDK 19+ + frame = frameIterator.next(); + assertTrue(frame.isHostFrame()); + } assertTrue(frame.isHostFrame()); assertEquals("execute", frame.toHostFrame().getMethodName()); frame = frameIterator.next(); diff --git a/truffle/src/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/parser/NodeParser.java b/truffle/src/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/parser/NodeParser.java index 6ad4ebf27601..a168f3aa4def 100644 --- a/truffle/src/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/parser/NodeParser.java +++ b/truffle/src/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/parser/NodeParser.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2021, 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 @@ -3886,7 +3886,7 @@ private List parseInlineMethod(MessageContainer errorContainer, * on. This enables that @Cached InlinedBranchProfile inlines by default even if a cached * version is generated and no warning is printed. */ - private static boolean forceInlineByDefault(CacheExpression cache) { + private boolean forceInlineByDefault(CacheExpression cache) { AnnotationMirror cacheAnnotation = cache.getMessageAnnotation(); TypeElement parameterType = ElementUtils.castTypeElement(cache.getParameter().getType()); if (parameterType == null) { @@ -3896,6 +3896,13 @@ private static boolean forceInlineByDefault(CacheExpression cache) { if (defaultCached && !hasDefaultCreateCacheMethod(parameterType.asType())) { return hasInlineMethod(cache); } + if (ElementUtils.isAssignable(parameterType.asType(), types.Node)) { + AnnotationMirror inlineAnnotation = getGenerateInlineAnnotation(parameterType); + if (inlineAnnotation != null) { + return getAnnotationValue(Boolean.class, inlineAnnotation, "value") && + getAnnotationValue(Boolean.class, inlineAnnotation, "inlineByDefault"); + } + } return false; } diff --git a/truffle/src/com.oracle.truffle.host/src/com/oracle/truffle/host/HostMethodDesc.java b/truffle/src/com.oracle.truffle.host/src/com/oracle/truffle/host/HostMethodDesc.java index 10753aa97d8f..9c18dc4c75a3 100644 --- a/truffle/src/com.oracle.truffle.host/src/com/oracle/truffle/host/HostMethodDesc.java +++ b/truffle/src/com.oracle.truffle.host/src/com/oracle/truffle/host/HostMethodDesc.java @@ -259,6 +259,15 @@ public Object invokeGuestToHost(Object receiver, Object[] arguments, GuestToHost return GuestToHostRootNode.guestToHostCall(node, target, hostContext, receiver, this, arguments); } + /** + * Checks for the JDK-8304585: Duplicated InvocationTargetException when the invocation + * of a caller-sensitive method fails. + */ + @TruffleBoundary + static boolean checkForDuplicateInvocationTargetException(Executable executable) { + return Runtime.version().feature() >= 19 && isCallerSensitive(executable); + } + } private static final class MethodReflectImpl extends ReflectBase { @@ -280,7 +289,13 @@ public Object invoke(Object receiver, Object[] arguments) throws Throwable { try { return reflectInvoke(reflectionMethod, receiver, arguments); } catch (InvocationTargetException e) { - throw e.getCause(); + Throwable cause = e.getCause(); + if (cause instanceof InvocationTargetException && checkForDuplicateInvocationTargetException(reflectionMethod)) { + // JDK-8304585: Duplicated InvocationTargetException when the invocation of + // a caller-sensitive method fails. + cause = cause.getCause(); + } + throw cause; } } @@ -315,7 +330,13 @@ public Object invoke(Object receiver, Object[] arguments) throws Throwable { try { return reflectNewInstance(reflectionConstructor, arguments); } catch (InvocationTargetException e) { - throw e.getCause(); + Throwable cause = e.getCause(); + if (cause instanceof InvocationTargetException && checkForDuplicateInvocationTargetException(reflectionConstructor)) { + // JDK-8304585: Duplicated InvocationTargetException when the invocation of + // a caller-sensitive method fails. + cause = cause.getCause(); + } + throw cause; } } diff --git a/vm/ci/ci_common/common-bench.jsonnet b/vm/ci/ci_common/common-bench.jsonnet index 8be8d8517386..e700af993ceb 100644 --- a/vm/ci/ci_common/common-bench.jsonnet +++ b/vm/ci/ci_common/common-bench.jsonnet @@ -1,3 +1,5 @@ +# note: this file needs to be in sync between CE and EE + local vm = import '../ci_includes/vm.jsonnet'; local common = import '../../../ci/ci_common/common.jsonnet'; local vm_common = import '../ci_common/common.jsonnet'; @@ -176,7 +178,7 @@ local repo_config = import '../../../ci/repo-configuration.libsonnet'; self.warmup_bench_cmd + ['--polybench-vm-config=native-standard', '--metric=one-shot'], ], timelimit: '1:30:00', - notify_emails: [], + notify_groups: ['polybench'], }, vm_bench_polybench_nfi: { diff --git a/vm/ci/ci_common/common.jsonnet b/vm/ci/ci_common/common.jsonnet index ce4a59a067d1..0fd83d471f8f 100644 --- a/vm/ci/ci_common/common.jsonnet +++ b/vm/ci/ci_common/common.jsonnet @@ -574,7 +574,7 @@ local devkits = graal_common.devkits; $.upload_file_sizes, ] + $.create_releaser_notifier_artifact + vm.check_graalvm_complete_build($.mx_vm_installables, "windows", "amd64", java_version), notify_groups:: ['deploy'], - timelimit: '1:30:00', + timelimit: '1:45:00', }, deploy_graalvm_ruby(os, arch, java_version): { diff --git a/vm/ci/ci_common/libgraal.jsonnet b/vm/ci/ci_common/libgraal.jsonnet index 90819806263f..89789c15f5fb 100644 --- a/vm/ci/ci_common/libgraal.jsonnet +++ b/vm/ci/ci_common/libgraal.jsonnet @@ -10,6 +10,7 @@ local utils = import '../../../ci/ci_common/common-utils.libsonnet'; local underscore(s) = std.strReplace(s, "-", "_"), local os(os_arch) = std.split(os_arch, "-")[0], local arch(os_arch) = std.split(os_arch, "-")[1], + local t(limit) = {timelimit: limit}, libgraal_build(build_args):: { local build_command = if repo_config.graalvm_edition == 'ce' then 'build' else 'build-libgraal-pgo', @@ -70,7 +71,7 @@ local utils = import '../../../ci/ci_common/common-utils.libsonnet'; "gate-vm-libgraal_truffle-labsjdk-20-linux-amd64": {}, "gate-vm-libgraal_compiler_zgc-labsjdk-20-linux-amd64": {}, "gate-vm-libgraal_compiler_quickbuild-labsjdk-20-linux-amd64": {}, - "gate-vm-libgraal_truffle_quickbuild-labsjdk-20-linux-amd64": {}, + "gate-vm-libgraal_truffle_quickbuild-labsjdk-20-linux-amd64": t("1:10:00"), }, # See definition of `dailies` local variable in ../../compiler/ci_common/gate.jsonnet diff --git a/vm/mx.vm/ce b/vm/mx.vm/ce index 2cc2b10f162a..8dab0edf3c27 100644 --- a/vm/mx.vm/ce +++ b/vm/mx.vm/ce @@ -1,4 +1,5 @@ DYNAMIC_IMPORTS=/compiler,/graal-js,/sdk,/substratevm,/tools,/truffle COMPONENTS=cmp,cov,dap,gu,gvm,ins,insight,insightheap,jss,lg,lsp,nfi-libffi,ni,nic,nil,poly,polynative,pro,sdk,svm,svmnfi,svmsl,tfl,tflm NATIVE_IMAGES=graalvm-native-binutil,graalvm-native-clang,graalvm-native-clang-cl,graalvm-native-clang++,graalvm-native-ld,lib:jvmcicompiler,lib:native-image-agent,lib:native-image-diagnostics-agent,native-image +NON_REBUILDABLE_IMAGES=lib:jvmcicompiler DISABLE_INSTALLABLES=False diff --git a/vm/mx.vm/ce-aarch64 b/vm/mx.vm/ce-aarch64 index 2cc2b10f162a..8dab0edf3c27 100644 --- a/vm/mx.vm/ce-aarch64 +++ b/vm/mx.vm/ce-aarch64 @@ -1,4 +1,5 @@ DYNAMIC_IMPORTS=/compiler,/graal-js,/sdk,/substratevm,/tools,/truffle COMPONENTS=cmp,cov,dap,gu,gvm,ins,insight,insightheap,jss,lg,lsp,nfi-libffi,ni,nic,nil,poly,polynative,pro,sdk,svm,svmnfi,svmsl,tfl,tflm NATIVE_IMAGES=graalvm-native-binutil,graalvm-native-clang,graalvm-native-clang-cl,graalvm-native-clang++,graalvm-native-ld,lib:jvmcicompiler,lib:native-image-agent,lib:native-image-diagnostics-agent,native-image +NON_REBUILDABLE_IMAGES=lib:jvmcicompiler DISABLE_INSTALLABLES=False diff --git a/vm/mx.vm/ce-darwin b/vm/mx.vm/ce-darwin index 2cc2b10f162a..8dab0edf3c27 100644 --- a/vm/mx.vm/ce-darwin +++ b/vm/mx.vm/ce-darwin @@ -1,4 +1,5 @@ DYNAMIC_IMPORTS=/compiler,/graal-js,/sdk,/substratevm,/tools,/truffle COMPONENTS=cmp,cov,dap,gu,gvm,ins,insight,insightheap,jss,lg,lsp,nfi-libffi,ni,nic,nil,poly,polynative,pro,sdk,svm,svmnfi,svmsl,tfl,tflm NATIVE_IMAGES=graalvm-native-binutil,graalvm-native-clang,graalvm-native-clang-cl,graalvm-native-clang++,graalvm-native-ld,lib:jvmcicompiler,lib:native-image-agent,lib:native-image-diagnostics-agent,native-image +NON_REBUILDABLE_IMAGES=lib:jvmcicompiler DISABLE_INSTALLABLES=False diff --git a/vm/mx.vm/ce-darwin-aarch64 b/vm/mx.vm/ce-darwin-aarch64 index 2cc2b10f162a..8dab0edf3c27 100644 --- a/vm/mx.vm/ce-darwin-aarch64 +++ b/vm/mx.vm/ce-darwin-aarch64 @@ -1,4 +1,5 @@ DYNAMIC_IMPORTS=/compiler,/graal-js,/sdk,/substratevm,/tools,/truffle COMPONENTS=cmp,cov,dap,gu,gvm,ins,insight,insightheap,jss,lg,lsp,nfi-libffi,ni,nic,nil,poly,polynative,pro,sdk,svm,svmnfi,svmsl,tfl,tflm NATIVE_IMAGES=graalvm-native-binutil,graalvm-native-clang,graalvm-native-clang-cl,graalvm-native-clang++,graalvm-native-ld,lib:jvmcicompiler,lib:native-image-agent,lib:native-image-diagnostics-agent,native-image +NON_REBUILDABLE_IMAGES=lib:jvmcicompiler DISABLE_INSTALLABLES=False diff --git a/vm/mx.vm/ce-fastr b/vm/mx.vm/ce-fastr index 94dc23f2f02c..5a276480d7aa 100644 --- a/vm/mx.vm/ce-fastr +++ b/vm/mx.vm/ce-fastr @@ -1,4 +1,5 @@ DYNAMIC_IMPORTS=/compiler,/graal-js,/sdk,/substratevm,/sulong,/tools,/truffle,fastr COMPONENTS=R,cmp,cov,dap,gu,gvm,ins,insight,insightheap,jss,lg,llp,llrc,llrl,llrn,lsp,nfi-libffi,ni,nic,poly,polynative,pro,sdk,tfl,tflm NATIVE_IMAGES=lib:jvmcicompiler +NON_REBUILDABLE_IMAGES=lib:jvmcicompiler DISABLE_INSTALLABLES=False diff --git a/vm/mx.vm/ce-js b/vm/mx.vm/ce-js index 3d4a595672e3..18ee4999d14d 100644 --- a/vm/mx.vm/ce-js +++ b/vm/mx.vm/ce-js @@ -1,4 +1,5 @@ DYNAMIC_IMPORTS=/compiler,/graal-js,/regex,/sdk,/substratevm,/tools,/truffle COMPONENTS=cmp,cov,dap,gu,gvm,icu4j,ins,insight,insightheap,js,jss,lg,lsp,nfi,nfi-libffi,ni,nic,nil,poly,polynative,pro,rgx,sdk,svm,svmnfi,svmsl,tfl,tflm NATIVE_IMAGES=lib:jsvm,lib:jvmcicompiler +NON_REBUILDABLE_IMAGES=lib:jvmcicompiler DISABLE_INSTALLABLES=False diff --git a/vm/mx.vm/ce-nodejs b/vm/mx.vm/ce-nodejs index 1a4e5796d77e..b40703232d54 100644 --- a/vm/mx.vm/ce-nodejs +++ b/vm/mx.vm/ce-nodejs @@ -1,4 +1,5 @@ DYNAMIC_IMPORTS=/compiler,/graal-js,/graal-nodejs,/sdk,/substratevm,/tools,/truffle COMPONENTS=cmp,cov,dap,gu,gvm,ins,insight,insightheap,js,jss,lg,lsp,nfi-libffi,njs,ni,nic,nil,poly,polynative,pro,sdk,sjvm,svm,svmnfi,svmsl,tfl,tflm NATIVE_IMAGES=graalvm-native-binutil,graalvm-native-clang,graalvm-native-clang-cl,graalvm-native-clang++,graalvm-native-ld,lib:graal-nodejs,lib:jvmcicompiler,lib:native-image-agent,lib:native-image-diagnostics-agent,native-image +NON_REBUILDABLE_IMAGES=lib:jvmcicompiler DISABLE_INSTALLABLES=False diff --git a/vm/mx.vm/ce-win b/vm/mx.vm/ce-win index 1bddc6cf2ed8..c88a96885ed4 100644 --- a/vm/mx.vm/ce-win +++ b/vm/mx.vm/ce-win @@ -1,4 +1,5 @@ DYNAMIC_IMPORTS=/compiler,/graal-js,/sdk,/substratevm,/tools,/truffle COMPONENTS=cmp,cov,dap,gu,gvm,ins,insight,insightheap,jss,lg,lsp,nfi-libffi,ni,nic,nil,poly,polynative,pro,sdk,svm,svmnfi,svmsl,tfl,tflm NATIVE_IMAGES=lib:jvmcicompiler,lib:native-image-agent,lib:native-image-diagnostics-agent,native-image +NON_REBUILDABLE_IMAGES=lib:jvmcicompiler DISABLE_INSTALLABLES=False diff --git a/vm/mx.vm/libgraal b/vm/mx.vm/libgraal index bf88c04239a9..59ea87490cb2 100644 --- a/vm/mx.vm/libgraal +++ b/vm/mx.vm/libgraal @@ -1,5 +1,4 @@ -DYNAMIC_IMPORTS=/compiler,/sdk,/substratevm,/truffle -COMPONENTS=cmp,dis,gu,gvm,lg,nfi-libffi,poly,polynative,sdk,tfl,tflm -EXCLUDE_COMPONENTS=libpoly +DYNAMIC_IMPORTS=/substratevm +COMPONENTS=lg NATIVE_IMAGES=lib:jvmcicompiler -DISABLE_INSTALLABLES=False +DISABLE_INSTALLABLES=true diff --git a/vm/mx.vm/mx_vm.py b/vm/mx.vm/mx_vm.py index a8ea774f409f..4a2d655b3f1b 100644 --- a/vm/mx.vm/mx_vm.py +++ b/vm/mx.vm/mx_vm.py @@ -163,7 +163,7 @@ # pylint: disable=line-too-long ce_components_minimal = ['bgu', 'bpolyglot', 'cmp', 'cov', 'dap', 'gu', 'gvm', 'ins', 'insight', 'insightheap', 'jss', 'lg', 'libpoly', 'lsp', 'nfi-libffi', 'nfi', 'poly', 'polynative', 'pro', 'sdk', 'spolyglot', 'tfl', 'tflm'] -ce_components = ce_components_minimal + ['bnative-image-configure', 'ni', 'nic', 'nil', 'svm', 'svmnfi', 'svmsl'] +ce_components = ce_components_minimal + ['nr_lib_jvmcicompiler', 'bnative-image-configure', 'ni', 'nic', 'nil', 'svm', 'svmnfi', 'svmsl'] ce_win_complete_components = ['bgu', 'bnative-image-configure', 'bpolyglot', 'cmp', 'cov', 'dap', 'ejvm', 'gu', 'gvm', 'gwa', 'icu4j', 'ins', 'insight', 'insightheap', 'java', 'js', 'jss', 'lg', 'libpoly', 'llp', 'llrc', 'llrl', 'llrn', 'lsp', 'nfi-libffi', 'nfi', 'ni', 'nic', 'nil', 'njs', 'poly', 'polynative', 'pro', 'rgx', 'sdk', 'spolyglot', 'svm', 'svmnfi', 'svmsl', 'tfl', 'tflm', 'vvm'] ce_aarch64_complete_components = ce_win_complete_components + ['pyn', 'pynl', 'rby', 'rbyl', 'svml'] ce_complete_components = ce_aarch64_complete_components + ['ellvm', 'R', 'bRMain'] @@ -191,7 +191,7 @@ 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) -mx_sdk_vm.register_vm_config('libgraal', ['bgu', 'cmp', 'dis', 'gu', 'gvm', 'lg', 'nfi-libffi', 'nfi', 'poly', 'polynative', 'sdk', 'tfl', 'tflm', 'bpolyglot'], _suite) +mx_sdk_vm.register_vm_config('libgraal', ['lg'], _suite) mx_sdk_vm.register_vm_config('toolchain-only', ['sdk', 'tfl', 'tflm', 'nfi-libffi', 'nfi', 'cmp', 'llp', 'llrc', 'llrn'], _suite) mx_sdk_vm.register_vm_config('libgraal-bash', llvm_components + ['bgu', 'cmp', 'gu', 'gvm', 'lg', 'nfi-libffi', 'nfi', 'poly', 'polynative', 'sdk', 'tfl', 'tflm', 'bpolyglot'], _suite, env_file=False) mx_sdk_vm.register_vm_config('toolchain-only-bash', llvm_components + ['bgu', 'tfl', 'tflm', 'gu', 'gvm', 'polynative', 'llp', 'nfi-libffi', 'nfi', 'svml', 'bgu', 'sdk', 'llrc', 'llrn', 'cmp'], _suite, env_file=False) diff --git a/vm/mx.vm/mx_vm_benchmark.py b/vm/mx.vm/mx_vm_benchmark.py index 7ec1e96ed8ba..64834d93754f 100644 --- a/vm/mx.vm/mx_vm_benchmark.py +++ b/vm/mx.vm/mx_vm_benchmark.py @@ -538,15 +538,16 @@ def __exit__(self, tp, value, tb): self.failed = True if self.exit_code is not None and self.exit_code != 0: mx.log(mx.colorize('Failed in stage ' + self.current_stage + ' for ' + self.final_image_name + ' with exit code ' + str(self.exit_code), 'red')) - if self.stdout_path: - mx.log(mx.colorize('--------- Standard output:', 'blue')) - with open(self.stdout_path, 'r') as stdout: - mx.log(stdout.read()) - if self.stderr_path: - mx.log(mx.colorize('--------- Standard error:', 'red')) - with open(self.stderr_path, 'r') as stderr: - mx.log(stderr.read()) + if self.stdout_path: + mx.log(mx.colorize('--------- Standard output:', 'blue')) + with open(self.stdout_path, 'r') as stdout: + mx.log(stdout.read()) + + if self.stderr_path: + mx.log(mx.colorize('--------- Standard error:', 'red')) + with open(self.stderr_path, 'r') as stderr: + mx.log(stderr.read()) if tb: mx.log(mx.colorize('Failed in stage ' + self.current_stage + ' with ', 'red')) @@ -863,8 +864,8 @@ def run_stage_instrument_image(self, config, stages, out, i, instrumentation_ima out('Instrumented image size: ' + str(image_size) + ' B') def _ensureSamplesAreInProfile(self, profile_path): - # GR-42738 --pgo-sampling does not work with LLVM - if not self.is_llvm: + # GR-42738 --pgo-sampling does not work with LLVM. Sampling is disabled when doing JDK profiles collection. + if not self.is_llvm and not self.jdk_profiles_collect: with open(profile_path) as profile_file: parsed = json.load(profile_file) samples = parsed["samplingProfiles"] diff --git a/vm/mx.vm/mx_vm_gate.py b/vm/mx.vm/mx_vm_gate.py index 431ff123a151..a7634bd79168 100644 --- a/vm/mx.vm/mx_vm_gate.py +++ b/vm/mx.vm/mx_vm_gate.py @@ -153,7 +153,7 @@ def extra_check(compiler_log): stub = f'{m.group(1)}{m.group(2)}' stub_compilations[stub] = stub_compilations.get(stub, 0) + 1 if not stub_compilations: - mx.abort('Expected at least one stub compilation in compiler log') + mx.abort(f'Expected at least one stub compilation in compiler log:\n{compiler_log}') duplicated = {stub: count for stub, count in stub_compilations.items() if count > 1} if duplicated: table = f' Count Stub{nl} ' + f'{nl} '.join((f'{count:<8d} {stub}') for stub, count in stub_compilations.items()) @@ -226,6 +226,26 @@ def _test_libgraal_fatal_error_handling(): mx.log(f"Cleaning up scratch dir after gate task completion: {scratch_dir}") mx.rmtree(scratch_dir) +def _test_libgraal_systemic_failure_detection(): + """ + Tests that system compilation failures are detected and cause the VM to exit. + """ + vmargs = ['-Dlibgraal.CrashAt=get,set,toString'] + cmd = ["dacapo:fop", "--tracker=none", "--"] + vmargs + ["--", "--preserve"] + out = mx.OutputCapture() + exitcode, bench_suite, _ = mx_benchmark.gate_mx_benchmark(cmd, out=out, err=out, nonZeroIsFatal=False) + if exitcode == 0: + mx.abort('Expected benchmark to result in non-zero exit code: ' + ' '.join(cmd) + linesep + out.data) + else: + expect = 'Systemic Graal compilation failure detected' + if expect not in out.data: + mx.abort(f'Expected "{expect}" in output:{linesep}{out.data}') + + # Only clean up scratch dir on success + for scratch_dir in bench_suite.scratchDirs(): + mx.log(f"Cleaning up scratch dir after gate task completion: {scratch_dir}") + mx.rmtree(scratch_dir) + def _jdk_has_ForceTranslateFailure_jvmci_option(jdk): """ Determines if `jdk` supports the `-Djvmci.ForceTranslateFailure` option. @@ -403,7 +423,7 @@ def gate_body(args, tasks): if t and mx_sdk_vm_impl.has_component('GraalVM compiler'): # 1. the build must be a GraalVM # 2. the build must be JVMCI-enabled since the 'GraalVM compiler' component is registered - mx_sdk_vm_impl.check_versions(mx_sdk_vm_impl.graalvm_output(), graalvm_version_regex=mx_sdk_vm_impl.graalvm_version_regex, expect_graalvm=True, check_jvmci=True) + mx_sdk_vm_impl.check_versions(mx_sdk_vm_impl.graalvm_output(), expect_graalvm=True, check_jvmci=True) libgraal_suite_name = 'substratevm' if mx.suite(libgraal_suite_name, fatalIfMissing=False) is not None: @@ -424,6 +444,8 @@ def gate_body(args, tasks): if t: _test_libgraal_basic(extra_vm_arguments) with Task('LibGraal Compiler:FatalErrorHandling', tasks, tags=[VmGateTasks.libgraal], report='compiler') as t: if t: _test_libgraal_fatal_error_handling() + with Task('LibGraal Compiler:SystemicFailureDetection', tasks, tags=[VmGateTasks.libgraal], report='compiler') as t: + if t: _test_libgraal_systemic_failure_detection() with Task('LibGraal Compiler:CompilationTimeout:JIT', tasks, tags=[VmGateTasks.libgraal]) as t: if t: _test_libgraal_CompilationTimeout_JIT() with Task('LibGraal Compiler:CompilationTimeout:Truffle', tasks, tags=[VmGateTasks.libgraal]) as t: diff --git a/vm/mx.vm/suite.py b/vm/mx.vm/suite.py index d75840dc2089..b0c6cbc55853 100644 --- a/vm/mx.vm/suite.py +++ b/vm/mx.vm/suite.py @@ -1,6 +1,6 @@ suite = { "name": "vm", - "version" : "23.0.0", + "version" : "23.1.0", "mxversion": "6.17.0", "release" : False, "groupId" : "org.graalvm", @@ -23,63 +23,52 @@ { "name": "sdk", "subdir": True, - "urls": [ - {"url": "https://curio.ssw.jku.at/nexus/content/repositories/snapshots", "kind": "binary"}, - ] }, { "name": "truffle", "subdir": True, - "urls": [ - {"url": "https://curio.ssw.jku.at/nexus/content/repositories/snapshots", "kind": "binary"}, - ] }, # Dynamic imports for components: { "name": "graal-nodejs", "subdir": True, "dynamic": True, - "version": "f2029698ba2c52bd863d3bdcd059b56bbd1ae3e3", + "version": "a314832c8fc1e7f06244d9afb0553900f4d5a638", "urls" : [ {"url" : "https://github.com/graalvm/graaljs.git", "kind" : "git"}, - {"url": "https://curio.ssw.jku.at/nexus/content/repositories/snapshots", "kind": "binary"}, ] }, { "name": "graal-js", "subdir": True, "dynamic": True, - "version": "f2029698ba2c52bd863d3bdcd059b56bbd1ae3e3", + "version": "a314832c8fc1e7f06244d9afb0553900f4d5a638", "urls": [ {"url": "https://github.com/graalvm/graaljs.git", "kind" : "git"}, - {"url": "https://curio.ssw.jku.at/nexus/content/repositories/snapshots", "kind": "binary"}, ] }, { "name": "truffleruby", - "version": "58aea0198762de15659cd1680fbe03c6fb829aec", + "version": "b60c98de2069aefee9f161a6219958ca6184fc67", "dynamic": True, "urls": [ {"url": "https://github.com/oracle/truffleruby.git", "kind": "git"}, - {"url": "https://curio.ssw.jku.at/nexus/content/repositories/snapshots", "kind": "binary"}, ] }, { "name": "fastr", - "version": "ec6225ca40bc30122695bad17b11630fb0ff5a94", + "version": "4e696f96c64eb1e533ae1286e713b1a90c46844a", "dynamic": True, "urls": [ {"url": "https://github.com/oracle/fastr.git", "kind": "git"}, - {"url": "https://curio.ssw.jku.at/nexus/content/repositories/snapshots", "kind": "binary"}, ] }, { "name": "graalpython", - "version": "fc53982c3f9239baf7e670eb128384eb8acd6f25", + "version": "018f8bfe784eaf287055ff44723c0936fe6892ab", "dynamic": True, "urls": [ {"url": "https://github.com/graalvm/graalpython.git", "kind": "git"}, - {"url": "https://curio.ssw.jku.at/nexus/content/repositories/snapshots", "kind": "binary"}, ] }, { diff --git a/wasm/mx.wasm/suite.py b/wasm/mx.wasm/suite.py index c100cec4e402..4fa802fe5fb8 100644 --- a/wasm/mx.wasm/suite.py +++ b/wasm/mx.wasm/suite.py @@ -42,7 +42,7 @@ "mxversion": "6.17.0", "name" : "wasm", "groupId" : "org.graalvm.wasm", - "version" : "23.0.0", + "version" : "23.1.0", "versionConflictResolution" : "latest", "url" : "http://graalvm.org/", "developer" : { @@ -63,9 +63,6 @@ { "name" : "truffle", "subdir" : True, - "urls": [ - {"url" : "https://curio.ssw.jku.at/nexus/content/repositories/snapshots", "kind" : "binary"}, - ], }, ], },