diff --git a/sdk/src/org.graalvm.nativeimage/src/org/graalvm/nativeimage/LogHandler.java b/sdk/src/org.graalvm.nativeimage/src/org/graalvm/nativeimage/LogHandler.java new file mode 100644 index 000000000000..238e8bff436a --- /dev/null +++ b/sdk/src/org.graalvm.nativeimage/src/org/graalvm/nativeimage/LogHandler.java @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2018, 2018, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package org.graalvm.nativeimage; + +import org.graalvm.nativeimage.c.type.CCharPointer; +import org.graalvm.word.UnsignedWord; + +/** + * Implement this interface to create a custom log handler. The custom log handler must be installed + * in the {@code ImageSingletons} at {@code Feature.duringSetup()} time like so: + * + *
+ *    class LogHandlerFeature implements Feature {
+ *       {@literal @}Override
+ *        public void duringSetup(DuringSetupAccess access) {
+ *            ImageSingletons.add(LogHandler.class, new CustomLogHandler());
+ *        }
+ *    }
+ * 
+ * + * If no custom log handler is installed a default one would be provided at + * {@code Feature.beforeAnalysis()} time. Installing a custom log handler at a later time, after the + * default one has been installed, will result in an error. + * + */ +public interface LogHandler { + + static LogHandler get() { + return ImageSingletons.lookup(LogHandler.class); + } + + /** Writes the raw bytes. */ + void log(CCharPointer bytes, UnsignedWord length); + + /** Forces the log to flush to its destination. */ + void flush(); + + /** Exit the VM. Method must not return. No Java code should be run after this point. */ + void fatalError(); +} diff --git a/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/PinnedObjectImpl.java b/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/PinnedObjectImpl.java index 9424c2c7901e..19b8efdd4c32 100644 --- a/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/PinnedObjectImpl.java +++ b/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/PinnedObjectImpl.java @@ -85,11 +85,8 @@ public void afterRegistration(AfterRegistrationAccess access) { @Override @Uninterruptible(reason = "Called from uninterruptible code.") public void close() { - final Log trace = Log.noopLog().string("[PinnedObject.close:").string(" this: ").object(this); - trace.string(" referent: ").object(referent); assert open : "Should not call close() on a closed PinnedObject."; open = false; - trace.string("]").newline(); } /* diff --git a/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/ThreadLocalAllocation.java b/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/ThreadLocalAllocation.java index a0339e442c55..b730816c7700 100644 --- a/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/ThreadLocalAllocation.java +++ b/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/ThreadLocalAllocation.java @@ -468,15 +468,12 @@ private static void pushToThreadLocalFreeList(AlignedHeader alignedChunk) { */ @Uninterruptible(reason = "Pops from the free list that is drained, at a safepoint, by garbage collections.") private static AlignedHeader popFromThreadLocalFreeList() { - log().string("[ThreadLocalAllocation.popFromThreadLocalFreeList:").newline(); - log().string(" before freeList: ").hex(freeList.get()).string("]").newline(); final AlignedHeader result = freeList.get(); if (result.isNonNull()) { final AlignedHeader next = result.getNext(); result.setNext(WordFactory.nullPointer()); freeList.set(next); } - log().string(" after freeList: ").hex(freeList.get()).string(" result: ").hex(result).string("]").newline(); return result; } @@ -569,8 +566,6 @@ private static void retireAllocationChunk(Descriptor tlab) { if (allocationTop.isNonNull()) { AlignedHeader alignedChunk = tlab.getAlignedChunk(); - log().string(" [ThreadLocalAllocator.retireAllocationChunk: tlab ").hex(tlab).string(" chunk ").hex(alignedChunk).string(" top ").hex(allocationTop).string(" ]").newline(); - assert alignedChunk.getTop().isNull(); assert alignedChunk.getEnd().equal(tlab.getAllocationEnd(END_IDENTITY)); @@ -595,8 +590,6 @@ static void resumeAllocationChunk(Descriptor tlab) { AlignedHeader alignedChunk = tlab.getAlignedChunk(); if (alignedChunk.isNonNull()) { - log().string(" [ThreadLocalAllocator.resumeAllocationChunk: tlab ").hex(tlab).string(" chunk ").hex(alignedChunk).string(" top ").hex(alignedChunk.getTop()).string(" ]").newline(); - tlab.setAllocationTop(alignedChunk.getTop(), TOP_IDENTITY); tlab.setAllocationEnd(alignedChunk.getEnd(), END_IDENTITY); alignedChunk.setTop(WordFactory.nullPointer()); diff --git a/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/UnalignedHeapChunk.java b/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/UnalignedHeapChunk.java index 337c5f36cc41..ea6e05855891 100644 --- a/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/UnalignedHeapChunk.java +++ b/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/UnalignedHeapChunk.java @@ -150,9 +150,7 @@ protected static UnsignedWord getChunkSizeForObject(UnsignedWord objectSize) { */ @Uninterruptible(reason = "Returns uninitialized memory.", callerMustBe = true) public static Pointer allocateMemory(UnalignedHeader that, UnsignedWord size) { - final Log trace = Log.noopLog().string("[UnalignedHeapChunk.allocateMemory:"); final UnsignedWord available = availableObjectMemory(that); - trace.string(" size").unsigned(size).string(" top: ").hex(that.getTop()).string(" end: ").hex(that.getEnd()).string(" available: ").unsigned(available).newline(); // Is memory available for the requested size? Pointer result = WordFactory.nullPointer(); if (size.belowOrEqual(available)) { @@ -161,7 +159,6 @@ public static Pointer allocateMemory(UnalignedHeader that, UnsignedWord size) { final Pointer newTop = result.add(size); setTopCarefully(that, newTop); } - trace.string(" returns: ").hex(result).string("]").newline(); return result; } diff --git a/substratevm/src/com.oracle.svm.core.graal/src/com/oracle/svm/core/graal/posix/PosixCEntryPointSnippets.java b/substratevm/src/com.oracle.svm.core.graal/src/com/oracle/svm/core/graal/posix/PosixCEntryPointSnippets.java index fe53540261e7..915c1860855c 100644 --- a/substratevm/src/com.oracle.svm.core.graal/src/com/oracle/svm/core/graal/posix/PosixCEntryPointSnippets.java +++ b/substratevm/src/com.oracle.svm.core.graal/src/com/oracle/svm/core/graal/posix/PosixCEntryPointSnippets.java @@ -53,6 +53,7 @@ import org.graalvm.nativeimage.ImageSingletons; import org.graalvm.nativeimage.Isolate; import org.graalvm.nativeimage.IsolateThread; +import org.graalvm.nativeimage.LogHandler; import org.graalvm.nativeimage.StackValue; import org.graalvm.nativeimage.c.function.CEntryPointContext; import org.graalvm.nativeimage.c.function.CFunction; @@ -364,7 +365,7 @@ private static int reportException(Throwable exception) { } } Log.log().newline(); - LibC.abort(); + LogHandler.get().fatalError(); return Errors.UNSPECIFIED; // unreachable } diff --git a/substratevm/src/com.oracle.svm.core.posix/src/com/oracle/svm/core/posix/DefaultLogHandler.java b/substratevm/src/com.oracle.svm.core.posix/src/com/oracle/svm/core/posix/DefaultLogHandler.java new file mode 100644 index 000000000000..97313a0b6545 --- /dev/null +++ b/substratevm/src/com.oracle.svm.core.posix/src/com/oracle/svm/core/posix/DefaultLogHandler.java @@ -0,0 +1,80 @@ +/* + * Copyright (c) 2018, 2018, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.svm.core.posix; + +import java.io.FileDescriptor; + +import com.oracle.svm.core.annotate.AutomaticFeature; +import org.graalvm.nativeimage.Feature; +import org.graalvm.nativeimage.ImageSingletons; +import org.graalvm.nativeimage.LogHandler; +import org.graalvm.nativeimage.c.type.CCharPointer; +import org.graalvm.word.UnsignedWord; + +import com.oracle.svm.core.config.ConfigurationValues; + +@AutomaticFeature +class DefaultLogHandlerFeature implements Feature { + @Override + public void beforeAnalysis(BeforeAnalysisAccess access) { + /* An alternative log handler can be set in Feature.duringSetup(). */ + if (!ImageSingletons.contains(LogHandler.class)) { + /* + * Install the default log handler in ImageSingletons such that if another feature tries + * to install another log handler at a later point it will get an error. + */ + LogHandler logHandler = new DefaultLogHandler(); + ImageSingletons.add(LogHandler.class, logHandler); + } + } +} + +public class DefaultLogHandler implements LogHandler { + + @Override + public void log(CCharPointer bytes, UnsignedWord length) { + if (!ConfigurationValues.getOSInterface().writeBytesUninterruptibly(getOutputFile(), bytes, length)) { + /* + * We are in a low-level log routine and output failed, so there is little we can do. + */ + ConfigurationValues.getOSInterface().abort(); + } + } + + @Override + public void flush() { + ConfigurationValues.getOSInterface().flush(getOutputFile()); + /* ignore error -- they're benign */ + } + + @Override + public void fatalError() { + ConfigurationValues.getOSInterface().abort(); + } + + /* Allow subclasses to customize the file descriptor that we write to. */ + private static FileDescriptor getOutputFile() { + return FileDescriptor.err; + } + +} diff --git a/substratevm/src/com.oracle.svm.core.posix/src/com/oracle/svm/core/posix/SegfaultHandlerFeature.java b/substratevm/src/com.oracle.svm.core.posix/src/com/oracle/svm/core/posix/SegfaultHandlerFeature.java index 7a2c1ec12bb7..b2a9a749fedb 100644 --- a/substratevm/src/com.oracle.svm.core.posix/src/com/oracle/svm/core/posix/SegfaultHandlerFeature.java +++ b/substratevm/src/com.oracle.svm.core.posix/src/com/oracle/svm/core/posix/SegfaultHandlerFeature.java @@ -25,6 +25,7 @@ import org.graalvm.compiler.options.Option; import org.graalvm.compiler.word.Word; import org.graalvm.nativeimage.Feature; +import org.graalvm.nativeimage.LogHandler; import org.graalvm.nativeimage.Platform; import org.graalvm.nativeimage.Platforms; import org.graalvm.nativeimage.StackValue; @@ -120,7 +121,7 @@ private static void dispatch(int signalNumber, @SuppressWarnings("unused") sigin log.string("Use runtime option -R:-InstallSegfaultHandler if you don't want to use SubstrateSegfaultHandler.").newline(); log.newline().string("Bye bye ...").newline().newline(); - LibC.abort(); + LogHandler.get().fatalError(); } /** The address of the signal handler for signals handled by Java code, above. */ diff --git a/substratevm/src/com.oracle.svm.core.posix/src/com/oracle/svm/core/posix/pthread/PthreadVMLockSupport.java b/substratevm/src/com.oracle.svm.core.posix/src/com/oracle/svm/core/posix/pthread/PthreadVMLockSupport.java index 1b0f11b05cb1..1af3765d2efc 100644 --- a/substratevm/src/com.oracle.svm.core.posix/src/com/oracle/svm/core/posix/pthread/PthreadVMLockSupport.java +++ b/substratevm/src/com.oracle.svm.core.posix/src/com/oracle/svm/core/posix/pthread/PthreadVMLockSupport.java @@ -26,6 +26,7 @@ import org.graalvm.compiler.word.Word; import org.graalvm.nativeimage.Feature; import org.graalvm.nativeimage.ImageSingletons; +import org.graalvm.nativeimage.LogHandler; import org.graalvm.nativeimage.Platform; import org.graalvm.nativeimage.Platforms; import org.graalvm.nativeimage.StackValue; @@ -44,9 +45,9 @@ import com.oracle.svm.core.locks.VMMutex; import com.oracle.svm.core.log.Log; import com.oracle.svm.core.posix.headers.Errno; -import com.oracle.svm.core.posix.headers.LibC; import com.oracle.svm.core.posix.headers.Pthread; import com.oracle.svm.core.posix.headers.Time; +import com.oracle.svm.core.thread.VMThreads; import jdk.vm.ci.meta.JavaKind; @@ -140,15 +141,16 @@ public static void initialize() { } } - @Uninterruptible(reason = "Called from uninterruptible code.") + @Uninterruptible(reason = "Called from uninterruptible code.", calleeMustBe = false) protected static void checkResult(int result, String functionName) { if (result != 0) { /* * Functions are called very early and late during our execution, so there is not much * we can do when they fail. */ + VMThreads.StatusSupport.setStatusIgnoreSafepoints(); Log.log().string(functionName).string(" returned ").signed(result).newline(); - LibC.abort(); + LogHandler.get().fatalError(); } } } diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/SubstrateUtil.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/SubstrateUtil.java index 0f500db6afc1..fac8bfbe82da 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/SubstrateUtil.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/SubstrateUtil.java @@ -228,7 +228,6 @@ public interface Thunk { * Prints extensive diagnostic information to the given Log. */ @RestrictHeapAccess(access = RestrictHeapAccess.Access.NO_ALLOCATION, reason = "Must not allocate during printing diagnostics.") - @Uninterruptible(reason = "Allow printDiagnostics to be used in uninterruptible code.", calleeMustBe = false) public static void printDiagnostics(Log log, Pointer sp, CodePointer ip) { if (diagnosticsInProgress) { log.string("Error: printDiagnostics already in progress.").newline(); diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/annotate/RestrictHeapAccess.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/annotate/RestrictHeapAccess.java index 6969a46cfb8f..a17b89383ac1 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/annotate/RestrictHeapAccess.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/annotate/RestrictHeapAccess.java @@ -28,7 +28,8 @@ import java.lang.annotation.Target; /** - * Methods annotated with this annotation have restricted access to the heap. + * Methods annotated with this annotation have restricted access to the heap. This annotation is + * checked transitively, i.e., callees of the annotated method do not need to be annotated. */ @Retention(RetentionPolicy.RUNTIME) @Target({ElementType.METHOD, ElementType.CONSTRUCTOR}) diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/VMErrorSubstitutions.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/VMErrorSubstitutions.java index 1fc4d226b5cc..291beddd8694 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/VMErrorSubstitutions.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/VMErrorSubstitutions.java @@ -22,12 +22,13 @@ */ package com.oracle.svm.core.jdk; +import org.graalvm.nativeimage.LogHandler; + import com.oracle.svm.core.SubstrateUtil; import com.oracle.svm.core.annotate.NeverInline; import com.oracle.svm.core.annotate.Substitute; import com.oracle.svm.core.annotate.TargetClass; import com.oracle.svm.core.annotate.Uninterruptible; -import com.oracle.svm.core.config.ConfigurationValues; import com.oracle.svm.core.log.Log; import com.oracle.svm.core.snippets.KnownIntrinsics; import com.oracle.svm.core.stack.ThreadStackPrinter; @@ -45,12 +46,8 @@ final class Target_com_oracle_svm_core_util_VMError { @Substitute private static RuntimeException shouldNotReachHere() { ThreadStackPrinter.printBacktrace(); - Log log = Log.log(); - log.autoflush(true); - log.string("VMError.shouldNotReachHere").newline(); VMThreads.StatusSupport.setStatusIgnoreSafepoints(); - SubstrateUtil.printDiagnostics(log, KnownIntrinsics.readCallerStackPointer(), KnownIntrinsics.readReturnAddress()); - ConfigurationValues.getOSInterface().abort(); + VMErrorSubstitutions.shutdown(); return null; } @@ -58,12 +55,8 @@ private static RuntimeException shouldNotReachHere() { @Substitute private static RuntimeException shouldNotReachHere(String msg) { ThreadStackPrinter.printBacktrace(); - Log log = Log.log(); - log.autoflush(true); - log.string("VMError.shouldNotReachHere: ").string(msg).newline(); VMThreads.StatusSupport.setStatusIgnoreSafepoints(); - SubstrateUtil.printDiagnostics(log, KnownIntrinsics.readCallerStackPointer(), KnownIntrinsics.readReturnAddress()); - ConfigurationValues.getOSInterface().abort(); + VMErrorSubstitutions.shutdown(msg); return null; } @@ -76,13 +69,9 @@ private static RuntimeException shouldNotReachHere(Throwable ex) { * Throwable. So we access the raw detailMessage directly from the field in Throwable. That * is better than printing nothing. */ - Log log = Log.log(); - log.autoflush(true); String detailMessage = JDKUtils.getRawMessage(ex); - log.string("VMError.shouldNotReachHere: ").string(ex.getClass().getName()).string(": ").string(detailMessage).newline(); VMThreads.StatusSupport.setStatusIgnoreSafepoints(); - SubstrateUtil.printDiagnostics(log, KnownIntrinsics.readCallerStackPointer(), KnownIntrinsics.readReturnAddress()); - ConfigurationValues.getOSInterface().abort(); + VMErrorSubstitutions.shutdown(detailMessage, ex.getClass().getName()); return null; } @@ -116,4 +105,34 @@ private static RuntimeException unsupportedFeature(String msg) { /** Dummy class to have a class with the file's name. */ public class VMErrorSubstitutions { + + @Uninterruptible(reason = "Allow use in uninterruptible code.", calleeMustBe = false) + static void shutdown() { + Log log = Log.log(); + log.autoflush(true); + log.string("VMError.shouldNotReachHere").newline(); + doShutdown(log); + } + + @Uninterruptible(reason = "Allow use in uninterruptible code.", calleeMustBe = false) + static void shutdown(String msg) { + Log log = Log.log(); + log.autoflush(true); + log.string("VMError.shouldNotReachHere: ").string(msg).newline(); + doShutdown(log); + } + + @Uninterruptible(reason = "Allow use in uninterruptible code.", calleeMustBe = false) + static void shutdown(String detailMessage, String exceptionClassName) { + Log log = Log.log(); + log.autoflush(true); + log.string("VMError.shouldNotReachHere: ").string(exceptionClassName).string(": ").string(detailMessage).newline(); + doShutdown(log); + } + + @Uninterruptible(reason = "Allow use in uninterruptible code.", calleeMustBe = false) + private static void doShutdown(Log log) { + SubstrateUtil.printDiagnostics(log, KnownIntrinsics.readCallerStackPointer(), KnownIntrinsics.readReturnAddress()); + LogHandler.get().fatalError(); + } } diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/log/Log.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/log/Log.java index 7ac04bf69d64..cbce2a9bd77d 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/log/Log.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/log/Log.java @@ -33,7 +33,7 @@ import org.graalvm.word.PointerBase; import org.graalvm.word.WordBase; -import com.oracle.svm.core.annotate.Uninterruptible; +import com.oracle.svm.core.annotate.RestrictHeapAccess; /** * Utility class that provides low-level output methods for basic Java data types (strings and @@ -114,31 +114,30 @@ protected Log() { } /** Is this log enabled? */ - @Uninterruptible(reason = "Logging may be called from uninterruptible code.") + @RestrictHeapAccess(access = RestrictHeapAccess.Access.NO_ALLOCATION, reason = "Must not allocate when logging.") public abstract boolean isEnabled(); /** * Prints all characters in the string, without any platform- or charset-depending conversions. */ - @Uninterruptible(reason = "Logging may be called from uninterruptible code.") public abstract Log string(String value); /** * Prints all characters in the string, filling with spaces before or after. */ - @Uninterruptible(reason = "Logging may be called from uninterruptible code.") + @RestrictHeapAccess(access = RestrictHeapAccess.Access.NO_ALLOCATION, reason = "Must not allocate when logging.") public abstract Log string(String str, int fill, int align); /** * Prints all characters in the array, without any platform- or charset-depending conversions. */ - @Uninterruptible(reason = "Logging may be called from uninterruptible code.") + @RestrictHeapAccess(access = RestrictHeapAccess.Access.NO_ALLOCATION, reason = "Must not allocate when logging.") public abstract Log string(char[] value); /** * Prints all bytes in the array, without any conversion. */ - @Uninterruptible(reason = "Logging may be called from uninterruptible code.", mayBeInlined = true) + @RestrictHeapAccess(access = RestrictHeapAccess.Access.NO_ALLOCATION, reason = "Must not allocate when logging.") public final Log string(byte[] value) { return string(value, 0, value.length); } @@ -146,25 +145,25 @@ public final Log string(byte[] value) { /** * Prints the provided range of bytes in the array, without any conversion. */ - @Uninterruptible(reason = "Logging may be called from uninterruptible code.") + @RestrictHeapAccess(access = RestrictHeapAccess.Access.NO_ALLOCATION, reason = "Must not allocate when logging.") public abstract Log string(byte[] value, int offset, int length); /** * Prints the C string. */ - @Uninterruptible(reason = "Logging may be called from uninterruptible code.") + @RestrictHeapAccess(access = RestrictHeapAccess.Access.NO_ALLOCATION, reason = "Must not allocate when logging.") public abstract Log string(CCharPointer value); /** * Prints the provided character. */ - @Uninterruptible(reason = "Logging may be called from uninterruptible code.") + @RestrictHeapAccess(access = RestrictHeapAccess.Access.NO_ALLOCATION, reason = "Must not allocate when logging.") public abstract Log character(char value); /** * Prints the newline character. */ - @Uninterruptible(reason = "Logging may be called from uninterruptible code.") + @RestrictHeapAccess(access = RestrictHeapAccess.Access.NO_ALLOCATION, reason = "Must not allocate when logging.") public abstract Log newline(); /** @@ -172,7 +171,7 @@ public final Log string(byte[] value) { * * @param onOrOff true if auto-flush must be turned on, false otherwise. */ - @Uninterruptible(reason = "Logging may be called from uninterruptible code.", mayBeInlined = true) + @RestrictHeapAccess(access = RestrictHeapAccess.Access.NO_ALLOCATION, reason = "Must not allocate when logging.") public abstract Log autoflush(boolean onOrOff); /** @@ -184,104 +183,104 @@ public final Log string(byte[] value) { * @param signed true if the value should be treated as a signed value (and the digits are * preceded by '-' for negative values). */ - @Uninterruptible(reason = "Logging may be called from uninterruptible code.") + @RestrictHeapAccess(access = RestrictHeapAccess.Access.NO_ALLOCATION, reason = "Must not allocate when logging.") public abstract Log number(long value, int radix, boolean signed); /** * Prints the value, treated as a signed value, in decimal format. */ - @Uninterruptible(reason = "Logging may be called from uninterruptible code.") + @RestrictHeapAccess(access = RestrictHeapAccess.Access.NO_ALLOCATION, reason = "Must not allocate when logging.") public abstract Log signed(WordBase value); /** * Prints the value, treated as a signed value, in decimal format. */ - @Uninterruptible(reason = "Logging may be called from uninterruptible code.") + @RestrictHeapAccess(access = RestrictHeapAccess.Access.NO_ALLOCATION, reason = "Must not allocate when logging.") public abstract Log signed(int value); /** * Prints the value, treated as a signed value, in decimal format. */ - @Uninterruptible(reason = "Logging may be called from uninterruptible code.") + @RestrictHeapAccess(access = RestrictHeapAccess.Access.NO_ALLOCATION, reason = "Must not allocate when logging.") public abstract Log signed(long value); /** * Prints the value, treated as an unsigned value, in decimal format. */ - @Uninterruptible(reason = "Logging may be called from uninterruptible code.") + @RestrictHeapAccess(access = RestrictHeapAccess.Access.NO_ALLOCATION, reason = "Must not allocate when logging.") public abstract Log unsigned(WordBase value); /** * Prints the value, treated as an unsigned value, filing spaces before or after. */ - @Uninterruptible(reason = "Logging may be called from uninterruptible code.") + @RestrictHeapAccess(access = RestrictHeapAccess.Access.NO_ALLOCATION, reason = "Must not allocate when logging.") public abstract Log unsigned(WordBase value, int fill, int align); /** * Prints the value, treated as an unsigned value, in decimal format. */ - @Uninterruptible(reason = "Logging may be called from uninterruptible code.") + @RestrictHeapAccess(access = RestrictHeapAccess.Access.NO_ALLOCATION, reason = "Must not allocate when logging.") public abstract Log unsigned(int value); /** * Prints the value, treated as an unsigned value, in decimal format. */ - @Uninterruptible(reason = "Logging may be called from uninterruptible code.") + @RestrictHeapAccess(access = RestrictHeapAccess.Access.NO_ALLOCATION, reason = "Must not allocate when logging.") public abstract Log unsigned(long value); /** * Prints the value, treated as an unsigned value, filing spaces before or after. */ - @Uninterruptible(reason = "Logging may be called from uninterruptible code.") + @RestrictHeapAccess(access = RestrictHeapAccess.Access.NO_ALLOCATION, reason = "Must not allocate when logging.") public abstract Log unsigned(long value, int fill, int align); - @Uninterruptible(reason = "Logging may be called from uninterruptible code.") + @RestrictHeapAccess(access = RestrictHeapAccess.Access.NO_ALLOCATION, reason = "Must not allocate when logging.") public abstract Log rational(long numerator, long denominator, long decimals); /** * Prints the value, treated as an unsigned value, in hexadecimal format. */ - @Uninterruptible(reason = "Logging may be called from uninterruptible code.") + @RestrictHeapAccess(access = RestrictHeapAccess.Access.NO_ALLOCATION, reason = "Must not allocate when logging.") public abstract Log hex(WordBase value); /** * Prints the value, treated as an unsigned value, in hexadecimal format. */ - @Uninterruptible(reason = "Logging may be called from uninterruptible code.") + @RestrictHeapAccess(access = RestrictHeapAccess.Access.NO_ALLOCATION, reason = "Must not allocate when logging.") public abstract Log hex(int value); /** * Prints the value, treated as an unsigned value, in hexadecimal format. */ - @Uninterruptible(reason = "Logging may be called from uninterruptible code.") + @RestrictHeapAccess(access = RestrictHeapAccess.Access.NO_ALLOCATION, reason = "Must not allocate when logging.") public abstract Log hex(long value); /** * Prints the value, treated as an unsigned value, in hexadecimal format zero filled to * 16-digits. */ - @Uninterruptible(reason = "Logging may be called from uninterruptible code.") + @RestrictHeapAccess(access = RestrictHeapAccess.Access.NO_ALLOCATION, reason = "Must not allocate when logging.") public abstract Log zhex(long value); /** * Prints the value, treated as an unsigned value, in hexadecimal format zero filled to * 8-digits. */ - @Uninterruptible(reason = "Logging may be called from uninterruptible code.") + @RestrictHeapAccess(access = RestrictHeapAccess.Access.NO_ALLOCATION, reason = "Must not allocate when logging.") public abstract Log zhex(int value); /** * Prints the value, treated as an unsigned value, in hexadecimal format zero filled to * 4-digits. */ - @Uninterruptible(reason = "Logging may be called from uninterruptible code.") + @RestrictHeapAccess(access = RestrictHeapAccess.Access.NO_ALLOCATION, reason = "Must not allocate when logging.") public abstract Log zhex(short value); /** * Prints the value, treated as an unsigned value, in hexadecimal format zero filled to * 2-digits. */ - @Uninterruptible(reason = "Logging may be called from uninterruptible code.") + @RestrictHeapAccess(access = RestrictHeapAccess.Access.NO_ALLOCATION, reason = "Must not allocate when logging.") public abstract Log zhex(byte value); /** @@ -291,38 +290,38 @@ public final Log string(byte[] value) { * @param wordSize size in bytes that a single word should have * @param numWords number of words to dump */ - @Uninterruptible(reason = "Logging may be called from uninterruptible code.") + @RestrictHeapAccess(access = RestrictHeapAccess.Access.NO_ALLOCATION, reason = "Must not allocate when logging.") public abstract Log hexdump(PointerBase from, int wordSize, int numWords); /** * Change current amount of indentation. Indentation determines the amount of spaces emitted * after each newline. */ - @Uninterruptible(reason = "Logging may be called from uninterruptible code.") + @RestrictHeapAccess(access = RestrictHeapAccess.Access.NO_ALLOCATION, reason = "Must not allocate when logging.") public abstract Log indent(boolean addOrRemove); /** * Prints the strings "true" or "false" depending on the value. */ - @Uninterruptible(reason = "Logging may be called from uninterruptible code.") + @RestrictHeapAccess(access = RestrictHeapAccess.Access.NO_ALLOCATION, reason = "Must not allocate when logging.") public abstract Log bool(boolean value); /** * Simulates java.lang.String.valueOf(Object obj), but without the call to hashCode(). */ - @Uninterruptible(reason = "Logging may be called from uninterruptible code.") + @RestrictHeapAccess(access = RestrictHeapAccess.Access.NO_ALLOCATION, reason = "Must not allocate when logging.") public abstract Log object(Object value); /** * Prints the requested number of spaces, e.g., for indentation. */ - @Uninterruptible(reason = "Logging may be called from uninterruptible code.") + @RestrictHeapAccess(access = RestrictHeapAccess.Access.NO_ALLOCATION, reason = "Must not allocate when logging.") public abstract Log spaces(int value); /** * Forces the log to flush to its destination. */ - @Uninterruptible(reason = "Logging may be called from uninterruptible code.") + @RestrictHeapAccess(access = RestrictHeapAccess.Access.NO_ALLOCATION, reason = "Must not allocate when logging.") public abstract Log flush(); /** An implementation of AutoCloseable.close(). */ @@ -356,199 +355,166 @@ public void close() { */ private static final class NoopLog extends Log { - @Uninterruptible(reason = "Logging may be called from uninterruptible code.", mayBeInlined = true) protected NoopLog() { super(); } @Override - @Uninterruptible(reason = "Logging may be called from uninterruptible code.", mayBeInlined = true) public boolean isEnabled() { return false; } @Override - @Uninterruptible(reason = "Logging may be called from uninterruptible code.", mayBeInlined = true) public Log string(String value) { return this; } @Override - @Uninterruptible(reason = "Logging may be called from uninterruptible code.", mayBeInlined = true) public Log string(String str, int fill, int align) { return this; } @Override - @Uninterruptible(reason = "Logging may be called from uninterruptible code.", mayBeInlined = true) public Log string(char[] value) { return this; } @Override - @Uninterruptible(reason = "Logging may be called from uninterruptible code.", mayBeInlined = true) public Log string(byte[] value, int offset, int length) { return this; } @Override - @Uninterruptible(reason = "Logging may be called from uninterruptible code.", mayBeInlined = true) public Log string(CCharPointer value) { return this; } @Override - @Uninterruptible(reason = "Logging may be called from uninterruptible code.", mayBeInlined = true) public Log character(char value) { return this; } @Override - @Uninterruptible(reason = "Logging may be called from uninterruptible code.", mayBeInlined = true) public Log newline() { return this; } @Override - @Uninterruptible(reason = "Logging may be called from uninterruptible code.", mayBeInlined = true) public Log number(long value, int radix, boolean signed) { return this; } @Override - @Uninterruptible(reason = "Logging may be called from uninterruptible code.", mayBeInlined = true) public Log signed(WordBase value) { return this; } @Override - @Uninterruptible(reason = "Logging may be called from uninterruptible code.", mayBeInlined = true) public Log signed(int value) { return this; } @Override - @Uninterruptible(reason = "Logging may be called from uninterruptible code.", mayBeInlined = true) public Log signed(long value) { return this; } @Override - @Uninterruptible(reason = "Logging may be called from uninterruptible code.", mayBeInlined = true) public Log unsigned(WordBase value) { return this; } @Override - @Uninterruptible(reason = "Logging may be called from uninterruptible code.", mayBeInlined = true) public Log unsigned(WordBase value, int fill, int align) { return this; } @Override - @Uninterruptible(reason = "Logging may be called from uninterruptible code.", mayBeInlined = true) public Log unsigned(int value) { return this; } @Override - @Uninterruptible(reason = "Logging may be called from uninterruptible code.", mayBeInlined = true) public Log unsigned(long value) { return this; } @Override - @Uninterruptible(reason = "Logging may be called from uninterruptible code.", mayBeInlined = true) public Log unsigned(long value, int fill, int align) { return this; } @Override - @Uninterruptible(reason = "Logging may be called from uninterruptible code.", mayBeInlined = true) public Log rational(long numerator, long denominator, long decimals) { return this; } @Override - @Uninterruptible(reason = "Logging may be called from uninterruptible code.", mayBeInlined = true) public Log hex(WordBase value) { return this; } @Override - @Uninterruptible(reason = "Logging may be called from uninterruptible code.", mayBeInlined = true) public Log hex(int value) { return this; } @Override - @Uninterruptible(reason = "Logging may be called from uninterruptible code.", mayBeInlined = true) public Log hex(long value) { return this; } @Override - @Uninterruptible(reason = "Logging may be called from uninterruptible code.", mayBeInlined = true) public Log bool(boolean value) { return this; } @Override - @Uninterruptible(reason = "Logging may be called from uninterruptible code.", mayBeInlined = true) public Log object(Object value) { return this; } @Override - @Uninterruptible(reason = "Logging may be called from uninterruptible code.", mayBeInlined = true) public Log spaces(int value) { return this; } @Override - @Uninterruptible(reason = "Logging may be called from uninterruptible code.", mayBeInlined = true) public Log flush() { return this; } @Override - @Uninterruptible(reason = "Logging may be called from uninterruptible code.", mayBeInlined = true) public Log autoflush(boolean onOrOff) { return this; } @Override - @Uninterruptible(reason = "Logging may be called from uninterruptible code.", mayBeInlined = true) public Log zhex(long value) { return this; } @Override - @Uninterruptible(reason = "Logging may be called from uninterruptible code.", mayBeInlined = true) public Log zhex(int value) { return this; } @Override - @Uninterruptible(reason = "Logging may be called from uninterruptible code.", mayBeInlined = true) public Log zhex(short value) { return this; } @Override - @Uninterruptible(reason = "Logging may be called from uninterruptible code.", mayBeInlined = true) public Log zhex(byte value) { return this; } @Override - @Uninterruptible(reason = "Logging may be called from uninterruptible code.", mayBeInlined = true) public Log hexdump(PointerBase from, int wordSize, int numWords) { return null; } @Override - @Uninterruptible(reason = "Logging may be called from uninterruptible code.", mayBeInlined = true) public Log indent(boolean addOrRemove) { return this; } diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/log/RealLog.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/log/RealLog.java index 0f9279acf81a..b77bd4bb7711 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/log/RealLog.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/log/RealLog.java @@ -27,6 +27,7 @@ import org.graalvm.compiler.core.common.calc.UnsignedMath; import org.graalvm.compiler.word.Word; +import org.graalvm.nativeimage.LogHandler; import org.graalvm.nativeimage.StackValue; import org.graalvm.nativeimage.c.struct.SizeOf; import org.graalvm.nativeimage.c.type.CCharPointer; @@ -38,16 +39,10 @@ import com.oracle.svm.core.SubstrateUtil; import com.oracle.svm.core.annotate.RestrictHeapAccess; -import com.oracle.svm.core.annotate.Uninterruptible; -import com.oracle.svm.core.config.ConfigurationValues; -import com.oracle.svm.core.hub.LayoutEncoding; -import com.oracle.svm.core.jdk.UninterruptibleUtils; -import com.oracle.svm.core.jdk.UninterruptibleUtils.Integer; -import com.oracle.svm.core.jdk.UninterruptibleUtils.Math; -import com.oracle.svm.core.snippets.KnownIntrinsics; import com.oracle.svm.core.util.VMError; public class RealLog extends Log { + private boolean autoflush = false; private int indent = 0; @@ -55,13 +50,11 @@ protected RealLog() { super(); } - @Uninterruptible(reason = "Logging may be called from uninterruptible code.", mayBeInlined = true) @Override public boolean isEnabled() { return true; } - @Uninterruptible(reason = "Logging may be called from uninterruptible code.", mayBeInlined = true) @Override public Log string(String value) { if (value != null) { @@ -72,7 +65,6 @@ public Log string(String value) { return this; } - @Uninterruptible(reason = "Logging may be called from uninterruptible code.", mayBeInlined = true) @Override public Log string(String str, int fill, int align) { @@ -91,7 +83,6 @@ public Log string(String str, int fill, int align) { return this; } - @Uninterruptible(reason = "Logging may be called from uninterruptible code.", mayBeInlined = true) @Override public Log string(char[] value) { if (value != null) { @@ -102,12 +93,6 @@ public Log string(char[] value) { return this; } - @Uninterruptible(reason = "Returns raw pointer into an array.", callerMustBe = true) - private static CCharPointer arrayBase(Object array) { - return (CCharPointer) Word.objectToUntrackedPointer(array).add(LayoutEncoding.getArrayBaseOffset(KnownIntrinsics.readHub(array).getLayoutEncoding())); - } - - @Uninterruptible(reason = "Uses raw pointer into an array.") @Override public Log string(byte[] value, int offset, int length) { if (value == null) { @@ -115,16 +100,39 @@ public Log string(byte[] value, int offset, int length) { } else if ((offset < 0) || (offset > value.length) || (length < 0) || ((offset + length) > value.length) || ((offset + length) < 0)) { rawString("OUT OF BOUNDS"); } else { - /* - * We pass out a pointer into the array, without any pinning, so that we stay guaranteed - * allocation-free. - */ - rawBytes(arrayBase(value).addressOf(offset), WordFactory.unsigned(length)); + rawBytes(value, offset, length); } return this; } - @Uninterruptible(reason = "Logging may be called from uninterruptible code.", mayBeInlined = true) + /** + * Write a raw java array by copying it first to a stack allocated temporary buffer. Caller must + * ensure that the offset and length are within bounds. + */ + private void rawBytes(byte[] value, int offset, int length) { + /* + * Stack allocation needs an allocation size that is a compile time constant, so we split + * the byte array up in multiple chunks and write them separately. + */ + final int chunkSize = 256; + final CCharPointer bytes = StackValue.get(chunkSize); + + int chunkOffset = offset; + int inputLength = length; + while (inputLength > 0) { + int chunkLength = Math.min(inputLength, chunkSize); + + for (int i = 0; i < chunkLength; i++) { + byte b = value[chunkOffset + i]; + bytes.write(i, b); + } + rawBytes(bytes, WordFactory.unsigned(chunkLength)); + + chunkOffset += chunkLength; + inputLength -= chunkLength; + } + } + @Override public Log string(CCharPointer value) { if (value.notEqual(WordFactory.nullPointer())) { @@ -135,7 +143,6 @@ public Log string(CCharPointer value) { return this; } - @Uninterruptible(reason = "Logging may be called from uninterruptible code.", mayBeInlined = true) @Override public Log character(char value) { CCharPointer bytes = StackValue.get(SizeOf.get(CCharPointer.class)); @@ -144,7 +151,6 @@ public Log character(char value) { return this; } - @Uninterruptible(reason = "Logging may be called from uninterruptible code.", mayBeInlined = true) @Override public Log newline() { character('\n'); @@ -164,13 +170,12 @@ public Log newline() { * @param signed true if the value should be treated as a signed value (and the digits are * preceded by '-' for negative values). */ - @Uninterruptible(reason = "Logging may be called from uninterruptible code.", mayBeInlined = true) + @Override public Log number(long value, int radix, boolean signed) { return number(value, radix, signed, 0, NO_ALIGN); } - @Uninterruptible(reason = "Logging may be called from uninterruptible code.", mayBeInlined = true) private Log number(long value, int radix, boolean signed, int fill, int align) { if (radix < 2 || radix > 36) { /* Ignore bogus parameter value. */ @@ -224,50 +229,42 @@ private Log number(long value, int radix, boolean signed, int fill, int align) { return this; } - @Uninterruptible(reason = "Logging may be called from uninterruptible code.", mayBeInlined = true) @Override public Log signed(WordBase value) { return number(value.rawValue(), 10, true); } - @Uninterruptible(reason = "Logging may be called from uninterruptible code.", mayBeInlined = true) @Override public Log signed(int value) { return number(value, 10, true); } - @Uninterruptible(reason = "Logging may be called from uninterruptible code.", mayBeInlined = true) @Override public Log signed(long value) { return number(value, 10, true); } - @Uninterruptible(reason = "Logging may be called from uninterruptible code.", mayBeInlined = true) @Override public Log unsigned(WordBase value) { return number(value.rawValue(), 10, false); } - @Uninterruptible(reason = "Logging may be called from uninterruptible code.", mayBeInlined = true) @Override public Log unsigned(WordBase value, int fill, int align) { return number(value.rawValue(), 10, false, fill, align); } - @Uninterruptible(reason = "Logging may be called from uninterruptible code.", mayBeInlined = true) @Override public Log unsigned(int value) { // unsigned expansion from int to long return number(value & 0xffffffffL, 10, false); } - @Uninterruptible(reason = "Logging may be called from uninterruptible code.", mayBeInlined = true) @Override public Log unsigned(long value) { return number(value, 10, false); } - @Uninterruptible(reason = "Logging may be called from uninterruptible code.", mayBeInlined = true) @Override public Log unsigned(long value, int fill, int align) { return number(value, 10, false, fill, align); @@ -289,7 +286,7 @@ public Log unsigned(long value, int fill, int align) { * @param decimals number of decimals after the . to be printed. Note that no rounding is * performed and trailing zeros are printed. */ - @Uninterruptible(reason = "Logging may be called from uninterruptible code.", mayBeInlined = true) + @Override public Log rational(long numerator, long denominator, long decimals) { if (denominator == 0) { @@ -317,19 +314,16 @@ public Log rational(long numerator, long denominator, long decimals) { return this; } - @Uninterruptible(reason = "Logging may be called from uninterruptible code.", mayBeInlined = true) @Override public Log hex(WordBase value) { return string("0x").number(value.rawValue(), 16, false); } - @Uninterruptible(reason = "Logging may be called from uninterruptible code.", mayBeInlined = true) @Override public Log hex(int value) { return string("0x").number(value & 0xffffffffL, 16, false); } - @Uninterruptible(reason = "Logging may be called from uninterruptible code.", mayBeInlined = true) @Override public Log hex(long value) { return string("0x").number(value, 16, false); @@ -338,13 +332,11 @@ public Log hex(long value) { private static final byte[] trueString = Boolean.TRUE.toString().getBytes(); private static final byte[] falseString = Boolean.FALSE.toString().getBytes(); - @Uninterruptible(reason = "Logging may be called from uninterruptible code.", mayBeInlined = true) @Override public Log bool(boolean value) { return string(value ? trueString : falseString); } - @Uninterruptible(reason = "Logging may be called from uninterruptible code.", mayBeInlined = true) @Override public Log object(Object value) { return (value == null ? string("null") : string(value.getClass().getName()).string("@").hex(Word.objectToUntrackedPointer(value))); @@ -352,7 +344,6 @@ public Log object(Object value) { private static final char spaceChar = ' '; - @Uninterruptible(reason = "Logging may be called from uninterruptible code.", mayBeInlined = true) @Override public Log spaces(int value) { for (int i = 0; i < value; i += 1) { @@ -361,58 +352,44 @@ public Log spaces(int value) { return this; } - @Uninterruptible(reason = "Logging may be called from uninterruptible code.", mayBeInlined = true) @Override public Log flush() { - ConfigurationValues.getOSInterface().flushUninterruptibly(getOutputFile()); - /* ignore error -- they're benign */ + LogHandler.get().flush(); return this; } - @Uninterruptible(reason = "Logging may be called from uninterruptible code.", mayBeInlined = true) @Override public Log autoflush(boolean onOrOff) { autoflush = onOrOff; return this; } - @Uninterruptible(reason = "Logging may be called from uninterruptible code.", mayBeInlined = true) @Override public Log indent(boolean addOrRemove) { int delta = addOrRemove ? 2 : -2; - indent = UninterruptibleUtils.Math.max(0, indent + delta); + indent = Math.max(0, indent + delta); return newline(); } - @Uninterruptible(reason = "Called from uninterruptible code.") private static byte digit(long d) { return (byte) (d + (d < 10 ? '0' : 'a' - 10)); } @RestrictHeapAccess(access = RestrictHeapAccess.Access.UNRESTRICTED, overridesCallers = true, reason = "Some implementations allocate.") - @Uninterruptible(reason = "bytes can be a raw pointer into an array.", calleeMustBe = false) protected Log rawBytes(CCharPointer bytes, UnsignedWord length) { - if (!ConfigurationValues.getOSInterface().writeBytesUninterruptibly(getOutputFile(), bytes, length)) { - /* - * We are in a low-level log routine and output failed, so there is little we can do. - */ - ConfigurationValues.getOSInterface().abort(); - } + LogHandler.get().log(bytes, length); return this; } /* Allow subclasses to customize the file descriptor that we write to. */ - @Uninterruptible(reason = "Called from uninterruptible code.") protected FileDescriptor getOutputFile() { return FileDescriptor.err; } - @Uninterruptible(reason = "Called from uninterruptible code.") private void rawString(String value) { rawString(SubstrateUtil.getRawStringChars(value)); } - @Uninterruptible(reason = "Called from uninterruptible code.") private void rawString(char[] value) { int length = value.length; @@ -425,7 +402,7 @@ private void rawString(char[] value) { int chunkOffset = 0; while (length > 0) { - int chunkLength = UninterruptibleUtils.Math.min(length, chunkSize); + int chunkLength = Math.min(length, chunkSize); for (int i = 0; i < chunkLength; i++) { char c = value[chunkOffset + i]; @@ -438,10 +415,9 @@ private void rawString(char[] value) { } } - @Uninterruptible(reason = "Logging may be called from uninterruptible code.", mayBeInlined = true) @Override public Log zhex(long value) { - int zeros = UninterruptibleUtils.Long.numberOfLeadingZeros(value); + int zeros = Long.numberOfLeadingZeros(value); int hexZeros = zeros / 4; for (int i = 0; i < hexZeros; i += 1) { character('0'); @@ -452,9 +428,8 @@ public Log zhex(long value) { return this; } - @Uninterruptible(reason = "Logging may be called from uninterruptible code.", mayBeInlined = true) private Log zhex(int value, int wordSizeInBytes) { - int zeros = UninterruptibleUtils.Integer.numberOfLeadingZeros(value) - 32 + (wordSizeInBytes * 8); + int zeros = Integer.numberOfLeadingZeros(value) - 32 + (wordSizeInBytes * 8); int hexZeros = zeros / 4; for (int i = 0; i < hexZeros; i += 1) { character('0'); @@ -465,27 +440,23 @@ private Log zhex(int value, int wordSizeInBytes) { return this; } - @Uninterruptible(reason = "Logging may be called from uninterruptible code.", mayBeInlined = true) @Override public Log zhex(int value) { return zhex(value, 4); } - @Uninterruptible(reason = "Logging may be called from uninterruptible code.", mayBeInlined = true) @Override public Log zhex(short value) { int intValue = value; return zhex(intValue & 0xffff, 2); } - @Uninterruptible(reason = "Logging may be called from uninterruptible code.", mayBeInlined = true) @Override public Log zhex(byte value) { int intValue = value; return zhex(intValue & 0xff, 1); } - @Uninterruptible(reason = "Logging may be called from uninterruptible code.", mayBeInlined = true) @Override public Log hexdump(PointerBase from, int wordSize, int numWords) { Pointer base = WordFactory.pointer(from.rawValue()); diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/snippets/SnippetRuntime.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/snippets/SnippetRuntime.java index 27b1d926cfc9..3f5449236ab3 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/snippets/SnippetRuntime.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/snippets/SnippetRuntime.java @@ -35,6 +35,7 @@ import org.graalvm.compiler.graph.NodeSourcePosition; import org.graalvm.compiler.replacements.nodes.BinaryMathIntrinsicNode.BinaryOperation; import org.graalvm.compiler.replacements.nodes.UnaryMathIntrinsicNode.UnaryOperation; +import org.graalvm.nativeimage.LogHandler; import org.graalvm.nativeimage.c.function.CodePointer; import org.graalvm.word.LocationIdentity; import org.graalvm.word.Pointer; @@ -45,7 +46,6 @@ import com.oracle.svm.core.code.CodeInfoQueryResult; import com.oracle.svm.core.code.CodeInfoTable; import com.oracle.svm.core.code.DeoptimizationSourcePositionDecoder; -import com.oracle.svm.core.config.ConfigurationValues; import com.oracle.svm.core.deopt.DeoptTester; import com.oracle.svm.core.deopt.DeoptimizedFrame; import com.oracle.svm.core.deopt.Deoptimizer; @@ -425,7 +425,7 @@ private static void unwindException(Throwable exception, Pointer callerSP, CodeP */ Log.log().string("Fatal error: recursion in exception handling: ").string(exception.getClass().getName()); Log.log().string(" thrown while unwinding ").string(currentException.get().getClass().getName()).newline(); - ConfigurationValues.getOSInterface().abort(); + LogHandler.get().fatalError(); return; } currentException.set(exception); @@ -452,7 +452,7 @@ public static void reportUnhandledExceptionRaw(Throwable exception) { Log.log().string(": ").string(detail); } Log.log().newline(); - ConfigurationValues.getOSInterface().abort(); + LogHandler.get().fatalError(); } public static void reportUnhandledExceptionJava(Throwable exception) { diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/threadlocal/VMThreadLocalInfos.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/threadlocal/VMThreadLocalInfos.java index 4b34fd00e62c..271b3d6cafd9 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/threadlocal/VMThreadLocalInfos.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/threadlocal/VMThreadLocalInfos.java @@ -56,7 +56,6 @@ public static boolean setInfos(Collection infos) { } } - @Uninterruptible(reason = "called from uninterruptible code") public static void dumpToLog(Log log, IsolateThread thread) { for (VMThreadLocalInfo info : ImageSingletons.lookup(VMThreadLocalInfos.class).infos) { log.signed(info.offset).string(" (").signed(info.sizeInBytes).string(" bytes): ").string(info.name).string(" = "); diff --git a/substratevm/src/com.oracle.svm.jni/src/com/oracle/svm/jni/functions/JNIFunctions.java b/substratevm/src/com.oracle.svm.jni/src/com/oracle/svm/jni/functions/JNIFunctions.java index 5d37834e2982..115aa295a2d6 100644 --- a/substratevm/src/com.oracle.svm.jni/src/com/oracle/svm/jni/functions/JNIFunctions.java +++ b/substratevm/src/com.oracle.svm.jni/src/com/oracle/svm/jni/functions/JNIFunctions.java @@ -37,6 +37,7 @@ import org.graalvm.compiler.word.Word; import org.graalvm.nativeimage.IsolateThread; +import org.graalvm.nativeimage.LogHandler; import org.graalvm.nativeimage.c.function.CEntryPoint; import org.graalvm.nativeimage.c.function.CFunctionPointer; import org.graalvm.nativeimage.c.function.InvokeCFunctionPointer; @@ -58,7 +59,6 @@ import com.oracle.svm.core.c.function.CEntryPointActions; import com.oracle.svm.core.c.function.CEntryPointOptions; import com.oracle.svm.core.c.function.CEntryPointOptions.Publish; -import com.oracle.svm.core.config.ConfigurationValues; import com.oracle.svm.core.log.Log; import com.oracle.svm.core.snippets.KnownIntrinsics; import com.oracle.svm.core.thread.VMThreads; @@ -796,7 +796,7 @@ static void FatalError(JNIEnvironment env, CCharPointer message) { log.string("Fatal error reported via JNI: ").string(message).newline(); VMThreads.StatusSupport.setStatusIgnoreSafepoints(); SubstrateUtil.printDiagnostics(log, KnownIntrinsics.readCallerStackPointer(), KnownIntrinsics.readReturnAddress()); - ConfigurationValues.getOSInterface().abort(); + LogHandler.get().fatalError(); } /*