< prev index next >

src/hotspot/os/windows/os_windows.cpp

Print this page
8248238: Adding Windows support to OpenJDK on AArch64

Summary: Adding Windows support for AArch64

Contributed-by: Ludovic Henry <luhenry@microsoft.com>, Monica Beckwith <monica.beckwith@microsoft.com>
Reviewed-by:

*** 29,38 **** --- 29,39 ---- #include "jvm.h" #include "classfile/classLoader.hpp" #include "classfile/systemDictionary.hpp" #include "classfile/vmSymbols.hpp" #include "code/icBuffer.hpp" + #include "code/nativeInst.hpp" #include "code/vtableStubs.hpp" #include "compiler/compileBroker.hpp" #include "compiler/disassembler.hpp" #include "interpreter/interpreter.hpp" #include "logging/log.hpp"
*** 116,132 **** static FILETIME process_creation_time; static FILETIME process_exit_time; static FILETIME process_user_time; static FILETIME process_kernel_time; ! #ifdef _M_AMD64 #define __CPU__ amd64 #else #define __CPU__ i486 #endif ! #if INCLUDE_AOT PVOID topLevelVectoredExceptionHandler = NULL; LONG WINAPI topLevelVectoredExceptionFilter(struct _EXCEPTION_POINTERS* exceptionInfo); #endif // save DLL module handle, used by GetModuleFileName --- 117,137 ---- static FILETIME process_creation_time; static FILETIME process_exit_time; static FILETIME process_user_time; static FILETIME process_kernel_time; ! #if defined(_M_ARM64) ! #define __CPU__ aarch64 ! #elif defined(_M_AMD64) #define __CPU__ amd64 #else #define __CPU__ i486 #endif ! #if defined(USE_VECTORED_EXCEPTION_HANDLING) ! PVOID topLevelVectoredExceptionHandler = NULL; ! #elif INCLUDE_AOT PVOID topLevelVectoredExceptionHandler = NULL; LONG WINAPI topLevelVectoredExceptionFilter(struct _EXCEPTION_POINTERS* exceptionInfo); #endif // save DLL module handle, used by GetModuleFileName
*** 145,155 **** break; case DLL_PROCESS_DETACH: if (ForceTimeHighResolution) { timeEndPeriod(1L); } ! #if INCLUDE_AOT if (topLevelVectoredExceptionHandler != NULL) { RemoveVectoredExceptionHandler(topLevelVectoredExceptionHandler); topLevelVectoredExceptionHandler = NULL; } #endif --- 150,160 ---- break; case DLL_PROCESS_DETACH: if (ForceTimeHighResolution) { timeEndPeriod(1L); } ! #if defined(USE_VECTORED_EXCEPTION_HANDLING) || INCLUDE_AOT if (topLevelVectoredExceptionHandler != NULL) { RemoveVectoredExceptionHandler(topLevelVectoredExceptionHandler); topLevelVectoredExceptionHandler = NULL; } #endif
*** 454,472 **** --- 459,484 ---- res = 20115; // java thread } log_info(os, thread)("Thread is alive (tid: " UINTX_FORMAT ").", os::current_thread_id()); + #ifdef USE_VECTORED_EXCEPTION_HANDLING + // Any exception is caught by the Vectored Exception Handler, so VM can + // generate error dump when an exception occurred in non-Java thread + // (e.g. VM thread). + thread->call_run(); + #else // Install a win32 structured exception handler around every thread created // by VM, so VM can generate error dump when an exception occurred in non- // Java thread (e.g. VM thread). __try { thread->call_run(); } __except(topLevelExceptionFilter( (_EXCEPTION_POINTERS*)_exception_info())) { // Nothing to do. } + #endif // Note: at this point the thread object may already have deleted itself. // Do not dereference it from here on out. log_info(os, thread)("Thread finished (tid: " UINTX_FORMAT ").", os::current_thread_id());
*** 1425,1443 **** char* arch_name; } arch_t; static const arch_t arch_array[] = { {IMAGE_FILE_MACHINE_I386, (char*)"IA 32"}, ! {IMAGE_FILE_MACHINE_AMD64, (char*)"AMD 64"} }; ! #if (defined _M_AMD64) static const uint16_t running_arch = IMAGE_FILE_MACHINE_AMD64; #elif (defined _M_IX86) static const uint16_t running_arch = IMAGE_FILE_MACHINE_I386; #else #error Method os::dll_load requires that one of following \ ! is defined :_M_AMD64 or _M_IX86 #endif // Obtain a string for printf operation // lib_arch_str shall contain string what platform this .dll was built for --- 1437,1458 ---- char* arch_name; } arch_t; static const arch_t arch_array[] = { {IMAGE_FILE_MACHINE_I386, (char*)"IA 32"}, ! {IMAGE_FILE_MACHINE_AMD64, (char*)"AMD 64"}, ! {IMAGE_FILE_MACHINE_ARM64, (char*)"ARM 64"} }; ! #if (defined _M_ARM64) ! static const uint16_t running_arch = IMAGE_FILE_MACHINE_ARM64; ! #elif (defined _M_AMD64) static const uint16_t running_arch = IMAGE_FILE_MACHINE_AMD64; #elif (defined _M_IX86) static const uint16_t running_arch = IMAGE_FILE_MACHINE_I386; #else #error Method os::dll_load requires that one of following \ ! is defined :_M_AMD64 or _M_IX86 or _M_ARM64 #endif // Obtain a string for printf operation // lib_arch_str shall contain string what platform this .dll was built for
*** 1730,1740 **** // Retrieve SYSTEM_INFO from GetNativeSystemInfo call so that we could // find out whether we are running on 64 bit processor or not SYSTEM_INFO si; ZeroMemory(&si, sizeof(SYSTEM_INFO)); GetNativeSystemInfo(&si); ! if (si.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_AMD64) { st->print(" , 64 bit"); } st->print(" Build %d", build_number); st->print(" (%d.%d.%d.%d)", major_version, minor_version, build_number, build_minor); --- 1745,1756 ---- // Retrieve SYSTEM_INFO from GetNativeSystemInfo call so that we could // find out whether we are running on 64 bit processor or not SYSTEM_INFO si; ZeroMemory(&si, sizeof(SYSTEM_INFO)); GetNativeSystemInfo(&si); ! if ((si.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_AMD64) || ! (si.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_ARM64)) { st->print(" , 64 bit"); } st->print(" Build %d", build_number); st->print(" (%d.%d.%d.%d)", major_version, minor_version, build_number, build_minor);
*** 2138,2148 **** LONG Handle_Exception(struct _EXCEPTION_POINTERS* exceptionInfo, address handler) { JavaThread* thread = (JavaThread*) Thread::current_or_null(); // Save pc in thread ! #ifdef _M_AMD64 // Do not blow up if no thread info available. if (thread) { thread->set_saved_exception_pc((address)(DWORD_PTR)exceptionInfo->ContextRecord->Rip); } // Set pc to handler --- 2154,2171 ---- LONG Handle_Exception(struct _EXCEPTION_POINTERS* exceptionInfo, address handler) { JavaThread* thread = (JavaThread*) Thread::current_or_null(); // Save pc in thread ! #if defined(_M_ARM64) ! // Do not blow up if no thread info available. ! if (thread) { ! thread->set_saved_exception_pc((address)(DWORD_PTR)exceptionInfo->ContextRecord->Pc); ! } ! // Set pc to handler ! exceptionInfo->ContextRecord->Pc = (DWORD64)handler; ! #elif defined(_M_AMD64) // Do not blow up if no thread info available. if (thread) { thread->set_saved_exception_pc((address)(DWORD_PTR)exceptionInfo->ContextRecord->Rip); } // Set pc to handler
*** 2236,2246 **** //----------------------------------------------------------------------------- LONG Handle_IDiv_Exception(struct _EXCEPTION_POINTERS* exceptionInfo) { // handle exception caused by idiv; should only happen for -MinInt/-1 // (division by zero is handled explicitly) ! #ifdef _M_AMD64 PCONTEXT ctx = exceptionInfo->ContextRecord; address pc = (address)ctx->Rip; assert(pc[0] >= Assembler::REX && pc[0] <= Assembler::REX_WRXB && pc[1] == 0xF7 || pc[0] == 0xF7, "not an idiv opcode"); assert(pc[0] >= Assembler::REX && pc[0] <= Assembler::REX_WRXB && (pc[2] & ~0x7) == 0xF8 || (pc[1] & ~0x7) == 0xF8, "cannot handle non-register operands"); if (pc[0] == 0xF7) { --- 2259,2279 ---- //----------------------------------------------------------------------------- LONG Handle_IDiv_Exception(struct _EXCEPTION_POINTERS* exceptionInfo) { // handle exception caused by idiv; should only happen for -MinInt/-1 // (division by zero is handled explicitly) ! #if defined(_M_ARM64) ! PCONTEXT ctx = exceptionInfo->ContextRecord; ! address pc = (address)ctx->Sp; ! assert(pc[0] == 0x83, "not an sdiv opcode"); //Fixme did i get the right opcode? ! assert(ctx->X4 == min_jint, "unexpected idiv exception"); ! // set correct result values and continue after idiv instruction ! ctx->Pc = (uint64_t)pc + 4; // idiv reg, reg, reg is 4 bytes ! ctx->X4 = (uint64_t)min_jint; // result ! ctx->X5 = (uint64_t)0; // remainder ! // Continue the execution ! #elif defined(_M_AMD64) PCONTEXT ctx = exceptionInfo->ContextRecord; address pc = (address)ctx->Rip; assert(pc[0] >= Assembler::REX && pc[0] <= Assembler::REX_WRXB && pc[1] == 0xF7 || pc[0] == 0xF7, "not an idiv opcode"); assert(pc[0] >= Assembler::REX && pc[0] <= Assembler::REX_WRXB && (pc[2] & ~0x7) == 0xF8 || (pc[1] & ~0x7) == 0xF8, "cannot handle non-register operands"); if (pc[0] == 0xF7) {
*** 2267,2276 **** --- 2300,2310 ---- // Continue the execution #endif return EXCEPTION_CONTINUE_EXECUTION; } + #if defined(_M_AMD64) || defined(_M_IX86) //----------------------------------------------------------------------------- LONG WINAPI Handle_FLT_Exception(struct _EXCEPTION_POINTERS* exceptionInfo) { PCONTEXT ctx = exceptionInfo->ContextRecord; #ifndef _WIN64 // handle exception caused by native method modifying control word
*** 2312,2366 **** } #endif // !_WIN64 return EXCEPTION_CONTINUE_SEARCH; } static inline void report_error(Thread* t, DWORD exception_code, address addr, void* siginfo, void* context) { VMError::report_and_die(t, exception_code, addr, siginfo, context); // If UseOsErrorReporting, this will return here and save the error file // somewhere where we can find it in the minidump. } ! bool os::win32::get_frame_at_stack_banging_point(JavaThread* thread, ! struct _EXCEPTION_POINTERS* exceptionInfo, address pc, frame* fr) { ! PEXCEPTION_RECORD exceptionRecord = exceptionInfo->ExceptionRecord; ! address addr = (address) exceptionRecord->ExceptionInformation[1]; ! if (Interpreter::contains(pc)) { ! *fr = os::fetch_frame_from_context((void*)exceptionInfo->ContextRecord); ! if (!fr->is_first_java_frame()) { ! // get_frame_at_stack_banging_point() is only called when we ! // have well defined stacks so java_sender() calls do not need ! // to assert safe_for_sender() first. ! *fr = fr->java_sender(); ! } ! } else { ! // more complex code with compiled code ! assert(!Interpreter::contains(pc), "Interpreted methods should have been handled above"); ! CodeBlob* cb = CodeCache::find_blob(pc); ! if (cb == NULL || !cb->is_nmethod() || cb->is_frame_complete_at(pc)) { ! // Not sure where the pc points to, fallback to default ! // stack overflow handling ! return false; ! } else { ! *fr = os::fetch_frame_from_context((void*)exceptionInfo->ContextRecord); ! // in compiled code, the stack banging is performed just after the return pc ! // has been pushed on the stack ! *fr = frame(fr->sp() + 1, fr->fp(), (address)*(fr->sp())); ! if (!fr->is_java_frame()) { ! // See java_sender() comment above. ! *fr = fr->java_sender(); ! } ! } ! } ! assert(fr->is_java_frame(), "Safety check"); ! return true; ! } ! ! #if INCLUDE_AOT LONG WINAPI topLevelVectoredExceptionFilter(struct _EXCEPTION_POINTERS* exceptionInfo) { PEXCEPTION_RECORD exceptionRecord = exceptionInfo->ExceptionRecord; address addr = (address) exceptionRecord->ExceptionInformation[1]; address pc = (address) exceptionInfo->ContextRecord->Rip; --- 2346,2366 ---- } #endif // !_WIN64 return EXCEPTION_CONTINUE_SEARCH; } + #endif static inline void report_error(Thread* t, DWORD exception_code, address addr, void* siginfo, void* context) { VMError::report_and_die(t, exception_code, addr, siginfo, context); // If UseOsErrorReporting, this will return here and save the error file // somewhere where we can find it in the minidump. } ! #if !defined(USE_VECTORED_EXCEPTION_HANDLING) && INCLUDE_AOT LONG WINAPI topLevelVectoredExceptionFilter(struct _EXCEPTION_POINTERS* exceptionInfo) { PEXCEPTION_RECORD exceptionRecord = exceptionInfo->ExceptionRecord; address addr = (address) exceptionRecord->ExceptionInformation[1]; address pc = (address) exceptionInfo->ContextRecord->Rip;
*** 2379,2389 **** //----------------------------------------------------------------------------- LONG WINAPI topLevelExceptionFilter(struct _EXCEPTION_POINTERS* exceptionInfo) { if (InterceptOSException) return EXCEPTION_CONTINUE_SEARCH; DWORD exception_code = exceptionInfo->ExceptionRecord->ExceptionCode; ! #ifdef _M_AMD64 address pc = (address) exceptionInfo->ContextRecord->Rip; #else address pc = (address) exceptionInfo->ContextRecord->Eip; #endif Thread* t = Thread::current_or_null_safe(); --- 2379,2391 ---- //----------------------------------------------------------------------------- LONG WINAPI topLevelExceptionFilter(struct _EXCEPTION_POINTERS* exceptionInfo) { if (InterceptOSException) return EXCEPTION_CONTINUE_SEARCH; DWORD exception_code = exceptionInfo->ExceptionRecord->ExceptionCode; ! #if defined(_M_ARM64) ! address pc = (address)exceptionInfo->ContextRecord->Pc; ! #elif defined(_M_AMD64) address pc = (address) exceptionInfo->ContextRecord->Rip; #else address pc = (address) exceptionInfo->ContextRecord->Eip; #endif Thread* t = Thread::current_or_null_safe();
*** 2470,2484 **** --- 2472,2488 ---- return EXCEPTION_CONTINUE_SEARCH; } } #endif // _WIN64 + #if defined(_M_AMD64) || defined(_M_IX86) if ((exception_code == EXCEPTION_ACCESS_VIOLATION) && VM_Version::is_cpuinfo_segv_addr(pc)) { // Verify that OS save/restore AVX registers. return Handle_Exception(exceptionInfo, VM_Version::cpuinfo_cont_addr()); } + #endif if (t != NULL && t->is_Java_thread()) { JavaThread* thread = (JavaThread*) t; bool in_java = thread->thread_state() == _thread_in_Java;
*** 2559,2568 **** --- 2563,2595 ---- return EXCEPTION_CONTINUE_SEARCH; } } } + #ifdef _M_ARM64 + // Unsafe memory access + CompiledMethod* nm = NULL; + JavaThread* thread = (JavaThread*)t; + if (in_java) { + CodeBlob* cb = CodeCache::find_blob_unsafe(pc); + nm = (cb != NULL) ? cb->as_compiled_method_or_null() : NULL; + } + + bool is_unsafe_arraycopy = (thread->thread_state() == _thread_in_native || in_java) && UnsafeCopyMemory::contains_pc(pc); + if (is_unsafe_arraycopy || + ((thread->thread_state() == _thread_in_vm || + thread->thread_state() == _thread_in_native) && + thread->doing_unsafe_access()) || + (nm != NULL && nm->has_unsafe_access())) { + address next_pc = Assembler::locate_next_instruction(pc); + if (is_unsafe_arraycopy) { + next_pc = UnsafeCopyMemory::page_error_continue_pc(pc); + } + return Handle_Exception(exceptionInfo, SharedRuntime::handle_unsafe_access(thread, next_pc)); + } + #endif + #ifdef _WIN64 // Special care for fast JNI field accessors. // jni_fast_Get<Primitive>Field can trap at certain pc's if a GC kicks // in and the heap gets shrunk before the field access. if (exception_code == EXCEPTION_ACCESS_VIOLATION) {
*** 2600,2625 **** --- 2627,2668 ---- } return Handle_Exception(exceptionInfo, SharedRuntime::handle_unsafe_access(thread, next_pc)); } } + #ifdef _M_ARM64 + if (in_java && + (exception_code == EXCEPTION_ILLEGAL_INSTRUCTION || + exception_code == EXCEPTION_ILLEGAL_INSTRUCTION_2)) { + if (nativeInstruction_at(pc)->is_sigill_zombie_not_entrant()) { + if (TraceTraps) { + tty->print_cr("trap: zombie_not_entrant"); + } + return Handle_Exception(exceptionInfo, SharedRuntime::get_handle_wrong_method_stub()); + } + } + #endif + if (in_java) { switch (exception_code) { case EXCEPTION_INT_DIVIDE_BY_ZERO: return Handle_Exception(exceptionInfo, SharedRuntime::continuation_for_implicit_exception(thread, pc, SharedRuntime::IMPLICIT_DIVIDE_BY_ZERO)); case EXCEPTION_INT_OVERFLOW: return Handle_IDiv_Exception(exceptionInfo); } // switch } + + #if defined(_M_AMD64) || defined(_M_IX86) if (((thread->thread_state() == _thread_in_Java) || (thread->thread_state() == _thread_in_native)) && exception_code != EXCEPTION_UNCAUGHT_CXX_EXCEPTION) { LONG result=Handle_FLT_Exception(exceptionInfo); if (result==EXCEPTION_CONTINUE_EXECUTION) return result; } + #endif } if (exception_code != EXCEPTION_BREAKPOINT) { report_error(t, exception_code, pc, exceptionInfo->ExceptionRecord, exceptionInfo->ContextRecord);
*** 3623,3633 **** --- 3666,3681 ---- char* os::non_memory_address_word() { // Must never look like an address returned by reserve_memory, // even in its subfields (as defined by the CPU immediate fields, // if the CPU splits constants across multiple instructions). + #ifdef _M_ARM64 + // AArch64 has a maximum addressable space of 48-bits + return (char*)((1ull << 48) - 1); + #else return (char*)-1; + #endif } #define MAX_ERROR_COUNT 100 #define SYS_THREAD_ERROR 0xffffffffUL
*** 3819,3828 **** --- 3867,3904 ---- "stack size not a multiple of page size"); initialize_performance_counter(); } + int os::win32::get_cacheline_size() { + PSYSTEM_LOGICAL_PROCESSOR_INFORMATION buffer = NULL; + DWORD returnLength = 0; + + // See https://docs.microsoft.com/en-us/windows/win32/api/sysinfoapi/nf-sysinfoapi-getlogicalprocessorinformation + + GetLogicalProcessorInformation(NULL, &returnLength); + assert(GetLastError() == ERROR_INSUFFICIENT_BUFFER, "Unexpected return from GetLogicalProcessorInformation"); + + buffer = (PSYSTEM_LOGICAL_PROCESSOR_INFORMATION)os::malloc(returnLength, mtInternal); + BOOL rc = GetLogicalProcessorInformation(buffer, &returnLength); + assert(rc, "Unexpected return from GetLogicalProcessorInformation"); + + int line_sz = -1; + for (PSYSTEM_LOGICAL_PROCESSOR_INFORMATION ptr = buffer; ptr < buffer + returnLength / sizeof(SYSTEM_LOGICAL_PROCESSOR_INFORMATION); ptr++) { + switch (ptr->Relationship) { + case RelationCache: + // Cache data is in ptr->Cache, one CACHE_DESCRIPTOR structure for each cache. + PCACHE_DESCRIPTOR Cache = &ptr->Cache; + if (Cache->Level == 1) { + line_sz = Cache->LineSize; + } + break; + } + } + os::free(buffer); + return line_sz; + } HINSTANCE os::win32::load_Windows_dll(const char* name, char *ebuf, int ebuflen) { char path[MAX_PATH]; DWORD size;
*** 4147,4157 **** // have to set it the same so we have to mirror Solaris. DEBUG_ONLY(os::set_mutex_init_done();) // Setup Windows Exceptions ! #if INCLUDE_AOT // If AOT is enabled we need to install a vectored exception handler // in order to forward implicit exceptions from code in AOT // generated DLLs. This is necessary since these DLLs are not // registered for structured exceptions like codecache methods are. if (AOTLibrary != NULL && (UseAOT || FLAG_IS_DEFAULT(UseAOT))) { --- 4223,4235 ---- // have to set it the same so we have to mirror Solaris. DEBUG_ONLY(os::set_mutex_init_done();) // Setup Windows Exceptions ! #if defined(USE_VECTORED_EXCEPTION_HANDLING) ! topLevelVectoredExceptionHandler = AddVectoredExceptionHandler(1, topLevelExceptionFilter); ! #elif INCLUDE_AOT // If AOT is enabled we need to install a vectored exception handler // in order to forward implicit exceptions from code in AOT // generated DLLs. This is necessary since these DLLs are not // registered for structured exceptions like codecache methods are. if (AOTLibrary != NULL && (UseAOT || FLAG_IS_DEFAULT(UseAOT))) {
*** 5606,5616 **** } // WINDOWS CONTEXT Flags for THREAD_SAMPLING #if defined(IA32) #define sampling_context_flags (CONTEXT_FULL | CONTEXT_FLOATING_POINT | CONTEXT_EXTENDED_REGISTERS) ! #elif defined (AMD64) #define sampling_context_flags (CONTEXT_FULL | CONTEXT_FLOATING_POINT) #endif // returns true if thread could be suspended, // false otherwise --- 5684,5694 ---- } // WINDOWS CONTEXT Flags for THREAD_SAMPLING #if defined(IA32) #define sampling_context_flags (CONTEXT_FULL | CONTEXT_FLOATING_POINT | CONTEXT_EXTENDED_REGISTERS) ! #elif defined(AMD64) || defined(_M_ARM64) #define sampling_context_flags (CONTEXT_FULL | CONTEXT_FLOATING_POINT) #endif // returns true if thread could be suspended, // false otherwise
< prev index next >