< 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 >