summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorDavid Chisnall <dchisnall@pathscale.com>2012-03-20 16:56:14 +0000
committerDavid Chisnall <dchisnall@pathscale.com>2012-03-20 16:56:14 +0000
commitcddcf8734ed06ada9384a461bc21d58b44f6eba1 (patch)
tree05f0ee42205622cb4851edc2dcce576708f68739 /src
parenta35d8de85ffd4df32e2dc47fa539d61fd3024a54 (diff)
downloadlibcxxrt-cddcf8734ed06ada9384a461bc21d58b44f6eba1.tar.gz
libcxxrt-cddcf8734ed06ada9384a461bc21d58b44f6eba1.tar.bz2
libcxxrt-cddcf8734ed06ada9384a461bc21d58b44f6eba1.tar.xz
Rework exception matching.
- Remove typeinfo since thing break if the compiler decides to use the system one and merge its contents into typeinfo.h - Make each type_info object have a vtable with the same layout as the public vtable in libstdc++'s <typeinfo>. This fixes code (e.g. libobjc2's Objective-C++ exception handling) which rely on being able to add new types. - Add some extra tests I suspect exceptions catching pointer-to-member types will not work correctly, but I've never seen anyone do this and don't have any tests for it.
Diffstat (limited to 'src')
-rw-r--r--src/dynamic_cast.cc107
-rw-r--r--src/exception.cc47
-rw-r--r--src/typeinfo26
-rw-r--r--src/typeinfo.h107
4 files changed, 182 insertions, 105 deletions
diff --git a/src/dynamic_cast.cc b/src/dynamic_cast.cc
index c81ad01..7a07e4c 100644
--- a/src/dynamic_cast.cc
+++ b/src/dynamic_cast.cc
@@ -46,9 +46,65 @@ struct vtable_header
*/
#define ADD_TO_PTR(x, off) (__typeof__(x))(((char*)x) + off)
-bool __class_type_info::can_cast_to(const struct __class_type_info *other) const
+bool std::type_info::__do_catch(std::type_info const *ex_type,
+ void **exception_object,
+ unsigned int outer) const
{
- return this == other;
+ const type_info *type = this;
+
+ if (type == ex_type)
+ {
+ return true;
+ }
+ if (const __class_type_info *cti = dynamic_cast<const __class_type_info *>(type))
+ {
+ return ex_type->__do_upcast(cti, exception_object);
+ }
+ return false;
+}
+
+bool __pbase_type_info::__do_catch(std::type_info const *ex_type,
+ void **exception_object,
+ unsigned int outer) const
+{
+ if (ex_type == this)
+ {
+ return true;
+ }
+ if (!ex_type->__is_pointer_p())
+ {
+ // Can't catch a non-pointer type in a pointer catch
+ return false;
+ }
+
+ if (!(outer & 1))
+ {
+ // If the low bit is cleared on this means that we've gone
+ // through a pointer that is not const qualified.
+ return false;
+ }
+ // Clear the low bit on outer if we're not const qualified.
+ if (!(__flags & __const_mask))
+ {
+ outer &= ~1;
+ }
+
+ const __pbase_type_info *ptr_type =
+ static_cast<const __pbase_type_info*>(ex_type);
+
+ if (ptr_type->__flags & ~__flags)
+ {
+ // Handler pointer is less qualified
+ return false;
+ }
+
+ // Special case for void* handler.
+ if(*__pointee == typeid(void))
+ {
+ return true;
+ }
+
+ return __pointee->__do_catch(ptr_type->__pointee, exception_object, outer);
}
void *__class_type_info::cast_to(void *obj, const struct __class_type_info *other) const
@@ -60,12 +116,6 @@ void *__class_type_info::cast_to(void *obj, const struct __class_type_info *othe
return 0;
}
-
-bool __si_class_type_info::can_cast_to(const struct __class_type_info *other) const
-{
- return this == other || __base_type->can_cast_to(other);
-}
-
void *__si_class_type_info::cast_to(void *obj, const struct __class_type_info *other) const
{
if (this == other)
@@ -74,31 +124,32 @@ void *__si_class_type_info::cast_to(void *obj, const struct __class_type_info *o
}
return __base_type->cast_to(obj, other);
}
-
-
-bool __vmi_class_type_info::can_cast_to(const struct __class_type_info *other) const
+bool __si_class_type_info::__do_upcast(const __class_type_info *target,
+ void **thrown_object) const
{
- if (this == other)
+ if (this == target)
{
return true;
}
- for (unsigned int i=0 ; i<__base_count ; i++)
- {
- const __base_class_type_info *info = &__base_info[i];
- if(info->isPublic() && info->__base_type->can_cast_to(other))
- {
- return true;
- }
- }
- return false;
+ return __base_type->__do_upcast(target, thrown_object);
}
void *__vmi_class_type_info::cast_to(void *obj, const struct __class_type_info *other) const
{
- if (this == other)
+ if (__do_upcast(other, &obj))
{
return obj;
}
+ return 0;
+}
+
+bool __vmi_class_type_info::__do_upcast(const __class_type_info *target,
+ void **thrown_object) const
+{
+ if (this == target)
+ {
+ return true;
+ }
for (unsigned int i=0 ; i<__base_count ; i++)
{
const __base_class_type_info *info = &__base_info[i];
@@ -111,6 +162,7 @@ void *__vmi_class_type_info::cast_to(void *obj, const struct __class_type_info *
// virtual table of the virtual base offset for the virtual base
// referenced (negative).'
+ void *obj = *thrown_object;
if (info->isVirtual())
{
// Object's vtable
@@ -121,18 +173,17 @@ void *__vmi_class_type_info::cast_to(void *obj, const struct __class_type_info *
}
void *cast = ADD_TO_PTR(obj, offset);
- if (info->__base_type == other)
+ if (info->__base_type == target ||
+ (info->__base_type->__do_upcast(target, &cast)))
{
- return cast;
- }
- if ((cast = info->__base_type->cast_to(cast, other)))
- {
- return cast;
+ *thrown_object = cast;
+ return true;
}
}
return 0;
}
+
/**
* ABI function used to implement the dynamic_cast<> operator. Some cases of
* this operator are implemented entirely in the compiler (e.g. to void*).
diff --git a/src/exception.cc b/src/exception.cc
index 8cbcb97..fe56297 100644
--- a/src/exception.cc
+++ b/src/exception.cc
@@ -847,14 +847,11 @@ static bool check_type_signature(__cxa_exception *ex,
const std::type_info *type,
void *&adjustedPtr)
{
- // TODO: For compatibility with the GNU implementation, we should move this
- // out into a __do_catch() virtual function in std::type_info
void *exception_ptr = (void*)(ex+1);
- const std::type_info *ex_type = ex->exceptionType;
+ const std::type_info *ex_type = ex->exceptionType;
- const __pointer_type_info *ptr_type =
- dynamic_cast<const __pointer_type_info*>(ex_type);
- if (0 != ptr_type)
+ bool is_ptr = ex_type->__is_pointer_p();
+ if (is_ptr)
{
exception_ptr = *(void**)exception_ptr;
}
@@ -862,11 +859,6 @@ static bool check_type_signature(__cxa_exception *ex,
//
// Note: A 0 here is a catchall, not a cleanup, so we return true to
// indicate that we found a catch.
- //
- // TODO: Provide a class for matching against foreign exceptions. This is
- // already done in libobjc2, allowing C++ exceptions to be boxed as
- // Objective-C objects. We should do something similar, allowing foreign
- // exceptions to be wrapped in a C++ exception and delivered.
if (0 == type)
{
if (ex)
@@ -878,28 +870,6 @@ static bool check_type_signature(__cxa_exception *ex,
if (0 == ex) { return false; }
- const __pointer_type_info *target_ptr_type =
- dynamic_cast<const __pointer_type_info*>(type);
-
- if (0 != ptr_type && 0 != target_ptr_type)
- {
- if (ptr_type->__flags & ~target_ptr_type->__flags)
- {
- // Handler pointer is less qualified
- return false;
- }
-
- // Special case for void* handler.
- if(*target_ptr_type->__pointee == typeid(void))
- {
- adjustedPtr = exception_ptr;
- return true;
- }
-
- ex_type = ptr_type->__pointee;
- type = target_ptr_type->__pointee;
- }
-
// If the types are the same, no casting is needed.
if (*type == *ex_type)
{
@@ -907,18 +877,13 @@ static bool check_type_signature(__cxa_exception *ex,
return true;
}
- const __class_type_info *cls_type =
- dynamic_cast<const __class_type_info*>(ex_type);
- const __class_type_info *target_cls_type =
- dynamic_cast<const __class_type_info*>(type);
- if (0 != cls_type &&
- 0 != target_cls_type &&
- cls_type->can_cast_to(target_cls_type))
+ if (type->__do_catch(ex_type, &exception_ptr, 1))
{
- adjustedPtr = cls_type->cast_to(exception_ptr, target_cls_type);
+ adjustedPtr = exception_ptr;
return true;
}
+
return false;
}
/**
diff --git a/src/typeinfo b/src/typeinfo
deleted file mode 100644
index 74e77ae..0000000
--- a/src/typeinfo
+++ /dev/null
@@ -1,26 +0,0 @@
-namespace std
-{
- /**
- * Standard type info class. The layout of this class is specified by the
- * ABI.
- */
- class type_info
- {
- public:
- /**
- * Virtual destructor. This class must have one virtual function to
- * ensure that it has a vtable.
- */
- virtual ~type_info();
- bool operator==(const type_info &) const;
- bool operator!=(const type_info &) const;
- bool before(const type_info &) const;
- const char* name() const;
- type_info();
- private:
- type_info(const type_info& rhs);
- type_info& operator= (const type_info& rhs);
- const char *__type_name;
- };
-}
-
diff --git a/src/typeinfo.h b/src/typeinfo.h
index e35f6c1..8223977 100644
--- a/src/typeinfo.h
+++ b/src/typeinfo.h
@@ -26,7 +26,86 @@
#include <stddef.h>
#include "abi_namespace.h"
-#include "typeinfo"
+
+namespace ABI_NAMESPACE
+{
+ struct __class_type_info;
+}
+namespace std
+{
+ /**
+ * Standard type info class. The layout of this class is specified by the
+ * ABI. The layout of the vtable is not, but is intended to be
+ * compatible with the GNU ABI.
+ *
+ * Unlike the GNU version, the vtable layout is considered semi-private.
+ */
+ class type_info
+ {
+ public:
+ /**
+ * Virtual destructor. This class must have one virtual function to
+ * ensure that it has a vtable.
+ */
+ virtual ~type_info();
+ bool operator==(const type_info &) const;
+ bool operator!=(const type_info &) const;
+ bool before(const type_info &) const;
+ const char* name() const;
+ type_info();
+ private:
+ type_info(const type_info& rhs);
+ type_info& operator= (const type_info& rhs);
+ const char *__type_name;
+ /*
+ * The following functions are in this order to match the
+ * vtable layout of libsupc++. This allows libcxxrt to be used
+ * with libraries that depend on this.
+ *
+ * These functions are in the public headers for libstdc++, so
+ * we have to assume that someone will probably call them and
+ * expect them to work. Their names must also match the names used in
+ * libsupc++, so that code linking against this library can subclass
+ * type_info and correctly fill in the values in the vtables.
+ */
+ public:
+ /**
+ * Catch function. Allows external libraries to implement
+ * their own basic types. This is used, for example, in the
+ * GNUstep Objective-C runtime to allow Objective-C types to be
+ * caught in G++ catch blocks.
+ *
+ * The outer parameter indicates the number of outer pointers
+ * in the high bits. The low bit indicates whether the
+ * pointers are const qualified.
+ */
+ virtual bool __do_catch(const type_info *thrown_type,
+ void **thrown_object,
+ unsigned outer) const;
+ /**
+ * Performs an upcast. This is used in exception handling to
+ * cast from subclasses to superclasses. If the upcast is
+ * possible, it returns true and adjusts the pointer. If the
+ * upcast is not possible, it returns false and does not adjust
+ * the pointer.
+ */
+ virtual bool __do_upcast(
+ const ABI_NAMESPACE::__class_type_info *target,
+ void **thrown_object) const
+ {
+ return false;
+ }
+ /**
+ * Returns true if this is some pointer type, false otherwise.
+ */
+ virtual bool __is_pointer_p() const { return false; }
+ /**
+ * Returns true if this is some function type, false otherwise.
+ */
+ virtual bool __is_function_p() const { return false; }
+ };
+}
+
namespace ABI_NAMESPACE
{
@@ -50,6 +129,7 @@ namespace ABI_NAMESPACE
struct __function_type_info : public std::type_info
{
virtual ~__function_type_info();
+ virtual bool __is_function_p() const { return true; }
};
/**
* Type info for enums.
@@ -68,13 +148,12 @@ namespace ABI_NAMESPACE
/**
* Function implementing dynamic casts.
*/
- virtual void *cast_to(void *obj,
- const struct __class_type_info *other) const;
- /**
- * Function returning whether a cast from this type to another type is
- * possible.
- */
- virtual bool can_cast_to(const struct __class_type_info *other) const;
+ virtual void *cast_to(void *obj, const struct __class_type_info *other) const;
+ virtual bool __do_upcast(const __class_type_info *target,
+ void **thrown_object) const
+ {
+ return this == target;
+ }
};
/**
@@ -85,8 +164,10 @@ namespace ABI_NAMESPACE
{
virtual ~__si_class_type_info();
const __class_type_info *__base_type;
+ virtual bool __do_upcast(
+ const ABI_NAMESPACE::__class_type_info *target,
+ void **thrown_object) const;
virtual void *cast_to(void *obj, const struct __class_type_info *other) const;
- virtual bool can_cast_to(const struct __class_type_info *other) const;
};
/**
@@ -166,8 +247,10 @@ namespace ABI_NAMESPACE
/** The class is diamond shaped. */
__diamond_shaped_mask = 0x2
};
+ virtual bool __do_upcast(
+ const ABI_NAMESPACE::__class_type_info *target,
+ void **thrown_object) const;
virtual void *cast_to(void *obj, const struct __class_type_info *other) const;
- virtual bool can_cast_to(const struct __class_type_info *other) const;
};
/**
@@ -201,6 +284,10 @@ namespace ABI_NAMESPACE
/** Pointer is a pointer to a member of an incomplete class. */
__incomplete_class_mask = 0x10
};
+ virtual bool __is_pointer_p() const { return true; }
+ virtual bool __do_catch(const type_info *thrown_type,
+ void **thrown_object,
+ unsigned outer) const;
};
/**