< 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,10 +29,11 @@
#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,17 +117,21 @@
static FILETIME process_creation_time;
static FILETIME process_exit_time;
static FILETIME process_user_time;
static FILETIME process_kernel_time;
-#ifdef _M_AMD64
+#if defined(_M_ARM64)
+ #define __CPU__ aarch64
+#elif defined(_M_AMD64)
#define __CPU__ amd64
#else
#define __CPU__ i486
#endif
-#if INCLUDE_AOT
+#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,11 +150,11 @@
break;
case DLL_PROCESS_DETACH:
if (ForceTimeHighResolution) {
timeEndPeriod(1L);
}
-#if INCLUDE_AOT
+#if defined(USE_VECTORED_EXCEPTION_HANDLING) || INCLUDE_AOT
if (topLevelVectoredExceptionHandler != NULL) {
RemoveVectoredExceptionHandler(topLevelVectoredExceptionHandler);
topLevelVectoredExceptionHandler = NULL;
}
#endif
@@ -454,19 +459,26 @@
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,19 +1437,22 @@
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_AMD64, (char*)"AMD 64"},
+ {IMAGE_FILE_MACHINE_ARM64, (char*)"ARM 64"}
};
-#if (defined _M_AMD64)
+#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
+ 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,11 +1745,12 @@
// 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) {
+ 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,11 +2154,18 @@
LONG Handle_Exception(struct _EXCEPTION_POINTERS* exceptionInfo,
address handler) {
JavaThread* thread = (JavaThread*) Thread::current_or_null();
// Save pc in thread
-#ifdef _M_AMD64
+#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,11 +2259,21 @@
//-----------------------------------------------------------------------------
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
+#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,10 +2300,11 @@
// 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,55 +2346,21 @@
}
#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.
}
-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
+#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,11 +2379,13 @@
//-----------------------------------------------------------------------------
LONG WINAPI topLevelExceptionFilter(struct _EXCEPTION_POINTERS* exceptionInfo) {
if (InterceptOSException) return EXCEPTION_CONTINUE_SEARCH;
DWORD exception_code = exceptionInfo->ExceptionRecord->ExceptionCode;
-#ifdef _M_AMD64
+#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,15 +2472,17 @@
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,10 +2563,33 @@
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,26 +2627,42 @@
}
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,11 +3666,16 @@
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,10 +3867,38 @@
"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,11 +4223,13 @@
// 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 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,11 +5684,11 @@
}
// WINDOWS CONTEXT Flags for THREAD_SAMPLING
#if defined(IA32)
#define sampling_context_flags (CONTEXT_FULL | CONTEXT_FLOATING_POINT | CONTEXT_EXTENDED_REGISTERS)
-#elif defined (AMD64)
+#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 >