Merge remote-tracking branch 'upstream/master' into HEAD
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..2f0da84
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,25 @@
+#==============================================================================#
+# This file specifies intentionally untracked files that git should ignore.
+# See: http://www.kernel.org/pub/software/scm/git/docs/gitignore.html
+#
+# This file is intentionally different from the output of `git svn show-ignore`,
+# as most of those are useless.
+#==============================================================================#
+
+#==============================================================================#
+# File extensions to be ignored anywhere in the tree.
+#==============================================================================#
+# Temp files created by most text editors.
+*~
+# Merge files created by git.
+*.orig
+# Byte compiled python modules.
+*.pyc
+# vim swap files
+.*.swp
+.sw?
+
+#==============================================================================#
+# Explicit files to ignore (only matches one).
+#==============================================================================#
+.gitusers
diff --git a/OWNERS b/OWNERS
new file mode 100644
index 0000000..ac015a5
--- /dev/null
+++ b/OWNERS
@@ -0,0 +1,8 @@
+dschuff@chromium.org
+eliben@chromium.org
+jfb@chromium.org
+jvoung@chromium.org
+kschimpf@chromium.org
+mseaborn@chromium.org
+sehr@chromium.org
+stichnot@chromium.org
diff --git a/codereview.settings b/codereview.settings
new file mode 100644
index 0000000..6dc999c
--- /dev/null
+++ b/codereview.settings
@@ -0,0 +1,10 @@
+# This file is used by gcl to get repository specific information.
+CODE_REVIEW_SERVER: codereview.chromium.org
+CC_LIST: native-client-reviews@googlegroups.com
+VIEW_VC: https://gerrit.chromium.org/gerrit/gitweb?p=native_client/pnacl-libcxxabi.git;a=commit;h=
+STATUS: http://nativeclient-status.appspot.com/status
+TRY_ON_UPLOAD: False
+TRYSERVER_PROJECT: nacl
+TRYSERVER_SVN_URL: svn://svn.chromium.org/chrome-try/try-nacl
+PUSH_URL_CONFIG: url.ssh://gerrit.chromium.org.pushinsteadof
+ORIGIN_URL_CONFIG: http://chromium.googlesource.com
diff --git a/src/cxa_demangle.cpp b/src/cxa_demangle.cpp
index 839aebe..39b6f3e 100644
--- a/src/cxa_demangle.cpp
+++ b/src/cxa_demangle.cpp
@@ -4876,6 +4876,16 @@
             *status = invalid_args;
         return nullptr;
     }
+    // @LOCALMOD-START The demangler is *huge* and only used in
+    // default_terminate_handler with a fallback to printing mangled
+    // names instead. pexe size matters a lot, so PNaCl only prints out
+    // mangled names when exceptions are uncaught.
+#ifdef __pnacl__
+    if (status)
+        *status = memory_alloc_failure;
+    return nullptr;
+#else
+    // @LOCALMOD-END
     size_t internal_size = buf != nullptr ? *n : 0;
     arena<bs> a;
     Db db(a);
@@ -4932,6 +4942,9 @@
     if (status)
         *status = internal_status;
     return buf;
+    // @LOCALMOD-START
+#endif // __pnacl__
+    // @LOCALMOD-END
 }
 
 }  // __cxxabiv1
diff --git a/src/cxa_personality.cpp b/src/cxa_personality.cpp
index 97e5800..589a27c 100644
--- a/src/cxa_personality.cpp
+++ b/src/cxa_personality.cpp
@@ -421,7 +421,14 @@
 set_registers(_Unwind_Exception* unwind_exception, _Unwind_Context* context,
               const scan_results& results)
 {
-#if __arm__
+    // @LOCALMOD-START
+#if defined(__pnacl__)
+    _Unwind_PNaClSetResult0(
+        context, reinterpret_cast<uintptr_t>(unwind_exception));
+    _Unwind_PNaClSetResult1(
+        context, static_cast<uintptr_t>(results.ttypeIndex));
+#elif __arm__
+    // @LOCALMOD-END
     _Unwind_SetGR(context, 0, reinterpret_cast<uintptr_t>(unwind_exception));
     _Unwind_SetGR(context, 1, static_cast<uintptr_t>(results.ttypeIndex));
 #else
diff --git a/src/cxa_pnacl_sjlj_exception.cpp b/src/cxa_pnacl_sjlj_exception.cpp
new file mode 100644
index 0000000..0b9f7cf
--- /dev/null
+++ b/src/cxa_pnacl_sjlj_exception.cpp
@@ -0,0 +1,408 @@
+//===- cxa_pnacl_sjlj_exception.cpp - PNaCl SJLJ-based exception handling--===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This implements setjmp()/longjmp()-based (SJLJ) C++ exception
+// handling for PNaCl.  This uses the C++ exception info tables
+// generated by the PNaClSjLjEH LLVM pass.
+//
+// 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
+// libc++/libcxxabi.  When SJLJ EH is enabled, each
+// __pnacl_eh_sjlj_Unwind_*() symbol will get renamed to _Unwind_*()
+// when linking a PNaCl pexe.
+//
+//===----------------------------------------------------------------------===//
+
+#include <setjmp.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+#include <typeinfo>
+
+#include "cxa_exception.hpp"
+#include "cxa_handlers.hpp"
+#include "private_typeinfo.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 __shim_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;
+
+
+// Returns whether the thrown exception (specified by throw_type and
+// obj) matches none of the exception types in a C++ exception
+// specification (specified by filter_id).
+static bool
+exception_spec_can_catch(const __shim_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 != 0; ++filter_ptr)
+    {
+        const __shim_type_info *catch_type =
+            __pnacl_eh_type_table[*filter_ptr - 1];
+        // We ignore the modified value of obj here.
+        if (catch_type->can_catch(throw_type, obj))
+            return false;
+    }
+    // No type matched, so we have an exception specification error.
+    return true;
+}
+
+// Returns whether the thrown exception (specified by throw_type and
+// obj) matches the given landingpad clause (clause_id).
+//
+// If the exception matches and the clause is a "catch" clause, this
+// adjusts *obj to upcast it to the type specified in the "catch"
+// clause.  (For example, if throw_type uses multiple inheritance and
+// derives from multiple base classes, this might involve adding a
+// constant offset to *obj.)
+static bool
+does_clause_match(const __shim_type_info *throw_type, void **obj,
+                  int32_t clause_id)
+{
+    // Handle "cleanup" clause.
+    if (clause_id == 0)
+        return true;
+
+    // Handle "filter" clause.
+    if (clause_id < 0)
+        return exception_spec_can_catch(throw_type, obj, clause_id);
+
+    // Handle "catch" clause.
+    const __shim_type_info *catch_type = __pnacl_eh_type_table[clause_id - 1];
+    if (catch_type == NULL)
+        return true;
+    return catch_type->can_catch(throw_type, *obj);
+}
+
+// Returns whether the given frame should be entered in order to
+// handle the thrown exception (specified by throw_type and *obj).  If
+// so, this adjusts *obj (see does_clause_match()) and sets
+// *result_clause_id.
+static bool
+does_frame_match(const __shim_type_info *throw_type, void **obj,
+                 struct exception_frame *frame, int32_t *result_clause_id)
+{
+    for (int32_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))
+        {
+            *result_clause_id = list_node->clause_id;
+            return true;
+        }
+        clause_list_id = list_node->next_clause_list_id;
+    }
+    return false;
+}
+
+// Search for a stack frame that will handle the given exception,
+// starting from frame.  The exception is specified by throw_type and
+// *obj.
+//
+// If a frame is found that will handle the exception, this adjusts
+// *obj (to upcast it to the "catch" type, if there is one), sets
+// *result_frame and *result_clause_id to the frame and clause ID that
+// matched the exception, and returns true.
+static bool
+find_match(const __shim_type_info *throw_type, void **obj,
+           struct exception_frame *frame,
+           struct exception_frame **result_frame, int32_t *result_clause_id)
+{
+    for (; frame != NULL; frame = frame->next)
+    {
+        if (does_frame_match(throw_type, obj, frame, result_clause_id))
+        {
+            *result_frame = frame;
+            return true;
+        }
+    }
+    return false;
+}
+
+// Search for a non-cleanup stack frame that will handle the given
+// exception, starting from frame.  Returns whether a matching frame
+// was found.
+static bool
+is_exception_caught(const __shim_type_info *throw_type, void *obj,
+                    struct exception_frame *frame)
+{
+    for (; frame != NULL; frame = frame->next)
+    {
+        int32_t clause_id;
+        if (does_frame_match(throw_type, &obj, frame, &clause_id)
+            && clause_id != 0)
+            return true;
+    }
+    return false;
+}
+
+static __cxa_exception *
+get_exception_header_from_ue(struct _Unwind_Exception *ue_header)
+{
+    return (__cxa_exception *) (ue_header + 1) - 1;
+}
+
+static __cxa_dependent_exception *
+get_dependent_exception_from_ue(struct _Unwind_Exception *ue_header)
+{
+    return (__cxa_dependent_exception *) (ue_header + 1) - 1;
+}
+
+static void *
+get_object_from_ue(struct _Unwind_Exception *ue_header)
+{
+    if (ue_header->exception_class == kOurDependentExceptionClass)
+    {
+        return get_dependent_exception_from_ue(ue_header)->primaryException;
+    }
+    return ue_header + 1;
+}
+
+// handle_exception() is called by _Unwind_RaiseException().  It
+// unwinds the stack, looking for the first C++ destructor or catch()
+// block to pass control to.  In LLVM terms, it searches for the first
+// matching invoke/landingpad instruction.  When it finds a match,
+// this implementation passes control to the landingpad block by
+// longjmp()'ing to it.
+//
+// In a traditional implementation (based on the Itanium ABI),
+// _Unwind_RaiseException() is implemented in a library (libgcc_eh)
+// that is separate from libcxxabi.  It calls back to libcxxabi's
+// personality function (__gxx_personality_v0()) to determine whether
+// a call on the stack has a handler for the exception.
+// __gxx_personality_v0() knows that ue_header was allocated by
+// libcxxabi's __cxa_allocate_exception() and can downcast it to
+// libcxxabi's __cxa_exception type.
+//
+// In contrast, in the implementation below, the functionality of the
+// personality function is folded into _Unwind_RaiseException(), so
+// this implements C++-specific matching of exceptions and downcasts
+// ue_header to __cxa_exception immediately.
+//
+// This function returns if stack unwinding did not find any stack
+// frames that match the exception being thrown.
+static void
+handle_exception(struct _Unwind_Exception *ue_header, bool check_for_catch)
+{
+    __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((__shim_type_info *) xh->exceptionType, &obj,
+                    __pnacl_eh_stack, &frame, &clause_id))
+        return;
+
+    // Check that there is a non-cleanup handler for the exception.
+    // If not, we should abort before running cleanup handlers
+    // (i.e. destructors).
+    //
+    // This is mainly a convenience for debugging.  It means that if
+    // the program throws an uncaught exception, the location of the
+    // "throw" will be on the stack when the program aborts.  If we
+    // ran cleanup handlers before aborting, this context would be
+    // lost.
+    //
+    // This is optional in 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".
+    if (check_for_catch && clause_id == 0 &&
+        !is_exception_caught((__shim_type_info *) xh->exceptionType, obj,
+                             frame->next))
+        return;
+
+    __pnacl_eh_stack = frame->next;
+
+    // Save adjusted exception pointer so that it can be returned by
+    // __cxa_begin_catch() when entering a catch() block.
+    xh->adjustedPtr = obj;
+
+    // Save the clause ID so that if the landingpad block calls
+    // __cxa_call_unexpected() and the std::set_unexpected() handler
+    // throws an exception, we can re-check that exception against the
+    // exception specification.
+    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));
+
+    // Return to the landingpad block, passing it two values.
+    frame->result.exception_obj = ue_header;
+    frame->result.matched_clause_id = clause_id;
+    longjmp(jmpbuf_copy, 1);
+}
+
+
+// This implements _Unwind_RaiseException().  This is called when
+// raising an exception for the first time, i.e. for the statement
+// "throw EXPR;".  The compiler lowers "throw EXPR;" to:
+//  * a call to __cxa_allocate_exception() to allocate memory;
+//  * a call to __cxa_throw() which throws the exception by calling
+//    _Unwind_RaiseException().
+extern "C" _Unwind_Reason_Code
+__pnacl_eh_sjlj_Unwind_RaiseException(struct _Unwind_Exception *ue_header)
+{
+    handle_exception(ue_header, true);
+    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.
+//
+// This is called by a landingpad block as a final step after it has
+// run C++ destructors.  This is only called by a landingpad if it did
+// not enter a catch() block.
+//
+// This function never returns.
+extern "C" void
+__pnacl_eh_resume(struct _Unwind_Exception *ue_header)
+{
+    // Pass check_for_catch=false so that unwinding does not take O(n^2)
+    // time in the number of cleanup landingpads entered before entering
+    // the catch() block.
+    handle_exception(ue_header, false);
+
+    // We've run C++ destructors (cleanup handlers), but no further
+    // handlers were found, so abort.  We should not reach here, because
+    // __pnacl_eh_sjlj_Unwind_RaiseException() already checked that
+    // there was a handler for this exception other than cleanup
+    // handlers.
+    __cxa_begin_catch(ue_header);
+    std::terminate();
+}
+
+// _Unwind_Resume_or_Rethrow() is called when rethrowing an
+// exception, i.e. for the statement "throw;" (with no arguments).
+// The compiler lowers "throw;" to a call to __cxa_rethrow(), which
+// calls this function.
+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.
+//
+// This is called when a catch() block that handles an exception exits
+// without rethrowing the exception.  This is called by
+// __cxa_end_catch().  The compiler generates a call to
+// __cxa_end_catch() at the end of a catch() block.
+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 function implements __cxa_call_unexpected(), which is called
+// by a landingpad block when an exception is thrown that doesn't
+// match a function's exception spec (i.e. a "throw(...)" attribute on
+// a function).  Calls to __cxa_call_unexpected() are generated by the
+// C++ front end.
+//
+// This calls the handler registered with std::set_unexpected().  This
+// handler is allowed to throw, in which case we must re-check the
+// resulting exception against the original exception specification.
+//
+// The reason that __cxa_call_unexpected() is called by landingpad
+// code rather than by the personality function is so that the
+// landingpad code can run destructors first.
+//
+// This is loosely based on the __cxa_call_unexpected() implementation
+// in cxa_personality.cpp.
+//
+// This function never returns.
+extern "C" void
+__pnacl_eh_sjlj_cxa_call_unexpected(struct _Unwind_Exception *ue_header)
+{
+    // Mark the exception as being handled, so that the
+    // set_unexpected() handler can rethrow it.
+    __cxa_begin_catch(ue_header);
+
+    // Ensure that the corresponding __cxa_end_catch() call happens on
+    // all paths out of this function.
+    struct do_end_catch
+    {
+        ~do_end_catch() { __cxa_end_catch(); }
+    } do_end_catch_obj;
+
+    __cxa_exception *old_exception_header =
+        get_exception_header_from_ue(ue_header);
+    int32_t filter_id = old_exception_header->handlerSwitchValue;
+    std::unexpected_handler u_handler = old_exception_header->unexpectedHandler;
+    std::terminate_handler t_handler = old_exception_header->terminateHandler;
+
+    try
+    {
+        std::__unexpected(u_handler);
+    }
+    catch (...)
+    {
+        __cxa_eh_globals *globals = __cxa_get_globals_fast();
+        __cxa_exception *new_exception_header = globals->caughtExceptions;
+
+        // If the handler threw an exception that is allowed by the
+        // original exception spec, allow this exception to propagate.
+        if (!exception_spec_can_catch(
+                (const __shim_type_info *) new_exception_header->exceptionType,
+                get_object_from_ue(&new_exception_header->unwindHeader),
+                filter_id))
+            throw;
+
+        // Otherwise, if the original exception spec allows
+        // std::bad_exception, throw an exception of that type.
+        std::bad_exception be;
+        const __shim_type_info *be_type =
+            (const __shim_type_info *) &typeid(be);
+        if (!exception_spec_can_catch(be_type, &be, filter_id))
+            throw be;
+    }
+    std::__terminate(t_handler);
+}