From 6607747c0f32bb19195728ac722fc17f24982292 Mon Sep 17 00:00:00 2001 From: Foivos Zakkak Date: Fri, 3 Dec 2021 15:22:38 +0200 Subject: [PATCH 01/17] Adds debuginfo size to native-image output. --- .../src/com/oracle/svm/hosted/NativeImageGenerator.java | 2 +- .../src/com/oracle/svm/hosted/image/AbstractImage.java | 5 +++++ .../src/com/oracle/svm/hosted/image/NativeImage.java | 6 ++++++ .../com/oracle/svm/hosted/reporting/ProgressReporter.java | 7 +++++-- 4 files changed, 17 insertions(+), 3 deletions(-) diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/NativeImageGenerator.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/NativeImageGenerator.java index 2fa307cb3bbd..67ff9a78a2d1 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 @@ -680,7 +680,7 @@ private void doRun(Map entryPoints, featureHandler.forEachFeature(feature -> feature.afterImageWrite(afterConfig)); } reporter.printCreationEnd(imageTimer, writeTimer, image.getImageSize(), bb.getUniverse(), heap.getObjectCount(), image.getImageHeapSize(), codeCache.getCodeCacheSize(), - codeCache.getCompilations().size()); + codeCache.getCompilations().size(), image.getDebugInfoSize()); if (SubstrateOptions.BuildOutputBreakdowns.getValue()) { ProgressReporter.singleton().printBreakdowns(compileQueue.getCompilationTasks(), image.getHeap().getObjects()); } diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/AbstractImage.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/AbstractImage.java index 3745dddc4217..708dbf89dce2 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/AbstractImage.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/AbstractImage.java @@ -47,6 +47,7 @@ public abstract class AbstractImage { protected final NativeImageCodeCache codeCache; protected final List entryPoints; protected int resultingImageSize; // for statistical output + protected int debugInfoSize; // for statistical output public enum NativeImageKind { SHARED_LIBRARY(false) { @@ -115,6 +116,10 @@ public int getImageSize() { return resultingImageSize; } + public int getDebugInfoSize() { + return debugInfoSize; + } + public NativeLibraries getNativeLibs() { return nativeLibs; } diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/NativeImage.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/NativeImage.java index 7f2057e9cebe..c9c054c7f6ab 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/NativeImage.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/NativeImage.java @@ -179,6 +179,12 @@ protected final void write(DebugContext context, Path outputFile) { throw shouldNotReachHere(ex); } resultingImageSize = (int) outputFile.toFile().length(); + debugInfoSize = 0; + for (Element e : objectFile.getElements()) { + if (e.getName().contains(".debug")) { + debugInfoSize += e.getMemSize(objectFile.getDecisionsByElement()); + } + } if (NativeImageOptions.PrintImageElementSizes.getValue()) { for (Element e : objectFile.getElements()) { System.out.printf("PrintImageElementSizes: size: %15d name: %s\n", e.getMemSize(objectFile.getDecisionsByElement()), e.getElementName()); diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/reporting/ProgressReporter.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/reporting/ProgressReporter.java index d5fa6c8bd5d0..505aefc713cf 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/reporting/ProgressReporter.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/reporting/ProgressReporter.java @@ -347,7 +347,7 @@ public void setDebugInfoTimer(Timer timer) { } public void printCreationEnd(Timer creationTimer, Timer writeTimer, int imageSize, AnalysisUniverse universe, int numHeapObjects, long imageHeapSize, int codeCacheSize, - int numCompilations) { + int numCompilations, int debugInfoSize) { printStageEnd(creationTimer.getTotalTime() + writeTimer.getTotalTime()); String total = bytesToHuman("%4.2f", imageSize); long otherBytes = imageSize - codeCacheSize - imageHeapSize; @@ -357,7 +357,10 @@ public void printCreationEnd(Timer creationTimer, Timer writeTimer, int imageSiz l().a("%9s for code area:%,9d compilation units", bytesToHuman("%4.2f", codeCacheSize), numCompilations).flushln(); long numInstantiatedClasses = universe.getTypes().stream().filter(t -> t.isInstantiated()).count(); l().a("%9s for image heap:%,8d classes and %,d objects", bytesToHuman("%4.2f", imageHeapSize), numInstantiatedClasses, numHeapObjects).flushln(); - l().a("%9s for other data", bytesToHuman("%4.2f", otherBytes)).a(debugInfoTimer != null ? " including debug info" : "").flushln(); + if (debugInfoSize > 0) { + l().a("%9s in debugInfo size", bytesToHuman("%4.2f", debugInfoSize)).flushln(); + } + l().a("%9s for other data", bytesToHuman("%4.2f", otherBytes)).flushln(); if (debugInfoTimer != null) { String debugInfoTime = String.format("%.1fs", millisToSeconds(debugInfoTimer.getTotalTime())); l().dim().a("%9s for generating debug info", debugInfoTime).reset().flushln(); From 122ff0416ae8ab240d03f09f70532579dcf44ea0 Mon Sep 17 00:00:00 2001 From: Fabio Niephaus Date: Thu, 9 Dec 2021 18:34:36 +0100 Subject: [PATCH 02/17] Simplify library detection. --- .../svm/hosted/reporting/ProgressReporterCHelper.java | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/reporting/ProgressReporterCHelper.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/reporting/ProgressReporterCHelper.java index de708cd318f5..6ceeccbcde75 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/reporting/ProgressReporterCHelper.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/reporting/ProgressReporterCHelper.java @@ -31,9 +31,6 @@ import org.graalvm.compiler.serviceprovider.JavaVersionUtil; -import com.oracle.svm.core.OS; -import com.oracle.svm.hosted.image.AbstractImage.NativeImageKind; - public final class ProgressReporterCHelper { private static final int DEFAULT_CHARACTERS_PER_LINE = 80; public static final int MAX_CHARACTERS_PER_LINE = 120; @@ -46,8 +43,8 @@ private static void loadCHelperLibrary() { if (JavaVersionUtil.JAVA_SPEC <= 8) { return; // TODO: remove as part of JDK8 removal (GR-35238). } - String libName = OS.getCurrent() == OS.WINDOWS ? "reporterchelper" : "libreporterchelper"; - Path libRSSHelperPath = Paths.get(System.getProperty("java.home"), "lib", "svm", "builder", "lib", libName + NativeImageKind.SHARED_LIBRARY.getFilenameSuffix()); + String libName = System.mapLibraryName("reporterchelper"); + Path libRSSHelperPath = Paths.get(System.getProperty("java.home"), "lib", "svm", "builder", "lib", libName); if (Files.exists(libRSSHelperPath)) { System.load(libRSSHelperPath.toString()); } From 0f37d57ca4be02dd54ea691844bd785080f2bd4d Mon Sep 17 00:00:00 2001 From: Fabio Niephaus Date: Thu, 9 Dec 2021 18:43:17 +0100 Subject: [PATCH 03/17] Capture stdout/stderr during progress reporting. --- .../svm/core/jdk/SystemInOutErrSupport.java | 78 +++++++++++++++++++ .../hosted/reporting/ProgressReporter.java | 25 +++--- 2 files changed, 94 insertions(+), 9 deletions(-) diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/SystemInOutErrSupport.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/SystemInOutErrSupport.java index 8dd5aa807b45..6d944cc27a82 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/SystemInOutErrSupport.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/SystemInOutErrSupport.java @@ -26,9 +26,11 @@ import java.io.BufferedInputStream; import java.io.BufferedOutputStream; +import java.io.ByteArrayOutputStream; import java.io.FileDescriptor; import java.io.FileInputStream; import java.io.FileOutputStream; +import java.io.IOException; import java.io.InputStream; import java.io.PrintStream; import java.io.UnsupportedEncodingException; @@ -39,6 +41,7 @@ import com.oracle.svm.core.annotate.AutomaticFeature; import com.oracle.svm.core.annotate.RecomputeFieldValue; +import com.oracle.svm.core.util.VMError; /** * This class provides replacement values for the {@link System#in}, {@link System#out}, and @@ -51,9 +54,22 @@ * static analysis starts, i.e., in a {@link Feature#beforeAnalysis} method. */ public final class SystemInOutErrSupport { + // Checkstyle: stop + private final PrintStream outOriginal = System.out; + private final CapturingStdioWrapper outWrapper = new CapturingStdioWrapper(outOriginal, new ByteArrayOutputStream(128)); + private final CapturingStdioWrapper errWrapper = new CapturingStdioWrapper(System.err, new ByteArrayOutputStream(128)); + // Checkstyle: resume + private InputStream in = new BufferedInputStream(new FileInputStream(FileDescriptor.in)); private PrintStream out = newPrintStream(new FileOutputStream(FileDescriptor.out), System.getProperty("sun.stdout.encoding")); private PrintStream err = newPrintStream(new FileOutputStream(FileDescriptor.err), System.getProperty("sun.stderr.encoding")); + private boolean isCapturing; + + public SystemInOutErrSupport() { + /* Install stdout and stderr wrappers. */ + System.setOut(outWrapper); + System.setErr(errWrapper); + } /* Create `PrintStream` in the same way as `System.newPrintStream`. */ private static PrintStream newPrintStream(FileOutputStream fos, String enc) { @@ -78,8 +94,22 @@ public static void setErr(PrintStream err) { ImageSingletons.lookup(SystemInOutErrSupport.class).err = Objects.requireNonNull(err); } + public static void setCapturing(boolean value) { + ImageSingletons.lookup(SystemInOutErrSupport.class).isCapturing = value; + } + + public static void flushCapturedContent() { + ImageSingletons.lookup(SystemInOutErrSupport.class).outWrapper.flushCapturedContent(); + ImageSingletons.lookup(SystemInOutErrSupport.class).errWrapper.flushCapturedContent(); + } + + public static void printToStdOutUnconditionally(char value) { + ImageSingletons.lookup(SystemInOutErrSupport.class).outOriginal.print(value); + } + // Checkstyle: stop Object replaceStreams(Object object) { + assert System.out == outWrapper && System.err == errWrapper : "stdio handles are not allowed to change during image construction"; if (object == System.in) { return in; } else if (object == System.out) { @@ -91,6 +121,54 @@ Object replaceStreams(Object object) { } } // Checkstyle: resume + + /** Wrapper with the ability to temporarily capture output to stdout and stderr. */ + final class CapturingStdioWrapper extends PrintStream { + private final ByteArrayOutputStream buffer; + private final PrintStream delegate; + + CapturingStdioWrapper(PrintStream delegate, ByteArrayOutputStream buffer) { + super(buffer); + this.buffer = buffer; + this.delegate = delegate; + } + + @Override + public void write(int b) { + if (isCapturing) { + super.write(b); + } else { + delegate.write(b); + } + } + + @Override + public void write(byte[] buf, int off, int len) { + if (isCapturing) { + super.write(buf, off, len); + } else { + delegate.write(buf, off, len); + } + } + + @Override + public void write(byte[] buf) throws IOException { + if (isCapturing) { + super.write(buf); + } else { + delegate.write(buf); + } + } + + void flushCapturedContent() { + try { + delegate.write(buffer.toByteArray()); + } catch (IOException e) { + throw VMError.shouldNotReachHere(); + } + buffer.reset(); + } + } } /** diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/reporting/ProgressReporter.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/reporting/ProgressReporter.java index 505aefc713cf..76e94ecb3ef9 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/reporting/ProgressReporter.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/reporting/ProgressReporter.java @@ -63,6 +63,7 @@ import com.oracle.svm.core.SubstrateOptions; import com.oracle.svm.core.VM; import com.oracle.svm.core.annotate.AutomaticFeature; +import com.oracle.svm.core.jdk.SystemInOutErrSupport; import com.oracle.svm.core.option.HostedOptionValues; import com.oracle.svm.core.reflect.MethodMetadataDecoder; import com.oracle.svm.hosted.NativeImageGenerator; @@ -239,8 +240,7 @@ public ReporterClosable printAnalysis(BigBang bb) { public void closeAction() { timer.stop(); printProgressEnd(); - int analysisMillis = (int) bb.getAnalysisTimer().getTotalTime(); - printStageEnd(analysisMillis); + printStageEndAndFlushStdioContent(bb.getAnalysisTimer()); String actualVsTotalFormat = "%,8d (%5.2f%%) of %,6d"; long reachableClasses = bb.getUniverse().getTypes().stream().filter(t -> t.isReachable()).count(); long totalClasses = bb.getUniverse().getTypes().size(); @@ -296,7 +296,7 @@ public void closeAction() { timer.stop(); stopPeriodicPrinting(); printProgressEnd(); - printStageEnd(timer); + printStageEndAndFlushStdioContent(timer); } }; } @@ -310,7 +310,7 @@ public ReporterClosable printInlining(Timer timer) { public void closeAction() { timer.stop(); printProgressEnd(); - printStageEnd(timer); + printStageEndAndFlushStdioContent(timer); } }; } @@ -332,7 +332,7 @@ public void closeAction() { timer.stop(); stopPeriodicPrinting(); printProgressEnd(); - printStageEnd(timer); + printStageEndAndFlushStdioContent(timer); } }; } @@ -549,6 +549,7 @@ private void printProgressStart() { linePrinter.a(progressBarStartPadding()).dim().a("["); numStageChars = PROGRESS_BAR_START + 1; /* +1 for [ */ linePrinter.flush(); + SystemInOutErrSupport.setCapturing(true); } private String progressBarStartPadding() { @@ -556,12 +557,13 @@ private String progressBarStartPadding() { } private void printProgressEnd() { + SystemInOutErrSupport.setCapturing(false); linePrinter.a("]").reset().flush(); numStageChars++; // for ] } public void printStageProgress() { - linePrinter.printRaw("*"); + linePrinter.printRaw('*'); numStageChars++; // for * } @@ -584,6 +586,11 @@ private void stopPeriodicPrinting() { periodicPrintingTask.cancel(false); } + private void printStageEndAndFlushStdioContent(Timer timer) { + printStageEnd(timer); + SystemInOutErrSupport.flushCapturedContent(); + } + private void printStageEnd(Timer timer) { printStageEnd(timer.getTotalTime()); } @@ -827,14 +834,14 @@ private void flush() { textBuffer.clear(); } - private void printRaw(String text) { + private void printRaw(char value) { if (!isEnabled) { return; } if (printBuffer != null) { - printBuffer.append(text); + printBuffer.append(value); } else { - System.out.print(text); + SystemInOutErrSupport.printToStdOutUnconditionally(value); } } From 43298520c32bad63b1bc6d772680ae8ffe895b7f Mon Sep 17 00:00:00 2001 From: Fabio Niephaus Date: Thu, 9 Dec 2021 21:24:07 +0100 Subject: [PATCH 04/17] Improve resource statistics. --- docs/reference-manual/native-image/BuildOutput.md | 6 +++--- .../oracle/svm/hosted/reporting/ProgressReporter.java | 9 +++++---- 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/docs/reference-manual/native-image/BuildOutput.md b/docs/reference-manual/native-image/BuildOutput.md index 0c51c220f263..0d2e0ac00e80 100644 --- a/docs/reference-manual/native-image/BuildOutput.md +++ b/docs/reference-manual/native-image/BuildOutput.md @@ -45,7 +45,7 @@ Top 10 packages in code area: Top 10 object types in image heap: ... 111 additional packages ... 723 additional object types (use GraalVM Dashboard to see all) -------------------------------------------------------------------------------- - 0.8s (5.4% of total time) in 17 GCs | Peak RSS: 2.60GB | CPU load: ~1183.69% + 0.8s (5.4% of total time) in 17 GCs | Peak RSS: 2.60GB | CPU load: 11.83 -------------------------------------------------------------------------------- Produced artifacts: /home/janedoe/helloworld/helloworld (executable) @@ -136,7 +136,7 @@ This data typically contains internal information for Native Image but it can al ### Resource Usage Statistics #### Garbage Collections -The total time spent in all garbage collectors, total GC time divided by the total time to build the image in percent, and the total number of garbage collections. +The total time spent in all garbage collectors, total GC time divided by the total process time in percent, and the total number of garbage collections. A large number of collections or time spent in collectors usually indicates that the system is under memory pressure. Increase the amount of available memory to reduce the time to build the image. @@ -146,7 +146,7 @@ This value indicates the maximum amount of memory consumed by the build process. If the [GC statistics](#glossary-garbage-collection) do not show any problems, the amount of available memory of the system can be reduced to a value closer to the peak RSS. #### CPU load -The CPU time used by the process divided by the total time to build the image in percent. +The CPU time used by the process divided by the total process time. Increase the number of CPU threads to reduce the time to build the image. ## Build Output Options diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/reporting/ProgressReporter.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/reporting/ProgressReporter.java index 76e94ecb3ef9..afeb82148dca 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/reporting/ProgressReporter.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/reporting/ProgressReporter.java @@ -461,7 +461,7 @@ private Map calculateHeapBreakdown(Collection heapObje public void printEpilog(String imageName, NativeImageGenerator generator, boolean wasSuccessfulBuild, Timer totalTimer, OptionValues parsedHostedOptions) { l().printLineSeparator(); - printResourceStats(millisToSeconds(totalTimer.getTotalTime())); + printResourceStats(); l().printLineSeparator(); l().yellowBold().a("Produced artifacts:").reset().flushln(); @@ -518,10 +518,11 @@ private Path reportBuildArtifacts(String imageName, Map return ReportUtils.report("build artifacts", buildDir.resolve(imageName + ".build_artifacts.txt"), writerConsumer, !isEnabled); } - private void printResourceStats(double totalSeconds) { + private void printResourceStats() { + double totalProcessTimeSeconds = millisToSeconds(System.currentTimeMillis() - ManagementFactory.getRuntimeMXBean().getStartTime()); GCStats gcStats = getCurrentGCStats(); double gcSeconds = millisToSeconds(gcStats.totalTimeMillis); - LinePrinter l = l().a("%.1fs (%.1f%% of total time) in %d ", gcSeconds, gcSeconds / totalSeconds * 100, gcStats.totalCount) + LinePrinter l = l().a("%.1fs (%.1f%% of total time) in %d ", gcSeconds, gcSeconds / totalProcessTimeSeconds * 100, gcStats.totalCount) .doclink("GCs", "#glossary-garbage-collections"); long peakRSS = ProgressReporterCHelper.getPeakRSS(); if (peakRSS >= 0) { @@ -530,7 +531,7 @@ private void printResourceStats(double totalSeconds) { OperatingSystemMXBean osMXBean = ManagementFactory.getOperatingSystemMXBean(); long processCPUTime = ((com.sun.management.OperatingSystemMXBean) osMXBean).getProcessCpuTime(); if (processCPUTime > 0) { - l.a(" | ").doclink("CPU load", "#glossary-cpu-load").a(": ").a("~%.2f%%", nanosToSeconds(processCPUTime) / totalSeconds * 100); + l.a(" | ").doclink("CPU load", "#glossary-cpu-load").a(": ").a("%.2f", nanosToSeconds(processCPUTime) / totalProcessTimeSeconds); } l.flushCenteredln(); } From 55bf6c4daab1776ecd9d1e3b946f6b0ba267ff7d Mon Sep 17 00:00:00 2001 From: Fabio Niephaus Date: Thu, 9 Dec 2021 21:27:11 +0100 Subject: [PATCH 05/17] Improve image statistics. --- .../native-image/BuildOutput.md | 45 ++++++++++--------- .../hosted/reporting/ProgressReporter.java | 32 ++++++------- 2 files changed, 41 insertions(+), 36 deletions(-) diff --git a/docs/reference-manual/native-image/BuildOutput.md b/docs/reference-manual/native-image/BuildOutput.md index 0d2e0ac00e80..767db96d870f 100644 --- a/docs/reference-manual/native-image/BuildOutput.md +++ b/docs/reference-manual/native-image/BuildOutput.md @@ -9,49 +9,52 @@ permalink: /reference-manual/native-image/BuildOutput/ This page provides documentation for the build output of GraalVM Native Image. ## HelloWorld Example Output -``` +```text ================================================================================ GraalVM Native Image: Generating 'helloworld'... ================================================================================ -[1/7] Initializing... (2.1s @ 0.19GB) +[1/7] Initializing... (2.5s @ 0.21GB) Version info: 'GraalVM dev Java 11 CE' -[2/7] Performing analysis... [*******] (5.7s @ 0.47GB) +[2/7] Performing analysis... [*******] (5.6s @ 0.46GB) 2,565 (82.61%) of 3,105 classes reachable 3,216 (60.42%) of 5,323 fields reachable - 11,653 (72.44%) of 16,087 methods reachable + 11,652 (72.44%) of 16,086 methods reachable 27 classes, 0 fields, and 135 methods registered for reflection 57 classes, 59 fields, and 51 methods registered for JNI access -[3/7] Building universe... (0.4s @ 0.63GB) -[4/7] Parsing methods... [*] (0.4s @ 0.83GB) -[5/7] Inlining methods... [****] (0.4s @ 0.67GB) -[6/7] Compiling methods... [**] (3.4s @ 1.38GB) -[7/7] Creating image... (0.8s @ 1.65GB) - 10.52MB in total (35.1% code area, 55.7% image heap, and 9.3% other data) - 3.69MB for code area: 6,955 compilation units - 5.86MB for image heap: 1,545 classes and 81,111 objects - 997.09KB for other data +[3/7] Building universe... (0.5s @ 0.61GB) +[4/7] Parsing methods... [*] (0.5s @ 0.86GB) +[5/7] Inlining methods... [****] (0.5s @ 0.73GB) +[6/7] Compiling methods... [**] (3.7s @ 2.38GB) +[7/7] Creating image... (2.1s @ 1.04GB) + 3.69MB (27.19%) for code area: 6,955 compilation units + 5.86MB (43.18%) for image heap: 1,545 classes and 80,528 objects + 3.05MB (22.46%) for debug info generated in 1.0s + 997.25KB ( 7.18%) for other data + 13.57MB in total -------------------------------------------------------------------------------- Top 10 packages in code area: Top 10 object types in image heap: - 606.11KB java.util 1.64MB byte[] for general heap data - 282.34KB java.lang 718.09KB java.lang.String + 606.23KB java.util 1.64MB byte[] for general heap data + 282.34KB java.lang 715.56KB java.lang.String 222.47KB java.util.regex 549.46KB java.lang.Class - 219.55KB java.text 454.06KB byte[] for java.lang.String + 219.55KB java.text 451.79KB byte[] for java.lang.String 193.17KB com.oracle.svm.jni 363.23KB java.util.HashMap$Node - 149.80KB java.util.concurrent 192.11KB java.util.HashMap$Node[] - 118.09KB java.math 139.04KB char[] - 103.60KB com.oracle.svm.core.reflect 136.48KB java.lang.String[] + 149.80KB java.util.concurrent 192.00KB java.util.HashMap$Node[] + 118.07KB java.math 139.83KB java.lang.String[] + 103.60KB com.oracle.svm.core.reflect 139.04KB char[] 97.83KB sun.text.normalizer 130.59KB j.u.c.ConcurrentHashMap$Node 88.78KB c.oracle.svm.core.genscavenge 103.92KB s.u.l.LocaleObjec~e$CacheEntry ... 111 additional packages ... 723 additional object types (use GraalVM Dashboard to see all) -------------------------------------------------------------------------------- - 0.8s (5.4% of total time) in 17 GCs | Peak RSS: 2.60GB | CPU load: 11.83 + 0.9s (5.6% of total time) in 17 GCs | Peak RSS: 3.22GB | CPU load: 10.87 -------------------------------------------------------------------------------- Produced artifacts: /home/janedoe/helloworld/helloworld (executable) + /home/janedoe/helloworld/sources (debug_info) + /home/janedoe/helloworld/helloworld (debug_info) /home/janedoe/helloworld/helloworld.build_artifacts.txt ================================================================================ -Finished generating 'helloworld' in 14.0s. +Finished generating 'helloworld' in 16.2s. ``` ## Build Stages diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/reporting/ProgressReporter.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/reporting/ProgressReporter.java index afeb82148dca..7ea782317917 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/reporting/ProgressReporter.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/reporting/ProgressReporter.java @@ -349,22 +349,24 @@ public void setDebugInfoTimer(Timer timer) { public void printCreationEnd(Timer creationTimer, Timer writeTimer, int imageSize, AnalysisUniverse universe, int numHeapObjects, long imageHeapSize, int codeCacheSize, int numCompilations, int debugInfoSize) { printStageEnd(creationTimer.getTotalTime() + writeTimer.getTotalTime()); - String total = bytesToHuman("%4.2f", imageSize); - long otherBytes = imageSize - codeCacheSize - imageHeapSize; - l().a("%9s in total (%.1f%% ", total, codeCacheSize / (double) imageSize * 100).doclink("code area", "#glossary-code-area") - .a(", %.1f%% ", imageHeapSize / (double) imageSize * 100).doclink("image heap", "#glossary-image-heap") - .a(", and %.1f%% ", otherBytes / (double) imageSize * 100).doclink("other data", "#glossary-other-data").a(")").flushln(); - l().a("%9s for code area:%,9d compilation units", bytesToHuman("%4.2f", codeCacheSize), numCompilations).flushln(); + String format = "%9s (%5.2f%%) for "; + l().a(format, bytesToHuman(codeCacheSize), codeCacheSize / (double) imageSize * 100) + .doclink("code area", "#glossary-code-area").a(":%,9d compilation units", numCompilations).flushln(); long numInstantiatedClasses = universe.getTypes().stream().filter(t -> t.isInstantiated()).count(); - l().a("%9s for image heap:%,8d classes and %,d objects", bytesToHuman("%4.2f", imageHeapSize), numInstantiatedClasses, numHeapObjects).flushln(); + l().a(format, bytesToHuman(imageHeapSize), imageHeapSize / (double) imageSize * 100) + .doclink("image heap", "#glossary-image-heap").a(":%,8d classes and %,d objects", numInstantiatedClasses, numHeapObjects).flushln(); if (debugInfoSize > 0) { - l().a("%9s in debugInfo size", bytesToHuman("%4.2f", debugInfoSize)).flushln(); - } - l().a("%9s for other data", bytesToHuman("%4.2f", otherBytes)).flushln(); - if (debugInfoTimer != null) { - String debugInfoTime = String.format("%.1fs", millisToSeconds(debugInfoTimer.getTotalTime())); - l().dim().a("%9s for generating debug info", debugInfoTime).reset().flushln(); + LinePrinter l = l().a(format, bytesToHuman(debugInfoSize), debugInfoSize / (double) imageSize * 100) + .doclink("debug info", "#glossary-debug-info"); + if (debugInfoTimer != null) { + l.a(" generated in %.1fs", millisToSeconds(debugInfoTimer.getTotalTime())); + } + l.flushln(); } + long otherBytes = imageSize - codeCacheSize - imageHeapSize - debugInfoSize; + l().a(format, bytesToHuman(otherBytes), otherBytes / (double) imageSize * 100) + .doclink("other data", "#glossary-other-data").flushln(); + l().a("%9s in total", bytesToHuman(imageSize)).flushln(); } public void printBreakdowns(Collection compilationTasks, Collection heapObjects) { @@ -387,7 +389,7 @@ public void printBreakdowns(Collection compilationTasks, Collection if (packagesBySize.hasNext()) { Entry e = packagesBySize.next(); String className = truncateClassOrPackageName(e.getKey()); - codeSizePart = String.format("%9s %s", bytesToHuman("%4.2f", e.getValue()), className); + codeSizePart = String.format("%9s %s", bytesToHuman(e.getValue()), className); printedCodeSizeEntries.add(e); } @@ -675,7 +677,7 @@ private static double getUsedMemory() { } private static String bytesToHuman(long bytes) { - return bytesToHuman("%.2f", bytes); + return bytesToHuman("%4.2f", bytes); } private static String bytesToHuman(String format, long bytes) { From 1f3678779ab2bf65eef4301dc2162233b1d656eb Mon Sep 17 00:00:00 2001 From: Fabio Niephaus Date: Thu, 9 Dec 2021 21:29:52 +0100 Subject: [PATCH 06/17] Fix indentation in Truffle changelog. --- truffle/CHANGELOG.md | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/truffle/CHANGELOG.md b/truffle/CHANGELOG.md index 131c7859a5da..5ba98140dc72 100644 --- a/truffle/CHANGELOG.md +++ b/truffle/CHANGELOG.md @@ -34,17 +34,17 @@ No active inner context is allowed after `TruffleLanguage.finalizeContext(Object * Removed many deprecated methods in `TruffleLanguage`, `TruffleLanguage.Env` and `TruffleInstrument.Env`. All of which were already deprecated for at least four releases. * Removed deprecated `GraphPrintVisitor`. * Added new APIs to `com.oracle.truffle.api.frame.Frame` and `com.oracle.truffle.api.frame.FrameDescriptor`: - * Added a new "namespace" of index-based slots in `Frame` that is defined during construction of the frame descriptor and cannot be changed afterwards, and that is accessed using `int` indexes instead of `FrameSlot`s. - * Added a second new "namespace" of slots (called auxiliary slots) in `Frame` that can be added to the frame descriptor dynamically (and which only supports "object" slots). - * In addition to `get.../set...` methods, the new API also supports `copy` and `swap` of frame slots. - * The `FrameSlot`-based API methods in `Frame` and `FrameDescriptor` were deprecated. - * `FrameSlotTypeException` is now an unchecked exception, which simplifies many APIs and removes the need for the `FrameUtil` class. + * Added a new "namespace" of index-based slots in `Frame` that is defined during construction of the frame descriptor and cannot be changed afterwards, and that is accessed using `int` indexes instead of `FrameSlot`s. + * Added a second new "namespace" of slots (called auxiliary slots) in `Frame` that can be added to the frame descriptor dynamically (and which only supports "object" slots). + * In addition to `get.../set...` methods, the new API also supports `copy` and `swap` of frame slots. + * The `FrameSlot`-based API methods in `Frame` and `FrameDescriptor` were deprecated. + * `FrameSlotTypeException` is now an unchecked exception, which simplifies many APIs and removes the need for the `FrameUtil` class. * Changes to the way frame slots are handled during partial evaluation: - * Removed the `FrameClearPhase` - now clearing the frame slots in the "clear" intrinsics instead. - * Added a new `FrameAccessVerificationPhase` that detects improper pairing of frame slot types at merges, inserts deopts and outputs a performance warning: frame slots can now change type freely and will still be optimized by the frame intrinsics optimization, as long as the types are compatible at merges (whereas frame slots used to be restricted to one primitive type in the whole compilation unit). + * Removed the `FrameClearPhase` - now clearing the frame slots in the "clear" intrinsics instead. + * Added a new `FrameAccessVerificationPhase` that detects improper pairing of frame slot types at merges, inserts deopts and outputs a performance warning: frame slots can now change type freely and will still be optimized by the frame intrinsics optimization, as long as the types are compatible at merges (whereas frame slots used to be restricted to one primitive type in the whole compilation unit). * Made conversion rules for passing values to native code through the Truffle NFI more lenient. - * Passing a `double` to a parameter of type `float` is allowed, possibly losing precision. - * Passing signed integers to parameters of type `uint*` and unsigned integers to parameters of type `sint*` is allowed. + * Passing a `double` to a parameter of type `float` is allowed, possibly losing precision. + * Passing signed integers to parameters of type `uint*` and unsigned integers to parameters of type `sint*` is allowed. ## Version 21.3.0 * Added a `@GenerateWrapper.Ignore` annotation to prevent methods from being instrumented in wrapper classes. From 0a1b5e7881844c9081c7e24bcedc850cd0ee0e03 Mon Sep 17 00:00:00 2001 From: Fabio Niephaus Date: Thu, 9 Dec 2021 21:58:24 +0100 Subject: [PATCH 07/17] Fix reported image build time. --- .../src/com/oracle/svm/hosted/reporting/ProgressReporter.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/reporting/ProgressReporter.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/reporting/ProgressReporter.java index 7ea782317917..3361a68d1666 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/reporting/ProgressReporter.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/reporting/ProgressReporter.java @@ -484,7 +484,7 @@ public void printEpilog(String imageName, NativeImageGenerator generator, boolea if (totalSeconds < 60) { timeStats = String.format("%.1fs", totalSeconds); } else { - timeStats = String.format("%.0fm %.0fs", totalSeconds / 60, totalSeconds % 60); + timeStats = String.format("%dm %ds", (int) totalSeconds / 60, (int) totalSeconds % 60); } l().a(wasSuccessfulBuild ? "Finished" : "Failed").a(" generating '").bold().a(imageName).reset().a("' ") .a(wasSuccessfulBuild ? "in" : "after").a(" ").a(timeStats).a(".").flushln(); From 721e3cac7b7e5eddde408d251f09b2dcbd25d1a3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Paul=20W=C3=B6gerer?= Date: Tue, 14 Dec 2021 10:53:09 +0100 Subject: [PATCH 08/17] Use NativeImageSystemIOWrappers for image builder System.out and err usage and adjust ProgressReporter to suppress output between `...` and (X.Xs @ X.XXGB). --- .../svm/core/jdk/SystemInOutErrSupport.java | 123 ++---------------- .../hosted/NativeImageSystemClassLoader.java | 11 ++ .../hosted/NativeImageSystemIOWrappers.java | 111 ++++++++++++++++ .../svm/hosted/jdk/SystemInOutErrFeature.java | 75 +++++++++++ .../hosted/reporting/ProgressReporter.java | 40 +++--- 5 files changed, 229 insertions(+), 131 deletions(-) create mode 100644 substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/NativeImageSystemIOWrappers.java create mode 100644 substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/jdk/SystemInOutErrFeature.java diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/SystemInOutErrSupport.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/SystemInOutErrSupport.java index 6d944cc27a82..a6905d33d28c 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/SystemInOutErrSupport.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/SystemInOutErrSupport.java @@ -26,11 +26,9 @@ import java.io.BufferedInputStream; import java.io.BufferedOutputStream; -import java.io.ByteArrayOutputStream; import java.io.FileDescriptor; import java.io.FileInputStream; import java.io.FileOutputStream; -import java.io.IOException; import java.io.InputStream; import java.io.PrintStream; import java.io.UnsupportedEncodingException; @@ -39,10 +37,6 @@ import org.graalvm.nativeimage.ImageSingletons; import org.graalvm.nativeimage.hosted.Feature; -import com.oracle.svm.core.annotate.AutomaticFeature; -import com.oracle.svm.core.annotate.RecomputeFieldValue; -import com.oracle.svm.core.util.VMError; - /** * This class provides replacement values for the {@link System#in}, {@link System#out}, and * {@link System#err} streams at run time. We want a fresh set of objects, so that any buffers @@ -54,22 +48,9 @@ * static analysis starts, i.e., in a {@link Feature#beforeAnalysis} method. */ public final class SystemInOutErrSupport { - // Checkstyle: stop - private final PrintStream outOriginal = System.out; - private final CapturingStdioWrapper outWrapper = new CapturingStdioWrapper(outOriginal, new ByteArrayOutputStream(128)); - private final CapturingStdioWrapper errWrapper = new CapturingStdioWrapper(System.err, new ByteArrayOutputStream(128)); - // Checkstyle: resume - private InputStream in = new BufferedInputStream(new FileInputStream(FileDescriptor.in)); private PrintStream out = newPrintStream(new FileOutputStream(FileDescriptor.out), System.getProperty("sun.stdout.encoding")); private PrintStream err = newPrintStream(new FileOutputStream(FileDescriptor.err), System.getProperty("sun.stderr.encoding")); - private boolean isCapturing; - - public SystemInOutErrSupport() { - /* Install stdout and stderr wrappers. */ - System.setOut(outWrapper); - System.setErr(errWrapper); - } /* Create `PrintStream` in the same way as `System.newPrintStream`. */ private static PrintStream newPrintStream(FileOutputStream fos, String enc) { @@ -82,107 +63,27 @@ private static PrintStream newPrintStream(FileOutputStream fos, String enc) { return new PrintStream(new BufferedOutputStream(fos, 128), true); } - public static void setIn(InputStream in) { - ImageSingletons.lookup(SystemInOutErrSupport.class).in = Objects.requireNonNull(in); + public static InputStream in() { + return ImageSingletons.lookup(SystemInOutErrSupport.class).in; } - public static void setOut(PrintStream out) { - ImageSingletons.lookup(SystemInOutErrSupport.class).out = Objects.requireNonNull(out); - } - - public static void setErr(PrintStream err) { - ImageSingletons.lookup(SystemInOutErrSupport.class).err = Objects.requireNonNull(err); - } - - public static void setCapturing(boolean value) { - ImageSingletons.lookup(SystemInOutErrSupport.class).isCapturing = value; + public static void setIn(InputStream in) { + ImageSingletons.lookup(SystemInOutErrSupport.class).in = Objects.requireNonNull(in); } - public static void flushCapturedContent() { - ImageSingletons.lookup(SystemInOutErrSupport.class).outWrapper.flushCapturedContent(); - ImageSingletons.lookup(SystemInOutErrSupport.class).errWrapper.flushCapturedContent(); + public static PrintStream out() { + return ImageSingletons.lookup(SystemInOutErrSupport.class).out; } - public static void printToStdOutUnconditionally(char value) { - ImageSingletons.lookup(SystemInOutErrSupport.class).outOriginal.print(value); + public static void setOut(PrintStream out) { + ImageSingletons.lookup(SystemInOutErrSupport.class).out = Objects.requireNonNull(out); } - // Checkstyle: stop - Object replaceStreams(Object object) { - assert System.out == outWrapper && System.err == errWrapper : "stdio handles are not allowed to change during image construction"; - if (object == System.in) { - return in; - } else if (object == System.out) { - return out; - } else if (object == System.err) { - return err; - } else { - return object; - } + public static PrintStream err() { + return ImageSingletons.lookup(SystemInOutErrSupport.class).err; } - // Checkstyle: resume - /** Wrapper with the ability to temporarily capture output to stdout and stderr. */ - final class CapturingStdioWrapper extends PrintStream { - private final ByteArrayOutputStream buffer; - private final PrintStream delegate; - - CapturingStdioWrapper(PrintStream delegate, ByteArrayOutputStream buffer) { - super(buffer); - this.buffer = buffer; - this.delegate = delegate; - } - - @Override - public void write(int b) { - if (isCapturing) { - super.write(b); - } else { - delegate.write(b); - } - } - - @Override - public void write(byte[] buf, int off, int len) { - if (isCapturing) { - super.write(buf, off, len); - } else { - delegate.write(buf, off, len); - } - } - - @Override - public void write(byte[] buf) throws IOException { - if (isCapturing) { - super.write(buf); - } else { - delegate.write(buf); - } - } - - void flushCapturedContent() { - try { - delegate.write(buffer.toByteArray()); - } catch (IOException e) { - throw VMError.shouldNotReachHere(); - } - buffer.reset(); - } - } -} - -/** - * We use an {@link Feature.DuringSetupAccess#registerObjectReplacer object replacer} because the - * streams can be cached in other instance and static fields in addition to the fields in - * {@link System}. We do not know all these places, so we do now know where to place - * {@link RecomputeFieldValue} annotations. - */ -@AutomaticFeature -class SystemInOutErrFeature implements Feature { - @Override - public void duringSetup(DuringSetupAccess access) { - SystemInOutErrSupport support = new SystemInOutErrSupport(); - ImageSingletons.add(SystemInOutErrSupport.class, support); - access.registerObjectReplacer(support::replaceStreams); + public static void setErr(PrintStream err) { + ImageSingletons.lookup(SystemInOutErrSupport.class).err = Objects.requireNonNull(err); } } diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/NativeImageSystemClassLoader.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/NativeImageSystemClassLoader.java index ea341219dcbc..43f249a31e22 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/NativeImageSystemClassLoader.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/NativeImageSystemClassLoader.java @@ -52,6 +52,9 @@ public final class NativeImageSystemClassLoader extends SecureClassLoader { public final ClassLoader defaultSystemClassLoader; + + NativeImageSystemIOWrappers systemIOWrappers; + private volatile ClassLoader nativeImageClassLoader = null; private Set disallowedClassLoaders = Collections.newSetFromMap(new WeakHashMap<>()); @@ -59,6 +62,13 @@ public final class NativeImageSystemClassLoader extends SecureClassLoader { public NativeImageSystemClassLoader(ClassLoader defaultSystemClassLoader) { super(defaultSystemClassLoader); this.defaultSystemClassLoader = defaultSystemClassLoader; + resetSystemIOWrappers(); + } + + private void resetSystemIOWrappers() { + systemIOWrappers = new NativeImageSystemIOWrappers(); + /* Image building console output requires custom System.out and System.err */ + systemIOWrappers.replaceSystemOutErr(); } public static NativeImageSystemClassLoader singleton() { @@ -243,4 +253,5 @@ private void appendToClassPathForInstrumentation(String classPathEntry) { VMError.shouldNotReachHere(message, e); } } + } diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/NativeImageSystemIOWrappers.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/NativeImageSystemIOWrappers.java new file mode 100644 index 000000000000..eac8df2cf518 --- /dev/null +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/NativeImageSystemIOWrappers.java @@ -0,0 +1,111 @@ +/* + * Copyright (c) 2021, 2021, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package com.oracle.svm.hosted; + +import java.io.ByteArrayOutputStream; +import java.io.PrintStream; + +import com.oracle.svm.core.util.VMError; + +public class NativeImageSystemIOWrappers { + + private final CapturingStdioWrapper outWrapper; + private final CapturingStdioWrapper errWrapper; + + public boolean useCapturing; + + NativeImageSystemIOWrappers() { + outWrapper = new CapturingStdioWrapper(System.out, new ByteArrayOutputStream(128)); + errWrapper = new CapturingStdioWrapper(System.err, new ByteArrayOutputStream(128)); + useCapturing = false; + } + + public static NativeImageSystemIOWrappers singleton() { + return NativeImageSystemClassLoader.singleton().systemIOWrappers; + } + + public void verifySystemOutErrReplacement() { + String msg = " was changed during image building. This is not allowed."; + VMError.guarantee(System.out == outWrapper, "System.out" + msg); + VMError.guarantee(System.err == errWrapper, "System.err" + msg); + } + + public PrintStream originalOut() { + return outWrapper.delegate; + } + + public PrintStream originalErr() { + return errWrapper.delegate; + } + + public void flushCapturedContent() { + outWrapper.flushCapturedContent(); + errWrapper.flushCapturedContent(); + } + + void replaceSystemOutErr() { + System.setOut(outWrapper); + System.setErr(errWrapper); + } + + /** + * Wrapper with the ability to temporarily capture output to stdout and stderr. + */ + private final class CapturingStdioWrapper extends PrintStream { + private final ByteArrayOutputStream buffer; + private final PrintStream delegate; + + private CapturingStdioWrapper(PrintStream delegate, ByteArrayOutputStream buffer) { + super(buffer); + this.buffer = buffer; + this.delegate = delegate; + } + + @Override + public void write(int b) { + if (useCapturing) { + super.write(b); + } else { + delegate.write(b); + } + } + + @Override + public void write(byte[] buf, int off, int len) { + if (useCapturing) { + super.write(buf, off, len); + } else { + delegate.write(buf, off, len); + } + } + + private void flushCapturedContent() { + byte[] byteArray = buffer.toByteArray(); + delegate.write(byteArray, 0, byteArray.length); + buffer.reset(); + } + } +} diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/jdk/SystemInOutErrFeature.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/jdk/SystemInOutErrFeature.java new file mode 100644 index 000000000000..d71758f9bea2 --- /dev/null +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/jdk/SystemInOutErrFeature.java @@ -0,0 +1,75 @@ +/* + * Copyright (c) 2021, 2021, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package com.oracle.svm.hosted.jdk; + +import java.io.InputStream; +import java.io.PrintStream; + +import org.graalvm.nativeimage.ImageSingletons; +import org.graalvm.nativeimage.hosted.Feature; + +import com.oracle.svm.core.annotate.AutomaticFeature; +import com.oracle.svm.core.annotate.RecomputeFieldValue; +import com.oracle.svm.core.jdk.SystemInOutErrSupport; +import com.oracle.svm.hosted.NativeImageSystemIOWrappers; + +/** + * We use an {@link Feature.DuringSetupAccess#registerObjectReplacer object replacer} because the + * streams can be cached in other instance and static fields in addition to the fields in + * {@link System}. We do not know all these places, so we do now know where to place + * {@link RecomputeFieldValue} annotations. + */ +@AutomaticFeature +public class SystemInOutErrFeature implements Feature { + private final InputStream hostedIn = System.in; + private final PrintStream hostedOut = System.out; + private final PrintStream hostedErr = System.err; + + @Override + public void duringSetup(DuringSetupAccess access) { + NativeImageSystemIOWrappers.singleton().verifySystemOutErrReplacement(); + + ImageSingletons.add(SystemInOutErrSupport.class, new SystemInOutErrSupport()); + access.registerObjectReplacer(this::replaceStreams); + } + + @Override + public void cleanup() { + NativeImageSystemIOWrappers.singleton().verifySystemOutErrReplacement(); + } + + Object replaceStreams(Object object) { + if (object == hostedIn) { + return SystemInOutErrSupport.in(); + } else if (object == hostedOut) { + return SystemInOutErrSupport.out(); + } else if (object == hostedErr) { + return SystemInOutErrSupport.err(); + } else { + return object; + } + } +} diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/reporting/ProgressReporter.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/reporting/ProgressReporter.java index 3361a68d1666..c286a6f7c866 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/reporting/ProgressReporter.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/reporting/ProgressReporter.java @@ -63,10 +63,10 @@ import com.oracle.svm.core.SubstrateOptions; import com.oracle.svm.core.VM; import com.oracle.svm.core.annotate.AutomaticFeature; -import com.oracle.svm.core.jdk.SystemInOutErrSupport; import com.oracle.svm.core.option.HostedOptionValues; import com.oracle.svm.core.reflect.MethodMetadataDecoder; import com.oracle.svm.hosted.NativeImageGenerator; +import com.oracle.svm.hosted.NativeImageSystemIOWrappers; import com.oracle.svm.hosted.StringAccess; import com.oracle.svm.hosted.code.CompileQueue.CompileTask; import com.oracle.svm.hosted.image.NativeImageHeap.ObjectInfo; @@ -92,6 +92,8 @@ public class ProgressReporter { private static final double BYTES_TO_MiB = 1024d * 1024d; private static final double BYTES_TO_GiB = 1024d * 1024d * 1024d; + private final NativeImageSystemIOWrappers builderIO; + private final boolean isEnabled; private final LinePrinter linePrinter; private final boolean usePrefix; @@ -137,6 +139,8 @@ public static ProgressReporter singleton() { } public ProgressReporter(OptionValues options) { + builderIO = NativeImageSystemIOWrappers.singleton(); + isEnabled = SubstrateOptions.BuildOutputUseNewStyle.getValue(options); if (isEnabled) { Timer.disablePrinting(); @@ -240,7 +244,7 @@ public ReporterClosable printAnalysis(BigBang bb) { public void closeAction() { timer.stop(); printProgressEnd(); - printStageEndAndFlushStdioContent(bb.getAnalysisTimer()); + printStageEnd(bb.getAnalysisTimer()); String actualVsTotalFormat = "%,8d (%5.2f%%) of %,6d"; long reachableClasses = bb.getUniverse().getTypes().stream().filter(t -> t.isReachable()).count(); long totalClasses = bb.getUniverse().getTypes().size(); @@ -296,7 +300,7 @@ public void closeAction() { timer.stop(); stopPeriodicPrinting(); printProgressEnd(); - printStageEndAndFlushStdioContent(timer); + printStageEnd(timer); } }; } @@ -310,7 +314,7 @@ public ReporterClosable printInlining(Timer timer) { public void closeAction() { timer.stop(); printProgressEnd(); - printStageEndAndFlushStdioContent(timer); + printStageEnd(timer); } }; } @@ -332,7 +336,7 @@ public void closeAction() { timer.stop(); stopPeriodicPrinting(); printProgressEnd(); - printStageEndAndFlushStdioContent(timer); + printStageEnd(timer); } }; } @@ -546,13 +550,13 @@ private void printStageStart(BuildStage stage) { .doclink(stage.message, "#stage-" + stage.name().toLowerCase()).a("...").reset(); numStageChars = linePrinter.getCurrentTextLength(); linePrinter.flush(); + builderIO.useCapturing = true; } private void printProgressStart() { linePrinter.a(progressBarStartPadding()).dim().a("["); numStageChars = PROGRESS_BAR_START + 1; /* +1 for [ */ linePrinter.flush(); - SystemInOutErrSupport.setCapturing(true); } private String progressBarStartPadding() { @@ -560,8 +564,7 @@ private String progressBarStartPadding() { } private void printProgressEnd() { - SystemInOutErrSupport.setCapturing(false); - linePrinter.a("]").reset().flush(); + linePrinter.printRaw(']'); numStageChars++; // for ] } @@ -589,11 +592,6 @@ private void stopPeriodicPrinting() { periodicPrintingTask.cancel(false); } - private void printStageEndAndFlushStdioContent(Timer timer) { - printStageEnd(timer); - SystemInOutErrSupport.flushCapturedContent(); - } - private void printStageEnd(Timer timer) { printStageEnd(timer.getTotalTime()); } @@ -607,6 +605,8 @@ private void printStageEnd(double totalTime) { if (SubstrateOptions.BuildOutputGCWarnings.getValue()) { checkForExcessiveGarbageCollection(); } + builderIO.useCapturing = false; + builderIO.flushCapturedContent(); } private void checkForExcessiveGarbageCollection() { @@ -632,7 +632,7 @@ private void checkForExcessiveGarbageCollection() { */ private static void resetANSIMode() { - System.out.print(ANSIColors.RESET); + NativeImageSystemIOWrappers.singleton().originalOut().print(ANSIColors.RESET); } private static String stringFilledWith(int size, String fill) { @@ -832,7 +832,7 @@ private void flush() { if (printBuffer != null) { textBuffer.forEach(printBuffer::append); } else { - textBuffer.forEach(System.out::print); + textBuffer.forEach(builderIO.originalOut()::print); } textBuffer.clear(); } @@ -844,7 +844,7 @@ private void printRaw(char value) { if (printBuffer != null) { printBuffer.append(value); } else { - SystemInOutErrSupport.printToStdOutUnconditionally(value); + builderIO.originalOut().print(value); } } @@ -857,15 +857,15 @@ private void flushln(boolean useOutputPrefix) { return; } if (useOutputPrefix) { - System.out.print(outputPrefix); + builderIO.originalOut().print(outputPrefix); } if (printBuffer != null) { - System.out.print(printBuffer.toString()); + builderIO.originalOut().print(printBuffer); printBuffer.setLength(0); // Clear buffer. } - textBuffer.forEach(System.out::print); + textBuffer.forEach(builderIO.originalOut()::print); textBuffer.clear(); - System.out.println(); + builderIO.originalOut().println(); } private void flushCenteredln() { From 51f7cd41662cc26decdacb83ebbe629d02c60591 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Paul=20W=C3=B6gerer?= Date: Tue, 14 Dec 2021 16:52:52 +0100 Subject: [PATCH 09/17] Ensure error reporting works with ProgressReporter --- .../hosted/NativeImageGeneratorRunner.java | 200 +++++++++--------- .../hosted/reporting/ProgressReporter.java | 10 +- 2 files changed, 112 insertions(+), 98 deletions(-) diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/NativeImageGeneratorRunner.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/NativeImageGeneratorRunner.java index a962208e9f2d..362e763877d4 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/NativeImageGeneratorRunner.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/NativeImageGeneratorRunner.java @@ -313,117 +313,125 @@ private int buildImage(ImageClassLoader classLoader) { if (imageName.length() == 0) { throw UserError.abort("No output file name specified. Use '%s'.", SubstrateOptionsParser.commandArgument(SubstrateOptions.Name, "")); } - reporter.printStart(imageName); - - totalTimer.setPrefix(imageName); - classlistTimer.setPrefix(imageName); - - // print the time here to avoid interactions with flags processing - classlistTimer.print(); - - Map entryPoints = new HashMap<>(); - Pair mainEntryPointData = Pair.empty(); - JavaMainSupport javaMainSupport = null; - - NativeImageKind imageKind; - boolean isStaticExecutable = SubstrateOptions.StaticExecutable.getValue(parsedHostedOptions); - boolean isSharedLibrary = SubstrateOptions.SharedLibrary.getValue(parsedHostedOptions); - if (isStaticExecutable && isSharedLibrary) { - throw UserError.abort("Cannot pass both option: %s and %s", SubstrateOptionsParser.commandArgument(SubstrateOptions.SharedLibrary, "+"), - SubstrateOptionsParser.commandArgument(SubstrateOptions.StaticExecutable, "+")); - } else if (isSharedLibrary) { - imageKind = NativeImageKind.SHARED_LIBRARY; - } else if (isStaticExecutable) { - imageKind = NativeImageKind.STATIC_EXECUTABLE; - } else { - imageKind = NativeImageKind.EXECUTABLE; - } + try { + reporter.printStart(imageName); + + totalTimer.setPrefix(imageName); + classlistTimer.setPrefix(imageName); + + // print the time here to avoid interactions with flags processing + classlistTimer.print(); + + Map entryPoints = new HashMap<>(); + Pair mainEntryPointData = Pair.empty(); + JavaMainSupport javaMainSupport = null; + + NativeImageKind imageKind; + boolean isStaticExecutable = SubstrateOptions.StaticExecutable.getValue(parsedHostedOptions); + boolean isSharedLibrary = SubstrateOptions.SharedLibrary.getValue(parsedHostedOptions); + if (isStaticExecutable && isSharedLibrary) { + throw UserError.abort("Cannot pass both option: %s and %s", SubstrateOptionsParser.commandArgument(SubstrateOptions.SharedLibrary, "+"), + SubstrateOptionsParser.commandArgument(SubstrateOptions.StaticExecutable, "+")); + } else if (isSharedLibrary) { + imageKind = NativeImageKind.SHARED_LIBRARY; + } else if (isStaticExecutable) { + imageKind = NativeImageKind.STATIC_EXECUTABLE; + } else { + imageKind = NativeImageKind.EXECUTABLE; + } - String className = SubstrateOptions.Class.getValue(parsedHostedOptions); - String moduleName = SubstrateOptions.Module.getValue(parsedHostedOptions); - if (imageKind.isExecutable && moduleName.isEmpty() && className.isEmpty()) { - throw UserError.abort("Must specify main entry point class when building %s native image. Use '%s'.", imageKind, - SubstrateOptionsParser.commandArgument(SubstrateOptions.Class, "")); - } + String className = SubstrateOptions.Class.getValue(parsedHostedOptions); + String moduleName = SubstrateOptions.Module.getValue(parsedHostedOptions); + if (imageKind.isExecutable && moduleName.isEmpty() && className.isEmpty()) { + throw UserError.abort("Must specify main entry point class when building %s native image. Use '%s'.", imageKind, + SubstrateOptionsParser.commandArgument(SubstrateOptions.Class, "")); + } - if (!className.isEmpty() || !moduleName.isEmpty()) { - Method mainEntryPoint; - Class mainClass; - try { - Object mainModule = null; - if (!moduleName.isEmpty()) { - mainModule = classLoader.findModule(moduleName) - .orElseThrow(() -> UserError.abort("Module " + moduleName + " for mainclass not found.")); - } - if (className.isEmpty()) { - className = classLoader.getMainClassFromModule(mainModule) - .orElseThrow(() -> UserError.abort("module %s does not have a ModuleMainClass attribute, use -m /", moduleName)); - } - mainClass = classLoader.forName(className, mainModule); - if (mainClass == null) { + if (!className.isEmpty() || !moduleName.isEmpty()) { + Method mainEntryPoint; + Class mainClass; + try { + Object mainModule = null; + if (!moduleName.isEmpty()) { + mainModule = classLoader.findModule(moduleName) + .orElseThrow(() -> UserError.abort("Module " + moduleName + " for mainclass not found.")); + } + if (className.isEmpty()) { + className = classLoader.getMainClassFromModule(mainModule) + .orElseThrow(() -> UserError.abort("module %s does not have a ModuleMainClass attribute, use -m /", moduleName)); + } + mainClass = classLoader.forName(className, mainModule); + if (mainClass == null) { + throw UserError.abort("Main entry point class '%s' not found.", className); + } + } catch (ClassNotFoundException ex) { throw UserError.abort("Main entry point class '%s' not found.", className); } - } catch (ClassNotFoundException ex) { - throw UserError.abort("Main entry point class '%s' not found.", className); - } - String mainEntryPointName = SubstrateOptions.Method.getValue(parsedHostedOptions); - if (mainEntryPointName.isEmpty()) { - throw UserError.abort("Must specify main entry point method when building %s native image. Use '%s'.", imageKind, - SubstrateOptionsParser.commandArgument(SubstrateOptions.Method, "")); - } - try { - /* First look for an main method with the C-level signature for arguments. */ - mainEntryPoint = mainClass.getDeclaredMethod(mainEntryPointName, int.class, CCharPointerPointer.class); - } catch (NoSuchMethodException ignored2) { - Method javaMainMethod; + String mainEntryPointName = SubstrateOptions.Method.getValue(parsedHostedOptions); + if (mainEntryPointName.isEmpty()) { + throw UserError.abort("Must specify main entry point method when building %s native image. Use '%s'.", imageKind, + SubstrateOptionsParser.commandArgument(SubstrateOptions.Method, "")); + } try { /* - * If no C-level main method was found, look for a Java-level main method - * and use our wrapper to invoke it. + * First look for an main method with the C-level signature for arguments. */ - javaMainMethod = ReflectionUtil.lookupMethod(mainClass, mainEntryPointName, String[].class); - } catch (ReflectionUtilError ex) { - throw UserError.abort(ex.getCause(), - "Method '%s.%s' is declared as the main entry point but it can not be found. " + - "Make sure that class '%s' is on the classpath and that method '%s(String[])' exists in that class.", - mainClass.getName(), - mainEntryPointName, - mainClass.getName(), - mainEntryPointName); - } + mainEntryPoint = mainClass.getDeclaredMethod(mainEntryPointName, int.class, CCharPointerPointer.class); + } catch (NoSuchMethodException ignored2) { + Method javaMainMethod; + try { + /* + * If no C-level main method was found, look for a Java-level main + * method and use our wrapper to invoke it. + */ + javaMainMethod = ReflectionUtil.lookupMethod(mainClass, mainEntryPointName, String[].class); + } catch (ReflectionUtilError ex) { + throw UserError.abort(ex.getCause(), + "Method '%s.%s' is declared as the main entry point but it can not be found. " + + "Make sure that class '%s' is on the classpath and that method '%s(String[])' exists in that class.", + mainClass.getName(), + mainEntryPointName, + mainClass.getName(), + mainEntryPointName); + } - if (javaMainMethod.getReturnType() != void.class) { - throw UserError.abort("Java main method '%s.%s(String[])' does not have the return type 'void'.", mainClass.getName(), mainEntryPointName); + if (javaMainMethod.getReturnType() != void.class) { + throw UserError.abort("Java main method '%s.%s(String[])' does not have the return type 'void'.", mainClass.getName(), mainEntryPointName); + } + final int mainMethodModifiers = javaMainMethod.getModifiers(); + if (!Modifier.isStatic(mainMethodModifiers)) { + throw UserError.abort("Java main method '%s.%s(String[])' is not static.", mainClass.getName(), mainEntryPointName); + } + if (!Modifier.isPublic(mainMethodModifiers)) { + throw UserError.abort("Java main method '%s.%s(String[])' is not public.", mainClass.getName(), mainEntryPointName); + } + javaMainSupport = new JavaMainSupport(javaMainMethod); + mainEntryPoint = JavaMainWrapper.class.getDeclaredMethod("run", int.class, CCharPointerPointer.class); } - final int mainMethodModifiers = javaMainMethod.getModifiers(); - if (!Modifier.isStatic(mainMethodModifiers)) { - throw UserError.abort("Java main method '%s.%s(String[])' is not static.", mainClass.getName(), mainEntryPointName); + CEntryPoint annotation = mainEntryPoint.getAnnotation(CEntryPoint.class); + if (annotation == null) { + throw UserError.abort("Entry point must have the '@%s' annotation", CEntryPoint.class.getSimpleName()); } - if (!Modifier.isPublic(mainMethodModifiers)) { - throw UserError.abort("Java main method '%s.%s(String[])' is not public.", mainClass.getName(), mainEntryPointName); + + Class[] pt = mainEntryPoint.getParameterTypes(); + if (pt.length != 2 || pt[0] != int.class || pt[1] != CCharPointerPointer.class || mainEntryPoint.getReturnType() != int.class) { + throw UserError.abort("Main entry point must have signature 'int main(int argc, CCharPointerPointer argv)'."); } - javaMainSupport = new JavaMainSupport(javaMainMethod); - mainEntryPoint = JavaMainWrapper.class.getDeclaredMethod("run", int.class, CCharPointerPointer.class); - } - CEntryPoint annotation = mainEntryPoint.getAnnotation(CEntryPoint.class); - if (annotation == null) { - throw UserError.abort("Entry point must have the '@%s' annotation", CEntryPoint.class.getSimpleName()); + mainEntryPointData = Pair.create(mainEntryPoint, CEntryPointData.create(mainEntryPoint, imageKind.mainEntryPointName)); } - Class[] pt = mainEntryPoint.getParameterTypes(); - if (pt.length != 2 || pt[0] != int.class || pt[1] != CCharPointerPointer.class || mainEntryPoint.getReturnType() != int.class) { - throw UserError.abort("Main entry point must have signature 'int main(int argc, CCharPointerPointer argv)'."); + int maxConcurrentThreads = NativeImageOptions.getMaximumNumberOfConcurrentThreads(parsedHostedOptions); + analysisExecutor = NativeImagePointsToAnalysis.createExecutor(debug, NativeImageOptions.getMaximumNumberOfAnalysisThreads(parsedHostedOptions)); + compilationExecutor = NativeImagePointsToAnalysis.createExecutor(debug, maxConcurrentThreads); + generator = new NativeImageGenerator(classLoader, optionParser, mainEntryPointData, reporter); + generator.run(entryPoints, javaMainSupport, imageName, classlistTimer, imageKind, SubstitutionProcessor.IDENTITY, + compilationExecutor, analysisExecutor, optionParser.getRuntimeOptionNames()); + wasSuccessfulBuild = true; + } finally { + if (!wasSuccessfulBuild) { + reporter.printInitializeEnd(classlistTimer, classlistTimer); } - mainEntryPointData = Pair.create(mainEntryPoint, CEntryPointData.create(mainEntryPoint, imageKind.mainEntryPointName)); } - - int maxConcurrentThreads = NativeImageOptions.getMaximumNumberOfConcurrentThreads(parsedHostedOptions); - analysisExecutor = NativeImagePointsToAnalysis.createExecutor(debug, NativeImageOptions.getMaximumNumberOfAnalysisThreads(parsedHostedOptions)); - compilationExecutor = NativeImagePointsToAnalysis.createExecutor(debug, maxConcurrentThreads); - generator = new NativeImageGenerator(classLoader, optionParser, mainEntryPointData, reporter); - generator.run(entryPoints, javaMainSupport, imageName, classlistTimer, imageKind, SubstitutionProcessor.IDENTITY, - compilationExecutor, analysisExecutor, optionParser.getRuntimeOptionNames()); - wasSuccessfulBuild = true; } catch (InterruptImageBuilding e) { if (analysisExecutor != null) { analysisExecutor.shutdownNow(); diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/reporting/ProgressReporter.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/reporting/ProgressReporter.java index c286a6f7c866..4eccde0f62df 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/reporting/ProgressReporter.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/reporting/ProgressReporter.java @@ -49,6 +49,7 @@ import org.graalvm.compiler.serviceprovider.GraalServices; import org.graalvm.nativeimage.ImageSingletons; import org.graalvm.nativeimage.hosted.Feature; +import org.graalvm.nativeimage.impl.ImageSingletonsSupport; import org.graalvm.nativeimage.impl.RuntimeReflectionSupport; import com.oracle.graal.pointsto.BigBang; @@ -200,8 +201,12 @@ public void printStart(String imageName) { printStageStart(BuildStage.INITIALIZING); } - public void printInitializeEnd(Timer classlistTimer, Timer setupTimer, Collection libraries) { + public void printInitializeEnd(Timer classlistTimer, Timer setupTimer) { printStageEnd(classlistTimer.getTotalTime() + setupTimer.getTotalTime()); + } + + public void printInitializeEnd(Timer classlistTimer, Timer setupTimer, Collection libraries) { + printInitializeEnd(classlistTimer, setupTimer); l().a(" ").doclink("Version info", "#glossary-version-info").a(": '").a(ImageSingletons.lookup(VM.class).version).a("'").flushln(); printNativeLibraries(libraries); } @@ -602,7 +607,8 @@ private void printStageEnd(double totalTime) { String padding = stringFilledWith(Math.max(0, CHARACTERS_PER_LINE - numStageChars - suffix.length()), " "); linePrinter.a(padding).dim().a(suffix).reset().flushln(false); numStageChars = 0; - if (SubstrateOptions.BuildOutputGCWarnings.getValue()) { + boolean optionsAvailable = ImageSingletonsSupport.isInstalled() && ImageSingletons.contains(HostedOptionValues.class); + if (optionsAvailable && SubstrateOptions.BuildOutputGCWarnings.getValue()) { checkForExcessiveGarbageCollection(); } builderIO.useCapturing = false; From 51949b1f5d59c9efe7a5a0f7b1cb4b995c0d98cf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Paul=20W=C3=B6gerer?= Date: Tue, 14 Dec 2021 20:28:33 +0100 Subject: [PATCH 10/17] Provide com.oracle.svm.core.jdk.SystemInOutErrFeature backward compatibility --- .../svm/core/jdk/SystemInOutErrSupport.java | 17 +++++++++++------ .../svm/hosted/jdk/SystemInOutErrFeature.java | 16 +++++++++++----- 2 files changed, 22 insertions(+), 11 deletions(-) diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/SystemInOutErrSupport.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/SystemInOutErrSupport.java index a6905d33d28c..a578d6272322 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/SystemInOutErrSupport.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/SystemInOutErrSupport.java @@ -63,27 +63,32 @@ private static PrintStream newPrintStream(FileOutputStream fos, String enc) { return new PrintStream(new BufferedOutputStream(fos, 128), true); } - public static InputStream in() { - return ImageSingletons.lookup(SystemInOutErrSupport.class).in; + public InputStream in() { + return in; } public static void setIn(InputStream in) { ImageSingletons.lookup(SystemInOutErrSupport.class).in = Objects.requireNonNull(in); } - public static PrintStream out() { - return ImageSingletons.lookup(SystemInOutErrSupport.class).out; + public PrintStream out() { + return out; } public static void setOut(PrintStream out) { ImageSingletons.lookup(SystemInOutErrSupport.class).out = Objects.requireNonNull(out); } - public static PrintStream err() { - return ImageSingletons.lookup(SystemInOutErrSupport.class).err; + public PrintStream err() { + return err; } public static void setErr(PrintStream err) { ImageSingletons.lookup(SystemInOutErrSupport.class).err = Objects.requireNonNull(err); } } + +@SuppressWarnings("unused") +class SystemInOutErrFeature implements Feature { + /* Dummy for backward compatibility. */ +} diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/jdk/SystemInOutErrFeature.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/jdk/SystemInOutErrFeature.java index d71758f9bea2..a2d629740557 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/jdk/SystemInOutErrFeature.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/jdk/SystemInOutErrFeature.java @@ -48,11 +48,17 @@ public class SystemInOutErrFeature implements Feature { private final PrintStream hostedOut = System.out; private final PrintStream hostedErr = System.err; + private SystemInOutErrSupport runtime; + + @Override + public void afterRegistration(AfterRegistrationAccess access) { + runtime = new SystemInOutErrSupport(); + ImageSingletons.add(SystemInOutErrSupport.class, runtime); + } + @Override public void duringSetup(DuringSetupAccess access) { NativeImageSystemIOWrappers.singleton().verifySystemOutErrReplacement(); - - ImageSingletons.add(SystemInOutErrSupport.class, new SystemInOutErrSupport()); access.registerObjectReplacer(this::replaceStreams); } @@ -63,11 +69,11 @@ public void cleanup() { Object replaceStreams(Object object) { if (object == hostedIn) { - return SystemInOutErrSupport.in(); + return runtime.in(); } else if (object == hostedOut) { - return SystemInOutErrSupport.out(); + return runtime.out(); } else if (object == hostedErr) { - return SystemInOutErrSupport.err(); + return runtime.err(); } else { return object; } From 87a53b7f953c8228e4a1f6c814bd98b96b260004 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Paul=20W=C3=B6gerer?= Date: Wed, 15 Dec 2021 09:53:05 +0100 Subject: [PATCH 11/17] Explicitly initialize hostedOut/hostedErr with NativeImageSystemIOWrappers outWrapper/errWrapper --- .../svm/hosted/NativeImageSystemIOWrappers.java | 10 +++++----- .../hosted/{jdk => }/SystemInOutErrFeature.java | 16 +++++++++++----- 2 files changed, 16 insertions(+), 10 deletions(-) rename substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/{jdk => }/SystemInOutErrFeature.java (87%) diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/NativeImageSystemIOWrappers.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/NativeImageSystemIOWrappers.java index eac8df2cf518..a6d1514d588c 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/NativeImageSystemIOWrappers.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/NativeImageSystemIOWrappers.java @@ -28,12 +28,12 @@ import java.io.ByteArrayOutputStream; import java.io.PrintStream; -import com.oracle.svm.core.util.VMError; +import com.oracle.svm.core.util.UserError; public class NativeImageSystemIOWrappers { - private final CapturingStdioWrapper outWrapper; - private final CapturingStdioWrapper errWrapper; + final CapturingStdioWrapper outWrapper; + final CapturingStdioWrapper errWrapper; public boolean useCapturing; @@ -49,8 +49,8 @@ public static NativeImageSystemIOWrappers singleton() { public void verifySystemOutErrReplacement() { String msg = " was changed during image building. This is not allowed."; - VMError.guarantee(System.out == outWrapper, "System.out" + msg); - VMError.guarantee(System.err == errWrapper, "System.err" + msg); + UserError.guarantee(System.out == outWrapper, "System.out" + msg); + UserError.guarantee(System.err == errWrapper, "System.err" + msg); } public PrintStream originalOut() { diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/jdk/SystemInOutErrFeature.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/SystemInOutErrFeature.java similarity index 87% rename from substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/jdk/SystemInOutErrFeature.java rename to substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/SystemInOutErrFeature.java index a2d629740557..ee2fc6ad5950 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/jdk/SystemInOutErrFeature.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/SystemInOutErrFeature.java @@ -23,7 +23,7 @@ * questions. */ -package com.oracle.svm.hosted.jdk; +package com.oracle.svm.hosted; import java.io.InputStream; import java.io.PrintStream; @@ -34,7 +34,6 @@ import com.oracle.svm.core.annotate.AutomaticFeature; import com.oracle.svm.core.annotate.RecomputeFieldValue; import com.oracle.svm.core.jdk.SystemInOutErrSupport; -import com.oracle.svm.hosted.NativeImageSystemIOWrappers; /** * We use an {@link Feature.DuringSetupAccess#registerObjectReplacer object replacer} because the @@ -44,9 +43,16 @@ */ @AutomaticFeature public class SystemInOutErrFeature implements Feature { - private final InputStream hostedIn = System.in; - private final PrintStream hostedOut = System.out; - private final PrintStream hostedErr = System.err; + private final InputStream hostedIn; + private final PrintStream hostedOut; + private final PrintStream hostedErr; + + public SystemInOutErrFeature() { + hostedIn = System.in; + NativeImageSystemIOWrappers wrappers = NativeImageSystemIOWrappers.singleton(); + hostedOut = wrappers.outWrapper; + hostedErr = wrappers.errWrapper; + } private SystemInOutErrSupport runtime; From 787e354958386ebbfafe4b0fce5d024d12049c4e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Paul=20W=C3=B6gerer?= Date: Wed, 15 Dec 2021 16:14:52 +0100 Subject: [PATCH 12/17] Provide NativeImageSystemIOWrappers output sink customization --- .../oracle/svm/graal/hosted/GraalFeature.java | 4 ++-- .../svm/hosted/NativeImageGenerator.java | 9 ++++----- .../hosted/NativeImageGeneratorRunner.java | 1 - .../hosted/NativeImageSystemClassLoader.java | 7 +------ .../hosted/NativeImageSystemIOWrappers.java | 17 +++++++++++++---- .../{reporting => }/ProgressReporter.java | 19 ++++++++----------- .../ProgressReporterCHelper.java | 4 ++-- .../oracle/svm/hosted/code/CompileQueue.java | 9 ++++----- .../oracle/svm/hosted/image/NativeImage.java | 2 +- .../svm/jni/access/JNIAccessFeature.java | 2 +- 10 files changed, 36 insertions(+), 38 deletions(-) rename substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/{reporting => }/ProgressReporter.java (98%) rename substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/{reporting => }/ProgressReporterCHelper.java (96%) diff --git a/substratevm/src/com.oracle.svm.graal/src/com/oracle/svm/graal/hosted/GraalFeature.java b/substratevm/src/com.oracle.svm.graal/src/com/oracle/svm/graal/hosted/GraalFeature.java index 82572f3f693a..772597b2fc97 100644 --- a/substratevm/src/com.oracle.svm.graal/src/com/oracle/svm/graal/hosted/GraalFeature.java +++ b/substratevm/src/com.oracle.svm.graal/src/com/oracle/svm/graal/hosted/GraalFeature.java @@ -42,7 +42,6 @@ import java.util.function.Function; import java.util.function.Predicate; -import com.oracle.graal.pointsto.meta.PointsToAnalysisMethod; import org.graalvm.compiler.api.replacements.Fold; import org.graalvm.compiler.api.runtime.GraalRuntime; import org.graalvm.compiler.core.common.spi.MetaAccessExtensionProvider; @@ -90,6 +89,7 @@ import com.oracle.graal.pointsto.meta.AnalysisMethod; import com.oracle.graal.pointsto.meta.AnalysisType; import com.oracle.graal.pointsto.meta.HostedProviders; +import com.oracle.graal.pointsto.meta.PointsToAnalysisMethod; import com.oracle.graal.pointsto.util.GraalAccess; import com.oracle.svm.core.ParsingReason; import com.oracle.svm.core.SubstrateOptions; @@ -121,6 +121,7 @@ import com.oracle.svm.hosted.FeatureImpl.DuringAnalysisAccessImpl; import com.oracle.svm.hosted.FeatureImpl.DuringSetupAccessImpl; import com.oracle.svm.hosted.NativeImageGenerator; +import com.oracle.svm.hosted.ProgressReporter; import com.oracle.svm.hosted.analysis.Inflation; import com.oracle.svm.hosted.classinitialization.ClassInitializationSupport; import com.oracle.svm.hosted.code.CompilationInfoSupport; @@ -133,7 +134,6 @@ import com.oracle.svm.hosted.phases.StrengthenStampsPhase; import com.oracle.svm.hosted.phases.SubstrateClassInitializationPlugin; import com.oracle.svm.hosted.phases.SubstrateGraphBuilderPhase; -import com.oracle.svm.hosted.reporting.ProgressReporter; import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary; import jdk.vm.ci.meta.DeoptimizationAction; 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 67ff9a78a2d1..a01d07c2fe4f 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/NativeImageGenerator.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/NativeImageGenerator.java @@ -56,9 +56,6 @@ import java.util.function.BooleanSupplier; import java.util.stream.Collectors; -import com.oracle.graal.pointsto.PointsToAnalysis; -import com.oracle.graal.pointsto.meta.PointsToAnalysisFactory; -import com.oracle.graal.pointsto.meta.PointsToAnalysisMethod; import org.graalvm.collections.EconomicSet; import org.graalvm.collections.Pair; import org.graalvm.compiler.api.replacements.Fold; @@ -135,6 +132,7 @@ import com.oracle.graal.pointsto.BigBang; import com.oracle.graal.pointsto.BytecodeSensitiveAnalysisPolicy; import com.oracle.graal.pointsto.DefaultAnalysisPolicy; +import com.oracle.graal.pointsto.PointsToAnalysis; import com.oracle.graal.pointsto.api.PointstoOptions; import com.oracle.graal.pointsto.constraints.UnsupportedFeatureException; import com.oracle.graal.pointsto.infrastructure.SubstitutionProcessor; @@ -146,6 +144,8 @@ import com.oracle.graal.pointsto.meta.AnalysisType; import com.oracle.graal.pointsto.meta.AnalysisUniverse; import com.oracle.graal.pointsto.meta.HostedProviders; +import com.oracle.graal.pointsto.meta.PointsToAnalysisFactory; +import com.oracle.graal.pointsto.meta.PointsToAnalysisMethod; import com.oracle.graal.pointsto.reports.AnalysisReporter; import com.oracle.graal.pointsto.typestate.TypeState; import com.oracle.graal.pointsto.util.AnalysisError; @@ -220,6 +220,7 @@ import com.oracle.svm.hosted.FeatureImpl.BeforeUniverseBuildingAccessImpl; import com.oracle.svm.hosted.FeatureImpl.DuringAnalysisAccessImpl; import com.oracle.svm.hosted.FeatureImpl.OnAnalysisExitAccessImpl; +import com.oracle.svm.hosted.ProgressReporter.ReporterClosable; import com.oracle.svm.hosted.ameta.AnalysisConstantFieldProvider; import com.oracle.svm.hosted.ameta.AnalysisConstantReflectionProvider; import com.oracle.svm.hosted.analysis.Inflation; @@ -270,8 +271,6 @@ import com.oracle.svm.hosted.phases.SubstrateClassInitializationPlugin; import com.oracle.svm.hosted.phases.VerifyDeoptFrameStatesLIRPhase; import com.oracle.svm.hosted.phases.VerifyNoGuardsPhase; -import com.oracle.svm.hosted.reporting.ProgressReporter; -import com.oracle.svm.hosted.reporting.ProgressReporter.ReporterClosable; import com.oracle.svm.hosted.snippets.SubstrateGraphBuilderPlugins; import com.oracle.svm.hosted.substitute.AnnotationSubstitutionProcessor; import com.oracle.svm.hosted.substitute.DeletedFieldsPlugin; diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/NativeImageGeneratorRunner.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/NativeImageGeneratorRunner.java index 362e763877d4..e3e0715f5e7e 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/NativeImageGeneratorRunner.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/NativeImageGeneratorRunner.java @@ -72,7 +72,6 @@ import com.oracle.svm.hosted.code.CEntryPointData; import com.oracle.svm.hosted.image.AbstractImage.NativeImageKind; import com.oracle.svm.hosted.option.HostedOptionParser; -import com.oracle.svm.hosted.reporting.ProgressReporter; import com.oracle.svm.util.ClassUtil; import com.oracle.svm.util.ModuleSupport; import com.oracle.svm.util.ReflectionUtil; diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/NativeImageSystemClassLoader.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/NativeImageSystemClassLoader.java index 43f249a31e22..d336adb0eb58 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/NativeImageSystemClassLoader.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/NativeImageSystemClassLoader.java @@ -52,8 +52,7 @@ public final class NativeImageSystemClassLoader extends SecureClassLoader { public final ClassLoader defaultSystemClassLoader; - - NativeImageSystemIOWrappers systemIOWrappers; + final NativeImageSystemIOWrappers systemIOWrappers; private volatile ClassLoader nativeImageClassLoader = null; @@ -62,10 +61,6 @@ public final class NativeImageSystemClassLoader extends SecureClassLoader { public NativeImageSystemClassLoader(ClassLoader defaultSystemClassLoader) { super(defaultSystemClassLoader); this.defaultSystemClassLoader = defaultSystemClassLoader; - resetSystemIOWrappers(); - } - - private void resetSystemIOWrappers() { systemIOWrappers = new NativeImageSystemIOWrappers(); /* Image building console output requires custom System.out and System.err */ systemIOWrappers.replaceSystemOutErr(); diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/NativeImageSystemIOWrappers.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/NativeImageSystemIOWrappers.java index a6d1514d588c..446b2c387c23 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/NativeImageSystemIOWrappers.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/NativeImageSystemIOWrappers.java @@ -27,6 +27,7 @@ import java.io.ByteArrayOutputStream; import java.io.PrintStream; +import java.util.Objects; import com.oracle.svm.core.util.UserError; @@ -35,7 +36,7 @@ public class NativeImageSystemIOWrappers { final CapturingStdioWrapper outWrapper; final CapturingStdioWrapper errWrapper; - public boolean useCapturing; + boolean useCapturing; NativeImageSystemIOWrappers() { outWrapper = new CapturingStdioWrapper(System.out, new ByteArrayOutputStream(128)); @@ -53,14 +54,22 @@ public void verifySystemOutErrReplacement() { UserError.guarantee(System.err == errWrapper, "System.err" + msg); } - public PrintStream originalOut() { + public PrintStream getOut() { return outWrapper.delegate; } - public PrintStream originalErr() { + public void setOut(PrintStream customOut) { + outWrapper.delegate = Objects.requireNonNull(customOut); + } + + public PrintStream getErr() { return errWrapper.delegate; } + public void setErr(PrintStream customErr) { + errWrapper.delegate = Objects.requireNonNull(customErr); + } + public void flushCapturedContent() { outWrapper.flushCapturedContent(); errWrapper.flushCapturedContent(); @@ -76,7 +85,7 @@ void replaceSystemOutErr() { */ private final class CapturingStdioWrapper extends PrintStream { private final ByteArrayOutputStream buffer; - private final PrintStream delegate; + private PrintStream delegate; private CapturingStdioWrapper(PrintStream delegate, ByteArrayOutputStream buffer) { super(buffer); diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/reporting/ProgressReporter.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/ProgressReporter.java similarity index 98% rename from substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/reporting/ProgressReporter.java rename to substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/ProgressReporter.java index 4eccde0f62df..5a95940632dc 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/reporting/ProgressReporter.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/ProgressReporter.java @@ -22,7 +22,7 @@ * or visit www.oracle.com if you need additional information or have any * questions. */ -package com.oracle.svm.hosted.reporting; +package com.oracle.svm.hosted; import java.io.File; import java.io.PrintWriter; @@ -66,9 +66,6 @@ import com.oracle.svm.core.annotate.AutomaticFeature; import com.oracle.svm.core.option.HostedOptionValues; import com.oracle.svm.core.reflect.MethodMetadataDecoder; -import com.oracle.svm.hosted.NativeImageGenerator; -import com.oracle.svm.hosted.NativeImageSystemIOWrappers; -import com.oracle.svm.hosted.StringAccess; import com.oracle.svm.hosted.code.CompileQueue.CompileTask; import com.oracle.svm.hosted.image.NativeImageHeap.ObjectInfo; import com.oracle.svm.util.ImageBuildStatistics; @@ -638,7 +635,7 @@ private void checkForExcessiveGarbageCollection() { */ private static void resetANSIMode() { - NativeImageSystemIOWrappers.singleton().originalOut().print(ANSIColors.RESET); + NativeImageSystemIOWrappers.singleton().getOut().print(ANSIColors.RESET); } private static String stringFilledWith(int size, String fill) { @@ -838,7 +835,7 @@ private void flush() { if (printBuffer != null) { textBuffer.forEach(printBuffer::append); } else { - textBuffer.forEach(builderIO.originalOut()::print); + textBuffer.forEach(builderIO.getOut()::print); } textBuffer.clear(); } @@ -850,7 +847,7 @@ private void printRaw(char value) { if (printBuffer != null) { printBuffer.append(value); } else { - builderIO.originalOut().print(value); + builderIO.getOut().print(value); } } @@ -863,15 +860,15 @@ private void flushln(boolean useOutputPrefix) { return; } if (useOutputPrefix) { - builderIO.originalOut().print(outputPrefix); + builderIO.getOut().print(outputPrefix); } if (printBuffer != null) { - builderIO.originalOut().print(printBuffer); + builderIO.getOut().print(printBuffer); printBuffer.setLength(0); // Clear buffer. } - textBuffer.forEach(builderIO.originalOut()::print); + textBuffer.forEach(builderIO.getOut()::print); textBuffer.clear(); - builderIO.originalOut().println(); + builderIO.getOut().println(); } private void flushCenteredln() { diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/reporting/ProgressReporterCHelper.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/ProgressReporterCHelper.java similarity index 96% rename from substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/reporting/ProgressReporterCHelper.java rename to substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/ProgressReporterCHelper.java index 6ceeccbcde75..1d21218e8254 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/reporting/ProgressReporterCHelper.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/ProgressReporterCHelper.java @@ -23,7 +23,7 @@ * questions. */ -package com.oracle.svm.hosted.reporting; +package com.oracle.svm.hosted; import java.nio.file.Files; import java.nio.file.Path; @@ -33,7 +33,7 @@ public final class ProgressReporterCHelper { private static final int DEFAULT_CHARACTERS_PER_LINE = 80; - public static final int MAX_CHARACTERS_PER_LINE = 120; + static final int MAX_CHARACTERS_PER_LINE = 120; static { loadCHelperLibrary(); diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/code/CompileQueue.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/code/CompileQueue.java index 20f0660fe485..aeb22fde497e 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/code/CompileQueue.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/code/CompileQueue.java @@ -157,6 +157,7 @@ import com.oracle.svm.hosted.FeatureHandler; import com.oracle.svm.hosted.NativeImageGenerator; import com.oracle.svm.hosted.NativeImageOptions; +import com.oracle.svm.hosted.ProgressReporter; import com.oracle.svm.hosted.meta.HostedField; import com.oracle.svm.hosted.meta.HostedMethod; import com.oracle.svm.hosted.meta.HostedType; @@ -166,8 +167,6 @@ import com.oracle.svm.hosted.phases.ImageBuildStatisticsCounterPhase; import com.oracle.svm.hosted.phases.ImplicitAssertionsPhase; import com.oracle.svm.hosted.phases.StrengthenStampsPhase; -import com.oracle.svm.hosted.reporting.ProgressReporter; -import com.oracle.svm.hosted.reporting.ProgressReporter.ReporterClosable; import com.oracle.svm.hosted.substitute.DeletedMethod; import com.oracle.svm.util.ImageBuildStatistics; @@ -372,7 +371,7 @@ public void finish(DebugContext debug) { ProgressReporter reporter = ProgressReporter.singleton(); try { String imageName = universe.getBigBang().getHostVM().getImageName(); - try (ReporterClosable ac = reporter.printParsing(new Timer(imageName, "(parse)"))) { + try (ProgressReporter.ReporterClosable ac = reporter.printParsing(new Timer(imageName, "(parse)"))) { parseAll(); } // Checking @Uninterruptible annotations does not take long enough to justify a timer. @@ -391,7 +390,7 @@ public void finish(DebugContext debug) { } if (SubstrateOptions.AOTInline.getValue() && SubstrateOptions.AOTTrivialInline.getValue()) { - try (ReporterClosable ac = reporter.printInlining(new Timer(imageName, "(inline)"))) { + try (ProgressReporter.ReporterClosable ac = reporter.printInlining(new Timer(imageName, "(inline)"))) { inlineTrivialMethods(debug); } } else { @@ -400,7 +399,7 @@ public void finish(DebugContext debug) { assert suitesNotCreated(); createSuites(); - try (ReporterClosable ac = reporter.printCompiling(new Timer(imageName, "(compile)"))) { + try (ProgressReporter.ReporterClosable ac = reporter.printCompiling(new Timer(imageName, "(compile)"))) { compileAll(); } } catch (InterruptedException ie) { diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/NativeImage.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/NativeImage.java index c9c054c7f6ab..acbfeb1f1cd6 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/NativeImage.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/NativeImage.java @@ -102,6 +102,7 @@ import com.oracle.svm.core.util.UserError; import com.oracle.svm.hosted.FeatureImpl; import com.oracle.svm.hosted.NativeImageOptions; +import com.oracle.svm.hosted.ProgressReporter; import com.oracle.svm.hosted.c.CGlobalDataFeature; import com.oracle.svm.hosted.c.NativeLibraries; import com.oracle.svm.hosted.c.codegen.CSourceCodeWriter; @@ -114,7 +115,6 @@ import com.oracle.svm.hosted.meta.HostedMetaAccess; import com.oracle.svm.hosted.meta.HostedMethod; import com.oracle.svm.hosted.meta.HostedUniverse; -import com.oracle.svm.hosted.reporting.ProgressReporter; import com.oracle.svm.util.ReflectionUtil; import com.oracle.svm.util.ReflectionUtil.ReflectionUtilError; diff --git a/substratevm/src/com.oracle.svm.jni/src/com/oracle/svm/jni/access/JNIAccessFeature.java b/substratevm/src/com.oracle.svm.jni/src/com/oracle/svm/jni/access/JNIAccessFeature.java index 13576d1f4d07..433d14283a67 100644 --- a/substratevm/src/com.oracle.svm.jni/src/com/oracle/svm/jni/access/JNIAccessFeature.java +++ b/substratevm/src/com.oracle.svm.jni/src/com/oracle/svm/jni/access/JNIAccessFeature.java @@ -60,11 +60,11 @@ import com.oracle.svm.hosted.FeatureImpl.BeforeAnalysisAccessImpl; import com.oracle.svm.hosted.FeatureImpl.CompilationAccessImpl; import com.oracle.svm.hosted.FeatureImpl.DuringAnalysisAccessImpl; +import com.oracle.svm.hosted.ProgressReporter; import com.oracle.svm.hosted.c.NativeLibraries; import com.oracle.svm.hosted.code.CEntryPointData; import com.oracle.svm.hosted.config.ConfigurationParserUtils; import com.oracle.svm.hosted.meta.MaterializedConstantFields; -import com.oracle.svm.hosted.reporting.ProgressReporter; import com.oracle.svm.hosted.substitute.SubstitutionReflectivityFilter; import com.oracle.svm.jni.JNIJavaCallWrappers; import com.oracle.svm.jni.JNISupport; From 5cd1b44bacae8147fb167862aa0427128db3c017 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Paul=20W=C3=B6gerer?= Date: Wed, 15 Dec 2021 17:48:28 +0100 Subject: [PATCH 13/17] Fix style issue --- .../com/oracle/svm/hosted/NativeImageSystemIOWrappers.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/NativeImageSystemIOWrappers.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/NativeImageSystemIOWrappers.java index 446b2c387c23..424b6c12202b 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/NativeImageSystemIOWrappers.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/NativeImageSystemIOWrappers.java @@ -49,9 +49,9 @@ public static NativeImageSystemIOWrappers singleton() { } public void verifySystemOutErrReplacement() { - String msg = " was changed during image building. This is not allowed."; - UserError.guarantee(System.out == outWrapper, "System.out" + msg); - UserError.guarantee(System.err == errWrapper, "System.err" + msg); + String format = "%s was changed during image building. This is not allowed."; + UserError.guarantee(System.out == outWrapper, format, "System.out"); + UserError.guarantee(System.err == errWrapper, format, "System.err"); } public PrintStream getOut() { From adfd6d9508bfe781deeb559dad38ef4714533254 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Paul=20W=C3=B6gerer?= Date: Thu, 16 Dec 2021 10:14:48 +0100 Subject: [PATCH 14/17] Make remaining methods package-private --- .../hosted/NativeImageSystemIOWrappers.java | 30 +++++++++---------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/NativeImageSystemIOWrappers.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/NativeImageSystemIOWrappers.java index 424b6c12202b..421761b819b8 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/NativeImageSystemIOWrappers.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/NativeImageSystemIOWrappers.java @@ -44,16 +44,26 @@ public class NativeImageSystemIOWrappers { useCapturing = false; } - public static NativeImageSystemIOWrappers singleton() { - return NativeImageSystemClassLoader.singleton().systemIOWrappers; - } - - public void verifySystemOutErrReplacement() { + void verifySystemOutErrReplacement() { String format = "%s was changed during image building. This is not allowed."; UserError.guarantee(System.out == outWrapper, format, "System.out"); UserError.guarantee(System.err == errWrapper, format, "System.err"); } + void flushCapturedContent() { + outWrapper.flushCapturedContent(); + errWrapper.flushCapturedContent(); + } + + void replaceSystemOutErr() { + System.setOut(outWrapper); + System.setErr(errWrapper); + } + + public static NativeImageSystemIOWrappers singleton() { + return NativeImageSystemClassLoader.singleton().systemIOWrappers; + } + public PrintStream getOut() { return outWrapper.delegate; } @@ -70,16 +80,6 @@ public void setErr(PrintStream customErr) { errWrapper.delegate = Objects.requireNonNull(customErr); } - public void flushCapturedContent() { - outWrapper.flushCapturedContent(); - errWrapper.flushCapturedContent(); - } - - void replaceSystemOutErr() { - System.setOut(outWrapper); - System.setErr(errWrapper); - } - /** * Wrapper with the ability to temporarily capture output to stdout and stderr. */ From d76efd53240b988cd9f87e6e51aba52cd901da79 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Paul=20W=C3=B6gerer?= Date: Thu, 16 Dec 2021 10:26:00 +0100 Subject: [PATCH 15/17] Prevent possibility of initialize-StageEnd to be called twice In case of an exception between the regular ProgressReporter#printInitializeEnd call at the end of NativeImageGenerator#setupNativeImage and the execution of the finally block in NativeImageGeneratorRunner#buildImage printing of initialize-StageEnd would have happened twice. --- .../src/com/oracle/svm/hosted/ProgressReporter.java | 5 +++++ 1 file changed, 5 insertions(+) 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 5a95940632dc..0377bbbc94f7 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 @@ -109,6 +109,7 @@ public class ProgressReporter { private int numJNIFields = -1; private int numJNIMethods = -1; private Timer debugInfoTimer; + private boolean initializeStageEndCompleted = false; private enum BuildStage { INITIALIZING("Initializing"), @@ -199,7 +200,11 @@ public void printStart(String imageName) { } public void printInitializeEnd(Timer classlistTimer, Timer setupTimer) { + if (initializeStageEndCompleted) { + return; + } printStageEnd(classlistTimer.getTotalTime() + setupTimer.getTotalTime()); + initializeStageEndCompleted = true; } public void printInitializeEnd(Timer classlistTimer, Timer setupTimer, Collection libraries) { From 0f82c651955bf0cf75b559c817c1639d2c774524 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Paul=20W=C3=B6gerer?= Date: Fri, 17 Dec 2021 14:16:19 +0100 Subject: [PATCH 16/17] Fix reporterchelper JNI library use --- .../com/oracle/svm/hosted/ProgressReporterCHelper.java | 8 ++++++-- .../src/getPeakRSS.c | 6 +++--- .../src/getTerminalWindowColumns.c | 4 ++-- 3 files changed, 11 insertions(+), 7 deletions(-) diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/ProgressReporterCHelper.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/ProgressReporterCHelper.java index 1d21218e8254..69422a6391ab 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/ProgressReporterCHelper.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/ProgressReporterCHelper.java @@ -31,6 +31,8 @@ import org.graalvm.compiler.serviceprovider.JavaVersionUtil; +import com.oracle.svm.core.util.VMError; + public final class ProgressReporterCHelper { private static final int DEFAULT_CHARACTERS_PER_LINE = 80; static final int MAX_CHARACTERS_PER_LINE = 120; @@ -47,6 +49,8 @@ private static void loadCHelperLibrary() { Path libRSSHelperPath = Paths.get(System.getProperty("java.home"), "lib", "svm", "builder", "lib", libName); if (Files.exists(libRSSHelperPath)) { System.load(libRSSHelperPath.toString()); + } else { + System.load(Paths.get(System.getProperty("substratevm.reporterchelper.path"), libName).toString()); } } @@ -64,7 +68,7 @@ public static int getTerminalWindowColumns() { try { return getTerminalWindowColumns0(); } catch (UnsatisfiedLinkError e) { - return DEFAULT_CHARACTERS_PER_LINE; + throw VMError.shouldNotReachHere("ProgressReporterCHelper.getTerminalWindowColumns0 native method not available"); } } @@ -75,7 +79,7 @@ public static long getPeakRSS() { try { return getPeakRSS0(); } catch (UnsatisfiedLinkError e) { - return -1; + throw VMError.shouldNotReachHere("ProgressReporterCHelper.getPeakRSS0 native method not available"); } } diff --git a/substratevm/src/com.oracle.svm.native.reporterchelper/src/getPeakRSS.c b/substratevm/src/com.oracle.svm.native.reporterchelper/src/getPeakRSS.c index 1d397afb098c..59d6cab3b4d0 100644 --- a/substratevm/src/com.oracle.svm.native.reporterchelper/src/getPeakRSS.c +++ b/substratevm/src/com.oracle.svm.native.reporterchelper/src/getPeakRSS.c @@ -29,7 +29,7 @@ #include -JNIEXPORT jlong JNICALL Java_com_oracle_svm_hosted_reporting_ProgressReporterCHelper_getPeakRSS0(void *env, void * ignored) { +JNIEXPORT jlong JNICALL Java_com_oracle_svm_hosted_ProgressReporterCHelper_getPeakRSS0(void *env, void * ignored) { struct rusage rusage; if (getrusage(RUSAGE_SELF, &rusage) == 0) { return (size_t)rusage.ru_maxrss * 1024; /* (in kilobytes) */ @@ -44,7 +44,7 @@ JNIEXPORT jlong JNICALL Java_com_oracle_svm_hosted_reporting_ProgressReporterCHe #include #include -JNIEXPORT jlong JNICALL Java_com_oracle_svm_hosted_reporting_ProgressReporterCHelper_getPeakRSS0(void *env, void * ignored) { +JNIEXPORT jlong JNICALL Java_com_oracle_svm_hosted_ProgressReporterCHelper_getPeakRSS0(void *env, void * ignored) { struct mach_task_basic_info info; mach_msg_type_number_t count = MACH_TASK_BASIC_INFO_COUNT; if (task_info(mach_task_self(), MACH_TASK_BASIC_INFO, (task_info_t)&info, &count) == KERN_SUCCESS) { @@ -59,7 +59,7 @@ JNIEXPORT jlong JNICALL Java_com_oracle_svm_hosted_reporting_ProgressReporterCHe #include #include -JNIEXPORT jlong JNICALL Java_com_oracle_svm_hosted_reporting_ProgressReporterCHelper_getPeakRSS0(void *env, void * ignored) { +JNIEXPORT jlong JNICALL Java_com_oracle_svm_hosted_ProgressReporterCHelper_getPeakRSS0(void *env, void * ignored) { PROCESS_MEMORY_COUNTERS memCounter; if (GetProcessMemoryInfo(GetCurrentProcess(), &memCounter, sizeof memCounter)) { return (size_t)memCounter.PeakWorkingSetSize; diff --git a/substratevm/src/com.oracle.svm.native.reporterchelper/src/getTerminalWindowColumns.c b/substratevm/src/com.oracle.svm.native.reporterchelper/src/getTerminalWindowColumns.c index 221a4e3700bf..dfc5ac55fd16 100644 --- a/substratevm/src/com.oracle.svm.native.reporterchelper/src/getTerminalWindowColumns.c +++ b/substratevm/src/com.oracle.svm.native.reporterchelper/src/getTerminalWindowColumns.c @@ -32,7 +32,7 @@ #include #include -JNIEXPORT jint JNICALL Java_com_oracle_svm_hosted_reporting_ProgressReporterCHelper_getTerminalWindowColumns0(void *env, void * ignored) { +JNIEXPORT jint JNICALL Java_com_oracle_svm_hosted_ProgressReporterCHelper_getTerminalWindowColumns0(void *env, void * ignored) { struct winsize w; ioctl(STDOUT_FILENO, TIOCGWINSZ, &w); return w.ws_col; @@ -42,7 +42,7 @@ JNIEXPORT jint JNICALL Java_com_oracle_svm_hosted_reporting_ProgressReporterCHel #include -JNIEXPORT jint JNICALL Java_com_oracle_svm_hosted_reporting_ProgressReporterCHelper_getTerminalWindowColumns0(void *env, void * ignored) { +JNIEXPORT jint JNICALL Java_com_oracle_svm_hosted_ProgressReporterCHelper_getTerminalWindowColumns0(void *env, void * ignored) { CONSOLE_SCREEN_BUFFER_INFO c; GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), &c); return c.srWindow.Right - c.srWindow.Left + 1; From d0553d8c51c3a46ccbd5894e7aa91ed22a553425 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Paul=20W=C3=B6gerer?= Date: Fri, 17 Dec 2021 15:35:03 +0100 Subject: [PATCH 17/17] Fix ProgressReporterCHelper.loadCHelperLibrary for Java 8 --- .../com/oracle/svm/hosted/ProgressReporterCHelper.java | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/ProgressReporterCHelper.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/ProgressReporterCHelper.java index 69422a6391ab..d3f776d81b0a 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/ProgressReporterCHelper.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/ProgressReporterCHelper.java @@ -29,8 +29,6 @@ import java.nio.file.Path; import java.nio.file.Paths; -import org.graalvm.compiler.serviceprovider.JavaVersionUtil; - import com.oracle.svm.core.util.VMError; public final class ProgressReporterCHelper { @@ -42,11 +40,9 @@ public final class ProgressReporterCHelper { } private static void loadCHelperLibrary() { - if (JavaVersionUtil.JAVA_SPEC <= 8) { - return; // TODO: remove as part of JDK8 removal (GR-35238). - } + Path javaHome = Paths.get(System.getProperty("java.home")); String libName = System.mapLibraryName("reporterchelper"); - Path libRSSHelperPath = Paths.get(System.getProperty("java.home"), "lib", "svm", "builder", "lib", libName); + Path libRSSHelperPath = javaHome.resolve(Paths.get("lib", "svm", "builder", "lib", libName)); if (Files.exists(libRSSHelperPath)) { System.load(libRSSHelperPath.toString()); } else {