diff --git a/com.oracle.max.vm.native/hosted/platform.c b/com.oracle.max.vm.native/hosted/platform.c index de3410bb39..5147627b04 100644 --- a/com.oracle.max.vm.native/hosted/platform.c +++ b/com.oracle.max.vm.native/hosted/platform.c @@ -18,12 +18,21 @@ * 2 along with this work; if not, write to the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. */ +#include "os.h" +#if !os_WINDOWS #include +#else + #include + #include +#endif #include "word.h" #include "isa.h" #include "jni.h" #include #include +#include + + JNIEXPORT void JNICALL JVM_OnLoad(JavaVM *vm, char *options, void *arg) @@ -54,7 +63,14 @@ Java_com_sun_max_platform_Platform_nativeGetOS(JNIEnv *env, jclass c) JNIEXPORT jint JNICALL Java_com_sun_max_platform_Platform_nativeGetPageSize(JNIEnv *env, jclass c) { - return (jint) sysconf(_SC_PAGESIZE); + #if os_WINDOWS + SYSTEM_INFO systemInfo = {0}; + GetSystemInfo(&systemInfo); + return systemInfo.dwAllocationGranularity ; //Windows do not care about page alignment but about memory allocatio granularity + + #else + return (jint) sysconf(_SC_PAGESIZE); + #endif } diff --git a/com.oracle.max.vm.native/javatest/javatest.mk b/com.oracle.max.vm.native/javatest/javatest.mk index 6a76e4ed70..7890bf514a 100644 --- a/com.oracle.max.vm.native/javatest/javatest.mk +++ b/com.oracle.max.vm.native/javatest/javatest.mk @@ -27,8 +27,11 @@ LIB = javatest include $(PROJECT)/platform/platform.mk -SOURCES = jvmni.c tests.c threads.c jnitests.c - +ifeq ($(OS),windows) + SOURCES = jvmni.c tests.c threads.c jnitests.c jvm.c jni.c threadLocals.c image.c log.c virtualMemory.c mutex.c c.c trap.c time.c jmm.c jvmti.c relocation.c signal.c dataio.c +else + SOURCES = jvmni.c tests.c threads.c jnitests.c +endif SOURCE_DIRS = javatest jni platform hosted share substrate include $(PROJECT)/share/share.mk diff --git a/com.oracle.max.vm.native/javatest/tests.c b/com.oracle.max.vm.native/javatest/tests.c index 94c9cb4f4b..f700cd6dac 100644 --- a/com.oracle.max.vm.native/javatest/tests.c +++ b/com.oracle.max.vm.native/javatest/tests.c @@ -24,8 +24,11 @@ * JNI code for any of the JavaTester tests that use native methods. */ #include "os.h" - +#if !os_WINDOWS #include +#else + #include +#endif #include "jni.h" JNIEXPORT void JNICALL @@ -96,23 +99,42 @@ void upcall(jclass cls) { (*env)->DeleteGlobalRef(env, cls); (*vm)->DetachCurrentThread(vm); } - +#if os_WINDOWS +DWORD WINAPI thread_function(void *arguments) {//we prefer this signature in order to avoid compiler waring on Windows. +#else void *thread_function(void *arguments) { +#endif upcall((jclass) arguments); - return NULL; + #if os_WINDOWS + return 0; + #else + return NULL; + #endif } JNIEXPORT void JNICALL Java_test_output_AttachThread_callHelloWorldOnAttachedThread(JNIEnv *env, jclass clazz) { - pthread_t thread_id; - pthread_attr_t attributes; - + #if !os_WINDOWS + pthread_t thread_id; + pthread_attr_t attributes; + + #endif /* Convert argument to be a global handle as it is going to the new thread */ clazz = (*env)->NewGlobalRef(env, clazz); - void *arguments = clazz; + #if os_WINDOWS + LPVOID + #else + void * + #endif + arguments = clazz; + #if !os_WINDOWS pthread_attr_init(&attributes); pthread_attr_setdetachstate(&attributes, PTHREAD_CREATE_JOINABLE); pthread_create(&thread_id, &attributes, thread_function, arguments); pthread_attr_destroy(&attributes); + #else + CreateThread(NULL, 0, thread_function, arguments, 0, NULL); + + #endif } diff --git a/com.oracle.max.vm.native/launch/launch.mk b/com.oracle.max.vm.native/launch/launch.mk index 4624b29373..04c0268ad5 100644 --- a/com.oracle.max.vm.native/launch/launch.mk +++ b/com.oracle.max.vm.native/launch/launch.mk @@ -32,6 +32,10 @@ SOURCES = maxvm.c SOURCE_DIRS = jni platform share substrate launch include $(PROJECT)/platform/platform.mk +ifeq ($(OS),windows) + MAIN = maxvm.exe #some cp implementations for windows require .exe at the end, while other work without it + +endif include $(PROJECT)/share/share.mk all : $(MAIN) diff --git a/com.oracle.max.vm.native/launch/maxvm.c b/com.oracle.max.vm.native/launch/maxvm.c index 1c45914fff..214a12a67e 100644 --- a/com.oracle.max.vm.native/launch/maxvm.c +++ b/com.oracle.max.vm.native/launch/maxvm.c @@ -18,13 +18,19 @@ * 2 along with this work; if not, write to the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. */ + #include "os.h" +#if os_WINDOWS +#include +char last_dl_error [100]; //emulating dlerror() function not available on Windows + +#else #include +#endif #include #include #include #include -#include "os.h" #include "maxine.h" typedef int (*MaxineFunction)(int argc, char *argv[], char *executablePath); @@ -58,6 +64,15 @@ typedef int (*MaxineFunction)(int argc, char *argv[], char *executablePath); #include const CFNullRef initializeCoreFoundationOnMainThread; +#elif os_WINDOWS +#define LIBRARY_NAME "jvm.dll" +#define MAIN_EXTRA_ARGS +#define PROG_PATH argv[0] +char *dlerror(){ + + + return last_dl_error; +} #else #define LIBRARY_NAME "libjvm.so" #define MAIN_EXTRA_ARGS @@ -108,23 +123,42 @@ int main(int argc, char *argv[] MAIN_EXTRA_ARGS) { strncpy(libraryPath, programPath, prefixLength); strcpy(libraryPath + prefixLength, LIBRARY_NAME); #endif + #if os_WINDOWS + void *result = LoadLibraryA(libraryPath); + if (result==NULL) { + sprintf(last_dl_error, "dl function : LoadLibraryA error code : %lu", GetLastError ()); + fprintf(stderr, "could not load %s: %s %s\n", LIBRARY_NAME, dlerror(), libraryPath); + exit(1); + + } + MaxineFunction maxine = (MaxineFunction) GetProcAddress(result, "maxine"); + if (maxine == 0) { + sprintf(last_dl_error, "dl function : LoadLibraryA error code : %lu", GetLastError ()); + fprintf(stderr, "could not find symbol 'maxine' in %s: %s %s\n", LIBRARY_NAME, dlerror(), libraryPath); + exit(1); + } + + return (*maxine)(argc, argv, NULL); + #else void *handle = dlopen(libraryPath, RTLD_LAZY | RTLD_GLOBAL); if (handle == 0) { - fprintf(stderr, "could not load %s: %s\n", LIBRARY_NAME, dlerror()); + fprintf(stderr, "could not load %s: %s %s\n", LIBRARY_NAME, dlerror(), libraryPath); exit(1); } MaxineFunction maxine = (MaxineFunction) dlsym(handle, "maxine"); if (maxine == 0) { - fprintf(stderr, "could not find symbol 'maxine' in %s: %s\n", LIBRARY_NAME, dlerror()); + fprintf(stderr, "could not find symbol 'maxine' in %s: %s %s\n", LIBRARY_NAME, dlerror(), libraryPath); exit(1); } + #endif #if os_DARWIN return (*maxine)(argc, argv, programPath); #else free(libraryPath); + return (*maxine)(argc, argv, NULL); #endif } diff --git a/com.oracle.max.vm.native/makefile b/com.oracle.max.vm.native/makefile index cab187f58c..1689f20130 100644 --- a/com.oracle.max.vm.native/makefile +++ b/com.oracle.max.vm.native/makefile @@ -27,8 +27,13 @@ # testing, inspecting (browsing, profiling and debugging) and running a Maxine VM. include platform/platform.mk +ifeq ($(OS),windows) + all : hosted substrate launch javatest +else + all : hosted substrate launch javatest tele -all : hosted substrate launch tele javatest + +endif hosted : build/$(OS)/hosted/makefile $(AT) (cd build/$(OS)/hosted; $(MAKE) all) diff --git a/com.oracle.max.vm.native/platform/aarch64.c b/com.oracle.max.vm.native/platform/aarch64.c index 3b946e3ff8..b8ca765cf4 100644 --- a/com.oracle.max.vm.native/platform/aarch64.c +++ b/com.oracle.max.vm.native/platform/aarch64.c @@ -23,7 +23,7 @@ void isa_canonicalizeTeleIntegerRegisters(isa_OsTeleIntegerRegisters os, isa_CanonicalIntegerRegisters c) { -#if os_LINUX +#if os_LINUX || os_WINDOWS #define CANONICALIZE(reg) c->r##reg = (Word) os->regs[reg] #else #define CANONICALIZE(reg, ucReg) c_UNIMPLEMENTED() diff --git a/com.oracle.max.vm.native/platform/aarch64.h b/com.oracle.max.vm.native/platform/aarch64.h index 75303f0b13..5efd40fd8d 100644 --- a/com.oracle.max.vm.native/platform/aarch64.h +++ b/com.oracle.max.vm.native/platform/aarch64.h @@ -23,7 +23,7 @@ #include "word.h" -#if os_LINUX +#if (os_LINUX || os_WINDOWS) # include # include typedef struct user_regs_struct *aarch64_OsTeleIntegerRegisters; diff --git a/com.oracle.max.vm.native/platform/amd64.c b/com.oracle.max.vm.native/platform/amd64.c index 5db518c005..df6edd7508 100644 --- a/com.oracle.max.vm.native/platform/amd64.c +++ b/com.oracle.max.vm.native/platform/amd64.c @@ -27,7 +27,7 @@ void isa_canonicalizeTeleIntegerRegisters(isa_OsTeleIntegerRegisters os, isa_Can #if os_DARWIN #define CANONICALIZE(reg, ucReg) c->reg = (Word) os->__##reg -#elif os_LINUX || os_MAXVE +#elif os_LINUX || os_MAXVE || os_WINDOWS #define CANONICALIZE(reg, ucReg) c->reg = (Word) os->reg #elif os_SOLARIS #define CANONICALIZE(reg, ucReg) c->reg = (Word) os[REG_##ucReg] @@ -58,7 +58,7 @@ void isa_canonicalizeTeleIntegerRegisters(isa_OsTeleIntegerRegisters os, isa_Can void isa_canonicalizeTeleFloatingPointRegisters(isa_OsTeleFloatingPointRegisters os, isa_CanonicalFloatingPointRegisters c) { #if os_DARWIN #define CANONICALIZE(reg) c->xmm##reg = (*((Word *) (&os->__fpu_xmm##reg))) -#elif os_LINUX +#elif os_LINUX || os_WINDOWS #define CANONICALIZE(reg) c->xmm##reg = (Word) ((XMMRegister *) &os->xmm_space)[reg].low #elif os_SOLARIS #define CANONICALIZE(reg) c->xmm##reg = (Word) *((Word *) &os->fp_reg_set.fpchip_state.xmm[reg]) @@ -92,7 +92,7 @@ void isa_canonicalizeTeleStateRegisters(isa_OsTeleStateRegisters os, isa_Canonic #if os_DARWIN c->rip = (Word) os->__rip; c->flags = (Word) os->__rflags; -#elif os_LINUX +#elif os_LINUX || os_WINDOWS c->rip = (Word) os->rip; c->flags = (Word) os->eflags; #elif os_SOLARIS diff --git a/com.oracle.max.vm.native/platform/amd64.h b/com.oracle.max.vm.native/platform/amd64.h index 25f1015604..731be34164 100644 --- a/com.oracle.max.vm.native/platform/amd64.h +++ b/com.oracle.max.vm.native/platform/amd64.h @@ -40,6 +40,16 @@ Word low; Word high; } XMMRegister; +#elif os_WINDOWS +//# include +# include "usercygwinamd64.h" + typedef struct user_regs_struct *amd64_OsTeleIntegerRegisters; + typedef struct user_fpregs_struct *amd64_OsTeleFloatingPointRegisters; + typedef struct user_regs_struct *amd64_OsTeleStateRegisters; + typedef struct { + Word low; + Word high; + } XMMRegister; #elif os_SOLARIS # include typedef prgreg_t *amd64_OsTeleIntegerRegisters; @@ -47,6 +57,12 @@ typedef prgreg_t *amd64_OsTeleStateRegisters; #elif os_MAXVE # include +# include + typedef struct db_regs* amd64_OsTeleIntegerRegisters; + typedef struct db_regs* amd64_OsTeleStateRegisters; + typedef struct db_regs* amd64_OsTeleFloatingPointRegisters; +#elif os_WINDOWS +# include # include typedef struct db_regs* amd64_OsTeleIntegerRegisters; typedef struct db_regs* amd64_OsTeleStateRegisters; diff --git a/com.oracle.max.vm.native/platform/arm.c b/com.oracle.max.vm.native/platform/arm.c index 6b73ec0f9d..8ca37e79bc 100644 --- a/com.oracle.max.vm.native/platform/arm.c +++ b/com.oracle.max.vm.native/platform/arm.c @@ -25,7 +25,7 @@ void isa_canonicalizeTeleIntegerRegisters(isa_OsTeleIntegerRegisters os, isa_Can #if os_DARWIN #define CANONICALIZE(reg, ucReg) c->reg = (Word) os->__##reg -#elif os_LINUX || os_MAXVE +#elif os_LINUX || os_MAXVE || os_WINDOWS #ifdef __arm__ #define CANONICALIZE(reg, intpos) c->reg = (Word) os->uregs[intpos] #else @@ -79,7 +79,7 @@ void isa_canonicalizeTeleIntegerRegisters(isa_OsTeleIntegerRegisters os, isa_Can void isa_canonicalizeTeleFloatingPointRegisters(isa_OsTeleFloatingPointRegisters os, isa_CanonicalFloatingPointRegisters c) { #if os_DARWIN #define CANONICALIZE(reg) c->xmm##reg = (*((Word *) (&os->__fpu_xmm##reg))) -#elif os_LINUX +#elif os_LINUX || os_WINDOWS #define CANONICALIZE(reg) c->xmm##reg = (Word) ((XMMRegister *) &os->xmm_space)[reg].low #elif os_SOLARIS #define CANONICALIZE(reg) c->xmm##reg = (Word) *((Word *) &os->fp_reg_set.fpchip_state.xmm[reg]) @@ -116,7 +116,7 @@ void isa_canonicalizeTeleStateRegisters(isa_OsTeleStateRegisters os, isa_Canonic #if os_DARWIN c->rip = (Word) os->__rip; c->flags = (Word) os->__rflags; -#elif os_LINUX +#elif os_LINUX || os_WINDOWS #ifdef __arm__ log_println("ARM: isa_canonicalizeTeleStateRegisters is not implemented!"); #else diff --git a/com.oracle.max.vm.native/platform/platform.mk b/com.oracle.max.vm.native/platform/platform.mk index 69221735ef..7309157f3e 100644 --- a/com.oracle.max.vm.native/platform/platform.mk +++ b/com.oracle.max.vm.native/platform/platform.mk @@ -22,6 +22,7 @@ # # Print verbose output only when MX_VERBOSE is set to y (i.e. mx -V command is used) + ifneq ($(MX_VERBOSE), y) AT := @ MAKE := $(MAKE) -s @@ -151,9 +152,14 @@ ifeq ($(TARGETOS),SunOS) endif endif -ifeq ($(findstring CYGWIN,$(TARGETOS)),CYGWIN) +ifeq ($(TARGETOS),WindowsNT) OS := windows - ISA := ia32 + ISA := amd64 +else + ifeq ($(findstring MINGW,$(TARGETOS)), MINGW) + OS := windows + ISA := amd64 + endif endif # There are three variants for Maxine VE, owing to the 32/64 dom0 variants @@ -310,20 +316,26 @@ ifeq ($(OS),solaris) endif ifeq ($(OS),windows) - # determine predefined macros: touch foo.c; gcc -E -dD foo.c ifneq "$(findstring def, $(origin CC))" "" # origin of CC is either undefined or default, so set it here CC = gcc endif ifneq "$(findstring def, $(origin CFLAGS))" "" # origin of CFLAGS is either undefined or default, so set it here - CFLAGS = -g -ansi -Wall -pedantic -Wno-long-long -mno-cygwin -DWINDOWS -D$(ISA) -D$(TARGET) -D$(TARGET_WORD_SIZE) $(JDK) + CFLAGS = -g -Wall -Wno-long-long -Wextra -Wno-main -Wno-unused-parameter -fPIC -D_GNU_SOURCE -D$(ISA) -DWINDOWS -D__int64=int64_t -D$(TARGET) -D$(TARGET_WORD_SIZE) $(JDK) $(OTHER_CFLAGS) endif - C_DEPENDENCIES_FLAGS = -MM -DWINDOWS -D$(ISA) -D$(TARGET) -D$(TARGET_WORD_SIZE) - LINK_MAIN = $(CC) -g -mno-cygwin -Wall -W1,----add-stdcall-alias -ldl - LINK_LIB = $(CC) -g -shared -mno-cygwin -Wall -W1,----add-stdcall-alias + C_DEPENDENCIES_FLAGS = -M -DWINDOWS -D$(ISA) -D$(TARGET) -D$(TARGET_WORD_SIZE) + + LINK_MAIN = $(CC) -g -Xlinker -rpath -Xlinker $(shell cd $(PROJECT)/generated/$(OS) && /bin/pwd) -o $(MAIN) + + LINK_LIB = $(CC) -g -shared -mwindows + LINK_LIB_POSTFIX += -lole32 -lws2_32 + + + LIB_PREFIX = - LIB_SUFFIX = .dll + LIB_SUFFIX = .dll + endif ifeq ($(OS),maxve) @@ -413,9 +425,15 @@ else endif JNI_INCLUDES = -I $(dir $(JNI_H_PATH)) endif - else - JNI_INCLUDES = -I $(JAVA_HOME)/include -I $(JAVA_HOME)/include/$(OS) - JNI_H_PATH = $(wildcard $(JAVA_HOME)/include/jni.h) + else + ifeq ($(OS),windows) + JNI_INCLUDES = -I $(JAVA_HOME)/include -I $(JAVA_HOME)/include/win32/ + JNI_H_PATH = $(JAVA_HOME)/include/jni.h + else + JNI_INCLUDES = -I $(JAVA_HOME)/include -I $(JAVA_HOME)/include/$(OS) + JNI_H_PATH = $(wildcard $(JAVA_HOME)/include/jni.h) + endif + endif endif diff --git a/com.oracle.max.vm.native/platform/usercygwinamd64.h b/com.oracle.max.vm.native/platform/usercygwinamd64.h new file mode 100644 index 0000000000..e1a4c0d496 --- /dev/null +++ b/com.oracle.max.vm.native/platform/usercygwinamd64.h @@ -0,0 +1,45 @@ +struct user_fpregs_struct +{ + unsigned short int cwd; + unsigned short int swd; + unsigned short int ftw; + unsigned short int fop; + __extension__ unsigned long long int rip; + __extension__ unsigned long long int rdp; + unsigned int mxcsr; + unsigned int mxcr_mask; + unsigned int st_space[32]; /* 8*16 bytes for each FP-reg = 128 bytes */ + unsigned int xmm_space[64]; /* 16*16 bytes for each XMM-reg = 256 bytes */ + unsigned int padding[24]; +}; + +struct user_regs_struct +{ + __extension__ unsigned long long int r15; + __extension__ unsigned long long int r14; + __extension__ unsigned long long int r13; + __extension__ unsigned long long int r12; + __extension__ unsigned long long int rbp; + __extension__ unsigned long long int rbx; + __extension__ unsigned long long int r11; + __extension__ unsigned long long int r10; + __extension__ unsigned long long int r9; + __extension__ unsigned long long int r8; + __extension__ unsigned long long int rax; + __extension__ unsigned long long int rcx; + __extension__ unsigned long long int rdx; + __extension__ unsigned long long int rsi; + __extension__ unsigned long long int rdi; + __extension__ unsigned long long int orig_rax; + __extension__ unsigned long long int rip; + __extension__ unsigned long long int cs; + __extension__ unsigned long long int eflags; + __extension__ unsigned long long int rsp; + __extension__ unsigned long long int ss; + __extension__ unsigned long long int fs_base; + __extension__ unsigned long long int gs_base; + __extension__ unsigned long long int ds; + __extension__ unsigned long long int es; + __extension__ unsigned long long int fs; + __extension__ unsigned long long int gs; +}; diff --git a/com.oracle.max.vm.native/share/c.h b/com.oracle.max.vm.native/share/c.h index c4add88ca4..ed33c77f61 100644 --- a/com.oracle.max.vm.native/share/c.h +++ b/com.oracle.max.vm.native/share/c.h @@ -53,10 +53,12 @@ typedef long long Signed8; typedef float Float4; typedef double Float8; +#define true 1 +#define false 0 #if !defined(false) && !defined(true) typedef enum {false, true} boolean; #else - typedef int boolean; + typedef unsigned char boolean; #endif #define MAX_PATH_LENGTH 2048 diff --git a/com.oracle.max.vm.native/share/condition.c b/com.oracle.max.vm.native/share/condition.c index 90e052fcfe..b8b8feac0c 100644 --- a/com.oracle.max.vm.native/share/condition.c +++ b/com.oracle.max.vm.native/share/condition.c @@ -18,6 +18,15 @@ * 2 along with this work; if not, write to the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. */ +#include "os.h" +#if os_WINDOWS +#ifdef _WIN32_WINNT +#undef _WIN32_WINNT +#endif +#define _WIN32_WINNT 0x0600 // needed for tools like MINGW in order to use condition variables which became available from Windows Vista and on. Visual Studio might define it on its own +#include + +#endif #include #include #include @@ -45,6 +54,10 @@ void condition_initialize(Condition condition) { } #elif os_MAXVE *condition = maxve_condition_create(); +#elif os_WINDOWS + InitializeConditionVariable(condition); + //initialize condtionVariable does not return anything! + #else # error #endif @@ -62,6 +75,8 @@ void condition_destroy(Condition condition) { if (pthread_cond_destroy(condition) != 0) { c_FATAL(); } +#elif os_WINDOWS +//condition variables cannot get destroyed https://stackoverflow.com/questions/28975958/why-does-windows-have-no-deleteconditionvariable-function-to-go-together-with #endif } @@ -80,7 +95,7 @@ void condition_destroy(Condition condition) { * @return false if an error occurred, true otherwise (i.e. the thread was notified or interrupted). * In either case, the current thread has reacquired the lock on 'mutex'. */ -boolean condition_wait(Condition condition, Mutex mutex) { +boolean condition_wait(Condition condition, Mutex mutex) { //mutex is not needed in windows #if log_MONITORS log_println("condition_wait (" THREAD_CONDVAR_MUTEX_FORMAT ")", thread_self(), condition, mutex); #endif @@ -101,6 +116,8 @@ boolean condition_wait(Condition condition, Mutex mutex) { /* (Doug) I assume 1 means EINTR */ return true; } +#elif os_WINDOWS + error = !SleepConditionVariableCS (condition, mutex, INFINITE); // non zero return value means success on Windows! #endif if (error != 0) { log_println("condition_wait (" THREAD_CONDVAR_MUTEX_FORMAT ") unexpected error code %d [%s]", thread_self(), condition, mutex, error, strerror(error)); @@ -112,7 +129,7 @@ boolean condition_wait(Condition condition, Mutex mutex) { return true; } -#if (os_DARWIN || os_LINUX) +#if (os_DARWIN || os_LINUX ) /* * This function is taken from HotSpot (os_linux.cpp). */ @@ -159,7 +176,7 @@ boolean condition_timedWait(Condition condition, Mutex mutex, Unsigned8 timeoutM log_println("condition_timedWait (" THREAD_CONDVAR_MUTEX_FORMAT ", %d)", thread_self(), condition, mutex, timeoutMilliSeconds); #endif int error; -#if (os_DARWIN || os_LINUX) +#if (os_DARWIN || os_LINUX ) struct timeval now; int status = gettimeofday(&now, NULL); c_ASSERT(status != -1); @@ -198,6 +215,8 @@ boolean condition_timedWait(Condition condition, Mutex mutex, Unsigned8 timeoutM /* (Doug) I assume 1 means EINTR */ return true; } +#elif os_WINDOWS + error = !SleepConditionVariableCS (condition, mutex, timeoutMilliSeconds); // non zero return value means success on Windows! #else # error #endif @@ -222,6 +241,9 @@ boolean condition_notify(Condition condition) { return cond_signal(condition) == 0; #elif os_MAXVE return maxve_condition_notify(*condition, 0) == 0; +#elif os_WINDOWS + WakeConditionVariable (condition); //WakeConditionVariable returns nothing + return true; #else # error #endif @@ -231,12 +253,15 @@ boolean condition_notifyAll(Condition condition) { #if log_MONITORS log_println("condition_notifyAll (" THREAD_CONDVAR_FORMAT ")", thread_self(), condition); #endif -#if (os_DARWIN || os_LINUX) +#if (os_DARWIN || os_LINUX ) return pthread_cond_broadcast(condition) == 0; #elif os_SOLARIS return cond_broadcast(condition) == 0; #elif os_MAXVE return maxve_condition_notify(*condition, 1) == 0; +#elif os_WINDOWS + WakeAllConditionVariable (condition); //WakeAllConditionVariable returns nothing + return true; #else # error #endif diff --git a/com.oracle.max.vm.native/share/condition.h b/com.oracle.max.vm.native/share/condition.h index 93c379f5ca..953fa41c4b 100644 --- a/com.oracle.max.vm.native/share/condition.h +++ b/com.oracle.max.vm.native/share/condition.h @@ -36,6 +36,10 @@ #elif os_MAXVE # include "maxve.h" typedef maxve_condition_t condition_Struct; +#elif os_WINDOWS + typedef CONDITION_VARIABLE condition_Struct; + + #endif typedef condition_Struct *Condition; diff --git a/com.oracle.max.vm.native/share/log.c b/com.oracle.max.vm.native/share/log.c index a5bedc320a..5e5a04a828 100644 --- a/com.oracle.max.vm.native/share/log.c +++ b/com.oracle.max.vm.native/share/log.c @@ -18,17 +18,28 @@ * 2 along with this work; if not, write to the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. */ + + #include #include #include #include -#include #include "log.h" +#if os_WINDOWS +#include +#define pthread_self GetCurrentThread +#else +#include + +#endif + #include "jni.h" #include "mutex.h" #include "threads.h" + + #if !os_MAXVE static FILE *fileStream = NULL; #endif @@ -46,14 +57,14 @@ static mutex_Struct allocationProfiler_mutexStruct; void log_initialize(const char *path) { mutex_initialize(&log_mutexStruct); mutex_initialize(&allocationProfiler_mutexStruct); -#if !os_MAXVE +#if !os_MAXVE && !os_WINDOWS if (path == NULL) { path = "stdout"; } if (strncmp(path, "stdout\0", 7) == 0) { fileStream = stdout; /* Set the file stream to flush whenever a newline character is encountered */ - setlinebuf(fileStream); + // setlinebuf(fileStream); } else if (strncmp(path, "stderr\0", 7) == 0) { fileStream = stderr; } else { @@ -63,7 +74,7 @@ void log_initialize(const char *path) { exit(1); } /* Set the file stream to flush whenever a newline character is encountered */ - setlinebuf(fileStream); + // setlinebuf(fileStream); } #endif } @@ -71,7 +82,7 @@ void log_initialize(const char *path) { void log_lock(void) { int result; if ((result = mutex_enter_nolog(&log_mutexStruct)) != 0) { - log_exit(-1, "Thread %p could not lock mutex %p: %s", thread_self(), &log_mutexStruct, strerror(result)); + log_exit(-1, "Thread %d could not lock mutex %p: %s", pthread_self(), &log_mutexStruct, strerror(result)); } } @@ -79,14 +90,14 @@ void numaProfiler_lock(void) { int result; result = mutex_enter_nolog(&allocationProfiler_mutexStruct); if (result != 0) { - log_exit(-1, "Thread %p could not lock mutex %p: %s", thread_self(), &allocationProfiler_mutexStruct, strerror(result)); + log_exit(-1, "Thread %d could not lock mutex %p: %s", pthread_self(), &allocationProfiler_mutexStruct, strerror(result)); } } void log_unlock(void) { int result; if ((result = mutex_exit_nolog(&log_mutexStruct)) != 0) { - log_exit(-1, "Thread %p could not unlock mutex %p: %s", thread_self(), &log_mutexStruct, strerror(result)); + log_exit(-1, "Thread %d could not unlock mutex %p: %s", pthread_self(), &log_mutexStruct, strerror(result)); } } @@ -94,7 +105,7 @@ void numaProfiler_unlock(void) { int result; result = mutex_exit_nolog(&allocationProfiler_mutexStruct); if (result != 0) { - log_exit(-1, "Thread %p could not unlock mutex %p: %s", thread_self(), &allocationProfiler_mutexStruct, strerror(result)); + log_exit(-1, "Thread %d could not unlock mutex %p: %s", pthread_self(), &allocationProfiler_mutexStruct, strerror(result)); } } @@ -111,14 +122,14 @@ void log_print_format(const char *format, ...) { } void log_flush() { -#if !os_MAXVE +#if !os_MAXVE && !os_WINDOWS FILE* out = fileStream == NULL ? stdout : fileStream; fflush(out); #endif } void log_print_vformat(const char *format, va_list ap) { -#if !os_MAXVE +#if !os_MAXVE && !os_WINDOWS FILE* out = fileStream == NULL ? stdout : fileStream; vfprintf(out, format, ap); #else @@ -197,8 +208,8 @@ void log_print_newline() { } void log_print_symbol(Address address) { -#if !os_MAXVE - Dl_info info; +#if !os_MAXVE && !os_WINDOWS + Dl_info info; if (dladdr((void *) address, &info) != 0) { if (info.dli_sname == NULL) { log_print("%s (%p+%d)", info.dli_fname, info.dli_fbase, address - (Address) info.dli_fbase); diff --git a/com.oracle.max.vm.native/share/mutex.c b/com.oracle.max.vm.native/share/mutex.c index 4902d146fc..3ed0431939 100644 --- a/com.oracle.max.vm.native/share/mutex.c +++ b/com.oracle.max.vm.native/share/mutex.c @@ -20,6 +20,11 @@ * or visit www.oracle.com if you need additional information or have any * questions. */ +#include "os.h" +#if os_WINDOWS +#include +#endif + #include "mutex.h" #include "log.h" #include "threads.h" @@ -50,6 +55,8 @@ void mutex_initialize(Mutex mutex) { } #elif os_MAXVE *mutex = maxve_monitor_create(); +#elif os_WINDOWS + InitializeCriticalSection(mutex); //windows CS's are recursive be default ,mutex is pointer to Critical section # else c_UNIMPLEMENTED(); # endif @@ -65,6 +72,9 @@ int mutex_enter_nolog(Mutex mutex) { c_ASSERT(false); } return 0; +#elif os_WINDOWS + EnterCriticalSection(mutex); //mutex is pointer to Critical section. EnterCriticalSection returns nothing + return 0; //0 means success for funcs like pthread_mutex_lock #else c_UNIMPLEMENTED(); #endif @@ -73,8 +83,11 @@ int mutex_enter_nolog(Mutex mutex) { int mutex_try_enter(Mutex mutex) { #if os_SOLARIS return mutex_trylock(mutex); -#elif os_LINUX || os_DARWIN +#elif os_LINUX || os_DARWIN return pthread_mutex_trylock(mutex); +#elif os_WINDOWS + return !TryEnterCriticalSection(mutex); //mutex is pointer to Critical section. On windows non zero return value means success that's why we use ! at the result + #else c_UNIMPLEMENTED(); #endif @@ -98,6 +111,9 @@ int mutex_exit_nolog(Mutex mutex) { c_ASSERT(false); } return 0; +#elif os_WINDOWS + LeaveCriticalSection(mutex); //mutex is pointer to Critical section + return 0; #else c_UNIMPLEMENTED(); #endif @@ -124,5 +140,8 @@ void mutex_dispose(Mutex mutex) { } #elif os_MAXVE c_UNIMPLEMENTED(); +#elif os_WINDOWS + DeleteCriticalSection(mutex); //mutex is pointer to Critical section + #endif } diff --git a/com.oracle.max.vm.native/share/mutex.h b/com.oracle.max.vm.native/share/mutex.h index 962941271a..68ebec04de 100644 --- a/com.oracle.max.vm.native/share/mutex.h +++ b/com.oracle.max.vm.native/share/mutex.h @@ -35,8 +35,9 @@ #elif os_MAXVE # include typedef maxve_monitor_t mutex_Struct; +#elif os_WINDOWS +typedef CRITICAL_SECTION mutex_Struct; #endif - typedef mutex_Struct *Mutex; extern void mutex_initialize(Mutex mutex); diff --git a/com.oracle.max.vm.native/share/threadLocals.c b/com.oracle.max.vm.native/share/threadLocals.c index 5868340538..d8e2022413 100644 --- a/com.oracle.max.vm.native/share/threadLocals.c +++ b/com.oracle.max.vm.native/share/threadLocals.c @@ -18,7 +18,16 @@ * 2 along with this work; if not, write to the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. */ -#include + #include "os.h" +#if !os_WINDOWS + #include +#else + #include + #include + #include + + #define aligned_alloc(a, b) _aligned_malloc(b, a) +#endif #include #include @@ -48,6 +57,9 @@ typedef maxve_Thread Thread; typedef maxve_SpecificsKey ThreadLocalsKey; typedef void (*ThreadLocalsBlockDestructor)(void *); +#elif os_WINDOWS + typedef DWORD ThreadLocalsKey; + #endif int theTLASize = -1; @@ -68,7 +80,7 @@ static Address allocateThreadLocalBlock(size_t tlBlockSize) { return result; #else c_ASSERT(tlBlockSize < 100000000); - return (Address) aligned_alloc(4096, tlBlockSize); + return (Address) aligned_alloc(virtualMemory_getPageSize(), tlBlockSize); #endif } @@ -86,7 +98,7 @@ static void deallocateThreadLocalBlock(Address tlBlock, Size tlBlockSize) { * lazily commit memory reserved for the initial thread's stack. */ static void commitStackMemoryForInitialThread(Address base, int pageSize) { -#if os_LINUX +#if os_LINUX || os_WINDOWS /* Writing to the bottom page of the reserved stack (appears) not to be * sufficient on Linux. Using alloca() to allocate a chunk approximately * the size of the remaining stack seems to fix it. */ @@ -94,13 +106,17 @@ static void commitStackMemoryForInitialThread(Address base, int pageSize) { alloca(s); volatile char *p = (volatile char *) base; p[0] = p[0]; -#elif os_SOLARIS +#elif os_SOLARIS /* Writing to the bottom page of the reserved stack (appears) to be sufficient on Solaris. */ volatile char *p = (volatile char *) base; p[0] = p[0]; #elif os_DARWIN /* Mac OS X appears to commit the whole stack. */ -#endif +#elif os_WINDOWS // On Windows + //VirtualAlloc(base, pageSize,MEM_COMMIT,PAGE_READWRITE ); + + + #endif } /** @@ -113,9 +129,11 @@ static void commitStackMemoryForInitialThread(Address base, int pageSize) { * @param stackSize ignored if tlBlock != 0 */ Address threadLocalsBlock_create(jint id, Address tlBlock, Size stackSize) { - c_ASSERT(id != 0); + + c_ASSERT(id != 0); const int s = tlaSize(); const int tlaSize = s; + const int pageSize = virtualMemory_getPageSize(); const jboolean attaching = id < 0 || id == PRIMORDIAL_THREAD_ID; jboolean haveRedZone = false; @@ -158,12 +176,12 @@ Address threadLocalsBlock_create(jint id, Address tlBlock, Size stackSize) { /* Clear each of the thread local spaces: */ memset((void *) ttla, 0, tlaSize); + memset((void *) etla, 0, tlaSize); memset((void *) dtla, 0, tlaSize); /* Clear the NativeThreadLocals: */ memset((void *) ntl, 0, sizeof(NativeThreadLocalsStruct)); - ntl->handle = (Address) thread_self(); ntl->stackBase = stackBase; ntl->stackSize = stackSize; @@ -192,13 +210,13 @@ Address threadLocalsBlock_create(jint id, Address tlBlock, Size stackSize) { startGuardZone = ntl->redZone; guardZonePages = YELLOW_ZONE_PAGES + RED_ZONE_PAGES; - if (id == PRIMORDIAL_THREAD_ID) { commitStackMemoryForInitialThread(ntl->stackBase, pageSize); } } - tla_store(etla, ETLA, etla); + tla_store(etla, ETLA, etla); + tla_store(etla, DTLA, dtla); tla_store(etla, TTLA, ttla); @@ -254,8 +272,11 @@ Address threadLocalsBlock_create(jint id, Address tlBlock, Size stackSize) { maxve_initStack(ntl); #else virtualMemory_protectPages(startGuardZone, guardZonePages); + printf("vvvvvvv \n"); + #endif } + /* Protect the first page of the TL block (which contains the first word of the triggered thread locals) */ virtualMemory_protectPages(tlBlock, 1); @@ -347,7 +368,7 @@ void threadLocalsBlock_destroy(Address tlBlock) { void tla_initialize(int tlaSize) { theTLASize = tlaSize; #if !TELE -#if os_DARWIN || os_LINUX +#if os_DARWIN || os_LINUX int error = pthread_key_create(&theThreadLocalsKey, (ThreadLocalsBlockDestructor)(void *) threadLocalsBlock_destroy); #if log_THREADS log_println("tla_initialize: pthread_key_create returned code = %d", error); @@ -355,6 +376,8 @@ void tla_initialize(int tlaSize) { if (error != 0) { log_exit(-1, "tla_initialize: pthread_key_create returned non zero code = %d", error); } +#elif os_WINDOWS + theThreadLocalsKey = TlsAlloc(); #elif os_SOLARIS thr_keycreate(&theThreadLocalsKey, (ThreadLocalsBlockDestructor) threadLocalsBlock_destroy); #elif os_MAXVE @@ -368,7 +391,7 @@ void tla_initialize(int tlaSize) { Address threadLocalsBlock_current() { Address tlBlock; -#if os_DARWIN || os_LINUX +#if os_DARWIN || os_LINUX tlBlock = (Address) pthread_getspecific(theThreadLocalsKey); #elif os_SOLARIS Address value; @@ -379,6 +402,8 @@ Address threadLocalsBlock_current() { tlBlock = value; #elif os_MAXVE tlBlock = (Address) maxve_thread_getSpecific(theThreadLocalsKey); +#elif os_WINDOWS + tlBlock = (Address) TlsGetValue(theThreadLocalsKey); #else c_UNIMPLEMENTED(); #endif @@ -386,12 +411,14 @@ Address threadLocalsBlock_current() { } void threadLocalsBlock_setCurrent(Address tlBlock) { -#if (os_DARWIN || os_LINUX) +#if (os_DARWIN || os_LINUX ) pthread_setspecific(theThreadLocalsKey, (void *) tlBlock); #elif os_SOLARIS thr_setspecific(theThreadLocalsKey, (void *) tlBlock); #elif os_MAXVE maxve_thread_setSpecific(theThreadLocalsKey, (void *) tlBlock); +#elif os_WINDOWS + TlsSetValue(theThreadLocalsKey, (LPVOID) tlBlock); #endif } diff --git a/com.oracle.max.vm.native/share/threads.h b/com.oracle.max.vm.native/share/threads.h index f360882742..63b48db454 100644 --- a/com.oracle.max.vm.native/share/threads.h +++ b/com.oracle.max.vm.native/share/threads.h @@ -80,8 +80,13 @@ typedef void (*VmThreadDetachMethod)(Address tla); * @return true if the sleep was interrupted */ extern jboolean thread_sleep(jlong numberOfMilliSeconds); +#if os_WINDOWS +DWORD WINAPI thread_run(LPVOID param); +#else + +void * thread_run(void *arg); -void *thread_run(void *arg); +#endif int thread_attachCurrent(void **penv, JavaVMAttachArgs* args, boolean daemon); int thread_detachCurrent(); diff --git a/com.oracle.max.vm.native/share/virtualMemory.c b/com.oracle.max.vm.native/share/virtualMemory.c index 1846d69f03..c043583a62 100644 --- a/com.oracle.max.vm.native/share/virtualMemory.c +++ b/com.oracle.max.vm.native/share/virtualMemory.c @@ -18,18 +18,28 @@ * 2 along with this work; if not, write to the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. */ + + #include "virtualMemory.h" #include "log.h" + #if defined(MAXVE) -#include + #include /* No mmap function on MaxVE (yet)*/ #else -#include -#include -#include -#include - + #include + #include + #include + #if !os_WINDOWS + #include + #else + #ifdef _WIN32_WINNT + #undef _WIN32_WINNT + #endif + #define _WIN32_WINNT 0x0601 //needed for tools like MINGW which declare an earlier version of Windows making some features of win32 api unavailable. Visual Studio might not need this. + #include + #endif #include "jni.h" #include "unistd.h" @@ -39,7 +49,7 @@ #endif /* There is a problem binding these identifiers in RedHat's include files, so we fake them: */ -#if os_LINUX +#if os_LINUX || os_WINDOWS # ifndef MAP_ANONYMOUS # define MAP_ANONYMOUS 0x20 # endif @@ -58,11 +68,16 @@ # define MAP_32BIT 0 # endif #endif - +#if !os_WINDOWS #define PROT (PROT_EXEC | PROT_READ | PROT_WRITE) +#endif + +#if !os_WINDOWS //we do not use mmap on Windows so this function is not needed. /* mmap returns MAP_FAILED on error, we convert to ALLOC_FAILED */ static Address check_mmap_result(void *result) { + + #if log_MMAP if(result == MAP_FAILED) { switch(errno) { @@ -99,8 +114,11 @@ static Address check_mmap_result(void *result) { } } #endif + return ((Address) (result == (void *) MAP_FAILED ? ALLOC_FAILED : result)); } +#endif + #ifdef arm static int attempt = 0; @@ -125,8 +143,38 @@ Address virtualMemory_allocatePrivateAnon(Address address, Size size, jboolean r address = allocAddress; } #endif +#if os_WINDOWS + //Windows got no Swap space, so jboolean reserveSwap is redundant + Address result; + if(protNone == JNI_TRUE){ + + result = (Address) VirtualAlloc( (void *) address, size, MEM_RESERVE, PAGE_NOACCESS| PAGE_WRITECOPY); + + //virtualalloc is the only win32 function that supports the PROT_NONE equivalent PAGE_NOACCESS + //PAGE_WRITECOPY is equivalent to MAP_PRIVATE + if(!result) + log_println("%d\n", GetLastError()); + } + else { + //if protnone is not used, we can use CreateFileMappingA + MapViewOfFile combination to emulate mmap() on Windows + //INVALID_HANDLE_VALUE means that we dont use an actual file but the system pagefile, similar to fd= -1 & MPI_ANON in mmap() + HANDLE fmapping = CreateFileMappingA( INVALID_HANDLE_VALUE , NULL , PAGE_EXECUTE_READWRITE | SEC_RESERVE,0u ,size, NULL); + // FILE_MAP_COPY is equivalent to MAP_PRIVATE +if(!fmapping) + log_println("%d\n", GetLastError()); + result = (Address) MapViewOfFileEx (fmapping, FILE_MAP_ALL_ACCESS | FILE_MAP_COPY, 0, 0, size, (LPVOID)address); + // result = (Address) VirtualAlloc( (void *) address, size, MEM_RESERVE, PAGE_READWRITE); + + if(!result) + log_println("%d %d\n", GetLastError(), size); + + + } + return result; + +#else int flags = MAP_PRIVATE | MAP_ANON; -#if os_LINUX +#if os_LINUX /* For some reason, subsequent calls to mmap to allocate out of the space * reserved here only work if the reserved space is in 32-bit space. */ #endif @@ -153,6 +201,7 @@ Address virtualMemory_allocatePrivateAnon(Address address, Size size, jboolean r #else return check_mmap_result(result); #endif +#endif } @@ -172,6 +221,15 @@ Address virtualMemory_mapFile(Size size, jint fd, Size offset) { address = check_mmap_result(result); allocAddress = address + size; return address; +#elif os_WINDOWS + HANDLE fmapping = CreateFileMappingA( (HANDLE)_get_osfhandle(fd) , NULL , PAGE_READWRITE | SEC_COMMIT,0u ,size, NULL); + //_get_osfhandle returns a Windows HANDLE for the file descriptor fd, needed by CreateFileMappingA + Address result = (Address) MapViewOfFile (fmapping, FILE_MAP_READ | FILE_MAP_WRITE| FILE_MAP_COPY, (DWORD)(offset >> 32), (DWORD) offset, size); + //FILE_MAP_COPY is equivalent to mmap's MAP_PRIVATE. It maps a copy-on-write view of the file that is private to the process. + //MapViewOfFile needs lower and high order of offset (last and first 32 bits). We get high and lower orders of the offset (which might be 64bit long) by doing casts to DWORD( 32 BITS) and Binary shifts + if(!result) + log_println("%d\n", GetLastError()); + return result; #else return check_mmap_result(mmap(0, (size_t) size, PROT, MAP_PRIVATE, fd, (off_t) offset)); #endif @@ -183,7 +241,20 @@ Java_com_sun_max_memory_VirtualMemory_virtualMemory_1mapFile(JNIEnv *env, jclass } Address virtualMemory_mapFileIn31BitSpace(jint size, jint fd, Size offset) { + #if os_WINDOWS //MAP_32BIT is not supported on Windows.... Also in Linux, it is no longer really needed + /*"It was added to allow thread stacks to be + allocated somewhere in the first 2 GB of memory, so as to + improve context-switch performance on some early 64-bit + processors. Modern x86-64 processors no longer have this + performance problem, so use of this flag is not required on + those systems. + + https://man7.org/linux/man-pages/man2/mmap.2.html + */ + return virtualMemory_mapFile(size, fd, offset); + #else return check_mmap_result(mmap(0, (size_t) size, PROT, MAP_PRIVATE | MAP_32BIT, fd, (off_t) offset)); + #endif } JNIEXPORT jlong JNICALL @@ -192,7 +263,20 @@ Java_com_sun_max_memory_VirtualMemory_virtualMemory_1mapFileIn31BitSpace(JNIEnv } Address virtualMemory_mapFileAtFixedAddress(Address address, Size size, jint fd, Size offset) { + #if os_WINDOWS + HANDLE fmapping = CreateFileMappingA( (HANDLE)_get_osfhandle(fd) , NULL , PAGE_READWRITE | SEC_COMMIT,0u ,0, NULL); + //_get_osfhandle returns a Windows HANDLE for the file descriptor fd, needed by CreateFileMappingA + if(!fmapping) + log_println("%d\n", GetLastError()); + Address result = (Address) MapViewOfFileEx (fmapping, FILE_MAP_ALL_ACCESS| FILE_MAP_COPY, (DWORD)(offset >> 32), (DWORD) offset, size,(LPVOID) address); + //the only diffrence is that we use MapViewOfFileEx instead MapViewOfFile. The first one allows us to provide an initial base address where the mapping begins (last argument) + + if(!result) + log_println("%d\n", GetLastError()); + return result; + #else return check_mmap_result(mmap((void *) address, (size_t) size, PROT, MAP_PRIVATE | MAP_FIXED, fd, (off_t) offset)); + #endif } // end of conditional exclusion of mmap stuff not available (or used) on MAXVE @@ -202,14 +286,23 @@ Address virtualMemory_mapFileAtFixedAddress(Address address, Size size, jint fd, Address virtualMemory_allocate(Size size, int type) { #if os_MAXVE return (Address) maxve_virtualMemory_allocate(size, type); +#elif os_WINDOWS + HANDLE fmapping = CreateFileMappingA( INVALID_HANDLE_VALUE , NULL , PAGE_READWRITE | SEC_COMMIT,0u ,size, NULL); + Address result = (Address) MapViewOfFile (fmapping, FILE_MAP_READ | FILE_MAP_WRITE, 0, 0, size); + if(!result) + log_println("%d\n", GetLastError()); + return result; #else return check_mmap_result(mmap(0, (size_t) size, PROT, MAP_ANON | MAP_PRIVATE, -1, (off_t) 0)); #endif } Address virtualMemory_allocateIn31BitSpace(Size size, int type) { -#if os_LINUX +#if os_LINUX return check_mmap_result(mmap(0, (size_t) size, PROT, MAP_ANON | MAP_PRIVATE | MAP_32BIT, -1, (off_t) 0)); + +#elif os_WINDOWS + return virtualMemory_allocate(size, type); //windows do not have equivalent of MAP_32BIT, also obsolete in Linux #elif os_MAXVE return (Address) maxve_virtualMemory_allocateIn31BitSpace(size, type); #else @@ -221,6 +314,17 @@ Address virtualMemory_allocateIn31BitSpace(Size size, int type) { Address virtualMemory_deallocate(Address start, Size size, int type) { #if os_MAXVE return (Address) maxve_virtualMemory_deallocate((void *)start, size, type); +#elif os_WINDOWS + if( UnmapViewOfFile((LPVOID) start) == 0){ // VirtualFree will fail for addresses mapped with MapViewOfFile so we use UnmapViewOfFile first + int result = VirtualFree((LPVOID)start, size, type); //if UnmapViewOfFile failed, we try virtualalloc (the memory might got mapped with VirtualAlloc) + //type can be MEM_RELEASE or whatever the user provides. (It was implemented for MAXVE that way) + if (!result) + return result; + else + return start; + } + else + return start; #else int result = munmap((void *) start, (size_t) size); return result == -1 ? 0 : start; @@ -230,6 +334,13 @@ Address virtualMemory_deallocate(Address start, Size size, int type) { boolean virtualMemory_allocateAtFixedAddress(Address address, Size size, int type) { #if os_SOLARIS || os_DARWIN || os_LINUX return check_mmap_result(mmap((void *) address, (size_t) size, PROT, MAP_ANON | MAP_PRIVATE | MAP_FIXED, -1, (off_t) 0)) != ALLOC_FAILED; +#elif os_WINDOWS + HANDLE fmapping = CreateFileMappingA( INVALID_HANDLE_VALUE , NULL , PAGE_READWRITE | SEC_COMMIT,0u ,size, NULL); + //_get_osfhandle returns a Windows HANDLE for the file descriptor fd, needed by CreateFileMappingA + Address result = (Address) MapViewOfFileEx (fmapping, FILE_MAP_READ | FILE_MAP_WRITE| FILE_MAP_COPY, 0, 0, size,(LPVOID) address); + if(!result) + log_println("%d\n", GetLastError()); + return result; #elif os_MAXVE return (Address) maxve_virtualMemory_allocateAtFixedAddress((unsigned long)address, size, type) != ALLOC_FAILED; #else @@ -240,12 +351,19 @@ boolean virtualMemory_allocateAtFixedAddress(Address address, Size size, int typ void virtualMemory_protectPages(Address address, int count) { /* log_println("--- protected %p .. %p", address, address + (count * virtualMemory_getPageSize())); */ - c_ASSERT(virtualMemory_pageAlign(address) == address); -#if os_SOLARIS || os_DARWIN || os_LINUX + c_ASSERT(virtualMemory_pageAlign(address) == address); +#if os_SOLARIS || os_DARWIN || os_LINUX if (mprotect((void *) address, count * virtualMemory_getPageSize(), PROT_NONE) != 0) { int error = errno; log_exit(error, "protectPages: mprotect(%p) failed: %s", address, strerror(error)); } +#elif os_WINDOWS + DWORD old; //needed for VirtualProtect + int error = 0 ; + if(!VirtualProtect((LPVOID) address,count * virtualMemory_getPageSize(), PAGE_NOACCESS, &old)) //PAGE_NOACCESS (WINAPI) = PROT_NONE (UNIX) + log_exit(error, "protectPages: VirtualProtect(%p) failed %d", address, GetLastError()); + + #elif os_MAXVE maxve_virtualMemory_protectPages(address, count); #else @@ -256,11 +374,14 @@ void virtualMemory_protectPages(Address address, int count) { void virtualMemory_unprotectPages(Address address, int count) { /* log_println("--- unprotected %p .. %p", address, address + (count * virtualMemory_getPageSize())); */ c_ASSERT(virtualMemory_pageAlign(address) == address); -#if os_SOLARIS || os_DARWIN || os_LINUX +#if os_SOLARIS || os_DARWIN || os_LINUX if (mprotect((void *) address, count * virtualMemory_getPageSize(), PROT_READ| PROT_WRITE) != 0) { int error = errno; log_exit(error, "unprotectPages: mprotect(%p) failed: %s", address, strerror(error)); } +#elif os_WINDOWS + DWORD old; //needed for VirtualProtect + VirtualProtect((LPVOID) address,count * virtualMemory_getPageSize(), PAGE_READWRITE, &old); //PAGE_NOACCESS (WINAPI) = PROT_NONE (UNIX) #elif os_MAXVE maxve_virtualMemory_unProtectPages(address, count); #else @@ -276,7 +397,13 @@ unsigned int virtualMemory_getPageSize(void) { return maxve_virtualMemory_pageSize(); #else if (pageSize == 0) { + #if os_WINDOWS + SYSTEM_INFO systemInfo = {0}; + GetSystemInfo(&systemInfo); + pageSize = systemInfo.dwAllocationGranularity ; + #else pageSize = getpagesize(); + #endif } return pageSize; #endif @@ -287,9 +414,12 @@ Size virtualMemory_getPhysicalMemorySize(void) { #if os_MAXVE // TODO return 0; -#elif os_SOLARIS || os_LINUX +#elif os_SOLARIS || os_LINUX Size numPhysicalPages = (Size) sysconf(_SC_PHYS_PAGES); physicalMemory = numPhysicalPages * virtualMemory_getPageSize(); +#elif os_WINDOWS + GetPhysicallyInstalledSystemMemory(&physicalMemory); + return physicalMemory * 1024; //we want bytes #elif os_DARWIN int query[2]; query[0] = CTL_HW; @@ -307,6 +437,12 @@ Size virtualMemory_getPhysicalMemorySize(void) { * Aligns a given address up to the next page-aligned address if it is not already page-aligned. */ Address virtualMemory_pageAlign(Address address) { + #if os_WINDOWS //aparrently windows do not care about page alignment but rather memory allocation granularity + SYSTEM_INFO systemInfo = {0}; + GetSystemInfo(&systemInfo); + long alignment = systemInfo.dwAllocationGranularity - 1 ; + #else long alignment = virtualMemory_getPageSize() - 1; + #endif return ((long)(address + alignment) & ~alignment); } diff --git a/com.oracle.max.vm.native/substrate/barrier.c b/com.oracle.max.vm.native/substrate/barrier.c index 86bb92ad9d..20fbdcd928 100644 --- a/com.oracle.max.vm.native/substrate/barrier.c +++ b/com.oracle.max.vm.native/substrate/barrier.c @@ -1,6 +1,4 @@ /* - * Copyright (c) 2020, APT Group, Department of Computer Science, - * School of Engineering, The University of Manchester. All rights reserved. * Copyright (c) 2019, APT Group, School of Computer Science, * The University of Manchester. All rights reserved. * @@ -40,7 +38,7 @@ /* * Pre-processor override for whether to compile in the membarrier system call. - * Currently only affects Aarch64 and RISCV64. See syscall_membarrier() in this compilation + * Currently only affects Aarch64. See syscall_membarrier() in this compilation * unit. */ #ifndef USE_SYS_MEMBARRIER @@ -64,7 +62,7 @@ static int membarrier_init(void) __attribute__ ((unused)); void syscall_membarrier() { -#if isa_AARCH64 || isa_RISCV64 +#if isa_AARCH64 # if USE_SYS_MEMBARRIER static volatile int barrier_kind = 0; if (!barrier_kind) { diff --git a/com.oracle.max.vm.native/substrate/image.c b/com.oracle.max.vm.native/substrate/image.c index 9825dd7ab9..4cb3ee7335 100644 --- a/com.oracle.max.vm.native/substrate/image.c +++ b/com.oracle.max.vm.native/substrate/image.c @@ -20,10 +20,15 @@ */ #include "os.h" + #include #include #include -#include +#if !os_WINDOWS + #include +#else + #include +#endif #include #include @@ -259,6 +264,7 @@ static void checkTrailer(int fd) { if (fileSize != expectedFileSize) { log_exit(2, "wrong image file size: expected %u bytes, read %u", expectedFileSize, fileSize); } + offset = lseek(fd, trailerOffset, SEEK_SET); if (offset != trailerOffset) { log_exit(1, "could not set trailer position in file"); @@ -277,7 +283,7 @@ static void checkTrailer(int fd) { if (trailerStructPtr->identification != theHeader->identification || trailerStructPtr->bootImageFormatVersion != theHeader->bootImageFormatVersion || trailerStructPtr->randomID != theHeader->randomID) { log_println("inconsistent trailer"); #if !MEMORY_IMAGE - offset = lseek(fd, -sizeof(trailerStruct), SEEK_END); + offset = lseek(fd, (long int)-sizeof(trailerStruct), SEEK_END); if (offset != fileSize - (off_t) sizeof(trailerStruct)) { log_exit(1, "could not set trailer position at end of file"); } @@ -294,7 +300,62 @@ static void checkTrailer(int fd) { exit(2); } } +#if os_WINDOWS + +static void mapHeapAndCode_winHandle(HANDLE open_img_result){ + int heapOffsetInImage = virtualMemory_pageAlign(sizeof(struct image_Header) + theHeader->stringDataSize + theHeader->relocationDataSize); + int heapAndCodeSize = theHeader->heapSize + theHeader->codeSize; + c_ASSERT(virtualMemory_pageAlign((Size) heapAndCodeSize) == (Size) heapAndCodeSize); + + + + Address reservedVirtualSpace = (Address) 0; + size_t virtualSpaceSize = 1024L * theHeader->reservedVirtualSpaceSize; + c_ASSERT(virtualMemory_pageAlign((Size) virtualSpaceSize) == (Size) virtualSpaceSize); + if (virtualSpaceSize != 0) { + // VM configuration asks for reserving an address space of size reservedVirtualSpaceSize. + // The following will create a mapping in virtual space of the requested size. + // The address returned might subsequently be used to memory map various regions, including the + // boot heap region, automatically splitting this mapping. + // In any case, the VM (mostly the heap scheme) is responsible for releasing unused reserved space. + reservedVirtualSpace = virtualMemory_allocatePrivateAnon((Address) 0, virtualSpaceSize, JNI_FALSE, JNI_FALSE, HEAP_VM); + if (reservedVirtualSpace == ALLOC_FAILED) { + log_exit(4, "could not reserve requested virtual space"); + } + } + if (theHeader->bootRegionMappingConstraint == 1) { + // Map the boot heap region at the start of the reserved space + theHeap = reservedVirtualSpace; + } else if (theHeader->bootRegionMappingConstraint == 2) { + // Map the boot heap region at the end of the reserved space. The start of the boot heap region is page-aligned. + theHeap = reservedVirtualSpace + virtualSpaceSize - heapAndCodeSize; + } else { + // Map the boot heap region anywhere outside of the reserved space. + theHeap = virtualMemory_allocatePrivateAnon((Address) 0, heapAndCodeSize, JNI_FALSE, JNI_FALSE, HEAP_VM); + if (theHeap == ALLOC_FAILED) { + log_exit(4, "could not reserve virtual space for boot image"); + } + } + virtualMemory_deallocate(theHeap,heapAndCodeSize, MEM_RELEASE ); //windows cannot map twice before freeing. However, we need the first map in order to get a validbase address (correctly aligned) for the second map + + HANDLE fmapping = CreateFileMappingA( open_img_result , NULL , PAGE_EXECUTE_READWRITE| SEC_COMMIT ,0u ,0, NULL); + if(!fmapping) + log_println("ss %d\n", GetLastError()); + Address result = (Address) MapViewOfFileEx (fmapping, FILE_MAP_READ | FILE_MAP_WRITE | FILE_MAP_EXECUTE |FILE_MAP_COPY, (DWORD)((Size)heapOffsetInImage >> 32), (DWORD) heapOffsetInImage, heapAndCodeSize,(LPVOID) theHeap); + + if(!result) + log_println("error %d\n", GetLastError()); + + if (reservedVirtualSpace) { + Address *addr = image_offset_as_address(Address *, reservedVirtualSpaceFieldOffset); + *addr = reservedVirtualSpace; + } + theCode = theHeap + theHeader->heapSize; + theCodeEnd = theCode + theHeader->codeSize; + +} +#endif static void mapHeapAndCode(int fd) { int heapOffsetInImage = virtualMemory_pageAlign(sizeof(struct image_Header) + theHeader->stringDataSize + theHeader->relocationDataSize); int heapAndCodeSize = theHeader->heapSize + theHeader->codeSize; @@ -304,7 +365,7 @@ static void mapHeapAndCode(int fd) { #endif #if MEMORY_IMAGE theHeap = (Address) &maxvm_image_start + heapOffsetInImage; -#elif os_SOLARIS || os_DARWIN || os_LINUX +#elif os_SOLARIS || os_DARWIN || os_LINUX || os_WINDOWS Address reservedVirtualSpace = (Address) 0; size_t virtualSpaceSize = 1024L * theHeader->reservedVirtualSpaceSize; c_ASSERT(virtualMemory_pageAlign((Size) virtualSpaceSize) == (Size) virtualSpaceSize); @@ -332,8 +393,12 @@ static void mapHeapAndCode(int fd) { log_exit(4, "could not reserve virtual space for boot image"); } } - if (virtualMemory_mapFileAtFixedAddress(theHeap, heapAndCodeSize, fd, heapOffsetInImage) == ALLOC_FAILED) { - log_exit(4, "could not map boot image"); + #if os_WINDOWS + virtualMemory_deallocate(theHeap,heapAndCodeSize, MEM_RELEASE ); //windows cannot map twice before freeing. However, we need the first map in order to get a validbase address (correctly aligned) for the second map + #endif + if (virtualMemory_mapFileAtFixedAddress(theHeap, heapAndCodeSize, fd, heapOffsetInImage) == ALLOC_FAILED) { //CAUTION on Windows, the Base Address must be a multiple of dwAllocationGranularity else mapping fails (UNTESTED since no image file is availabe) + + log_exit(4, "could not map boot image"); } if (reservedVirtualSpace) { Address *addr = image_offset_as_address(Address *, reservedVirtualSpaceFieldOffset); @@ -383,7 +448,7 @@ static void relocate(int fd) { } n = read(fd, relocationData, theHeader->relocationDataSize); if (n != theHeader->relocationDataSize) { - log_exit(1, "could not read relocation data"); + log_exit(1, "could not read relocation data %d %d %d ", n, theHeader->relocationDataSize, actualFileOffset); } #else relocationData = (Byte*)(((char*)&maxvm_image_start) + wantedFileOffset); @@ -413,21 +478,46 @@ void image_load(char *imageFileName) { #if log_LOADER log_println("reading image from %s", imageFileName); #endif - fd = open(imageFileName, O_RDWR); - if (fd < 0) { +#if os_WINDOWS +HANDLE open_img_result = CreateFileA( + imageFileName , + GENERIC_READ | GENERIC_WRITE|GENERIC_EXECUTE , + FILE_SHARE_WRITE | FILE_SHARE_READ, + NULL, + OPEN_EXISTING, + FILE_ATTRIBUTE_NORMAL, + NULL +); +if (open_img_result == INVALID_HANDLE_VALUE || !open_img_result) + log_exit(1, "could not open image file: %s %d", imageFileName, GetLastError()); + fd = open(imageFileName, _O_RDWR|_O_BINARY); //on windows, we use the image both as file handle (for executing) as well as a file descriptor (for reading) + +#else + fd = open(imageFileName, O_RDWR); //on windows, we use the image both as file handle (for executing) as well as a file descriptor (for reading) + +#endif +if (fd < 0) { log_exit(1, "could not open image file: %s", imageFileName); } #endif - readHeader(fd); + readHeader(fd); checkImage(); readStringInfo(fd); checkTrailer(fd); + #if os_WINDOWS + //_close(fd); + mapHeapAndCode_winHandle( open_img_result); + //mapHeapAndCode(fd); + + #else mapHeapAndCode(fd); + #endif #if log_LOADER log_println("code @%p codeEnd @%p heap @%p", theCode, theCodeEnd, theHeap); #endif relocate(fd); + #if log_LOADER log_println("code @%p codeEnd @%p heap @%p", theCode, theCodeEnd, theHeap); #endif diff --git a/com.oracle.max.vm.native/substrate/jni.c b/com.oracle.max.vm.native/substrate/jni.c index 871108e597..a18a76141b 100644 --- a/com.oracle.max.vm.native/substrate/jni.c +++ b/com.oracle.max.vm.native/substrate/jni.c @@ -26,7 +26,10 @@ * arguments in such an array. This isolates the implementation of such functions * from the platform/compiler dependent way in which varargs are implemented. */ -#include +#include "os.h" +#if os_WINDOWS +#include +#endif #include #include #include @@ -37,7 +40,9 @@ #include "threads.h" #include "vm.h" - +#if !os_WINDOWS +#include +#endif #ifndef JNI_VERSION_1_6 #error The version of jni.h being included must define the JNI_VERSION_1_6 macro #endif @@ -808,11 +813,15 @@ jint JNICALL jni_GetEnv(JavaVM *javaVM, void **penv, jint version) { return JNI_OK; } } - +#if os_WINDOWS +__declspec( dllimport ) +#endif jint JNICALL JNI_CreateJavaVM(JavaVM **vm, void **penv, void *args) { return c_UNIMPLEMENTED(); } - +#if os_WINDOWS +__declspec( dllimport ) +#endif jint JNICALL jni_DestroyJavaVM(JavaVM *vm) { return c_UNIMPLEMENTED(); } @@ -829,7 +838,9 @@ jint JNICALL jni_AttachCurrentThreadAsDaemon(JavaVM *vm, void **penv, void *args jint JNICALL jni_DetachCurrentThread(JavaVM *vm) { return thread_detachCurrent(); } - +#if os_WINDOWS +__declspec( dllimport ) +#endif jint JNICALL JNI_GetDefaultJavaVMInitArgs(void *args_) { return c_UNIMPLEMENTED(); } @@ -857,7 +868,7 @@ JNIEXPORT jint JNICALL JNI_GetCreatedJavaVMs_Impl(JavaVM **vm, jsize vmBufLen, j return JNI_OK; } -JNIEXPORT jint JNICALL JNI_GetCreatedJavaVMs(JavaVM **vm, jsize vmBufLen, jsize *nVMs) { +JNIEXPORT jint JNICALL __imp_JNI_GetCreatedJavaVMs(JavaVM **vm, jsize vmBufLen, jsize *nVMs) { return JNI_GetCreatedJavaVMs_Impl(vm, vmBufLen, nVMs); } diff --git a/com.oracle.max.vm.native/substrate/jvm.c b/com.oracle.max.vm.native/substrate/jvm.c index c2eab15fbc..0fd63eb587 100644 --- a/com.oracle.max.vm.native/substrate/jvm.c +++ b/com.oracle.max.vm.native/substrate/jvm.c @@ -26,40 +26,71 @@ * In cases where we bypass JDK's native libraries (@see com.sun.max.vm.jdk) * we can simply omit unneeded JVM interface functions that would otherwise occur here. */ -#include +#include "os.h" +#if os_WINDOWS +#ifdef _WIN32_WINNT +#undef _WIN32_WINNT +#endif +#define _WIN32_WINNT 0x0600 //needed for tools like MINGW which declare an earlier version of Windows making some features of win32 api unavailable. Visual Studio might not need this. +#include +#include +#define lseek64 _lseeki64 +#define open _open +#define close _close //open and close work on mingw but are deprecated in MSVC so we better use _ before the name. (Internally, they call win32 funcs like CreateFile() and are added by Microsoft for POSIX compatibility +#define ftruncate _chsize +#define ioctl(a, b, c) ioctlsocket(a, b, (u_long *) c) +#include +#endif + + + + +#include "vm.h" +#include "log.h" +#include "trap.h" +#include "mutex.h" +#include "threads.h" +#include "maxine.h" +#include "memory.h" + +#if !os_WINDOWS + #include #include #include -#include -#include + + #include #include #include #include +#endif +#include + +#include +#include + #if os_DARWIN #include -#else +#elif !os_WINDOWS #include #endif +#if !os_WINDOWS +#include +#endif -#include "vm.h" -#include "log.h" -#include "trap.h" -#include "mutex.h" -#include "threads.h" -#include "maxine.h" -#include "memory.h" #if os_SOLARIS #include #endif -#if os_DARWIN +#if os_DARWIN #define lseek64 lseek #include - #endif +#include + // Platform-independent error return values from OS functions enum OSReturn { @@ -253,7 +284,7 @@ JVM_ActiveProcessorCount(void) { } // Otherwise return number of online cpus return online_cpus; -#elif os_LINUX +#elif os_LINUX cpu_set_t cpus; // can represent at most 1024 (CPU_SETSIZE) processors int cpus_size = sizeof(cpu_set_t); int processor_count = sysconf(_SC_NPROCESSORS_CONF); @@ -279,6 +310,11 @@ JVM_ActiveProcessorCount(void) { int online_cpus = sysconf(_SC_NPROCESSORS_ONLN); c_ASSERT(online_cpus > 0); return online_cpus; +#elif os_WINDOWS + SYSTEM_INFO systemInfo = {0}; + GetSystemInfo(&systemInfo); + return systemInfo.dwNumberOfProcessors; //not sure if we need logical or physical processors + //alternatively we can read NUMBER_OF_PROCESSORS environment variable #else UNIMPLEMENTED(); return 0; @@ -287,12 +323,15 @@ JVM_ActiveProcessorCount(void) { #if os_SOLARIS || os_LINUX || os_DARWIN #include + #endif void * JVM_LoadLibrary(const char *name) { -#if os_SOLARIS || os_LINUX || os_DARWIN +#if os_SOLARIS || os_LINUX || os_DARWIN return dlopen(name, RTLD_LAZY); +#elif os_WINDOWS + return LoadLibraryA(name); #else UNIMPLEMENTED(); return 0; @@ -303,6 +342,8 @@ void JVM_UnloadLibrary(void * handle) { #if os_SOLARIS || os_LINUX || os_DARWIN dlclose(handle); +#elif os_WINDOWS + FreeLibrary(handle); #else UNIMPLEMENTED(); #endif @@ -310,8 +351,10 @@ JVM_UnloadLibrary(void * handle) { void * JVM_FindLibraryEntry(void *handle, const char *name) { -#if os_SOLARIS || os_LINUX || os_DARWIN +#if os_SOLARIS || os_LINUX || os_DARWIN return dlsym(handle, name); +#elif os_WINDOWS + return GetProcAddress(handle, name); #else UNIMPLEMENTED(); return 0; @@ -443,7 +486,9 @@ JVM_SetNativeThreadName(JNIEnv *env, jobject jthread, jstring name) { /* Same as JDK7u4 (and before): do nothing as not yet implemented on either Solaris / Linux */ #endif } - +#if os_WINDOWS //Microsot uses an empty Yield() Macro (obsolete, not needed) in windows.h which breaks our code so we need to undef it. +#undef Yield +#endif void JVM_Yield(JNIEnv *env, jclass threadClass) { vm.Yield(env); @@ -591,7 +636,7 @@ JVM_GetArrayElement(JNIEnv *env, jobject arr, jint index) { jvalue JVM_GetPrimitiveArrayElement(JNIEnv *env, jobject arr, jint index, jint wCode) { UNIMPLEMENTED_WITH_ENV(); - return (jvalue) 0; + return (jvalue) (jint)0; } void @@ -725,7 +770,9 @@ JVM_DefineClassWithSource(JNIEnv *env, const char *name, jobject loader, /* * Reflection support functions */ - +#if os_WINDOWS //Microsot defines GetClassName as GetClassNameA in windows.h which breaks our code so we need to undef it. +#undef GetClassName +#endif jstring JVM_GetClassName(JNIEnv *env, jclass cls) { return vm.GetClassName(env, cls); @@ -1084,36 +1131,37 @@ JVM_RaiseSignal(jint sig) { if (kill(getpid(), sig) < 0) { log_println("error raising signal %d in current process: %s", sig, strerror(errno)); } +#elif os_WINDOWS + if(raise(sig)) + log_println("error raising signal %d in current process: %s", sig, strerror(errno)); + #else UNIMPLEMENTED(); #endif return JNI_TRUE; } -#if os_DARWIN || os_LINUX +#if os_DARWIN || os_LINUX || os_WINDOWS typedef struct { const char *name; int number; } Signal; Signal signals[] = { + #if !os_WINDOWS {"HUP", SIGHUP}, - {"INT", SIGINT}, + {"QUIT", SIGQUIT}, {"ILL", SIGILL}, {"TRAP", SIGTRAP}, - {"ABRT", SIGABRT}, #if os_DARWIN {"EMT", SIGEMT}, #endif - {"FPE", SIGFPE}, {"KILL", SIGKILL}, {"BUS", SIGBUS}, - {"SEGV", SIGSEGV}, {"SYS", SIGSYS}, {"PIPE", SIGPIPE}, {"ALRM", SIGALRM}, - {"TERM", SIGTERM}, {"URG", SIGURG}, {"STOP", SIGSTOP}, {"TSTP", SIGTSTP}, @@ -1132,12 +1180,23 @@ Signal signals[] = { #endif {"USR1", SIGUSR1}, {"USR2", SIGUSR2}, + + + #endif + {"ABRT", SIGABRT}, + {"FPE", SIGFPE}, + {"ILL", SIGILL}, + {"INT", SIGINT}, + {"SEGV", SIGSEGV}, + {"TERM", SIGTERM}, + + }; #endif jint JVM_FindSignal(const char *name) { -#if os_DARWIN || os_LINUX +#if os_DARWIN || os_LINUX || os_WINDOWS unsigned int i; for (i = 0; i < ARRAY_LENGTH(signals); i++) { if(!strcmp(name, signals[i].name)) { @@ -1804,7 +1863,7 @@ jint JVM_GetLastErrorString(char *buffer, size_t length) { if (errno == 0) { return 0; } -#if os_DARWIN || os_SOLARIS || os_LINUX +#if os_DARWIN || os_SOLARIS || os_LINUX || os_WINDOWS const char *s = strerror(errno); size_t n = strlen(s); if (n >= length) { @@ -1826,7 +1885,7 @@ jint JVM_GetLastErrorString(char *buffer, size_t length) { */ char *JVM_NativePath(char *path) { jvmni_log_println("JVM_NativePath(%s)", path); -#if os_DARWIN || os_SOLARIS || os_LINUX +#if os_DARWIN || os_SOLARIS || os_LINUX || os_WINDOWS return path; #else UNIMPLEMENTED(); @@ -1902,6 +1961,7 @@ JVM_Write(jint fd, char *buf, jint nbytes) { jint JVM_Available(jint fd, jlong *pbytes) { jlong cur, end; + #if !os_WINDOWS struct stat st; if (fstat(fd, &st) >= 0) { if (S_ISCHR(st.st_mode) || S_ISFIFO(st.st_mode) || S_ISSOCK(st.st_mode)) { @@ -1912,6 +1972,7 @@ jint JVM_Available(jint fd, jlong *pbytes) { } } } + #endif if ((cur = lseek64(fd, 0L, SEEK_CUR)) == -1) { return 0; } else if ((end = lseek64(fd, 0L, SEEK_END)) == -1) { @@ -1945,7 +2006,9 @@ JVM_Lseek(jint fd, jlong offset, jint whence) { */ jint JVM_SetLength(jint fd, jlong length) { - return ftruncate(fd, length); + return + + ftruncate(fd, length); } /* @@ -1954,7 +2017,12 @@ JVM_SetLength(jint fd, jlong length) { */ jint JVM_Sync(jint fd) { - return fsync(fd); + #if !os_WINDOWS + return fsync(fd); + #else + return !FlushFileBuffers((HANDLE)_get_osfhandle(fd)); //_get_osfhandle transforms fd to HANDLE that is needed by FlushFileBuffers +//Windows return nonzero on success + #endif } /* @@ -1963,7 +2031,7 @@ JVM_Sync(jint fd) { jint JVM_InitializeSocketLibrary(void) { -#if os_SOLARIS || os_LINUX || os_DARWIN +#if os_SOLARIS || os_LINUX || os_DARWIN || os_WINDOWS return 0; #else UNIMPLEMENTED(); @@ -1971,16 +2039,15 @@ JVM_InitializeSocketLibrary(void) { #endif } -#if os_SOLARIS || os_LINUX || os_DARWIN +#if os_SOLARIS || os_LINUX || os_DARWIN || os_WINDOWS #include -#include #else struct sockaddr; #endif jint JVM_Socket(jint domain, jint type, jint protocol) { -#if os_SOLARIS || os_LINUX || os_DARWIN +#if os_SOLARIS || os_LINUX || os_DARWIN || os_WINDOWS return socket(domain, type, protocol); #else UNIMPLEMENTED(); @@ -1990,7 +2057,7 @@ JVM_Socket(jint domain, jint type, jint protocol) { jint JVM_SocketClose(jint fd) { -#if os_SOLARIS || os_LINUX || os_DARWIN +#if os_SOLARIS || os_LINUX || os_DARWIN || os_WINDOWS return close(fd); #else UNIMPLEMENTED(); @@ -2000,7 +2067,7 @@ JVM_SocketClose(jint fd) { jint JVM_SocketShutdown(jint fd, jint howto) { -#if os_SOLARIS || os_LINUX || os_DARWIN +#if os_SOLARIS || os_LINUX || os_DARWIN || os_WINDOWS return shutdown(fd, howto); #else UNIMPLEMENTED(); @@ -2010,7 +2077,9 @@ JVM_SocketShutdown(jint fd, jint howto) { jint JVM_Recv(jint fd, char *buf, jint nBytes, jint flags) { -#if os_SOLARIS || os_LINUX || os_DARWIN +#if os_SOLARIS || os_LINUX || os_DARWIN || os_WINDOWS + + return recv(fd, buf, nBytes, flags); #else UNIMPLEMENTED(); @@ -2020,7 +2089,8 @@ JVM_Recv(jint fd, char *buf, jint nBytes, jint flags) { jint JVM_Send(jint fd, char *buf, jint nBytes, jint flags) { -#if os_SOLARIS || os_LINUX || os_DARWIN +#if os_SOLARIS || os_LINUX || os_DARWIN || os_WINDOWS + return send(fd, buf, nBytes, flags); #else UNIMPLEMENTED(); @@ -2028,6 +2098,10 @@ JVM_Send(jint fd, char *buf, jint nBytes, jint flags) { #endif } +#if os_WINDOWS +extern int gettimeofday(struct timeval * tp); + +#endif jint JVM_Timeout(int fd, long timeout) { #if os_DARWIN || os_LINUX @@ -2085,6 +2159,36 @@ JVM_Timeout(int fd, long timeout) { } } else return res; } +#elif os_WINDOWS +Unsigned8 prevtime,newtime; + struct timeval t; + + gettimeofday(&t); + prevtime = ((Unsigned8)t.tv_sec * 1000) + t.tv_usec / 1000; + + for(;;) { + WSAPOLLFD pfd; + + pfd.fd = fd; + pfd.events = POLLIN | POLLERR; + + int res = WSAPoll(&pfd, 1, timeout); + + if (res == SOCKET_ERROR && errno == EINTR) { + + // On Windows any value < 0 means "forever" too + + if(timeout >= 0) { + gettimeofday(&t); + newtime = ((Unsigned8)t.tv_sec * 1000) + t.tv_usec / 1000; + timeout -= newtime - prevtime; + if(timeout <= 0) + return OS_OK; + prevtime = newtime; + } + } else + return res; + } #else UNIMPLEMENTED(); return 0; @@ -2093,7 +2197,7 @@ JVM_Timeout(int fd, long timeout) { jint JVM_Listen(jint fd, jint count) { -#if os_SOLARIS || os_LINUX || os_DARWIN +#if os_SOLARIS || os_LINUX || os_DARWIN || os_WINDOWS return listen(fd, count); #else UNIMPLEMENTED(); @@ -2103,7 +2207,7 @@ JVM_Listen(jint fd, jint count) { jint JVM_Connect(jint fd, struct sockaddr *him, jint len) { -#if os_SOLARIS || os_LINUX || os_DARWIN +#if os_SOLARIS || os_LINUX || os_DARWIN || os_WINDOWS return connect(fd, him, len); #else UNIMPLEMENTED(); @@ -2113,7 +2217,7 @@ JVM_Connect(jint fd, struct sockaddr *him, jint len) { jint JVM_Bind(jint fd, struct sockaddr *him, jint len) { -#if os_SOLARIS || os_LINUX || os_DARWIN +#if os_SOLARIS || os_LINUX || os_DARWIN || os_WINDOWS return bind(fd, him, len); #else UNIMPLEMENTED(); @@ -2123,7 +2227,7 @@ JVM_Bind(jint fd, struct sockaddr *him, jint len) { jint JVM_Accept(jint fd, struct sockaddr *him, jint *len) { -#if os_SOLARIS || os_LINUX || os_DARWIN +#if os_SOLARIS || os_LINUX || os_DARWIN || os_WINDOWS if (fd < 0) { return -1; } @@ -2173,7 +2277,8 @@ JVM_SocketAvailable(jint fd, jint *pbytes) { // note ioctl can return 0 when successful, JVM_SocketAvailable // is expected to return 0 on failure and 1 on success to the jdk. return (ret == OS_ERR) ? 0 : 1; -#elif os_LINUX +#elif os_LINUX || os_WINDOWS + // Linux doc says EINTR not returned, unlike Solaris int ret = ioctl(fd, FIONREAD, pbytes); @@ -2189,7 +2294,7 @@ JVM_SocketAvailable(jint fd, jint *pbytes) { jint JVM_GetSockName(jint fd, struct sockaddr *him, int *len) { -#if os_SOLARIS || os_LINUX || os_DARWIN +#if os_SOLARIS || os_LINUX || os_DARWIN || os_WINDOWS return getsockname(fd, him, (socklen_t*) len); #else UNIMPLEMENTED(); @@ -2199,7 +2304,7 @@ JVM_GetSockName(jint fd, struct sockaddr *him, int *len) { jint JVM_GetSockOpt(jint fd, int level, int optname, char *optval, int *optlen) { -#if os_SOLARIS || os_LINUX || os_DARWIN +#if os_SOLARIS || os_LINUX || os_DARWIN || os_WINDOWS return getsockopt(fd, level, optname, optval, (socklen_t*) optlen); #else UNIMPLEMENTED(); @@ -2209,7 +2314,7 @@ JVM_GetSockOpt(jint fd, int level, int optname, char *optval, int *optlen) { jint JVM_SetSockOpt(jint fd, int level, int optname, const char *optval, int optlen) { -#if os_SOLARIS || os_LINUX || os_DARWIN +#if os_SOLARIS || os_LINUX || os_DARWIN || os_WINDOWS return setsockopt(fd, level, optname, optval, optlen); #else UNIMPLEMENTED(); @@ -2245,7 +2350,7 @@ JVM_GetHostByName(char* name) { int JVM_GetHostName(char* name, int namelen) { -#if os_SOLARIS || os_LINUX || os_DARWIN +#if os_SOLARIS || os_LINUX || os_DARWIN || os_WINDOWS return gethostname(name, namelen); #else UNIMPLEMENTED(); diff --git a/com.oracle.max.vm.native/substrate/jvmti.c b/com.oracle.max.vm.native/substrate/jvmti.c index c8b9dc0129..5e6c923371 100644 --- a/com.oracle.max.vm.native/substrate/jvmti.c +++ b/com.oracle.max.vm.native/substrate/jvmti.c @@ -18,7 +18,15 @@ * 2 along with this work; if not, write to the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. */ +#include "os.h" +#if os_WINDOWS +#ifdef _WIN32_WINNT +#undef _WIN32_WINNT +#endif +#define _WIN32_WINNT 0x0600 // needed for tools like MINGW in order to use condition variables which became available from Windows Vista and on. Visual Studio might define it on its own +#include +#endif #include #include #include @@ -28,7 +36,7 @@ // (cwi): Java 7 added a new JVMTI function, so it is necessary to distinguish between Java 6 and Java 7. // This is the only #define that I found in the header files that allows this distinction. -#if os_LINUX || os_SOLARIS +#if os_LINUX || os_SOLARIS || os_WINDOWS #include #endif diff --git a/com.oracle.max.vm.native/substrate/maxine.c b/com.oracle.max.vm.native/substrate/maxine.c index a8a3dbf3bf..c50c2bfda3 100644 --- a/com.oracle.max.vm.native/substrate/maxine.c +++ b/com.oracle.max.vm.native/substrate/maxine.c @@ -26,35 +26,67 @@ * hands control over to the VM's compiled code, which has been written in Java, * by calling a VM entry point as a C function. */ -#include + #include "os.h" + + #if !os_WINDOWS + #include + #include + #include + #include + #include + #include + #include +#else + #ifdef _WIN32_WINNT + #undef _WIN32_WINNT + #endif + #define _WIN32_WINNT 0x0600 //needed for tools like MINGW which declare an earlier version of Windows making some features of win32 api unavailable. Visual Studio might not need this. + #include + #include + #include + #include + #include + #define sleep(a) Sleep(a * 1000) + #define strdup _strdup + char last_dl_error [100]; //emulating dlerror() function not available on Windows + char *dlerror(){ + + + return last_dl_error; + } + +#endif + + #include #include -#include -#include + #include -#include #include -#include -#include -#include + #include #include "log.h" #include "isa.h" #include "image.h" #include "threads.h" -#include "os.h" #include "vm.h" #include "virtualMemory.h" #include "maxine.h" #include + + + + #if os_MAXVE #include "maxve.h" #endif -#ifdef arm +#ifdef arm +#if !os_WINDOWS #include #endif +#endif static void max_fd_limit() { @@ -76,7 +108,10 @@ static void max_fd_limit() { log_println("setrlimit failed"); } } +#elif os_WINDOWS + _setmaxstdio(16777216); //windows support setting the max number of fds but they do not have a global max defined. That numer is the theoeretical max fo 64 bit machines #endif + } #define IMAGE_FILE_NAME "maxine.vm" @@ -96,15 +131,18 @@ static void getExecutablePath(char *result) { #elif os_MAXVE result[0] = 0; return; -#elif os_LINUX +#elif os_LINUX char *linkName = "/proc/self/exe"; #elif os_SOLARIS char *linkName = "/proc/self/path/a.out"; +#elif os_WINDOWS + + int numberOfChars = GetModuleFileNameA(NULL,result, MAX_PATH_LENGTH); #else # error getExecutablePath() not supported on other platforms yet #endif -#if os_LINUX || os_SOLARIS +#if os_LINUX || os_SOLARIS // read the symbolic link to figure out what the executable is. int numberOfChars = readlink(linkName, result, MAX_PATH_LENGTH); if (numberOfChars < 0) { @@ -116,7 +154,11 @@ static void getExecutablePath(char *result) { char *p; // chop off the name of the executable for (p = result + (numberOfChars - 1); p >= result; p--) { + #if os_WINDOWS + if (*p == '\\') { + #else if (*p == '/') { + #endif p[1] = 0; break; } @@ -146,7 +188,14 @@ static void *openLibrary(char *path) { log_println("openLibrary(\"%s\")", path); } #endif +#if !os_WINDOWS void *result = dlopen(path, RTLD_LAZY); +#else + void *result = LoadLibraryA(path); + if (result==NULL) { + sprintf(last_dl_error, "dl function : LoadLibraryA error code : %lu", GetLastError ()); + } +#endif #if log_LINKER char* errorMessage = dlerror(); if (path == NULL) { @@ -162,8 +211,16 @@ static void *openLibrary(char *path) { } static void* loadSymbol(void* handle, const char* symbol) { + #if os_WINDOWS + void* result = GetProcAddress(handle, symbol); + if (!result) { + sprintf(last_dl_error, "dl function : GetProcAddress error code : %lu", GetLastError ()); + + } + #else void* result = dlsym(handle, symbol); -#if log_LINKER + #endif +#if log_LINKER //NOT IMPLEMENTED FOR WINDOWS, you can get info using the dlerror() function we defined #if os_MAXVE log_println("loadSymbol(%p, \"%s\") = %p", handle, symbol, result); #else @@ -183,7 +240,7 @@ static void* loadSymbol(void* handle, const char* symbol) { return result; } -#if os_DARWIN || os_SOLARIS || os_LINUX +#if os_DARWIN || os_SOLARIS || os_LINUX #include #include @@ -194,7 +251,7 @@ static void* loadSymbol(void* handle, const char* symbol) { #if os_DARWIN #include -#elif os_LINUX +#elif os_LINUX #include #elif os_SOLARIS #define _STRUCTURED_PROC 1 /* Use new definitions in procfs.h instead of those in procfs_old.h */ @@ -215,7 +272,7 @@ void debugger_initialize() { char *port = getenv("MAX_AGENT_PORT"); if (port != NULL) { -#if os_LINUX && defined(PR_SET_PTRACER) +#if (os_LINUX ) && defined(PR_SET_PTRACER) /* See info about PR_SET_PTRACER at https://wiki.ubuntu.com/Security/Features#ptrace */ char *val = getenv("MAX_AGENT_PID"); if (val == NULL) { @@ -269,7 +326,7 @@ void debugger_initialize() { #if log_TELE log_println("Stopping VM for debugger"); #endif -#if os_DARWIN || os_LINUX +#if os_DARWIN || os_LINUX kill(getpid(), SIGTRAP); #elif os_SOLARIS int ctlfd = open("/proc/self/ctl", O_WRONLY); @@ -284,7 +341,7 @@ void debugger_initialize() { } } #else -#define debugger_initialize() +#define debugger_initialize() //not implemented for WINDOWS #endif /** @@ -293,6 +350,9 @@ void debugger_initialize() { typedef jint (*VMRunMethod)(Address tlBlock, int tlBlockSize, Address bootHeapRegionStart, void *openLibrary(char *), void *dlsym(void *, const char *), char *dlerror(void), void* vmInterface, JNIEnv jniEnv, void *jmmInterface, void *jvmtiInterface, int argc, char *argv[]); +#if os_WINDOWS +__declspec(dllexport) +#endif int maxine(int argc, char *argv[], char *executablePath) { VMRunMethod method; int exitCode = 0; @@ -338,7 +398,6 @@ int maxine(int argc, char *argv[], char *executablePath) { tla_initialize(image_header()->tlaSize); debugger_initialize(); method = image_offset_as_address(VMRunMethod, vmRunMethodOffset); - Address tlBlock = threadLocalsBlock_create(PRIMORDIAL_THREAD_ID, 0, 0); NativeThreadLocals ntl = NATIVE_THREAD_LOCALS_FROM_TLBLOCK(tlBlock); @@ -346,7 +405,11 @@ int maxine(int argc, char *argv[], char *executablePath) { log_println("entering Java by calling MaxineVM.run(tlBlock=%p, bootHeapRegionStart=%p, openLibrary=%p, dlsym=%p, dlerror=%p, vmInterface=%p, jniEnv=%p, jmmInterface=%p, jvmtiInterface=%p, argc=%d, argv=%p)", tlBlock, image_heap(), openLibrary, loadSymbol, dlerror, getVMInterface(), jniEnv(), getJMMInterface(-1), getJVMTIInterface(-1), argc, argv); #endif - exitCode = (*method)(tlBlock, ntl->tlBlockSize, image_heap(), openLibrary, loadSymbol, dlerror, getVMInterface(), jniEnv(), getJMMInterface(-1), getJVMTIInterface(-1), argc, argv); + #if os_WINDOWS + printf("reached here \n"); + #endif + exitCode = (*method)(tlBlock, ntl->tlBlockSize, image_heap(), openLibrary, loadSymbol, dlerror, getVMInterface(), jniEnv(), getJMMInterface(-1), getJVMTIInterface(-1), argc, argv); + #if log_LOADER log_println("start method exited with code: %d", exitCode); @@ -405,8 +468,12 @@ void core_dump() { log_print("dumping core....\n heap @ "); log_print_symbol(image_heap()); log_print_newline(); + #if os_WINDOWS + raise(SIGABRT); + #else // Use kill instead of abort so the vm process keeps running after the core is created. kill(getpid(), SIGABRT); + #endif sleep(3); #endif } @@ -444,6 +511,23 @@ void *native_properties(void) { } #if os_MAXVE maxve_native_props(&nativeProperties); +#elif os_WINDOWS + + nativeProperties.user_name = malloc(MAX_PATH_LENGTH); + nativeProperties.user_dir = malloc(MAX_PATH_LENGTH); + nativeProperties.user_home = malloc(MAX_PATH_LENGTH); + + DWORD size = MAX_PATH_LENGTH; + GetUserNameA(nativeProperties.user_name, &size); + size = MAX_PATH_LENGTH; + char * tmp; + SHGetKnownFolderPath(&FOLDERID_Profile, 0, NULL, (WCHAR **) &tmp); //Unfortunately, windows return home dir only in Unicode (Wide) format, not ANSI + nativeProperties.user_home = (char*) _wcsdup((const wchar_t * ) tmp); + CoTaskMemFree(tmp); //SHGetKnownFolderPath allocated that space and it is our responsibility to free it + GetCurrentDirectory(MAX_PATH_LENGTH, nativeProperties.user_dir); +//CAUTION nativeProperties.user_home contains the path in Unicode format so it cannot be printed with %s but rather with %ls using printf + + #else /* user properties */ { diff --git a/com.oracle.max.vm.native/substrate/maxine.h b/com.oracle.max.vm.native/substrate/maxine.h index 64df50d182..76ef87f53d 100644 --- a/com.oracle.max.vm.native/substrate/maxine.h +++ b/com.oracle.max.vm.native/substrate/maxine.h @@ -27,7 +27,7 @@ extern jlong native_nanoTime(void); extern jlong native_currentTimeMillis(void); extern void *native_executablePath(void); -extern void native_exit(int code); +extern void native_exit(jint code); extern void *native_environment(void); extern int maxine(int argc, char *argv[], char *executablePath); diff --git a/com.oracle.max.vm.native/substrate/memory.c b/com.oracle.max.vm.native/substrate/memory.c index 542f654493..1849aaa863 100644 --- a/com.oracle.max.vm.native/substrate/memory.c +++ b/com.oracle.max.vm.native/substrate/memory.c @@ -19,9 +19,13 @@ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. */ #include "os.h" - +#if !os_WINDOWS #include #include +#else +#include +#endif + #include #include diff --git a/com.oracle.max.vm.native/substrate/signal.c b/com.oracle.max.vm.native/substrate/signal.c index 9813304e5c..f07eb5cea2 100644 --- a/com.oracle.max.vm.native/substrate/signal.c +++ b/com.oracle.max.vm.native/substrate/signal.c @@ -24,6 +24,10 @@ /** * Native functions for SignalDispatcher.java. */ +#include "os.h" +#if os_WINDOWS +#include +#endif #include #include #include @@ -32,7 +36,9 @@ #include "threads.h" #include "log.h" -#if os_DARWIN +#if os_WINDOWS +static HANDLE signal_sem; +#elif os_DARWIN #include static semaphore_t signal_sem; #elif os_SOLARIS @@ -43,11 +49,11 @@ static semaphore_t signal_sem; #define sem_destroy sema_destroy #define sem_t sema_t static sem_t signal_sem; -#elif os_LINUX +#elif os_MAXVE +#else #include static sem_t signal_sem; -#elif os_MAXVE -// no signals, so nothing necessary + #endif boolean traceSignals = false; @@ -69,10 +75,15 @@ Java_com_sun_max_vm_runtime_SignalDispatcher_nativeSignalNotify(JNIEnv *env, jcl if (kr != KERN_SUCCESS) { log_exit(11, "semaphore_signal failed: %s", mach_error_string(kr)); } -#elif os_LINUX || os_SOLARIS +#elif os_LINUX || os_SOLARIS if (sem_post(&signal_sem) != 0) { log_exit(11, "sem_post failed: %s", strerror(errno)); } +#elif os_WINDOWS + if(!ReleaseSemaphore(signal_sem, 1, NULL)) + log_exit(GetLastError(), "ReleaseSemaphore failed"); + + #elif os_MAXVE #else c_UNIMPLEMENTED(); @@ -113,13 +124,18 @@ Java_com_sun_max_vm_runtime_SignalDispatcher_nativeSignalWait(JNIEnv *env, jclas if (kr != KERN_SUCCESS) { log_exit(11, "semaphore_wait failed: %s", mach_error_string(kr)); } -#elif os_LINUX || os_SOLARIS +#elif os_LINUX || os_SOLARIS int ret; - while ((ret = sem_wait(&signal_sem) == EINTR)) { + while ((ret = sem_wait(&signal_sem) == EINTR)) { //not sure if EINTR can occur on Windows (No sending signals is supported } if (ret != 0) { log_exit(11, "sem_wait failed: %s", strerror(errno)); } +#elif os_WINDOWS + if ( WaitForSingleObject(signal_sem,INFINITE) == WAIT_FAILED) + log_exit(GetLastError(), "WaitForSingleObject failed:"); + + #elif os_MAXVE #else c_UNIMPLEMENTED(); @@ -139,10 +155,13 @@ Java_com_sun_max_vm_runtime_SignalDispatcher_nativeSignalInit(JNIEnv *env, jclas if (kr != KERN_SUCCESS) { log_exit(11, "semaphore_create failed: %s", mach_error_string(kr)); } -#elif os_LINUX +#elif os_LINUX if (sem_init(&signal_sem, 0, 0) != 0) { log_exit(11, "sem_init failed: %s", strerror(errno)); } +#elif os_WINDOWS + signal_sem = CreateSemaphoreA(NULL, 1, 50000,NULL); //Windows Semaphore needs to have initial val 1 not 0 like Linux. If it was 0 no thread could enter +//Unfortunately, Windows Semaphores need a maximum value representing how many can enter it so we use a random big value (50000) #elif os_SOLARIS if (sem_init(&signal_sem, 0, USYNC_THREAD, NULL) != 0) { log_exit(11, "sema_init failed: %s", strerror(errno)); @@ -176,6 +195,8 @@ Java_com_sun_max_vm_runtime_SignalDispatcher_nativeSignalFinalize(JNIEnv *env, j if (sem_destroy(&signal_sem) != 0) { log_exit(11, "sema_destroy failed: %s", strerror(errno)); } +#elif os_WINDOWS + CloseHandle(signal_sem); #endif } diff --git a/com.oracle.max.vm.native/substrate/sync.c b/com.oracle.max.vm.native/substrate/sync.c index bb6f59e38c..d0f4af3ead 100644 --- a/com.oracle.max.vm.native/substrate/sync.c +++ b/com.oracle.max.vm.native/substrate/sync.c @@ -18,6 +18,10 @@ * 2 along with this work; if not, write to the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. */ +#include "os.h" +#if os_WINDOWS +#include +#endif #include #include @@ -26,7 +30,6 @@ #include "log.h" #include "jni.h" #include "mutex.h" -#include "os.h" #include "word.h" #include "threads.h" diff --git a/com.oracle.max.vm.native/substrate/threads.c b/com.oracle.max.vm.native/substrate/threads.c index 6d82a2491b..802fa70f61 100644 --- a/com.oracle.max.vm.native/substrate/threads.c +++ b/com.oracle.max.vm.native/substrate/threads.c @@ -19,11 +19,16 @@ * 2 along with this work; if not, write to the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. */ + +#include "os.h" -#include +#if (!os_WINDOWS) + #include +#else + #include +#endif #include -#include "os.h" #include "isa.h" #include "virtualMemory.h" @@ -41,8 +46,9 @@ #include "trap.h" #include "threads.h" #include "threadLocals.h" +#if !os_WINDOWS #include - +#endif #if (os_DARWIN || os_LINUX) # include # include @@ -56,6 +62,16 @@ # include "maxve.h" typedef maxve_Thread Thread; #define thread_current() (maxve_get_current()) + +#elif os_WINDOWS + + #include + #include + #include + #include + typedef HANDLE Thread; +#define thread_current() ((Thread) GetCurrentThread()) + #endif #if log_NUMA_THREADS @@ -114,6 +130,22 @@ void thread_getStackInfo(Address *stackBase, Size* stackSize) { } pthread_attr_destroy(&attr); +#elif os_WINDOWS + SYSTEM_INFO systemInfo = {0}; + GetSystemInfo(&systemInfo); + + NT_TIB *tib = (NT_TIB*)NtCurrentTeb(); + *stackBase = (DWORD_PTR)tib->StackBase; //On windows, guard size is always one memory page so we remove it from stacksize. + + + MEMORY_BASIC_INFORMATION mbi = {0}; + if (VirtualQuery((LPCVOID)(*stackBase - systemInfo.dwPageSize ), &mbi, sizeof(MEMORY_BASIC_INFORMATION)) != 0) //we use virtualquery to get windows reserved stack size (not committed). + { + DWORD_PTR allocationStart = (DWORD_PTR)mbi.AllocationBase; + *stackSize = (size_t) (*stackBase) - allocationStart; + } + *stackBase = (DWORD_PTR)mbi.AllocationBase + systemInfo.dwAllocationGranularity; //tib->StackBase is actually the HIGHEST address of the stack, we want the lowest so we use AllocationBase + guard_size + *stackSize -= systemInfo.dwAllocationGranularity;//On windows, guard size is always one memory page so we remove it from stacksize. #elif os_DARWIN pthread_t self = pthread_self(); void *stackTop = pthread_get_stackaddr_np(self); @@ -146,7 +178,7 @@ void thread_getStackInfo(Address *stackBase, Size* stackSize) { */ static Thread thread_create(jint id, Size stackSize, int priority) { Thread thread; -#if !os_MAXVE +#if !os_MAXVE && !os_WINDOWS int error; #endif @@ -158,8 +190,10 @@ static Thread thread_create(jint id, Size stackSize, int priority) { #if log_THREADS log_println("thread_create: id = %d, stack size = %ld", id, stackSize); #endif - -#if (os_LINUX || os_DARWIN) +#if os_WINDOWS +#define PTHREAD_STACK_MIN 0 +#endif +#if (os_LINUX || os_DARWIN ) if (stackSize < PTHREAD_STACK_MIN) { stackSize = PTHREAD_STACK_MIN; } @@ -184,7 +218,7 @@ static Thread thread_create(jint id, Size stackSize, int priority) { if (thread == NULL) { return (Thread) 0; } -#elif (os_LINUX || os_DARWIN) +#elif (os_LINUX || os_DARWIN ) pthread_attr_t attributes; pthread_attr_init(&attributes); @@ -200,6 +234,15 @@ static Thread thread_create(jint id, Size stackSize, int priority) { log_println("pthread_create failed with error: %d", error); return (Thread) 0; } +#elif (os_WINDOWS) + thread = CreateThread(NULL, stackSize, thread_run, NULL, STACK_SIZE_PARAM_IS_A_RESERVATION, NULL); //we demand explicitly stack size to be reservedd + //Also guard is set automatically + if(!thread){ + log_println("thread_create failed with error: %d", GetLastError()); + return (Thread) 0; + } + //the only way to make thread detached is to invalidate its handle using CloseHandle(). However, this would result in returning an invalid Thread at the end of the function + #elif os_SOLARIS if (stackSize < thr_min_stack()) { stackSize = thr_min_stack(); @@ -226,7 +269,13 @@ void *thread_self() { * * @param arg the pre-allocated, but uninitialized, thread locals block. */ -void *thread_run(void *arg) { + #if os_WINDOWS +DWORD WINAPI thread_run(void *arg) //we prefer this signature in order to avoid compiler waring on Windows. + + #else +void * thread_run(void *arg) +#endif + { Address tlBlock = (Address) arg; TLA etla = ETLA_FROM_TLBLOCK(tlBlock); @@ -247,7 +296,6 @@ void *thread_run(void *arg) { threadLocalsBlock_create(id, tlBlock, 0); } NativeThreadLocals ntl = NATIVE_THREAD_LOCALS_FROM_TLBLOCK(tlBlock); - /* Grab the global thread lock so that: * 1. This thread can atomically be added to the thread list * 2. This thread is blocked if a GC is currently underway. Once we have the lock, @@ -307,7 +355,11 @@ void *thread_run(void *arg) { setCurrentThreadSignalMaskOnThreadExit(result == 1); /* Successful thread exit */ - return NULL; + #if os_WINDOWS + return 0; + #else + return NULL; + #endif } /** @@ -478,10 +530,12 @@ Java_com_sun_max_vm_thread_VmThread_nativeYield(JNIEnv *env, jclass c) { thr_yield(); #elif os_DARWIN sched_yield(); -#elif os_LINUX +#elif os_LINUX pthread_yield(); #elif os_MAXVE maxve_yield(); +#elif os_WINDOWS + SwitchToThread(); #else c_UNIMPLEMENTED(); #endif @@ -504,7 +558,7 @@ Java_com_sun_max_vm_thread_VmThread_nativeInterrupt(JNIEnv *env, jclass c, Addre log_exit(11, "Error sending signal SIGUSR1 to native thread %p", nativeThread); } } -#elif os_LINUX || os_DARWIN +#elif os_LINUX || os_DARWIN // Signals the thread int result = pthread_kill((pthread_t) nativeThread, SIGUSR1); if (result != 0) { @@ -517,7 +571,12 @@ Java_com_sun_max_vm_thread_VmThread_nativeInterrupt(JNIEnv *env, jclass c, Addre } } #elif os_MAXVE + maxve_interrupt((void*) nativeThread); +#elif os_WINDOWS + c_UNIMPLEMENTED(); + + #else c_UNIMPLEMENTED(); #endif @@ -526,6 +585,9 @@ Java_com_sun_max_vm_thread_VmThread_nativeInterrupt(JNIEnv *env, jclass c, Addre jboolean thread_sleep(jlong numberOfMilliSeconds) { #if os_MAXVE return maxve_sleep(numberOfMilliSeconds * 1000000); +#elif os_WINDOWS +Sleep(numberOfMilliSeconds); + return TRUE; #else struct timespec time, remainder; diff --git a/com.oracle.max.vm.native/substrate/time.c b/com.oracle.max.vm.native/substrate/time.c index 60e90b0d39..06eb634748 100644 --- a/com.oracle.max.vm.native/substrate/time.c +++ b/com.oracle.max.vm.native/substrate/time.c @@ -21,15 +21,47 @@ #include "os.h" #include "jni.h" #include "maxine.h" - #include -#include +#if !os_WINDOWS +#include //MINGW may contain this file but it is not officially part of WINAPI so other SDKs (eg. Visual Studio do not include it) +#endif #if os_DARWIN #include #include #elif os_LINUX #include +#elif os_WINDOWS +#include +#include +int gettimeofday(struct timeval * tp) +{ + // Note: some broken versions only have 8 trailing zero's, the correct epoch has 9 trailing zero's + // This magic number is the number of 100 nanosecond intervals since January 1, 1601 (UTC) + // until 00:00:00 January 1, 1970 + static const uint64_t EPOCH = ((uint64_t) 116444736000000000ULL); + + SYSTEMTIME system_time; + FILETIME file_time; + uint64_t time; + + GetSystemTime( &system_time ); + SystemTimeToFileTime( &system_time, &file_time ); + time = ((uint64_t)file_time.dwLowDateTime ) ; + time += ((uint64_t)file_time.dwHighDateTime) << 32; + + tp->tv_sec = (long) ((time - EPOCH) / 10000000L); + tp->tv_usec = (long) (system_time.wMilliseconds * 1000); + return 0; +} + +int clock_gettime(int x, struct timespec *spec) +{ __int64 wintime; GetSystemTimeAsFileTime((FILETIME*)&wintime); + wintime -=(int64_t)116444736000000000; //1jan1601 to 1jan1970 + spec->tv_sec =wintime / (int64_t)10000000; //seconds + spec->tv_nsec =wintime % (int64_t)10000000 *100; //nano-seconds + return 0; +} #endif @@ -69,7 +101,7 @@ jlong native_nanoTime(void) { struct timeval tv; gettimeofday(&tv, NULL); return (uint64_t)tv.tv_sec * (uint64_t)(1000 * 1000 * 1000) + (uint64_t)(tv.tv_usec * 1000); -#elif os_LINUX +#elif os_LINUX #ifndef CLOCK_MONOTONIC #define CLOCK_MONOTONIC (1) @@ -119,15 +151,24 @@ jlong native_nanoTime(void) { c_ASSERT(status != -1); jlong usecs = ((jlong) time.tv_sec) * (1000 * 1000) + (jlong) time.tv_usec; return 1000 * usecs; +#elif os_WINDOWS + struct timespec time; + clock_gettime(1, &time); + return ((jlong)time.tv_sec) * (1000 * 1000 * 1000) + (jlong) time.tv_nsec; +//NOT 100% TESTED #else return 1; #endif } jlong native_currentTimeMillis(void) { -#if os_SOLARIS || os_DARWIN || os_LINUX +#if os_SOLARIS || os_DARWIN || os_LINUX || os_WINDOWS struct timeval tv; + #if os_WINDOWS + gettimeofday(&tv); + #else gettimeofday(&tv, NULL); + #endif // we need to cast to jlong to avoid overflows in ARMv7 return ((jlong) tv.tv_sec * 1000) + ((jlong) tv.tv_usec / 1000); #else diff --git a/com.oracle.max.vm.native/substrate/trap.c b/com.oracle.max.vm.native/substrate/trap.c index 3030b388ae..7501e780fe 100644 --- a/com.oracle.max.vm.native/substrate/trap.c +++ b/com.oracle.max.vm.native/substrate/trap.c @@ -19,13 +19,15 @@ * 2 along with this work; if not, write to the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. */ - +#include "os.h" +#if os_WINDOWS +#include +#endif #include "c.h" #include "threads.h" #include "virtualMemory.h" #include "log.h" #include "jni.h" -#include "os.h" #include "isa.h" #include "image.h" #include "trap.h" @@ -49,7 +51,7 @@ static Address theJavaTrapStub; static boolean traceTraps = false; -#if !os_MAXVE +#if !os_MAXVE && !os_WINDOWS //Windows do not support POSIX signals unfortunately. You can only raise some signals from within your own process/thread but not send it to another process/thread /** * All signals. @@ -77,13 +79,13 @@ static sigset_t blockedOnThreadExitSignals; int getTrapNumber(int signal) { switch (signal) { case SIGSEGV: -#if !os_MAXVE +#if !os_MAXVE && !os_WINDOWS case SIGBUS: #endif return MEMORY_FAULT; case SIGFPE: return ARITHMETIC_EXCEPTION; -#if !os_MAXVE +#if !os_MAXVE && !os_WINDOWS case SIGUSR1: return ASYNC_INTERRUPT; default: @@ -96,12 +98,12 @@ int getTrapNumber(int signal) { #if os_SOLARIS #include #define thread_setSignalMask thr_sigsetmask -#elif os_DARWIN || os_LINUX +#elif os_DARWIN || os_LINUX #define thread_setSignalMask pthread_sigmask #endif void setCurrentThreadSignalMaskOnThreadExit(boolean isVmOperationThread) { -#if !os_MAXVE +#if !os_MAXVE && !os_WINDOWS if (!isVmOperationThread) { /* disable signals sent by Thread.interrupt() as thread is transitioning to not alive state. */ thread_setSignalMask(SIG_BLOCK, &blockedOnThreadExitSignals, NULL); @@ -110,7 +112,7 @@ void setCurrentThreadSignalMaskOnThreadExit(boolean isVmOperationThread) { } void setCurrentThreadSignalMask(boolean isVmOperationThread) { -#if !os_MAXVE +#if !os_MAXVE && !os_WINDOWS if (isVmOperationThread) { thread_setSignalMask(SIG_SETMASK, &vmAndDefaultSignals, NULL); } else { @@ -120,9 +122,12 @@ void setCurrentThreadSignalMask(boolean isVmOperationThread) { #endif } -void* setSignalHandler(int signal, SignalHandlerFunction handler) { +void* setSignalHandler(int sig, SignalHandlerFunction handler) { //Changed 'signal' argument to 'sig' because it overlapped with windows signal() function #if os_MAXVE - maxve_register_fault_handler(signal, handler); + maxve_register_fault_handler(sig, handler); + return NULL; +#elif os_WINDOWS + signal(sig, handler); return NULL; #else struct sigaction newSigaction; @@ -132,14 +137,14 @@ void* setSignalHandler(int signal, SignalHandlerFunction handler) { sigemptyset(&newSigaction.sa_mask); newSigaction.sa_flags = SA_SIGINFO | SA_RESTART | SA_ONSTACK; -#if os_SOLARIS || os_LINUX || os_DARWIN - if (signal == SIGUSR1) { +#if os_SOLARIS || os_LINUX || os_DARWIN + if (sig == SIGUSR1) { newSigaction.sa_flags = SA_SIGINFO | SA_ONSTACK; } #endif newSigaction.sa_sigaction = handler; - if (sigaction(signal, &newSigaction, &oldSigaction) != 0) { + if (sigaction(sig, &newSigaction, &oldSigaction) != 0) { log_exit(1, "sigaction failed"); } @@ -147,7 +152,7 @@ void* setSignalHandler(int signal, SignalHandlerFunction handler) { log_lock(); log_print("Registered handler %p [", handler); log_print_symbol((Address) handler); - log_print("] for signal %d", signal); + log_print("] for signal %d", sig); if (oldSigaction.sa_handler != NULL) { log_print(" replacing handler "); log_print_symbol((Address) oldSigaction.sa_handler); @@ -163,7 +168,7 @@ void* setSignalHandler(int signal, SignalHandlerFunction handler) { static Address getInstructionPointer(UContext *ucontext) { #if os_SOLARIS return ucontext->uc_mcontext.gregs[REG_PC]; -#elif os_LINUX +#elif os_LINUX # if isa_AMD64 return ucontext->uc_mcontext.gregs[REG_RIP]; # elif isa_IA32 @@ -179,6 +184,10 @@ static Address getInstructionPointer(UContext *ucontext) { return ucontext->uc_mcontext->__ss.__rip; #elif os_MAXVE return ucontext->rip; +#elif os_WINDOWS +#if isa_AMD64 + return ucontext->Rip; + #endif #else c_UNIMPLEMENTED(); #endif @@ -192,7 +201,7 @@ static void setInstructionPointer(UContext *ucontext, Address stub) { ucontext->uc_mcontext.gregs[REG_PC] = (greg_t) stub; #elif os_DARWIN ucontext->uc_mcontext->__ss.__rip = stub; -#elif os_LINUX +#elif os_LINUX # if isa_AMD64 ucontext->uc_mcontext.gregs[REG_RIP] = (greg_t) stub; # elif isa_IA32 @@ -206,15 +215,19 @@ static void setInstructionPointer(UContext *ucontext, Address stub) { # endif #elif os_MAXVE ucontext->rip = (unsigned long) stub; +#elseif os_WINDOWS +# if isa_AMD64 + ucontext->uc_mcontext.rip = (greg_t) stub; + #endif #else c_UNIMPLEMENTED(); #endif } -static Address getFaultAddress(SigInfo * sigInfo, UContext *ucontext) { +static Address getFaultAddress(SigInfo * sigInfo, UContext *ucontext) { //there is no siginfo_t struct in Windows #if (os_DARWIN || os_SOLARIS || os_LINUX ) return (Address) sigInfo->si_addr; -#elif (os_MAXVE) +#elif (os_MAXVE) || os_WINDOWS return (Address) sigInfo; #endif } @@ -228,7 +241,7 @@ char *vmSignalName(int signal) { case SIGSEGV: return "SIGSEGV"; case SIGFPE: return "SIGFPE"; case SIGILL: return "SIGILL"; -#if !os_MAXVE +#if !os_MAXVE && !os_WINDOWS case SIGUSR1: return "SIGUSR1"; case SIGBUS: return "SIGBUS"; #endif @@ -269,12 +282,15 @@ static boolean handleDivideOverflow(UContext *ucontext) { if (rip[0] == 0xf7) { #if os_SOLARIS Address dividend = ucontext->uc_mcontext.gregs[REG_RAX]; -#elif os_LINUX +#elif os_LINUX Address dividend = ucontext->uc_mcontext.gregs[REG_RAX]; #elif os_DARWIN Address dividend = ucontext->uc_mcontext->__ss.__rax; #elif os_MAXVE Address dividend = ucontext->rax; +#elif os_WINDOWS + Address dividend = ucontext->Rax; + #else c_UNIMPLEMENTED(); #endif @@ -294,12 +310,15 @@ static boolean handleDivideOverflow(UContext *ucontext) { /* Set the remainder to 0. */ #if os_SOLARIS ucontext->uc_mcontext.gregs[REG_RDX] = 0; -#elif os_LINUX +#elif os_LINUX ucontext->uc_mcontext.gregs[REG_RDX] = 0; #elif os_DARWIN ucontext->uc_mcontext->__ss.__rdx = 0; #elif os_MAXVE ucontext->rdx = 0; +#elif os_WINDOWS + ucontext->Rdx = 0; + #else c_UNIMPLEMENTED(); #endif @@ -446,6 +465,9 @@ static void vmSignalHandler(int signal, SigInfo *signalInfo, UContext *ucontext) #elif isa_AMD64 && (os_SOLARIS || os_LINUX) tla_store3(dtla, TRAP_LATCH_REGISTER, ucontext->uc_mcontext.gregs[REG_R14]); ucontext->uc_mcontext.gregs[REG_R14] = (Address) dtla; +#elif isa_AMD64 && os_WINDOWS + tla_store3(dtla, TRAP_LATCH_REGISTER, ucontext->R14); + ucontext->R14 = (Address) dtla; #elif isa_AMD64 && os_DARWIN tla_store3(dtla, TRAP_LATCH_REGISTER, ucontext->uc_mcontext->__ss.__r14); ucontext->uc_mcontext->__ss.__r14 = (Address) dtla; @@ -471,11 +493,17 @@ static void vmSignalHandler(int signal, SigInfo *signalInfo, UContext *ucontext) /** * The handler for signals handled by SignalDispatcher.java. */ + #if os_WINDOWS + static void userSignalHandlerDef(int signal) { + void postSignal(int signal); + postSignal(signal); +} +#else static void userSignalHandlerDef(int signal, SigInfo *signalInfo, UContext *ucontext) { void postSignal(int signal); postSignal(signal); } - +#endif /* Defined global declared in trap.h */ SignalHandlerFunction userSignalHandler = (SignalHandlerFunction) userSignalHandlerDef; @@ -491,7 +519,7 @@ void nativeTrapInitialize(Address javaTrapStub) { setSignalHandler(SIGILL, (SignalHandlerFunction) vmSignalHandler); setSignalHandler(SIGFPE, (SignalHandlerFunction) vmSignalHandler); -#if !os_MAXVE +#if !os_MAXVE && !os_WINDOWS //no support for windows signals setSignalHandler(SIGBUS, (SignalHandlerFunction) vmSignalHandler); setSignalHandler(SIGUSR1, (SignalHandlerFunction) vmSignalHandler); diff --git a/com.oracle.max.vm.native/substrate/trap.h b/com.oracle.max.vm.native/substrate/trap.h index 620a4b9afe..990f1a582a 100644 --- a/com.oracle.max.vm.native/substrate/trap.h +++ b/com.oracle.max.vm.native/substrate/trap.h @@ -29,14 +29,22 @@ # include # include # include -# include +#if (!os_WINDOWS) + # include # include -#endif +#endif +#endif #include "os.h" -#if os_MAXVE +#if os_MAXVE #define SignalHandlerFunction fault_handler_t +#elif os_WINDOWS +typedef void SigInfo; + +typedef void (*SignalHandlerFunction)(int signal); //Windows want a signal handler with one argument (Remember, Windows do not support POSIX signals. They can only be used as exceptions raised from within the same process. You cannot send them to other threads/ procs) + +typedef CONTEXT UContext; #else typedef ucontext_t UContext; typedef siginfo_t SigInfo; diff --git a/com.oracle.max.vm.native/substrate/vm.h b/com.oracle.max.vm.native/substrate/vm.h index 880df618d4..8a4da41eed 100644 --- a/com.oracle.max.vm.native/substrate/vm.h +++ b/com.oracle.max.vm.native/substrate/vm.h @@ -36,6 +36,10 @@ * A set of VM functions implemented in Java that can (only) be called from C code. * These are defined in VMFunctionsSource.java. */ + #include "os.h" + #if os_WINDOWS + #undef GetClassName + #endif //Microsoft defines GetClassName as GetClassNameA in some header files which breaks our code typedef struct vmInterface_ { // START GENERATED CODE void (JNICALL *Unimplemented) (JNIEnv *env); diff --git a/com.oracle.max.vm.native/windows_tests/memory_map_test.c b/com.oracle.max.vm.native/windows_tests/memory_map_test.c new file mode 100644 index 0000000000..9e94de1703 --- /dev/null +++ b/com.oracle.max.vm.native/windows_tests/memory_map_test.c @@ -0,0 +1,58 @@ +#include + +#include // size_t +#include // uint8_t, uint32_t +#include // printf +#include // Must be included before strsafe.h +#include +#include +// Display the error message corresponding to GetLastError() in a message box. + + uint8_t machine_code[] = {'k', 0xB8, 0x78, 0x56, 0x34, 0x12, 0xC3 }; + +int _tmain(int argc, _TCHAR **argv) { + // Allocate a new page of memory, setting its protections to read+write + LPVOID mem = VirtualAlloc(NULL, sizeof(machine_code), + MEM_COMMIT, PAGE_READWRITE); + if (mem == NULL) { + return 1; + } + + int fd = open("output.txt" , _O_RDWR ); + write( + fd, + machine_code, + sizeof(machine_code)); + _close(fd); + HANDLE open_img_result = CreateFileA( + "output.txt" , + GENERIC_READ | GENERIC_WRITE|GENERIC_EXECUTE , + FILE_SHARE_WRITE | FILE_SHARE_READ, + NULL, + OPEN_EXISTING, + FILE_ATTRIBUTE_NORMAL, + NULL +); +if (open_img_result == INVALID_HANDLE_VALUE || !open_img_result) + printf("could not open image file: %d" , GetLastError()); + + + HANDLE fmapping = CreateFileMappingA( open_img_result , NULL , PAGE_EXECUTE_READWRITE| SEC_COMMIT ,0u ,0, NULL); + if(!fmapping) + printf("ss %d\n", GetLastError()); + mem = MapViewOfFileEx (fmapping, FILE_MAP_READ | FILE_MAP_WRITE | FILE_MAP_EXECUTE |FILE_MAP_COPY, 0, 0,0, 0); + if(!mem) + printf("dd %d\n", GetLastError()); + + + // Point a function pointer at the newly allocated page, then call it + printf("fff %d \n", sizeof(machine_code)); + mem =mem +1; + uint32_t(*fn)() = (uint32_t(*)()) mem; + uint32_t result = fn(); + _tprintf(TEXT("result = 0x%x\n"), result); + return 0; + + +} + diff --git a/com.oracle.max.vm.native/windows_tests/output.txt b/com.oracle.max.vm.native/windows_tests/output.txt new file mode 100644 index 0000000000..e69de29bb2 diff --git a/com.sun.max/src/com/sun/max/config/jdk/Package.java b/com.sun.max/src/com/sun/max/config/jdk/Package.java index e69b0759cc..1d9dddffc9 100644 --- a/com.sun.max/src/com/sun/max/config/jdk/Package.java +++ b/com.sun.max/src/com/sun/max/config/jdk/Package.java @@ -31,6 +31,8 @@ import com.sun.max.vm.actor.member.*; import com.sun.max.vm.hosted.*; import com.sun.max.vm.jdk.*; +import static com.sun.max.platform.Platform.*; +import com.sun.max.platform.*; /** * Redirection for the standard set of JDK packages to include in the image. @@ -150,8 +152,11 @@ public Package() { if (JDK.JDK_VERSION == JDK.JDK_8) { Extensions.resetField("java.lang.invoke.MethodHandles$Lookup", "LOOKASIDE_TABLE"); Extensions.registerClassForReInit("java.lang.invoke.MethodHandles$Lookup"); - Extensions.resetField("java.lang.UNIXProcess", "processReaperExecutor"); - Extensions.registerClassForReInit("java.lang.UNIXProcess"); + + if(platform().os != OS.WINDOWS ){ + Extensions.resetField("java.lang.UNIXProcess", "processReaperExecutor"); + Extensions.registerClassForReInit("java.lang.UNIXProcess"); + } Extensions.resetField("java.io.File", "fs"); Extensions.registerClassForReInit("java.io.File"); @@ -170,11 +175,11 @@ public Package() { */ @Override public void loading() { + if (loadingDone) { return; } loadingDone = true; - // Classes that must not be in the boot image for various reasons HostedBootClassLoader.omitClass(java.io.File.class.getName() + "$LazyInitialization"); HostedBootClassLoader.omitClass(java.io.File.class.getName() + "$TempDirectory"); diff --git a/com.sun.max/src/com/sun/max/platform/Platform.java b/com.sun.max/src/com/sun/max/platform/Platform.java index 7c10fe9514..6e3a6a4d9b 100644 --- a/com.sun.max/src/com/sun/max/platform/Platform.java +++ b/com.sun.max/src/com/sun/max/platform/Platform.java @@ -142,7 +142,7 @@ private CiTarget createTarget() { if (os == OS.DARWIN) { // Darwin requires 16-byte stack frame alignment. stackAlignment = 16; - } else if (os == OS.SOLARIS || os == OS.LINUX) { + } else if (os == OS.SOLARIS || os == OS.LINUX || os == OS.WINDOWS) { // Linux apparently also requires it for functions that pass floating point functions on the stack. // One such function in the Maxine code base is log_print_float() in log.c which passes a float // value to fprintf on the stack. However, gcc doesn't fix the alignment itself so we simply diff --git a/com.sun.max/src/com/sun/max/vm/compiler/target/RegisterConfigs.java b/com.sun.max/src/com/sun/max/vm/compiler/target/RegisterConfigs.java index ef9a9dcb58..7e6faba0ce 100644 --- a/com.sun.max/src/com/sun/max/vm/compiler/target/RegisterConfigs.java +++ b/com.sun.max/src/com/sun/max/vm/compiler/target/RegisterConfigs.java @@ -188,7 +188,7 @@ public static RegisterConfigs create() { return new RegisterConfigs(standard, n2j, trampoline, template, compilerStub, uncommonTrapStub, trapStub); } } else if (platform().isa == ISA.AMD64) { - if (os == OS.LINUX || os == OS.SOLARIS || os == OS.DARWIN || os == OS.MAXVE) { + if (os == OS.LINUX || os == OS.SOLARIS || os == OS.DARWIN || os == OS.MAXVE || os == OS.WINDOWS) { allocatable = new CiRegister[] {rax, rcx, rdx, rbx, rsi, rdi, com.oracle.max.asm.target.amd64.AMD64.r8, com.oracle.max.asm.target.amd64.AMD64.r9, com.oracle.max.asm.target.amd64.AMD64.r10, com.oracle.max.asm.target.amd64.AMD64.r12, com.oracle.max.asm.target.amd64.AMD64.r13, com.oracle.max.asm.target.amd64.AMD64.r15, xmm0, xmm1, xmm2, xmm3, xmm4, xmm5, xmm6, xmm7, xmm8, xmm9, xmm10, xmm11, xmm12, xmm13, xmm14, xmm15}; diff --git a/com.sun.max/src/com/sun/max/vm/heap/HeapSchemeAdaptor.java b/com.sun.max/src/com/sun/max/vm/heap/HeapSchemeAdaptor.java index 9a29cb6c9f..edf60a7723 100644 --- a/com.sun.max/src/com/sun/max/vm/heap/HeapSchemeAdaptor.java +++ b/com.sun.max/src/com/sun/max/vm/heap/HeapSchemeAdaptor.java @@ -215,6 +215,7 @@ public CodeManager createCodeManager() { case LINUX: case MAXVE: case DARWIN: + case WINDOWS: case SOLARIS: { // If you change this for any platform above, you may also want to revisit reservedVirtualSpaceSize, // bootRegionMappingConstraint and the native implementation of mapHeapAndCode. diff --git a/docs/Status.rst b/docs/Status.rst index 23a6c32da9..d5f6e42ace 100644 --- a/docs/Status.rst +++ b/docs/Status.rst @@ -15,6 +15,8 @@ Maxine is being developed and tested on the following configurations: +----------------+----------------------+--------------------------+--------------------+ | x86_64 | macOS Mojave 10.14 | OpenJDK 8 (u222) | 2.9.0 | +----------------+----------------------+--------------------------+--------------------+ +| X86_64 | Windows 10 | OpenJDK 8 (u222) | 2.9.0 | ++----------------+----------------------+--------------------------+--------------------+ | Aarch64 | Ubuntu 18.04 | OpenJDK 8 (u222) | 2.9.0 | +----------------+----------------------+--------------------------+--------------------+ | RISC-V64 | Fedora 31 (on QEMU) | OpenJDK 8 (u222) | 2.9.0 |