package com.oracle.svm.core.log;
import org.graalvm.nativeimage.ImageSingletons;
import org.graalvm.nativeimage.LogHandler;
import org.graalvm.nativeimage.c.function.CFunctionPointer;
import org.graalvm.nativeimage.c.function.CodePointer;
import org.graalvm.nativeimage.c.function.InvokeCFunctionPointer;
import org.graalvm.nativeimage.c.type.CCharPointer;
import org.graalvm.nativeimage.c.type.WordPointer;
import org.graalvm.word.UnsignedWord;
public class FunctionPointerLogHandler implements LogHandlerExtension {
private final LogHandler delegate;
private LogFunctionPointer logFunctionPointer;
private VoidFunctionPointer flushFunctionPointer;
private VoidFunctionPointer fatalErrorFunctionPointer;
public FunctionPointerLogHandler(LogHandler delegate) {
this.delegate = delegate;
}
@Override
public void log(CCharPointer bytes, UnsignedWord length) {
if (logFunctionPointer.isNonNull()) {
logFunctionPointer.invoke(bytes, length);
} else if (delegate != null) {
delegate.log(bytes, length);
}
}
@Override
public void flush() {
if (flushFunctionPointer.isNonNull()) {
flushFunctionPointer.invoke();
} else if (delegate != null) {
delegate.flush();
}
}
@Override
public boolean fatalContext(CodePointer callerIP, String msg, Throwable ex) {
if (delegate instanceof LogHandlerExtension) {
return ((LogHandlerExtension) delegate).fatalContext(callerIP, msg, ex);
}
return true;
}
@Override
public void fatalError() {
if (fatalErrorFunctionPointer.isNonNull()) {
fatalErrorFunctionPointer.invoke();
} else if (delegate != null) {
delegate.fatalError();
}
}
public CFunctionPointer getFatalErrorFunctionPointer() {
return fatalErrorFunctionPointer;
}
interface LogFunctionPointer extends CFunctionPointer {
@InvokeCFunctionPointer
void invoke(CCharPointer bytes, UnsignedWord length);
}
interface VoidFunctionPointer extends CFunctionPointer {
@InvokeCFunctionPointer
void invoke();
}
interface FatalContextFunctionPointer extends CFunctionPointer {
@InvokeCFunctionPointer
boolean invoke(CodePointer callerIP, String msg, Throwable ex);
}
public static boolean parseVMOption(String optionString, WordPointer extraInfo) {
if (optionString.equals("_log")) {
handler(optionString).logFunctionPointer = (LogFunctionPointer) extraInfo;
return true;
} else if (optionString.equals("_flush_log")) {
handler(optionString).flushFunctionPointer = (VoidFunctionPointer) extraInfo;
return true;
} else if (optionString.equals("_fatal")) {
handler(optionString).fatalErrorFunctionPointer = (VoidFunctionPointer) extraInfo;
return true;
}
return false;
}
private static FunctionPointerLogHandler handler(String optionString) {
LogHandler handler = ImageSingletons.lookup(LogHandler.class);
if (handler == null || !(handler instanceof FunctionPointerLogHandler)) {
throw new IllegalArgumentException("The " + optionString + " option is not supported by JNI_CreateJavaVM");
}
return (FunctionPointerLogHandler) handler;
}
public static void afterParsingVMOptions() {
LogHandler handler = ImageSingletons.lookup(LogHandler.class);
if (handler == null || !(handler instanceof FunctionPointerLogHandler)) {
return;
}
FunctionPointerLogHandler fpHandler = (FunctionPointerLogHandler) handler;
if (fpHandler.logFunctionPointer.isNonNull()) {
if (fpHandler.flushFunctionPointer.isNull()) {
throw new IllegalArgumentException("The _flush_log option cannot be null when _log is non-null");
}
} else if (fpHandler.flushFunctionPointer.isNonNull()) {
throw new IllegalArgumentException("The _log option cannot be null when _flush_log is non-null");
}
}
}