Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(699)

Unified Diff: libstdc++-v3/libsupc++/eh_pnacl.cc

Issue 27341005: libstdc++: Add support for exception handling using the PNaClSjLjEH LLVM pass (Closed) Base URL: http://git.chromium.org/native_client/pnacl-gcc.git@pnacl
Patch Set: Retry upload Created 7 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « libstdc++-v3/libsupc++/Makefile.in ('k') | no next file » | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: libstdc++-v3/libsupc++/eh_pnacl.cc
diff --git a/libstdc++-v3/libsupc++/eh_pnacl.cc b/libstdc++-v3/libsupc++/eh_pnacl.cc
new file mode 100644
index 0000000000000000000000000000000000000000..1b4c6ef73137c838ce9f56af66ea10fc83125d9a
--- /dev/null
+++ b/libstdc++-v3/libsupc++/eh_pnacl.cc
@@ -0,0 +1,287 @@
+// -*- C++ -*- Exception handling routines for PNaCl.
+// Copyright (C) 2013
+// Free Software Foundation, Inc.
+//
+// This file is part of GCC.
+//
+// GCC is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 3, or (at your option)
+// any later version.
+//
+// GCC is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// Under Section 7 of GPL version 3, you are granted additional
+// permissions described in the GCC Runtime Library Exception, version
+// 3.1, as published by the Free Software Foundation.
+
+// You should have received a copy of the GNU General Public License and
+// a copy of the GCC Runtime Library Exception along with this program;
+// see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
+// <http://www.gnu.org/licenses/>.
+
+#include <setjmp.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+#include <typeinfo>
+#include "unwind-cxx.h"
+
+using namespace __cxxabiv1;
+
+
+// Exception info written by ExceptionInfoWriter.cpp.
+
+struct action_table_entry
+{
+ int32_t clause_id;
+ uint32_t next_clause_list_id;
+};
+
+extern const struct action_table_entry __pnacl_eh_action_table[];
+extern const std::type_info *const __pnacl_eh_type_table[];
+extern const int32_t __pnacl_eh_filter_table[];
+
+// Data structures used by PNaClSjLjEH.cpp.
+
+struct landing_pad_result
+{
+ void *exception_obj;
+ uint32_t matched_clause_id;
+};
+
+struct exception_frame
+{
+ union
+ {
+ jmp_buf jmpbuf;
+ struct landing_pad_result result;
+ };
+ struct exception_frame *next;
+ uint32_t clause_list_id;
+};
+
+__thread struct exception_frame *__pnacl_eh_stack;
+
+
+// This is based on get_adjusted_ptr() in eh_personality.cc.
+//
+// Given the thrown type THROW_TYPE, pointer to a variable containing a
+// pointer to the exception object THROWN_PTR_P and a type CATCH_TYPE to
+// compare against, return whether or not there is a match and if so,
+// update *THROWN_PTR_P.
+static bool
+get_adjusted_ptr (const std::type_info *catch_type,
+ const std::type_info *throw_type,
+ void **thrown_ptr_p)
+{
+ if (catch_type == NULL)
+ return true;
+
+ void *thrown_ptr = *thrown_ptr_p;
+
+ // Pointer types need to adjust the actual pointer, not
+ // the pointer to pointer that is the exception object.
+ // This also has the effect of passing pointer types
+ // "by value" through the __cxa_begin_catch return value.
+ if (throw_type->__is_pointer_p ())
+ thrown_ptr = *(void **) thrown_ptr;
+
+ if (catch_type->__do_catch (throw_type, &thrown_ptr, 1))
+ {
+ *thrown_ptr_p = thrown_ptr;
+ return true;
+ }
+
+ return false;
+}
+
+// Returns whether the thrown exception (specified by THROW_TYPE and
+// OBJ) matches one of the exception types in a C++ exception
+// specification (specified by FILTER_ID).
+static bool
+check_exception_spec (const std::type_info *throw_type, void *obj,
+ int32_t filter_id)
+{
+ const int32_t *filter_ptr =
+ &__pnacl_eh_filter_table[-filter_id - 1];
+ for (; *filter_ptr != -1; ++filter_ptr)
+ {
+ const std::type_info *catch_type = __pnacl_eh_type_table[*filter_ptr];
+ // We ignore the modified value of obj here.
+ if (get_adjusted_ptr (catch_type, throw_type, &obj))
+ return true;
+ }
+ // No type matched, so we have an exception specification error.
+ return false;
+}
+
+// Returns whether the thrown exception (specified by THROW_TYPE and
+// OBJ) matches the given landingpad clause (CLAUSE_ID). If the
+// exception matches, this adjusts *OBJ.
+static bool
+does_clause_match (const std::type_info *throw_type, void **obj,
+ int32_t clause_id)
+{
+ if (clause_id < 0)
+ return !check_exception_spec (throw_type, obj, clause_id);
+
+ const std::type_info *catch_type = __pnacl_eh_type_table[clause_id];
+ return get_adjusted_ptr (catch_type, throw_type, obj);
+}
+
+// Search for a stack frame that will handle the given exception.
+static bool
+find_match (const std::type_info *throw_type, void **obj,
+ struct exception_frame **result_frame, int32_t *result_clause_id)
+{
+ while (__pnacl_eh_stack != NULL)
+ {
+ struct exception_frame *frame = __pnacl_eh_stack;
+ __pnacl_eh_stack = frame->next;
+
+ for (uint32_t clause_list_id = frame->clause_list_id;
+ clause_list_id != 0; )
+ {
+ const struct action_table_entry *list_node =
+ &__pnacl_eh_action_table[clause_list_id - 1];
+ if (does_clause_match (throw_type, obj, list_node->clause_id))
+ {
+ // Match found.
+ *result_frame = frame;
+ *result_clause_id = list_node->clause_id;
+ return true;
+ }
+ clause_list_id = list_node->next_clause_list_id;
+ }
+ }
+ return false;
+}
+
+// Each __pnacl_eh_sjlj_Unwind_*() function below provides the
+// definition of _Unwind_*().
+//
+// The "__pnacl_eh_sjlj" prefix is added so that PNaCl's SJLJ
+// (setjmp()/longjmp()-based) implementation of C++ exception handling
+// can coexist with other implementations in the same build of
+// libstdc++/libsupc++. When SJLJ EH is enabled, each
+// __pnacl_eh_sjlj_Unwind_*() symbol will get renamed to _Unwind_*()
+// when linking a PNaCl pexe.
+
+extern "C" _Unwind_Reason_Code
+__pnacl_eh_sjlj_Unwind_RaiseException (struct _Unwind_Exception *ue_header)
+{
+ __cxa_exception *xh = __get_exception_header_from_ue (ue_header);
+
+ void *obj = __get_object_from_ue (ue_header);
+ struct exception_frame *frame;
+ int32_t clause_id;
+ if (find_match (xh->exceptionType, &obj, &frame, &clause_id))
+ {
+ xh->adjustedPtr = obj;
+ xh->handlerSwitchValue = clause_id;
+
+ // exception_frame uses the same location for storing the
+ // jmp_buf and the landing_pad_result, so we must make a copy of
+ // the jmp_buf first.
+ jmp_buf jmpbuf_copy;
+ memcpy (&jmpbuf_copy, &frame->jmpbuf, sizeof (jmpbuf_copy));
+
+ frame->result.exception_obj = ue_header;
+ frame->result.matched_clause_id = clause_id;
+ longjmp (jmpbuf_copy, 1);
+ }
+
+ return _URC_END_OF_STACK;
+}
+
+// This is the equivalent of _Unwind_Resume() from libgcc_eh, but we
+// use a different name for PNaCl SJLJ to avoid accidental collisions
+// with libgcc_eh.
+extern "C" void
+__pnacl_eh_resume (struct _Unwind_Exception *ue_header)
Derek Schuff 2013/10/24 20:41:17 why __pnacl_eh_resume and not __pnacl_eh_sjlj_Unwi
Mark Seaborn 2013/10/24 21:43:54 My thinking here was that there is a distinction b
+{
+ __pnacl_eh_sjlj_Unwind_RaiseException (ue_header);
+
+ // We've run C++ destructors (cleanup handlers), but no further
+ // handlers were found, so abort.
+ //
+ // Note that this situation does not normally happen with GNU C++,
+ // which scans the stack to check for a matching catch or filter
+ // clause, and calls std::terminate() if none is found, before
+ // calling any cleanup handlers.
+ //
+ // Both behaviours are allowed by the C++ standard, which says "If
+ // no matching handler is found, the function std::terminate() is
+ // called; whether or not the stack is unwound before this call to
+ // std::terminate() is implementation-defined".
+ __cxa_begin_catch (ue_header);
+ std::terminate ();
+}
+
+extern "C" _Unwind_Reason_Code
+__pnacl_eh_sjlj_Unwind_Resume_or_Rethrow (struct _Unwind_Exception *ue_header)
+{
+ return __pnacl_eh_sjlj_Unwind_RaiseException (ue_header);
+}
+
+// A convenience function that calls the exception_cleanup field.
+// Based on the definition in libgcc_eh's unwind.inc.
+extern "C" void
+__pnacl_eh_sjlj_Unwind_DeleteException (struct _Unwind_Exception *exc)
+{
+ if (exc->exception_cleanup)
+ (*exc->exception_cleanup) (_URC_FOREIGN_EXCEPTION_CAUGHT, exc);
+}
+
+// This is based on __cxa_call_unexpected in eh_personality.cc,
+// adapted to use PNaCl's exception info instead of the non-portable
+// LSDA.
+extern "C" void
+__pnacl_eh_sjlj_cxa_call_unexpected (_Unwind_Exception *ue_header)
+{
+ __cxa_exception *xh = __get_exception_header_from_ue (ue_header);
+ int xh_switch_value = xh->handlerSwitchValue;
+ std::terminate_handler xh_terminate_handler = xh->terminateHandler;
+
+ __cxa_begin_catch (ue_header);
+
+ // This function is a handler for our exception argument. If we exit
+ // by throwing a different exception, we'll need the original cleaned up.
+ struct end_catch_protect
+ {
+ end_catch_protect() { }
+ ~end_catch_protect() { __cxa_end_catch(); }
+ } end_catch_protect_obj;
+
+ // We use the handler function that was cached by __cxa_throw().
+ // libstdc++'s unwind-cxx.h says this is cached because "The C++
+ // standard has entertaining rules wrt calling set_terminate and
+ // set_unexpected in the middle of the exception cleanup process."
+ try
+ {__unexpected (xh->unexpectedHandler); }
+ catch (...)
+ {
+ __cxa_eh_globals *globals = __cxa_get_globals_fast ();
+ __cxa_exception *new_xh = globals->caughtExceptions;
+ void *new_ptr = __get_object_from_ambiguous_exception (new_xh);
+
+ // If this new exception meets the exception spec, allow it.
+ if (check_exception_spec (
+ __get_exception_header_from_obj (new_ptr)->exceptionType,
+ new_ptr, xh_switch_value))
+ throw;
+
+ // If the exception spec allows std::bad_exception, throw that.
+ // We don't have a thrown object to compare against, but since
+ // bad_exception doesn't have virtual bases, that's OK; just pass 0.
+ const std::type_info *bad_exc = &typeid (std::bad_exception);
+ if (check_exception_spec (bad_exc, NULL, xh_switch_value))
+ throw std::bad_exception ();
+
+ __terminate (xh_terminate_handler);
+ }
+}
« no previous file with comments | « libstdc++-v3/libsupc++/Makefile.in ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698