package com.oracle.svm.core.windows;
import static com.oracle.svm.core.annotate.RecomputeFieldValue.Kind.Custom;
import java.io.FileDescriptor;
import java.io.IOException;
import org.graalvm.nativeimage.PinnedObject;
import org.graalvm.nativeimage.Platform;
import org.graalvm.nativeimage.Platforms;
import org.graalvm.nativeimage.StackValue;
import org.graalvm.nativeimage.c.type.CCharPointer;
import org.graalvm.nativeimage.c.type.CIntPointer;
import org.graalvm.nativeimage.c.type.CLongPointer;
import org.graalvm.word.UnsignedWord;
import org.graalvm.word.WordFactory;
import com.oracle.svm.core.SubstrateUtil;
import com.oracle.svm.core.annotate.Alias;
import com.oracle.svm.core.annotate.RecomputeFieldValue;
import com.oracle.svm.core.annotate.RecomputeFieldValue.CustomFieldValueComputer;
import com.oracle.svm.core.annotate.TargetClass;
import com.oracle.svm.core.annotate.Uninterruptible;
import com.oracle.svm.core.windows.headers.FileAPI;
import com.oracle.svm.core.windows.headers.WinBase;
import jdk.vm.ci.meta.MetaAccessProvider;
import jdk.vm.ci.meta.ResolvedJavaField;
@Platforms(Platform.WINDOWS.class)
public class WindowsUtils {
@TargetClass(className = "java.lang.ProcessImpl")
private static final class Target_java_lang_ProcessImpl {
@Alias long handle;
}
public static int getpid(java.lang.Process process) {
Target_java_lang_ProcessImpl processImpl = SubstrateUtil.cast(process, Target_java_lang_ProcessImpl.class);
return com.oracle.svm.core.windows.headers.Process.GetProcessId(WordFactory.pointer(processImpl.handle));
}
@TargetClass(java.io.FileDescriptor.class)
private static final class Target_java_io_FileDescriptor {
static class InvalidHandleValueComputer implements CustomFieldValueComputer {
@Override
public Object compute(MetaAccessProvider metaAccess, ResolvedJavaField original, ResolvedJavaField annotated, Object receiver) {
return -1L;
}
}
@Alias @RecomputeFieldValue(kind = Custom, declClass = InvalidHandleValueComputer.class)
long handle;
}
static void setHandle(FileDescriptor descriptor, long handle) {
SubstrateUtil.cast(descriptor, Target_java_io_FileDescriptor.class).handle = handle;
}
static boolean outOfBounds(int off, int len, byte[] array) {
return off < 0 || len < 0 || array.length - off < len;
}
public static String lastErrorString(String defaultMsg) {
int error = WinBase.GetLastError();
return defaultMsg + " GetLastError: " + error;
}
public static boolean writeBytes(int handle, CCharPointer bytes, UnsignedWord length) {
CCharPointer curBuf = bytes;
UnsignedWord curLen = length;
while (curLen.notEqual(0)) {
if (handle == -1) {
return false;
}
CIntPointer bytesWritten = StackValue.get(CIntPointer.class);
int ret = FileAPI.WriteFile(handle, curBuf, curLen, bytesWritten, WordFactory.nullPointer());
if (ret == 0) {
return false;
}
int writtenCount = bytesWritten.read();
if (curLen.notEqual(writtenCount)) {
return false;
}
curBuf = curBuf.addressOf(writtenCount);
curLen = curLen.subtract(writtenCount);
}
return true;
}
static boolean flush(int handle) {
if (handle == -1) {
return false;
}
int result = FileAPI.FlushFileBuffers(handle);
return (result != 0);
}
@SuppressWarnings("unused")
static void writeBytes(FileDescriptor descriptor, byte[] bytes, int off, int len, boolean append) throws IOException {
if (bytes == null) {
throw new NullPointerException();
} else if (WindowsUtils.outOfBounds(off, len, bytes)) {
throw new IndexOutOfBoundsException();
}
if (len == 0) {
return;
}
try (PinnedObject bytesPin = PinnedObject.create(bytes)) {
CCharPointer curBuf = bytesPin.addressOfArrayElement(off);
UnsignedWord curLen = WordFactory.unsigned(len);
int handle = FileAPI.GetStdHandle(FileAPI.STD_ERROR_HANDLE());
CIntPointer bytesWritten = StackValue.get(CIntPointer.class);
int ret = FileAPI.WriteFile(handle, curBuf, curLen, bytesWritten, WordFactory.nullPointer());
if (ret == 0) {
throw new IOException(lastErrorString("Write error"));
}
int writtenCount = bytesWritten.read();
if (curLen.notEqual(writtenCount)) {
throw new IOException(lastErrorString("Write error"));
}
}
}
private static long performanceFrequency = 0L;
public static final long NANOSECS_PER_SEC = 1000000000L;
public static final int NANOSECS_PER_MILLISEC = 1000000;
@Uninterruptible(reason = "Called from uninterruptible code.", mayBeInlined = true)
public static long getNanoCounter() {
if (performanceFrequency == 0L) {
CLongPointer count = StackValue.get(CLongPointer.class);
WinBase.QueryPerformanceFrequency(count);
performanceFrequency = count.read();
}
CLongPointer currentCount = StackValue.get(CLongPointer.class);
WinBase.QueryPerformanceCounter(currentCount);
double current = currentCount.read();
double freq = performanceFrequency;
return (long) ((current / freq) * NANOSECS_PER_SEC);
}
}