/* * Copyright (c) 1999 Apple Computer, Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved. * * This file contains Original Code and/or Modifications of Original Code * as defined in and that are subject to the Apple Public Source License * Version 2.0 (the 'License'). You may not use this file except in * compliance with the License. Please obtain a copy of the License at * http://www.opensource.apple.com/apsl/ and read it before using this * file. * * The Original Code and all software distributed under the License are * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. * Please see the License for the specific language governing rights and * limitations under the License. * * @APPLE_LICENSE_HEADER_END@ */ // // objc_exception.m // Support minimal stand-alone implementation plus hooks for swapping // in a richer implementation. // // Created by Blaine Garst on Fri Nov 01 2002. // Copyright (c) 2002 Apple Computer, Inc. All rights reserved. // #undef _BUILDING_OBJC #import "objc-exception.h" static objc_exception_functions_t xtab; // forward declaration static void set_default_handlers(); /* * Exported functions */ // get table; version tells how many void objc_exception_get_functions(objc_exception_functions_t *table) { // only version 0 supported at this point if (table && table->version == 0) *table = xtab; } // set table void objc_exception_set_functions(objc_exception_functions_t *table) { // only version 0 supported at this point if (table && table->version == 0) xtab = *table; } /* * The following functions are * synthesized by the compiler upon encountering language constructs */ void objc_exception_throw(id exception) { if (!xtab.throw_exc) { set_default_handlers(); } xtab.throw_exc(exception); } void objc_exception_try_enter(void *localExceptionData) { if (!xtab.throw_exc) { set_default_handlers(); } xtab.try_enter(localExceptionData); } void objc_exception_try_exit(void *localExceptionData) { if (!xtab.throw_exc) { set_default_handlers(); } xtab.try_exit(localExceptionData); } id objc_exception_extract(void *localExceptionData) { if (!xtab.throw_exc) { set_default_handlers(); } return xtab.extract(localExceptionData); } int objc_exception_match(Class exceptionClass, id exception) { if (!xtab.throw_exc) { set_default_handlers(); } return xtab.match(exceptionClass, exception); } // quick and dirty exception handling code // default implementation - mostly a toy for use outside/before Foundation // provides its implementation // Perhaps the default implementation should just complain loudly and quit #import #import extern void _objc_inform(const char *fmt, ...); typedef struct { jmp_buf buf; void *pointers[4]; } LocalData_t; typedef struct _threadChain { LocalData_t *topHandler; void *perThreadID; struct _threadChain *next; } ThreadChainLink_t; #define _ExceptionDebug 0 static ThreadChainLink_t ThreadChainLink; static ThreadChainLink_t *getChainLink() { // follow links until thread_self() found (someday) XXX pthread_t self = pthread_self(); ThreadChainLink_t *walker = &ThreadChainLink; while (walker->perThreadID != (void *)self) { if (walker->next != NULL) { walker = walker->next; continue; } // create a new one // XXX not thread safe (!) // XXX Also, we don't register to deallocate on thread death walker->next = (ThreadChainLink_t *)malloc(sizeof(ThreadChainLink_t)); walker = walker->next; walker->next = NULL; walker->topHandler = NULL; walker->perThreadID = self; } return walker; } static void default_try_enter(void *localExceptionData) { ThreadChainLink_t *chainLink = getChainLink(); ((LocalData_t *)localExceptionData)->pointers[1] = chainLink->topHandler; chainLink->topHandler = localExceptionData; if (_ExceptionDebug) _objc_inform("entered try block %x\n", chainLink->topHandler); } static void default_throw(id value) { ThreadChainLink_t *chainLink = getChainLink(); if (value == nil) { if (_ExceptionDebug) _objc_inform("objc_exception_throw with nil value\n"); return; } if (chainLink == NULL) { if (_ExceptionDebug) _objc_inform("No handler in place!\n"); return; } if (_ExceptionDebug) _objc_inform("exception thrown, going to handler block %x\n", chainLink->topHandler); LocalData_t *led = chainLink->topHandler; chainLink->topHandler = led->pointers[1]; // pop top handler led->pointers[0] = value; // store exception that is thrown _longjmp(led->buf, 1); } static void default_try_exit(void *led) { ThreadChainLink_t *chainLink = getChainLink(); if (!chainLink || led != chainLink->topHandler) { if (_ExceptionDebug) _objc_inform("!!! mismatched try block exit handlers !!!\n"); return; } if (_ExceptionDebug) _objc_inform("removing try block handler %x\n", chainLink->topHandler); chainLink->topHandler = chainLink->topHandler->pointers[1]; // pop top handler } static id default_extract(void *localExceptionData) { LocalData_t *led = (LocalData_t *)localExceptionData; return (id)led->pointers[0]; } static int default_match(Class exceptionClass, id exception) { //return [exception isKindOfClass:exceptionClass]; Class cls; for (cls = exception->isa; nil != cls; cls = cls->super_class) if (cls == exceptionClass) return 1; return 0; } static void set_default_handlers() { objc_exception_functions_t default_functions = { 0, default_throw, default_try_enter, default_try_exit, default_extract, default_match }; // should this always print? if (_ExceptionDebug) _objc_inform("*** Setting default (non-Foundation) exception mechanism\n"); objc_exception_set_functions(&default_functions); }