Salikh Zakirov wrote:
> I recently found out the reason why smoke test gc.LOS hangs DRLVM on Windows
> XP, and it turned out to be related to the hardware exception handling.
> 
> Since the fix will involve significant modifications to the file
> vm/vmcore/src/util/win/ia32/nt_exception_filter.cpp,
> I can do this modification too.

I'm sending my current state of the patch (well, series of 3 patches)
for interested parties to review.

However, these patches somewhat regress in functionality:
I still haven't figured out how to piggy-back on exception throw
to call JVMTI callback and to restore stack guard page.
(the commented out block at the end of nt_exception_filter.cpp was doing it
before fix).

Any ideas appreciated.
>From a8f9838563950b4eaed54582f053c841d55759f7 Mon Sep 17 00:00:00 2001
From: Salikh Zakirov <[EMAIL PROTECTED]>
Date: Fri, 24 Nov 2006 16:14:27 +0300
Subject: [PATCH] changed logging in nt_exception_filter.c from cxx-style to 
c-style

---
 .../src/util/win/ia32/nt_exception_filter.cpp      |   26 ++++++++++----------
 1 files changed, 13 insertions(+), 13 deletions(-)

diff --git a/vm/vmcore/src/util/win/ia32/nt_exception_filter.cpp 
b/vm/vmcore/src/util/win/ia32/nt_exception_filter.cpp
index 65cd721..061d33b 100644
--- a/vm/vmcore/src/util/win/ia32/nt_exception_filter.cpp
+++ b/vm/vmcore/src/util/win/ia32/nt_exception_filter.cpp
@@ -19,7 +19,7 @@
  * @version $Revision: 1.1.2.1.4.4 $
  */  
 
-#include "cxxlog.h"
+#include "clog.h"
 #include "method_lookup.h"
 #include "Environment.h"
 #include "exceptions.h"
@@ -301,9 +301,9 @@ static LONG NTAPI vectored_exception_han
     bool run_default_handler = true;
     PCONTEXT context = nt_exception->ContextRecord;
     
-    TRACE2("signals", "VEH received an exception: code = 0x" <<
-        ((void*)nt_exception->ExceptionRecord->ExceptionCode) <<
-        " location IP = 0x" << ((void*)context->Eip));
+    TRACE2("signals", ("VEH received an exception: code = %x, eip = %p",
+        nt_exception->ExceptionRecord->ExceptionCode,
+        ((void*)context->Eip)));
     
     // this filter catches _all_ hardware exceptions including those caused by
     // VM internal code.  To elimate confusion over what caused the
@@ -360,9 +360,9 @@ static LONG NTAPI vectored_exception_han
     case STATUS_STACK_OVERFLOW:
         // stack overflow exception -- see ...\vc\include\winnt.h
         {
-            TRACE2("signals", "StackOverflowError detected at "
-                << (void *) context->Eip << " on the stack at "
-                << (void *) context->Esp);
+            TRACE2("signals",
+                ("StackOverflowError detected at eip = %p, esp = %p",
+                 context->Eip,context->Esp));
             // Lazy exception object creation
             exc_clss = env->java_lang_StackOverflowError_Class;
             p_TLS_vmthread->restore_guard_page = true;
@@ -371,8 +371,8 @@ static LONG NTAPI vectored_exception_han
     case STATUS_ACCESS_VIOLATION:
         // null pointer exception -- see ...\vc\include\winnt.h
         {
-            TRACE2("signals", "NullPointerException detected at " 
-                << (void *) context->Eip);
+            TRACE2("signals",
+                ("NullPointerException detected at eip = %p", context->Eip));
             // Lazy exception object creation
             exc_clss = env->java_lang_NullPointerException_Class;
         }
@@ -381,8 +381,8 @@ static LONG NTAPI vectored_exception_han
     case STATUS_INTEGER_DIVIDE_BY_ZERO:
         // divide by zero exception  -- see ...\vc\include\winnt.h
         {
-            TRACE2("signals", "ArithmeticException detected at "
-                << (void *) context->Eip);
+            TRACE2("signals",
+                ("ArithmeticException detected at eip = %p", context->Eip));
             // Lazy exception object creation
             exc_clss = env->java_lang_ArithmeticException_Class;
         }
@@ -392,8 +392,8 @@ static LONG NTAPI vectored_exception_han
         {
             Registers regs;
             nt_to_vm_context(context, &regs);
-            TRACE2("signals", "JVMTI breakpoint detected at " <<
-                (void *)regs.eip);
+            TRACE2("signals",
+                ("JVMTI breakpoint detected at eip = %p", regs.eip));
             bool handled = jvmti_jit_breakpoint_handler(&regs);
             if (handled)
             {
-- 
1.4.4.1.g2d57

>From c3e6321984a02e5b9bdcf36cc36adfc7176d9239 Mon Sep 17 00:00:00 2001
From: Salikh Zakirov <[EMAIL PROTECTED]>
Date: Fri, 24 Nov 2006 17:09:15 +0300
Subject: [PATCH] fixed exception handler to throw exception outside of NT 
hardware exception handler

---
 .../src/util/win/ia32/nt_exception_filter.cpp      |  135 ++++++++++++++++----
 1 files changed, 111 insertions(+), 24 deletions(-)

diff --git a/vm/vmcore/src/util/win/ia32/nt_exception_filter.cpp 
b/vm/vmcore/src/util/win/ia32/nt_exception_filter.cpp
index 061d33b..8f5644d 100644
--- a/vm/vmcore/src/util/win/ia32/nt_exception_filter.cpp
+++ b/vm/vmcore/src/util/win/ia32/nt_exception_filter.cpp
@@ -27,10 +27,13 @@
 #include "interpreter_exports.h"
 #include "stack_dump.h"
 #include "jvmti_break_intf.h"
+#include "vm_threads.h"
+#include "m2n.h"
 
 // Windows specific
 #include <string>
 #include <excpt.h>
+#include <stddef.h> // for offsetof
 
 #if INSTRUMENTATION_BYTE == INSTRUMENTATION_BYTE_INT3
 #define JVMTI_EXCEPTION_STATUS STATUS_BREAKPOINT
@@ -276,6 +279,61 @@ void __declspec(naked) asm_jvmti_excepti
     }
 }
 
+static void __cdecl c_exception_handler(Class*);
+
+// the control is transferred to this handler
+// after NT exception handler returned
+static void __declspec(naked) asm_exception_handler_push_m2n() {
+    // input parameters:
+    //      EAX = exception eip
+    //      EDX = exn_class
+    static const int last_m2n_frame_offset =
+        offsetof(VM_thread, last_m2n_frame);
+    __asm {
+        // construct M2nFrame on a stack
+        push eax            // M2n: EIP
+        push ebp            // M2n: EBP
+        mov ebp, esp
+        push ebx            // M2n: EBX
+        push esi            // M2n: ESI
+        push edi            // M2n: EDI
+
+        push 0              // M2n: pop_regs = NULL
+        push 0              // M2n: frame type
+        push 0              // M2n: method = NULL
+        push 0              // M2n: object handles = NULL
+
+        // get thread ptr to eax
+        push ecx
+        push edx
+        call get_thread_ptr
+        pop edx
+        pop ecx
+
+        // get &p_TLS_vmthread->last_m2n_frame
+        add eax, last_m2n_frame_offset
+        push eax            // M2n: p_lm2nf
+        push [eax]          // M2n: prev_m2nf
+        mov [eax], esp      // store M2n pointer to VM_thread
+
+        // push parameter exn_class
+        push edx
+        call c_exception_handler
+    }
+    assert(!"internal error on throwing exception");
+}
+
+static void __declspec(naked) asm_exception_handler_no_m2n() {
+    // input parameters:
+    //      EDX = exn_class
+    __asm {
+        // push parameter exn_class
+        push edx
+        call c_exception_handler
+    }
+    assert(!"internal error on throwing exception");
+}
+
 static LONG NTAPI vectored_exception_handler_internal(LPEXCEPTION_POINTERS 
nt_exception);
 
 LONG __declspec(naked) NTAPI vectored_exception_handler(LPEXCEPTION_POINTERS 
nt_exception)
@@ -297,24 +355,33 @@ LONG __declspec(naked) NTAPI vectored_ex
 static LONG NTAPI vectored_exception_handler_internal(LPEXCEPTION_POINTERS 
nt_exception)
 {
     DWORD code = nt_exception->ExceptionRecord->ExceptionCode;
-    
-    bool run_default_handler = true;
     PCONTEXT context = nt_exception->ContextRecord;
-    
+
     TRACE2("signals", ("VEH received an exception: code = %x, eip = %p",
         nt_exception->ExceptionRecord->ExceptionCode,
         ((void*)context->Eip)));
-    
-    // this filter catches _all_ hardware exceptions including those caused by
-    // VM internal code.  To elimate confusion over what caused the
-    // exception, we first make sure the exception was thrown inside a Java
-    // method else crash handler or default handler is executed, this means 
that
-    // it was thrown by VM C/C++ code.
-    if (((code == STATUS_ACCESS_VIOLATION ||
-        code == STATUS_INTEGER_DIVIDE_BY_ZERO ||
-        code == STATUS_STACK_OVERFLOW) &&
-        vm_identify_eip((void *)context->Eip) == VM_TYPE_JAVA) ||
-        code == JVMTI_EXCEPTION_STATUS) {
+
+    // the possible reasons for hardware exception are
+    //  - segfault in java code
+    //     => NullPointerException
+    //
+    //  - stack overflow, either in java or in native
+    //    => StackOverflowError
+    //
+    //  - breakpoint in java code
+    //    => send jvmti breakpoint event
+    //
+    //  - other (likely internal VM error)
+    //    => delegate to default handler
+
+    void* eip = (void*)context->Eip;
+    bool run_default_handler = true;
+    bool in_java = (vm_identify_eip(eip) == VM_TYPE_JAVA);
+
+    if ((in_java && (code == STATUS_ACCESS_VIOLATION
+                    || code == STATUS_INTEGER_DIVIDE_BY_ZERO
+                    || code == STATUS_STACK_OVERFLOW))
+                || code == JVMTI_EXCEPTION_STATUS) {
             run_default_handler = false;
     } else if (code == STATUS_STACK_OVERFLOW) {
         if (is_unwindable()) {
@@ -406,18 +473,39 @@ static LONG NTAPI vectored_exception_han
     default: assert(false);
     }
 
-    Registers regs;
+    // we must not call potentially blocking or suspendable
+    // code (e.g. java code) from exception handler, because
+    // this handler may holds a system-wide lock, and thus
+    // may lead to a deadlock.
+
+    // it was reported that exception handler grabs a system
+    // lock on Windows XPsp2 and 2003sp0, but not on a 2003sp1
+
+    // exit NT exception handler and transfer
+    // control to VM exception handler,
+    // passing parameters on the registers
+    context->Eax = context->Eip;
+    context->Edx = (uint32)exc_clss;
+    if (in_java)
+        context->Eip = (uint32)asm_exception_handler_push_m2n;
+    else
+        context->Eip = (uint32)asm_exception_handler_no_m2n;
+    return EXCEPTION_CONTINUE_EXECUTION;
+}
 
-    nt_to_vm_context(context, &regs);
 
-    uint32 exception_esp = regs.esp;
+static void __cdecl c_exception_handler(Class *exn_class)
+{
     DebugUtilsTI* ti = VM_Global_State::loader_env->TI;
 
-    // TODO: We already checked that above. Is it possible to reuse the result?
-    bool java_code = (vm_identify_eip((void *)regs.eip) == VM_TYPE_JAVA);
-    exn_athrow_regs(&regs, exc_clss, java_code);
+    void *eip = m2n_get_ip(p_TLS_vmthread->last_m2n_frame);
 
-    assert(exception_esp <= regs.esp);
+    TRACE2("signals", ("should throw exception at EIP: %p", eip));
+    TRACE2("signals", ("last m2n: %p",
+                p_TLS_vmthread->last_m2n_frame));
+    exn_athrow(NULL, exn_class, NULL, NULL);
+
+    /*
     if (ti->get_global_capability(DebugUtilsTI::TI_GC_ENABLE_EXCEPTION_EVENT)) 
{
         regs.esp = regs.esp - 4;
         *((uint32*) regs.esp) = regs.eip;
@@ -429,6 +517,5 @@ static LONG NTAPI vectored_exception_han
     }
 
     vm_to_nt_context(&regs, context);
-
-    return EXCEPTION_CONTINUE_EXECUTION;
-} //vectored_exception_handler
+    */
+}
-- 
1.4.4.1.g2d57

>From f29c05e52cb9c61d958239f1307d01f4b5279794 Mon Sep 17 00:00:00 2001
From: Salikh Zakirov <[EMAIL PROTECTED]>
Date: Fri, 24 Nov 2006 18:13:03 +0300
Subject: [PATCH] cleaned up NT exception handler

---
 .../src/util/win/ia32/nt_exception_filter.cpp      |  101 ++++++++------------
 1 files changed, 40 insertions(+), 61 deletions(-)

diff --git a/vm/vmcore/src/util/win/ia32/nt_exception_filter.cpp 
b/vm/vmcore/src/util/win/ia32/nt_exception_filter.cpp
index 8f5644d..02804c0 100644
--- a/vm/vmcore/src/util/win/ia32/nt_exception_filter.cpp
+++ b/vm/vmcore/src/util/win/ia32/nt_exception_filter.cpp
@@ -281,8 +281,7 @@ void __declspec(naked) asm_jvmti_excepti
 
 static void __cdecl c_exception_handler(Class*);
 
-// the control is transferred to this handler
-// after NT exception handler returned
+// pushes M2nFrame and calls c_exception_handler()
 static void __declspec(naked) asm_exception_handler_push_m2n() {
     // input parameters:
     //      EAX = exception eip
@@ -323,6 +322,7 @@ static void __declspec(naked) asm_except
     assert(!"internal error on throwing exception");
 }
 
+// calls c_exception_handler() without pushing M2nFrame
 static void __declspec(naked) asm_exception_handler_no_m2n() {
     // input parameters:
     //      EDX = exn_class
@@ -362,95 +362,72 @@ static LONG NTAPI vectored_exception_han
         ((void*)context->Eip)));
 
     // the possible reasons for hardware exception are
-    //  - segfault in java code
-    //     => NullPointerException
+    //  - segfault or division by zero in java code
+    //     => NullPointerException or ArithmeticException
+    //
+    //  - breakpoint or privileged instruction in java code
+    //    => send jvmti breakpoint event
     //
     //  - stack overflow, either in java or in native
     //    => StackOverflowError
     //
-    //  - breakpoint in java code
-    //    => send jvmti breakpoint event
-    //
-    //  - other (likely internal VM error)
+    //  - other (internal VM error or debugger breakpoint)
     //    => delegate to default handler
 
-    void* eip = (void*)context->Eip;
-    bool run_default_handler = true;
-    bool in_java = (vm_identify_eip(eip) == VM_TYPE_JAVA);
-
-    if ((in_java && (code == STATUS_ACCESS_VIOLATION
-                    || code == STATUS_INTEGER_DIVIDE_BY_ZERO
-                    || code == STATUS_STACK_OVERFLOW))
-                || code == JVMTI_EXCEPTION_STATUS) {
-            run_default_handler = false;
-    } else if (code == STATUS_STACK_OVERFLOW) {
-        if (is_unwindable()) {
-            if (hythread_is_suspend_enabled()) {
-                tmn_suspend_disable();
-            }
-            run_default_handler = false;
-        } else {
-                Global_Env *env = VM_Global_State::loader_env;
-                exn_raise_by_class(env->java_lang_StackOverflowError_Class);
-            p_TLS_vmthread->restore_guard_page = true;
-            return EXCEPTION_CONTINUE_EXECUTION;
-        }
-    }
+    bool in_java = (vm_identify_eip((void*)context->Eip) == VM_TYPE_JAVA);
 
-    if (run_default_handler) {
-#ifndef NDEBUG
-        if (vm_get_boolean_property_value_with_default("vm.assert_dialog")) {
-
-            if (IS_ERROR(code)) {
-                 if (UnhandledExceptionFilter(nt_exception) == 
EXCEPTION_CONTINUE_SEARCH)
-                     DebugBreak();
-            }
-        }
-#endif
+    // delegate "other" cases to default handler
+    if (!in_java && code != STATUS_STACK_OVERFLOW)
         return EXCEPTION_CONTINUE_SEARCH;
-    }
 
-    // since we are now sure HWE occured in java code, gc should also have 
been disabled
+    // if HWE occured in java code, suspension should also have been disabled
+    assert(!in_java || !hythread_is_suspend_enabled());
 
-    // gregory - this is not true since for debugging we may use int3
-    // in VM code which produces BREAKPOINT exception. JVMTI has
-    // assertions for breakpoints which it has set in Java inside of
-    // breakpoint handling function. Otherwise this assert should not
-    // fail in case _CrtDbgBreak() was added somewhere in VM.
-    assert(!hythread_is_suspend_enabled() || code == JVMTI_EXCEPTION_STATUS);
-    
     Global_Env *env = VM_Global_State::loader_env;
+    // the actual exception object will be created lazily,
+    // we determine only exception class here
     Class *exc_clss = 0;
 
     switch(nt_exception->ExceptionRecord->ExceptionCode) 
     {
     case STATUS_STACK_OVERFLOW:
-        // stack overflow exception -- see ...\vc\include\winnt.h
         {
             TRACE2("signals",
                 ("StackOverflowError detected at eip = %p, esp = %p",
                  context->Eip,context->Esp));
-            // Lazy exception object creation
-            exc_clss = env->java_lang_StackOverflowError_Class;
+
             p_TLS_vmthread->restore_guard_page = true;
+            exc_clss = env->java_lang_StackOverflowError_Class;
+            if (in_java) {
+                // stack overflow occured in java code:
+                // nothing special to do
+            } else if (is_unwindable()) {
+                // stack overflow occured in native code that can be unwound
+                // safely.
+                // Throwing exception requires suspend disabled status
+                if (hythread_is_suspend_enabled())
+                    hythread_suspend_disable();
+            } else {
+                // stack overflow occured in native code that
+                // cannot be unwound.
+                // Mark raised exception in TLS and resume execution
+                exn_raise_by_class(env->java_lang_StackOverflowError_Class);
+                return EXCEPTION_CONTINUE_EXECUTION;
+            }
         }
         break;
     case STATUS_ACCESS_VIOLATION:
-        // null pointer exception -- see ...\vc\include\winnt.h
         {
             TRACE2("signals",
                 ("NullPointerException detected at eip = %p", context->Eip));
-            // Lazy exception object creation
             exc_clss = env->java_lang_NullPointerException_Class;
         }
         break;
 
     case STATUS_INTEGER_DIVIDE_BY_ZERO:
-        // divide by zero exception  -- see ...\vc\include\winnt.h
         {
             TRACE2("signals",
                 ("ArithmeticException detected at eip = %p", context->Eip));
-            // Lazy exception object creation
             exc_clss = env->java_lang_ArithmeticException_Class;
         }
         break;
@@ -470,13 +447,15 @@ static LONG NTAPI vectored_exception_han
             else
                 return EXCEPTION_CONTINUE_SEARCH;
         }
-    default: assert(false);
+    default:
+        // unexpected hardware exception occured in java code
+        return EXCEPTION_CONTINUE_SEARCH;
     }
 
-    // we must not call potentially blocking or suspendable
-    // code (e.g. java code) from exception handler, because
-    // this handler may holds a system-wide lock, and thus
-    // may lead to a deadlock.
+    // we must not call potentially blocking or suspendable code
+    // (i.e. java code of exception constructor) from exception
+    // handler, because this handler may holds a system-wide lock,
+    // and thus may lead to a deadlock.
 
     // it was reported that exception handler grabs a system
     // lock on Windows XPsp2 and 2003sp0, but not on a 2003sp1
-- 
1.4.4.1.g2d57

Reply via email to