diff --git a/acinclude.m4 b/acinclude.m4 new file mode 100644 index 0000000..6a0bbc4 --- /dev/null +++ b/acinclude.m4 @@ -0,0 +1,24 @@ +dnl Copyright 1994, 1995, 1996, 1997, 1998, 1999, 2001, 2004 +dnl Free Software Foundation, Inc. +dnl This file is free software; the Free Software Foundation +dnl gives unlimited permission to copy and/or distribute it, +dnl with or without modifications, as long as this notice is preserved. + +dnl This program is distributed in the hope that it will be useful, +dnl but WITHOUT ANY WARRANTY, to the extent permitted by law; without +dnl even the implied warranty of MERCHANTABILITY or FITNESS FOR A +dnl PARTICULAR PURPOSE. + +m4_include(../config/acx.m4) +m4_include(../config/no-executables.m4) + +m4_include(../libtool.m4) +dnl The lines below arrange for aclocal not to bring an installed +dnl libtool.m4 into aclocal.m4, while still arranging for automake to +dnl add a definition of LIBTOOL to Makefile.in. +ifelse(yes,no,[ +AC_DEFUN([AM_PROG_LIBTOOL],) +AC_DEFUN([AC_LIBTOOL_DLOPEN],) +AC_DEFUN([AC_LIBLTDL_CONVENIENCE],) +AC_SUBST(LIBTOOL) +]) diff --git a/configure.ac b/configure.ac new file mode 100644 index 0000000..b1b43ad --- /dev/null +++ b/configure.ac @@ -0,0 +1,318 @@ +# Process this file with autoconf to produce a configure script. +# Copyright 1994, 1995, 1996, 1997, 1998, 1999, 2001, 2002, 2003, 2004 +# Free Software Foundation, Inc. +# Originally contributed by Dave Love (d.love@dl.ac.uk). +# +#This file is part of GCC. +# +#GCC is free software; you can redistribute it and/or modify +#it under the terms of the GNU General Public License as published by +#the Free Software Foundation; either version 2, or (at your option) +#any later version. +# +#GCC is distributed in the hope that it will be useful, +#but WITHOUT ANY WARRANTY; without even the implied warranty of +#MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +#GNU General Public License for more details. +# +#You should have received a copy of the GNU General Public License +#along with GCC; see the file COPYING. If not, write to +#the Free Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA +#02110-1301, USA. + +AC_PREREQ(2.59) +AC_INIT(package-unused, version-unused,, libobjc) +AC_CONFIG_SRCDIR([objc/objc.h]) +GCC_TOPLEV_SUBDIRS + +# We need the following definitions because AC_PROG_LIBTOOL relies on them +PACKAGE=libobjc +# Version is pulled out to make it a bit easier to change using sed. +VERSION=2:0:0 +AC_SUBST(VERSION) + +# This works around the fact that libtool configuration may change LD +# for this particular configuration, but some shells, instead of +# keeping the changes in LD private, export them just because LD is +# exported. +ORIGINAL_LD_FOR_MULTILIBS=$LD + +# ------- +# Options +# ------- + +# Default to --enable-multilib +AC_ARG_ENABLE(multilib, + [ --enable-multilib build hella library versions (default)], + [case "${enableval}" in + yes) multilib=yes ;; + no) multilib=no ;; + *) AC_MSG_ERROR(bad value ${enableval} for multilib option) ;; + esac], + [multilib=yes]) + +# We use these options to decide which functions to include. +AC_ARG_WITH(target-subdir, +[ --with-target-subdir=SUBDIR + configuring in a subdirectory]) +AC_ARG_WITH(cross-host, +[ --with-cross-host=HOST configuring with a cross compiler]) + +AC_MSG_CHECKING([for --enable-version-specific-runtime-libs]) +AC_ARG_ENABLE(version-specific-runtime-libs, +[ --enable-version-specific-runtime-libs Specify that runtime libraries should be installed in a compiler-specific directory ], +[case "$enableval" in + yes) version_specific_libs=yes ;; + no) version_specific_libs=no ;; + *) AC_MSG_ERROR([Unknown argument to enable/disable version-specific libs]);; + esac], +[version_specific_libs=no]) +AC_MSG_RESULT($version_specific_libs) + +AC_ARG_ENABLE(objc-gc, +[ --enable-objc-gc enable the use of Boehm's garbage collector with + the GNU Objective-C runtime.], +[case $enable_objc_gc in + no) OBJC_BOEHM_GC='' ;; + *) OBJC_BOEHM_GC=libobjc_gc.la ;; +esac], +[OBJC_BOEHM_GC='']) +AC_SUBST(OBJC_BOEHM_GC) + +# ----------- +# Directories +# ----------- + +# When building with srcdir == objdir, links to the source files will +# be created in directories within the target_subdir. We have to +# adjust toplevel_srcdir accordingly, so that configure finds +# install-sh and other auxiliary files that live in the top-level +# source directory. +if test "${srcdir}" = "."; then + if test -z "${with_target_subdir}"; then + toprel=".." + else + if test "${with_target_subdir}" != "."; then + toprel="${with_multisrctop}../.." + else + toprel="${with_multisrctop}.." + fi + fi +else + toprel=".." +fi +AC_CONFIG_AUX_DIR(${srcdir}/$toprel) +toplevel_srcdir=\${srcdir}/$toprel +AC_SUBST(toplevel_srcdir) + +AC_CANONICAL_SYSTEM +ACX_NONCANONICAL_TARGET + +# Export source directory. +# These need to be absolute paths, yet at the same time need to +# canonicalize only relative paths, because then amd will not unmount +# drives. Thus the use of PWDCMD: set it to 'pawd' or 'amq -w' if using amd. +case $srcdir in + [\\/$]* | ?:[\\/]*) glibcpp_srcdir=${srcdir} ;; + *) glibcpp_srcdir=`cd "$srcdir" && ${PWDCMD-pwd} || echo "$srcdir"` ;; +esac +AC_SUBST(glibcpp_srcdir) + +# Calculate toolexeclibdir +# Also toolexecdir, though it's only used in toolexeclibdir +case ${version_specific_libs} in + yes) + # Need the gcc compiler version to know where to install libraries + # and header files if --enable-version-specific-runtime-libs option + # is selected. + toolexecdir='$(libdir)/gcc/$(target_noncanonical)' + toolexeclibdir='$(toolexecdir)/$(gcc_version)$(MULTISUBDIR)' + ;; + no) + if test -n "$with_cross_host" && + test x"$with_cross_host" != x"no"; then + # Install a library built with a cross compiler in tooldir, not libdir. + toolexecdir='$(exec_prefix)/$(target_noncanonical)' + toolexeclibdir='$(toolexecdir)/lib' + else + toolexecdir='$(libdir)/gcc-lib/$(target_noncanonical)' + toolexeclibdir='$(libdir)' + fi + multi_os_directory=`$CC -print-multi-os-directory` + case $multi_os_directory in + .) ;; # Avoid trailing /. + *) toolexeclibdir=$toolexeclibdir/$multi_os_directory ;; + esac + ;; +esac +AC_SUBST(toolexecdir) +AC_SUBST(toolexeclibdir) + +# Figure out if we want to name the include directory and the +# library name changes differently. +includedirname=include +libext= +case "${host}" in + *-darwin*) + # Darwin is the only target so far that needs a different include directory. + includedirname=include-gnu-runtime + libext=-gnu + ;; +esac +AC_SUBST(includedirname) +AC_SUBST(libext) + +AC_CONFIG_HEADERS(config.h) + +# -------- +# Programs +# -------- + +GCC_NO_EXECUTABLES + +# We must force CC to /not/ be a precious variable; otherwise +# the wrong, non-multilib-adjusted value will be used in multilibs. +# As a side effect, we have to subst CFLAGS ourselves. +m4_rename([_AC_ARG_VAR_PRECIOUS],[real_PRECIOUS]) +m4_define([_AC_ARG_VAR_PRECIOUS],[]) +AC_PROG_CC +m4_rename([real_PRECIOUS],[_AC_ARG_VAR_PRECIOUS]) + +# extra LD Flags which are required for targets +case "${host}" in + *-darwin*) + # Darwin needs -single_module when linking libobjc + extra_ldflags_libobjc=-Wl,-single_module + ;; +esac +AC_SUBST(extra_ldflags_libobjc) + +AC_SUBST(CFLAGS) + +AC_CHECK_TOOL(AS, as) +AC_CHECK_TOOL(AR, ar) +AC_CHECK_TOOL(RANLIB, ranlib, :) +AC_PROG_INSTALL + +AM_MAINTAINER_MODE + +# Enable Win32 DLL on MS Windows - FIXME +AC_LIBTOOL_WIN32_DLL + +AC_PROG_LIBTOOL + +AM_PROG_CC_C_O + +AC_PROG_MAKE_SET + +# ------- +# Headers +# ------- + +# Sanity check for the cross-compilation case: +AC_CHECK_HEADER(stdio.h,:, + [AC_MSG_ERROR([Can't find stdio.h. +You must have a usable C system for the target already installed, at least +including headers and, preferably, the library, before you can configure +the Objective C runtime system. If necessary, install gcc now with +\`LANGUAGES=c', then the target library, then build with \`LANGUAGES=objc'.])]) + +AC_HEADER_STDC + +AC_CHECK_HEADERS(sched.h) + +# ----------- +# Miscellanea +# ----------- + +AC_MSG_CHECKING([for thread model used by GCC]) +target_thread_file=`$CC -v 2>&1 | sed -n 's/^Thread model: //p'` +AC_MSG_RESULT([$target_thread_file]) + +if test $target_thread_file != single; then + AC_DEFINE(HAVE_GTHR_DEFAULT, 1, + [Define if the compiler has a thread header that is non single.]) +fi + + +AC_MSG_CHECKING([for exception model to use]) +AC_LANG_PUSH(C) +AC_ARG_ENABLE(sjlj-exceptions, + AS_HELP_STRING([--enable-sjlj-exceptions], + [force use of builtin_setjmp for exceptions]), +[:], +[dnl Botheration. Now we've got to detect the exception model. +dnl Link tests against libgcc.a are problematic since -- at least +dnl as of this writing -- we've not been given proper -L bits for +dnl single-tree newlib and libgloss. +dnl +dnl This is what AC_TRY_COMPILE would do if it didn't delete the +dnl conftest files before we got a change to grep them first. +cat > conftest.$ac_ext << EOF +[#]line __oline__ "configure" +@interface Frob +@end +@implementation Frob +@end +int proc(); +int foo() +{ + @try { + return proc(); + } + @catch (Frob* ex) { + return 0; + } +} +EOF +old_CFLAGS="$CFLAGS" +dnl work around that we don't have Objective-C support in autoconf +CFLAGS="-x objective-c -fgnu-runtime -fobjc-exceptions -S" +if AC_TRY_EVAL(ac_compile); then + if grep _Unwind_SjLj_Resume conftest.s >/dev/null 2>&1 ; then + enable_sjlj_exceptions=yes + elif grep _Unwind_Resume conftest.s >/dev/null 2>&1 ; then + enable_sjlj_exceptions=no + fi +fi +CFLAGS="$old_CFLAGS" +rm -f conftest*]) +if test x$enable_sjlj_exceptions = xyes; then + AC_DEFINE(SJLJ_EXCEPTIONS, 1, + [Define if the compiler is configured for setjmp/longjmp exceptions.]) + ac_exception_model_name=sjlj +elif test x$enable_sjlj_exceptions = xno; then + ac_exception_model_name="call frame" +else + AC_MSG_ERROR([unable to detect exception model]) +fi +AC_LANG_POP(C) +AC_MSG_RESULT($ac_exception_model_name) + +# ------ +# Output +# ------ + +AC_CONFIG_FILES([Makefile]) + +AC_CONFIG_COMMANDS([default], +[[if test -n "$CONFIG_FILES"; then + if test -n "${with_target_subdir}"; then + # FIXME: We shouldn't need to set ac_file + ac_file=Makefile + LD="${ORIGINAL_LD_FOR_MULTILIBS}" + . ${toplevel_srcdir}/config-ml.in + fi +fi]], +[[srcdir=${srcdir} +host=${host} +target=${target} +with_target_subdir=${with_target_subdir} +with_multisubdir=${with_multisubdir} +ac_configure_args="--enable-multilib ${ac_configure_args}" +toplevel_srcdir=${toplevel_srcdir} +CONFIG_SHELL=${CONFIG_SHELL-/bin/sh} +ORIGINAL_LD_FOR_MULTILIBS="${ORIGINAL_LD_FOR_MULTILIBS}" +]]) + +AC_OUTPUT diff --git a/exception.c b/exception.c new file mode 100644 index 0000000..e1de2ae --- /dev/null +++ b/exception.c @@ -0,0 +1,376 @@ +/* The implementation of exception handling primitives for Objective-C. + Copyright (C) 2004 Free Software Foundation, Inc. + +This file is part of GCC. + +GCC is free software; you can redistribute it and/or modify it +under the terms of the GNU General Public License as published by the +Free Software Foundation; either version 2, or (at your option) any +later version. + +GCC is distributed in the hope that it will be useful, but WITHOUT +ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public +License for more details. + +You should have received a copy of the GNU General Public License +along with GCC; see the file COPYING. If not, write to +the Free Software Foundation, 51 Franklin Street, Fifth Floor, +Boston, MA 02110-1301, USA. */ + +/* As a special exception, if you link this library with files compiled + with GCC to produce an executable, this does not cause the resulting + executable to be covered by the GNU General Public License. This + exception does not however invalidate any other reasons why the + executable file might be covered by the GNU General Public License. */ + +#include +#include "config.h" +#include "objc/objc-api.h" +#include "unwind.h" +#include "unwind-pe.h" + + +/* This is the exception class we report -- "GNUCOBJC". */ +#define __objc_exception_class \ + ((((((((_Unwind_Exception_Class) 'G' \ + << 8 | (_Unwind_Exception_Class) 'N') \ + << 8 | (_Unwind_Exception_Class) 'U') \ + << 8 | (_Unwind_Exception_Class) 'C') \ + << 8 | (_Unwind_Exception_Class) 'O') \ + << 8 | (_Unwind_Exception_Class) 'B') \ + << 8 | (_Unwind_Exception_Class) 'J') \ + << 8 | (_Unwind_Exception_Class) 'C') + +/* This is the object that is passed around by the Objective C runtime + to represent the exception in flight. */ + +struct ObjcException +{ + /* This bit is needed in order to interact with the unwind runtime. */ + struct _Unwind_Exception base; + + /* The actual object we want to throw. */ + id value; + + /* Cache some internal unwind data between phase 1 and phase 2. */ + _Unwind_Ptr landingPad; + int handlerSwitchValue; +}; + + + +struct lsda_header_info +{ + _Unwind_Ptr Start; + _Unwind_Ptr LPStart; + _Unwind_Ptr ttype_base; + const unsigned char *TType; + const unsigned char *action_table; + unsigned char ttype_encoding; + unsigned char call_site_encoding; +}; + +static const unsigned char * +parse_lsda_header (struct _Unwind_Context *context, const unsigned char *p, + struct lsda_header_info *info) +{ + _Unwind_Word tmp; + unsigned char lpstart_encoding; + + info->Start = (context ? _Unwind_GetRegionStart (context) : 0); + + /* Find @LPStart, the base to which landing pad offsets are relative. */ + lpstart_encoding = *p++; + if (lpstart_encoding != DW_EH_PE_omit) + p = read_encoded_value (context, lpstart_encoding, p, &info->LPStart); + else + info->LPStart = info->Start; + + /* Find @TType, the base of the handler and exception spec type data. */ + info->ttype_encoding = *p++; + if (info->ttype_encoding != DW_EH_PE_omit) + { + p = read_uleb128 (p, &tmp); + info->TType = p + tmp; + } + else + info->TType = 0; + + /* The encoding and length of the call-site table; the action table + immediately follows. */ + info->call_site_encoding = *p++; + p = read_uleb128 (p, &tmp); + info->action_table = p + tmp; + + return p; +} + +static Class +get_ttype_entry (struct lsda_header_info *info, _Unwind_Word i) +{ + _Unwind_Ptr ptr; + + i *= size_of_encoded_value (info->ttype_encoding); + read_encoded_value_with_base (info->ttype_encoding, info->ttype_base, + info->TType - i, &ptr); + + /* NULL ptr means catch-all. */ + if (ptr) + return objc_get_class ((const char *) ptr); + else + return 0; +} + +/* Like unto the method of the same name on Object, but takes an id. */ +/* ??? Does this bork the meta-type system? Can/should we look up an + isKindOf method on the id? */ + +static int +isKindOf (id value, Class target) +{ + Class c; + + /* NULL target is catch-all. */ + if (target == 0) + return 1; + + for (c = value->class_pointer; c; c = class_get_super_class (c)) + if (c == target) + return 1; + return 0; +} + +/* Using a different personality function name causes link failures + when trying to mix code using different exception handling models. */ +#ifdef SJLJ_EXCEPTIONS +#define PERSONALITY_FUNCTION __gnu_objc_personality_sj0 +#define __builtin_eh_return_data_regno(x) x +#else +#define PERSONALITY_FUNCTION __gnu_objc_personality_v0 +#endif + +_Unwind_Reason_Code +PERSONALITY_FUNCTION (int version, + _Unwind_Action actions, + _Unwind_Exception_Class exception_class, + struct _Unwind_Exception *ue_header, + struct _Unwind_Context *context) +{ + struct ObjcException *xh = (struct ObjcException *) ue_header; + + struct lsda_header_info info; + const unsigned char *language_specific_data; + const unsigned char *action_record; + const unsigned char *p; + _Unwind_Ptr landing_pad, ip; + int handler_switch_value; + int saw_cleanup = 0, saw_handler; + void *return_object; + + /* Interface version check. */ + if (version != 1) + return _URC_FATAL_PHASE1_ERROR; + + /* Shortcut for phase 2 found handler for domestic exception. */ + if (actions == (_UA_CLEANUP_PHASE | _UA_HANDLER_FRAME) + && exception_class == __objc_exception_class) + { + handler_switch_value = xh->handlerSwitchValue; + landing_pad = xh->landingPad; + goto install_context; + } + + language_specific_data = (const unsigned char *) + _Unwind_GetLanguageSpecificData (context); + + /* If no LSDA, then there are no handlers or cleanups. */ + if (! language_specific_data) + return _URC_CONTINUE_UNWIND; + + /* Parse the LSDA header. */ + p = parse_lsda_header (context, language_specific_data, &info); + info.ttype_base = base_of_encoded_value (info.ttype_encoding, context); + ip = _Unwind_GetIP (context) - 1; + landing_pad = 0; + action_record = 0; + handler_switch_value = 0; + +#ifdef SJLJ_EXCEPTIONS + /* The given "IP" is an index into the call-site table, with two + exceptions -- -1 means no-action, and 0 means terminate. But + since we're using uleb128 values, we've not got random access + to the array. */ + if ((int) ip < 0) + return _URC_CONTINUE_UNWIND; + else + { + _Unwind_Word cs_lp, cs_action; + do + { + p = read_uleb128 (p, &cs_lp); + p = read_uleb128 (p, &cs_action); + } + while (--ip); + + /* Can never have null landing pad for sjlj -- that would have + been indicated by a -1 call site index. */ + landing_pad = cs_lp + 1; + if (cs_action) + action_record = info.action_table + cs_action - 1; + goto found_something; + } +#else + /* Search the call-site table for the action associated with this IP. */ + while (p < info.action_table) + { + _Unwind_Ptr cs_start, cs_len, cs_lp; + _Unwind_Word cs_action; + + /* Note that all call-site encodings are "absolute" displacements. */ + p = read_encoded_value (0, info.call_site_encoding, p, &cs_start); + p = read_encoded_value (0, info.call_site_encoding, p, &cs_len); + p = read_encoded_value (0, info.call_site_encoding, p, &cs_lp); + p = read_uleb128 (p, &cs_action); + + /* The table is sorted, so if we've passed the ip, stop. */ + if (ip < info.Start + cs_start) + p = info.action_table; + else if (ip < info.Start + cs_start + cs_len) + { + if (cs_lp) + landing_pad = info.LPStart + cs_lp; + if (cs_action) + action_record = info.action_table + cs_action - 1; + goto found_something; + } + } +#endif /* SJLJ_EXCEPTIONS */ + + /* If ip is not present in the table, C++ would call terminate. */ + /* ??? As with Java, it's perhaps better to tweek the LSDA to + that no-action is mapped to no-entry. */ + return _URC_CONTINUE_UNWIND; + + found_something: + saw_cleanup = 0; + saw_handler = 0; + + if (landing_pad == 0) + { + /* If ip is present, and has a null landing pad, there are + no cleanups or handlers to be run. */ + } + else if (action_record == 0) + { + /* If ip is present, has a non-null landing pad, and a null + action table offset, then there are only cleanups present. + Cleanups use a zero switch value, as set above. */ + saw_cleanup = 1; + } + else + { + /* Otherwise we have a catch handler. */ + _Unwind_Sword ar_filter, ar_disp; + + while (1) + { + p = action_record; + p = read_sleb128 (p, &ar_filter); + read_sleb128 (p, &ar_disp); + + if (ar_filter == 0) + { + /* Zero filter values are cleanups. */ + saw_cleanup = 1; + } + + /* During forced unwinding, we only run cleanups. With a + foreign exception class, we have no class info to match. */ + else if ((actions & _UA_FORCE_UNWIND) + || exception_class != __objc_exception_class) + ; + + else if (ar_filter > 0) + { + /* Positive filter values are handlers. */ + + Class catch_type = get_ttype_entry (&info, ar_filter); + + if (isKindOf (xh->value, catch_type)) + { + handler_switch_value = ar_filter; + saw_handler = 1; + break; + } + } + else + { + /* Negative filter values are exception specifications, + which Objective-C does not use. */ + abort (); + } + + if (ar_disp == 0) + break; + action_record = p + ar_disp; + } + } + + if (! saw_handler && ! saw_cleanup) + return _URC_CONTINUE_UNWIND; + + if (actions & _UA_SEARCH_PHASE) + { + if (!saw_handler) + return _URC_CONTINUE_UNWIND; + + /* For domestic exceptions, we cache data from phase 1 for phase 2. */ + if (exception_class == __objc_exception_class) + { + xh->handlerSwitchValue = handler_switch_value; + xh->landingPad = landing_pad; + } + return _URC_HANDLER_FOUND; + } + + install_context: + if (saw_cleanup == 0) + { + return_object = xh->value; + if (!(actions & _UA_SEARCH_PHASE)) + _Unwind_DeleteException(&xh->base); + } + + _Unwind_SetGR (context, __builtin_eh_return_data_regno (0), + __builtin_extend_pointer (saw_cleanup ? xh : return_object)); + _Unwind_SetGR (context, __builtin_eh_return_data_regno (1), + handler_switch_value); + _Unwind_SetIP (context, landing_pad); + return _URC_INSTALL_CONTEXT; +} + +static void +__objc_exception_cleanup (_Unwind_Reason_Code code __attribute__((unused)), + struct _Unwind_Exception *exc) +{ + free (exc); +} + +void +objc_exception_throw (id value) +{ + struct ObjcException *header = calloc (1, sizeof (*header)); + header->base.exception_class = __objc_exception_class; + header->base.exception_cleanup = __objc_exception_cleanup; + header->value = value; + +#ifdef SJLJ_EXCEPTIONS + _Unwind_SjLj_RaiseException (&header->base); +#else + _Unwind_RaiseException (&header->base); +#endif + + /* Some sort of unwinding error. */ + abort (); +}