From 416bc10f4ad49d3bd82855c65ba04ca212868d48 Mon Sep 17 00:00:00 2001 From: Pavel Afremov Date: Wed, 8 Nov 2006 12:49:26 +0300 Subject: [PATCH] Fix support of SOE and other runtime exceptions in VM native code. The fix consists in: enable lazy exception scheme, remove fake assertions, provide separate way of throwing exception for native code from exn_athrow_regs, add test excetion.FinalizeStackTest to smoke tests to check this changes. --- vm/tests/smoke/StackTest.java | 5 ++ vm/tests/smoke/exception/FinalizeStackTest.java | 48 ++++++++++++++++++++ vm/vmcore/include/exceptions_jit.h | 2 - vm/vmcore/src/exception/exceptions.cpp | 8 +++ vm/vmcore/src/exception/exceptions_impl.cpp | 4 +- vm/vmcore/src/exception/exceptions_jit.cpp | 15 +++++- vm/vmcore/src/util/linux/signals_em64t.cpp | 30 +++---------- vm/vmcore/src/util/linux/signals_ia32.cpp | 31 ++++++++----- vm/vmcore/src/util/linux/signals_ipf.cpp | 2 - .../src/util/win/em64t/nt_exception_filter.cpp | 3 + .../src/util/win/ia32/nt_exception_filter.cpp | 12 ++++-- vm/vmcore/src/util/win/ipf/nt_exception_filter.cpp | 2 - 12 files changed, 112 insertions(+), 50 deletions(-) diff --git a/vm/tests/smoke/StackTest.java b/vm/tests/smoke/StackTest.java index ee0a652..a7a0722 100644 --- a/vm/tests/smoke/StackTest.java +++ b/vm/tests/smoke/StackTest.java @@ -27,8 +27,11 @@ public class StackTest { public static void main(String[] args) { try { func(); + System.out.println("FAIL"); + } catch (StackOverflowError soe) { + System.out.println("PASS : First SOE depth = " + depth + " : " + soe); } catch (Throwable th) { - System.out.println("PASS : First SOE depth = " + depth + " : " + th); + System.out.println("FAIL"); } } } diff --git a/vm/tests/smoke/exception/FinalizeStackTest.java b/vm/tests/smoke/exception/FinalizeStackTest.java new file mode 100755 index 0000000..03f11cc --- /dev/null +++ b/vm/tests/smoke/exception/FinalizeStackTest.java @@ -0,0 +1,48 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Pavel Afremov + * @version $Revision: 1.0 $ + */ +package exception; + +class FinalizeStackTest { + private static final int MAX_DEPTH = 1000000; + + FinalizeStackTest(int c) { + if (c > 0) { + new FinalizeStackTest(c - 1); + } else { + System.out.println("PASS"); + } + } + + protected void finalize() { + // empty + } + + public static void main(String[] args) { + try { + new FinalizeStackTest(MAX_DEPTH); + System.out.println("FAIL"); + } catch (StackOverflowError soe) { + System.out.println("PASS : " + soe); + } catch (Throwable th) { + System.out.println("FAIL"); + } + } +} diff --git a/vm/vmcore/include/exceptions_jit.h b/vm/vmcore/include/exceptions_jit.h index 482fcd4..92a9518 100644 --- a/vm/vmcore/include/exceptions_jit.h +++ b/vm/vmcore/include/exceptions_jit.h @@ -42,7 +42,7 @@ void exn_athrow(ManagedObject* exn_obj, // Must be called with the current thread "suspended" in managed code and regs holds the suspended values. // Exception defined as in previous two functions. // Mutates the regs value, which should be used to "resume" the managed code. -void exn_athrow_regs(Registers* regs, Class_Handle exn_class); +void exn_athrow_regs(Registers* regs, Class_Handle exn_class, bool java_code); // exception catch callback to restore stack after Stack Overflow Error void exception_catch_callback(); diff --git a/vm/vmcore/src/exception/exceptions.cpp b/vm/vmcore/src/exception/exceptions.cpp index b151622..33e0230 100644 --- a/vm/vmcore/src/exception/exceptions.cpp +++ b/vm/vmcore/src/exception/exceptions.cpp @@ -347,8 +347,12 @@ #else } else if (NULL != p_TLS_vmthread->thread_exception.exc_class) { Class * exc_class = p_TLS_vmthread->thread_exception.exc_class; const char* exc_message = p_TLS_vmthread->thread_exception.exc_message; - jthrowable exc_cause = oh_allocate_local_handle(); - exc_cause->object = p_TLS_vmthread->thread_exception.exc_cause; + jthrowable exc_cause = NULL; + + if (p_TLS_vmthread->thread_exception.exc_cause){ + exc_cause = oh_allocate_local_handle(); + exc_cause->object = p_TLS_vmthread->thread_exception.exc_cause; + } clear_exception_internal(); exn_throw_by_class_internal(exc_class, exc_message, exc_cause); } else { diff --git a/vm/vmcore/src/exception/exceptions_impl.cpp b/vm/vmcore/src/exception/exceptions_impl.cpp index 949542e..86d2782 100644 --- a/vm/vmcore/src/exception/exceptions_impl.cpp +++ b/vm/vmcore/src/exception/exceptions_impl.cpp @@ -26,6 +26,7 @@ #include "clog.h" #include "Class.h" #include "classloader.h" #include "exceptions.h" +#include "exceptions_impl.h" #include "exceptions_jit.h" #include "exceptions_type.h" #include "environment.h" @@ -36,6 +37,7 @@ #include "vm_strings.h" Class *get_exc_class(const char *exception_name) { ASSERT_RAISE_AREA; + assert(hythread_is_suspend_enabled()); Global_Env *env = VM_Global_State::loader_env; String *exc_str = env->string_pool.lookup(exception_name); Class *exc_class = @@ -299,7 +301,6 @@ void exn_throw_object_internal(jthrowabl void exn_throw_by_class_internal(Class* exc_class, const char* exc_message, jthrowable exc_cause) { - assert(is_unwindable()); #ifdef VM_LAZY_EXCEPTION set_unwindable(false); @@ -369,6 +370,7 @@ #ifdef VM_LAZY_EXCEPTION } tmn_suspend_enable_recursive(); #else + assert(hythread_is_suspend_enabled()); jthrowable exc_object = exn_create(exc_class, exc_message, exc_cause); if (exn_raised()){ diff --git a/vm/vmcore/src/exception/exceptions_jit.cpp b/vm/vmcore/src/exception/exceptions_jit.cpp index a92a449..7cad1f0 100644 --- a/vm/vmcore/src/exception/exceptions_jit.cpp +++ b/vm/vmcore/src/exception/exceptions_jit.cpp @@ -444,18 +444,27 @@ void exn_athrow(ManagedObject* exn_obj, // Exception defined as in previous two functions. // Mutates the regs value, which should be used to "resume" the managed code. -void exn_athrow_regs(Registers * regs, Class_Handle exn_class) +void exn_athrow_regs(Registers * regs, Class_Handle exn_class, bool java_code) { assert(exn_class); #ifndef _IPF_ - M2nFrame *m2nf = m2n_push_suspended_frame(regs); + M2nFrame *m2nf; + + if (java_code) { + m2nf = m2n_push_suspended_frame(regs); + } + StackIterator *si = si_create_from_native(); ManagedObject *local_exn_obj = NULL; exn_propagate_exception(si, &local_exn_obj, exn_class, NULL, NULL, NULL); si_copy_to_registers(si, regs); + m2n_set_last_frame(si_get_m2n(si)); si_free(si); - STD_FREE(m2nf); + + if (java_code) { + STD_FREE(m2nf); + } #endif } //exn_athrow_regs diff --git a/vm/vmcore/src/util/linux/signals_em64t.cpp b/vm/vmcore/src/util/linux/signals_em64t.cpp index b77427a..e64ed88 100644 --- a/vm/vmcore/src/util/linux/signals_em64t.cpp +++ b/vm/vmcore/src/util/linux/signals_em64t.cpp @@ -113,8 +113,9 @@ static void throw_from_sigcontext(uconte linux_ucontext_to_regs(®s, uc); DebugUtilsTI* ti = VM_Global_State::loader_env->TI; + bool java_code = (vm_identify_eip((void *)regs.rip) == VM_TYPE_JAVA); - exn_athrow_regs(®s, exc_clss); + exn_athrow_regs(®s, exc_clss, java_code); linux_regs_to_ucontext(uc, ®s); } @@ -131,24 +132,6 @@ static bool java_throw_from_sigcontext(u return true; } -static bool linux_throw_from_sigcontext(ucontext_t *uc, Class* exc_clss) -{ - ASSERT_NO_INTERPRETER; - unsigned *rip = (unsigned *) uc->uc_mcontext.gregs[REG_RIP]; - VM_Code_Type vmct = vm_identify_eip((void *)rip); - if(vmct != VM_TYPE_JAVA) { - return false; - } - - Registers regs; - linux_ucontext_to_regs(®s, uc); - - exn_athrow_regs(®s, exc_clss); - - linux_regs_to_ucontext(uc, ®s); - return true; -} - /** * the saved copy of the executable name. */ @@ -318,7 +301,8 @@ size_t get_available_stack_size() { bool check_available_stack_size(size_t required_size) { if (get_available_stack_size() < required_size) { - exn_raise_by_name("java/lang/StackOverflowError"); + Global_Env *env = VM_Global_State::loader_env; + exn_raise_by_class(env->java_lang_StackOverflowError_Class); return false; } else { return true; @@ -381,7 +365,7 @@ void stack_overflow_handler(int signum, uc, env->java_lang_StackOverflowError_Class); } else { remove_guard_stack(); - exn_raise_by_name("java/lang/StackOverflowError"); + exn_raise_by_class(env->java_lang_StackOverflowError_Class); p_TLS_vmthread->restore_guard_page = true; } } @@ -401,7 +385,7 @@ void null_java_reference_handler(int sig if (env->shutting_down != 0) { fprintf(stderr, "null_java_reference_handler(): called in shutdown stage\n"); } else if (!interpreter_enabled()) { - if (linux_throw_from_sigcontext( + if (java_throw_from_sigcontext( uc, env->java_lang_NullPointerException_Class)) { return; } @@ -420,7 +404,7 @@ void null_java_divide_by_zero_handler(in if (env->shutting_down != 0) { fprintf(stderr, "null_java_divide_by_zero_handler(): called in shutdown stage\n"); } else if (!interpreter_enabled()) { - if (linux_throw_from_sigcontext( + if (java_throw_from_sigcontext( uc, env->java_lang_ArithmeticException_Class)) { return; } diff --git a/vm/vmcore/src/util/linux/signals_ia32.cpp b/vm/vmcore/src/util/linux/signals_ia32.cpp index c8077cc..e035594 100644 --- a/vm/vmcore/src/util/linux/signals_ia32.cpp +++ b/vm/vmcore/src/util/linux/signals_ia32.cpp @@ -152,7 +152,8 @@ static void throw_from_sigcontext(uconte uint32 exception_esp = regs.esp; DebugUtilsTI* ti = VM_Global_State::loader_env->TI; - exn_athrow_regs(®s, exc_clss); + bool java_code = (vm_identify_eip((void *)regs.eip) == VM_TYPE_JAVA); + exn_athrow_regs(®s, exc_clss, java_code); assert(exception_esp <= regs.esp); if (ti->get_global_capability(DebugUtilsTI::TI_GC_ENABLE_EXCEPTION_EVENT)) { regs.esp = regs.esp - 4; @@ -317,32 +318,32 @@ void init_stack_info() { void set_guard_stack() { int err; - char* stack_addr = (char*) get_stack_addr(); size_t stack_size = get_stack_size(); size_t guard_stack_size = get_guard_stack_size(); size_t guard_page_size = get_guard_page_size(); - // map the guard page and protect it + // FIXME: Workaround for main thread + // map the guard page and protect it void UNUSED *res = mmap(stack_addr - stack_size + guard_page_size + - guard_stack_size, guard_page_size, PROT_READ | PROT_WRITE, - MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); + guard_stack_size, guard_page_size, PROT_READ | PROT_WRITE, + MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); assert(res!=MAP_FAILED); err = mprotect(stack_addr - stack_size + guard_page_size + - guard_stack_size, guard_page_size, PROT_NONE ); - + guard_stack_size, guard_page_size, PROT_NONE ); + assert(!err); - //map the alternate stack on which we want to handle the signal + // FIXME: Workaround for main thread + // map the alternate stack on which we want to handle the signal void UNUSED *res2 = mmap(stack_addr - stack_size + guard_page_size, - guard_stack_size, PROT_READ | PROT_WRITE, - MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); + guard_stack_size, PROT_READ | PROT_WRITE, + MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); assert(res2!=MAP_FAILED); - stack_t sigalt; sigalt.ss_sp = stack_addr - stack_size + guard_page_size; sigalt.ss_flags = SS_ONSTACK; @@ -367,7 +368,8 @@ size_t get_default_stack_size() { } bool check_available_stack_size(size_t required_size) { if (get_available_stack_size() < required_size) { - exn_raise_by_name("java/lang/StackOverflowError"); + Global_Env *env = VM_Global_State::loader_env; + exn_raise_by_class(env->java_lang_StackOverflowError_Class); return false; } else { return true; @@ -404,6 +406,9 @@ bool check_stack_overflow(siginfo_t *inf char* guard_page_begin = stack_addr - stack_size + guard_page_size + guard_stack_size; char* guard_page_end = guard_page_begin + guard_page_size; + // FIXME: Workaround for main thread + guard_page_end += guard_page_size; + char* fault_addr = (char*)(info->si_addr); //char* esp_value = (char*)(uc->uc_mcontext.gregs[REG_ESP]); @@ -434,7 +439,7 @@ void stack_overflow_handler(int signum, uc, env->java_lang_StackOverflowError_Class); } else { remove_guard_stack(); - exn_raise_by_name("java/lang/StackOverflowError"); + exn_raise_by_class(env->java_lang_StackOverflowError_Class); p_TLS_vmthread->restore_guard_page = true; } } diff --git a/vm/vmcore/src/util/linux/signals_ipf.cpp b/vm/vmcore/src/util/linux/signals_ipf.cpp index 438ac6c..197c6fb 100644 --- a/vm/vmcore/src/util/linux/signals_ipf.cpp +++ b/vm/vmcore/src/util/linux/signals_ipf.cpp @@ -201,7 +201,7 @@ static void linux_throw_from_sigcontext( Registers regs; // linux_sigcontext_to_regs(®s, sc); // FIXME: transfer to linux_ucontext_to_regs - exn_athrow_regs(®s, exc_clss); + exn_athrow_regs(®s, exc_clss, true); // linux_regs_to_sigcontext(sc, ®s); // FIXME: transfer to linux_regs_to_ucontext // linux_regs_to_sigcontext(top_sc, ®s); // FIXME: transfer to linux_regs_to_ucontext } diff --git a/vm/vmcore/src/util/win/em64t/nt_exception_filter.cpp b/vm/vmcore/src/util/win/em64t/nt_exception_filter.cpp index 76e8e1b..886dccd 100644 --- a/vm/vmcore/src/util/win/em64t/nt_exception_filter.cpp +++ b/vm/vmcore/src/util/win/em64t/nt_exception_filter.cpp @@ -126,7 +126,8 @@ int NT_exception_filter(LPEXCEPTION_POIN nt_to_vm_context(p_NT_exception->ContextRecord, ®s); - exn_athrow_regs(®s, exc_clss); + bool java_code = (vm_identify_eip((void *)regs.eip) == VM_TYPE_JAVA); + exn_athrow_regs(®s, exc_clss, java_code); vm_to_nt_context(®s, p_NT_exception->ContextRecord); 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 63543ab..a99e194 100644 --- a/vm/vmcore/src/util/win/ia32/nt_exception_filter.cpp +++ b/vm/vmcore/src/util/win/ia32/nt_exception_filter.cpp @@ -28,6 +28,8 @@ #include "interpreter_exports.h" #include "stack_dump.h" #include "jvmti_break_intf.h" +#include "m2n.h" + // Windows specific #include #include @@ -211,7 +213,8 @@ size_t get_default_stack_size() { } bool check_available_stack_size(size_t required_size) { if (get_available_stack_size() < required_size) { - exn_raise_by_name("java/lang/StackOverflowError"); + Global_Env *env = VM_Global_State::loader_env; + exn_raise_by_class(env->java_lang_StackOverflowError_Class); return false; } else { return true; @@ -325,7 +328,9 @@ static LONG NTAPI vectored_exception_han } run_default_handler = false; } else { - exn_raise_by_name("java/lang/StackOverflowError"); + M2nFrame* frame = m2n_get_last_frame(); + 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; } @@ -456,7 +461,8 @@ static LONG NTAPI vectored_exception_han uint32 exception_esp = regs.esp; DebugUtilsTI* ti = VM_Global_State::loader_env->TI; - exn_athrow_regs(®s, exc_clss); + bool java_code = (vm_identify_eip((void *)regs.eip) == VM_TYPE_JAVA); + exn_athrow_regs(®s, exc_clss, java_code); assert(exception_esp <= regs.esp); if (ti->get_global_capability(DebugUtilsTI::TI_GC_ENABLE_EXCEPTION_EVENT)) { diff --git a/vm/vmcore/src/util/win/ipf/nt_exception_filter.cpp b/vm/vmcore/src/util/win/ipf/nt_exception_filter.cpp index 23e9680..9412426 100644 --- a/vm/vmcore/src/util/win/ipf/nt_exception_filter.cpp +++ b/vm/vmcore/src/util/win/ipf/nt_exception_filter.cpp @@ -186,7 +186,7 @@ int NT_exception_filter(LPEXCEPTION_POIN // The exception object of class exc_clss will be created by vm_null_ptr_throw. assert(exc_clss); - exn_athrow_regs(®s, exc_clss); + exn_athrow_regs(®s, exc_clss, true); vm_to_nt_context(®s, p_NT_exception->ContextRecord); -- 1.4.1