Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

MinGW: Use _Unwind_RaiseException to throw exceptions #278

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 2 additions & 4 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -124,9 +124,7 @@ set(libobjc_CXX_SRCS
# Windows does not use DWARF EH, except when using the GNU ABI (MinGW)
if (WIN32 AND NOT MINGW)
list(APPEND libobjc_CXX_SRCS eh_win32_msvc.cc)
elseif (MINGW)
list(APPEND libobjc_CXX_SRCS eh_win32_mingw.m)
else ()
elseif (NOT MINGW)
list(APPEND libobjc_C_SRCS eh_personality.c)
endif ()

Expand Down Expand Up @@ -230,7 +228,7 @@ if (WIN32 AND NOT MINGW)
message(STATUS "Using MSVC-compatible exception model")
elseif (MINGW)
message(STATUS "Using MinGW-compatible exception model")
list(APPEND libobjc_CXX_SRCS objcxx_eh.cc)
list(APPEND libobjc_CXX_SRCS objcxx_eh.cc objcxx_eh_mingw.cc)
else ()
separate_arguments(EH_PERSONALITY_FLAGS NATIVE_COMMAND ${CMAKE_CXX_FLAGS})
if (CMAKE_CXX_COMPILER_TARGET)
Expand Down
59 changes: 0 additions & 59 deletions eh_win32_mingw.m

This file was deleted.

261 changes: 22 additions & 239 deletions objcxx_eh.cc
Original file line number Diff line number Diff line change
@@ -1,19 +1,11 @@
typedef struct objc_object* id;
#include <atomic>
#include <stdlib.h>
#include <stdio.h>
#include "dwarf_eh.h"
#include "objcxx_eh_private.h"
#include "objcxx_eh.h"
#include "visibility.h"
#include "objc/runtime.h"
#include "objc/objc-arc.h"

#ifndef DEBUG_EXCEPTIONS
#define DEBUG_LOG(...)
#else
#define DEBUG_LOG(str, ...) fprintf(stderr, str, ## __VA_ARGS__)
#endif

/**
* Helper function that has a custom personality function.
* This calls `cxx_throw` and has a destructor that must be run. We intercept
Expand All @@ -23,92 +15,8 @@ int eh_trampoline();

uint64_t cxx_exception_class;

/**
* Our own definitions of C++ ABI functions and types. These are provided
* because this file must not include cxxabi.h. We need to handle subtly
* different variations of the ABI and including one specific implementation
* would make that very difficult.
*/
namespace __cxxabiv1
{
/**
* Type info for classes. Forward declared because the GNU ABI provides a
* method on all type_info objects that the dynamic the dynamic cast header
* needs.
*/
struct __class_type_info;
/**
* The C++ in-flight exception object. We will derive the offset of fields
* in this, so we do not ever actually see a concrete definition of it.
*/
struct __cxa_exception;
/**
* The public ABI structure for current exception state.
*/
struct __cxa_eh_globals
{
/**
* The current exception that has been caught.
*/
__cxa_exception *caughtExceptions;
/**
* The number of uncaught exceptions still in flight.
*/
unsigned int uncaughtExceptions;
};
/**
* Retrieve the above structure.
*/
extern "C" __cxa_eh_globals *__cxa_get_globals();
}

namespace std
{
struct type_info;
}

using namespace __cxxabiv1;

// Define some C++ ABI types here, rather than including them. This prevents
// conflicts with the libstdc++ headers, which expose only a subset of the
// type_info class (the part required for standards compliance, not the
// implementation details).

typedef void (*unexpected_handler)();
typedef void (*terminate_handler)();

namespace std
{
/**
* std::type_info, containing the minimum requirements for the ABI.
* Public headers on some implementations also expose some implementation
* details. The layout of our subclasses must respect the layout of the
* C++ runtime library, but also needs to be portable across multiple
* implementations and so should not depend on internal symbols from those
* libraries.
*/
class type_info
{
public:
virtual ~type_info();
bool operator==(const type_info &) const;
bool operator!=(const type_info &) const;
bool before(const type_info &) const;
type_info();
private:
type_info(const type_info& rhs);
type_info& operator= (const type_info& rhs);
const char *__type_name;
protected:
type_info(const char *name): __type_name(name) { }
public:
const char* name() const { return __type_name; }
};
}

extern "C" void __cxa_throw(void*, std::type_info*, void(*)(void*));
extern "C" void __cxa_rethrow();

namespace
{
/**
Expand Down Expand Up @@ -140,49 +48,6 @@ std::atomic<ptrdiff_t> type_info_offset;
*/
std::atomic<size_t> exception_struct_size;

/**
* Helper function to find a particular value scanning backwards in a
* structure.
*/
template<typename T>
ptrdiff_t find_backwards(void *addr, T val)
{
T *ptr = reinterpret_cast<T*>(addr);
for (ptrdiff_t disp = -1 ; (disp * sizeof(T) > -128) ; disp--)
{
if (ptr[disp] == val)
{
return disp * sizeof(T);
}
}
fprintf(stderr, "Unable to find field in C++ exception structure\n");
abort();
}

/**
* Helper function to find a particular value scanning forwards in a
* structure.
*/
template<typename T>
ptrdiff_t find_forwards(void *addr, T val)
{
T *ptr = reinterpret_cast<T*>(addr);
for (ptrdiff_t disp = 0 ; (disp * sizeof(T) < 256) ; disp++)
{
if (ptr[disp] == val)
{
return disp * sizeof(T);
}
}
fprintf(stderr, "Unable to find field in C++ exception structure\n");
abort();
}

template<typename T>
T *pointer_add(void *ptr, ptrdiff_t offset)
{
return reinterpret_cast<T*>(reinterpret_cast<char*>(ptr) + offset);
}

/**
* Exception cleanup function for C++ exceptions that wrap Objective-C
Expand Down Expand Up @@ -225,76 +90,33 @@ namespace gnustep
{
namespace libobjc
{
/**
* Superclass for the type info for Objective-C exceptions.
*/
struct OBJC_PUBLIC __objc_type_info : std::type_info
{
/**
* Constructor that sets the name.
*/
__objc_type_info(const char *name) : type_info(name) {}
/**
* Helper function used by libsupc++ and libcxxrt to determine if
* this is a pointer type. If so, catches automatically
* dereference the pointer to the thrown pointer in
* `__cxa_begin_catch`.
*/
virtual bool __is_pointer_p() const { return true; }
/**
* Helper function used by libsupc++ and libcxxrt to determine if
* this is a function pointer type. Irrelevant for our purposes.
*/
virtual bool __is_function_p() const { return false; }
/**
* Catch handler. This is used in the C++ personality function.
* `thrown_type` is the type info of the thrown object, `this` is
* the type info at the catch site. `thrown_object` is a pointer
* to a pointer to the thrown object and may be adjusted by this
* function.
*/
virtual bool __do_catch(const type_info *thrown_type,
__objc_type_info::__objc_type_info(const char *name) : type_info(name) {}

bool __objc_type_info::__is_pointer_p() const { return true; }

bool __objc_type_info::__is_function_p() const { return false; }

bool __objc_type_info::__do_catch(const type_info *thrown_type,
void **thrown_object,
unsigned) const
{
assert(0);
return false;
};
/**
* Function used for `dynamic_cast` between two C++ class types in
* libsupc++ and libcxxrt.
*
* This should never be called on Objective-C types.
*/
virtual bool __do_upcast(
{
assert(0);
return false;
};

bool __objc_type_info::__do_upcast(
const __class_type_info *target,
void **thrown_object) const
{
return false;
};
{
return false;
};


/**
* Singleton type info for the `id` type.
* The `id` type is mangled to `@id`, which is not a valid mangling
* of anything else.
*/
struct OBJC_PUBLIC __objc_id_type_info : __objc_type_info
{
/**
* The `id` type is mangled to `@id`, which is not a valid mangling
* of anything else.
*/
__objc_id_type_info() : __objc_type_info("@id") {};
virtual ~__objc_id_type_info();
virtual bool __do_catch(const type_info *thrownType,
void **obj,
unsigned outer) const;
};
struct OBJC_PUBLIC __objc_class_type_info : __objc_type_info
{
virtual ~__objc_class_type_info();
virtual bool __do_catch(const type_info *thrownType,
void **obj,
unsigned outer) const;
};
__objc_id_type_info::__objc_id_type_info() : __objc_type_info("@id") {};
}

static inline id dereference_thrown_object_pointer(void** obj) {
Expand Down Expand Up @@ -430,29 +252,7 @@ void* objc_object_for_cxx_exception(void *thrown_exception, int *isValid)
} // extern "C"


/**
* C++ structure that is thrown through a frame with the `test_eh_personality`
* personality function. This contains a well-known value that we can search
* for after the unwind header.
*/
struct
PRIVATE
MagicValueHolder
{
/**
* The constant that we will search for to identify this object.
*/
static constexpr uint32_t magic = 0x01020304;
/**
* The single field in this structure.
*/
uint32_t magic_value;
/**
* Constructor. Initialises the field with the magic constant.
*/
MagicValueHolder() { magic_value = magic; }
};

MagicValueHolder::MagicValueHolder() { magic_value = magic; }

/**
* Function that simply throws an instance of `MagicValueHolder`.
Expand Down Expand Up @@ -508,21 +308,4 @@ extern "C" void test_cxx_eh_implementation()
}
assert(caught);
}
#else
static void eh_cleanup(void *exception)
{
DEBUG_LOG("eh_cleanup: Releasing 0x%x\n", *(id*)exception);
objc_release(*(id*)exception);
}

extern "C"
OBJC_PUBLIC
void objc_exception_throw(id object)
{
id *exc = (id *)__cxa_allocate_exception(sizeof(id));
*exc = object;
objc_retain(object);
DEBUG_LOG("objc_exception_throw: Throwing 0x%x\n", *exc);
__cxa_throw(exc, & __objc_id_type_info, eh_cleanup);
}
#endif
Loading
Loading