This commit implements the zero-cost exception handling support
for libc++abi.

http://reviews.llvm.org/D3613

Files:
  include/cxxabi.h
  include/unwind.h
  src/cxa_demangle.cpp
  src/cxa_exception.cpp
  src/cxa_exception.hpp
  src/cxa_personality.cpp
  test/test_demangle.cpp
Index: include/cxxabi.h
===================================================================
--- include/cxxabi.h
+++ include/cxxabi.h
@@ -44,6 +44,10 @@
 extern void * __cxa_get_exception_ptr(void * exceptionObject) throw();
 extern void * __cxa_begin_catch(void * exceptionObject) throw();
 extern void __cxa_end_catch();
+#if __arm__
+extern bool __cxa_begin_cleanup(void * exceptionObject) throw();
+extern void __cxa_end_cleanup();
+#endif
 extern std::type_info * __cxa_current_exception_type();
 
 // 2.5.4 Rethrowing Exceptions
Index: include/unwind.h
===================================================================
--- include/unwind.h
+++ include/unwind.h
@@ -23,8 +23,13 @@
 #define LIBUNWIND_UNAVAIL
 #endif
 
+#if !__USING_SJLJ_EXCEPTIONS__ && defined(__arm__) && !defined(__APPLE__)
+#define LIBCXXABI_ARM_EHABI 1
+#endif
+
 typedef enum {
   _URC_NO_REASON = 0,
+  _URC_OK = 0,
   _URC_FOREIGN_EXCEPTION_CAUGHT = 1,
   _URC_FATAL_PHASE2_ERROR = 2,
   _URC_FATAL_PHASE1_ERROR = 3,
@@ -32,7 +37,8 @@
   _URC_END_OF_STACK = 5,
   _URC_HANDLER_FOUND = 6,
   _URC_INSTALL_CONTEXT = 7,
-  _URC_CONTINUE_UNWIND = 8
+  _URC_CONTINUE_UNWIND = 8,
+  _URC_FAILURE = 9
 } _Unwind_Reason_Code;
 
 typedef enum {
@@ -43,13 +49,69 @@
   _UA_END_OF_STACK = 16 // gcc extension to C++ ABI
 } _Unwind_Action;
 
+
+#if LIBCXXABI_ARM_EHABI
+typedef uint32_t _Unwind_State;
+
+static const _Unwind_State _US_VIRTUAL_UNWIND_FRAME   = 0;
+static const _Unwind_State _US_UNWIND_FRAME_STARTING  = 1;
+static const _Unwind_State _US_UNWIND_FRAME_RESUME    = 2;
+
+typedef uint32_t _Unwind_EHT_Header;
+
+struct _Unwind_Control_Block;
+typedef struct _Unwind_Control_Block _Unwind_Control_Block;
+typedef struct _Unwind_Control_Block _Unwind_Exception; /* Alias */
+
+struct _Unwind_Control_Block {
+  uint64_t exception_class;
+  void (*exception_cleanup)(_Unwind_Reason_Code, _Unwind_Control_Block*);
+
+  struct {
+    uint32_t reserved1;
+    uint32_t reserved2;
+    uint32_t reserved3;
+    uint32_t reserved4;
+    uint32_t reserved5;
+  } unwinder_cache;
+
+  struct {
+    uint32_t sp;
+    uint32_t bitpattern[5];
+  } barrier_cache;
+
+  struct {
+    uint32_t bitpattern[4];
+  } cleanup_cache;
+
+  struct {
+    uint32_t fnstart;
+    _Unwind_EHT_Header* ehtp;
+    uint32_t additional;
+    uint32_t reserved1;
+  } pr_cache;
+
+  long long int :0; /* Enforce the 8-byte alignment */
+};
+
+typedef _Unwind_Reason_Code (*_Unwind_Stop_Fn)
+      (_Unwind_State state,
+       _Unwind_Exception* exceptionObject,
+       struct _Unwind_Context* context);
+
+typedef _Unwind_Reason_Code (*__personality_routine)
+      (_Unwind_State state,
+       _Unwind_Exception* exceptionObject,
+       struct _Unwind_Context* context);
+#else
 struct _Unwind_Context;   // opaque
 struct _Unwind_Exception; // forward declaration
+typedef struct _Unwind_Exception _Unwind_Exception;
 
 struct _Unwind_Exception {
   uint64_t exception_class;
   void (*exception_cleanup)(_Unwind_Reason_Code reason,
-                            struct _Unwind_Exception *exc);
+                            _Unwind_Exception *exc);
   uintptr_t private_1; // non-zero means forced unwind
   uintptr_t private_2; // holds sp that phase1 found for phase2 to use
 #if !__LP64__
@@ -65,7 +127,7 @@
     (int version,
      _Unwind_Action actions,
      uint64_t exceptionClass,
-     struct _Unwind_Exception* exceptionObject,
+     _Unwind_Exception* exceptionObject,
      struct _Unwind_Context* context,
      void* stop_parameter );
 
@@ -73,8 +135,9 @@
       (int version,
        _Unwind_Action actions,
        uint64_t exceptionClass,
-       struct _Unwind_Exception* exceptionObject,
+       _Unwind_Exception* exceptionObject,
        struct _Unwind_Context* context);
+#endif
 
 #ifdef __cplusplus
 extern "C" {
@@ -85,33 +148,94 @@
 //
 #if __USING_SJLJ_EXCEPTIONS__
 extern _Unwind_Reason_Code
-    _Unwind_SjLj_RaiseException(struct _Unwind_Exception *exception_object);
-extern void _Unwind_SjLj_Resume(struct _Unwind_Exception *exception_object);
+    _Unwind_SjLj_RaiseException(_Unwind_Exception *exception_object);
+extern void _Unwind_SjLj_Resume(_Unwind_Exception *exception_object);
 #else
 extern _Unwind_Reason_Code
-    _Unwind_RaiseException(struct _Unwind_Exception *exception_object);
-extern void _Unwind_Resume(struct _Unwind_Exception *exception_object);
+    _Unwind_RaiseException(_Unwind_Exception *exception_object);
+extern void _Unwind_Resume(_Unwind_Exception *exception_object);
 #endif
-extern void _Unwind_DeleteException(struct _Unwind_Exception *exception_object);
+extern void _Unwind_DeleteException(_Unwind_Exception *exception_object);
+
+#if LIBCXXABI_ARM_EHABI
+typedef enum {
+  _UVRSC_CORE = 0,
+  _UVRSC_VFP = 1,
+  _UVRSC_WMMXD = 3,
+  _UVRSC_WMMXC = 4
+} _Unwind_VRS_RegClass;
+
+typedef enum {
+  _UVRSD_UINT32 = 0,
+  _UVRSD_VFPX = 1,
+  _UVRSD_UINT64 = 3,
+  _UVRSD_FLOAT = 4,
+  _UVRSD_DOUBLE = 5
+} _Unwind_VRS_DataRepresentation;
+
+typedef enum {
+  _UVRSR_OK = 0,
+  _UVRSR_NOT_IMPLEMENTED = 1,
+  _UVRSR_FAILED = 2
+} _Unwind_VRS_Result;
+
+extern _Unwind_VRS_Result _Unwind_VRS_Get(_Unwind_Context* context,
+                                          _Unwind_VRS_RegClass regclass,
+                                          uint32_t regno,
+                                          _Unwind_VRS_DataRepresentation representation,
+                                          void *valuep);
+
+extern _Unwind_VRS_Result _Unwind_VRS_Set(_Unwind_Context* context,
+                                          _Unwind_VRS_RegClass regclass,
+                                          uint32_t regno,
+                                          _Unwind_VRS_DataRepresentation representation,
+                                          void *valuep);
+
+static inline uintptr_t _Unwind_GetGR(struct _Unwind_Context* context,
+                                      int index) {
+  uintptr_t value = 0;
+  _Unwind_VRS_Get(context, _UVRSC_CORE, (uint32_t)index, _UVRSD_UINT32, &value);
+  return value;
+}
+
+static inline void _Unwind_SetGR(struct _Unwind_Context* context, int index,
+                                 uintptr_t new_value) {
+  _Unwind_VRS_Set(context, _UVRSC_CORE, (uint32_t)index,
+                  _UVRSD_UINT32, &new_value);
+}
+
+static inline uintptr_t _Unwind_GetIP(struct _Unwind_Context* context) {
+  // remove the thumb-bit before returning
+  return (_Unwind_GetGR(context, 15) & (~(uintptr_t)0x1));
+}
+
+static inline void _Unwind_SetIP(struct _Unwind_Context* context,
+                                 uintptr_t new_value) {
+  uintptr_t thumb_bit = _Unwind_GetGR(context, 15) & ((uintptr_t)0x1);
+  _Unwind_SetGR(context, 15, new_value | thumb_bit);
+}
+#else
 extern uintptr_t _Unwind_GetGR(struct _Unwind_Context *context, int index);
 extern void _Unwind_SetGR(struct _Unwind_Context *context, int index,
                           uintptr_t new_value);
 extern uintptr_t _Unwind_GetIP(struct _Unwind_Context *context);
 extern void _Unwind_SetIP(struct _Unwind_Context *, uintptr_t new_value);
+#endif
+
 extern uintptr_t _Unwind_GetRegionStart(struct _Unwind_Context *context);
 extern uintptr_t
     _Unwind_GetLanguageSpecificData(struct _Unwind_Context *context);
-#if __arm__
+#if __USING_SJLJ_EXCEPTIONS__
 extern _Unwind_Reason_Code
-    _Unwind_SjLj_ForcedUnwind(struct _Unwind_Exception *exception_object,
+    _Unwind_SjLj_ForcedUnwind(_Unwind_Exception *exception_object,
                               _Unwind_Stop_Fn stop, void *stop_parameter);
 #else
 extern _Unwind_Reason_Code
-    _Unwind_ForcedUnwind(struct _Unwind_Exception *exception_object,
+    _Unwind_ForcedUnwind(_Unwind_Exception *exception_object,
                          _Unwind_Stop_Fn stop, void *stop_parameter);
 #endif
 
-#if __arm__
+#if __USING_SJLJ_EXCEPTIONS__
 typedef struct _Unwind_FunctionContext *_Unwind_FunctionContext_t;
 extern void _Unwind_SjLj_Register(_Unwind_FunctionContext_t fc);
 extern void _Unwind_SjLj_Unregister(_Unwind_FunctionContext_t fc);
@@ -124,12 +248,12 @@
 //
 //  called by __cxa_rethrow().
 //
-#if __arm__
+#if __USING_SJLJ_EXCEPTIONS__
 extern _Unwind_Reason_Code
-    _Unwind_SjLj_Resume_or_Rethrow(struct _Unwind_Exception *exception_object);
+    _Unwind_SjLj_Resume_or_Rethrow(_Unwind_Exception *exception_object);
 #else
 extern _Unwind_Reason_Code
-    _Unwind_Resume_or_Rethrow(struct _Unwind_Exception *exception_object);
+    _Unwind_Resume_or_Rethrow(_Unwind_Exception *exception_object);
 #endif
 
 // _Unwind_Backtrace() is a gcc extension that walks the stack and calls the
Index: src/cxa_demangle.cpp
===================================================================
--- src/cxa_demangle.cpp
+++ src/cxa_demangle.cpp
@@ -155,7 +155,11 @@
 template <>
 struct float_data<long double>
 {
+#if defined(__arm__)
+    static const size_t mangled_size = 16;
+#else
     static const size_t mangled_size = 20;  // May need to be adjusted to 16 or 24 on other platforms
+#endif
     static const size_t max_demangled_size = 40;
     static constexpr const char* spec = "%LaL";
 };
Index: src/cxa_exception.cpp
===================================================================
--- src/cxa_exception.cpp
+++ src/cxa_exception.cpp
@@ -254,11 +254,101 @@
 void*
 __cxa_get_exception_ptr(void* unwind_exception) throw()
 {
+#if LIBCXXABI_ARM_EHABI
+    return reinterpret_cast<void*>(
+           static_cast<_Unwind_Control_Block*>(unwind_exception)->barrier_cache.bitpattern[0]);
+#else
     return cxa_exception_from_exception_unwind_exception
            (
                static_cast<_Unwind_Exception*>(unwind_exception)
            )->adjustedPtr;
+#endif
+}
+
+#if LIBCXXABI_ARM_EHABI
+/*
+The routine to be called before the cleanup.  This will save __cxa_exception in
+__cxa_eh_globals, so that __cxa_end_cleanup() can recover later.
+*/
+bool
+__cxa_begin_cleanup(void* unwind_arg) throw ()
+{
+    _Unwind_Exception* unwind_exception = static_cast<_Unwind_Exception*>(unwind_arg);
+    __cxa_eh_globals* globals = __cxa_get_globals();
+    __cxa_exception* exception_header =
+        cxa_exception_from_exception_unwind_exception(unwind_exception);
+
+    if (isOurExceptionClass(unwind_exception))
+    {
+        if (0 == exception_header->propagationCount)
+        {
+            exception_header->nextPropagatingException = globals->propagatingExceptions;
+            globals->propagatingExceptions = exception_header;
+        }
+        ++exception_header->propagationCount;
+    }
+    else
+    {
+        // If the propagatingExceptions stack is not empty, since we can't
+        // chain the foreign exception, terminate it.
+        if (NULL != globals->propagatingExceptions)
+            std::terminate();
+        globals->propagatingExceptions = exception_header;
+    }
+    return true;
+}
+
+/*
+The routine to be called after the cleanup has been performed.  It will get the
+propagating __cxa_exception from __cxa_eh_globals, and continue the stack
+unwinding with _Unwind_Resume.
+
+According to ARM EHABI 8.4.1, __cxa_end_cleanup() should not clobber any
+registers, thus we have to write this function in assembly so that we can
+save {r1-r3}.  Besides, in order to make sure that the stack is aligned to
+16 bytes, we are saving r4 as well, even though it is callee-save register.
+*/
+__attribute__((visibility("hidden"))) _Unwind_Exception *
+__cxa_end_cleanup_impl()
+{
+    __cxa_eh_globals* globals = __cxa_get_globals();
+    __cxa_exception* exception_header = globals->propagatingExceptions;
+    if (NULL == exception_header)
+    {
+        // It seems that __cxa_begin_cleanup() is not called properly.
+        // We have no choice but terminate the program now.
+        std::terminate();
+    }
+
+    if (isOurExceptionClass(&exception_header->unwindHeader))
+    {
+        --exception_header->propagationCount;
+        if (0 == exception_header->propagationCount)
+        {
+            globals->propagatingExceptions = exception_header->nextPropagatingException;
+            exception_header->nextPropagatingException = NULL;
+        }
+    }
+    else
+    {
+        globals->propagatingExceptions = NULL;
+    }
+    return &exception_header->unwindHeader;
 }
+
+asm (
+    "	.pushsection	.text.__cxa_end_cleanup\n"
+    "	.globl	__cxa_end_cleanup\n"
+    "	.type	__cxa_end_cleanup,%function\n"
+    "__cxa_end_cleanup:\n"
+    "	push	{r1, r2, r3, r4}\n"
+    "	bl	__cxa_end_cleanup_impl\n"
+    "	pop	{r1, r2, r3, r4}\n"
+    "	bl	_Unwind_Resume\n"
+    "	bl	abort\n"
+    "	.popsection"
+);
+#endif  // LIBCXXABI_ARM_EHABI
     
 /*
 This routine can catch foreign or native exceptions.  If native, the exception
@@ -318,7 +408,11 @@
             globals->caughtExceptions = exception_header;
         }
         globals->uncaughtExceptions -= 1;   // Not atomically, since globals are thread-local
+#if LIBCXXABI_ARM_EHABI
+        return reinterpret_cast<void*>(exception_header->unwindHeader.barrier_cache.bitpattern[0]);
+#else
         return exception_header->adjustedPtr;
+#endif
     }
     // Else this is a foreign exception
     // If the caughtExceptions stack is not empty, terminate
Index: src/cxa_exception.hpp
===================================================================
--- src/cxa_exception.hpp
+++ src/cxa_exception.hpp
@@ -27,7 +27,7 @@
 static const uint64_t get_vendor_and_language =     0xFFFFFFFFFFFFFF00; // mask for CLNGC++
                                                     
 struct __cxa_exception { 
-#if __LP64__
+#if __LP64__ || LIBCXXABI_ARM_EHABI
     // This is a new field to support C++ 0x exception_ptr.
     // For binary compatibility it is at the start of this
     // struct which is prepended to the object thrown in
@@ -45,7 +45,7 @@
 
     int handlerCount;
 
-#ifdef __ARM_EABI_UNWINDER__
+#if LIBCXXABI_ARM_EHABI
     __cxa_exception* nextPropagatingException;
     int propagationCount;
 #else
@@ -56,7 +56,7 @@
     void *adjustedPtr;
 #endif
 
-#if !__LP64__
+#if !__LP64__ && !LIBCXXABI_ARM_EHABI
     // This is a new field to support C++ 0x exception_ptr.
     // For binary compatibility it is placed where the compiler
     // previously adding padded to 64-bit align unwindHeader.
@@ -82,7 +82,7 @@
 
     int handlerCount;
     
-#ifdef __ARM_EABI_UNWINDER__
+#if LIBCXXABI_ARM_EHABI
     __cxa_exception* nextPropagatingException;
     int propagationCount;
 #else
@@ -103,7 +103,7 @@
 struct __cxa_eh_globals {
     __cxa_exception *   caughtExceptions;
     unsigned int        uncaughtExceptions;
-#ifdef __ARM_EABI_UNWINDER__
+#if LIBCXXABI_ARM_EHABI
     __cxa_exception* propagatingExceptions;
 #endif
 };
Index: src/cxa_personality.cpp
===================================================================
--- src/cxa_personality.cpp
+++ src/cxa_personality.cpp
@@ -307,6 +307,29 @@
     std::terminate();
 }
 
+#if LIBCXXABI_ARM_EHABI
+static const void* read_target2_value(const void* ptr)
+{
+    uintptr_t offset = *reinterpret_cast<const uintptr_t*>(ptr);
+    if (!offset)
+        return 0;
+    return *reinterpret_cast<const void**>(reinterpret_cast<uintptr_t>(ptr) + offset);
+}
+
+static const __shim_type_info*
+get_shim_type_info(uint64_t ttypeIndex, const uint8_t* classInfo,
+                   uint8_t /* ttypeEncoding */, bool native_exception,
+                   _Unwind_Exception* unwind_exception)
+{
+    if (classInfo == 0)
+    {
+        // this should not happen.  Indicates corrupted eh_table.
+        call_terminate(native_exception, unwind_exception);
+    }
+    const uint8_t* ttypePtr = classInfo - ttypeIndex * sizeof(uintptr_t);
+    return reinterpret_cast<const __shim_type_info*>(read_target2_value(ttypePtr));
+}
+#else
 static
 const __shim_type_info*
 get_shim_type_info(uint64_t ttypeIndex, const uint8_t* classInfo,
@@ -342,6 +365,7 @@
     classInfo -= ttypeIndex;
     return (const __shim_type_info*)readEncodedPointer(&classInfo, ttypeEncoding);
 }
+#endif
 
 /*
     This is checking a thrown exception type, excpType, against a possibly empty
@@ -352,6 +376,34 @@
     the list will catch a excpType.  If any catchType in the list can catch an
     excpType, then this exception spec does not catch the excpType.
 */
+#if LIBCXXABI_ARM_EHABI
+static
+bool
+exception_spec_can_catch(int64_t specIndex, const uint8_t* classInfo,
+                         uint8_t /*ttypeEncoding*/, const __shim_type_info* excpType,
+                         void* adjustedPtr, _Unwind_Exception* unwind_exception)
+{
+    if (classInfo == 0)
+    {
+        // this should not happen.   Indicates corrupted eh_table.
+        call_terminate(false, unwind_exception);
+    }
+    // specIndex is negative of 1-based byte offset into classInfo;
+    uintptr_t table = reinterpret_cast<uintptr_t>(classInfo) +
+                      static_cast<uintptr_t>(-specIndex - 1) * sizeof(uintptr_t);
+    // If any type in the spec list can catch excpType, return false, else return true
+    //    adjustments to adjustedPtr are ignored.
+    for (const void** ttypePtr = reinterpret_cast<const void**>(table); *ttypePtr; ++ttypePtr)
+    {
+        const __shim_type_info* catchType =
+            static_cast<const __shim_type_info*>(read_target2_value(ttypePtr));
+        void* tempPtr = adjustedPtr;
+        if (catchType->can_catch(excpType, tempPtr))
+            return false;
+    }
+    return true;
+}
+#else
 static
 bool
 exception_spec_can_catch(int64_t specIndex, const uint8_t* classInfo,
@@ -385,6 +437,7 @@
     }
     return true;
 }
+#endif
 
 static
 void*
@@ -511,7 +564,7 @@
     // Get beginning current frame's code (as defined by the 
     // emitted dwarf code)
     uintptr_t funcStart = _Unwind_GetRegionStart(context);
-#if __arm__
+#if __USING_SJLJ_EXCEPTIONS__
     if (ip == uintptr_t(-1))
     {
         // no action
@@ -544,7 +597,7 @@
     // Walk call-site table looking for range that 
     // includes current PC. 
     uint8_t callSiteEncoding = *lsda++;
-#if __arm__
+#if __USING_SJLJ_EXCEPTIONS__
     (void)callSiteEncoding;  // On arm callSiteEncoding is never used
 #endif
     uint32_t callSiteTableLength = static_cast<uint32_t>(readULEB128(&lsda));
@@ -555,7 +608,7 @@
     while (callSitePtr < callSiteTableEnd)
     {
         // There is one entry per call site.
-#if !__arm__
+#if !__USING_SJLJ_EXCEPTIONS__
         // The call sites are non-overlapping in [start, start+length)
         // The call sites are ordered in increasing value of start
         uintptr_t start = readEncodedPointer(&callSitePtr, callSiteEncoding);
@@ -563,15 +616,15 @@
         uintptr_t landingPad = readEncodedPointer(&callSitePtr, callSiteEncoding);
         uintptr_t actionEntry = readULEB128(&callSitePtr);
         if ((start <= ipOffset) && (ipOffset < (start + length)))
-#else  // __arm__
+#else  // __USING_SJLJ_EXCEPTIONS__
         // ip is 1-based index into this table
         uintptr_t landingPad = readULEB128(&callSitePtr);
         uintptr_t actionEntry = readULEB128(&callSitePtr);
         if (--ip == 0)
-#endif  // __arm__
+#endif  // __USING_SJLJ_EXCEPTIONS__
         {
             // Found the call site containing ip.
-#if !__arm__
+#if !__USING_SJLJ_EXCEPTIONS__
             if (landingPad == 0)
             {
                 // No handler here
@@ -579,9 +632,9 @@
                 return;
             }
             landingPad = (uintptr_t)lpStart + landingPad;
-#else  // __arm__
+#else  // __USING_SJLJ_EXCEPTIONS__
             ++landingPad;
-#endif  // __arm__
+#endif  // __USING_SJLJ_EXCEPTIONS__
             if (actionEntry == 0)
             {
                 // Found a cleanup
@@ -656,7 +709,7 @@
                             // If this is a type 1 search save state and return _URC_HANDLER_FOUND
                             // If this is a type 3 search and !_UA_FORCE_UNWIND, we should have found this in phase 1!
                             // If this is a type 3 search and _UA_FORCE_UNWIND, ignore handler and continue scan
-                            if (actions & _UA_SEARCH_PHASE)
+                            if ((actions & _UA_SEARCH_PHASE) || (actions & _UA_HANDLER_FRAME))
                             {
                                 // Save state and return _URC_HANDLER_FOUND
                                 results.ttypeIndex = ttypeIndex;
@@ -700,7 +753,7 @@
                             // If this is a type 1 search, save state and return _URC_HANDLER_FOUND
                             // If this is a type 3 search !_UA_FORCE_UNWIND, we should have found this in phase 1!
                             // If this is a type 3 search _UA_FORCE_UNWIND, ignore handler and continue scan
-                            if (actions & _UA_SEARCH_PHASE)
+                            if ((actions & _UA_SEARCH_PHASE) || (actions & _UA_HANDLER_FRAME))
                             {
                                 // Save state and return _URC_HANDLER_FOUND
                                 results.ttypeIndex = ttypeIndex;
@@ -773,7 +826,7 @@
                 action += actionOffset;
             }  // there is no break out of this loop, only return
         }
-#if !__arm__
+#if !__USING_SJLJ_EXCEPTIONS__
         else if (ipOffset < start)
         {
             // There is no call site for this ip
@@ -781,7 +834,7 @@
             // Possible stack corruption.
             call_terminate(native_exception, unwind_exception);
         }
-#endif  // !__arm__
+#endif  // !__USING_SJLJ_EXCEPTIONS__
     }  // there might be some tricky cases which break out of this loop
 
     // It is possible that no eh table entry specify how to handle
@@ -837,6 +890,7 @@
         Else a cleanup is not found: return _URC_CONTINUE_UNWIND
 */
 
+#if !LIBCXXABI_ARM_EHABI
 _Unwind_Reason_Code
 #if __USING_SJLJ_EXCEPTIONS__
 __gxx_personality_sj0
@@ -848,6 +902,7 @@
 {
     if (version != 1 || unwind_exception == 0 || context == 0)
         return _URC_FATAL_PHASE1_ERROR;
+
     bool native_exception = (exceptionClass     & get_vendor_and_language) ==
                             (kOurExceptionClass & get_vendor_and_language);
     scan_results results;
@@ -924,6 +979,131 @@
     // We were called improperly: neither a phase 1 or phase 2 search
     return _URC_FATAL_PHASE1_ERROR;
 }
+#else
+
+extern "C" _Unwind_Reason_Code __gnu_unwind_frame(_Unwind_Exception*, _Unwind_Context*);
+
+// Helper function to unwind one frame.
+// ARM EHABI 7.3 and 7.4: If the personality function returns _URC_CONTINUE_UNWIND, the
+// personality routine should update the virtual register set (VRS) according to the
+// corresponding frame unwinding instructions (ARM EHABI 9.3.)
+static _Unwind_Reason_Code continue_unwind(_Unwind_Exception* unwind_exception,
+                                           _Unwind_Context* context)
+{
+    if (__gnu_unwind_frame(unwind_exception, context) != _URC_OK)
+        return _URC_FAILURE;
+    return _URC_CONTINUE_UNWIND;
+}
+
+// ARM register names
+static const uint32_t REG_UCB = 12;  // Register to save _Unwind_Control_Block
+static const uint32_t REG_SP = 13;
+
+static void save_results_to_barrier_cache(_Unwind_Exception* unwind_exception,
+                                          const scan_results& results)
+{
+    unwind_exception->barrier_cache.bitpattern[0] = (uint32_t)results.adjustedPtr;
+    unwind_exception->barrier_cache.bitpattern[1] = (uint32_t)results.actionRecord;
+    unwind_exception->barrier_cache.bitpattern[2] = (uint32_t)results.languageSpecificData;
+    unwind_exception->barrier_cache.bitpattern[3] = (uint32_t)results.landingPad;
+    unwind_exception->barrier_cache.bitpattern[4] = (uint32_t)results.ttypeIndex;
+}
+
+#if 0
+static void load_results_from_barrier_cache(scan_results& results,
+                                            const _Unwind_Exception* unwind_exception)
+{
+    results.adjustedPtr = (void*)unwind_exception->barrier_cache.bitpattern[0];
+    results.actionRecord = (const uint8_t*)unwind_exception->barrier_cache.bitpattern[1];
+    results.languageSpecificData = (const uint8_t*)unwind_exception->barrier_cache.bitpattern[2];
+    results.landingPad = (uintptr_t)unwind_exception->barrier_cache.bitpattern[3];
+    results.ttypeIndex = (int64_t)(int32_t)unwind_exception->barrier_cache.bitpattern[4];
+}
+#endif
+
+extern "C" _Unwind_Reason_Code
+__gxx_personality_v0(_Unwind_State state,
+                     _Unwind_Exception* unwind_exception,
+                     _Unwind_Context* context)
+{
+    if (unwind_exception == 0 || context == 0)
+        return _URC_FATAL_PHASE1_ERROR;
+
+    bool native_exception = (unwind_exception->exception_class & get_vendor_and_language) ==
+                            (kOurExceptionClass & get_vendor_and_language);
+
+    // Copy the address of _Unwind_Control_Block to r12 so that _Unwind_GetLangauageSpecificData()
+    // and _Unwind_GetRegionStart() can return correct address.
+    _Unwind_SetGR(context, REG_UCB, reinterpret_cast<uint32_t>(unwind_exception));
+
+    scan_results results;
+    switch (state) {
+    case _US_VIRTUAL_UNWIND_FRAME:
+        // Phase 1 search:  All we're looking for in phase 1 is a handler that halts unwinding
+        scan_eh_tab(results, _UA_SEARCH_PHASE, native_exception, unwind_exception, context);
+        if (results.reason == _URC_HANDLER_FOUND)
+        {
+            unwind_exception->barrier_cache.sp = _Unwind_GetGR(context, REG_SP);
+            if (native_exception)
+                save_results_to_barrier_cache(unwind_exception, results);
+            return _URC_HANDLER_FOUND;
+        }
+        // Did not find the catch handler
+        if (results.reason == _URC_CONTINUE_UNWIND)
+            return continue_unwind(unwind_exception, context);
+        return results.reason;
+
+    case _US_UNWIND_FRAME_STARTING:
+        // Phase 2 search
+        if (unwind_exception->barrier_cache.sp == _Unwind_GetGR(context, REG_SP))
+        {
+            // Found a catching handler in phase 1
+
+            // TODO: Load the phase 1 result from unwind_exception if this is a native exception.
+            // load_results_from_barrier_cache(results, unwind_exception);
+            // results.reason = _URC_HANDLER_FOUND;
+
+            // Search for the catching handler again
+            scan_eh_tab(results, static_cast<_Unwind_Action>(_UA_CLEANUP_PHASE | _UA_HANDLER_FRAME),
+                        native_exception, unwind_exception, context);
+            if (results.reason != _URC_HANDLER_FOUND)  // phase1 search should guarantee to find one
+                call_terminate(native_exception, unwind_exception);
+
+            // Install the context for the catching handler
+            set_registers(unwind_exception, context, results);
+            return _URC_INSTALL_CONTEXT;
+        }
+
+        // Search for a (non-catching) cleanup
+        scan_eh_tab(results, _UA_CLEANUP_PHASE, native_exception, unwind_exception, context);
+        if (results.reason == _URC_HANDLER_FOUND)
+        {
+            // Found a non-catching handler
+
+            // ARM EHABI 8.4.2: Before we can jump to the cleanup handler, we have to setup some
+            // internal data structures, so that __cxa_end_cleanup() can get unwind_exception from
+            // __cxa_get_globals().
+            __cxa_begin_cleanup(unwind_exception);
+
+            // Install the context for the cleanup handler
+            set_registers(unwind_exception, context, results);
+            return _URC_INSTALL_CONTEXT;
+        }
+
+        // Did not find any handler
+        if (results.reason == _URC_CONTINUE_UNWIND)
+            return continue_unwind(unwind_exception, context);
+        return results.reason;
+
+    case _US_UNWIND_FRAME_RESUME:
+        return continue_unwind(unwind_exception, context);
+    }
+
+    // We were called improperly: neither a phase 1 or phase 2 search
+    return _URC_FATAL_PHASE1_ERROR;
+}
+#endif
+
 
 __attribute__((noreturn))
 void
@@ -948,8 +1128,13 @@
         u_handler = old_exception_header->unexpectedHandler;
         // If std::__unexpected(u_handler) rethrows the same exception,
         //   these values get overwritten by the rethrow.  So save them now:
+#if LIBCXXABI_ARM_EHABI
+        ttypeIndex = (int64_t)(int32_t)unwind_exception->barrier_cache.bitpattern[4];
+        lsda = (const uint8_t*)unwind_exception->barrier_cache.bitpattern[2];
+#else
         ttypeIndex = old_exception_header->handlerSwitchValue;
         lsda = old_exception_header->languageSpecificData;
+#endif
     }
     else
     {
Index: test/test_demangle.cpp
===================================================================
--- test/test_demangle.cpp
+++ test/test_demangle.cpp
@@ -29513,7 +29513,10 @@
     {"_ZN5test01fIiEEvT_RAszcl3ovlcvS1__EE_c", "void test0::f<int>(int, char (&) [sizeof (ovl((int)()))])"},
     {"_ZN5test01gIfEEvRAszplcvT__ELf40a00000E_c", "void test0::g<float>(char (&) [sizeof (((float)()) + (0x1.4p+2f))])"},
     {"_ZN5test01hIfEEvRAszplcvT__ELd4014000000000000E_c", "void test0::h<float>(char (&) [sizeof (((float)()) + (0x1.4p+2))])"},
+#if !defined(__arm__)
+    // This case assumes 80-bit long double.
     {"_ZN5test01hIfEEvRAcvjplstT_Le4001a000000000000000E_c", "void test0::h<float>(char (&) [(unsigned int)((sizeof (float)) + (0xap-1L))])"},
+#endif
     {"_ZN5test01jINS_1AEEEvRAszdtcvT__E6buffer_c", "void test0::j<test0::A>(char (&) [sizeof ((test0::A)().buffer)])"},
     {"_ZN5test11fINS_1XEiEEvT_IT0_E", "void test1::f<test1::X, int>(test1::X<int>)"},
     {"_ZN5test211read_memberINS_1AEEEDtptcvPT_Li0E6memberERS2_", "decltype((test2::A*)(0)->member) test2::read_member<test2::A>(test2::A&)"},
@@ -29597,6 +29600,10 @@
     "NSoERj5E=Y1[uM:ga",
     "Aon_PmKVPDk7?fg4XP5smMUL6;<WsI_mgbf23cCgsHbT<l8EE\0uVRkNOoXDrgdA4[8IU>Vl<>IL8ayHpiVDDDXTY;^o9;i",
     "_ZNSt16allocator_traitsISaIN4llvm3sys2fs18directory_iteratorEEE9constructIS3_IS3_EEEDTcl12_S_constructfp_fp0_spcl7forwardIT0_Efp1_EEERS4_PT_DpOS7_",
+#if defined(__arm__)
+    // Since ARM does not have 80-bit long double, this should fail.
+    "_ZN5test01hIfEEvRAcvjplstT_Le4001a000000000000000E_c",
+#endif
 };
 
 const unsigned NI = sizeof(invalid_cases) / sizeof(invalid_cases[0]);
_______________________________________________
cfe-commits mailing list
[email protected]
http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits

Reply via email to