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

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: 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..564917f4f605213e75ac5dcf7c3ef8f1eb885931
--- /dev/null
+++ b/libstdc++-v3/libsupc++/eh_pnacl.cc
@@ -0,0 +1,225 @@
+
+#include <setjmp.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <typeinfo>
+
+#include "unwind-cxx.h"
+
+
+using namespace __cxxabiv1;
+
+struct exc_result {
+ void *exc;
+ uint32_t exc_type_id;
+};
+
+struct unwind_frame {
+ union {
+ jmp_buf jmpbuf;
+ struct exc_result result;
+ };
+ struct unwind_frame *next;
+ uint32_t action_id;
+};
+
+struct action_table_entry {
+ int32_t type_filter_id;
+ uint32_t next_action_id;
+};
+
+extern std::type_info *const __pnacl_eh_type_table[];
+extern const struct action_table_entry __pnacl_eh_action_table[];
+extern const uint32_t __pnacl_eh_filter_table[];
+
+__thread struct unwind_frame *__pnacl_eh_stack;
+
+
+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;
+}
+
+static int check_exception_spec(const std::type_info *throw_type, void *obj,
+ int32_t filter_id) {
+ const uint32_t *filter_ptr =
+ &__pnacl_eh_filter_table[-filter_id - 1];
+ for (; *filter_ptr != -1; ++filter_ptr) {
+ std::type_info *catch_type = __pnacl_eh_type_table[*filter_ptr];
+ // If any type matches, the overall filter doesn't trigger.
+ // We ignore the modified value of obj.
+ if (get_adjusted_ptr(catch_type, throw_type, &obj))
+ return 1;
+ }
+ // No type matched, so we have an exception specification error.
+ return 0;
+}
+
+static int filter_matches(std::type_info *throw_type, void **obj,
+ int32_t filter_id) {
+ if (filter_id < 0)
+ return !check_exception_spec(throw_type, obj, filter_id);
+
+ std::type_info *catch_type = __pnacl_eh_type_table[filter_id];
+ printf(" exception id: type_id=%i -> %p (%s)\n",
+ filter_id, catch_type,
+ catch_type ? catch_type->name() : "catch-all");
+ if (get_adjusted_ptr(catch_type, throw_type, obj)) {
+ printf(" match found (%s match)\n",
+ throw_type == catch_type ? "exact" : "subtype");
+ return 1;
+ } else {
+ return 0;
+ }
+}
+
+static void find_match(std::type_info *throw_type, void **obj,
+ struct unwind_frame **result_frame,
+ int *result_filter_id) {
+ while (__pnacl_eh_stack != NULL) {
+ struct unwind_frame *frame = __pnacl_eh_stack;
+ __pnacl_eh_stack = frame->next;
+
+ for (uint32_t action_id = frame->action_id; action_id != 0; ) {
+ const struct action_table_entry *action =
+ &__pnacl_eh_action_table[action_id - 1];
+ if (filter_matches(throw_type, obj, action->type_filter_id)) {
+ // Match found.
+ *result_frame = frame;
+ *result_filter_id = action->type_filter_id;
+ return;
+ }
+ action_id = action->next_action_id;
+ }
+ printf(" no match: trying next frame\n");
+ }
+
+ printf("no match\n");
+ abort();
+}
+
+__attribute__((noreturn))
+static void do_return(struct unwind_frame *frame,
+ void *ue_header, int filter_id) {
+ // We reuse the storage of jmpbuf for the landingpad data, so
+ // save a copy of jmpbuf.
+ jmp_buf jmpbuf_copy;
+ memcpy(&jmpbuf_copy, &frame->jmpbuf, sizeof(jmpbuf_copy));
+
+ frame->result.exc = ue_header;
+ frame->result.exc_type_id = filter_id;
+ longjmp(jmpbuf_copy, 1);
+ abort();
+}
+
+static void do_unwinding(struct _Unwind_Exception *ue_header) {
+ __cxa_exception *xh = __get_exception_header_from_ue(ue_header);
+ printf(" thrown type: %p (%s)\n",
+ xh->exceptionType, xh->exceptionType->name());
+
+ void *obj = __get_object_from_ue(ue_header);
+ std::type_info *throw_type = xh->exceptionType;
+
+ struct unwind_frame *frame;
+ int filter_id;
+ find_match(throw_type, &obj, &frame, &filter_id);
+
+ xh->adjustedPtr = obj;
+ xh->handlerSwitchValue = filter_id;
+
+ do_return(frame, ue_header, filter_id);
+}
+
+extern "C" _Unwind_Reason_Code
+__pnacl_eh_sjlj_Unwind_RaiseException(struct _Unwind_Exception *ue_header) {
+ printf("_Unwind_RaiseException: %p\n", ue_header);
+
+ do_unwinding(ue_header);
+ abort();
+}
+
+extern "C" void __pnacl_eh_resume(struct _Unwind_Exception *ue_header) {
+ printf("__pnacl_eh_resume() called\n");
+ do_unwinding(ue_header);
+}
+
+extern "C" _Unwind_Reason_Code
+_Unwind_Resume_or_Rethrow(struct _Unwind_Exception *ue_header) {
+ printf("_Unwind_Resume_or_Rethrow: %p\n", ue_header);
+ return _Unwind_RaiseException(ue_header);
+}
+
+extern "C" void
+_Unwind_DeleteException (struct _Unwind_Exception *exc)
+{
+ if (exc->exception_cleanup)
+ (*exc->exception_cleanup) (_URC_FOREIGN_EXCEPTION_CAUGHT, exc);
+}
+
+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."
+ printf(" calling 'unexpected' handler\n");
+ try {
+ xh->unexpectedHandler();
+ } catch (...) {
+ printf(" 'unexpected' handler threw\n");
+ __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);
+ }
+ printf(" 'unexpected' handler returned\n");
+ std::terminate();
+}
« 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