This is NSObjectAllocation.m in view mode; [Download] [Up]
/* NSObjectAllocation.m Copyright (C) 1995, 1996 Ovidiu Predescu and Mircea Oancea. All rights reserved. Author: Ovidiu Predescu <ovidiu@bx.logicnet.ro> Mircea Oancea <mircea@jupiter.elcom.pub.ro> This file is part of libFoundation. Permission to use, copy, modify, and distribute this software and its documentation for any purpose and without fee is hereby granted, provided that the above copyright notice appear in all copies and that both that copyright notice and this permission notice appear in supporting documentation. We disclaim all warranties with regard to this software, including all implied warranties of merchantability and fitness, in no event shall we be liable for any special, indirect or consequential damages or any damages whatsoever resulting from loss of use, data or profits, whether in an action of contract, negligence or other tortious action, arising out of or in connection with the use or performance of this software. */ #include <config.h> #if HAVE_LIBC_H # include <libc.h> #else # include <unistd.h> #endif #if HAVE_STRING_H # include <string.h> #endif #if HAVE_MEMORY_H # include <memory.h> #endif #if !HAVE_MEMCPY # define memcpy(d, s, n) bcopy((s), (d), (n)) # define memmove(d, s, n) bcopy((s), (d), (n)) #endif #if HAVE_STDLIB_H # include <stdlib.h> #else extern void* malloc(); extern void* calloc(); extern void* realloc(); extern void free(); extern atoi(); extern atol(); #endif #include <assert.h> #include <Foundation/common.h> #include <Foundation/NSZone.h> #include <Foundation/NSUtilities.h> #include <Foundation/exceptions/GeneralExceptions.h> #include <extensions/objc-runtime.h> /* * When an object is deallocated, its class pointer points to the FREED_OBJECT * class. */ @interface FREED_OBJECT @end /* * Refence counting can be done in two ways: * (1) increasing the size of NSObject by allocating a "hidden" int * before the pointer. This has the disadvantage that the pointers * returned by malloc differ from those kept by the program, making * the use of NeXT's MallocDebug program unusable :-) * (2) keeping a global hash with object pointers as keys and reference * counts as values. * * This mecanisms are controlled by one compile time defines and one * environment variable as follows: * OBJECT_REFCOUNT (define) * 1 => mecanism is controlled by hash * 0 => mechanism is controlled by extra ref-count * * => mecanism controlled by environment variable * OBJECT_REFCOUNT (environment variable) * defined => mecanism is controlled by hash * undefined => mechanism is controlled by extra ref-count * */ /* * OBJ2PTR(p) : id object --> real allocated pointer used by Malloc/Free * PTR2HSH(p) : id object --> pointer kept as key in hashtable */ #define OBJ2PTR(p) ((struct RefObjectLayout*)((unsigned*)p-1)) #define PTR2HSH(p) ((void*)((unsigned*)p-1)) struct RefObjectLayout { unsigned ref_count; /* <---- Malloc/Free pointer */ Class class_pointer; /* <---- id pointer */ char extra[0]; }; struct HashObjectLayout { Class class_pointer; /* <---- id pointer == Malloc/Free pointer */ char extra[0]; }; /* * Global variables */ static BOOL objectRefInit = NO; static NSMapTable* objectRefsHash; static BOOL objectRefIsHash; static Class freedObjectClass = nil; static void init_refcounting(void) { #if defined(OBJECT_REFCOUNT) && OBJECT_REFCOUNT == 1 objectRefIsHash = YES; #elif defined(OBJECT_REFCOUNT) && OBJECT_REFCOUNT == 0 objectRefIsHash = NO; #else /* Undefined at compile-time. Use OBJECT_REFCOUNT environment variable */ objectRefIsHash = getenv("OBJECT_REFCOUNT") ? YES : NO; #endif /* fprintf(stderr, "NSObjectAllocation: using %s refcounting\n", objectRefIsHash ? "hashtable" : "extra-allocated"); */ if (objectRefIsHash) objectRefsHash = NSCreateMapTableWithZone( NSNonOwnedPointerMapKeyCallBacks, NSIntMapValueCallBacks, 64, nil); objectRefInit = YES; freedObjectClass = objc_get_class("FREED_OBJECT"); } /* * Allocate an Object */ NSObject *NSAllocateObject(Class aClass, unsigned extraBytes, NSZone *zone) { assert(CLS_ISCLASS(aClass)); if (!objectRefInit) init_refcounting(); if (objectRefIsHash) { struct HashObjectLayout* p; p = NSZoneCalloc(zone, 1, sizeof(struct HashObjectLayout) + aClass->instance_size + extraBytes); p->class_pointer = aClass; NSMapInsert(objectRefsHash, PTR2HSH(p), (void*)1); return (NSObject*)p; } else { struct RefObjectLayout* p; p = NSZoneCalloc(zone, 1, sizeof(struct RefObjectLayout) + aClass->instance_size + extraBytes); p->class_pointer = aClass; p->ref_count = 1; return (NSObject*)(&(p->class_pointer)); } return nil; } NSObject *NSCopyObject(NSObject *anObject, unsigned extraBytes, NSZone *zone) { id copy = NSAllocateObject(((id)anObject)->class_pointer, extraBytes, zone); unsigned size = ((id)anObject)->class_pointer->instance_size + extraBytes; memcpy(copy, anObject, size); return copy; } NSZone* NSZoneFromObject(NSObject *anObject) { if (!objectRefInit) init_refcounting(); if (objectRefIsHash) { return NSZoneFromPointer(anObject); } else { return NSZoneFromPointer(OBJ2PTR(anObject)); } } void NSDeallocateObject(NSObject *anObject) { void* p; /* Set the class of anObject to FREED_OBJECT. The further messages to this object will cause an error to occur. */ ((id)anObject)->class_pointer = freedObjectClass; if (!objectRefInit) init_refcounting(); if (objectRefIsHash) { p = anObject; NSMapRemove(objectRefsHash, PTR2HSH(anObject)); } else { p = OBJ2PTR(anObject); } NSZoneFree(NSZoneFromPointer(p), p); } /* * Retain / Release NSObject */ BOOL NSShouldRetainWithZone(NSObject* anObject, NSZone* requestedZone) { return requestedZone == NULL || requestedZone == NSDefaultMallocZone() || requestedZone == [anObject zone]; } /* * Modify the Number of References to an Object */ BOOL NSDecrementExtraRefCountWasZero(id anObject) { if (!objectRefInit) init_refcounting(); if (objectRefIsHash) { void* p = PTR2HSH(anObject); int r = (unsigned)NSMapGet(objectRefsHash, p); if (!r) return YES; NSMapInsert(objectRefsHash, p, (void*)(--r)); return (r == 0); } else { struct RefObjectLayout* p = OBJ2PTR(anObject); int r = p->ref_count; if (!r) return YES; r = --(p->ref_count); return (r == 0); } } void NSIncrementExtraRefCount(id anObject) { if (!objectRefInit) init_refcounting(); if (objectRefIsHash) { void* p = PTR2HSH(anObject); int r = (unsigned)NSMapGet(objectRefsHash, p); NSMapInsert(objectRefsHash, p, (void*)(r+1)); } else { struct RefObjectLayout* p = OBJ2PTR(anObject); (p->ref_count)++; } } /* Obtain the Number of References to an Object */ unsigned NSGetExtraRefCount(id anObject) { int r; if (!objectRefInit) init_refcounting(); if (objectRefIsHash) { void* p = PTR2HSH(anObject); r = (unsigned)NSMapGet(objectRefsHash, p); } else { struct RefObjectLayout* p = OBJ2PTR(anObject); r = p->ref_count; } return r; } @implementation FREED_OBJECT #if GNU_RUNTIME - (void)doesNotRecognize:(SEL)aSelector #else - (void)doesNotRecognizeSelector:(SEL)aSelector #endif { id exception = [[ObjcRuntimeException alloc] initWithFormat:@"message '%s' sent to freed object %p", sel_get_name(aSelector), (void*)self]; THROW(exception); } @end
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.