#include "WAVM/Inline/BasicTypes.h" #include "WAVM/Inline/Errors.h" #include "WAVM/Inline/I128.h" #include "WAVM/Inline/Time.h" #include "WAVM/Platform/Clock.h" #include "WindowsPrivate.h" #define NOMINMAX #include using namespace WAVM; using namespace WAVM::Platform; static I128 fileTimeToI128(FILETIME fileTime) { return I128(U64(fileTime.dwLowDateTime) | (U64(fileTime.dwHighDateTime) << 32)) * 100; } static FILETIME i128ToFileTime(I128 i128) { const I128 fileTime128 = i128 / 100; const U64 fileTime64 = fileTime128 >= 0 && fileTime128 <= UINT64_MAX ? U64(fileTime128) : 0; FILETIME result; result.dwLowDateTime = U32(fileTime64); result.dwHighDateTime = U32(fileTime64 >> 32); return result; } static I128 getRealtimeClockOrigin() { SYSTEMTIME systemTime; systemTime.wYear = 1970; systemTime.wMonth = 1; systemTime.wDay = 1; systemTime.wHour = 0; systemTime.wMinute = 0; systemTime.wSecond = 0; systemTime.wMilliseconds = 0; FILETIME fileTime; WAVM_ERROR_UNLESS(SystemTimeToFileTime(&systemTime, &fileTime)); return fileTimeToI128(fileTime); } static const I128& getCachedRealtimeClockOrigin() { static const I128 cachedRealtimeClockOrigin = getRealtimeClockOrigin(); return cachedRealtimeClockOrigin; } static LARGE_INTEGER getQPCFrequency() { LARGE_INTEGER result; WAVM_ERROR_UNLESS(QueryPerformanceFrequency(&result)); return result; } static LARGE_INTEGER getCachedQPCFrequency() { static const LARGE_INTEGER cachedResult = getQPCFrequency(); return cachedResult; } Time Platform::fileTimeToWAVMRealTime(FILETIME fileTime) { return Time{fileTimeToI128(fileTime) - getCachedRealtimeClockOrigin()}; } FILETIME Platform::wavmRealTimeToFileTime(Time realTime) { return i128ToFileTime(getCachedRealtimeClockOrigin() + realTime.ns); } Time Platform::getClockTime(Clock clock) { switch(clock) { case Clock::realtime: { FILETIME realtimeClock; GetSystemTimePreciseAsFileTime(&realtimeClock); return Time{fileTimeToWAVMRealTime(realtimeClock)}; } case Clock::monotonic: { LARGE_INTEGER ticksPerSecond = getCachedQPCFrequency(); LARGE_INTEGER ticks; WAVM_ERROR_UNLESS(QueryPerformanceCounter(&ticks)); return Time{I128(ticks.QuadPart) * 1000000000 / ticksPerSecond.QuadPart}; } case Clock::processCPUTime: { FILETIME creationTime; FILETIME exitTime; FILETIME kernelTime; FILETIME userTime; WAVM_ERROR_UNLESS( GetProcessTimes(GetCurrentProcess(), &creationTime, &exitTime, &kernelTime, &userTime)); return Time{fileTimeToI128(kernelTime) + fileTimeToI128(userTime)}; } default: WAVM_UNREACHABLE(); }; } Time Platform::getClockResolution(Clock clock) { switch(clock) { case Clock::realtime: return Time{100}; case Clock::monotonic: { LARGE_INTEGER ticksPerSecond = getCachedQPCFrequency(); U64 result = U64(1000000000) / ticksPerSecond.QuadPart; if(result == 0) { result = 1; } return Time{I128(result)}; } case Clock::processCPUTime: return Time{100}; default: WAVM_UNREACHABLE(); }; }