From: Apple Date: Tue, 7 Aug 2001 17:37:47 +0000 (+0000) Subject: objc4-217.tar.gz X-Git-Tag: mac-os-x-101^0 X-Git-Url: https://git.saurik.com/apple/objc4.git/commitdiff_plain/41c8faa53824a4e6dd6cf2de319a92a0e535adc2?ds=sidebyside objc4-217.tar.gz --- diff --git a/runtime/Makefile b/runtime/Makefile index b0dc277..ec9acaa 100644 --- a/runtime/Makefile +++ b/runtime/Makefile @@ -14,18 +14,17 @@ PROJECT_TYPE = Library HFILES = error.h hashtable2.h maptable.h objc-api.h objc-class.h\ objc-config.h objc-load.h objc-private.h objc-runtime.h\ - objc.h Object.h Protocol.h + objc.h Object.h Protocol.h MFILES = hashtable2.m maptable.m objc-class.m objc-errors.m\ - objc-file.m objc-load.m objc-runtime.m objc-sel.m\ - Object.m Protocol.m + objc-file.m objc-load.m objc-runtime.m objc-sel.m Object.m\ + Protocol.m CFILES = objc-moninit.c SUBPROJECTS = Messengers.subproj OldClasses.subproj -OTHERSRCS = Makefile.preamble Makefile Makefile.postamble\ - objc_hpux_register_shlib.c objc_dllMain.c +OTHERSRCS = Makefile.preamble Makefile Makefile.postamble MAKEFILEDIR = $(MAKEFILEPATH)/pb_makefiles @@ -34,7 +33,6 @@ DEPLOY_WITH_VERSION_NAME = A CODE_GEN_STYLE = DYNAMIC MAKEFILE = library.make NEXTSTEP_INSTALLDIR = /usr/lib -#NEXTSTEP_INSTALLDIR = /Local/Developer/libs WINDOWS_INSTALLDIR = /. PDO_UNIX_INSTALLDIR = $(LOCAL_DEVELOPER_DIR)/Libraries LIBS = @@ -45,6 +43,8 @@ PROF_LIBS = $(LIBS) PUBLIC_HEADERS = objc-class.h objc-api.h objc-load.h objc-runtime.h\ objc.h Object.h Protocol.h error.h hashtable2.h +PROJECT_HEADERS = objc-runtime.h objc-class.h + NEXTSTEP_OBJCPLUS_COMPILER = /usr/bin/cc diff --git a/runtime/Makefile.postamble b/runtime/Makefile.postamble index 3a6e960..193b70c 100644 --- a/runtime/Makefile.postamble +++ b/runtime/Makefile.postamble @@ -18,26 +18,10 @@ create-profile-lib-compat-link: $(SYMLINK) $(notdir $(VERSIONED_PROFILE_PRODUCT)) $(DSTROOT)$(INSTALLDIR)/libobjc.A_profile.dylib link-hashtable: -ifeq ("$(PLATFORM_OS)", "macos") $(RM) -f $(DSTROOT)$(PUBLIC_HEADER_DIR)$(PUBLIC_HEADER_DIR_SUFFIX)/hashtable.h $(CP) $(DSTROOT)$(PUBLIC_HEADER_DIR)$(PUBLIC_HEADER_DIR_SUFFIX)/hashtable2.h $(DSTROOT)$(PUBLIC_HEADER_DIR)$(PUBLIC_HEADER_DIR_SUFFIX)/hashtable.h -endif -ifeq ("$(PLATFORM_OS)", "solaris") - $(RM) -f $(DSTROOT)$(PUBLIC_HEADER_DIR)$(PUBLIC_HEADER_DIR_SUFFIX)/hashtable.h - $(LN) $(DSTROOT)$(PUBLIC_HEADER_DIR)$(PUBLIC_HEADER_DIR_SUFFIX)/hashtable2.h $(DSTROOT)$(PUBLIC_HEADER_DIR)$(PUBLIC_HEADER_DIR_SUFFIX)/hashtable.h -endif -ifeq ("$(PLATFORM_OS)", "hpux") - $(RM) -f $(DSTROOT)$(PUBLIC_HEADER_DIR)$(PUBLIC_HEADER_DIR_SUFFIX)/hashtable.h - $(LN) $(DSTROOT)$(PUBLIC_HEADER_DIR)$(PUBLIC_HEADER_DIR_SUFFIX)/hashtable2.h $(DSTROOT)$(PUBLIC_HEADER_DIR)$(PUBLIC_HEADER_DIR_SUFFIX)/hashtable.h -endif true # from AFTER_POSTINSTALL postprocess: -ifeq ("$(PLATFORM_OS)", "winnt") - $(MKDIRS) $(DSTROOT)$(LOCAL_DEVELOPER_DIR)/Libraries - $(CP) $(SYMROOT)/runtime.lib $(DSTROOT)$(LOCAL_DEVELOPER_DIR)/Libraries/libobjc.a - $(CP) $(SYMROOT)/runtime.lib $(DSTROOT)$(LOCAL_DEVELOPER_DIR)/Libraries/libobjc_g.a - $(RM) -f $(DSTROOT)$(INSTALLDIR)/runtime.lib -endif diff --git a/runtime/Makefile.preamble b/runtime/Makefile.preamble index 1cc06c0..83a3305 100644 --- a/runtime/Makefile.preamble +++ b/runtime/Makefile.preamble @@ -3,38 +3,13 @@ # Copyright 1997,2000 Apple Computer, Inc. ############################################################################### -ifeq "$(PLATFORM_OS)" "winnt" - BUILDING_ON_WINDOWS = YES -else -ifeq "$(PLATFORM_OS)" "win95" - BUILDING_ON_WINDOWS = YES -else -ifeq "$(PLATFORM_OS)" "win32" - BUILDING_ON_WINDOWS = YES -endif # win32 -endif # win95 -endif # winnt -ifeq "$(PLATFORM_OS)" "macos" - NAME = objc - OTHER_CFLAGS += -Wno-unused - OTHER_LIBTOOL_FLAGS += -Wl,-init,___initialize_objc - FRAMEWORKS += -framework CoreFoundation - HEADER_PATHS += -I$(NEXT_ROOT)$(SYSTEM_LIBRARY_DIR)/Frameworks/System.framework/PrivateHeaders - AFTER_INSTALL += create-profile-lib-compat-link -endif -ifeq "$(BUILDING_ON_WINDOWS)" "YES" - LIBRARY_STYLE = STATIC - OTHER_LIBTOOL_FLAGS = -debugtype:both -endif -ifeq "$(PLATFORM_OS)" "solaris" - OTHER_CFLAGS += -Wno-unused -fPIC - LIBRARY_STYLE = STATIC -endif -ifeq "$(PLATFORM_OS)" "hpux" - OTHER_CFLAGS += -Wno-unused -Wno-comment -D_REENTRANT -DNSBUILDINGHPUXSHLIB -fPIC - LIBRARY_STYLE = STATIC -endif +NAME = objc +OTHER_CFLAGS += -Wno-unused +OTHER_LIBTOOL_FLAGS += -Wl,-init,__objcInit +FRAMEWORKS += -framework CoreFoundation +HEADER_PATHS += -I$(NEXT_ROOT)$(SYSTEM_LIBRARY_DIR)/Frameworks/System.framework/PrivateHeaders +AFTER_INSTALL += create-profile-lib-compat-link OTHER_CFLAGS += -DNSBUILDINGOBJC -I$(SYMROOT) OTHER_LDFLAGS = @@ -42,23 +17,8 @@ OTHER_LDFLAGS = AFTER_INSTALLHDRS += link-hashtable AFTER_POSTINSTALL += postprocess -ifeq ("$(PLATFORM_OS)", "macos") - PUBLIC_HEADER_DIR = /usr/include - PRIVATE_HEADER_DIR = /usr/local/include -else -ifeq ("$(PLATFORM_OS)", "solaris") - PUBLIC_HEADER_DIR = $(SYSTEM_LIBRARY_DIR)/Frameworks/System.framework/Versions/A/Headers - PRIVATE_HEADER_DIR = $(SYSTEM_LIBRARY_DIR)/Frameworks/System.framework/Versions/A/PrivateHeaders -else -ifeq ("$(PLATFORM_OS)", "hpux") - PUBLIC_HEADER_DIR = $(SYSTEM_LIBRARY_DIR)/Frameworks/System.framework/Versions/A/Headers - PRIVATE_HEADER_DIR = $(SYSTEM_LIBRARY_DIR)/Frameworks/System.framework/Versions/A/PrivateHeaders -else - PUBLIC_HEADER_DIR = $(SYSTEM_DEVELOPER_DIR)/Headers - PRIVATE_HEADER_DIR = $(LOCAL_DEVELOPER_DIR)/Headers -endif -endif -endif +PUBLIC_HEADER_DIR = /usr/include +PRIVATE_HEADER_DIR = /usr/local/include # If, in a subproject, you want to append to the parent's PUBLIC_HEADER_DIR# # (say, to add a subdirectory like "/sys"), you can use: diff --git a/runtime/Messengers.subproj/Makefile b/runtime/Messengers.subproj/Makefile index e4dda7b..df1daed 100644 --- a/runtime/Messengers.subproj/Makefile +++ b/runtime/Messengers.subproj/Makefile @@ -1,5 +1,5 @@ # -# Generated by the NeXT Project Builder. +# Generated by the Apple Project Builder. # # NOTE: Do NOT change this file -- Project Builder maintains it. # @@ -15,11 +15,7 @@ PROJECT_TYPE = Component OTHERLINKED = objc-msg.s OTHERSRCS = Makefile.preamble Makefile Makefile.postamble\ - objc-msg-hppa-lock.s objc-msg-hppa-nolock.s\ - objc-msg-hppa-pdo.s objc-msg-hppa-pdo-pic.s objc-msg-i386.s\ - objc-msg-i386-nextpdo-winnt3.5.s objc-msg-ppc.s\ - objc-msg-m68k-lock.s objc-msg-m68k-nolock.s objc-msg-sparc.s\ - objc-msg-sparc-pdo.s + objc-msg-i386.s objc-msg-ppc.s OTHERLINKEDOFILES = objc-msg.o diff --git a/runtime/Messengers.subproj/Makefile.postamble b/runtime/Messengers.subproj/Makefile.postamble index 1ace51f..db6b4a2 100644 --- a/runtime/Messengers.subproj/Makefile.postamble +++ b/runtime/Messengers.subproj/Makefile.postamble @@ -65,13 +65,6 @@ # DEBUG_BUILD_LDFLAGS, OPTIMIZE_BUILD_LDFLAGS, PROFILE_BUILD_LDFLAGS: flags # passed to ld/libtool (defaults to nothing) -ifeq "$(PLATFORM_OS)" "solaris" -CODE_GEN_STYLE = STATIC -else -ifeq "$(PLATFORM_OS)" "hpux" -CODE_GEN_STYLE = STATIC -endif # hpux -endif # solaris # Library and Framework projects only: # INSTALL_NAME_DIRECTIVE: This directive ensures that executables linked diff --git a/runtime/Messengers.subproj/PB.project b/runtime/Messengers.subproj/PB.project index fd1a78e..d82efb2 100644 --- a/runtime/Messengers.subproj/PB.project +++ b/runtime/Messengers.subproj/PB.project @@ -8,17 +8,8 @@ Makefile.preamble, Makefile, Makefile.postamble, - "objc-msg-hppa-lock.s", - "objc-msg-hppa-nolock.s", - "objc-msg-hppa-pdo.s", - "objc-msg-hppa-pdo-pic.s", "objc-msg-i386.s", - "objc-msg-i386-nextpdo-winnt3.5.s", - "objc-msg-ppc.s", - "objc-msg-m68k-lock.s", - "objc-msg-m68k-nolock.s", - "objc-msg-sparc.s", - "objc-msg-sparc-pdo.s" + "objc-msg-ppc.s" ); SUBPROJECTS = (); }; diff --git a/runtime/Messengers.subproj/objc-msg-hppa-lock.s b/runtime/Messengers.subproj/objc-msg-hppa-lock.s deleted file mode 100644 index b55820a..0000000 --- a/runtime/Messengers.subproj/objc-msg-hppa-lock.s +++ /dev/null @@ -1,523 +0,0 @@ -/* - * Copyright (c) 1999 Apple Computer, Inc. All rights reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * Portions Copyright (c) 1999 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 1.1 (the "License"). You may not use this file - * except in compliance with the License. Please obtain a copy of the - * License at http://www.apple.com/publicsource 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 OR NON- INFRINGEMENT. Please see the - * License for the specific language governing rights and limitations - * under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ -#ifdef KERNEL -#define OBJC_LOCK_ROUTINE _simple_lock -#else -; _objc_entryPoints and _objc_exitPoints are used by moninitobjc() to setup -; objective-C messages for profiling. The are made private_externs when in -; a shared library. - .reference _moninitobjc - .const - .align 2 -.globl _objc_entryPoints -_objc_entryPoints: - .long _objc_msgSend - .long _objc_msgSendSuper - .long _objc_msgSendv - .long 0 - -.globl _objc_exitPoints -_objc_exitPoints: - .long Lexit1 - .long Lexit2 - .long Lexit3 - .long Lexit4 - .long Lexit5 - .long Lexit6 - .long Lexit7 - .long Lexit8 - .long 0 - -#define OBJC_LOCK_ROUTINE _spin_lock -#endif /* KERNEL */ - -#define isa 0 -#define cache 32 -#define mask 0 -#define buckets 8 -#define method_name 0 -#define method_imp 8 - - -; optimized for hppa: 20? clocks (best case) + 6 clocks / probe - - .text - .align 4 - .globl _objc_msgSend - -_objc_msgSend: - ldil L`__objc_multithread_mask,%r1 - ldw R`__objc_multithread_mask(%r1),%r19 - and,= %r19,%r26,%r19 - b,n L0 ; if (self & multi) goto normalcase - comiclr,= 0,%r26,0 - b,n LSendLocking ; else if (self) goto lockingcase - nop - bv 0(%r2) ; else return null - copy 0,%r28 ; return val = 0 -L0: - ldw isa(0,%r26),%r19 ; class = self->isa; - ldw cache(0,%r19),%r20 ; cache = class->cache - ldw mask(0,%r20),%r21 ; mask = cache->mask - ldo buckets(%r20),%r20 ; buckets = cache->buckets - and %r21,%r25,%r22 ; index = selector & mask; -L1: - ldwx,s %r22(0,%r20),%r19 ; method = cache->buckets[index]; - comib,=,n 0,%r19,LcacheMiss ; if (method == NULL) - ldw method_name(0,%r19),%r1 ; - addi 1,%r22,%r22 ; ++index - comb,<> %r1, %r25, L1 ; if (name!=sel) continue loop - and %r21,%r22,%r22 ; index &=mask - ldw method_imp(0,%r19),%r19 -Lexit1: - bv,n 0(%r19) ; goto *imp; (nullify delay) - -#ifdef MONINIT - .space 128 ; /* area for moninitobjc to write */ -#endif - -LcacheMiss: -; We have to save all the register based arguments (including floating -; point) before calling _class_lookupMethodAndLoadCache. This is because -; we do not know what arguments were passed to us, and the arguments are -; not guaranteed to be saved across procedure calls (they are all caller-saved) -; We also have to save the return address (since we did not save it on entry). - - - copy %r30,%r19 - ldo 128(%r30),%r30 ; Allocate space on stack - stwm %r2,4(0,%r19) ; Save return pointer - stwm %r23,4(0,%r19) ; Save old args - stwm %r24,4(0,%r19) ; - stwm %r25,4(0,%r19) ; - stwm %r26,4(0,%r19) ; -#ifndef KERNEL - fstds,mb %fr4,4(0,%r19) ; Save floating point args - fstds,mb %fr5,8(0,%r19) ; mb (modify before) is used instead - fstds,mb %fr6,8(0,%r19) ; of ma (as is implicit in above - fstds,mb %fr7,8(0,%r19) ; stores) with an initial value of 4 - ; so that doubles are aligned - ; to 8 byte boundaries. - ; Arg 1 (selector) is the same -#endif /* KERNEL */ - - stw %r28,8(0,%r19) ; save return struct ptr - ldw isa(0,%r26),%r26 ; arg 0 = self->isa - CALL_EXTERN(__class_lookupMethodAndLoadCache) - - ldo -128(%r30),%r30 ; deallocate - copy %r30,%r19 ; - ldwm 4(0,%r19),%r2 ; restore everything - ldwm 4(0,%r19),%r23 ; - ldwm 4(0,%r19),%r24 ; - ldwm 4(0,%r19),%r25 ; - ldwm 4(0,%r19),%r26 ; -#ifndef KERNEL - fldds,mb 4(0,%r19),%fr4 ; see comment above about alignment - fldds,mb 8(0,%r19),%fr5 ; - fldds,mb 8(0,%r19),%fr6 ; - fldds,mb 8(0,%r19),%fr7 ; -#endif /* KERNEL */ - ldw 8(0,%r19),%r20 ; get ret structure ptr - - copy %r28,%r19 - copy %r20,%r28 ; restore ret structure ptr -Lexit2: - bv,n 0(%r19) ; goto *imp (nullify delay) - -#ifdef MONINIT - .space 128 ; /* area for moninitobjc to write */ -#endif - - - -; Locking version of objc_msgSend -; uses spin_lock() to lock the mutex. - -LSendLocking: - copy %r30,%r19 - ldo 128(%r30),%r30 ; Allocate space on stack - stwm %r2,4(0,%r19) ; Save return pointer - stwm %r23,4(0,%r19) ; Save old args - stwm %r24,4(0,%r19) ; - stwm %r25,4(0,%r19) ; - stwm %r26,4(0,%r19) ; - stwm %r28,4(0,%r19) ; save return struct ptr -#ifndef KERNEL - fstds,ma %fr4,8(0,%r19) ; Save floating point args - fstds,ma %fr5,8(0,%r19) ; - fstds,ma %fr6,8(0,%r19) ; - fstds,ma %fr7,8(0,%r19) ; -#endif /* KERNEL */ - - ldil L`_messageLock,%r1 - ldo R`_messageLock(%r1),%r26 - ldil L`OBJC_LOCK_ROUTINE,%r1 ; call spin_lock() with _messageLock - ble R`OBJC_LOCK_ROUTINE(%sr4,%r1) - copy %r31,%r2 - ldw -112(%r30),%r26 ; restore arg0 - ldw -108(%r30),%r28 ; and ret0 (spin_lock doesnt - ; touch anything else important) - ldw isa(0,%r26),%r19 ; class = self->isa; - ldw cache(0,%r19),%r20 ; cache = class->cache - ldw mask(0,%r20),%r21 ; mask = cache->mask - ldo buckets(%r20),%r20 ; buckets = cache->buckets - and %r21,%r25,%r22 ; index = selector & mask; -LL1: - ldwx,s %r22(0,%r20),%r19 ; method = cache->buckets[index]; - comib,=,n 0,%r19,LL2 ; if (method == NULL) - ldw method_name(0,%r19),%r1 ; - addi 1,%r22,%r22 ; ++index - comb,<> %r1, %r25, LL1 ; if (name!=sel) continue loop - and %r21,%r22,%r22 ; index &=mask - ldw method_imp(0,%r19),%r19 -#if KERNEL - ldil L`_messageLock,%r1 - ldo R`_messageLock(%r1),%r20 - addi 0xc,%r20,%r20 - depi 0,31,4,%r20 - zdepi 1,31,1,%r1 - stw %r1,0(0,%r20) -#else - ldil L`_messageLock,%r1 - stw %r0,R`_messageLock(%r1) ; unlock the lock -#endif - ldwm -128(%r30),%r2 ; restore original rp and deallocate -Lexit3: - bv,n 0(%r19) ; goto *imp; (nullify delay) - -#ifdef MONINIT - .space 128 ; /* area for moninitobjc to write */ -#endif - -LL2: - ldw isa(0,%r26),%r26 ; arg 0 = self->isa - CALL_EXTERN_AGAIN(__class_lookupMethodAndLoadCache) - - ldo -128(%r30),%r30 ; deallocate - copy %r30,%r19 ; - ldwm 4(0,%r19),%r2 ; restore everything - ldwm 4(0,%r19),%r23 ; - ldwm 4(0,%r19),%r24 ; - ldwm 4(0,%r19),%r25 ; - ldwm 4(0,%r19),%r26 ; - ldwm 4(0,%r19),%r20 ; get ret structure ptr -#ifndef KERNEL - fldds,ma 8(0,%r19),%fr4 ; - fldds,ma 8(0,%r19),%fr5 ; - fldds,ma 8(0,%r19),%fr6 ; - fldds,ma 8(0,%r19),%fr7 ; -#endif /* KERNEL */ - - copy %r28,%r19 - copy %r20,%r28 ; restore ret structure ptr -#if KERNEL - ldil L`_messageLock,%r1 - ldo R`_messageLock(%r1),%r20 - addi 0xc,%r20,%r20 - depi 0,31,4,%r20 - zdepi 1,31,1,%r1 - stw %r1,0(0,%r20) -#else - ldil L`_messageLock,%r1 - stw %r0,R`_messageLock(%r1) ; unlock the lock -#endif -Lexit4: - bv,n 0(%r19) ; goto *imp (nullify delay) - -#ifdef MONINIT - .space 128 ; /* area for moninitobjc to write */ -#endif - - - - - -#define receiver 0 -#define class 4 - - .globl _objc_msgSendSuper -_objc_msgSendSuper: - ldil L`__objc_multithread_mask,%r1 - ldw R`__objc_multithread_mask(%r1),%r19 - combt,= %r0,%r19,LSuperLocking ; - ldw class(0,%r26),%r19 ; class = caller->class; - ldw cache(0,%r19),%r20 ; cache = class->cache - ldw mask(0,%r20),%r21 ; mask = cache->mask - ldo buckets(%r20),%r20 ; buckets = cache->buckets - and %r21,%r25,%r22 ; index = selector & mask; -LS1: ; - ldwx,s %r22(0,%r20),%r19 ; method = cache->buckets[index]; - comib,=,n 0,%r19,LS2 ; if (method == NULL) - ldw method_name(0,%r19),%r1; - addi 1,%r22,%r22 ; ++index - comb,<> %r1, %r25, LS1 ; if (name!=sel) continue loop - and %r21,%r22,%r22 ; index &=mask - ldw method_imp(0,%r19),%r19 - ldw receiver(0,%r26),%r26 ; self = caller->receiver; -Lexit5: - bv,n 0(%r19) ; goto *imp; (nullify delay) -#ifdef MONINIT - .space 128 ; /* area for moninitobjc to write */ -#endif - - ; -LS2: ; - copy %r30,%r19 - ldo 128(%r30),%r30 ; Allocate space on stack - stwm %r2,4(0,%r19) ; Save return pointer - stwm %r23,4(0,%r19) ; Save old args - stwm %r24,4(0,%r19) ; - stwm %r25,4(0,%r19) ; - stwm %r26,4(0,%r19) ; -#ifndef KERNEL - fstds,mb %fr4,4(0,%r19) ; Save floating point args - fstds,mb %fr5,8(0,%r19) ; mb (modify before) is used instead - fstds,mb %fr6,8(0,%r19) ; of ma (as is implicit in above - fstds,mb %fr7,8(0,%r19) ; stores) with an initial value of 4 - ; so that doubles are aligned - ; to 8 byte boundaries. - ; Arg 1 (selector) is the same -#endif /* KERNEL */ - stw %r28,8(0,%r19) ; save return struct ptr - ldw class(0,%r26),%r26 ; arg 0 = caller->class; - CALL_EXTERN_AGAIN(__class_lookupMethodAndLoadCache) - ldo -128(%r30),%r30 ; deallocate - copy %r30,%r19 ; - ldwm 4(0,%r19),%r2 ; restore everything - ldwm 4(0,%r19),%r23 ; - ldwm 4(0,%r19),%r24 ; - ldwm 4(0,%r19),%r25 ; - ldwm 4(0,%r19),%r26 ; -#ifndef KERNEL - fldds,mb 4(0,%r19),%fr4 ; see comment above about alignment - fldds,mb 8(0,%r19),%fr5 ; - fldds,mb 8(0,%r19),%fr6 ; - fldds,mb 8(0,%r19),%fr7 ; -#endif /* KERNEL */ - ldw 8(0,%r19),%r20 ; get ret structure ptr - ldw receiver(0,%r26),%r26 ; self = caller->receiver; - copy %r28,%r19 - copy %r20,%r28 -Lexit6: bv,n 0(%r19) ; goto *imp (nullify delay) - -#ifdef MONINIT - .space 128 ; /* area for moninitobjc to write */ -#endif - - - - - -; locking version of objc_msgSendSuper -; uses spin_lock() to lock the lock. - - -LSuperLocking: - copy %r30,%r19 - ldo 128(%r30),%r30 ; Allocate space on stack - stwm %r2,4(0,%r19) ; Save return pointer - stwm %r23,4(0,%r19) ; Save old args - stwm %r24,4(0,%r19) ; - stwm %r25,4(0,%r19) ; - stwm %r26,4(0,%r19) ; - stwm %r28,4(0,%r19) ; save return struct ptr -#ifndef KERNEL - fstds,ma %fr4,8(0,%r19) ; Save floating point args - fstds,ma %fr5,8(0,%r19) ; - fstds,ma %fr6,8(0,%r19) ; - fstds,ma %fr7,8(0,%r19) ; -#endif /* KERNEL */ - ldil L`_messageLock,%r1 - ldo R`_messageLock(%r1),%r26 - ldil L`OBJC_LOCK_ROUTINE,%r1 ; call spin_lock() with _messageLock - ble R`OBJC_LOCK_ROUTINE(%sr4,%r1) - copy %r31,%r2 - ldw -112(%r30),%r26 ; restore arg0 - ldw -108(%r30),%r28 ; and ret0 (spin_lock doesnt - ; touch anything else) - ldw class(0,%r26),%r19 ; class = caller->class; - ldw cache(0,%r19),%r20 ; cache = class->cache - ldw mask(0,%r20),%r21 ; mask = cache->mask - ldo buckets(%r20),%r20 ; buckets = cache->buckets - and %r21,%r25,%r22 ; index = selector & mask; -LLS1: ; - ldwx,s %r22(0,%r20),%r19 ; method = cache->buckets[index]; - comib,=,n 0,%r19,LLS2 ; if (method == NULL) - ldw method_name(0,%r19),%r1; - addi 1,%r22,%r22 ; ++index - comb,<> %r1, %r25, LLS1 ; if (name!=sel) continue loop - and %r21,%r22,%r22 ; index &=mask - ldw method_imp(0,%r19),%r19 - ldw receiver(0,%r26),%r26 ; self = caller->receiver; -#if KERNEL - ldil L`_messageLock,%r1 - ldo R`_messageLock(%r1),%r20 - addi 0xc,%r20,%r20 - depi 0,31,4,%r20 - zdepi 1,31,1,%r1 - stw %r1,0(0,%r20) -#else - ldil L`_messageLock,%r1 - stw %r0,R`_messageLock(%r1) ; unlock the lock -#endif - ldwm -128(%r30),%r2 ; restore original rp and deallocate -Lexit7: - bv,n 0(%r19) ; goto *imp; (nullify delay) -#ifdef MONINIT - .space 128 ; /* area for moninitobjc to write */ -#endif - - ; -LLS2: ; - ldw class(0,%r26),%r26 ; arg 0 = caller->class; - CALL_EXTERN_AGAIN(__class_lookupMethodAndLoadCache) - ldo -128(%r30),%r30 ; deallocate - copy %r30,%r19 ; - ldwm 4(0,%r19),%r2 ; restore everything - ldwm 4(0,%r19),%r23 ; - ldwm 4(0,%r19),%r24 ; - ldwm 4(0,%r19),%r25 ; - ldwm 4(0,%r19),%r26 ; - ldwm 4(0,%r19),%r20 ; get ret structure ptr -#ifndef KERNEL - fldds,ma 8(0,%r19),%fr4 ; - fldds,ma 8(0,%r19),%fr5 ; - fldds,ma 8(0,%r19),%fr6 ; - fldds,ma 8(0,%r19),%fr7 ; -#endif /* KERNEL */ - ldw receiver(0,%r26),%r26 ; self = caller->receiver; - copy %r28,%r19 - copy %r20,%r28 -#if KERNEL - ldil L`_messageLock,%r1 - ldo R`_messageLock(%r1),%r20 - addi 0xc,%r20,%r20 - depi 0,31,4,%r20 - zdepi 1,31,1,%r1 - stw %r1,0(0,%r20) -#else - ldil L`_messageLock,%r1 - stw %r0,R`_messageLock(%r1) ; unlock the lock -#endif -Lexit8: bv,n 0(%r19) ; goto *imp (nullify delay) - -#ifdef MONINIT - .space 128 ; /* area for moninitobjc to write */ -#endif - - - - - .objc_meth_var_names - .align 1 -L30: .ascii "forward::\0" - - .objc_message_refs - .align 2 -L31: .long L30 - - .cstring - .align 1 -L32: .ascii "Does not recognize selector %s\0" - - .text - .align 1 -; -; NOTE: Because the stack grows from low mem to high mem on this machine -; and the args go the other way, the marg_list pointer is to the first argument -; and subsequent arguments are at NEGATIVE offsets from the marg_list. -; This means that marg_getValue() and related macros will have to be adjusted -; appropriately. -; - .globl __objc_msgForward -__objc_msgForward: - stw %r2,-20(0,%r30) ; save rp - ldo 64(%r30),%r30 ; create frame area (no locals needed) - ldil L`L31,%r1 - ldo R`L31(%r1),%r19 - ldw 0(0,%r19),%r19 - combt,=,n %r19, %r25,L34 ; if (sel==@selector(forward::)) - ldo -112(%r30),%r20 ; ptr to arg3 homing area - stwm %r23,4(0,%r20) ; Mirror registers onto stack - stwm %r24,4(0,%r20) ; - stwm %r25,4(0,%r20) ; - stwm %r26,4(0,%r20) ; - - copy %r25,%r24 - copy %r19,%r25 ; [self forward:sel :marg_list] - - bl _objc_msgSend,%r2 - copy %r20,%r23 ; copy original sel - - ldo -64(%r30),%r30 ; deallocate - ldw -20(0,%r30),%r2 ; restore rp - bv,n 0(%r2) ; return -L34: - ldil L`L32,%r1 - ldo R`L32(%r1),%r25 - copy %r19,%r24 ; - BRANCH_EXTERN(__objc_error) - - -; Algorithm is as follows: -; . Calculate how much stack size is needed for any arguments not in the -; general registers and allocate space on stack. -; . Restore general argument regs from the bottom of the marg_list. -; . Restore fp argument regs from the same area. -; (The first two args in the marg list are always old obj and old SEL.) -; . Call the new method. - .globl _objc_msgSendv -_objc_msgSendv: - ; objc_msgSendv(self, sel, size, margs) - stw %r2,-20(0,%r30) ; Save rp - stw %r4,-36(0,%r30) ; Save callee-saved r4 - copy %r30,%r4 ; Save old sp vale - ldo 95(%r24),%r19 ; Calculate frame size, rounded - depi 0,31,6,%r19 ; up to 64 byte boundary... - - add %r19,%r30,%r30 ; Allocate frame area (no locals) - copy %r24,%r20 ; r20 now holds arg size - ldo -16(%r23),%r21 ; r21 now holds marg_list+16 - ldws 0(0,%r21),%r23 ; Get old general register args (dont - ldws 4(0,%r21),%r24 ; need first two: always self & SEL) -#ifndef KERNEL - fldds 0(0,%r21),%fr7 ; Mirror to fp regs - fldws 4(0,%r21),%fr6 ; -#endif /* KERNEL */ - - ldo -52(%r30),%r22 ; newly allocated stack area. - ldo -8(%r20),%r20 ; Size -= 8 - comibf,<,n 0,%r20,L36 -L35: ldws,mb -4(0,%r21),%r19 ; while(size>0) - addibf,<= -4,%r20,L35 ; { *(dest--) = *(src--); size-=4; } - stws,ma %r19,-4(0,%r22) ; -L36: bl _objc_msgSend,%r2 - nop - copy %r4,%r30 ; deallocate - ldw -36(0,%r30), %r4 - ldw -20(0,%r30), %r2 - bv,n 0(%r2) - - diff --git a/runtime/Messengers.subproj/objc-msg-hppa-nolock.s b/runtime/Messengers.subproj/objc-msg-hppa-nolock.s deleted file mode 100644 index 549beb2..0000000 --- a/runtime/Messengers.subproj/objc-msg-hppa-nolock.s +++ /dev/null @@ -1,307 +0,0 @@ -/* - * Copyright (c) 1999 Apple Computer, Inc. All rights reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * Portions Copyright (c) 1999 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 1.1 (the "License"). You may not use this file - * except in compliance with the License. Please obtain a copy of the - * License at http://www.apple.com/publicsource 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 OR NON- INFRINGEMENT. Please see the - * License for the specific language governing rights and limitations - * under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ -#ifdef KERNEL -#define OBJC_LOCK_ROUTINE _simple_lock -#else -; _objc_entryPoints and _objc_exitPoints are used by moninitobjc() to setup -; objective-C messages for profiling. The are made private_externs when in -; a shared library. - .reference _moninitobjc - .const - .align 2 -.globl _objc_entryPoints -_objc_entryPoints: - .long _objc_msgSend - .long _objc_msgSendSuper - .long 0 - -.globl _objc_exitPoints -_objc_exitPoints: - .long Lexit1 - .long Lexit5 - .long 0 - -#define OBJC_LOCK_ROUTINE _spin_lock -#endif /* KERNEL */ - -#define isa 0 -#define cache 32 -#define mask 0 -#define buckets 8 -#define method_name 0 -#define method_imp 8 - - -; optimized for hppa: 20? clocks (best case) + 6 clocks / probe - - .text - .align 4 - .globl _objc_msgSend - -_objc_msgSend: - comib,<>,n 0,%r26,L0 ; if (self) goto normalcase - nop - bv 0(%r2) ; else return null - copy 0,%r28 ; return val = 0 -L0: - ldw isa(0,%r26),%r19 ; class = self->isa; - ldw cache(0,%r19),%r20 ; cache = class->cache - ldw mask(0,%r20),%r21 ; mask = cache->mask - ldo buckets(%r20),%r20 ; buckets = cache->buckets - and %r21,%r25,%r22 ; index = selector & mask; -L1: - ldwx,s %r22(0,%r20),%r19 ; method = cache->buckets[index]; - comib,=,n 0,%r19,LcacheMiss ; if (method == NULL) - ldw method_name(0,%r19),%r1 ; - addi 1,%r22,%r22 ; ++index - comb,<> %r1, %r25, L1 ; if (name!=sel) continue loop - and %r21,%r22,%r22 ; index &=mask - ldw method_imp(0,%r19),%r19 -Lexit1: - bv,n 0(%r19) ; goto *imp; (nullify delay) - -#ifdef MONINIT - .space 128 ; /* area for moninitobjc to write */ -#endif - -LcacheMiss: -; We have to save all the register based arguments (including floating -; point) before calling _class_lookupMethodAndLoadCache. This is because -; we do not know what arguments were passed to us, and the arguments are -; not guaranteed to be saved across procedure calls (they are all caller-saved) -; We also have to save the return address (since we did not save it on entry). - - - copy %r30,%r19 - ldo 128(%r30),%r30 ; Allocate space on stack - stwm %r2,4(0,%r19) ; Save return pointer - stwm %r23,4(0,%r19) ; Save old args - stwm %r24,4(0,%r19) ; - stwm %r25,4(0,%r19) ; - stwm %r26,4(0,%r19) ; -#ifndef KERNEL - fstds,mb %fr4,4(0,%r19) ; Save floating point args - fstds,mb %fr5,8(0,%r19) ; mb (modify before) is used instead - fstds,mb %fr6,8(0,%r19) ; of ma (as is implicit in above - fstds,mb %fr7,8(0,%r19) ; stores) with an initial value of 4 - ; so that doubles are aligned - ; to 8 byte boundaries. - ; Arg 1 (selector) is the same -#endif /* KERNEL */ - - stw %r28,8(0,%r19) ; save return struct ptr - ldw isa(0,%r26),%r26 ; arg 0 = self->isa - CALL_EXTERN(__class_lookupMethodAndLoadCache) - - ldo -128(%r30),%r30 ; deallocate - copy %r30,%r19 ; - ldwm 4(0,%r19),%r2 ; restore everything - ldwm 4(0,%r19),%r23 ; - ldwm 4(0,%r19),%r24 ; - ldwm 4(0,%r19),%r25 ; - ldwm 4(0,%r19),%r26 ; -#ifndef KERNEL - fldds,mb 4(0,%r19),%fr4 ; see comment above about alignment - fldds,mb 8(0,%r19),%fr5 ; - fldds,mb 8(0,%r19),%fr6 ; - fldds,mb 8(0,%r19),%fr7 ; -#endif /* KERNEL */ - ldw 8(0,%r19),%r20 ; get ret structure ptr - - copy %r28,%r19 - copy %r20,%r28 ; restore ret structure ptr -Lexit2: - bv,n 0(%r19) ; goto *imp (nullify delay) - -#ifdef MONINIT - .space 128 ; /* area for moninitobjc to write */ -#endif - - - - - -#define receiver 0 -#define class 4 - - .globl _objc_msgSendSuper -_objc_msgSendSuper: - ldw class(0,%r26),%r19 ; class = caller->class; - ldw cache(0,%r19),%r20 ; cache = class->cache - ldw mask(0,%r20),%r21 ; mask = cache->mask - ldo buckets(%r20),%r20 ; buckets = cache->buckets - and %r21,%r25,%r22 ; index = selector & mask; -LS1: ; - ldwx,s %r22(0,%r20),%r19 ; method = cache->buckets[index]; - comib,=,n 0,%r19,LS2 ; if (method == NULL) - ldw method_name(0,%r19),%r1; - addi 1,%r22,%r22 ; ++index - comb,<> %r1, %r25, LS1 ; if (name!=sel) continue loop - and %r21,%r22,%r22 ; index &=mask - ldw method_imp(0,%r19),%r19 - ldw receiver(0,%r26),%r26 ; self = caller->receiver; -Lexit5: - bv,n 0(%r19) ; goto *imp; (nullify delay) -#ifdef MONINIT - .space 128 ; /* area for moninitobjc to write */ -#endif - - ; -LS2: ; - copy %r30,%r19 - ldo 128(%r30),%r30 ; Allocate space on stack - stwm %r2,4(0,%r19) ; Save return pointer - stwm %r23,4(0,%r19) ; Save old args - stwm %r24,4(0,%r19) ; - stwm %r25,4(0,%r19) ; - stwm %r26,4(0,%r19) ; -#ifndef KERNEL - fstds,mb %fr4,4(0,%r19) ; Save floating point args - fstds,mb %fr5,8(0,%r19) ; mb (modify before) is used instead - fstds,mb %fr6,8(0,%r19) ; of ma (as is implicit in above - fstds,mb %fr7,8(0,%r19) ; stores) with an initial value of 4 - ; so that doubles are aligned - ; to 8 byte boundaries. - ; Arg 1 (selector) is the same -#endif /* KERNEL */ - stw %r28,8(0,%r19) ; save return struct ptr - ldw class(0,%r26),%r26 ; arg 0 = caller->class; - CALL_EXTERN_AGAIN(__class_lookupMethodAndLoadCache) - - ldo -128(%r30),%r30 ; deallocate - copy %r30,%r19 ; - ldwm 4(0,%r19),%r2 ; restore everything - ldwm 4(0,%r19),%r23 ; - ldwm 4(0,%r19),%r24 ; - ldwm 4(0,%r19),%r25 ; - ldwm 4(0,%r19),%r26 ; -#ifndef KERNEL - fldds,mb 4(0,%r19),%fr4 ; see comment above about alignment - fldds,mb 8(0,%r19),%fr5 ; - fldds,mb 8(0,%r19),%fr6 ; - fldds,mb 8(0,%r19),%fr7 ; -#endif /* KERNEL */ - ldw 8(0,%r19),%r20 ; get ret structure ptr - ldw receiver(0,%r26),%r26 ; self = caller->receiver; - copy %r28,%r19 - copy %r20,%r28 -Lexit6: bv,n 0(%r19) ; goto *imp (nullify delay) - -#ifdef MONINIT - .space 128 ; /* area for moninitobjc to write */ -#endif - - -.objc_meth_var_names -.align 1 -L30: .ascii "forward::\0" - -.objc_message_refs -.align 2 -L31: .long L30 - -.cstring -.align 1 -L32: .ascii "Does not recognize selector %s\0" - -.text -.align 1 -; -; NOTE: Because the stack grows from low mem to high mem on this machine -; and the args go the other way, the marg_list pointer is to the first argument -; and subsequent arguments are at NEGATIVE offsets from the marg_list. -; This means that marg_getValue() and related macros will have to be adjusted -; appropriately. -; - .globl __objc_msgForward -__objc_msgForward: - stw %r2,-20(0,%r30) ; save rp - ldo 64(%r30),%r30 ; create frame area (no locals needed) - ldil L`L31,%r1 - ldo R`L31(%r1),%r19 - ldw 0(0,%r19),%r19 - combt,=,n %r19, %r25,L34 ; if (sel==@selector(forward::)) - ldo -112(%r30),%r20 ; ptr to arg3 homing area - stwm %r23,4(0,%r20) ; Mirror registers onto stack - stwm %r24,4(0,%r20) ; - stwm %r25,4(0,%r20) ; - stwm %r26,4(0,%r20) ; - - copy %r25,%r24 - copy %r19,%r25 ; [self forward:sel :marg_list] - - bl _objc_msgSend,%r2 - copy %r20,%r23 ; copy original sel - - ldo -64(%r30),%r30 ; deallocate - ldw -20(0,%r30),%r2 ; restore rp - bv,n 0(%r2) ; return -L34: - ldil L`L32,%r1 - ldo R`L32(%r1),%r25 - copy %r19,%r24 ; no need to clean up. - BRANCH_EXTERN(__objc_error) - - -; Algorithm is as follows: -; . Calculate how much stack size is needed for any arguments not in the -; general registers and allocate space on stack. -; . Restore general argument regs from the bottom of the marg_list. -; . Restore fp argument regs from the same area. -; (The first two args in the marg list are always old obj and old SEL.) -; . Call the new method. - .globl _objc_msgSendv -_objc_msgSendv: - ; objc_msgSendv(self, sel, size, margs) - stw %r2,-20(0,%r30) ; Save rp - stw %r4,-36(0,%r30) ; Save callee-saved r4 - copy %r30,%r4 ; Save old sp vale - ldo 95(%r24),%r19 ; Calculate frame size, rounded - depi 0,31,6,%r19 ; up to 64 byte boundary... - - add %r19,%r30,%r30 ; Allocate frame area (no locals) - copy %r24,%r20 ; r20 now holds arg size - ldo -16(%r23),%r21 ; r21 now holds marg_list+16 - ldws 0(0,%r21),%r23 ; Get old general register args (dont - ldws 4(0,%r21),%r24 ; need first two: always self & SEL) -#ifndef KERNEL - fldds,mb 0(0,%r21),%fr7 ; Mirror to fp regs - fldws 4(0,%r21),%fr6 ; -#endif /* KERNEL */ - - ldo -52(%r30),%r22 ; newly allocated stack area. - ldo -8(%r20),%r20 ; Size -= 8 - comibf,<,n 0,%r20,L36 -L35: ldws,mb -4(0,%r21),%r19 ; while(size>0) - addibf,<= -4,%r20,L35 ; { *(dest--) = *(src--); size-=4; } - stws,ma %r19,-4(0,%r22) ; -L36: bl _objc_msgSend,%r2 - nop - copy %r4,%r30 ; deallocate - ldw -36(0,%r30), %r4 - ldw -20(0,%r30), %r2 -Lexit9: - bv,n 0(%r2) - - diff --git a/runtime/Messengers.subproj/objc-msg-hppa-pdo-pic.s b/runtime/Messengers.subproj/objc-msg-hppa-pdo-pic.s deleted file mode 100644 index f33393b..0000000 --- a/runtime/Messengers.subproj/objc-msg-hppa-pdo-pic.s +++ /dev/null @@ -1,563 +0,0 @@ -/* - * Copyright (c) 1999 Apple Computer, Inc. All rights reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * Portions Copyright (c) 1999 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 1.1 (the "License"). You may not use this file - * except in compliance with the License. Please obtain a copy of the - * License at http://www.apple.com/publicsource 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 OR NON- INFRINGEMENT. Please see the - * License for the specific language governing rights and limitations - * under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ - -/* -** June 16, 1999 - Laurent Ramontianu -** A PIC/sanitized version of the standard hppa-pdo messenger -** for use with shared libraries. -*/ - - .SPACE $PRIVATE$ - .SUBSPA $DATA$,QUAD=1,ALIGN=8,ACCESS=31 - .SUBSPA $BSS$,QUAD=1,ALIGN=8,ACCESS=31,ZERO,SORT=82 - .SUBSPA $$OBJC_MESSAGE_REFS$$,QUAD=1,ALIGN=4,ACCESS=31 - .SPACE $TEXT$ - .SUBSPA $LIT$,QUAD=0,ALIGN=8,ACCESS=44 - .SUBSPA $CODE$,QUAD=0,ALIGN=8,ACCESS=44,CODE_ONLY - - .IMPORT _objc_msgSend_v,DATA - .IMPORT _objc_multithread_mask,DATA - .IMPORT messageLock,DATA - .IMPORT $$dyncall,MILLICODE - .IMPORT _class_lookupMethodAndLoadCache,CODE - .IMPORT __objc_error,CODE - - -#define isa 0 -#define cache 32 -#define mask 0 -#define buckets 8 -#define method_name 0 -#define method_imp 8 - -;; -;; objc_msgSend: Standard messenger -;; - - .SPACE $TEXT$ - .SUBSPA $CODE$ - .align 4 - .EXPORT objc_msgSend,CODE - .EXPORT objc_msgSend,ENTRY,PRIV_LEV=3,ARGW0=GR,ARGW1=GR,ARGW2=GR,ARGW3=GR -objc_msgSend - .PROC - .CALLINFO - .ENTRY - - comib,= 0,%arg0,L$exitNull ; Return 0 if self == nil - nop - - addil LT'_objc_multithread_mask,%r19 ; ' - ldw RT'_objc_multithread_mask(%r1),%r1 ; ' - ldw 0(0,%r1),%r1 - comib,= 0,%r1,L$lock ; lock if multithreaded - nop - -L$continue - ldw isa(0,%arg0),%r20 ; class = self->isa; - ldw cache(0,%r20),%r20 ; cache = class->cache - ldw mask(0,%r20),%r21 ; mask = cache->mask - ldo buckets(%r20),%r20 ; buckets = cache->buckets - and %r21,%arg1,%r22 ; index = selector & mask - -L$loop - ldwx,s %r22(0,%r20),%r1 ; method= cache->buckets[index] - comib,= 0,%r1,L$cacheMiss ; if (method == NULL) - nop - - ldw method_name(0,%r1),%r1 ; - comb,= %r1,%arg1,L$finishOff ; if (name=sel) break loop - nop - - addi 1,%r22,%r22 ; ++index - and %r22,%r21,%r22 ; index &= mask - b L$loop ; continue loop - nop - -L$finishOff - ldwx,s %r22(0,%r20),%r1 ; method= cache->buckets[index] - ldw method_imp(0,%r1),%r22 ; implementation into r22 - - addil LT'_objc_multithread_mask,%r19 ; ' - ldw RT'_objc_multithread_mask(%r1),%r1 ; ' - ldw 0(0,%r1),%r1 - comib,= 0,%r1,L$unlock ; unlock if multithreaded - nop - - b __next_dynjmp ; goto *imp - nop - -L$exitNull - bv 0(%rp) ; return null - copy 0,%ret0 ; return val = 0 - -L$lock - addil LT'messageLock,%r19 ; ' - ldw RT'messageLock(%r1),%r20 ; ' - addi 0xf,%r20,%r20 ; add 15 - depi 0,31,4,%r20 ; clear low byte to align on 16 -L$spin - ldcws 0(0,%r20),%r1 ; try to lock it - comib,= 0,%r1,L$spin ; if locked, try again - nop - - b L$continue ; rejoin mainline - nop ; - -L$unlock - addil LT'messageLock,%r19 ; ' - ldw RT'messageLock(%r1),%r20 ; ' - addi 0xf,%r20,%r20 ; add 15 - depi 0,31,4,%r20 ; clear low byte to align on 16 - ldi 1,%r1 ; get a one - stw %r1,0(0,%r20) ; clear lock - - b __next_dynjmp ; goto *imp - .EXIT - nop - -/* -** We have to save all the register based arguments (including floating -** point) before calling _class_lookupMethodAndLoadCache. This is because -** we don't know what arguments were passed to us, and the arguments are -** not guaranteed to be saved across procedure calls (they're all caller-saved) -** We also have to save the return address (since we didn't save it on entry). -*/ -L$cacheMiss - .CALLINFO FRAME=128,CALLS,SAVE_RP,SAVE_SP,ENTRY_GR=3 - .ENTRY - - copy %sp,%r1 ; save sp in r1 to use store modify - stwm %r3,128(0,%sp) ; save frame pointer & allocate stack - copy %r1,%r3 ; establish new frame pointer - - stw %rp,-20(0,%r3) ; save rp in frame marker - stw %sp,-4(0,%r3) ; save sp in frame marker - - stw %arg0,-36(0,%r3) ; save arg0 in fixed arg area - stw %arg1,-40(0,%r3) ; save arg1 in fixed arg area - stw %arg2,-44(0,%r3) ; save arg2 in fixed arg area - stw %arg3,-48(0,%r3) ; save arg3 in fixed arg area - stw %ret0,4(0,%r3) ; save return struct ptr - stw %ret1,8(0,%r3) ; save return struct ptr - - fstds,mb %fr4,8(0,%r1) ; Save floating point args - fstds,mb %fr5,8(0,%r1) ; mb (modify before) is used - fstds,mb %fr6,8(0,%r1) - fstds,mb %fr7,8(0,%r1) - - .CALL ARGW0=GR,ARGW1=GR - bl _class_lookupMethodAndLoadCache,2 - ldw isa(0,%arg0),%arg0 ; arg 0 = self->isa - - copy %ret0,%r22 ; move return value r22 for dynjmp - - copy %r3,%r1 ; prev frame for fldds,mb - fldds,mb 8(0,%r1),%fr4 - fldds,mb 8(0,%r1),%fr5 - fldds,mb 8(0,%r1),%fr6 - fldds,mb 8(0,%r1),%fr7 - - ldw 4(0,%r3),%ret0 ; restore everything - ldw 8(0,%r3),%ret1 ; restore everything - ldw -36(0,%r3),%arg0 - ldw -40(0,%r3),%arg1 - ldw -44(0,%r3),%arg2 - ldw -48(0,%r3),%arg3 - - ldw -20(0,%r3),%rp ; restore return pointer - ldwm -128(0,%sp),%r3 ; free stack,restore prev frame pointer - - addil LT'_objc_multithread_mask,%r19 ; ' - ldw RT'_objc_multithread_mask(%r1),%r1 ; ' - ldw 0(0,%r1),%r1 - comib,= 0,%r1,L$unlock ; unlock if multithreaded - nop - - b __next_dynjmp ; goto *imp - .EXIT - nop - .PROCEND - - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - -#define receiver 0 -#define class 4 - - .SPACE $TEXT$ - .SUBSPA $CODE$ - .align 4 - .EXPORT objc_msgSendSuper,CODE - .EXPORT objc_msgSendSuper,ENTRY,PRIV_LEV=3,ARGW0=GR,ARGW1=GR,ARGW2=GR,ARGW3=GR -objc_msgSendSuper - .PROC - .CALLINFO - .ENTRY - - addil LT'_objc_multithread_mask,%r19 ; ' - ldw RT'_objc_multithread_mask(%r1),%r1 ; ' - ldw 0(0,%r1),%r1 - comib,= 0,%r1,L$slock ; lock if multithreaded - nop - -L$scontinue - ldw class(0,%arg0),%r20 ; class = caller->class; - ldw cache(0,%r20),%r20 ; cache = class->cache - ldw mask(0,%r20),%r21 ; mask = cache->mask - ldo buckets(%r20),%r20 ; buckets = cache->buckets - and %r21,%arg1,%r22 ; index = selector & mask; - -L$sloop - ldwx,s %r22(0,%r20),%r1 ; method= cache->buckets[index] - comib,= 0,%r1,L$scacheMiss ; if (method == NULL) - nop - - ldw method_name(0,%r1),%r1 ; - comb,= %r1,%arg1,L$sfinishOff ; if (name=sel) break loop - nop - - addi 1,%r22,%r22 ; ++index - and %r22,%r21,%r22 ; index &= mask - b L$sloop ; continue loop - nop - -L$sfinishOff - ldwx,s %r22(0,%r20),%r1 ; method= cache->buckets[index] - ldw method_imp(0,%r1),%r22 ; implementation into r22 - - addil LT'_objc_multithread_mask,%r19 ; ' - ldw RT'_objc_multithread_mask(%r1),%r1 ; ' - ldw 0(0,%r1),%r1 - ldw receiver(0,%arg0),%arg0 ; self = caller->receiver; - comib,= 0,%r1,L$sunlock ; unlock if multithreaded - nop - - b __next_dynjmp ; goto *imp - nop - -L$slock - addil LT'messageLock,%r19 ; ' - ldw RT'messageLock(%r1),%r20 ; ' - addi 0xf,%r20,%r20 ; add 15 - depi 0,31,4,%r20 ; clear low byte to align on 16 -L$sspin - ldcws 0(0,%r20),%r1 ; try to lock it - comib,= 0,%r1,L$sspin ; if locked, try again - nop - - b L$scontinue ; rejoin mainline - nop ; - -L$sunlock - addil LT'messageLock,%r19 ; ' - ldw RT'messageLock(%r1),%r20 ; ' - addi 0xf,%r20,%r20 ; add 15 - depi 0,31,4,%r20 ; clear low byte to align on 16 - ldi 1,%r1 ; get a one - stw %r1,0(0,%r20) ; clear lock - - b __next_dynjmp ; goto *imp - .EXIT - nop - -L$scacheMiss - .CALLINFO FRAME=128,CALLS,SAVE_RP,SAVE_SP,ENTRY_GR=3 - .ENTRY - - copy %sp,%r1 ; save sp in r1 to use store modify - stwm %r3,128(0,%sp) ; save frame pointer & allocate stack - copy %r1,%r3 ; establish new frame pointer - - stw %rp,-20(0,%r3) ; save rp in frame marker - stw %sp,-4(0,%r3) ; save sp in frame marker - - stw %arg0,-36(0,%r3) ; save arg0 in fixed arg area - stw %arg1,-40(0,%r3) ; save arg1 in fixed arg area - stw %arg2,-44(0,%r3) ; save arg2 in fixed arg area - stw %arg3,-48(0,%r3) ; save arg3 in fixed arg area - stw %ret0,4(0,%r3) ; save return struct ptr - stw %ret1,8(0,%r3) ; save return struct ptr - - fstds,mb %fr4,8(0,%r1) ; Save floating point args - fstds,mb %fr5,8(0,%r1) ; mb (modify before) is used - fstds,mb %fr6,8(0,%r1) - fstds,mb %fr7,8(0,%r1) - - .CALL ARGW0=GR,ARGW1=GR - bl _class_lookupMethodAndLoadCache,2 - ldw class(0,%arg0),%arg0 ; arg0 = caller->class - - copy %ret0,%r22 ; move return value to r22 for dynjmp - - copy %r3,%r1 ; prev frame for fldds,mb - fldds,mb 8(0,%r1),%fr4 - fldds,mb 8(0,%r1),%fr5 - fldds,mb 8(0,%r1),%fr6 - fldds,mb 8(0,%r1),%fr7 - - ldw 4(0,%r3),%ret0 ; restore everything - ldw 8(0,%r3),%ret1 ; restore everything - ldw -36(0,%r3),%arg0 - ldw -40(0,%r3),%arg1 - ldw -44(0,%r3),%arg2 - ldw -48(0,%r3),%arg3 - - ldw -20(0,%r3),%rp ; restore return pointer - ldwm -128(0,%sp),%r3 ; free stack, restore prev frame pointer - - addil LT'_objc_multithread_mask,%r19 ; ' - ldw RT'_objc_multithread_mask(%r1),%r1 ; ' - ldw 0(0,%r1),%r1 - ldw receiver(0,%arg0),%arg0 ; self = caller->receiver; - comib,= 0,%r1,L$sunlock ; unlock if multithreaded - nop - - b __next_dynjmp ; goto *imp - .EXIT - nop - .PROCEND - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - - .SPACE $PRIVATE$ - .SUBSPA $DATA$ - .align 4 - .EXPORT OBJC_METH_VAR_NAME_FORWARD,DATA - -OBJC_METH_VAR_NAME_FORWARD: - .STRING "forward::\0" - - .SPACE $PRIVATE$ - .SUBSPA $$OBJC_MESSAGE_REFS$$ - .align 4 -forwardstr - .word OBJC_METH_VAR_NAME_FORWARD - - .SPACE $PRIVATE$ - .SUBSPA $DATA$ -; .cstring -; .align 1 -errstr - .string "Does not recognize selector %s\0" - -; -; NOTE: Because the stack grows from low mem to high mem on this machine -; and the args go the other way, the marg_list pointer is 4 above the first arg -; and subsequent arguments are at NEGATIVE offsets from the marg_list. -; This means that marg_getValue() and related macros will have to be adjusted -; appropriately. -; - .SPACE $TEXT$ - .SUBSPA $CODE$ - .align 4 - .EXPORT _objc_msgForward,CODE - .EXPORT _objc_msgForward,ENTRY,PRIV_LEV=3,ARGW0=GR,ARGW1=GR,ARGW2=GR,ARGW3=GR -_objc_msgForward - .PROC - .CALLINFO FRAME=128,CALLS,SAVE_RP,SAVE_SP,ENTRY_GR=3 - .ENTRY - - copy %sp,%r1 ; save sp - stwm %r3,128(0,%sp) ; save frame pointer & allocate stack - copy %r1,%r3 ; establish new frame pointer - - stw %rp, -20(0,%r3) ; save rp in frame marker - stw %sp, -4(0,%r3) ; save sp in frame marker - stw %arg3,-48(0,%r3) ; save args in fixed arg area - stw %arg2,-44(0,%r3) ; ... - stw %arg1,-40(0,%r3) ; _cmd selector (arg1) - stw %arg0,-36(0,%r3) ; self - - addil LT'forwardstr,%r19 ; ' - ldw RT'forwardstr(%r1),%r20 ; ' - ldw 0(0,%r20),%r20 ; get forward:: - combt,= %r20,%arg1,L$error ; if (sel==@selector(forward::)) - nop - - ; Set up call as [self forward:sel :marg_list] - copy %arg1,%arg2 ; original selector in arg2 - copy %r20,%arg1 ; forward:: as arg1 (_cmd) - ldo -32(%r3),%arg3 ; copy original sel - - addil LT'_objc_msgSend_v,%r19 ; ' - ldw RT'_objc_msgSend_v(%r1),%r1 ; ' - ldw 0(0,%r1),%r22 - .CALL ARGW0=GR - bl $$dyncall,%r31 - copy %r31,%r2 - - ldw -20(0,%r3),%rp ; restore RP - bv 0(%rp) ; return to caller - ldwm -128(0,%sp),%r3 ; free stack, restore prev frame pointer - -L$error - addil LT'errstr,%r19 ; ' - ldw RT'errstr(%r1),%arg1 ; ' - .CALL ARGW0=GR,ARGW1=GR - bl __objc_error,%rp ; __objc_error never returns, - .EXIT - copy %r20,%arg2 ; so no need to clean up. - .PROCEND - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - -; Algorithm is as follows: -; . Calculate how much stack size is needed for any arguments not in the -; general registers and allocate space on stack. -; . Restore general argument regs from the bottom of the marg_list. -; . Restore fp argument regs from the same area. -; The first two args in the marg list are always old obj and struct -; return address - since old selector (_cmd) is not needed, struct -; return (which might be needed) is stashed in place of _cmd. -; . Call the new method. - - .SPACE $TEXT$ - .SUBSPA $CODE$ - .align 4 - .EXPORT objc_msgSendv,CODE - .EXPORT objc_msgSendv,ENTRY,PRIV_LEV=3,ARGW0=GR,ARGW1=GR,ARGW2=GR,ARGW3=GR -objc_msgSendv - .PROC - .CALLINFO FRAME=128,CALLS,SAVE_RP,SAVE_SP,ENTRY_GR=3 - .ENTRY - - copy %sp,%r1 ; save sp - stwm %r3,128(0,%sp) ; save frame pointer & allocate stack - copy %r1,%r3 ; establish new frame pointer - - stw %rp, -20(0,%r3) ; save rp in frame marker - stw %sp, -4(0,%r3) ; save sp in frame marker - - ldo 95(%arg2),%r1 ; Calculate frame size, rounded - depi 0,31,6,%r1 ; up to 64 byte boundary... - add %r1,%sp,%sp ; Allocate frame area (no locals) - - copy %arg2,%r20 ; r20 now holds arg size - ldo -16(%arg3),%r21 ; r21 now holds marg_list+16 - ldws 0(0,%r21),%arg3 ; Get old general register args 2-3 - ldws 4(0,%r21),%arg2 ; (self and sel not needed) - fldds 0(0,%r21),%fr7 ; Mirror to fp regs - fldws 4(0,%r21),%fr6 ; ditto - - ldo -52(%sp),%r22 ; newly allocated stack area. - ldo -8(%r20),%r20 ; Size -= 8 - comibf,< 0,%r20,L$L36 - nop -L$L35 - ldws,mb -4(0,%r21),%r1 ; while(size>0) - addibf,<= -4,%r20,L$L35 ; { *(dest--) = *(src--); size-=4; } - stws,ma %r1,-4(0,%r22) ; - -L$L36 - addil LT'_objc_msgSend_v,%r19 ; ' - ldw RT'_objc_msgSend_v(%r1),%r1 ; ' - ldw 0(0,%r1),%r22 - .CALL ARGW0=GR - bl $$dyncall,%r31 - copy %r31,%r2 - - ldw -20(0,%r3),%rp ; restore RP - ldo 128(%r3),%sp ; restore SP (free variable space) - - ldwm -128(0,%sp),%r3 ; restore frame pointer & free stack - bv 0(%rp) ; return to caller - .EXIT - nop - .PROCEND - - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -;; -;; -;; lock/unlock routines -;; -;; - -;; -;; Lock routine -;; - .SPACE $TEXT$ - .SUBSPA $CODE$ - .align 4 - .EXPORT _objc_private_lock,CODE - .EXPORT _objc_private_lock,ENTRY,PRIV_LEV=3,ARGW0=GR,ARGW1=GR,ARGW2=GR,ARGW3=GR -_objc_private_lock - .PROC - .CALLINFO FRAME=0,NO_CALLS - .ENTRY - addi 0xf,%arg0,%arg0 ; add 15 - depi 0,31,4,%arg0 ; clear low byte to align on 16 -L_lockspin: - ldcws 0(0,%arg0),%r1 ; try to lock it - comib,= 0,%r1,L_lockspin ; if had 0, try again - nop ; - .EXIT - bv,n 0(%rp) ; return - .PROCEND - -;; -;; Unlock routine -;; - .SPACE $TEXT$ - .SUBSPA $CODE$ - .align 4 - .EXPORT _objc_private_unlock,CODE - .EXPORT _objc_private_unlock,ENTRY,PRIV_LEV=3,ARGW0=GR,ARGW1=GR,ARGW2=GR,ARGW3=GR -_objc_private_unlock - .PROC - .CALLINFO FRAME=0,NO_CALLS - .ENTRY - addi 0xf,%arg0,%arg0 ; add 15 - depi 0,31,4,%arg0 ; clear low byte to align on 16 - ldi 1,%r1 ; get a one - bv 0(%rp) ; return - .EXIT - stw %r1,0(0,%arg0) ; clear lock - .PROCEND - -;; -;; __next_dynjmp routine -;; - .SPACE $TEXT$ - .SUBSPA $CODE$ - .align 4 - .EXPORT __next_dynjmp,CODE - .EXPORT __next_dynjmp,ENTRY,PRIV_LEV=3,ARGW0=GR,ARGW1=GR,ARGW2=GR,ARGW3=GR -__next_dynjmp - .PROC - .CALLINFO FRAME=0,NO_CALLS - .ENTRY - bb,>=,n %r22,0x1e,L$jumpExternal - depi 0,31,2,%r22 - ldws 4(%sr0,%r22),%r19 - ldws 0(%sr0,%r22),%r22 -L$jumpExternal - ldsid (%sr0,%r22),%r1 - mtsp %r1,%sr0 - be 0(%sr0,%r22) - .EXIT - nop - .PROCEND - diff --git a/runtime/Messengers.subproj/objc-msg-hppa-pdo.s b/runtime/Messengers.subproj/objc-msg-hppa-pdo.s deleted file mode 100644 index 06b403b..0000000 --- a/runtime/Messengers.subproj/objc-msg-hppa-pdo.s +++ /dev/null @@ -1,438 +0,0 @@ -/* - * Copyright (c) 1999 Apple Computer, Inc. All rights reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * Portions Copyright (c) 1999 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 1.1 (the "License"). You may not use this file - * except in compliance with the License. Please obtain a copy of the - * License at http://www.apple.com/publicsource 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 OR NON- INFRINGEMENT. Please see the - * License for the specific language governing rights and limitations - * under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ -/* -** 9605: Dan Schmidt (DSG&A) -** Modified to clean up the calling conventions on all routines. -** This allows gdb to back trace from and through these routines. -*/ - -#define isa 0 -#define cache 32 -#define mask 0 -#define buckets 8 -#define method_name 0 -#define method_imp 8 - -;; -;; Objc_msgSend: Standard messenger -;; optimized for hppa: 20? clocks (best case) + 6 clocks / probe -;; - - .CODE -objc_msgSend - .PROC - .CALLINFO - .ENTRY - - comib,=,n 0,%arg0,L$exitNull ; Return 0 if self == nil - ldil L'_objc_multithread_mask,%r20 ; ' - ldw R'_objc_multithread_mask(%r20),%r31 ; ' - comib,= 0,%r31,L$lock ; lock if multithreaded - ldw isa(0,%arg0),%r19 ; class = self->isa; -L$continue - ldw cache(0,%r19),%r20 ; cache = class->cache - ldw mask(0,%r20),%r21 ; mask = cache->mask - ldo buckets(%r20),%r20 ; buckets = cache->buckets - and %r21,%arg1,%r22 ; index = selector & mask -L$loop - ldwx,s %r22(0,%r20),%r19 ; method = cache->buckets[index] - comib,=,n 0,%r19,L$cacheMiss ; if (method == NULL) - ldw method_name(0,%r19),%r1 ; - addi 1,%r22,%r22 ; ++index - comb,<> %r1,%arg1,L$loop ; if (name!=sel) continue loop - and %r21,%r22,%r22 ; index &=mask - ldw method_imp(0,%r19),%r22 ; Implementation into r22 - comib,=,n 0,%r31,L$unlock ; unlock if multithreaded - b $$dyncall ; goto *imp; - nop - -L$exitNull - bv 0(%rp) ; return null - copy 0,%ret0 ; return val = 0 - -L$lock - ldil L'messageLock,%r1 ; ' - ldo R'messageLock(%r1),%r20 ; ' - addi 0xf,%r20,%r20 ; add 15 - depi 0,31,4,%r20 ; clear low byte to align on 16 -L$spin - ldcws 0(0,%r20),%r1 ; try to lock it - comib,= 0,%r1,L$spin ; if locked, try again - nop ; - b L$continue ; rejoin mainline - nop ; - -L$unlock - ldil L'messageLock,%r1 ; ' - ldo R'messageLock(%r1),%r20 ; ' - addi 0xf,%r20,%r20 ; add 15 - depi 0,31,4,%r20 ; clear low byte to align on 16 - ldi 1,%r1 ; get a one - b $$dyncall ; goto *imp; - .EXIT - stw %r1,0(0,%r20) ; clear lock - -/* -** We have to save all the register based arguments (including floating -** point) before calling _class_lookupMethodAndLoadCache. This is because -** we don't know what arguments were passed to us, and the arguments are -** not guaranteed to be saved across procedure calls (they're all caller-saved) -** We also have to save the return address (since we didn't save it on entry). -*/ -L$cacheMiss - .CALLINFO FRAME=80, CALLS, SAVE_RP, SAVE_SP, ENTRY_GR=3 - .ENTRY - - copy %sp,%r19 ; save sp in r19 to use store modify - stwm %r3,128(0,%sp) ; save frame pointer & allocate stack - copy %r19,%r3 ; establish new frame pointer - - stw %rp, -20(0,%r3) ; save rp in frame marker - stw %sp, -4(0,%r3) ; save sp in frame marker - stw %arg0,-36(0,%r3) ; save arg0 in fixed arg area - stw %arg1,-40(0,%r3) ; save arg1 in fixed arg area - stw %arg2,-44(0,%r3) ; save arg2 in fixed arg area - stw %arg3,-48(0,%r3) ; save arg3 in fixed arg area - stw %ret0, 4(0,%r3) ; save return struct ptr - - fstds,mb %fr4,8(0,%r19) ; Save floating point args - fstds,mb %fr5,8(0,%r19) ; mb (modify before) is used - fstds,mb %fr6,8(0,%r19) - fstds,mb %fr7,8(0,%r19) - - .CALL - bl _class_lookupMethodAndLoadCache,2 - ldw isa(0,%arg0),%arg0 ; arg 0 = self->isa - copy %ret0,%r22 ; move return value r22 for dyncall - - copy %r3,%r19 ; prev frame for fldds,mb - fldds,mb 8(0,%r19),%fr4 - fldds,mb 8(0,%r19),%fr5 - fldds,mb 8(0,%r19),%fr6 - fldds,mb 8(0,%r19),%fr7 - - ldw 4(0,%r3),%ret0 ; restore everything - ldw -36(0,%r3),%arg0 - ldw -40(0,%r3),%arg1 - ldw -44(0,%r3),%arg2 - ldw -48(0,%r3),%arg3 - ldw -20(0,%r3),%rp ; restore return pointer - ldwm -128(0,%sp),%r3 ; free stack, restore prev frame pointer - - ldil L'_objc_multithread_mask,%r20 ; ' - ldw R'_objc_multithread_mask(%r20),%r20 ; ' - comib,= 0,%r20,L$unlock ; unlock if multithreaded - nop ; delay slot - - b $$dyncall ; goto *imp (in r22); - .EXIT - nop - .PROCEND - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - -#define receiver 0 -#define class 4 - -objc_msgSendSuper - .PROC - .CALLINFO - .ENTRY - - ldil L'_objc_multithread_mask,%r20 ; ' - ldw R'_objc_multithread_mask(%r20),%r31 ; ' - comib,= 0,%r31,L$slock ; lock if multithreaded - ldw class(0,%arg0),%r19 ; class = caller->class; -L$scontinue - ldw cache(0,%r19),%r20 ; cache = class->cache - ldw mask(0,%r20),%r21 ; mask = cache->mask - ldo buckets(%r20),%r20 ; buckets = cache->buckets - and %r21,%arg1,%r22 ; index = selector & mask; -L$LS1 - ldwx,s %r22(0,%r20),%r19 ; method = cache->buckets[index] - comib,=,n 0,%r19,L$cacheMiss2 ; if (method == NULL) - ldw method_name(0,%r19),%r1 ; get method name - addi 1,%r22,%r22 ; ++index - comb,<> %r1, %arg1, L$LS1 ; if (name!=sel) continue loop - and %r21,%r22,%r22 ; index &=mask - ldw method_imp(0,%r19),%r22 ; get method implementation - comib,= 0,%r31,L$sunlock ; unlock if multithreaded - ldw receiver(0,%arg0),%arg0 ; self = caller->receiver; - b $$dyncall ; goto *imp (in r22); - nop - -L$slock - ldil L'messageLock,%r1 ; ' - ldo R'messageLock(%r1),%r20 ; ' - addi 0xf,%r20,%r20 ; add 15 - depi 0,31,4,%r20 ; clear low byte to align on 16 -L$sspin - ldcws 0(0,%r20),%r1 ; try to lock it - comib,= 0,%r1,L$sspin ; if locked, try again - nop ; - b L$scontinue ; rejoin mainline - nop ; - -L$sunlock - ldil L'messageLock,%r1 ; ' - ldo R'messageLock(%r1),%r20 ; ' - addi 0xf,%r20,%r20 ; add 15 - depi 0,31,4,%r20 ; clear low byte to align on 16 - ldi 1,%r1 ; get a one - b $$dyncall ; goto *imp (in r22); - .EXIT - stw %r1,0(0,%r20) ; clear lock - -L$cacheMiss2 - .CALLINFO FRAME=80, CALLS, SAVE_RP, SAVE_SP, ENTRY_GR=3 - .ENTRY - - copy %sp,%r19 ; save sp in r19 to use store modify - stwm %r3,128(0,%sp) ; save frame pointer & allocate stack - copy %r19,%r3 ; establish new frame pointer - - stw %rp, -20(0,%r3) ; save rp in frame marker - stw %sp, -4(0,%r3) ; save sp in frame marker - stw %arg0,-36(0,%r3) ; save arg0 in fixed arg area - stw %arg1,-40(0,%r3) ; save arg1 in fixed arg area - stw %arg2,-44(0,%r3) ; save arg2 in fixed arg area - stw %arg3,-48(0,%r3) ; save arg3 in fixed arg area - stw %ret0, 4(0,%r3) ; save return struct ptr - - fstds,mb %fr4,8(0,%r19) ; Save floating point args - fstds,mb %fr5,8(0,%r19) ; mb (modify before) is used - fstds,mb %fr6,8(0,%r19) - fstds,mb %fr7,8(0,%r19) - - .CALL - bl _class_lookupMethodAndLoadCache,2 - ldw class(0,%arg0),%arg0 ; arg0 = caller->class; - copy %ret0,%r22 ; move return value r22 for dyncall - - copy %r3,%r19 ; prev frame for fldds,mb - fldds,mb 8(0,%r19),%fr4 - fldds,mb 8(0,%r19),%fr5 - fldds,mb 8(0,%r19),%fr6 - fldds,mb 8(0,%r19),%fr7 - - ldw 4(0,%r3),%ret0 ; restore everything - ldw -36(0,%r3),%arg0 - ldw -40(0,%r3),%arg1 - ldw -44(0,%r3),%arg2 - ldw -48(0,%r3),%arg3 - ldw -20(0,%r3),%rp ; restore return pointer - ldwm -128(0,%sp),%r3 ; free stack, restore prev frame pointer - - ldil L'_objc_multithread_mask,%r20 ; ' - ldw R'_objc_multithread_mask(%r20),%r20 ; ' - comib,= 0,%r20,L$unlock ; unlock if multithreaded - ldw receiver(0,%arg0),%arg0 ; self = caller->receiver; - - b $$dyncall ; goto *imp (in r22); - .EXIT - nop - .PROCEND - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - - .EXPORT OBJC_METH_VAR_NAME_FORWARD,DATA - .SPACE $PRIVATE$ - .SUBSPA $DATA$ -OBJC_METH_VAR_NAME_FORWARD: - .STRING "forward::\0" - - .SUBSPA $$OBJC_MESSAGE_REFS$$,QUAD=1,ALIGN=4,ACCESS=31 -forwardstr - .word OBJC_METH_VAR_NAME_FORWARD - - .DATA -; .cstring -; .align 1 -errstr - .string "Does not recognize selector %s\0" - - .CODE - -; -; NOTE: Because the stack grows from low mem to high mem on this machine -; and the args go the other way, the marg_list pointer is 4 above the first arg -; and subsequent arguments are at NEGATIVE offsets from the marg_list. -; This means that marg_getValue() and related macros will have to be adjusted -; appropriately. -; -_objc_msgForward - .PROC - .CALLINFO FRAME=80, CALLS, SAVE_RP, SAVE_SP, ENTRY_GR=3 - .ENTRY - - copy %sp,%r19 ; save sp - stwm %r3,128(0,%sp) ; save frame pointer & allocate stack - copy %r19,%r3 ; establish new frame pointer - - stw %rp, -20(0,%r3) ; save rp in frame marker - stw %sp, -4(0,%r3) ; save sp in frame marker - stw %arg3,-48(0,%r3) ; save args in fixed arg area - stw %arg2,-44(0,%r3) ; - stw %arg1,-40(0,%r3) ; _cmd selector (arg1) - stw %arg0,-36(0,%r3) ; self - - addil L'forwardstr-$global$,%dp ; ' - ldo R'forwardstr-$global$(%r1),%r20 ; ' - ldw 0(0,%r20),%r20 ; get forward:: - combt,=,n %r20,%arg1,L$error ; if (sel==@selector(forward::)) - - ; Set up call as [self forward:sel :marg_list] - copy %arg1,%arg2 ; original selector in arg2 - copy %r20,%arg1 ; forward:: as arg1 (_cmd) - - .CALL ARGW0=GR,ARGW1=GR,ARGW2=GR,ARGW3=GR - bl objc_msgSend,2 ; call forward:: - ldo -32(%r3),%arg3 ; copy original sel - - ldw -20(0,%r3),%rp ; restore RP - bv 0(%rp) ; return to caller - ldwm -128(0,%sp),%r3 ; free stack, restore prev frame pointer - -L$error - addil L'errstr-$global$,%dp ; ' - ldo R'errstr-$global$(%r1),%arg1 ; ' - .CALL ARGW0=GR,ARGW1=GR - bl __objc_error,%rp ; __objc_error never returns, - .EXIT - copy %r20,%arg2 ; so no need to clean up. - .PROCEND - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - -; Algorithm is as follows: -; . Calculate how much stack size is needed for any arguments not in the -; general registers and allocate space on stack. -; . Restore general argument regs from the bottom of the marg_list. -; . Restore fp argument regs from the same area. -; The first two args in the marg list are always old obj and struct -; return address - since old selector (_cmd) is not needed, struct -; return (which might be needed) is stashed in place of _cmd. -; . Call the new method. - -objc_msgSendv - .PROC - .CALLINFO FRAME=80, CALLS, SAVE_RP, SAVE_SP, ENTRY_GR=3 - .ENTRY - - copy %sp,%r19 ; save sp - stwm %r3,128(0,%sp) ; save frame pointer & allocate stack - copy %r19,%r3 ; establish new frame pointer - - stw %rp, -20(0,%r3) ; save rp in frame marker - stw %sp, -4(0,%r3) ; save sp in frame marker - - ldo 95(%arg2),%r19 ; Calculate frame size, rounded - depi 0,31,6,%r19 ; up to 64 byte boundary... - add %r19,%sp,%sp ; Allocate frame area (no locals) - - copy %arg2,%r20 ; r20 now holds arg size - ldo -16(%arg3),%r21 ; r21 now holds marg_list+16 - ldws 0(0,%r21),%arg3 ; Get old general register args 2-3 - ldws 4(0,%r21),%arg2 ; (self and sel not needed) - fldds 0(0,%r21),%fr7 ; Mirror to fp regs - fldws 4(0,%r21),%fr6 ; ditto - - ldo -52(%sp),%r22 ; newly allocated stack area. - ldo -8(%r20),%r20 ; Size -= 8 - comibf,<,n 0,%r20,L$L36 -L$L35 - ldws,mb -4(0,%r21),%r19 ; while(size>0) - addibf,<= -4,%r20,L$L35 ; { *(dest--) = *(src--); size-=4; } - stws,ma %r19,-4(0,%r22) ; - - .CALL ARGW0=GR,ARGW1=GR,ARGW2=GR,ARGW3=GR -L$L36 - bl objc_msgSend,2 ; Call method - nop - - ldw -20(0,%r3),%rp ; restore RP - ldo 128(%r3),%sp ; restore SP (free variable space) - bv 0(%rp) ; return to caller - .EXIT - ldwm -128(0,%sp),%r3 ; restore frame pointer & free stack - .PROCEND - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -;; -;; -;; Lock routines -;; -;; - -;; -;; Lock routine -;; -_objc_private_lock - .PROC - .CALLINFO FRAME=0,NO_CALLS - .ENTRY - addi 0xf,%arg0,%arg0 ; add 15 - depi 0,31,4,%arg0 ; clear low byte to align on 16 -L_lockspin: - ldcws 0(0,%arg0),%r1 ; try to lock it - comib,= 0,%r1,L_lockspin ; if had 0, try again - nop ; - .EXIT - bv,n 0(%rp) ; return - .PROCEND -;; -;; Unlock routine -;; -_objc_private_unlock - .PROC - .CALLINFO FRAME=0,NO_CALLS - .ENTRY - addi 0xf,%arg0,%arg0 ; add 15 - depi 0,31,4,%arg0 ; clear low byte to align on 16 - ldi 1,%r1 ; get a one - bv 0(%rp) ; return - .EXIT - stw %r1,0(0,%arg0) ; clear lock - .PROCEND - -; -; -; Imports and Exports -; -; - - .IMPORT $global$,DATA - .IMPORT $$dyncall,MILLICODE - .IMPORT _objc_multithread_mask,DATA - .IMPORT messageLock,DATA - .IMPORT _class_lookupMethodAndLoadCache,CODE - .IMPORT __objc_error,CODE - - .EXPORT objc_msgSend, ENTRY,PRIV_LEV=3,ARGW0=GR,ARGW1=GR,ARGW2=GR,ARGW3=GR - .EXPORT objc_msgSendv, ENTRY,PRIV_LEV=3,ARGW0=GR,ARGW1=GR,ARGW2=GR,ARGW3=GR - .EXPORT objc_msgSendSuper, ENTRY,PRIV_LEV=3,ARGW0=GR,ARGW1=GR,ARGW2=GR,ARGW3=GR - .EXPORT _objc_msgForward, ENTRY,PRIV_LEV=3,ARGW0=GR,ARGW1=GR,ARGW2=GR,ARGW3=GR - .EXPORT _objc_private_lock, ENTRY,PRIV_LEV=3,ARGW0=GR - .EXPORT _objc_private_unlock,ENTRY,PRIV_LEV=3,ARGW0=GR - diff --git a/runtime/Messengers.subproj/objc-msg-i386-nextpdo-winnt3.5.s b/runtime/Messengers.subproj/objc-msg-i386-nextpdo-winnt3.5.s deleted file mode 100644 index e297ad8..0000000 --- a/runtime/Messengers.subproj/objc-msg-i386-nextpdo-winnt3.5.s +++ /dev/null @@ -1,688 +0,0 @@ -/* - * Copyright (c) 1999 Apple Computer, Inc. All rights reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * Portions Copyright (c) 1999 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 1.1 (the "License"). You may not use this file - * except in compliance with the License. Please obtain a copy of the - * License at http://www.apple.com/publicsource 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 OR NON- INFRINGEMENT. Please see the - * License for the specific language governing rights and limitations - * under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ - .file "objc-msg-i386.s" -gcc2_compiled.: -___gnu_compiled_objc: -#ifdef KERNEL -.globl _objc_entryPoints -_objc_entryPoints: - .long _objc_msgSend - .long _objc_msgSendSuper - .long _objc_msgSendv - .long 0 - -.globl _objc_exitPoints -_objc_exitPoints: - .long Lexit1 - .long Lexit2 - .long Lexit3 - .long Lexit4 - .long Lexit5 - .long Lexit6 - .long Lexit7 - .long Lexit8 - .long 0 -#endif /* KERNEL */ - -/******************************************************************** - ******************************************************************** - * - * Objective-C message dispatching for the Win32/i386 - * - ******************************************************************** - ********************************************************************/ - -// Make this non-zero to use old style 32-bit-dirty structure returns -#define COMPATIBLE_CODE 0 - -/******************************************************************** - * - * Stack frame definitions. - * - ********************************************************************/ - - // standard word-return arguments - self = 4 - selector = 8 - - // standard struct-return arguments - // These values are used when doing a struct return message. - // The return value of the struct return is pushed on the stack - // as a "hidden" first parameter so the remaining parameters - // are 4 bytes further down the stack than they are in a - // normal message - struct_return_addr = self - struct_return_self = self + 4 - struct_return_selector = selector + 4 - - // additional arguments for _objc_msgForward - margSize = 12 - margs = 16 - - // additional arguments for _objc_msgForward_stret - struct_return_margSize = margSize + 4 - struct_return_margs = margs + 4 - - - // special self argument for objc_msgSendSuper - caller = self - - // special self argument for objc_msgSendSuper_stret - struct_return_caller = caller + 4 - -/******************************************************************** - * - * Structure definitions. - * - ********************************************************************/ - -// objc_super parameter to objc_msgSendSuper - receiver = 0 - class = 4 - -// Selected field offsets in class structure - isa = 0 - cache = 32 - -// Method descriptor - method_name = 0 - method_imp = 8 - -// Cache header - mask = 0 - occupied = 4 - buckets = 8 // variable length array (null terminated) - -/******************************************************************** - * - * Constants. - * - ********************************************************************/ - -// In case the implementation is _objc_msgForward, indicate to it -// whether the method was invoked as a word-return or struct-return. -// This flag is passed in a register that is caller-saved, and is -// not part of the parameter passing convention (i.e. it is "out of -// band"). This works because _objc_msgForward is only entered -// from here in the messenger. - kFwdMsgSend = 0 - kFwdMsgSendStret = 1 - -/******************************************************************** - * id objc_msgSend (id self, - * SEL op, - * ...); - * - * On entry: (sp+4) is the message receiver, - * (sp+8) is the selector - * - * And the structure-return version : - * - * struct_type objc_msgSend_stret (id self, - * SEL op, - * ...); - * - * objc_msgSend_stret is the struct-return form of msgSend. - * The ABI calls for (sp+4) to be used as the address of the structure - * being returned, with the parameters in the succeeding locations. - * - * On entry: (sp+4)is the address where the structure is returned, - * (sp+8) is the message receiver, - * (sp+12) is the selector - ********************************************************************/ - - .text - .globl _objc_msgSend - .globl _objc_msgSend_stret - .align 4, 0x90 -_objc_msgSend_stret: - movl struct_return_self(%esp), %eax // %eax = self - movl struct_return_selector(%esp), %ecx // %ecx = selector - pushl $kFwdMsgSendStret // flag struct-return for _objc_msgForward - jmp L1check_message - - .align 4, 0x90 -_objc_msgSend: -#if COMPATIBLE_CODE - movl self(%esp), %eax - andl $0x80000000, %eax - jne _objc_msgSend_stret -#endif - movl self(%esp), %eax // %eax = self - movl selector(%esp), %ecx // %ecx = selector - pushl $kFwdMsgSend // flag word-return for _objc_msgForward - -L1check_message: - pushl %ecx // Push selector - pushl %eax // Push self - movl %eax, %edx // Move self off to do a comparison - andl __objc_multithread_mask, %edx // And it against the multithreading mask - // This will also tell us if it's a nil object - je L1nil_or_multi // Jump if nil or multithreading is on - -// Load variables and save caller registers. -// Overlapped to prevent AGI -// At this point, self has been loaded into eax and selector has been -// loaded into ecx. - movl isa(%eax), %eax // class = self->isa - pushl %edi // - movl cache(%eax), %eax // cache = class->cache - pushl %esi // - - lea buckets(%eax), %edi // buckets = &cache->buckets - movl mask(%eax), %esi // mask = cache->mask - movl %ecx, %edx // index = selector - -L1probe_cache: - andl %esi, %edx // index &= mask - movl (%edi, %edx, 4), %eax // method_name = buckets[index] - - testl %eax, %eax // if (method != NULL) { - je L1cache_miss // - cmpl method_name(%eax), %ecx // method_name = method->name - jne L1not_the_method // if (method_name == selector) { - - movl method_imp(%eax), %eax // imp = method->method_imp - popl %esi // - popl %edi // - addl $8, %esp // dump saved self and selector - popl %edx // secret word/struct return flag to _objc_msgForward -Lexit1: jmp *%eax // goto *imp - .space 17 // area for moninitobjc to write - // } -L1not_the_method: - inc %edx // index++ - jmp L1probe_cache // } - - .align 4, 0x90 -L1cache_miss: - // restore caller registers - popl %esi // - popl %edi // - -// self and selector are already on the stack, so just -// replace self with its class pointer - popl %eax // pop self - movl isa(%eax), %eax // load the class pointer - pushl %eax // push class pointer, selector is already there - call __class_lookupMethodAndLoadCache // lookup the method and load the cache - addl $8, %esp // pop the args off the stack - popl %edx // secret word/struct return flag to _objc_msgForward -Lexit2: jmp *%eax - .space 17 // area for moninitobjc to write - - .align 4, 0x90 -L1nil_or_multi: - testl %eax,%eax // Check for a nil object - jne L1multi_msgSend // Jump to multi_msgSend if it's not a real object - - movl __objc_msgNil, %eax // Load nil message handler - testl %eax, %eax - je Ljust_return // If NULL just return and don't do anything - call *%eax // call __objc_msgNil - xorl %eax, %eax // Rezero $eax just in case -Ljust_return: - addl $12, %esp // pop the args and flag off the stack - ret - - -// locking version of send - its the same except for the lock/clear - .align 4, 0x90 -L1multi_msgSend: - // spin lock - movl $1, %ecx // Move 1 into ecx - leal _messageLock, %eax // Then load the address of _messageLock -L11spin: - xchgl %ecx, (%eax) - cmpl $0, %ecx - jne L11spin - - movl 0(%esp),%eax // retrieve self - movl 4(%esp),%ecx // retrieve selector - -// load variables and save caller registers. -// Overlapped to prevent AGI -// At this point, self has been loaded into eax and selector has been -// loaded into ecx. - movl isa(%eax), %eax // class = self->isa - pushl %edi // - movl cache(%eax), %eax // cache = class->cache - pushl %esi // - - lea buckets(%eax), %edi // buckets = &cache->buckets - movl mask(%eax), %esi // mask = cache->mask - movl %ecx, %edx // index = selector - -L11probe_cache: - andl %esi, %edx // index &= mask - movl (%edi, %edx, 4), %eax // method_name = buckets[index] - - testl %eax, %eax // if (method != NULL) { - je L11cache_miss // - cmpl method_name(%eax), %ecx // method_name = method->name - jne L11not_the_method // if (method_name == selector) { - - movl method_imp(%eax), %eax // imp = method->method_imp - popl %esi // - popl %edi // - addl $8, %esp // dump saved self and selector - movl $0, _messageLock // unlock - popl %edx // secret word/struct return flag to _objc_msgForward -Lexit3: jmp *%eax // goto *imp - .space 17 // area for moninitobjc to write - // } - .align 4, 0x90 -L11not_the_method: - inc %edx // index++ - jmp L11probe_cache // } - - .align 4, 0x90 -L11cache_miss: - // restore caller registers - popl %esi // - popl %edi // - -// self and selector are already on the stack, so just -// replace self with its class pointer - popl %eax // pop self - movl isa(%eax), %eax // load the class pointer - pushl %eax // push class pointer, selector is already there - call __class_lookupMethodAndLoadCache - addl $8, %esp - movl $0, _messageLock // unlock - popl %edx // secret word/struct return flag to _objc_msgForward -Lexit4: jmp *%eax - .space 17 // area for moninitobjc to write - - -/******************************************************************** - * id objc_msgSendSuper (struct objc_super * super, - * SEL op, - * ...); - * - * struct objc_super { - * id receiver; - * Class class; - * }; - * - * And the structure-return version: - * - * struct_type objc_msgSendSuper_stret (objc_super * super, - * SEL op, - * ...); - * - * struct objc_super { - * id receiver; - * Class class; - * }; - * - * - * objc_msgSendSuper_stret is the struct-return form of msgSendSuper. - * The ABI calls for (sp+4) to be used as the address of the structure - * being returned, with the parameters in the succeeding registers. - * - * On entry: (sp+4) is the address to which to copy the returned structure, - * (sp+8) is the address of the objc_super structure, - * (sp+12) is the selector - * - ********************************************************************/ - - .globl _objc_msgSendSuper - .globl _objc_msgSendSuper_stret - .align 4, 0x90 -_objc_msgSendSuper: -#if COMPATIBLE_CODE - movl caller(%esp), %eax - andl $0x80000000, %eax - jne _objc_msgSendSuper_stret -#endif - movl caller(%esp), %eax // %eax = caller - movl receiver(%eax), %edx // get receiver - movl %edx, caller(%esp) // replace caller with receiver - movl selector(%esp), %ecx // %ecx = selector - pushl $kFwdMsgSend // flag word-return for _objc_msgForward - jmp L1check_message_sendSuper // goto common code - -_objc_msgSendSuper_stret: - movl struct_return_caller(%esp), %eax // %eax = caller - movl receiver(%eax), %edx // get receiver - movl %edx, struct_return_caller (%esp) // replace caller with receiver - movl struct_return_selector(%esp), %ecx // %ecx = selector - pushl $kFwdMsgSendStret // flag struct-return for _objc_msgForward - - .align 4, 0x90 -L1check_message_sendSuper: - pushl %ecx // push selector - movl class(%eax), %eax // class = caller->class - pushl %eax // push callers class - - movl __objc_multithread_mask, %edx // - testl %edx, %edx // if (multi) - je L2multi_msgSuperSend // goto locking version - -// At this point, callers class is in eax and selector is in ecx - pushl %edi // - movl cache(%eax), %eax // cache = class->cache - pushl %esi // - - lea buckets(%eax), %edi // buckets = &cache->buckets - movl mask(%eax), %esi // mask = cache->mask - movl %ecx, %edx // index = selector - -L2probe_cache: - andl %esi, %edx // index &= mask - movl (%edi, %edx, 4), %eax // method_name = buckets[index] - - testl %eax, %eax // if (method != NULL) { - je L2cache_miss // - cmpl method_name(%eax), %ecx // method_name = method->name - jne L2not_the_method // if (method_name == selector) { - - // Cache hit - popl %esi // restore caller register - popl %edi // restore caller register - addl $8, %esp // dump saved class/selector - - // extract imp - movl method_imp(%eax), %eax // imp = method->method_imp - popl %edx // secret word/struct return flag to _objc_msgForward -Lexit5: jmp *%eax // goto *imp - .space 17 // area for moninitobjc to write - // } - .align 4, 0x90 -L2not_the_method: - inc %edx // index++ - jmp L2probe_cache // } - - .align 4, 0x90 -L2cache_miss: - popl %esi // restore register - popl %edi // restore register - - // Go lookup the method. Parameters are the class and - // selector, which are already on the stack in the - // proper order. - call __class_lookupMethodAndLoadCache - addl $8, %esp - popl %edx // secret word/struct return flag to _objc_msgForward -Lexit6: jmp *%eax - .space 17 // area for moninitobjc to write - - - -// locking version of super send - - .align 4, 0x90 -L2multi_msgSuperSend: - // spin lock - movl $1, %ecx - leal _messageLock, %eax -L22spin: - xchgl %ecx, (%eax) - cmpl $0, %ecx - jne L22spin - - movl 0(%esp), %eax // retrieve class - movl 4(%esp), %ecx // retrieve selector - - pushl %edi // - movl cache(%eax), %eax // cache = class->cache - pushl %esi // - - lea buckets(%eax), %edi // buckets = &cache->buckets - movl mask(%eax), %esi // mask = cache->mask - movl %ecx, %edx // index = selector - -L22probe_cache: - andl %esi, %edx // index &= mask - movl (%edi, %edx, 4), %eax // method_name = buckets[index] - - testl %eax, %eax // if (method != NULL) { - je L22cache_miss // - - cmpl method_name(%eax), %ecx // method_name = method->name - jne L22not_the_method // if (method_name == selector) { - - // Cache hit - movl method_imp(%eax), %eax // imp = method->method_imp - popl %esi // restore caller register - popl %edi // restore caller register - addl $8, %esp // dump saved caller/selector - movl $0, _messageLock // unlock - popl %edx // secret word/struct return flag to _objc_msgForward -Lexit7: jmp *%eax // goto *imp - .space 17 // area for moninitobjc to write - // } - .align 4, 0x90 -L22not_the_method: - inc %edx // index++ - jmp L22probe_cache // } - - .align 4, 0x90 -L22cache_miss: - popl %esi // restore caller register - popl %edi // restore caller register - - // Go lookup the method. Parameters are the class and - // selector, which are already on the stack in the - // proper order. - call __class_lookupMethodAndLoadCache - addl $8, %esp - movl $0, _messageLock // unlock - popl %edx // secret word/struct return flag to _objc_msgForward -Lexit8: jmp *%eax - .space 17 // area for moninitobjc to write - -/******************************************************************** - * - * Out-of-band parameter %edx indicates whether it was objc_msgSend or - * objc_msgSend_stret that triggered the message forwarding. The - * - * Iff %edx == kFwdMsgSend, it is the word-return (objc_msgSend) case, - * and the interface is: - * - * id _objc_msgForward (id self, - * SEL selector, - * ...); - * - * Iff %edx != kFwdMsgSend, it is the structure-return - * (objc_msgSend_stret) case, and the interface is: - * - * struct_type _objc_msgForward (id self, - * SEL selector, - * ...); - * - * There are numerous reasons why it is better to have one - * _objc_msgForward, rather than adding _objc_msgForward_stret. - * The best one is that _objc_msgForward is the method that - * gets cached when respondsToMethod returns false, and it - * wouldnt know which one to use. - * - * Sends the message to a method having the signature - * - * - forward: (SEL) selector : (marg_list) margs; - ********************************************************************/ - -// Location LFwdStr contains the string "forward::" -// Location LFwdSel contains a pointer to LFwdStr, that can be changed -// to point to another forward:: string for selector uniquing -// purposes. ALWAYS dereference LFwdSel to get to "forward::" !! - .global objc_meth_var_names -objc_meth_var_names: - .align 2, 0x90 -LFwdStr: .ascii "forward::\0" - - .global objc_message_refs -objc_message_refs: - .align 2, 0x90 -//LFwdSel: .long LFwdStr -LFwdSel: .long _OBJC_METH_VAR_NAME_FORWARD - - .align 2, 0x90 -LUnkSelStr: .ascii "Does not recognize selector %s\0" - - .text - .globl __objc_msgForward - .align 4, 0x90 -__objc_msgForward: - cmpl $kFwdMsgSend, %edx // check secret flag for word vs struct return - jne LMsgForwardStretSel // jump if struct return - - // word-return - movl selector(%esp), %eax // %eax = selector - movl self(%esp), %edx // %edx = self - leal (self)(%esp), %ecx // %ecx = ¶meters - jmp LMsgForwardCommon - - // structure return - .align 4, 0x90 -LMsgForwardStretSel: - movl struct_return_selector(%esp), %eax // %eax = selector - movl struct_return_self(%esp), %edx // %edx = self - leal (struct_return_addr)(%esp), %ecx // %ecx = ¶meters - - // common code -LMsgForwardCommon: - cmpl LFwdSel, %eax // forwarding "forward::"? - je LMsgForwardError // that would be an error - - pushl %ecx // push ¶meters - pushl %eax // push original selector - pushl LFwdSel // push "forward::" selector - pushl %edx // push self - call _objc_msgSend // send the message - addl $16, %esp // dump parameters - ret - - // die because the receiver does not implement forward:: - .align 4, 0x90 -LMsgForwardError: - pushl $LFwdSel // push "forward::" selector - pushl $LUnkSelStr // push "unknown selector" string - pushl %edx // push self - call ___objc_error // volatile, will not return - -/******************************************************************** - * id objc_msgSendv (id self, - * SEL selector, - * unsigned margSize, - * marg_list margs); - * - * On entry: (sp+4) is the message receiver, - * (sp+8) is the selector, - * (sp+12) is the size of the marg_list, in bytes, - * (sp+16) is the address of the marg_list - * - ********************************************************************/ - - .text - .globl _objc_msgSendv - .align 4, 0x90 -_objc_msgSendv: -#if COMPATIBLE_CODE - movl (margs + 4)(%ebp), %eax - andl $0x80000000, %eax - jne _objc_msgSendv_stret -#endif - pushl %ebp // save %ebp - movl %esp, %ebp // set stack frame base pointer - movl (margs + 4)(%ebp), %edx // get address of method arguments - addl $8, %edx // skip self & selector - movl (margSize + 4)(%ebp), %ecx // get byte count - subl $5, %ecx // skip self & selector and begin rounding - shrl $2, %ecx // make it a word count (rounding up) - jle LMsgSendvArgsOK // jump if self/selector are the only parameters - -LMsgSendvArgLoop: - decl %ecx // decrement counter - movl 0(%edx, %ecx, 4), %eax // load one word - pushl %eax // store one word - jg LMsgSendvArgLoop // check counter, iterate if non-zero - -LMsgSendvArgsOK: - movl (selector + 4)(%ebp), %ecx // push selector - pushl %ecx - movl (self + 4)(%ebp),%ecx // push self - pushl %ecx - call _objc_msgSend // send the message - movl %ebp,%esp // restore stack - popl %ebp // restore %ebp - - ret - -/******************************************************************** - * struct_type objc_msgSendv_stret (id self, - * SEL op, - * unsigned arg_size, - * marg_list arg_frame); - * - * objc_msgSendv_stret is the struct-return form of msgSendv. - * The ABI calls for (sp+4) to be used as the address of the structure - * being returned, with the parameters in the succeeding locations. - * - * An equally correct way to prototype this routine is: - * - * void objc_msgSendv_stret (void * structStorage, - * id self, - * SEL op, - * unsigned arg_size, - * marg_list arg_frame); - * - * which is useful in, for example, message forwarding where the - * structure-return address needs to be passed in. - * - * On entry: (sp+4) is the address in which the returned struct is put, - * (sp+8) is the message receiver, - * (sp+12) is the selector, - * (sp+16) is the size of the marg_list, in bytes, - * (sp+20) is the address of the marg_list - ********************************************************************/ - - .text - .globl _objc_msgSendv_stret - .align 4, 0x90 -_objc_msgSendv_stret: - pushl %ebp // save %ebp - movl %esp, %ebp // set stack frame base pointer - movl (struct_return_margs + 4)(%ebp), %edx // get address of method arguments - addl $12, %edx // skip struct return, self & selector - movl (struct_return_margSize + 4)(%ebp), %ecx // get byte count - subl $9, %ecx // skip struct addr, self & selector and begin rounding - shrl $2, %ecx // make it a word count (rounding up) - jle LMsgSendvStretArgsOK // jump if self/selector are the only parameters - -LMsgSendvStretArgLoop: - decl %ecx // decrement counter - pushl 0(%edx, %ecx, 4) // copy one word - jg LMsgSendvStretArgLoop // check counter, iterate if non-zero - -LMsgSendvStretArgsOK: - pushl (struct_return_selector + 4)(%ebp) // push selector - pushl (struct_return_self + 4)(%ebp) // push self - pushl (struct_return_addr + 4)(%ebp) // push structure return address - call _objc_msgSend_stret // send the message - movl %ebp,%esp // restore stack - popl %ebp // restore %ebp - - ret diff --git a/runtime/Messengers.subproj/objc-msg-m68k-lock.s b/runtime/Messengers.subproj/objc-msg-m68k-lock.s deleted file mode 100644 index 370bd9a..0000000 --- a/runtime/Messengers.subproj/objc-msg-m68k-lock.s +++ /dev/null @@ -1,283 +0,0 @@ -/* - * Copyright (c) 1999 Apple Computer, Inc. All rights reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * Portions Copyright (c) 1999 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 1.1 (the "License"). You may not use this file - * except in compliance with the License. Please obtain a copy of the - * License at http://www.apple.com/publicsource 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 OR NON- INFRINGEMENT. Please see the - * License for the specific language governing rights and limitations - * under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ -#ifndef KERNEL -| _objc_entryPoints and _objc_exitPoints are used by moninitobjc() to setup -| objective-C messages for profiling. The are made private_externs when in -| a shared library. - .reference _moninitobjc - .const -.globl _objc_entryPoints -_objc_entryPoints: - .long _objc_msgSend - .long _objc_msgSendSuper - .long _objc_msgSendv - .long 0 - -.globl _objc_exitPoints -_objc_exitPoints: - .long Lexit1 - .long Lexit2 - .long Lexit3 - .long Lexit4 - .long Lexit5 - .long Lexit6 - .long Lexit7 - .long Lexit8 - .long 0 -#endif /* KERNEL */ - - self = 4 - selector = 8 - cache = 32 - buckets = 8 - method_imp = 8 - -| optimized for 68040: 27 clocks (best case) + 16 clocks / probe - - .text - .align 1 - .globl _objc_msgSend -_objc_msgSend: - movel sp@(self),d0 | (1) - movel d0,a0 | (1) - andl __objc_multithread_mask,d0 | (1) if (_objc_multithread_mask == 0) - jne L1 | (2) goto lock; - tstl a0 | if (self != nil) - jne L11 | continue with objc_msgSend - movel __objc_msgNil,a0 | (?) load nil object handler - tstl a0 | (?) If NULL just return and dont do anything - jeq L10 | (?) - jbsr a0@ | (?) call __objc_msgNil; - clrl d0 | (1) zero d0, just in case nil handler changed them - movel d0,a0 | (1) zero a0, just in case nil handler changed them -L10: rts | -L1: movel a0@,a0 | (1) class = self->isa; - movel a1,sp@- | (2) (save a1) - movel a0@(cache),a1 | (1) cache = class->cache; - movel sp@(selector+4),d1 | (1) index = selector; -L2: andl a1@,d1 | (1) index &= cache->mask; - movel a1@(buckets,d1:l:4),d0 | (4) method = cache->buckets[index]; - movel d0,a0 | (1) if (method == NULL) - jne L3 | (2) goto cache_miss; - jra L5 | -L3: movel sp@(selector+4),d0 | (1) - cmpl a0@,d0 | (1) if (method_name == selector) - jeq L4 | (2) goto cache_hit; - addql #1,d1 | index++ - jra L2 | goto loop; -L4: movel a0@(method_imp),a0 | (1) imp = method->method_imp; - movel sp@+,a1 | (1) (restore a1) -Lexit1: jmp a0@ | (3) goto *imp; - .space 22 | /* area for moninitobjc to write */ -L5: movel sp@(self+4),a0 | cache_miss: - movel sp@(selector+4),sp@- | imp = - movel a0@,sp@- | _class_lookupMethodAndLoadCache - CALL_EXTERN(__class_lookupMethodAndLoadCache) | (class, selector); - addql #8,sp | - movel d0,a0 | - movel sp@+,a1 | (restore a1) -Lexit2: jmp a0@ | goto *imp; - .space 22 | /* area for moninitobjc to write */ - - - -| locking version of objc_msgSend: - -L11: clrb _messageLock+1 | (workaround 040 bug) - tas _messageLock | mutex_lock (messageLock); - jpl L24 | - jra L11 | -L24: movel a0@,a0 | class = self->isa; - movel a1,sp@- | (save a1) - movel a0@(cache),a1 | cache = class->cache; - movel sp@(selector+4),d1 | index = selector; -L12: andl a1@,d1 | index &= cache->mask; - movel a1@(buckets,d1:l:4),d0 | method = cache->buckets[index]; - movel d0,a0 | if (method == NULL) - jne L13 | goto cache_miss; - jra L15 | -L13: movel sp@(selector+4),d0 | - cmpl a0@,d0 | if (method_name == selector) - jeq L14 | goto cache_hit; - addql #1,d1 | index++ - jra L12 | goto loop; -L14: movel a0@(method_imp),a0 | imp = method->method_imp; - movel sp@+,a1 | (restore a1) - clrb _messageLock | mutex_unlock (messageLock); -Lexit3: jmp a0@ | goto *imp; - .space 22 | /* area for moninitobjc to write */ -L15: movel sp@(self+4),a0 | cache_miss: - movel sp@(selector+4),sp@- | imp = - movel a0@,sp@- | _class_lookupMethodAndLoadCache - CALL_EXTERN_AGAIN(__class_lookupMethodAndLoadCache) | (class, selector); - addql #8,sp | - movel d0,a0 | - movel sp@+,a1 | (restore a1) - clrb _messageLock | mutex_unlock (messageLock); -Lexit4: jmp a0@ | goto *imp; - .space 22 | /* area for moninitobjc to write */ - - - - caller = 4 - -| optimized for 68040: 31 clocks (best case) + 16 clocks / probe - - .align 1 - .globl _objc_msgSendSuper -_objc_msgSendSuper: - tstl __objc_multithread_mask | (1) if (_objc_multithread_mask == 0) - jne L20 | (2) goto lock; - jra L21 | -L20: movel sp@(caller),a0 | (1) - movel a2,sp@- | (2) (save a2) - movel a0@+,sp@(self+4) | (2) self = caller->receiver; - movel a0@,a2 | (1) class = caller->class; - movel a1,sp@- | (2) (save a1) - movel a2@(cache),a1 | (1) cache = class->cache; - movel sp@(selector+8),d1 | (1) index = selector; -L6: andl a1@,d1 | (1) index &= cache->mask; - movel a1@(buckets,d1:l:4),d0 | (4) method = cache->buckets[index]; - movel d0,a0 | (1) if (method == NULL) - jne L7 | (2) goto cache_miss; - jra L9 | -L7: movel sp@(selector+8),d0 | (1) - cmpl a0@,d0 | (1) if (method_name == selector) - jeq L8 | (2) goto cache_hit; - addql #1,d1 | index++ - jra L6 | goto loop; -L8: movel a0@(method_imp),a0 | (1) imp = method->method_imp; - movel sp@+,a1 | (1) (restore a1) - movel sp@+,a2 | (1) (restore a2) -Lexit5: jmp a0@ | (3) goto *imp; - .space 22 | /* area for moninitobjc to write */ -L9: movel sp@(selector+8),sp@- | imp = - movel a2,sp@- | _class_lookupMethodAndLoadCache - CALL_EXTERN_AGAIN(__class_lookupMethodAndLoadCache) | (class, selector); - addql #8,sp | - movel d0,a0 | - movel sp@+,a1 | (restore a1) - movel sp@+,a2 | (restore a2) -Lexit6: jmp a0@ | goto *imp; - .space 22 | /* area for moninitobjc to write */ - - - -| locking version of objc_msgSendSuper: - -L21: clrb _messageLock+1 | (workaround 040 bug) - tas _messageLock | mutex_lock (messageLock); - jpl L27 | - jra L21 | -L27: movel sp@(caller),a0 | - movel a2,sp@- | (save a2) - movel a0@+,sp@(self+4) | self = caller->receiver; - movel a0@,a2 | class = caller->class; - movel a1,sp@- | (save a1) - movel a2@(cache),a1 | cache = class->cache; - movel sp@(selector+8),d1 | index = selector; -L16: andl a1@,d1 | index &= cache->mask; - movel a1@(buckets,d1:l:4),d0 | method = cache->buckets[index]; - movel d0,a0 | if (method == NULL) - jne L17 | goto cache_miss; - jra L19 | -L17: movel sp@(selector+8),d0 | - cmpl a0@,d0 | if (method_name == selector) - jeq L18 | goto cache_hit; - addql #1,d1 | index++ - jra L16 | goto loop; -L18: movel a0@(method_imp),a0 | imp = method->method_imp; - movel sp@+,a1 | (restore a1) - movel sp@+,a2 | (restore a2) - clrb _messageLock | mutex_unlock (messageLock); -Lexit7: jmp a0@ | goto *imp; - .space 22 | /* area for moninitobjc to write */ -L19: movel sp@(selector+8),sp@- | imp = - movel a2,sp@- | _class_lookupMethodAndLoadCache - CALL_EXTERN_AGAIN(__class_lookupMethodAndLoadCache) | (class, selector); - addql #8,sp | - movel d0,a0 | - movel sp@+,a1 | (restore a1) - movel sp@+,a2 | (restore a2) - clrb _messageLock | mutex_unlock (messageLock); -Lexit8: jmp a0@ | goto *imp; - .space 22 | /* area for moninitobjc to write */ - - - .objc_meth_var_names - .align 1 -L30: .ascii "forward::\0" - - .objc_message_refs - .align 2 -L31: .long L30 - - .cstring - .align 1 -L32: .ascii "Does not recognize selector %s\0" - - .text - .align 1 - .globl __objc_msgForward -__objc_msgForward: - linkw a6,#0x0 | set up frame pointer - movel sp@(selector+4),d0 | +n accounts for sp pushes - cmpl L31,d0 | if (sel == @selector (forward::)) - bne L33 | - pea L30 | __objc_error (self, - pea L32 | _errDoesntRecognize - movel sp@(self+12),sp@- | "forward::"); - BRANCH_EXTERN(___objc_error) | -L33: pea sp@(self+4) | return [self forward: sel : &self]; - movel d0,sp@- | - movel L31,sp@- | - movel sp@(self+16),sp@- | - bsr _objc_msgSend | - unlk a6 | clear frame pointer - rts | - - - size = 12 - args = 16 - - .text - .align 1 - .globl _objc_msgSendv -_objc_msgSendv: - linkw a6,#0 | - movel a6@(size+4),d0 | - addql #3,d0 | size = round_up (size, 4); - andl #0xfffffffc,d0 | - movel a6@(args+4),a0 | - addl d0,a0 | arg_ptr = &args[size]; - subql #8,d0 | size -= 8; - ble L35 | while (size > 0) -L34: movel a0@-,sp@- | *--sp = *--arg_ptr; - subql #4,d0 | size -= 4; - bgt L34 | -L35: movel a6@(selector+4),sp@- | - movel a6@(self+4),sp@- | objc_msgSend (self, selector, ...); - bsr _objc_msgSend | - unlk a6 | (deallocate variable storage) - rts | diff --git a/runtime/Messengers.subproj/objc-msg-m68k-nolock.s b/runtime/Messengers.subproj/objc-msg-m68k-nolock.s deleted file mode 100644 index ea94610..0000000 --- a/runtime/Messengers.subproj/objc-msg-m68k-nolock.s +++ /dev/null @@ -1,198 +0,0 @@ -/* - * Copyright (c) 1999 Apple Computer, Inc. All rights reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * Portions Copyright (c) 1999 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 1.1 (the "License"). You may not use this file - * except in compliance with the License. Please obtain a copy of the - * License at http://www.apple.com/publicsource 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 OR NON- INFRINGEMENT. Please see the - * License for the specific language governing rights and limitations - * under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ -#ifndef KERNEL -| _objc_entryPoints and _objc_exitPoints are used by moninitobjc() to setup -| objective-C messages for profiling. The are made private_externs when in -| a shared library. - .reference _moninitobjc - .data -.globl _objc_entryPoints -_objc_entryPoints: - .long _objc_msgSend - .long _objc_msgSendSuper - .long 0 - -.globl _objc_exitPoints -_objc_exitPoints: - .long Lexit1 - .long Lexit5 - .long 0 -#endif /* KERNEL */ - - self = 4 - selector = 8 - cache = 32 - buckets = 8 - method_imp = 8 - -| optimized for 68040: 27 clocks (best case) + 16 clocks / probe - - .text - .align 1 - .globl _objc_msgSend -_objc_msgSend: - movel sp@(self),a0 | (1) - tstl a0 | if (self == nil) - jne L1 | - movel a0,d0 | return nil - movel __objc_msgNil,a0 | (?) load nil object handler - tstl a0 | (?) If NULL just return and dont do anything - jeq L10 | (?) - jbsr a0@ | (?) call __objc_msgNil; - clrl d0 | (1) zero d0, just in case nil handler changed them - movel d0,a0 | (1) zero a0, just in case nil handler changed them -L10: rts | -L1: movel a0@,a0 | (1) class = self->isa; - movel a1,sp@- | (2) (save a1) - movel a0@(cache),a1 | (1) cache = class->cache; - movel sp@(selector+4),d1 | (1) index = selector; -L2: andl a1@,d1 | (1) index &= cache->mask; - movel a1@(buckets,d1:l:4),d0 | (4) method = cache->buckets[index]; - movel d0,a0 | (1) if (method == NULL) - jne L3 | (2) goto cache_miss; - jra L5 | -L3: movel sp@(selector+4),d0 | (1) - cmpl a0@,d0 | (1) if (method_name == selector) - jeq L4 | (2) goto cache_hit; - addql #1,d1 | index++ - jra L2 | goto loop; -L4: movel a0@(method_imp),a0 | (1) imp = method->method_imp; - movel sp@+,a1 | (1) (restore a1) -Lexit1: jmp a0@ | (3) goto *imp; -#ifdef MONINIT - .space 22 | /* area for moninitobjc to write */ -#endif -L5: movel sp@(self+4),a0 | cache_miss: - movel sp@(selector+4),sp@- | imp = - movel a0@,sp@- | _class_lookupMethodAndLoadCache - CALL_EXTERN(__class_lookupMethodAndLoadCache) | (class, selector); - addql #8,sp | - movel d0,a0 | - movel sp@+,a1 | (restore a1) -Lexit2: jmp a0@ | goto *imp; - .space 22 | /* area for moninitobjc to write */ - - - - caller = 4 - -| optimized for 68040: 31 clocks (best case) + 16 clocks / probe - - .align 1 - .globl _objc_msgSendSuper -_objc_msgSendSuper: - movel sp@(caller),a0 | (1) - movel a2,sp@- | (2) (save a2) - movel a0@+,sp@(self+4) | (2) self = caller->receiver; - movel a0@,a2 | (1) class = caller->class; - movel a1,sp@- | (2) (save a1) - movel a2@(cache),a1 | (1) cache = class->cache; - movel sp@(selector+8),d1 | (1) index = selector; -L6: andl a1@,d1 | (1) index &= cache->mask; - movel a1@(buckets,d1:l:4),d0 | (4) method = cache->buckets[index]; - movel d0,a0 | (1) if (method == NULL) - jne L7 | (2) goto cache_miss; - jra L9 | -L7: movel sp@(selector+8),d0 | (1) - cmpl a0@,d0 | (1) if (method_name == selector) - jeq L8 | (2) goto cache_hit; - addql #1,d1 | index++ - jra L6 | goto loop; -L8: movel a0@(method_imp),a0 | (1) imp = method->method_imp; - movel sp@+,a1 | (1) (restore a1) - movel sp@+,a2 | (1) (restore a2) -Lexit5: jmp a0@ | (3) goto *imp; -#ifdef MONINIT - .space 22 | /* area for moninitobjc to write */ -#endif -L9: movel sp@(selector+8),sp@- | imp = - movel a2,sp@- | _class_lookupMethodAndLoadCache - CALL_EXTERN_AGAIN(__class_lookupMethodAndLoadCache) | (class, selector); - addql #8,sp | - movel d0,a0 | - movel sp@+,a1 | (restore a1) - movel sp@+,a2 | (restore a2) -Lexit6: jmp a0@ | goto *imp; -#ifdef MONINIT - .space 22 | /* area for moninitobjc to write */ -#endif - - - - .objc_meth_var_names - .align 1 -L30: .ascii "forward::\0" - - .objc_message_refs - .align 2 -L31: .long L30 - - .cstring - .align 1 -L32: .ascii "Does not recognize selector %s\0" - - .text - .align 1 - .globl __objc_msgForward -__objc_msgForward: - linkw a6,#0x0 | set up frame pointer - movel sp@(selector+4),d0 | +n accounts for sp pushes - cmpl L31,d0 | if (sel == @selector (forward::)) - bne L33 | - pea L30 | __objc_error (self, - pea L32 | _errDoesntRecognize - movel sp@(self+12),sp@- | "forward::"); - BRANCH_EXTERN(___objc_error) | -L33: pea sp@(self+4) | return [self forward: sel : &self]; - movel d0,sp@- | - movel L31,sp@- | - movel sp@(self+16),sp@- | - bsr _objc_msgSend | - unlk a6 | clear frame pointer - rts | - - - size = 12 - args = 16 - - .text - .align 1 - .globl _objc_msgSendv -_objc_msgSendv: - linkw a6,#0 | - movel a6@(size+4),d0 | - addql #3,d0 | size = round_up (size, 4); - andl #0xfffffffc,d0 | - movel a6@(args+4),a0 | - addl d0,a0 | arg_ptr = &args[size]; - subql #8,d0 | size -= 8; - ble L35 | while (size > 0) -L34: movel a0@-,sp@- | *--sp = *--arg_ptr; - subql #4,d0 | size -= 4; - bgt L34 | -L35: movel a6@(selector+4),sp@- | - movel a6@(self+4),sp@- | objc_msgSend (self, selector, ...); - bsr _objc_msgSend | - unlk a6 | (deallocate variable storage) - rts | diff --git a/runtime/Messengers.subproj/objc-msg-ppc.s b/runtime/Messengers.subproj/objc-msg-ppc.s index c3d3ce0..005780b 100644 --- a/runtime/Messengers.subproj/objc-msg-ppc.s +++ b/runtime/Messengers.subproj/objc-msg-ppc.s @@ -264,7 +264,6 @@ $0: cmplwi r0,0 ; lock held? bne .-20 ; if locked, go spin waiting for unlock li r0,1 ; get value that means locked - sync ; PPC errata #7: Avoid address comparison qualification failure stwcx. r0,0,$0 ; store it iff reservation still holds bne- .-20 ; if reservation was lost, go re-reserve isync ; discard effects of prefetched instructions @@ -340,6 +339,9 @@ MANY_ARGS = 1 .endif ; locate the cache +; Locking idea: +;LGetMask_$0_$1_$2 + .if $0 == WORD_RETURN ; WORD_RETURN .if $1 == MSG_SEND ; MSG_SEND @@ -358,11 +360,21 @@ MANY_ARGS = 1 .endif + lwz r12,cache(r12) ; cache = class->cache #if defined(OBJC_INSTRUMENTED) mr r6,r12 ; save cache pointer #endif - lwz r11,mask(r12) ; mask = cache->mask + lwz r11,mask(r12) ; mask = cache->mask + +; Locking idea +; lea r0,mask(r12) ; XXX eliminate this by moving the mask to first position +; lwarx r11,r0 ; mask = reserve(cache->mask) +; bgt LGetMask_$0_$1_$2 ; if (mask > 0) goto LGetMask // someone already using it +; neg r11 ; mask = -mask +; stcwx. r11,r0 ; cache->mask = mask // store positive to mark in use +; bf LGetMask_$0_$1_$2 ; go to the class and get a possibly new one again + addi r9,r12,buckets ; buckets = cache->buckets .if $0 == WORD_RETURN ; WORD_RETURN and r12,r4,r11 ; index = selector & mask @@ -422,6 +434,14 @@ LLoop_$0_$1_$2: .endif bne LLoop_$0_$1_$2 ; goto loop +; Locking idea +; clear lock +; lwz r12,isa(r3) ; XXX or r4 or class(r3/4) - use macro +; lwz r12,cache(r12) +; neg r11 ; mask = -mask +; stwz r11,mask(r12) ; cache->mask = mask // store negative to mark free + + ; cache hit, r10 == method implementation address mr r12,r10 ; copy implementation to r12 mtctr r10 ; ctr = imp diff --git a/runtime/Messengers.subproj/objc-msg-sparc-pdo.s b/runtime/Messengers.subproj/objc-msg-sparc-pdo.s deleted file mode 100644 index 55cb3dc..0000000 --- a/runtime/Messengers.subproj/objc-msg-sparc-pdo.s +++ /dev/null @@ -1,375 +0,0 @@ -/* - * Copyright (c) 1999 Apple Computer, Inc. All rights reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * Portions Copyright (c) 1999 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 1.1 (the "License"). You may not use this file - * except in compliance with the License. Please obtain a copy of the - * License at http://www.apple.com/publicsource 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 OR NON- INFRINGEMENT. Please see the - * License for the specific language governing rights and limitations - * under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ -/* - * objc-msg-sparc.s - * Copyright 1994 NeXT, Inc. - * CREDITS: John Atkinson, Brad Taylor, Kresten Thorup, - * Gordie Freedman, and everybody else and their dog too ! - * - * - * id objc_msgSend(id self, SEL sel, ...) - * - * Implement [anObject aSelector] - * - * NOTE: objc_msgSend() is defined as a C function in - * objc-dispatch.c. This code is derived from - * compiler generated assembly code. - * - */ - -#define CLEARLOW22 0xffc00000 /* mask to clear low 22 bits */ - -#ifndef __svr4__ -#define _class_lookupMethodAndLoadCache __class_lookupMethodAndLoadCache -#define objc_msgSend _objc_msgSend -#define objc_msgSendv _objc_msgSendv -#define objc_msgSendSuper _objc_msgSendSuper -#define _objc_msgForward __objc_msgForward -#define OBJC_METH_VAR_NAME_FORWARD _OBJC_METH_VAR_NAME_FORWARD -#define _objc_error __objc_error -#define _objc_multithread_mask __objc_multithread_mask -#define messageLock _messageLock -#define _objc_private_lock __objc_private_lock -#define _objc_private_unlock __objc_private_unlock -#endif - -.text - .align 4 - .global objc_msgSend - .type objc_msgSend,#function - .proc 0110 -// -// ObjC message send: -// Arguments: %i0 - receiver (self) -// %i1 - selector -// %i2.. - arguments - -objc_msgSend: - save %sp,-96,%sp // Save the stack -.Ls1: - call .Ls2 - nop -.Ls2: - sethi %hi(_GLOBAL_OFFSET_TABLE_-(.Ls1-.)),%l6 - or %l6,%lo(_GLOBAL_OFFSET_TABLE_-(.Ls1-.)),%l6 - add %l6,%o7,%l6 - - tst %i0 // If (self == nil) - bz .L_receiver_is_nil // Then goto nil return -// sethi %hi(_objc_multithread_mask),%l2 -// ld [%l2+%lo(_objc_multithread_mask)],%l2 - set _objc_multithread_mask,%l2 - ld [%l6+%l2],%l2 - ld [%l2],%l2 - - tst %l2 // If zero - bz .L_lock // Then multithreaded - ld [%i0],%l1 // cls = self->isa - ld [%l1+32],%o0 // cache = cls->cache -.L_continue: - ld [%o0],%o4 // mask = cache->mask - add %o0,8,%o3 // buckets = cache->buckets - and %i1,%o4,%o2 // index = selector & mask -.L_loop: - sll %o2,2,%o1 // %o1 <= index << 2 - ld [%o3+%o1],%o0 // %o0 <= buckets[index] - cmp %o0,0 // if (buckets[index] == 0) - be,a .L_cacheMiss // then goto cacheMiss - mov %l1,%o0 // Class goes into arg0 - ld [%o0],%l3 // %l3 <= buckets[index]->method_name - cmp %l3,%i1 // if (method_name == sel) - be,a .L_cacheHit // goto cacheHit - ld [%o0+8],%o0 // Fish out IMP address - add %o2,1,%o2 // index++ - b .L_loop // Loop - and %o2,%o4,%o2 // index &= mask -.L_cacheMiss: - call _class_lookupMethodAndLoadCache,0 - mov %i1,%o1 // Selector goes into arg1 -.L_cacheHit: - tst %l2 // If mutithreaded is zero - bz,a .L_unlocked // Then multithreaded, so unlock - swap [%l7],%g0 // in the delay slot! -.L_unlocked: - jmp %o0 // Go to method imp - restore // restore the stack -.L_receiver_is_nil: - ld [%i7+8],%g3 // load instruction - sethi %hi(CLEARLOW22),%g2 // mask off low 22 bits - andcc %g3,%g2,%g0 // if 0, then its an UNIMP inst - bz .L_struct_returnSend // and we will return a structure - mov 0,%i1 // Second half of long long ret is 0 - ret // Get back, JoJo - restore // -.L_struct_returnSend: - jmp %i7 + 12 // convention for returning structs - restore // -.L_lock: - set (messageLock),%l7 // get the lock addr - ld [%l6+%l7],%l7 - set 1,%l3 // lock code (1) -.L_lockspin: - swap [%l7],%l3 // try to set the lock - tst %l3 // if lock was already set - bnz .L_lockspin // try again - set 1,%l3 // lock code (1) - b .L_continue // Head back to mainline - ld [%l1+32],%o0 // cache = cls->cache - -/* - * Implement [super aSelector] - * - * id objc_msgSendSuper(struct objc_super *caller, SEL sel, ...) - * - * NOTE: objc_msgSendSuper() is defined as a C function in - * objc-dispatch.c. This code is derived from - * compiler generated assembly code. - */ - .align 4 - .global objc_msgSendSuper - .type objc_msgSendSuper,#function - .proc 0110 -objc_msgSendSuper: - // receiver and cls won't be nil on entry, can skip check - save %sp,-112,%sp -.Lsu1: - call .Lsu2 - nop -.Lsu2: - sethi %hi(_GLOBAL_OFFSET_TABLE_-(.Lsu1-.)),%l6 - or %l6,%lo(_GLOBAL_OFFSET_TABLE_-(.Lsu1-.)),%l6 - add %l6,%o7,%l6 - -// sethi %hi(_objc_multithread_mask),%l2 -// ld [%l2+%lo(_objc_multithread_mask)],%l2 - set _objc_multithread_mask,%l2 - ld [%l6+%l2],%l2 - ld [%l2],%l2 - tst %l2 // If zero - bz .L_super_lock // Then multithreaded - ld [%i0],%l1 // Put caller->receiver in %l1 - st %l1,[%fp+68] // Save receiver for later -.L_super_continue: - ld [%i0+4],%o3 // Put caller->cls into %o3 - ld [%o3+32],%o0 // cache = cls->cache - ld [%o0],%o2 // mask = cls->cache->mask - add %o0,8,%l0 // buckets = cache->buckets - and %i1,%o2,%i0 // index = selector & mask -.L_super_loop: - sll %i0,2,%o0 // Adjust to word index - ld [%l0+%o0],%o1 // method = buckets[index] - cmp %o1,0 // if (method == NULL) ... - be .L_super_cacheMiss // ... then have a cache miss - mov %o3,%o0 // Class arg for LoadCache - ld [%o1],%o0 // Method name into o0 - cmp %o0,%i1 // Compare method name to one we want - be .L_super_cacheHit // Equal, got a hit - ld [%o1+8],%g1 // Get implementation address - add %i0,1,%i0 // Increment index - b .L_super_loop // Loop again - and %i0,%o2,%i0 // and with mask -.L_super_cacheMiss: - call _class_lookupMethodAndLoadCache,0 - mov %i1,%o1 // Selector into arg1 - mov %o0,%g1 // Save result from LoadCache -.L_super_cacheHit: - tst %l2 // If multithread is zero - bz,a .L_super_unlocked // Then multithreaded, so unlock - swap [%l7],%g0 // in the delay slot! -.L_super_unlocked: - restore // Restore the stack - jmp %g1 // Go to the method - ld [%sp+68],%o0 // Put receiver in arg0 -.L_super_lock: - set (messageLock),%l7 // get the lock addr - ld [%l6+%l7],%l7 - set 1,%l3 // lock code (1) -.L_super_lockspin: - swap [%l7],%l3 // try to set the lock - tst %l3 // if lock was already set - bnz .L_super_lockspin// try again - set 1,%l3 // lock code (1) - b .L_super_continue// Head back to mainline - st %l1,[%fp+68] // Save receiver for later - -// -// id __objc_msgForward(id self, SEL sel, ...) -// - .align 4 - .global _objc_msgForward - .type _objc_msgForward,#function - .proc 0110 -_objc_msgForward: - save %sp,-96,%sp -.Lmf1: - call .Lmf2 - nop -.Lmf2: - sethi %hi(_GLOBAL_OFFSET_TABLE_-(.Lmf1-.)),%l6 - or %l6,%lo(_GLOBAL_OFFSET_TABLE_-(.Lmf1-.)),%l6 - add %l6,%o7,%l6 - -// sethi %hi(OBJC_METH_VAR_NAME_FORWARD),%g2 -// or %g2,%lo(OBJC_METH_VAR_NAME_FORWARD),%g2 - set OBJC_METH_VAR_NAME_FORWARD,%g2 - ld [%l6+%g2],%g2 - - cmp %g2,%i1 // if (sel==@selector(forward::)) - be .LERROR // goto ERROR - mov %i1,%o2 // Put selector into %o2 - add %fp,68,%g1 // Pointer to %i3 stack homing area - st %i0,[%g1] // Store first 6 parameters onto stack - st %i1,[%g1+4] - st %i2,[%g1+8] - st %i3,[%g1+12] - st %i4,[%g1+16] - st %i5,[%g1+20] - mov %g2,%o1 // Put forward:: into %o1 - mov %g1,%o3 // Set margv vector as 4th parm - - ld [%i7+8],%g3 // load instruction - sethi %hi(CLEARLOW22),%g2 // mask off low 22 bits - andcc %g3,%g2,%g0 // if 0, then its an UNIMP inst - be .Lstruct_returnForward // and we will return a structure - nop // fill me in later - - // No structure is returned - call objc_msgSend,0 // send the message - mov %i0,%o0 // Set self - mov %o0,%i0 // Restore return parameter - ret // Return - restore %o1,0,%o1 // In case long long returned - -.Lstruct_returnForward: - ld [%fp+64],%g2 // get return struct ptr - st %g2,[%sp+64] // save return struct pointer - call objc_msgSend,0 // send the message - mov %i0,%o0 // Set self - unimp 0 // let 0 mean size = unknown - jmp %i7 + 12 // convention for returning structs - restore -.LERROR: // Error: Does not respond to sel - sethi %hi(.LC0), %o1 - or %o1,%lo(.LC0),%o1 - b _objc_error // __objc_error never returns, - nop -.LC0: - .ascii "Does not recognize selector %s\0" - .align 4 - -// -// id objc_msgSendv(id self, SEL sel, unsigned size, marg_list args) -// - .align 4 - .global objc_msgSendv - .type objc_msgSendv,#function -objc_msgSendv: - add %g0,-96,%g1 // Get min stack size + 4 (rounded by 8) - subcc %o2,28,%g2 // Get size of non reg params + 4 - ble .Lsave_stack // None or 1, so skip making stack larger - sub %g1,%g2,%g2 // Add local size to minimum stack - and %g2,-8,%g1 // Need to round to 8 bit boundary -.Lsave_stack: - save %sp,%g1,%sp // Save min stack + 4 for 8 byte bound ... - mov %i0,%o0 - mov %i1,%o1 - addcc %i2,-8,%i2 // The first 6 args go in registers - be .Lsend_msg - nop - ld [%i3+8],%o2 // Got at least 1 arg - addcc %i2,-4,%i2 - be .Lsend_msg - nop - ld [%i3+12],%o3 // Got at least 2 args - addcc %i2,-4,%i2 - be .Lsend_msg - nop - ld [%i3+16],%o4 // Got at least 3 args - addcc %i2,-4,%i2 - be .Lsend_msg - nop - ld [%i3+20],%o5 // Got at least 4 args - addcc %i2,-4,%i2 // Decrement count past 4th arg - be .Lsend_msg - nop - add %i3,24,%i1 // %i1 <== args += 24 - add %sp,92,%i5 -.Loop2: - ld [%i1],%i3 // Deal with remaining args - addcc %i2,-4,%i2 - st %i3,[%i5] - add %i5,4,%i5 - bne .Loop2 - add %i1,4,%i1 -.Lsend_msg: - - ld [%i7+8],%g3 // load instruction - sethi %hi(CLEARLOW22),%g2 // mask off low 22 bits - andcc %g3,%g2,%g0 // if 0, then its an UNIMP inst - be .Lstruct_returnSendv // and we will return a structure - nop // fill me in later - - // No structure is returned - call objc_msgSend,0 // send the message - nop // fill me in later - mov %o0,%i0 // Ret int, 1st half - ret // ... of long long - restore %o1,0,%o1 // 2nd half of ll - -.Lstruct_returnSendv: - ld [%fp+64],%g2 // get return struct ptr - st %g2,[%sp+64] // save return struct pointer - call objc_msgSend,0 // send the message - nop // fill me in later - unimp 0 // let 0 mean size = unknown - jmp %i7 + 12 // convention for returning structs - restore - -// -// void _objc_private_lock (long* lock) -// - .align 4 - .global _objc_private_lock - .type _objc_private_lock,#function -_objc_private_lock: - save %sp,-96,%sp // Save the stack - set 1,%l3 // lock code (1) -.L_private_loop: - swap [%i0],%l3 // try to set the lock - tst %l3 // if lock was already set - bnz,a .L_private_loop // try again - set 1,%l3 // lock code (1) - jmp %i7+8 - restore - -// -// void _objc_private_unlock (long* lock) -// - .align 4 - .global _objc_private_unlock - .type _objc_private_unlock,#function -_objc_private_unlock: - swap [%o0],%g0 // clear the lock - jmp %o7+8 - nop diff --git a/runtime/Messengers.subproj/objc-msg-sparc.s b/runtime/Messengers.subproj/objc-msg-sparc.s deleted file mode 100644 index 6be70b7..0000000 --- a/runtime/Messengers.subproj/objc-msg-sparc.s +++ /dev/null @@ -1,393 +0,0 @@ -/* - * Copyright (c) 1999 Apple Computer, Inc. All rights reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * Portions Copyright (c) 1999 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 1.1 (the "License"). You may not use this file - * except in compliance with the License. Please obtain a copy of the - * License at http://www.apple.com/publicsource 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 OR NON- INFRINGEMENT. Please see the - * License for the specific language governing rights and limitations - * under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ -#ifdef DYLIB -#warning Building of SPARC dynashlib not fully supported yet! -#endif - -#ifdef KERNEL -#define OBJC_LOCK_ROUTINE _simple_lock -#else -#define OBJC_LOCK_ROUTINE _spin_lock -#endif /* KERNEL */ - -#define CLEARLOW22 0xffc00000 /* mask to clear off low 22 bits */ - - -#define isa 0 -#define cache 32 -#define mask 0 -#define buckets 8 -#define method_name 0 -#define method_imp 8 -#define receiver 0 -#define class 4 - -! optimized for sparc: 26 clocks (best case) + 7 clocks/probe - - .text - .globl _objc_msgSend - -! ObjC message send: -! Arguments: %i0 - receiver (self) -! %i1 - selector -! %i2.. - arguments - -_objc_msgSend: - save %sp,-96,%sp ! save register windows - -! test for nil argument and locking requirements - sethi %hi(__objc_multithread_mask),%l1 - ld [%l1+%lo(__objc_multithread_mask)],%l1 - andcc %l1,%i0,%l1 ! if (self & multi) - bnz,a L_normalCase ! then normalcase - ld [%i0+isa],%o0 ! class = self->isa (class arg) - - tst %i0 ! if (self) - bnz L_sendLocking ! lockingcase - nop -! self is NIL, return - ld [%i7+8],%g3 // load instruction - sethi %hi(CLEARLOW22),%g2 // mask off low 22 bits - andcc %g3,%g2,%g0 // if 0, then its an UNIMP inst - bz L_struct_returnSend0 // and we will return a structure - nop // - ret // Get back, JoJo - restore // -L_struct_returnSend0: - jmp %i7 + 12 // convention for returning structs - restore // - -! Init pointers to class and cache -L_normalCase: - ld [%o0+cache],%l4 ! cache <- class->cache - ld [%l4+mask],%l3 ! mask <- cache->mask - add %l4,buckets,%l2 ! buckets <- cache->buckets - and %i1,%l3,%l1 ! index <- selector & mask - -! Try to find a method in the cache -L_loop: - sll %l1,2,%l6 ! adjust to word index - ld [%l2+%l6],%l4 ! method = buckets[index] - tst %l4 ! if (method == NULL) - bz,a L_cacheMiss ! handle cacheMiss case - mov %i1,%o1 ! (DS) selector arg for LoadCache - - ld [%l4+method_name],%l5! name = method->method_name - cmp %l5,%i1 ! if (name == selector) - be,a L_cacheHit ! goto hit - ld [%l4+method_imp],%o0! load method_imp pointer to call - - inc %l1 ! index++ - b L_loop ! check next cache entry - and %l1,%l3,%l1 ! index = index & mask -L_cacheMiss: - CALL_EXTERN(__class_lookupMethodAndLoadCache) -L_cacheHit: - jmp %o0 ! - restore - -! Locking version of objc_msgSend -! spins on the mutex lock. - -L_sendLocking: - set (_messageLock),%l7! get the lock addr - set 1,%l1 ! lock code (1) -L_lockspin: - swap [%l7],%l1 ! try to set the lock - tst %l1 ! if lock was already set - bnz L_lockspin ! try again - set 1,%l1 ! lock code (1) - - ! got the lock, ready to proceed - - ld [%i0+isa],%o0 ! class = self->isa - ld [%o0+cache],%l4 ! cache = class->cache - ld [%l4+mask],%l3 ! mask = cache->mask - add %l4,buckets,%l2 ! buckets = cache->buckets - and %i1,%l3,%l1 ! index = selector & mask - -L_loop_lk: - sll %l1,2,%l6 ! adjust to word index - ld [%l2+%l6],%l4 ! method = buckets[index] - tst %l4 ! if (method == NULL) - bz,a L_cacheMiss_lk ! handle cacheMiss case - mov %i1,%o1 ! (DS) selector arg for LoadCache - - ld [%l4+method_name],%l5! name = method->method_name - cmp %l5,%i1 ! if (name == selector) - be,a L_cacheHit_lk ! goto hit - ld [%l4+method_imp],%o0 ! impl = method->method_imp - - inc %l1 ! index++ - b L_loop_lk ! check next cache entry - and %l1,%l3,%l1 ! index = index & mask - -L_cacheMiss_lk: - CALL_EXTERN_AGAIN(__class_lookupMethodAndLoadCache) -L_cacheHit_lk: - swap [%l7],%g0 ! clear the lock - jmp %o0 - restore - - - .globl _objc_msgSendSuper -_objc_msgSendSuper: - save %sp,-120,%sp ! save register window - ld [%i0+receiver],%l0 ! receiver = caller->receiver - tst %l0 ! if (receiver) - bnz L_receiver ! work on it - st %l0,[%fp+68] ! save a copy -L_noreceiver: ! return on NULL receiver - ld [%i7+8],%g3 // load instruction - sethi %hi(CLEARLOW22),%g2 // mask off low 22 bits - andcc %g3,%g2,%g0 // if 0, then its an UNIMP inst - bz L_struct_returnSend1 // and we will return a structure - nop // - ret // Get back, JoJo - restore // -L_struct_returnSend1: - jmp %i7 + 12 // convention for returning structs - restore // - -L_receiver: - sethi %hi(__objc_multithread_mask),%l1 - ld [%l1+%lo(__objc_multithread_mask)],%l1 - tst %l1 - bz L_superLock - ld [%i0+class],%o0 ! class = caller->class - ld [%o0+cache],%l4 ! cache = class->cache - ld [%l4+mask],%l3 ! mask = cache->mask - add %l4,buckets,%l2 ! buckets = cache->buckets - and %i1,%l3,%l1 ! index = selector & mask - -L_super_loop: - sll %l1,2,%l6 ! adjust to word index - ld [%l2+%l6],%l4 ! method = buckets[index] - tst %l4 ! if (method == NULL) - bz,a L_super_cacheMiss ! handle cacheMiss case - mov %i1,%o1 ! (DS) selector arg for LoadCache - - ld [%l4+method_name],%l5! name = method->method_name - cmp %l5,%i1 ! if (name == selector) - be L_super_cacheHit ! goto hit - ld [%l4+method_imp],%g1 ! method = buckets[index] - - inc %l1 ! index++ - b L_super_loop ! check next cache entry - and %l1,%l3,%l1 ! index = index & mask - -L_super_cacheMiss: - CALL_EXTERN_AGAIN(__class_lookupMethodAndLoadCache) - mov %o0,%g1 ! save result from Loadcache - restore - jmp %g1 - ld [%sp+68],%o0 ! restore receiver - - -L_super_cacheHit: - restore - jmp %g1 - ld [%sp+68],%o0 ! restore receiver - - -! locking version of objc_msgSendSuper -! spins on the mutex lock - -L_superLock: - sethi %hi(_messageLock),%l1! aquire the lock addr - or %l1,%lo(_messageLock),%l7 -L_super_lockspin: - ldstub [%l7],%l1 ! try to set the lock - tst %l1 ! if lock was already set - bne L_super_lockspin ! try again - nop - - ! got the lock, ready to proceed - ! %o0 = class [set above] - ld [%o0+cache],%l4 ! cache = class->cache - ld [%l4+mask],%l3 ! mask = cache->mask - add %l4,buckets,%l2 ! buckets = cache->buckets - and %i1,%l3,%l1 ! index = selector & mask - -L_super_loop_lk: - sll %l1,2,%l6 ! adjust to word index - ld [%l2+%l6],%l4 ! method = buckets[index] - tst %l4 ! if (method == NULL) - bz,a L_super_cacheMiss_lk ! handle cacheMiss case - mov %i1,%o1 ! (DS) selector arg for LoadCache - - ld [%l4+method_name],%l5! name = method->method_name - cmp %l5,%i1 ! if (name == selector) - be L_super_cacheHit_lk ! goto hit - ld [%l4+method_imp],%g1 ! impl = method->method_imp - - inc %l1 ! index++ - b L_super_loop_lk ! check next cache entry - and %l1,%l3,%l1 ! index = index & mask - -L_super_cacheMiss_lk: - CALL_EXTERN_AGAIN(__class_lookupMethodAndLoadCache) - mov %o0,%g1 ! save result from Loadcache - st %g0,[%l7] ! clear lock - restore - jmp %g1 - ld [%sp+68],%o0 ! restore receiver - -L_super_cacheHit_lk: - st %g0,[%l7] ! clear the lock - restore - jmp %g1 - ld [%sp+68],%o0 ! restore receiver - - - .objc_meth_var_names - .align 1 -L30: .ascii "forward::\0" - - .objc_message_refs - .align 2 -L31: .long L30 - - .cstring - .align 1 -L32: .ascii "Does not recognize selector %s\0" - - .text - .align 2 - - .globl __objc_msgForward -__objc_msgForward: - save %sp,-96,%sp - sethi %hi(L31),%g2 - ld [%g2+%lo(L31)],%g2 - cmp %i1,%g2 ! if (selector == @selector(forward::)) - be L_error - nop - add %fp,68,%g1 ! ptr to stack area - st %i0,[%g1] - st %i1,[%g1+4] - st %i2,[%g1+8] - st %i3,[%g1+12] - st %i4,[%g1+16] - st %i5,[%g1+20] - mov %i1,%o2 - mov %g2,%o1 - mov %g1,%o3 - ld [%i7+8],%g3 ! load instruction - sethi %hi(CLEARLOW22),%g2 ! mask off low 22 bits - andcc %g3,%g2,%g0 ! if 0, then its an UNIMP inst - be Lstruct_returnForward ! and we will return a structure - nop ! fill me in later - - ! No structure is returned - call _objc_msgSend ! send the message - mov %i0,%o0 ! Set self - mov %o0,%i0 ! Restore return parameter - ret ! Return - restore %o1,0,%o1 !In case long long returned - -Lstruct_returnForward: - ld [%fp+64],%g2 ! get return struct ptr - st %g2,[%sp+64] ! save return struct pointer - call _objc_msgSend ! send the message - mov %i0,%o0 ! Set self - unimp 0 ! let 0 mean size = unknown - jmp %i7 + 12 ! convention for returning structs - restore - -L_error: - mov %i1, %o2 - set L32,%i1 - BRANCH_EXTERN(__objc_error) ! never returns - - -! id objc_msgSendv(id self, SEL sel, unsigned size, marg_list args) - - .globl _objc_msgSendv -_objc_msgSendv: - add %g0,-96,%g1 ! Get min stack size + 4 (rounded by 8) - subcc %o2,28,%g2 ! Get size of non reg params + 4 - ble Lsave_stack ! None or 1, so skip making stack larger - sub %g1,%g2,%g2 ! Add local size to minimum stack - and %g2,-8,%g1 ! Need to round to 8 bit boundary -Lsave_stack: - save %sp,%g1,%sp ! Save min stack + 4 for 8 byte bound! ... - mov %i0,%o0 - mov %i1,%o1 - addcc %i2,-8,%i2 ! adjust for first 2 args (self & sel) - be L_send_msg - nop - - ld [%i3+8],%o2 ! get 3rd arg - addcc %i2,-4,%i2 ! size-- - be L_send_msg - nop - - ld [%i3+12],%o3 ! arg 4 - addcc %i2,-4,%i2 ! size-- - be L_send_msg - nop - - ld [%i3+16],%o4 ! arg 5 - addcc %i2,-4,%i2 ! size-- - be L_send_msg - nop - - ld [%i3+20],%o5 ! arg 6 - addcc %i2,-4,%i2 ! size-- - be L_send_msg - nop - add %i3,24,%i1 ! %i1 = args + 24 - add %sp,92,%i5 -L_loopv: ! deal with remaining args - ld [%i1],%i3 - addcc %i2,-4,%i2 ! size-- - st %i3,[%i5] - add %i5,4,%i5 - bnz L_loopv - add %i1,4,%i1 ! arg++ - -L_send_msg: - ld [%i7+8],%g3 ! load instruction - sethi %hi(CLEARLOW22),%g2 - andcc %g3,%g2,%g0 ! if 0 it is an UNIMP inst - be L_struct_returnSendv! return a structure - nop - -! Case of no struct returned - - call _objc_msgSend - nop - mov %o0,%i0 ! Ret int, 1st half - ret ! ... of long long - restore %o1,0,%o1 ! 2nd half of ll - -L_struct_returnSendv: - ld [%fp+64],%g2 - st %g2,[%sp+64] - call _objc_msgSend - nop - unimp 0 - jmp %i7+12 - restore diff --git a/runtime/Messengers.subproj/objc-msg.s b/runtime/Messengers.subproj/objc-msg.s index 738d09f..c90c13e 100644 --- a/runtime/Messengers.subproj/objc-msg.s +++ b/runtime/Messengers.subproj/objc-msg.s @@ -32,39 +32,8 @@ #import "../objc-config.h" -#if defined (m68k) - #if defined(OBJC_COLLECTING_CACHE) - #include "objc-msg-m68k-nolock.s" - #else - #include "objc-msg-m68k-lock.s" - #endif - -#elif defined (WIN32) - #include "objc-msg-i386-nextpdo-winnt3.5.s" - -#elif defined (__i386__) || defined (i386) +#if defined (__i386__) || defined (i386) #include "objc-msg-i386.s" - -#elif defined (hppa) - #if defined(NeXT_PDO) - #if defined(NSBUILDINGHPUXSHLIB) - #include "objc-msg-hppa-pdo-pic.s" - #else - #include "objc-msg-hppa-pdo.s" - #endif - #elif defined(OBJC_COLLECTING_CACHE) - #include "objc-msg-hppa-nolock.s" - #else - #include "objc-msg-hppa-lock.s" - #endif - -#elif defined (sparc) - #if defined(NeXT_PDO) - #include "objc-msg-sparc-pdo.s" - #else - #include "objc-msg-sparc.s" - #endif - #elif defined (__ppc__) || defined(ppc) #include "objc-msg-ppc.s" diff --git a/runtime/Object.m b/runtime/Object.m index 569ae50..08a6df4 100644 --- a/runtime/Object.m +++ b/runtime/Object.m @@ -1044,9 +1044,6 @@ Ivar object_getInstanceVariable(id obj, const char *name, void **value) return ivar; } -#if defined(__hpux__) -id (*_objc_msgSend_v)(id, SEL, ...) = objc_msgSend; -#endif id (*_copy)(id, unsigned) = _internal_object_copy; id (*_realloc)(id, unsigned) = _internal_object_realloc; diff --git a/runtime/OldClasses.subproj/List.m b/runtime/OldClasses.subproj/List.m index 290334c..43cc3cb 100644 --- a/runtime/OldClasses.subproj/List.m +++ b/runtime/OldClasses.subproj/List.m @@ -28,11 +28,6 @@ Responsibility: Bertrand Serlet */ -#if defined(__svr4__) || defined(__hpux__) || defined(hpux) - #import // for bcmp() -#elif defined(WIN32) - #import // for bcopy() -#endif #import #import diff --git a/runtime/PB.project b/runtime/PB.project index 09488b5..e197c50 100644 --- a/runtime/PB.project +++ b/runtime/PB.project @@ -32,13 +32,8 @@ Object.m, Protocol.m ); - OTHER_SOURCES = ( - Makefile.preamble, - Makefile, - Makefile.postamble, - objc_hpux_register_shlib.c, - objc_dllMain.c - ); + OTHER_SOURCES = (Makefile.preamble, Makefile, Makefile.postamble); + PROJECT_HEADERS = ("objc-runtime.h", "objc-class.h"); PUBLIC_HEADERS = ( "objc-class.h", "objc-api.h", @@ -55,7 +50,7 @@ LANGUAGE = English; LOCALIZABLE_FILES = {}; MAKEFILEDIR = "$(MAKEFILEPATH)/pb_makefiles"; - NEXTSTEP_BUILDTOOL = /bin/gnumake; + NEXTSTEP_BUILDTOOL = /usr/bin/gnumake; NEXTSTEP_INSTALLDIR = /usr/lib; NEXTSTEP_JAVA_COMPILER = /usr/bin/javac; NEXTSTEP_OBJCPLUS_COMPILER = /usr/bin/cc; diff --git a/runtime/Protocol.h b/runtime/Protocol.h index 033aa26..2c66904 100644 --- a/runtime/Protocol.h +++ b/runtime/Protocol.h @@ -46,11 +46,6 @@ struct objc_method_description_list { char *protocol_name; struct objc_protocol_list *protocol_list; struct objc_method_description_list *instance_methods, *class_methods; -#ifdef NeXT_PDO /* hppa needs 8 byte aligned protocol blocks */ -#if defined(__hpux__) || defined(hpux) - unsigned long risc_pad; -#endif /* __hpux__ || hpux */ -#endif NeXT_PDO } /* Obtaining attributes intrinsic to the protocol */ diff --git a/runtime/Protocol.m b/runtime/Protocol.m index 90cb3f8..f9f4c12 100644 --- a/runtime/Protocol.m +++ b/runtime/Protocol.m @@ -26,9 +26,6 @@ Copyright 1991-1996 NeXT Software, Inc. */ -#if defined(WIN32) - #include -#endif #include "objc-private.h" #import @@ -36,10 +33,8 @@ #include #include -#if defined(__MACH__) - #include - #include -#endif +#include +#include /* some forward declarations */ diff --git a/runtime/error.h b/runtime/error.h index 19791e3..3faf3d5 100644 --- a/runtime/error.h +++ b/runtime/error.h @@ -39,10 +39,6 @@ #include #import -#if defined(__svr4__) - #define _setjmp setjmp - #define _longjmp longjmp -#endif typedef struct _NXHandler { /* a node in the handler chain */ jmp_buf jumpState; /* place to longjmp to */ diff --git a/runtime/hashtable2.m b/runtime/hashtable2.m index a6cb71a..26b88e1 100644 --- a/runtime/hashtable2.m +++ b/runtime/hashtable2.m @@ -141,7 +141,7 @@ NXHashTable *NXCreateHashTableFromZone (NXHashTablePrototype prototype, unsigned if (! prototype.isEqual) prototype.isEqual = NXPtrIsEqual; if (! prototype.free) prototype.free = NXNoEffectFree; if (prototype.style) { - _NXLogError ("*** NXCreateHashTable: invalid style\n"); + _objc_syslog ("*** NXCreateHashTable: invalid style\n"); return NULL; }; proto = NXHashGet (prototypes, &prototype); @@ -153,7 +153,7 @@ NXHashTable *NXCreateHashTableFromZone (NXHashTablePrototype prototype, unsigned (void) NXHashInsert (prototypes, proto); proto = NXHashGet (prototypes, &prototype); if (! proto) { - _NXLogError ("*** NXCreateHashTable: bug\n"); + _objc_syslog ("*** NXCreateHashTable: bug\n"); return NULL; }; }; @@ -310,7 +310,7 @@ static void _NXHashRehash (NXHashTable *table) { (void) NXHashInsert (table, aux); freeBuckets (old, NO); if (old->count != table->count) - _NXLogError("*** hashtable: count differs after rehashing; probably indicates a broken invariant: there are x and y such as isEqual(x, y) is TRUE but hash(x) != hash (y)\n"); + _objc_syslog("*** hashtable: count differs after rehashing; probably indicates a broken invariant: there are x and y such as isEqual(x, y) is TRUE but hash(x) != hash (y)\n"); free (old->buckets); free (old); }; @@ -603,7 +603,7 @@ NXAtom NXUniqueString (const char *buffer) { if (previous) return previous; previous = CopyIntoReadOnly (buffer); if (NXHashInsert (uniqueStrings, previous)) { - _NXLogError ("*** NXUniqueString: invariant broken\n"); + _objc_syslog ("*** NXUniqueString: invariant broken\n"); return NULL; }; return previous; diff --git a/runtime/maptable.m b/runtime/maptable.m index 50e9647..168428b 100644 --- a/runtime/maptable.m +++ b/runtime/maptable.m @@ -26,9 +26,6 @@ Created by Bertrand Serlet, August 1990 */ -#if defined(WIN32) - #include -#endif #import "objc-private.h" #import "maptable.h" @@ -39,9 +36,6 @@ #import #import -#if defined(NeXT_PDO) - #import -#endif /****** Macros and utilities ****************************/ @@ -111,7 +105,7 @@ NXMapTable *NXCreateMapTableFromZone(NXMapTablePrototype prototype, unsigned cap NXMapTablePrototype *proto; if (! prototypes) prototypes = NXCreateHashTable(protoPrototype, 0, NULL); if (! prototype.hash || ! prototype.isEqual || ! prototype.free || prototype.style) { - _NXLogError("*** NXCreateMapTable: invalid creation parameters\n"); + _objc_syslog("*** NXCreateMapTable: invalid creation parameters\n"); return NULL; } proto = NXHashGet(prototypes, &prototype); @@ -224,7 +218,7 @@ static void _NXMapRehash(NXMapTable *table) { pair++; } if (oldCount != table->count) - _NXLogError("*** maptable: count differs after rehashing; probably indicates a broken invariant: there are x and y such as isEqual(x, y) is TRUE but hash(x) != hash (y)\n"); + _objc_syslog("*** maptable: count differs after rehashing; probably indicates a broken invariant: there are x and y such as isEqual(x, y) is TRUE but hash(x) != hash (y)\n"); free(pairs); } @@ -237,7 +231,7 @@ void *NXMapInsert(NXMapTable *table, const void *key, const void *value) { unsigned index = bucketOf(table, key); MapPair *pair = pairs + index; if (key == NX_MAPNOTAKEY) { - _NXLogError("*** NXMapInsert: invalid key: -1\n"); + _objc_syslog("*** NXMapInsert: invalid key: -1\n"); return NULL; } mapInsert ++; @@ -287,7 +281,7 @@ void *NXMapInsert(NXMapTable *table, const void *key, const void *value) { } } /* no room: can't happen! */ - _NXLogError("**** NXMapInsert: bug\n"); + _objc_syslog("**** NXMapInsert: bug\n"); return NULL; } } @@ -315,7 +309,7 @@ void *NXMapRemove(NXMapTable *table, const void *key) { } } if (! found) return NULL; - if (found != 1) _NXLogError("**** NXMapRemove: incorrect table\n"); + if (found != 1) _objc_syslog("**** NXMapRemove: incorrect table\n"); /* remove then reinsert */ { MapPair buffer[16]; @@ -330,7 +324,7 @@ void *NXMapRemove(NXMapTable *table, const void *key) { index2 = nextIndex(table, index2); } table->count -= chain; - if (auxnb != chain-1) _NXLogError("**** NXMapRemove: bug\n"); + if (auxnb != chain-1) _objc_syslog("**** NXMapRemove: bug\n"); while (auxnb--) NXMapInsert(table, aux[auxnb].key, aux[auxnb].value); if (chain > 16) free(aux); } diff --git a/runtime/objc-api.h b/runtime/objc-api.h index 36ebc0f..2b139e1 100644 --- a/runtime/objc-api.h +++ b/runtime/objc-api.h @@ -23,18 +23,6 @@ */ // Copyright 1988-1996 NeXT Software, Inc. -#if defined(WIN32) - #if defined(NSBUILDINGOBJC) - #define OBJC_EXPORT __declspec(dllexport) extern - #else - #if !defined(OBJC_EXPORT) - #define OBJC_EXPORT __declspec(dllimport) extern - #endif - #endif - #if !defined(OBJC_IMPORT) - #define OBJC_IMPORT __declspec(dllimport) extern - #endif -#endif #if !defined(OBJC_EXPORT) #define OBJC_EXPORT extern @@ -45,11 +33,3 @@ #endif -// obsolete -#if !defined(NEXTPDO) - #if defined(WIN32) - #define NEXTPDO __declspec(dllimport) extern - #else - #define NEXTPDO extern - #endif -#endif diff --git a/runtime/objc-class.h b/runtime/objc-class.h index 9a7b57c..7d3be02 100644 --- a/runtime/objc-class.h +++ b/runtime/objc-class.h @@ -42,11 +42,7 @@ struct objc_class { long instance_size; struct objc_ivar_list *ivars; -#if defined(Release3CompatibilityBuild) - struct objc_method_list *methods; -#else struct objc_method_list **methodLists; -#endif struct objc_cache *cache; struct objc_protocol_list *protocols; @@ -61,7 +57,11 @@ struct objc_class { #define CLS_MAPPED 0x10L #define CLS_FLUSH_CACHE 0x20L #define CLS_GROW_CACHE 0x40L +#define CLS_NEED_BIND 0x80L #define CLS_METHOD_ARRAY 0x100L +// the JavaBridge constructs classes with these markers +#define CLS_JAVA_HYBRID 0x200L +#define CLS_JAVA_CLASS 0x400L /* * Category Template */ @@ -103,11 +103,7 @@ OBJC_EXPORT Ivar object_getInstanceVariable(id, const char *name, void **); typedef struct objc_method *Method; struct objc_method_list { -#if defined(Release3CompatibilityBuild) - struct objc_method_list *method_next; -#else struct objc_method_list *obsolete; -#endif int method_count; #ifdef __alpha__ @@ -202,29 +198,6 @@ OBJC_EXPORT struct objc_method_list *class_nextMethodList(Class, void **); typedef void *marg_list; -#if hppa - -#define marg_malloc(margs, method) \ - do { \ - unsigned int _sz = (7 + method_getSizeOfArguments(method)) & ~7; \ - char *_ml = (char *)malloc(_sz + sizeof(marg_list)); \ - void **_z ; \ - margs = (marg_list *)(_ml + _sz); \ - _z = margs; \ - *_z = (marg_list)_ml; \ - } while (0) - -#define marg_free(margs) \ - do { \ - void **_z = margs; \ - free(*_z); \ - } while (0) - -#define marg_adjustedOffset(method, offset) \ - ( (!offset) ? -(sizeof(id)) : offset) - -#else - #if defined(__ppc__) || defined(ppc) #define marg_prearg_size 128 #else @@ -245,7 +218,7 @@ typedef void *marg_list; #define marg_adjustedOffset(method, offset) \ (marg_prearg_size + offset) -#endif /* hppa */ + #define marg_getRef(margs, offset, type) \ @@ -258,35 +231,5 @@ typedef void *marg_list; ( marg_getValue(margs, offset, type) = (value) ) /* Load categories and non-referenced classes from libraries. */ -#if defined(NeXT_PDO) -#if defined(__hpux__) || defined(hpux) - -#define OBJC_REGISTER_SYMBOL(NAME) asm("._" #NAME "=0\n .globl ._" #NAME "\n") -#define OBJC_REFERENCE_SYMBOL(NAME) asm(".SPACE $PRIVATE$\n\t.SUBSPA $DATA$\n\t.word ._" #NAME "\n\t.SPACE $TEXT$\n\t.SUBSPA $CODE$\n") -#define OBJC_REGISTER_CATEGORY(NAME) asm("._" #NAME "=0\n .globl ._" #NAME "\n") -#define OBJC_REFERENCE_CATEGORY(NAME) asm(".SPACE $PRIVATE$\n\t.SUBSPA $DATA$\n\t.word ._" #NAME "\n\t.SPACE $TEXT$\n\t.SUBSPA $CODE$\n") -#define OBJC_REFERENCE_CLASS_CATEGORY(CL, CAT) asm(".SPACE $PRIVATE$\n\t.SUBSPA $DATA$\n\t.word .objc_category_name_" #CL "_" #CAT "\n\t.SPACE $TEXT$\n\t.SUBSPA $CODE$\n") -#define OBJC_REFERENCE_CLASS(NAME) asm(".SPACE $PRIVATE$\n\t.SUBSPA $DATA$\n\t.word .objc_class_name_" #NAME "\n\t.SPACE $TEXT$\n\t.SUBSPA $CODE$\n") - -#elif defined(__osf__) - -#define OBJC_REGISTER_SYMBOL(NAME) asm(".globl ._" #NAME "\n\t.align 3\n._" #NAME ":\n\t.quad 0\n") -#define OBJC_REFERENCE_SYMBOL(NAME) asm(".align 3\n\t.quad ._" #NAME "\n") -#define OBJC_REGISTER_CATEGORY(NAME) asm(".globl ._" #NAME "\n\t.align 3\n._" #NAME ":\n\t.quad 0\n") -#define OBJC_REFERENCE_CATEGORY(NAME) asm(".align 3\n\t.quad ._" #NAME "\n") -#define OBJC_REFERENCE_CLASS_CATEGORY(CL, CAT) asm(".align 3\n\t.quad .objc_category_name_" #CL "_" #CAT "\n") -#define OBJC_REFERENCE_CLASS(NAME) asm(".quad .objc_class_name_" #NAME "\n") - -#else /* Solaris || SunOS */ - -#define OBJC_REGISTER_SYMBOL(NAME) asm("._" #NAME "=0\n .globl ._" #NAME "\n") -#define OBJC_REFERENCE_SYMBOL(NAME) asm(".global ._" #NAME "\n") -#define OBJC_REGISTER_CATEGORY(NAME) asm("._" #NAME "=0\n .globl ._" #NAME "\n") -#define OBJC_REFERENCE_CATEGORY(NAME) asm(".global ._" #NAME "\n") -#define OBJC_REFERENCE_CLASS_CATEGORY(CL, CAT) asm(".global .objc_category_name_" #CL "_" #CAT "\n") -#define OBJC_REFERENCE_CLASS(NAME) asm(".global .objc_class_name_" #NAME "\n") - -#endif /* __hpux__ || hpux */ -#endif /* NeXT_PDO */ #endif /* _OBJC_CLASS_H_ */ diff --git a/runtime/objc-class.m b/runtime/objc-class.m index 71b8c9e..cfb47f2 100644 --- a/runtime/objc-class.m +++ b/runtime/objc-class.m @@ -2,7 +2,7 @@ * Copyright (c) 1999 Apple Computer, Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ - * + * * Portions Copyright (c) 1999 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 @@ -10,7 +10,7 @@ * except in compliance with the License. Please obtain a copy of the * License at http://www.apple.com/publicsource 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, @@ -18,44 +18,30 @@ * FITNESS FOR A PARTICULAR PURPOSE OR NON- INFRINGEMENT. Please see the * License for the specific language governing rights and limitations * under the License. - * + * * @APPLE_LICENSE_HEADER_END@ */ /*********************************************************************** - * objc-class.m - * Copyright 1988-1997, Apple Computer, Inc. - * Author: s. naroff - **********************************************************************/ +* objc-class.m +* Copyright 1988-1997, Apple Computer, Inc. +* Author: s. naroff +**********************************************************************/ /*********************************************************************** - * Imports. - **********************************************************************/ +* Imports. +**********************************************************************/ -#ifdef __MACH__ - #import - #include - #include -#endif +#import +#include +#include -#ifdef WIN32 - #include - #include - #include -#else - #include - #include - #include - #include - #ifdef __svr4__ - #include - #else - #include - #endif -#endif - -#if defined(__svr4__) || defined(__hpux__) || defined(hpux) - #import -#endif +#include +#include +#include +#include +#include + +#import "objc-class.h" #import #import @@ -72,21 +58,12 @@ size_t malloc_size (const void * ptr); // Needed kernel interface #import -#ifdef __MACH__ #import -#endif -// This is currently disabled in this file, because it is called a LOT here; turn it on when needed. -#if 0 && defined(__MACH__) -extern int ptrace(int, int, int, int); -// ObjC is assigned the range 0xb000 - 0xbfff for first parameter; this file 0xb300-0xb3ff -#else -#define ptrace(a, b, c, d) do {} while (0) -#endif /*********************************************************************** - * Conditionals. - **********************************************************************/ +* Conditionals. +**********************************************************************/ // Define PRELOAD_SUPERCLASS_CACHES to cause method lookups to add the // method the appropriate superclass caches, in addition to the normal @@ -94,15 +71,17 @@ extern int ptrace(int, int, int, int); // will speed up messaging the same method from instances of the // superclasses, but also uses up valuable cache space for a speculative // purpose +// See radar 2364264 about incorrectly propogating _objc_forward entries +// and double freeing them, first, before turning this on! //#define PRELOAD_SUPERCLASS_CACHES /*********************************************************************** - * Exports. - **********************************************************************/ +* Exports. +**********************************************************************/ #ifdef OBJC_INSTRUMENTED enum { - CACHE_HISTOGRAM_SIZE = 512 + CACHE_HISTOGRAM_SIZE = 512 }; unsigned int CacheHitHistogram [CACHE_HISTOGRAM_SIZE]; @@ -110,15 +89,15 @@ unsigned int CacheMissHistogram [CACHE_HISTOGRAM_SIZE]; #endif /*********************************************************************** - * Constants and macros internal to this module. - **********************************************************************/ +* Constants and macros internal to this module. +**********************************************************************/ // INIT_CACHE_SIZE and INIT_META_CACHE_SIZE must be a power of two enum { - INIT_CACHE_SIZE_LOG2 = 2, - INIT_META_CACHE_SIZE_LOG2 = 2, - INIT_CACHE_SIZE = (1 << INIT_CACHE_SIZE_LOG2), - INIT_META_CACHE_SIZE = (1 << INIT_META_CACHE_SIZE_LOG2) + INIT_CACHE_SIZE_LOG2 = 2, + INIT_META_CACHE_SIZE_LOG2 = 2, + INIT_CACHE_SIZE = (1 << INIT_CACHE_SIZE_LOG2), + INIT_META_CACHE_SIZE = (1 << INIT_META_CACHE_SIZE_LOG2) }; // Amount of space required for count hash table buckets, knowing that @@ -133,21 +112,21 @@ enum { #define MARKINITIALIZED(cls) (GETMETA(cls)->info |= CLS_INITIALIZED) /*********************************************************************** - * Types internal to this module. - **********************************************************************/ +* Types internal to this module. +**********************************************************************/ #ifdef OBJC_INSTRUMENTED struct CacheInstrumentation { - unsigned int hitCount; // cache lookup success tally - unsigned int hitProbes; // sum entries checked to hit - unsigned int maxHitProbes; // max entries checked to hit - unsigned int missCount; // cache lookup no-find tally - unsigned int missProbes; // sum entries checked to miss - unsigned int maxMissProbes; // max entries checked to miss - unsigned int flushCount; // cache flush tally - unsigned int flushedEntries; // sum cache entries flushed - unsigned int maxFlushedEntries; // max cache entries flushed + unsigned int hitCount; // cache lookup success tally + unsigned int hitProbes; // sum entries checked to hit + unsigned int maxHitProbes; // max entries checked to hit + unsigned int missCount; // cache lookup no-find tally + unsigned int missProbes; // sum entries checked to miss + unsigned int maxMissProbes; // max entries checked to miss + unsigned int flushCount; // cache flush tally + unsigned int flushedEntries; // sum cache entries flushed + unsigned int maxFlushedEntries; // max cache entries flushed }; typedef struct CacheInstrumentation CacheInstrumentation; @@ -156,14 +135,14 @@ typedef struct CacheInstrumentation CacheInstrumentation; #endif /*********************************************************************** - * Function prototypes internal to this module. - **********************************************************************/ +* Function prototypes internal to this module. +**********************************************************************/ static Ivar class_getVariable (Class cls, const char * name); static void flush_caches (Class cls, BOOL flush_meta); static void addClassToOriginalClass (Class posingClass, Class originalClass); static void _objc_addOrigClass (Class origClass); -static void _freedHandler (id self, SEL sel); +static void _freedHandler (id self, SEL sel); static void _nonexistentHandler (id self, SEL sel); static void class_initialize (Class clsDesc); static void * objc_malloc (int byteCount); @@ -172,8 +151,8 @@ static int LogObjCMessageSend (BOOL isClassMethod, const char * objectsClass, static void _cache_fill (Class cls, Method smt, SEL sel); static void _cache_flush (Class cls); static Method _class_lookupMethod (Class cls, SEL sel); -static int SubtypeUntil (const char * type, char end); -static const char * SkipFirstType (const char * type); +static int SubtypeUntil (const char * type, char end); +static const char * SkipFirstType (const char * type); #ifdef OBJC_COLLECTING_CACHE static unsigned long _get_pc_for_thread (mach_port_t thread); @@ -190,8 +169,8 @@ static void PrintCacheHistogram (char * title, unsigned int * firstEntry, unsi #endif /*********************************************************************** - * Static data internal to this module. - **********************************************************************/ +* Static data internal to this module. +**********************************************************************/ // When _class_uncache is non-zero, cache growth copies the existing // entries into the new (larger) cache. When this flag is zero, new @@ -232,7 +211,7 @@ CFMutableDictionaryRef _classIMPTables = NULL; static int traceDuplicates = 0; static int traceDuplicatesVerbose = 0; static int cacheFillDuplicates = 0; -#endif +#endif #ifdef OBJC_INSTRUMENTED // Instrumentation @@ -257,183 +236,183 @@ static int objcMsgLogEnabled = 0; // Error Messages static const char - _errNoMem[] = "failed -- out of memory(%s, %u)", - _errAllocNil[] = "allocating nil object", - _errFreedObject[] = "message %s sent to freed object=0x%lx", - _errNonExistentObject[] = "message %s sent to non-existent object=0x%lx", - _errBadSel[] = "invalid selector %s", - _errNotSuper[] = "[%s poseAs:%s]: target not immediate superclass", - _errNewVars[] = "[%s poseAs:%s]: %s defines new instance variables"; - -/*********************************************************************** - * Information about multi-thread support: - * - * Since we do not lock many operations which walk the superclass, method - * and ivar chains, these chains must remain intact once a class is published - * by inserting it into the class hashtable. All modifications must be - * atomic so that someone walking these chains will always geta valid - * result. - ***********************************************************************/ -/*********************************************************************** - * A static empty cache. All classes initially point at this cache. - * When the first message is sent it misses in the cache, and when - * the cache is grown it checks for this case and uses malloc rather - * than realloc. This avoids the need to check for NULL caches in the - * messenger. - ***********************************************************************/ +_errNoMem[] = "failed -- out of memory(%s, %u)", +_errAllocNil[] = "allocating nil object", +_errFreedObject[] = "message %s sent to freed object=0x%lx", +_errNonExistentObject[] = "message %s sent to non-existent object=0x%lx", +_errBadSel[] = "invalid selector %s", +_errNotSuper[] = "[%s poseAs:%s]: target not immediate superclass", +_errNewVars[] = "[%s poseAs:%s]: %s defines new instance variables"; + +/*********************************************************************** +* Information about multi-thread support: +* +* Since we do not lock many operations which walk the superclass, method +* and ivar chains, these chains must remain intact once a class is published +* by inserting it into the class hashtable. All modifications must be +* atomic so that someone walking these chains will always geta valid +* result. +***********************************************************************/ +/*********************************************************************** +* A static empty cache. All classes initially point at this cache. +* When the first message is sent it misses in the cache, and when +* the cache is grown it checks for this case and uses malloc rather +* than realloc. This avoids the need to check for NULL caches in the +* messenger. +***********************************************************************/ const struct objc_cache emptyCache = { - 0, // mask - 0, // occupied - { NULL } // buckets + 0, // mask + 0, // occupied + { NULL } // buckets }; // Freed objects have their isa set to point to this dummy class. // This avoids the need to check for Nil classes in the messenger. static const struct objc_class freedObjectClass = { - Nil, // isa - Nil, // super_class - "FREED(id)", // name - 0, // version - 0, // info - 0, // instance_size - NULL, // ivars - NULL, // methodLists - (Cache) &emptyCache, // cache - NULL // protocols + Nil, // isa + Nil, // super_class + "FREED(id)", // name + 0, // version + 0, // info + 0, // instance_size + NULL, // ivars + NULL, // methodLists + (Cache) &emptyCache, // cache + NULL // protocols }; static const struct objc_class nonexistentObjectClass = { - Nil, // isa - Nil, // super_class - "NONEXISTENT(id)", // name - 0, // version - 0, // info - 0, // instance_size - NULL, // ivars - NULL, // methodLists - (Cache) &emptyCache, // cache - NULL // protocols + Nil, // isa + Nil, // super_class + "NONEXISTENT(id)", // name + 0, // version + 0, // info + 0, // instance_size + NULL, // ivars + NULL, // methodLists + (Cache) &emptyCache, // cache + NULL // protocols }; /*********************************************************************** - * object_getClassName. - **********************************************************************/ +* object_getClassName. +**********************************************************************/ const char * object_getClassName (id obj) { - // Even nil objects have a class name, sort of - if (obj == nil) - return "nil"; + // Even nil objects have a class name, sort of + if (obj == nil) + return "nil"; - // Retrieve name from object's class - return ((struct objc_class *) obj->isa)->name; + // Retrieve name from object's class + return ((struct objc_class *) obj->isa)->name; } /*********************************************************************** - * object_getIndexedIvars. - **********************************************************************/ +* object_getIndexedIvars. +**********************************************************************/ void * object_getIndexedIvars (id obj) { - // ivars are tacked onto the end of the object - return ((char *) obj) + ((struct objc_class *) obj->isa)->instance_size; + // ivars are tacked onto the end of the object + return ((char *) obj) + ((struct objc_class *) obj->isa)->instance_size; } /*********************************************************************** - * _internal_class_createInstanceFromZone. Allocate an instance of the - * specified class with the specified number of bytes for indexed - * variables, in the specified zone. The isa field is set to the - * class, all other fields are zeroed. - **********************************************************************/ +* _internal_class_createInstanceFromZone. Allocate an instance of the +* specified class with the specified number of bytes for indexed +* variables, in the specified zone. The isa field is set to the +* class, all other fields are zeroed. +**********************************************************************/ static id _internal_class_createInstanceFromZone (Class aClass, - unsigned nIvarBytes, - void * z) -{ - id obj; - register unsigned byteCount; - - // Can't create something for nothing - if (aClass == Nil) - { - __objc_error ((id) aClass, _errAllocNil, 0); - return nil; - } - - // Allocate and initialize - byteCount = ((struct objc_class *) aClass)->instance_size + nIvarBytes; - obj = (id) malloc_zone_calloc (z, 1, byteCount); - if (!obj) - { - __objc_error ((id) aClass, _errNoMem, ((struct objc_class *) aClass)->name, nIvarBytes); - return nil; - } - - // Set the isa pointer - obj->isa = aClass; - return obj; -} - -/*********************************************************************** - * _internal_class_createInstance. Allocate an instance of the specified - * class with the specified number of bytes for indexed variables, in - * the default zone, using _internal_class_createInstanceFromZone. - **********************************************************************/ + unsigned nIvarBytes, + void * z) +{ + id obj; + register unsigned byteCount; + + // Can't create something for nothing + if (aClass == Nil) + { + __objc_error ((id) aClass, _errAllocNil, 0); + return nil; + } + + // Allocate and initialize + byteCount = ((struct objc_class *) aClass)->instance_size + nIvarBytes; + obj = (id) malloc_zone_calloc (z, 1, byteCount); + if (!obj) + { + __objc_error ((id) aClass, _errNoMem, ((struct objc_class *) aClass)->name, nIvarBytes); + return nil; + } + + // Set the isa pointer + obj->isa = aClass; + return obj; +} + +/*********************************************************************** +* _internal_class_createInstance. Allocate an instance of the specified +* class with the specified number of bytes for indexed variables, in +* the default zone, using _internal_class_createInstanceFromZone. +**********************************************************************/ static id _internal_class_createInstance (Class aClass, - unsigned nIvarBytes) + unsigned nIvarBytes) { - return _internal_class_createInstanceFromZone (aClass, - nIvarBytes, - malloc_default_zone ()); -} + return _internal_class_createInstanceFromZone (aClass, + nIvarBytes, + malloc_default_zone ()); +} id (*_poseAs)() = (id (*)())class_poseAs; id (*_alloc)(Class, unsigned) = _internal_class_createInstance; id (*_zoneAlloc)(Class, unsigned, void *) = _internal_class_createInstanceFromZone; /*********************************************************************** - * class_createInstanceFromZone. Allocate an instance of the specified - * class with the specified number of bytes for indexed variables, in - * the specified zone, using _zoneAlloc. - **********************************************************************/ +* class_createInstanceFromZone. Allocate an instance of the specified +* class with the specified number of bytes for indexed variables, in +* the specified zone, using _zoneAlloc. +**********************************************************************/ id class_createInstanceFromZone (Class aClass, - unsigned nIvarBytes, - void * z) + unsigned nIvarBytes, + void * z) { - // _zoneAlloc can be overridden, but is initially set to - // _internal_class_createInstanceFromZone - return (*_zoneAlloc) (aClass, nIvarBytes, z); -} + // _zoneAlloc can be overridden, but is initially set to + // _internal_class_createInstanceFromZone + return (*_zoneAlloc) (aClass, nIvarBytes, z); +} /*********************************************************************** - * class_createInstance. Allocate an instance of the specified class with - * the specified number of bytes for indexed variables, using _alloc. - **********************************************************************/ +* class_createInstance. Allocate an instance of the specified class with +* the specified number of bytes for indexed variables, using _alloc. +**********************************************************************/ id class_createInstance (Class aClass, - unsigned nIvarBytes) + unsigned nIvarBytes) { - // _alloc can be overridden, but is initially set to - // _internal_class_createInstance - return (*_alloc) (aClass, nIvarBytes); -} + // _alloc can be overridden, but is initially set to + // _internal_class_createInstance + return (*_alloc) (aClass, nIvarBytes); +} /*********************************************************************** - * class_setVersion. Record the specified version with the class. - **********************************************************************/ +* class_setVersion. Record the specified version with the class. +**********************************************************************/ void class_setVersion (Class aClass, - int version) + int version) { - ((struct objc_class *) aClass)->version = version; + ((struct objc_class *) aClass)->version = version; } /*********************************************************************** - * class_getVersion. Return the version recorded with the class. - **********************************************************************/ +* class_getVersion. Return the version recorded with the class. +**********************************************************************/ int class_getVersion (Class aClass) { - return ((struct objc_class *) aClass)->version; + return ((struct objc_class *) aClass)->version; } static void _addListIMPsToTable(CFMutableDictionaryRef table, struct objc_method_list *mlist, Class cls, void **iterator) { @@ -444,7 +423,7 @@ static void _addListIMPsToTable(CFMutableDictionaryRef table, struct objc_method new_mlist = _class_inlinedNextMethodList(cls, iterator); _addListIMPsToTable(table, new_mlist, cls, iterator); for (i = 0; i < mlist->method_count; i++) { - CFDictionarySetValue(table, mlist->method_list[i].method_name, mlist->method_list[i].method_imp); + CFDictionarySetValue(table, mlist->method_list[i].method_name, mlist->method_list[i].method_imp); } } @@ -453,40 +432,40 @@ static void _addClassIMPsToTable(CFMutableDictionaryRef table, Class cls) { void *iterator = 0; #ifdef INCLUDE_SUPER_IMPS_IN_IMP_TABLE if (cls->super_class) { /* Do superclass first so subclass overrides */ - CFMutableDictionaryRef super_table = CFDictionaryGetValue(_classIMPTables, cls->super_class); - if (super_table) { - CFIndex cnt; - const void **keys, **values, *buffer1[128], *buffer2[128]; - cnt = CFDictionaryGetCount(super_table); - keys = (cnt <= 128) ? buffer1 : CFAllocatorAllocate(NULL, cnt * sizeof(void *), 0); - values = (cnt <= 128) ? buffer2 : CFAllocatorAllocate(NULL, cnt * sizeof(void *), 0); - CFDictionaryGetKeysAndValues(super_table, keys, values); - while (cnt--) { - CFDictionarySetValue(table, keys[cnt], values[cnt]); - } - if (keys != buffer1) CFAllocatorDeallocate(NULL, keys); - if (values != buffer2) CFAllocatorDeallocate(NULL, values); - } else { - _addClassIMPsToTable(table, cls->super_class); - } + CFMutableDictionaryRef super_table = CFDictionaryGetValue(_classIMPTables, cls->super_class); + if (super_table) { + CFIndex cnt; + const void **keys, **values, *buffer1[128], *buffer2[128]; + cnt = CFDictionaryGetCount(super_table); + keys = (cnt <= 128) ? buffer1 : CFAllocatorAllocate(NULL, cnt * sizeof(void *), 0); + values = (cnt <= 128) ? buffer2 : CFAllocatorAllocate(NULL, cnt * sizeof(void *), 0); + CFDictionaryGetKeysAndValues(super_table, keys, values); + while (cnt--) { + CFDictionarySetValue(table, keys[cnt], values[cnt]); + } + if (keys != buffer1) CFAllocatorDeallocate(NULL, keys); + if (values != buffer2) CFAllocatorDeallocate(NULL, values); + } else { + _addClassIMPsToTable(table, cls->super_class); + } } #endif - mlist = _class_inlinedNextMethodList(cls, &iterator); - _addListIMPsToTable(table, mlist, cls, &iterator); +mlist = _class_inlinedNextMethodList(cls, &iterator); +_addListIMPsToTable(table, mlist, cls, &iterator); } CFMutableDictionaryRef _getClassIMPTable(Class cls) { CFMutableDictionaryRef table; if (NULL == _classIMPTables) { - // maps Classes to mutable dictionaries - _classIMPTables = CFDictionaryCreateMutable(NULL, 0, NULL, NULL); + // maps Classes to mutable dictionaries + _classIMPTables = CFDictionaryCreateMutable(NULL, 0, NULL, NULL); } table = (CFMutableDictionaryRef)CFDictionaryGetValue(_classIMPTables, cls); // IMP table maps SELs to IMPS if (NULL == table) { - table = CFDictionaryCreateMutable(NULL, 0, NULL, NULL); - _addClassIMPsToTable(table, cls); - CFDictionaryAddValue(_classIMPTables, cls, table); + table = CFDictionaryCreateMutable(NULL, 0, NULL, NULL); + _addClassIMPsToTable(table, cls); + CFDictionaryAddValue(_classIMPTables, cls, table); } return table; } @@ -495,10 +474,10 @@ static inline Method _findNamedMethodInList(struct objc_method_list * mlist, con int i; if (!mlist) return NULL; for (i = 0; i < mlist->method_count; i++) { - Method m = &mlist->method_list[i]; - if (*((const char *)m->method_name) == *meth_name && 0 == strcmp((const char *)(m->method_name), meth_name)) { - return m; - } + Method m = &mlist->method_list[i]; + if (*((const char *)m->method_name) == *meth_name && 0 == strcmp((const char *)(m->method_name), meth_name)) { + return m; + } } return NULL; } @@ -508,10 +487,10 @@ static inline Method _findMethodInList(struct objc_method_list * mlist, SEL sel) int i; if (!mlist) return NULL; for (i = 0; i < mlist->method_count; i++) { - Method m = &mlist->method_list[i]; - if (m->method_name == sel) { - return m; - } + Method m = &mlist->method_list[i]; + if (m->method_name == sel) { + return m; + } } return NULL; } @@ -520,8 +499,8 @@ static inline Method _findMethodInClass(Class cls, SEL sel) { struct objc_method_list *mlist; void *iterator = 0; while ((mlist = _class_inlinedNextMethodList(cls, &iterator))) { - Method m = _findMethodInList(mlist, sel); - if (m) return m; + Method m = _findMethodInList(mlist, sel); + if (m) return m; } return NULL; } @@ -529,1993 +508,2011 @@ static inline Method _findMethodInClass(Class cls, SEL sel) { static inline Method _getMethod(Class cls, SEL sel) { for (; cls; cls = cls->super_class) { Method m = _findMethodInClass(cls, sel); - if (m) return m; + if (m) return m; } return NULL; } /*********************************************************************** - * class_getInstanceMethod. Return the instance method for the - * specified class and selector. - **********************************************************************/ +* class_getInstanceMethod. Return the instance method for the +* specified class and selector. +**********************************************************************/ Method class_getInstanceMethod (Class aClass, - SEL aSelector) + SEL aSelector) { - // Need both a class and a selector - if (!aClass || !aSelector) - return NULL; + // Need both a class and a selector + if (!aClass || !aSelector) + return NULL; - // Go to the class - return _getMethod (aClass, aSelector); + // Go to the class + return _getMethod (aClass, aSelector); } /*********************************************************************** - * class_getClassMethod. Return the class method for the specified - * class and selector. - **********************************************************************/ +* class_getClassMethod. Return the class method for the specified +* class and selector. +**********************************************************************/ Method class_getClassMethod (Class aClass, - SEL aSelector) + SEL aSelector) { - // Need both a class and a selector - if (!aClass || !aSelector) - return NULL; + // Need both a class and a selector + if (!aClass || !aSelector) + return NULL; - // Go to the class or isa - return _getMethod (GETMETA(aClass), aSelector); + // Go to the class or isa + return _getMethod (GETMETA(aClass), aSelector); } /*********************************************************************** - * class_getVariable. Return the named instance variable. - **********************************************************************/ +* class_getVariable. Return the named instance variable. +**********************************************************************/ static Ivar class_getVariable (Class cls, - const char * name) -{ - struct objc_class * thisCls; - - // Outer loop - search the class and its superclasses - for (thisCls = cls; thisCls != Nil; thisCls = ((struct objc_class *) thisCls)->super_class) - { - int index; - Ivar thisIvar; - - // Skip class having no ivars - if (!thisCls->ivars) - continue; - - // Inner loop - search the given class - thisIvar = &thisCls->ivars->ivar_list[0]; - for (index = 0; index < thisCls->ivars->ivar_count; index += 1) - { - // Check this ivar's name. Be careful because the - // compiler generates ivar entries with NULL ivar_name - // (e.g. for anonymous bit fields). - if ((thisIvar->ivar_name) && - (strcmp (name, thisIvar->ivar_name) == 0)) - return thisIvar; - - // Move to next ivar - thisIvar += 1; - } - } + const char * name) +{ + struct objc_class * thisCls; + + // Outer loop - search the class and its superclasses + for (thisCls = cls; thisCls != Nil; thisCls = ((struct objc_class *) thisCls)->super_class) + { + int index; + Ivar thisIvar; + + // Skip class having no ivars + if (!thisCls->ivars) + continue; + + // Inner loop - search the given class + thisIvar = &thisCls->ivars->ivar_list[0]; + for (index = 0; index < thisCls->ivars->ivar_count; index += 1) + { + // Check this ivar's name. Be careful because the + // compiler generates ivar entries with NULL ivar_name + // (e.g. for anonymous bit fields). + if ((thisIvar->ivar_name) && + (strcmp (name, thisIvar->ivar_name) == 0)) + return thisIvar; + + // Move to next ivar + thisIvar += 1; + } + } - // Not found - return NULL; + // Not found + return NULL; } /*********************************************************************** - * class_getInstanceVariable. Return the named instance variable. - * - * Someday add class_getClassVariable (). - **********************************************************************/ +* class_getInstanceVariable. Return the named instance variable. +* +* Someday add class_getClassVariable (). +**********************************************************************/ Ivar class_getInstanceVariable (Class aClass, - const char * name) + const char * name) { - // Must have a class and a name - if (!aClass || !name) - return NULL; + // Must have a class and a name + if (!aClass || !name) + return NULL; - // Look it up - return class_getVariable (aClass, name); + // Look it up + return class_getVariable (aClass, name); } /*********************************************************************** - * flush_caches. Flush the instance and optionally class method caches - * of cls and all its subclasses. - * - * Specifying Nil for the class "all classes." - **********************************************************************/ +* flush_caches. Flush the instance and optionally class method caches +* of cls and all its subclasses. +* +* Specifying Nil for the class "all classes." +**********************************************************************/ static void flush_caches (Class cls, - BOOL flush_meta) + BOOL flush_meta) { - int numClasses = 0, newNumClasses; - struct objc_class * * classes = NULL; - int i; - struct objc_class * clsObject; + int numClasses = 0, newNumClasses; + struct objc_class * * classes = NULL; + int i; + struct objc_class * clsObject; #ifdef OBJC_INSTRUMENTED - unsigned int classesVisited; - unsigned int subclassCount; + unsigned int classesVisited; + unsigned int subclassCount; #endif - // Do nothing if class has no cache - if (cls && !((struct objc_class *) cls)->cache) - return; - - newNumClasses = objc_getClassList((Class *)NULL, 0); - while (numClasses < newNumClasses) { - numClasses = newNumClasses; - classes = realloc(classes, sizeof(Class) * numClasses); - newNumClasses = objc_getClassList((Class *)classes, numClasses); - } - numClasses = newNumClasses; - - // Handle nil and root instance class specially: flush all - // instance and class method caches. Nice that this - // loop is linear vs the N-squared loop just below. - if (!cls || !((struct objc_class *) cls)->super_class) - { + // Do nothing if class has no cache + if (cls && !((struct objc_class *) cls)->cache) + return; + + newNumClasses = objc_getClassList((Class *)NULL, 0); + while (numClasses < newNumClasses) { + numClasses = newNumClasses; + classes = realloc(classes, sizeof(Class) * numClasses); + newNumClasses = objc_getClassList((Class *)classes, numClasses); + } + numClasses = newNumClasses; + + // Handle nil and root instance class specially: flush all + // instance and class method caches. Nice that this + // loop is linear vs the N-squared loop just below. + if (!cls || !((struct objc_class *) cls)->super_class) + { #ifdef OBJC_INSTRUMENTED - LinearFlushCachesCount += 1; - classesVisited = 0; - subclassCount = 0; + LinearFlushCachesCount += 1; + classesVisited = 0; + subclassCount = 0; #endif - // Traverse all classes in the hash table - for (i = 0; i < numClasses; i++) - { - struct objc_class * metaClsObject; + // Traverse all classes in the hash table + for (i = 0; i < numClasses; i++) + { + struct objc_class * metaClsObject; #ifdef OBJC_INSTRUMENTED - classesVisited += 1; + classesVisited += 1; #endif - clsObject = classes[i]; - - // Skip class that is known not to be a subclass of this root - // (the isa pointer of any meta class points to the meta class - // of the root). - // NOTE: When is an isa pointer of a hash tabled class ever nil? - metaClsObject = ((struct objc_class *) clsObject)->isa; - if (cls && metaClsObject && (((struct objc_class *) metaClsObject)->isa != ((struct objc_class *) metaClsObject)->isa)) - continue; + clsObject = classes[i]; + + // Skip class that is known not to be a subclass of this root + // (the isa pointer of any meta class points to the meta class + // of the root). + // NOTE: When is an isa pointer of a hash tabled class ever nil? + metaClsObject = ((struct objc_class *) clsObject)->isa; + if (cls && metaClsObject && (((struct objc_class *) metaClsObject)->isa != ((struct objc_class *) metaClsObject)->isa)) + continue; #ifdef OBJC_INSTRUMENTED - subclassCount += 1; + subclassCount += 1; #endif - // Be careful of classes that do not yet have caches - if (((struct objc_class *) clsObject)->cache) - _cache_flush (clsObject); - if (flush_meta && metaClsObject && ((struct objc_class *) metaClsObject)->cache) - _cache_flush (((struct objc_class *) clsObject)->isa); - } + // Be careful of classes that do not yet have caches + if (((struct objc_class *) clsObject)->cache) + _cache_flush (clsObject); + if (flush_meta && metaClsObject && ((struct objc_class *) metaClsObject)->cache) + _cache_flush (((struct objc_class *) clsObject)->isa); + } #ifdef OBJC_INSTRUMENTED - LinearFlushCachesVisitedCount += classesVisited; - if (classesVisited > MaxLinearFlushCachesVisitedCount) - MaxLinearFlushCachesVisitedCount = classesVisited; - IdealFlushCachesCount += subclassCount; - if (subclassCount > MaxIdealFlushCachesCount) - MaxIdealFlushCachesCount = subclassCount; + LinearFlushCachesVisitedCount += classesVisited; + if (classesVisited > MaxLinearFlushCachesVisitedCount) + MaxLinearFlushCachesVisitedCount = classesVisited; + IdealFlushCachesCount += subclassCount; + if (subclassCount > MaxIdealFlushCachesCount) + MaxIdealFlushCachesCount = subclassCount; #endif - free(classes); - return; - } + free(classes); + return; + } - // Outer loop - flush any cache that could now get a method from - // cls (i.e. the cache associated with cls and any of its subclasses). + // Outer loop - flush any cache that could now get a method from + // cls (i.e. the cache associated with cls and any of its subclasses). #ifdef OBJC_INSTRUMENTED - NonlinearFlushCachesCount += 1; - classesVisited = 0; - subclassCount = 0; + NonlinearFlushCachesCount += 1; + classesVisited = 0; + subclassCount = 0; #endif - for (i = 0; i < numClasses; i++) - { - struct objc_class * clsIter; + for (i = 0; i < numClasses; i++) + { + struct objc_class * clsIter; #ifdef OBJC_INSTRUMENTED - NonlinearFlushCachesClassCount += 1; + NonlinearFlushCachesClassCount += 1; #endif - clsObject = classes[i]; + clsObject = classes[i]; - // Inner loop - Process a given class - clsIter = clsObject; - while (clsIter) - { + // Inner loop - Process a given class + clsIter = clsObject; + while (clsIter) + { #ifdef OBJC_INSTRUMENTED - classesVisited += 1; + classesVisited += 1; #endif - // Flush clsObject instance method cache if - // clsObject is a subclass of cls, or is cls itself - // Flush the class method cache if that was asked for - if (clsIter == cls) - { + // Flush clsObject instance method cache if + // clsObject is a subclass of cls, or is cls itself + // Flush the class method cache if that was asked for + if (clsIter == cls) + { #ifdef OBJC_INSTRUMENTED - subclassCount += 1; + subclassCount += 1; #endif - _cache_flush (clsObject); - if (flush_meta) - _cache_flush (clsObject->isa); - - break; - - } - - // Flush clsObject class method cache if cls is - // the meta class of clsObject or of one - // of clsObject's superclasses - else if (clsIter->isa == cls) - { + _cache_flush (clsObject); + if (flush_meta) + _cache_flush (clsObject->isa); + + break; + + } + + // Flush clsObject class method cache if cls is + // the meta class of clsObject or of one + // of clsObject's superclasses + else if (clsIter->isa == cls) + { #ifdef OBJC_INSTRUMENTED - subclassCount += 1; + subclassCount += 1; #endif - _cache_flush (clsObject->isa); - break; - } - - // Move up superclass chain - else if (ISINITIALIZED(clsIter)) - clsIter = clsIter->super_class; - - // clsIter is not initialized, so its cache - // must be empty. This happens only when - // clsIter == clsObject, because - // superclasses are initialized before - // subclasses, and this loop traverses - // from sub- to super- classes. - else - break; - } - } + _cache_flush (clsObject->isa); + break; + } + + // Move up superclass chain + else if (ISINITIALIZED(clsIter)) + clsIter = clsIter->super_class; + + // clsIter is not initialized, so its cache + // must be empty. This happens only when + // clsIter == clsObject, because + // superclasses are initialized before + // subclasses, and this loop traverses + // from sub- to super- classes. + else + break; + } + } #ifdef OBJC_INSTRUMENTED - NonlinearFlushCachesVisitedCount += classesVisited; - if (classesVisited > MaxNonlinearFlushCachesVisitedCount) - MaxNonlinearFlushCachesVisitedCount = classesVisited; - IdealFlushCachesCount += subclassCount; - if (subclassCount > MaxIdealFlushCachesCount) - MaxIdealFlushCachesCount = subclassCount; + NonlinearFlushCachesVisitedCount += classesVisited; + if (classesVisited > MaxNonlinearFlushCachesVisitedCount) + MaxNonlinearFlushCachesVisitedCount = classesVisited; + IdealFlushCachesCount += subclassCount; + if (subclassCount > MaxIdealFlushCachesCount) + MaxIdealFlushCachesCount = subclassCount; #endif - // Relinquish access to class hash table - free(classes); + // Relinquish access to class hash table + free(classes); } /*********************************************************************** - * _objc_flush_caches. Flush the caches of the specified class and any - * of its subclasses. If cls is a meta-class, only meta-class (i.e. - * class method) caches are flushed. If cls is an instance-class, both - * instance-class and meta-class caches are flushed. - **********************************************************************/ +* _objc_flush_caches. Flush the caches of the specified class and any +* of its subclasses. If cls is a meta-class, only meta-class (i.e. + * class method) caches are flushed. If cls is an instance-class, both +* instance-class and meta-class caches are flushed. +**********************************************************************/ void _objc_flush_caches (Class cls) { - flush_caches (cls, YES); + flush_caches (cls, YES); } /*********************************************************************** - * do_not_remove_this_dummy_function. - **********************************************************************/ +* do_not_remove_this_dummy_function. +**********************************************************************/ void do_not_remove_this_dummy_function (void) { - (void) class_nextMethodList (NULL, NULL); + (void) class_nextMethodList (NULL, NULL); } /*********************************************************************** - * class_nextMethodList. - * - * usage: - * void * iterator = 0; - * while (class_nextMethodList (cls, &iterator)) {...} - **********************************************************************/ +* class_nextMethodList. +* +* usage: +* void * iterator = 0; +* while (class_nextMethodList (cls, &iterator)) {...} +**********************************************************************/ OBJC_EXPORT struct objc_method_list * class_nextMethodList (Class cls, - void ** it) + void ** it) { return _class_inlinedNextMethodList(cls, it); } /*********************************************************************** - * _dummy. - **********************************************************************/ +* _dummy. +**********************************************************************/ void _dummy (void) { - (void) class_nextMethodList (Nil, NULL); + (void) class_nextMethodList (Nil, NULL); } /*********************************************************************** - * class_addMethods. - * - * Formerly class_addInstanceMethods () - **********************************************************************/ +* class_addMethods. +* +* Formerly class_addInstanceMethods () +**********************************************************************/ void class_addMethods (Class cls, - struct objc_method_list * meths) + struct objc_method_list * meths) { - // Insert atomically. - _objc_insertMethods (meths, &((struct objc_class *) cls)->methodLists); - - // Must flush when dynamically adding methods. No need to flush - // all the class method caches. If cls is a meta class, though, - // this will still flush it and any of its sub-meta classes. - flush_caches (cls, NO); + // Insert atomically. + _objc_insertMethods (meths, &((struct objc_class *) cls)->methodLists); + + // Must flush when dynamically adding methods. No need to flush + // all the class method caches. If cls is a meta class, though, + // this will still flush it and any of its sub-meta classes. + flush_caches (cls, NO); } /*********************************************************************** - * class_addClassMethods. - * - * Obsolete (for binary compatibility only). - **********************************************************************/ +* class_addClassMethods. +* +* Obsolete (for binary compatibility only). +**********************************************************************/ void class_addClassMethods (Class cls, - struct objc_method_list * meths) + struct objc_method_list * meths) { - class_addMethods (((struct objc_class *) cls)->isa, meths); + class_addMethods (((struct objc_class *) cls)->isa, meths); } /*********************************************************************** - * class_removeMethods. - **********************************************************************/ +* class_removeMethods. +**********************************************************************/ void class_removeMethods (Class cls, - struct objc_method_list * meths) + struct objc_method_list * meths) { - // Remove atomically. - _objc_removeMethods (meths, &((struct objc_class *) cls)->methodLists); - - // Must flush when dynamically removing methods. No need to flush - // all the class method caches. If cls is a meta class, though, - // this will still flush it and any of its sub-meta classes. - flush_caches (cls, NO); + // Remove atomically. + _objc_removeMethods (meths, &((struct objc_class *) cls)->methodLists); + + // Must flush when dynamically removing methods. No need to flush + // all the class method caches. If cls is a meta class, though, + // this will still flush it and any of its sub-meta classes. + flush_caches (cls, NO); } /*********************************************************************** - * addClassToOriginalClass. Add to a hash table of classes involved in - * a posing situation. We use this when we need to get to the "original" - * class for some particular name through the function objc_getOrigClass. - * For instance, the implementation of [super ...] will use this to be - * sure that it gets hold of the correct super class, so that no infinite - * loops will occur if the class it appears in is involved in posing. - * - * We use the classLock to guard the hash table. - * - * See tracker bug #51856. - **********************************************************************/ +* addClassToOriginalClass. Add to a hash table of classes involved in +* a posing situation. We use this when we need to get to the "original" +* class for some particular name through the function objc_getOrigClass. +* For instance, the implementation of [super ...] will use this to be +* sure that it gets hold of the correct super class, so that no infinite +* loops will occur if the class it appears in is involved in posing. +* +* We use the classLock to guard the hash table. +* +* See tracker bug #51856. +**********************************************************************/ static NXMapTable * posed_class_hash = NULL; static NXMapTable * posed_class_to_original_class_hash = NULL; static void addClassToOriginalClass (Class posingClass, - Class originalClass) -{ - // Install hash table when it is first needed - if (!posed_class_to_original_class_hash) - { - posed_class_to_original_class_hash = - NXCreateMapTableFromZone (NXPtrValueMapPrototype, - 8, - _objc_create_zone ()); - } + Class originalClass) +{ + // Install hash table when it is first needed + if (!posed_class_to_original_class_hash) + { + posed_class_to_original_class_hash = + NXCreateMapTableFromZone (NXPtrValueMapPrototype, + 8, + _objc_create_zone ()); + } - // Add pose to hash table - NXMapInsert (posed_class_to_original_class_hash, - posingClass, - originalClass); + // Add pose to hash table + NXMapInsert (posed_class_to_original_class_hash, + posingClass, + originalClass); } /*********************************************************************** - * getOriginalClassForPosingClass. - **********************************************************************/ +* getOriginalClassForPosingClass. +**********************************************************************/ Class getOriginalClassForPosingClass (Class posingClass) { - return NXMapGet (posed_class_to_original_class_hash, posingClass); + return NXMapGet (posed_class_to_original_class_hash, posingClass); } /*********************************************************************** - * objc_getOrigClass. - **********************************************************************/ +* objc_getOrigClass. +**********************************************************************/ Class objc_getOrigClass (const char * name) { - struct objc_class * ret; + struct objc_class * ret; - // Look for class among the posers - ret = Nil; - OBJC_LOCK(&classLock); - if (posed_class_hash) - ret = (Class) NXMapGet (posed_class_hash, name); - OBJC_UNLOCK(&classLock); - if (ret) - return ret; + // Look for class among the posers + ret = Nil; + OBJC_LOCK(&classLock); + if (posed_class_hash) + ret = (Class) NXMapGet (posed_class_hash, name); + OBJC_UNLOCK(&classLock); + if (ret) + return ret; - // Not a poser. Do a normal lookup. - ret = objc_getClass (name); - if (!ret) - _objc_inform ("class `%s' not linked into application", name); + // Not a poser. Do a normal lookup. + ret = objc_getClass (name); + if (!ret) + _objc_inform ("class `%s' not linked into application", name); - return ret; + return ret; } /*********************************************************************** - * _objc_addOrigClass. This function is only used from class_poseAs. - * Registers the original class names, before they get obscured by - * posing, so that [super ..] will work correctly from categories - * in posing classes and in categories in classes being posed for. - **********************************************************************/ +* _objc_addOrigClass. This function is only used from class_poseAs. +* Registers the original class names, before they get obscured by +* posing, so that [super ..] will work correctly from categories +* in posing classes and in categories in classes being posed for. +**********************************************************************/ static void _objc_addOrigClass (Class origClass) { - OBJC_LOCK(&classLock); - - // Create the poser's hash table on first use - if (!posed_class_hash) - { - posed_class_hash = NXCreateMapTableFromZone (NXStrValueMapPrototype, - 8, - _objc_create_zone ()); - } + OBJC_LOCK(&classLock); - // Add the named class iff it is not already there (or collides?) - if (NXMapGet (posed_class_hash, ((struct objc_class *)origClass)->name) == 0) - NXMapInsert (posed_class_hash, ((struct objc_class *)origClass)->name, origClass); + // Create the poser's hash table on first use + if (!posed_class_hash) + { + posed_class_hash = NXCreateMapTableFromZone (NXStrValueMapPrototype, + 8, + _objc_create_zone ()); + } - OBJC_UNLOCK(&classLock); + // Add the named class iff it is not already there (or collides?) + if (NXMapGet (posed_class_hash, ((struct objc_class *)origClass)->name) == 0) + NXMapInsert (posed_class_hash, ((struct objc_class *)origClass)->name, origClass); + + OBJC_UNLOCK(&classLock); } /*********************************************************************** - * class_poseAs. - * - * !!! class_poseAs () does not currently flush any caches. - **********************************************************************/ +* class_poseAs. +* +* !!! class_poseAs () does not currently flush any caches. +**********************************************************************/ Class class_poseAs (Class imposter, - Class original) -{ - struct objc_class * clsObject; - char imposterName[256]; - char * imposterNamePtr; - NXHashTable * class_hash; - NXHashState state; - struct objc_class * copy; + Class original) +{ + struct objc_class * clsObject; + char imposterName[256]; + char * imposterNamePtr; + NXHashTable * class_hash; + NXHashState state; + struct objc_class * copy; #ifdef OBJC_CLASS_REFS - unsigned int hidx; - unsigned int hdrCount; - header_info * hdrVector; - - // Get these now before locking, to minimize impact - hdrCount = _objc_headerCount (); - hdrVector = _objc_headerVector (NULL); + header_info * hInfo; #endif - // Trivial case is easy - if (imposter == original) - return imposter; - - // Imposter must be an immediate subclass of the original - if (((struct objc_class *)imposter)->super_class != original) - return (Class) [(id) imposter error:_errNotSuper, - ((struct objc_class *)imposter)->name, ((struct objc_class *)original)->name]; - - // Can't pose when you have instance variables (how could it work?) - if (((struct objc_class *)imposter)->ivars) - return (Class) [(id) imposter error:_errNewVars, ((struct objc_class *)imposter)->name, - ((struct objc_class *)original)->name, ((struct objc_class *)imposter)->name]; - - // Build a string to use to replace the name of the original class. - strcpy (imposterName, "_%"); - strcat (imposterName, ((struct objc_class *)original)->name); - imposterNamePtr = objc_malloc (strlen (imposterName)+1); - strcpy (imposterNamePtr, imposterName); - - // We lock the class hashtable, so we are thread safe with respect to - // calls to objc_getClass (). However, the class names are not - // changed atomically, nor are all of the subclasses updated - // atomically. I have ordered the operations so that you will - // never crash, but you may get inconsistent results.... - - // Register the original class so that [super ..] knows - // exactly which classes are the "original" classes. - _objc_addOrigClass (original); - _objc_addOrigClass (imposter); - - OBJC_LOCK(&classLock); - - class_hash = objc_getClasses (); - - // Remove both the imposter and the original class. - NXHashRemove (class_hash, imposter); - NXHashRemove (class_hash, original); - - // Copy the imposter, so that the imposter can continue - // its normal life in addition to changing the behavior of - // the original. As a hack we don't bother to copy the metaclass. - // For some reason we modify the original rather than the copy. - copy = (*_zoneAlloc)(imposter->isa, sizeof(struct objc_class), _objc_create_zone()); - memmove(copy, imposter, sizeof(struct objc_class)); - - NXHashInsert (class_hash, copy); - addClassToOriginalClass (imposter, copy); - - // Mark the imposter as such - CLS_SETINFO(((struct objc_class *)imposter), CLS_POSING); - CLS_SETINFO(((struct objc_class *)imposter)->isa, CLS_POSING); - - // Change the name of the imposter to that of the original class. - ((struct objc_class *)imposter)->name = ((struct objc_class *)original)->name; - ((struct objc_class *)imposter)->isa->name = ((struct objc_class *)original)->isa->name; - - // Also copy the version field to avoid archiving problems. - ((struct objc_class *)imposter)->version = ((struct objc_class *)original)->version; - - // Change all subclasses of the original to point to the imposter. - state = NXInitHashState (class_hash); - while (NXNextHashState (class_hash, &state, (void **) &clsObject)) - { - while ((clsObject) && (clsObject != imposter) && - (clsObject != copy)) - { - if (clsObject->super_class == original) - { - clsObject->super_class = imposter; - clsObject->isa->super_class = ((struct objc_class *)imposter)->isa; - // We must flush caches here! - break; - } - - clsObject = clsObject->super_class; - } - } + // Trivial case is easy + if (imposter == original) + return imposter; + + // Imposter must be an immediate subclass of the original + if (((struct objc_class *)imposter)->super_class != original) { + // radar 2203635 + __objc_error(imposter, _errNotSuper, ((struct objc_class *)imposter)->name, ((struct objc_class *)original)->name); + } + + // Can't pose when you have instance variables (how could it work?) + if (((struct objc_class *)imposter)->ivars) { + // radar 2203635 + __objc_error(imposter, _errNewVars, ((struct objc_class *)imposter)->name, ((struct objc_class *)original)->name, ((struct objc_class *)imposter)->name); + } + + // Build a string to use to replace the name of the original class. + strcpy (imposterName, "_%"); + strcat (imposterName, ((struct objc_class *)original)->name); + imposterNamePtr = objc_malloc (strlen (imposterName)+1); + strcpy (imposterNamePtr, imposterName); + + // We lock the class hashtable, so we are thread safe with respect to + // calls to objc_getClass (). However, the class names are not + // changed atomically, nor are all of the subclasses updated + // atomically. I have ordered the operations so that you will + // never crash, but you may get inconsistent results.... + + // Register the original class so that [super ..] knows + // exactly which classes are the "original" classes. + _objc_addOrigClass (original); + _objc_addOrigClass (imposter); + + OBJC_LOCK(&classLock); + + class_hash = objc_getClasses (); + + // Remove both the imposter and the original class. + NXHashRemove (class_hash, imposter); + NXHashRemove (class_hash, original); + + // Copy the imposter, so that the imposter can continue + // its normal life in addition to changing the behavior of + // the original. As a hack we don't bother to copy the metaclass. + // For some reason we modify the original rather than the copy. + copy = (*_zoneAlloc)(imposter->isa, sizeof(struct objc_class), _objc_create_zone()); + memmove(copy, imposter, sizeof(struct objc_class)); + + NXHashInsert (class_hash, copy); + addClassToOriginalClass (imposter, copy); + + // Mark the imposter as such + CLS_SETINFO(((struct objc_class *)imposter), CLS_POSING); + CLS_SETINFO(((struct objc_class *)imposter)->isa, CLS_POSING); + + // Change the name of the imposter to that of the original class. + ((struct objc_class *)imposter)->name = ((struct objc_class *)original)->name; + ((struct objc_class *)imposter)->isa->name = ((struct objc_class *)original)->isa->name; + + // Also copy the version field to avoid archiving problems. + ((struct objc_class *)imposter)->version = ((struct objc_class *)original)->version; + + // Change all subclasses of the original to point to the imposter. + state = NXInitHashState (class_hash); + while (NXNextHashState (class_hash, &state, (void **) &clsObject)) + { + while ((clsObject) && (clsObject != imposter) && + (clsObject != copy)) + { + if (clsObject->super_class == original) + { + clsObject->super_class = imposter; + clsObject->isa->super_class = ((struct objc_class *)imposter)->isa; + // We must flush caches here! + break; + } + + clsObject = clsObject->super_class; + } + } #ifdef OBJC_CLASS_REFS - // Replace the original with the imposter in all class refs - // Major loop - process all headers - for (hidx = 0; hidx < hdrCount; hidx += 1) - { - Class * cls_refs; - unsigned int refCount; - unsigned int index; - - // Get refs associated with this header - cls_refs = (Class *) _getObjcClassRefs ((headerType *) hdrVector[hidx].mhdr, &refCount); - if (!cls_refs || !refCount) - continue; - - // Minor loop - process this header's refs - cls_refs = (Class *) ((unsigned long) cls_refs + hdrVector[hidx].image_slide); - for (index = 0; index < refCount; index += 1) - { - if (cls_refs[index] == original) - cls_refs[index] = imposter; - } - } + // Replace the original with the imposter in all class refs + // Major loop - process all headers + for (hInfo = _objc_headerStart(); hInfo != NULL; hInfo = hInfo->next) + { + Class * cls_refs; + unsigned int refCount; + unsigned int index; + + // Get refs associated with this header + cls_refs = (Class *) _getObjcClassRefs ((headerType *) hInfo->mhdr, &refCount); + if (!cls_refs || !refCount) + continue; + + // Minor loop - process this header's refs + cls_refs = (Class *) ((unsigned long) cls_refs + hInfo->image_slide); + for (index = 0; index < refCount; index += 1) + { + if (cls_refs[index] == original) + cls_refs[index] = imposter; + } + } #endif // OBJC_CLASS_REFS - // Change the name of the original class. - ((struct objc_class *)original)->name = imposterNamePtr + 1; - ((struct objc_class *)original)->isa->name = imposterNamePtr; - - // Restore the imposter and the original class with their new names. - NXHashInsert (class_hash, imposter); - NXHashInsert (class_hash, original); - - OBJC_UNLOCK(&classLock); - - return imposter; + // Change the name of the original class. + ((struct objc_class *)original)->name = imposterNamePtr + 1; + ((struct objc_class *)original)->isa->name = imposterNamePtr; + + // Restore the imposter and the original class with their new names. + NXHashInsert (class_hash, imposter); + NXHashInsert (class_hash, original); + + OBJC_UNLOCK(&classLock); + + return imposter; } /*********************************************************************** - * _freedHandler. - **********************************************************************/ +* _freedHandler. +**********************************************************************/ static void _freedHandler (id self, - SEL sel) + SEL sel) { - __objc_error (self, _errFreedObject, SELNAME(sel), self); + __objc_error (self, _errFreedObject, SELNAME(sel), self); } /*********************************************************************** - * _nonexistentHandler. - **********************************************************************/ +* _nonexistentHandler. +**********************************************************************/ static void _nonexistentHandler (id self, - SEL sel) + SEL sel) { - __objc_error (self, _errNonExistentObject, SELNAME(sel), self); + __objc_error (self, _errNonExistentObject, SELNAME(sel), self); } /*********************************************************************** - * class_initialize. Send the 'initialize' message on demand to any - * uninitialized class. Force initialization of superclasses first. - * - * Called only from _class_lookupMethodAndLoadCache (or itself). - * - * #ifdef OBJC_COLLECTING_CACHE - * The messageLock can be in either state. - * #else - * The messageLock is already assumed to be taken out. - * It is temporarily released while the initialize method is sent. - * #endif - **********************************************************************/ +* class_initialize. Send the '+initialize' message on demand to any +* uninitialized class. Force initialization of superclasses first. +* +* Called only from _class_lookupMethodAndLoadCache (or itself). +* +* #ifdef OBJC_COLLECTING_CACHE +* The messageLock can be in either state. +* #else +* The messageLock is already assumed to be taken out. +* It is temporarily released while the initialize method is sent. +* #endif +**********************************************************************/ static void class_initialize (Class clsDesc) { - struct objc_class * super; + struct objc_class * super; + + // Skip if someone else beat us to it + if (ISINITIALIZED(((struct objc_class *)clsDesc))) + return; + + // Force initialization of superclasses first + super = ((struct objc_class *)clsDesc)->super_class; + if ((super != Nil) && (!ISINITIALIZED(super))) + class_initialize (super); - // Skip if someone else beat us to it - if (ISINITIALIZED(((struct objc_class *)clsDesc))) - return; + // Initializing the super class might have initialized us, + // or another thread might have initialized us during this time. + if (ISINITIALIZED(((struct objc_class *)clsDesc))) + return; - // Force initialization of superclasses first - super = ((struct objc_class *)clsDesc)->super_class; - if ((super != Nil) && (!ISINITIALIZED(super))) - class_initialize (super); - // Initializing the super class might have initialized us, - // or another thread might have initialized us during this time. - if (ISINITIALIZED(((struct objc_class *)clsDesc))) - return; + // bind the module in - if it came from a bundle or dynamic library + if (((struct objc_class *)clsDesc)->info & CLS_NEED_BIND) { + ((struct objc_class *)clsDesc)->info &= ~CLS_NEED_BIND; + _objc_bindModuleContainingClass(clsDesc); + } + + // by loading things we might get initialized (maybe) ((paranoia)) + if (ISINITIALIZED(((struct objc_class *)clsDesc))) + return; + + // chain on the categories and bind them if necessary + _objc_resolve_categories_for_class(clsDesc); - // Mark the class initialized so it can receive the "initialize" - // message. This solution to the catch-22 is the source of a - // bug: the class is able to receive messages *from anyone* now - // that it is marked, even though initialization is not complete. - MARKINITIALIZED(((struct objc_class *)clsDesc)); + // by loading things we might get initialized (maybe) ((paranoia)) + if (ISINITIALIZED(((struct objc_class *)clsDesc))) + return; + + // Mark the class initialized so it can receive the "initialize" + // message. This solution to the catch-22 is the source of a + // bug: the class is able to receive messages *from anyone* now + // that it is marked, even though initialization is not complete. + + MARKINITIALIZED(((struct objc_class *)clsDesc)); + // But the simple solution is to ask if this class itself implements + // initialize (!) and only send it then!! #ifndef OBJC_COLLECTING_CACHE - // Release the message lock so that messages can be sent. - OBJC_UNLOCK(&messageLock); + // Release the message lock so that messages can be sent. + OBJC_UNLOCK(&messageLock); #endif - // Send the initialize method. - [(id)clsDesc initialize]; + // Send the initialize method. + // Of course, if this class doesn't implement initialize but + // the super class does, we send initialize to the super class + // twice, thrice... + [(id)clsDesc initialize]; #ifndef OBJC_COLLECTING_CACHE - // Re-acquire the lock - OBJC_LOCK(&messageLock); + // Re-acquire the lock + OBJC_LOCK(&messageLock); #endif - return; + return; } /*********************************************************************** - * _class_install_relationships. Fill in the class pointers of a class - * that was loaded before some or all of the classes it needs to point to. - * The deal here is that the class pointer fields have been usurped to - * hold the string name of the pertinent class. Our job is to look up - * the real thing based on those stored names. - **********************************************************************/ +* _class_install_relationships. Fill in the class pointers of a class +* that was loaded before some or all of the classes it needs to point to. +* The deal here is that the class pointer fields have been usurped to +* hold the string name of the pertinent class. Our job is to look up +* the real thing based on those stored names. +**********************************************************************/ void _class_install_relationships (Class cls, - long version) -{ - struct objc_class * meta; - struct objc_class * clstmp; - - // Get easy access to meta class structure - meta = ((struct objc_class *)cls)->isa; - - // Set version in meta class strucure - meta->version = version; - - // Install superclass based on stored name. No name iff - // cls is a root class. - if (((struct objc_class *)cls)->super_class) - { - clstmp = objc_getClass ((const char *) ((struct objc_class *)cls)->super_class); - if (!clstmp) - { - _objc_inform("failed objc_getClass(%s) for %s->super_class", (const char *)((struct objc_class *)cls)->super_class, ((struct objc_class *)cls)->name); - goto Error; - } - - ((struct objc_class *)cls)->super_class = clstmp; - } - - // Install meta's isa based on stored name. Meta class isa - // pointers always point to the meta class of the root class - // (root meta class, too, it points to itself!). - clstmp = objc_getClass ((const char *) meta->isa); - if (!clstmp) - { - _objc_inform("failed objc_getClass(%s) for %s->isa->isa", (const char *) meta->isa, ((struct objc_class *)cls)->name); - goto Error; - } - - meta->isa = clstmp->isa; - - // Install meta's superclass based on stored name. No name iff - // cls is a root class. - if (meta->super_class) - { - // Locate instance class of super class - clstmp = objc_getClass ((const char *) meta->super_class); - if (!clstmp) - { - _objc_inform("failed objc_getClass(%s) for %s->isa->super_class", (const char *)meta->super_class, ((struct objc_class *)cls)->name); - goto Error; - } - - // Store meta class of super class - meta->super_class = clstmp->isa; - } - - // cls is root, so `tie' the (root) meta class down to its - // instance class. This way, class methods can come from - // the root instance class. - else - ((struct objc_class *)meta)->super_class = cls; - - // Use common static empty cache instead of NULL - if (((struct objc_class *)cls)->cache == NULL) - ((struct objc_class *)cls)->cache = (Cache) &emptyCache; - if (((struct objc_class *)meta)->cache == NULL) - ((struct objc_class *)meta)->cache = (Cache) &emptyCache; - - return; + long version) +{ + struct objc_class * meta; + struct objc_class * clstmp; + + // Get easy access to meta class structure + meta = ((struct objc_class *)cls)->isa; + + // Set version in meta class strucure + meta->version = version; + + // Install superclass based on stored name. No name iff + // cls is a root class. + if (((struct objc_class *)cls)->super_class) + { + clstmp = objc_getClass ((const char *) ((struct objc_class *)cls)->super_class); + if (!clstmp) + { + _objc_inform("failed objc_getClass(%s) for %s->super_class", (const char *)((struct objc_class *)cls)->super_class, ((struct objc_class *)cls)->name); + goto Error; + } + + ((struct objc_class *)cls)->super_class = clstmp; + } + + // Install meta's isa based on stored name. Meta class isa + // pointers always point to the meta class of the root class + // (root meta class, too, it points to itself!). + clstmp = objc_getClass ((const char *) meta->isa); + if (!clstmp) + { + _objc_inform("failed objc_getClass(%s) for %s->isa->isa", (const char *) meta->isa, ((struct objc_class *)cls)->name); + goto Error; + } + + meta->isa = clstmp->isa; + + // Install meta's superclass based on stored name. No name iff + // cls is a root class. + if (meta->super_class) + { + // Locate instance class of super class + clstmp = objc_getClass ((const char *) meta->super_class); + if (!clstmp) + { + _objc_inform("failed objc_getClass(%s) for %s->isa->super_class", (const char *)meta->super_class, ((struct objc_class *)cls)->name); + goto Error; + } + + // Store meta class of super class + meta->super_class = clstmp->isa; + } + + // cls is root, so `tie' the (root) meta class down to its + // instance class. This way, class methods can come from + // the root instance class. + else + ((struct objc_class *)meta)->super_class = cls; + + // Use common static empty cache instead of NULL + if (((struct objc_class *)cls)->cache == NULL) + ((struct objc_class *)cls)->cache = (Cache) &emptyCache; + if (((struct objc_class *)meta)->cache == NULL) + ((struct objc_class *)meta)->cache = (Cache) &emptyCache; + + return; Error: - _objc_fatal ("please link appropriate classes in your program"); + _objc_fatal ("please link appropriate classes in your program"); } /*********************************************************************** - * objc_malloc. - **********************************************************************/ +* objc_malloc. +**********************************************************************/ static void * objc_malloc (int byteCount) { - void * space; + void * space; - space = malloc_zone_malloc (_objc_create_zone (), byteCount); - if (!space && byteCount) - _objc_fatal ("unable to allocate space"); + space = malloc_zone_malloc (_objc_create_zone (), byteCount); + if (!space && byteCount) + _objc_fatal ("unable to allocate space"); -#ifdef WIN32 - bzero (space, byteCount); -#endif - - return space; + return space; } /*********************************************************************** - * class_respondsToMethod. - * - * Called from -[Object respondsTo:] and +[Object instancesRespondTo:] - **********************************************************************/ +* class_respondsToMethod. +* +* Called from -[Object respondsTo:] and +[Object instancesRespondTo:] +**********************************************************************/ BOOL class_respondsToMethod (Class cls, - SEL sel) -{ - struct objc_class * thisCls; - arith_t index; - arith_t mask; - Method * buckets; - Method meth; - - // No one responds to zero! - if (!sel) - return NO; - - // Synchronize access to caches - OBJC_LOCK(&messageLock); - - // Look in the cache of the specified class - mask = ((struct objc_class *)cls)->cache->mask; - buckets = ((struct objc_class *)cls)->cache->buckets; - index = ((uarith_t) sel & mask); - while (CACHE_BUCKET_VALID(buckets[index])) { - if (CACHE_BUCKET_NAME(buckets[index]) == sel) { - if (CACHE_BUCKET_IMP(buckets[index]) == &_objc_msgForward) { - OBJC_UNLOCK(&messageLock); - return NO; - } else { - OBJC_UNLOCK(&messageLock); - return YES; - } - } - - index += 1; - index &= mask; - } - - // Handle cache miss - meth = _getMethod(cls, sel); - if (meth) { - OBJC_UNLOCK(&messageLock); - _cache_fill (cls, meth, sel); - return YES; - } - - // Not implememted. Use _objc_msgForward. - { - Method smt; - - smt = malloc_zone_malloc (_objc_create_zone(), sizeof(struct objc_method)); - smt->method_name = sel; - smt->method_types = ""; - smt->method_imp = &_objc_msgForward; - _cache_fill (cls, smt, sel); - } - - OBJC_UNLOCK(&messageLock); - return NO; - -} - - -/*********************************************************************** - * class_lookupMethod. - * - * Called from -[Object methodFor:] and +[Object instanceMethodFor:] - **********************************************************************/ + SEL sel) +{ + struct objc_class * thisCls; + arith_t index; + arith_t mask; + Method * buckets; + Method meth; + + // No one responds to zero! + if (!sel) + return NO; + + // Synchronize access to caches + OBJC_LOCK(&messageLock); + + // Look in the cache of the specified class + mask = ((struct objc_class *)cls)->cache->mask; + buckets = ((struct objc_class *)cls)->cache->buckets; + index = ((uarith_t) sel & mask); + while (CACHE_BUCKET_VALID(buckets[index])) { + if (CACHE_BUCKET_NAME(buckets[index]) == sel) { + if (CACHE_BUCKET_IMP(buckets[index]) == &_objc_msgForward) { + OBJC_UNLOCK(&messageLock); + return NO; + } else { + OBJC_UNLOCK(&messageLock); + return YES; + } + } + + index += 1; + index &= mask; + } + + // Handle cache miss + meth = _getMethod(cls, sel); + if (meth) { + OBJC_UNLOCK(&messageLock); + _cache_fill (cls, meth, sel); + return YES; + } + + // Not implememted. Use _objc_msgForward. + { + Method smt; + + smt = malloc_zone_malloc (_objc_create_zone(), sizeof(struct objc_method)); + smt->method_name = sel; + smt->method_types = ""; + smt->method_imp = &_objc_msgForward; + _cache_fill (cls, smt, sel); + } + + OBJC_UNLOCK(&messageLock); + return NO; + +} + + +/*********************************************************************** +* class_lookupMethod. +* +* Called from -[Object methodFor:] and +[Object instanceMethodFor:] +**********************************************************************/ IMP class_lookupMethod (Class cls, - SEL sel) -{ - Method * buckets; - arith_t index; - arith_t mask; - IMP result; - - // No one responds to zero! - if (!sel) - [(id) cls error:_errBadSel, sel]; - - // Synchronize access to caches - OBJC_LOCK(&messageLock); - - // Scan the cache - mask = ((struct objc_class *)cls)->cache->mask; - buckets = ((struct objc_class *)cls)->cache->buckets; - index = ((unsigned int) sel & mask); - while (CACHE_BUCKET_VALID(buckets[index])) - { - if (CACHE_BUCKET_NAME(buckets[index]) == sel) - { - result = CACHE_BUCKET_IMP(buckets[index]); - OBJC_UNLOCK(&messageLock); - return result; - } - - index += 1; - index &= mask; - } - - // Handle cache miss - result = _class_lookupMethodAndLoadCache (cls, sel); - OBJC_UNLOCK(&messageLock); - return result; -} - -/*********************************************************************** - * class_lookupMethodInMethodList. - * - * Called from objc-load.m and _objc_callLoads () - **********************************************************************/ + SEL sel) +{ + Method * buckets; + arith_t index; + arith_t mask; + IMP result; + + // No one responds to zero! + if (!sel) { + // radar 2203635 + __objc_error(cls, _errBadSel, sel); + } + + // Synchronize access to caches + OBJC_LOCK(&messageLock); + + // Scan the cache + mask = ((struct objc_class *)cls)->cache->mask; + buckets = ((struct objc_class *)cls)->cache->buckets; + index = ((unsigned int) sel & mask); + while (CACHE_BUCKET_VALID(buckets[index])) + { + if (CACHE_BUCKET_NAME(buckets[index]) == sel) + { + result = CACHE_BUCKET_IMP(buckets[index]); + OBJC_UNLOCK(&messageLock); + return result; + } + + index += 1; + index &= mask; + } + + // Handle cache miss + result = _class_lookupMethodAndLoadCache (cls, sel); + OBJC_UNLOCK(&messageLock); + return result; +} + +/*********************************************************************** +* class_lookupMethodInMethodList. +* +* Called from objc-load.m and _objc_callLoads () +**********************************************************************/ IMP class_lookupMethodInMethodList (struct objc_method_list * mlist, - SEL sel) + SEL sel) { Method m = _findMethodInList(mlist, sel); return (m ? m->method_imp : NULL); } IMP class_lookupNamedMethodInMethodList(struct objc_method_list *mlist, - const char *meth_name) + const char *meth_name) { Method m = meth_name ? _findNamedMethodInList(mlist, meth_name) : NULL; return (m ? m->method_imp : NULL); } /*********************************************************************** - * _cache_create. - * - * Called from _cache_expand () and objc_addClass () - **********************************************************************/ +* _cache_create. +* +* Called from _cache_expand () and objc_addClass () +**********************************************************************/ Cache _cache_create (Class cls) { - Cache new_cache; - int slotCount; - int index; + Cache new_cache; + int slotCount; + int index; - // Select appropriate size - slotCount = (ISMETA(cls)) ? INIT_META_CACHE_SIZE : INIT_CACHE_SIZE; + // Select appropriate size + slotCount = (ISMETA(cls)) ? INIT_META_CACHE_SIZE : INIT_CACHE_SIZE; - // Allocate table (why not check for failure?) + // Allocate table (why not check for failure?) #ifdef OBJC_INSTRUMENTED - new_cache = malloc_zone_malloc (_objc_create_zone(), - sizeof(struct objc_cache) + TABLE_SIZE(slotCount) - + sizeof(CacheInstrumentation)); + new_cache = malloc_zone_malloc (_objc_create_zone(), + sizeof(struct objc_cache) + TABLE_SIZE(slotCount) + + sizeof(CacheInstrumentation)); #else - new_cache = malloc_zone_malloc (_objc_create_zone(), - sizeof(struct objc_cache) + TABLE_SIZE(slotCount)); + new_cache = malloc_zone_malloc (_objc_create_zone(), + sizeof(struct objc_cache) + TABLE_SIZE(slotCount)); #endif - // Invalidate all the buckets - for (index = 0; index < slotCount; index += 1) - CACHE_BUCKET_VALID(new_cache->buckets[index]) = NULL; - - // Zero the valid-entry counter - new_cache->occupied = 0; - - // Set the mask so indexing wraps at the end-of-table - new_cache->mask = slotCount - 1; + // Invalidate all the buckets + for (index = 0; index < slotCount; index += 1) + CACHE_BUCKET_VALID(new_cache->buckets[index]) = NULL; + + // Zero the valid-entry counter + new_cache->occupied = 0; + + // Set the mask so indexing wraps at the end-of-table + new_cache->mask = slotCount - 1; #ifdef OBJC_INSTRUMENTED - { - CacheInstrumentation * cacheData; + { + CacheInstrumentation * cacheData; - // Zero out the cache dynamic instrumention data - cacheData = CACHE_INSTRUMENTATION(new_cache); - bzero ((char *) cacheData, sizeof(CacheInstrumentation)); - } + // Zero out the cache dynamic instrumention data + cacheData = CACHE_INSTRUMENTATION(new_cache); + bzero ((char *) cacheData, sizeof(CacheInstrumentation)); + } #endif - // Install the cache - ((struct objc_class *)cls)->cache = new_cache; + // Install the cache + ((struct objc_class *)cls)->cache = new_cache; - // Clear the cache flush flag so that we will not flush this cache - // before expanding it for the first time. - ((struct objc_class * )cls)->info &= ~(CLS_FLUSH_CACHE); + // Clear the cache flush flag so that we will not flush this cache + // before expanding it for the first time. + ((struct objc_class * )cls)->info &= ~(CLS_FLUSH_CACHE); - // Clear the grow flag so that we will re-use the current storage, - // rather than actually grow the cache, when expanding the cache - // for the first time - if (_class_slow_grow) - ((struct objc_class * )cls)->info &= ~(CLS_GROW_CACHE); + // Clear the grow flag so that we will re-use the current storage, + // rather than actually grow the cache, when expanding the cache + // for the first time + if (_class_slow_grow) + ((struct objc_class * )cls)->info &= ~(CLS_GROW_CACHE); - // Return our creation - return new_cache; + // Return our creation + return new_cache; } /*********************************************************************** - * _cache_expand. - * - * #ifdef OBJC_COLLECTING_CACHE - * The cacheUpdateLock is assumed to be taken at this point. - * #endif - * - * Called from _cache_fill () - **********************************************************************/ +* _cache_expand. +* +* #ifdef OBJC_COLLECTING_CACHE +* The cacheUpdateLock is assumed to be taken at this point. +* #endif +* +* Called from _cache_fill () +**********************************************************************/ static Cache _cache_expand (Class cls) { - Cache old_cache; - Cache new_cache; - unsigned int slotCount; - unsigned int index; - - // First growth goes from emptyCache to a real one - old_cache = ((struct objc_class *)cls)->cache; - if (old_cache == &emptyCache) - return _cache_create (cls); - - // iff _class_slow_grow, trade off actual cache growth with re-using - // the current one, so that growth only happens every odd time - if (_class_slow_grow) - { - // CLS_GROW_CACHE controls every-other-time behavior. If it - // is non-zero, let the cache grow this time, but clear the - // flag so the cache is reused next time - if ((((struct objc_class * )cls)->info & CLS_GROW_CACHE) != 0) - ((struct objc_class * )cls)->info &= ~CLS_GROW_CACHE; - - // Reuse the current cache storage this time - else - { - // Clear the valid-entry counter - old_cache->occupied = 0; - - // Invalidate all the cache entries - for (index = 0; index < old_cache->mask + 1; index += 1) - { - // Remember what this entry was, so we can possibly - // deallocate it after the bucket has been invalidated - Method oldEntry = old_cache->buckets[index]; - // Skip invalid entry - if (!CACHE_BUCKET_VALID(old_cache->buckets[index])) - continue; - - // Invalidate this entry - CACHE_BUCKET_VALID(old_cache->buckets[index]) = NULL; - - // Deallocate "forward::" entry - if (CACHE_BUCKET_IMP(oldEntry) == &_objc_msgForward) - { + Cache old_cache; + Cache new_cache; + unsigned int slotCount; + unsigned int index; + + // First growth goes from emptyCache to a real one + old_cache = ((struct objc_class *)cls)->cache; + if (old_cache == &emptyCache) + return _cache_create (cls); + + // iff _class_slow_grow, trade off actual cache growth with re-using + // the current one, so that growth only happens every odd time + if (_class_slow_grow) + { + // CLS_GROW_CACHE controls every-other-time behavior. If it + // is non-zero, let the cache grow this time, but clear the + // flag so the cache is reused next time + if ((((struct objc_class * )cls)->info & CLS_GROW_CACHE) != 0) + ((struct objc_class * )cls)->info &= ~CLS_GROW_CACHE; + + // Reuse the current cache storage this time + else + { + // Clear the valid-entry counter + old_cache->occupied = 0; + + // Invalidate all the cache entries + for (index = 0; index < old_cache->mask + 1; index += 1) + { + // Remember what this entry was, so we can possibly + // deallocate it after the bucket has been invalidated + Method oldEntry = old_cache->buckets[index]; + // Skip invalid entry + if (!CACHE_BUCKET_VALID(old_cache->buckets[index])) + continue; + + // Invalidate this entry + CACHE_BUCKET_VALID(old_cache->buckets[index]) = NULL; + + // Deallocate "forward::" entry + if (CACHE_BUCKET_IMP(oldEntry) == &_objc_msgForward) + { #ifdef OBJC_COLLECTING_CACHE - _cache_collect_free (oldEntry, NO); + _cache_collect_free (oldEntry, NO); #else - malloc_zone_free (_objc_create_zone(), oldEntry); + malloc_zone_free (_objc_create_zone(), oldEntry); #endif - } - } - - // Set the slow growth flag so the cache is next grown - ((struct objc_class * )cls)->info |= CLS_GROW_CACHE; - - // Return the same old cache, freshly emptied - return old_cache; - } - - } - - // Double the cache size - slotCount = (old_cache->mask + 1) << 1; - - // Allocate a new cache table + } + } + + // Set the slow growth flag so the cache is next grown + ((struct objc_class * )cls)->info |= CLS_GROW_CACHE; + + // Return the same old cache, freshly emptied + return old_cache; + } + + } + + // Double the cache size + slotCount = (old_cache->mask + 1) << 1; + + // Allocate a new cache table #ifdef OBJC_INSTRUMENTED - new_cache = malloc_zone_malloc (_objc_create_zone(), - sizeof(struct objc_cache) + TABLE_SIZE(slotCount) - + sizeof(CacheInstrumentation)); + new_cache = malloc_zone_malloc (_objc_create_zone(), + sizeof(struct objc_cache) + TABLE_SIZE(slotCount) + + sizeof(CacheInstrumentation)); #else - new_cache = malloc_zone_malloc (_objc_create_zone(), - sizeof(struct objc_cache) + TABLE_SIZE(slotCount)); + new_cache = malloc_zone_malloc (_objc_create_zone(), + sizeof(struct objc_cache) + TABLE_SIZE(slotCount)); #endif - // Zero out the new cache - new_cache->mask = slotCount - 1; - new_cache->occupied = 0; - for (index = 0; index < slotCount; index += 1) - CACHE_BUCKET_VALID(new_cache->buckets[index]) = NULL; + // Zero out the new cache + new_cache->mask = slotCount - 1; + new_cache->occupied = 0; + for (index = 0; index < slotCount; index += 1) + CACHE_BUCKET_VALID(new_cache->buckets[index]) = NULL; #ifdef OBJC_INSTRUMENTED - // Propagate the instrumentation data - { - CacheInstrumentation * oldCacheData; - CacheInstrumentation * newCacheData; - - oldCacheData = CACHE_INSTRUMENTATION(old_cache); - newCacheData = CACHE_INSTRUMENTATION(new_cache); - bcopy ((const char *)oldCacheData, (char *)newCacheData, sizeof(CacheInstrumentation)); - } + // Propagate the instrumentation data + { + CacheInstrumentation * oldCacheData; + CacheInstrumentation * newCacheData; + + oldCacheData = CACHE_INSTRUMENTATION(old_cache); + newCacheData = CACHE_INSTRUMENTATION(new_cache); + bcopy ((const char *)oldCacheData, (char *)newCacheData, sizeof(CacheInstrumentation)); + } #endif - // iff _class_uncache, copy old cache entries into the new cache - if (_class_uncache == 0) - { - int newMask; - - newMask = new_cache->mask; - - // Look at all entries in the old cache - for (index = 0; index < old_cache->mask + 1; index += 1) - { - int index2; - - // Skip invalid entry - if (!CACHE_BUCKET_VALID(old_cache->buckets[index])) - continue; - - // Hash the old entry into the new table - index2 = ((unsigned int) CACHE_BUCKET_NAME(old_cache->buckets[index]) & newMask); - - // Find an available spot, at or following the hashed spot; - // Guaranteed to not infinite loop, because table has grown - for (;;) - { - if (!CACHE_BUCKET_VALID(new_cache->buckets[index2])) - { - new_cache->buckets[index2] = old_cache->buckets[index]; - break; - } - - index2 += 1; - index2 &= newMask; - } - - // Account for the addition - new_cache->occupied += 1; - } - - // Set the cache flush flag so that we will flush this cache - // before expanding it again. - ((struct objc_class * )cls)->info |= CLS_FLUSH_CACHE; - } - - // Deallocate "forward::" entries from the old cache - else - { - for (index = 0; index < old_cache->mask + 1; index += 1) - { - if (CACHE_BUCKET_VALID(old_cache->buckets[index]) && - CACHE_BUCKET_IMP(old_cache->buckets[index]) == &_objc_msgForward) - { + // iff _class_uncache, copy old cache entries into the new cache + if (_class_uncache == 0) + { + int newMask; + + newMask = new_cache->mask; + + // Look at all entries in the old cache + for (index = 0; index < old_cache->mask + 1; index += 1) + { + int index2; + + // Skip invalid entry + if (!CACHE_BUCKET_VALID(old_cache->buckets[index])) + continue; + + // Hash the old entry into the new table + index2 = ((unsigned int) CACHE_BUCKET_NAME(old_cache->buckets[index]) & newMask); + + // Find an available spot, at or following the hashed spot; + // Guaranteed to not infinite loop, because table has grown + for (;;) + { + if (!CACHE_BUCKET_VALID(new_cache->buckets[index2])) + { + new_cache->buckets[index2] = old_cache->buckets[index]; + break; + } + + index2 += 1; + index2 &= newMask; + } + + // Account for the addition + new_cache->occupied += 1; + } + + // Set the cache flush flag so that we will flush this cache + // before expanding it again. + ((struct objc_class * )cls)->info |= CLS_FLUSH_CACHE; + } + + // Deallocate "forward::" entries from the old cache + else + { + for (index = 0; index < old_cache->mask + 1; index += 1) + { + if (CACHE_BUCKET_VALID(old_cache->buckets[index]) && + CACHE_BUCKET_IMP(old_cache->buckets[index]) == &_objc_msgForward) + { #ifdef OBJC_COLLECTING_CACHE - _cache_collect_free (old_cache->buckets[index], NO); + _cache_collect_free (old_cache->buckets[index], NO); #else - malloc_zone_free (_objc_create_zone(), old_cache->buckets[index]); + malloc_zone_free (_objc_create_zone(), old_cache->buckets[index]); #endif - } - } - } + } + } + } - // Install new cache - ((struct objc_class *)cls)->cache = new_cache; + // Install new cache + ((struct objc_class *)cls)->cache = new_cache; - // Deallocate old cache, try freeing all the garbage + // Deallocate old cache, try freeing all the garbage #ifdef OBJC_COLLECTING_CACHE - _cache_collect_free (old_cache, YES); + _cache_collect_free (old_cache, YES); #else - malloc_zone_free (_objc_create_zone(), old_cache); + malloc_zone_free (_objc_create_zone(), old_cache); #endif - return new_cache; + return new_cache; } /*********************************************************************** - * instrumentObjcMessageSends/logObjcMessageSends. - **********************************************************************/ +* instrumentObjcMessageSends/logObjcMessageSends. +**********************************************************************/ static int LogObjCMessageSend (BOOL isClassMethod, - const char * objectsClass, - const char * implementingClass, - SEL selector) + const char * objectsClass, + const char * implementingClass, + SEL selector) { - char buf[ 1024 ]; + char buf[ 1024 ]; - // Create/open the log file - if (objcMsgLogFD == (-1)) - { - sprintf (buf, "/tmp/msgSends-%d", (int) getpid ()); - objcMsgLogFD = open (buf, O_WRONLY | O_CREAT, 0666); - } + // Create/open the log file + if (objcMsgLogFD == (-1)) + { + sprintf (buf, "/tmp/msgSends-%d", (int) getpid ()); + objcMsgLogFD = open (buf, O_WRONLY | O_CREAT, 0666); + } + + // Make the log entry + sprintf(buf, "%c %s %s %s\n", + isClassMethod ? '+' : '-', + objectsClass, + implementingClass, + (char *) selector); - // Make the log entry - sprintf(buf, "%c %s %s %s\n", - isClassMethod ? '+' : '-', - objectsClass, - implementingClass, - (char *) selector); - - write (objcMsgLogFD, buf, strlen(buf)); + write (objcMsgLogFD, buf, strlen(buf)); - // Tell caller to not cache the method - return 0; + // Tell caller to not cache the method + return 0; } void instrumentObjcMessageSends (BOOL flag) { - int enabledValue = (flag) ? 1 : 0; + int enabledValue = (flag) ? 1 : 0; + + // Shortcut NOP + if (objcMsgLogEnabled == enabledValue) + return; - // Shortcut NOP - if (objcMsgLogEnabled == enabledValue) - return; - - // If enabling, flush all method caches so we get some traces - if (flag) - flush_caches (Nil, YES); - - // Sync our log file - if (objcMsgLogFD != (-1)) - fsync (objcMsgLogFD); + // If enabling, flush all method caches so we get some traces + if (flag) + flush_caches (Nil, YES); - objcMsgLogEnabled = enabledValue; + // Sync our log file + if (objcMsgLogFD != (-1)) + fsync (objcMsgLogFD); + + objcMsgLogEnabled = enabledValue; } void logObjcMessageSends (ObjCLogProc logProc) { - if (logProc) - { - objcMsgLogProc = logProc; - objcMsgLogEnabled = 1; - } - else - { - objcMsgLogProc = logProc; - objcMsgLogEnabled = 0; - } + if (logProc) + { + objcMsgLogProc = logProc; + objcMsgLogEnabled = 1; + } + else + { + objcMsgLogProc = logProc; + objcMsgLogEnabled = 0; + } - if (objcMsgLogFD != (-1)) - fsync (objcMsgLogFD); + if (objcMsgLogFD != (-1)) + fsync (objcMsgLogFD); } /*********************************************************************** - * _cache_fill. Add the specified method to the specified class' cache. - * - * Called only from _class_lookupMethodAndLoadCache and - * class_respondsToMethod. - * - * #ifdef OBJC_COLLECTING_CACHE - * It doesn't matter if someone has the messageLock when we enter this - * function. This function will fail to do the update if someone else - * is already updating the cache, i.e. they have the cacheUpdateLock. - * #else - * The messageLock is already assumed to be taken out. - * #endif - **********************************************************************/ +* _cache_fill. Add the specified method to the specified class' cache. +* +* Called only from _class_lookupMethodAndLoadCache and +* class_respondsToMethod. +* +* #ifdef OBJC_COLLECTING_CACHE +* It doesn't matter if someone has the messageLock when we enter this +* function. This function will fail to do the update if someone else +* is already updating the cache, i.e. they have the cacheUpdateLock. +* #else +* The messageLock is already assumed to be taken out. +* #endif +**********************************************************************/ static void _cache_fill (Class cls, - Method smt, - SEL sel) + Method smt, + SEL sel) { - Cache cache; - Method * buckets; + Cache cache; + Method * buckets; - arith_t index; - arith_t mask; - unsigned int newOccupied; + arith_t index; + arith_t mask; + unsigned int newOccupied; - // Keep tally of cache additions - totalCacheFills += 1; + // Keep tally of cache additions + totalCacheFills += 1; #ifdef OBJC_COLLECTING_CACHE - // Make sure only one thread is updating the cache at a time, but don't - // wait for concurrent updater to finish, because it might be a while, or - // a deadlock! Instead, just leave the method out of the cache until - // next time. This is nasty given that cacheUpdateLock is per task! - if (!OBJC_TRYLOCK(&cacheUpdateLock)) - return; - - // Set up invariants for cache traversals - cache = ((struct objc_class *)cls)->cache; - mask = cache->mask; - buckets = cache->buckets; - - // Check for duplicate entries, if we're in the mode - if (traceDuplicates) - { - int index2; - - // Scan the cache - for (index2 = 0; index2 < mask + 1; index2 += 1) - { - // Skip invalid or non-duplicate entry - if ((!CACHE_BUCKET_VALID(buckets[index2])) || - (strcmp ((char *) CACHE_BUCKET_NAME(buckets[index2]), (char *) smt->method_name) != 0)) - continue; - - // Tally duplication, but report iff wanted - cacheFillDuplicates += 1; - if (traceDuplicatesVerbose) - { - _objc_inform ("Cache fill duplicate #%d: found %x adding %x: %s\n", - cacheFillDuplicates, - (unsigned int) CACHE_BUCKET_NAME(buckets[index2]), - (unsigned int) smt->method_name, - (char *) smt->method_name); - } - } - } - - // Do nothing if entry is already placed. This re-check is needed - // only in the OBJC_COLLECTING_CACHE code, because the probe is - // done un-sync'd. - index = ((unsigned int) sel & mask); - while (CACHE_BUCKET_VALID(buckets[index])) - { - if (CACHE_BUCKET_NAME(buckets[index]) == sel) - { - OBJC_UNLOCK(&cacheUpdateLock); - return; - } - - index += 1; - index &= mask; - } + // Make sure only one thread is updating the cache at a time, but don't + // wait for concurrent updater to finish, because it might be a while, or + // a deadlock! Instead, just leave the method out of the cache until + // next time. This is nasty given that cacheUpdateLock is per task! + if (!OBJC_TRYLOCK(&cacheUpdateLock)) + return; + + // Set up invariants for cache traversals + cache = ((struct objc_class *)cls)->cache; + mask = cache->mask; + buckets = cache->buckets; + + // Check for duplicate entries, if we're in the mode + if (traceDuplicates) + { + int index2; + + // Scan the cache + for (index2 = 0; index2 < mask + 1; index2 += 1) + { + // Skip invalid or non-duplicate entry + if ((!CACHE_BUCKET_VALID(buckets[index2])) || + (strcmp ((char *) CACHE_BUCKET_NAME(buckets[index2]), (char *) smt->method_name) != 0)) + continue; + + // Tally duplication, but report iff wanted + cacheFillDuplicates += 1; + if (traceDuplicatesVerbose) + { + _objc_inform ("Cache fill duplicate #%d: found %x adding %x: %s\n", + cacheFillDuplicates, + (unsigned int) CACHE_BUCKET_NAME(buckets[index2]), + (unsigned int) smt->method_name, + (char *) smt->method_name); + } + } + } + + // Do nothing if entry is already placed. This re-check is needed + // only in the OBJC_COLLECTING_CACHE code, because the probe is + // done un-sync'd. + index = ((unsigned int) sel & mask); + while (CACHE_BUCKET_VALID(buckets[index])) + { + if (CACHE_BUCKET_NAME(buckets[index]) == sel) + { + OBJC_UNLOCK(&cacheUpdateLock); + return; + } + + index += 1; + index &= mask; + } #else // not OBJC_COLLECTING_CACHE - cache = ((struct objc_class *)cls)->cache; - mask = cache->mask; + cache = ((struct objc_class *)cls)->cache; + mask = cache->mask; #endif - // Use the cache as-is if it is less than 3/4 full - newOccupied = cache->occupied + 1; - if ((newOccupied * 4) <= (mask + 1) * 3) - cache->occupied = newOccupied; - - // Cache is getting full - else - { - // Flush the cache - if ((((struct objc_class * )cls)->info & CLS_FLUSH_CACHE) != 0) - _cache_flush (cls); - - // Expand the cache - else - { - cache = _cache_expand (cls); - mask = cache->mask; - } - - // Account for the addition - cache->occupied += 1; - } - - // Insert the new entry. This can be done by either: - // (a) Scanning for the first unused spot. Easy! - // (b) Opening up an unused spot by sliding existing - // entries down by one. The benefit of this - // extra work is that it puts the most recently - // loaded entries closest to where the selector - // hash starts the search. - // - // The loop is a little more complicated because there - // are two kinds of entries, so there have to be two ways - // to slide them. - buckets = cache->buckets; - index = ((unsigned int) sel & mask); - for (;;) - { - // Slide existing entries down by one - Method saveMethod; - - // Copy current entry to a local - saveMethod = buckets[index]; - - // Copy previous entry (or new entry) to current slot - buckets[index] = smt; - - // Done if current slot had been invalid - if (saveMethod == NULL) - break; - - // Prepare to copy saved value into next slot - smt = saveMethod; - - // Move on to next slot - index += 1; - index &= mask; - } + // Use the cache as-is if it is less than 3/4 full + newOccupied = cache->occupied + 1; + if ((newOccupied * 4) <= (mask + 1) * 3) + cache->occupied = newOccupied; + + // Cache is getting full + else + { + // Flush the cache + if ((((struct objc_class * )cls)->info & CLS_FLUSH_CACHE) != 0) + _cache_flush (cls); + + // Expand the cache + else + { + cache = _cache_expand (cls); + mask = cache->mask; + } + + // Account for the addition + cache->occupied += 1; + } + + // Insert the new entry. This can be done by either: + // (a) Scanning for the first unused spot. Easy! + // (b) Opening up an unused spot by sliding existing + // entries down by one. The benefit of this + // extra work is that it puts the most recently + // loaded entries closest to where the selector + // hash starts the search. + // + // The loop is a little more complicated because there + // are two kinds of entries, so there have to be two ways + // to slide them. + buckets = cache->buckets; + index = ((unsigned int) sel & mask); + for (;;) + { + // Slide existing entries down by one + Method saveMethod; + + // Copy current entry to a local + saveMethod = buckets[index]; + + // Copy previous entry (or new entry) to current slot + buckets[index] = smt; + + // Done if current slot had been invalid + if (saveMethod == NULL) + break; + + // Prepare to copy saved value into next slot + smt = saveMethod; + + // Move on to next slot + index += 1; + index &= mask; + } #ifdef OBJC_COLLECTING_CACHE - OBJC_UNLOCK(&cacheUpdateLock); + OBJC_UNLOCK(&cacheUpdateLock); #endif } /*********************************************************************** - * _cache_flush. Invalidate all valid entries in the given class' cache, - * and clear the CLS_FLUSH_CACHE in the cls->info. - * - * Called from flush_caches (). - **********************************************************************/ +* _cache_flush. Invalidate all valid entries in the given class' cache, +* and clear the CLS_FLUSH_CACHE in the cls->info. +* +* Called from flush_caches (). +**********************************************************************/ static void _cache_flush (Class cls) { - Cache cache; - unsigned int index; - - // Locate cache. Ignore unused cache. - cache = ((struct objc_class *)cls)->cache; - if (cache == &emptyCache) - return; + Cache cache; + unsigned int index; + + // Locate cache. Ignore unused cache. + cache = ((struct objc_class *)cls)->cache; + if (cache == &emptyCache) + return; #ifdef OBJC_INSTRUMENTED - { - CacheInstrumentation * cacheData; - - // Tally this flush - cacheData = CACHE_INSTRUMENTATION(cache); - cacheData->flushCount += 1; - cacheData->flushedEntries += cache->occupied; - if (cache->occupied > cacheData->maxFlushedEntries) - cacheData->maxFlushedEntries = cache->occupied; - } + { + CacheInstrumentation * cacheData; + + // Tally this flush + cacheData = CACHE_INSTRUMENTATION(cache); + cacheData->flushCount += 1; + cacheData->flushedEntries += cache->occupied; + if (cache->occupied > cacheData->maxFlushedEntries) + cacheData->maxFlushedEntries = cache->occupied; + } #endif - - // Traverse the cache - for (index = 0; index <= cache->mask; index += 1) - { - // Remember what this entry was, so we can possibly - // deallocate it after the bucket has been invalidated - Method oldEntry = cache->buckets[index]; - - // Invalidate this entry - CACHE_BUCKET_VALID(cache->buckets[index]) = NULL; - - // Deallocate "forward::" entry - if (oldEntry && oldEntry->method_imp == &_objc_msgForward) + + // Traverse the cache + for (index = 0; index <= cache->mask; index += 1) + { + // Remember what this entry was, so we can possibly + // deallocate it after the bucket has been invalidated + Method oldEntry = cache->buckets[index]; + + // Invalidate this entry + CACHE_BUCKET_VALID(cache->buckets[index]) = NULL; + + // Deallocate "forward::" entry + if (oldEntry && oldEntry->method_imp == &_objc_msgForward) #ifdef OBJC_COLLECTING_CACHE - _cache_collect_free (oldEntry, NO); + _cache_collect_free (oldEntry, NO); #else - malloc_zone_free (_objc_create_zone(), oldEntry); + malloc_zone_free (_objc_create_zone(), oldEntry); #endif - } - - // Clear the valid-entry counter - cache->occupied = 0; + } - // Clear the cache flush flag so that we will not flush this cache - // before expanding it again. - ((struct objc_class * )cls)->info &= ~CLS_FLUSH_CACHE; + // Clear the valid-entry counter + cache->occupied = 0; + + // Clear the cache flush flag so that we will not flush this cache + // before expanding it again. + ((struct objc_class * )cls)->info &= ~CLS_FLUSH_CACHE; } /*********************************************************************** - * _objc_getFreedObjectClass. Return a pointer to the dummy freed - * object class. Freed objects get their isa pointers replaced with - * a pointer to the freedObjectClass, so that we can catch usages of - * the freed object. - **********************************************************************/ +* _objc_getFreedObjectClass. Return a pointer to the dummy freed +* object class. Freed objects get their isa pointers replaced with +* a pointer to the freedObjectClass, so that we can catch usages of +* the freed object. +**********************************************************************/ Class _objc_getFreedObjectClass (void) { - return (Class) &freedObjectClass; + return (Class) &freedObjectClass; } /*********************************************************************** - * _objc_getNonexistentClass. Return a pointer to the dummy nonexistent - * object class. This is used when, for example, mapping the class - * refs for an image, and the class can not be found, so that we can - * catch later uses of the non-existent class. - **********************************************************************/ +* _objc_getNonexistentClass. Return a pointer to the dummy nonexistent +* object class. This is used when, for example, mapping the class +* refs for an image, and the class can not be found, so that we can +* catch later uses of the non-existent class. +**********************************************************************/ Class _objc_getNonexistentClass (void) { - return (Class) &nonexistentObjectClass; + return (Class) &nonexistentObjectClass; } /*********************************************************************** - * _class_lookupMethodAndLoadCache. - * - * Called only from objc_msgSend, objc_msgSendSuper and class_lookupMethod. - **********************************************************************/ +* _class_lookupMethodAndLoadCache. +* +* Called only from objc_msgSend, objc_msgSendSuper and class_lookupMethod. +**********************************************************************/ IMP _class_lookupMethodAndLoadCache (Class cls, - SEL sel) -{ - struct objc_class * curClass; - Method smt; - BOOL calledSingleThreaded; - IMP methodPC; - - ptrace(0xb300, 0, 0, 0); - - // Check for freed class - if (cls == &freedObjectClass) - return (IMP) _freedHandler; - - // Check for nonexistent class - if (cls == &nonexistentObjectClass) - return (IMP) _nonexistentHandler; - + SEL sel) +{ + struct objc_class * curClass; + Method smt; + BOOL calledSingleThreaded; + IMP methodPC; + + trace(0xb300, 0, 0, 0); + + // Check for freed class + if (cls == &freedObjectClass) + return (IMP) _freedHandler; + + // Check for nonexistent class + if (cls == &nonexistentObjectClass) + return (IMP) _nonexistentHandler; + #ifndef OBJC_COLLECTING_CACHE - // Control can get here via the single-threaded message dispatcher, - // but class_initialize can cause application to go multithreaded. Notice - // whether this is the case, so we can leave the messageLock unlocked - // on the way out, just as the single-threaded message dispatcher - // expects. Note that the messageLock locking in classinitialize is - // appropriate in this case, because there are more than one thread now. - calledSingleThreaded = (_objc_multithread_mask != 0); + // Control can get here via the single-threaded message dispatcher, + // but class_initialize can cause application to go multithreaded. Notice + // whether this is the case, so we can leave the messageLock unlocked + // on the way out, just as the single-threaded message dispatcher + // expects. Note that the messageLock locking in classinitialize is + // appropriate in this case, because there are more than one thread now. + calledSingleThreaded = (_objc_multithread_mask != 0); #endif - ptrace(0xb301, 0, 0, 0); - - // Lazy initialization. This unlocks and relocks messageLock, - // so cache information we might already have becomes invalid. - if (!ISINITIALIZED(cls)) - class_initialize (objc_getClass (((struct objc_class *)cls)->name)); - - ptrace(0xb302, 0, 0, 0); - - // Outer loop - search the caches and method lists of the - // class and its super-classes - methodPC = NULL; - for (curClass = cls; curClass; curClass = ((struct objc_class * )curClass)->super_class) - { - Method * buckets; - arith_t idx; - arith_t mask; - arith_t methodCount; - struct objc_method_list *mlist; - void *iterator = 0; + trace(0xb301, 0, 0, 0); + + // Lazy initialization. This unlocks and relocks messageLock, + // so cache information we might already have becomes invalid. + if (!ISINITIALIZED(cls)) + class_initialize (objc_getClass (((struct objc_class *)cls)->name)); + + trace(0xb302, 0, 0, 0); + + // Outer loop - search the caches and method lists of the + // class and its super-classes + methodPC = NULL; + for (curClass = cls; curClass; curClass = ((struct objc_class * )curClass)->super_class) + { + Method * buckets; + arith_t idx; + arith_t mask; + arith_t methodCount; + struct objc_method_list *mlist; + void *iterator = 0; #ifdef PRELOAD_SUPERCLASS_CACHES - struct objc_class * curClass2; + struct objc_class * curClass2; #endif - ptrace(0xb303, 0, 0, 0); - - mask = curClass->cache->mask; - buckets = curClass->cache->buckets; - - // Minor loop #1 - check cache of given class - for (idx = ((uarith_t) sel & mask); - CACHE_BUCKET_VALID(buckets[idx]); - idx = (++idx & mask)) - { - // Skip entries until selector matches - if (CACHE_BUCKET_NAME(buckets[idx]) != sel) - continue; - - // Found the method. Add it to the cache(s) - // unless it was found in the cache of the - // class originally being messaged. - // - // NOTE: The method is usually not found - // the original class' cache, because - // objc_msgSend () has already looked. - // BUT, if sending this method resulted in - // a +initialize on the class, and +initialize - // sends the same method, the method will - // indeed now be in the cache. Calling - // _cache_fill with a buckets[idx] from the - // cache being filled results in a crash - // if the cache has to grow, because the - // buckets[idx] address is no longer valid. - if (curClass != cls) - { + trace(0xb303, 0, 0, 0); + + mask = curClass->cache->mask; + buckets = curClass->cache->buckets; + + // Minor loop #1 - check cache of given class + for (idx = ((uarith_t) sel & mask); + CACHE_BUCKET_VALID(buckets[idx]); + idx = (++idx & mask)) + { + // Skip entries until selector matches + if (CACHE_BUCKET_NAME(buckets[idx]) != sel) + continue; + + // Found the method. Add it to the cache(s) + // unless it was found in the cache of the + // class originally being messaged. + // + // NOTE: The method is usually not found + // the original class' cache, because + // objc_msgSend () has already looked. + // BUT, if sending this method resulted in + // a +initialize on the class, and +initialize + // sends the same method, the method will + // indeed now be in the cache. Calling + // _cache_fill with a buckets[idx] from the + // cache being filled results in a crash + // if the cache has to grow, because the + // buckets[idx] address is no longer valid. + if (curClass != cls) + { #ifdef PRELOAD_SUPERCLASS_CACHES - for (curClass2 = cls; curClass2 != curClass; curClass2 = curClass2->super_class) - _cache_fill (curClass2, buckets[idx], sel); - _cache_fill (curClass, buckets[idx], sel); + for (curClass2 = cls; curClass2 != curClass; curClass2 = curClass2->super_class) + _cache_fill (curClass2, buckets[idx], sel); + _cache_fill (curClass, buckets[idx], sel); #else - _cache_fill (cls, buckets[idx], sel); + _cache_fill (cls, buckets[idx], sel); #endif - } - - // Return the implementation address - methodPC = CACHE_BUCKET_IMP(buckets[idx]); - break; - } - - ptrace(0xb304, (int)methodPC, 0, 0); - - // Done if that found it - if (methodPC) - break; - - smt = _findMethodInClass(curClass, sel); - - if (smt) { - // If logging is enabled, log the message send and let - // the logger decide whether to encache the method. - if ((objcMsgLogEnabled == 0) || - (objcMsgLogProc (CLS_GETINFO(((struct objc_class * )curClass),CLS_META) ? YES : NO, - ((struct objc_class *)cls)->name, - curClass->name, sel))) - { - // Cache the method implementation + } + + // Return the implementation address + methodPC = CACHE_BUCKET_IMP(buckets[idx]); + break; + } + + trace(0xb304, (int)methodPC, 0, 0); + + // Done if that found it + if (methodPC) + break; + + smt = _findMethodInClass(curClass, sel); + + if (smt) { + // If logging is enabled, log the message send and let + // the logger decide whether to encache the method. + if ((objcMsgLogEnabled == 0) || + (objcMsgLogProc (CLS_GETINFO(((struct objc_class * )curClass),CLS_META) ? YES : NO, + ((struct objc_class *)cls)->name, + curClass->name, sel))) + { + // Cache the method implementation #ifdef PRELOAD_SUPERCLASS_CACHES - for (curClass2 = cls; curClass2 != curClass; curClass2 = curClass2->super_class) - _cache_fill (curClass2, smt, sel); - _cache_fill (curClass, smt, sel); + for (curClass2 = cls; curClass2 != curClass; curClass2 = curClass2->super_class) + _cache_fill (curClass2, smt, sel); + _cache_fill (curClass, smt, sel); #else - _cache_fill (cls, smt, sel); + _cache_fill (cls, smt, sel); #endif - } - // Return the implementation - methodPC = smt->method_imp; - } - - ptrace(0xb305, (int)methodPC, 0, 0); - - // Done if that found it - if (methodPC) - break; - } - - ptrace(0xb306, (int)methodPC, 0, 0); - - if (methodPC == NULL) - { - // Class and superclasses do not respond -- use forwarding - smt = malloc_zone_malloc (_objc_create_zone(), sizeof(struct objc_method)); - smt->method_name = sel; - smt->method_types = ""; - smt->method_imp = &_objc_msgForward; - _cache_fill (cls, smt, sel); - methodPC = &_objc_msgForward; - } - + } + // Return the implementation + methodPC = smt->method_imp; + } + + trace(0xb305, (int)methodPC, 0, 0); + + // Done if that found it + if (methodPC) + break; + } + + trace(0xb306, (int)methodPC, 0, 0); + + if (methodPC == NULL) + { + // Class and superclasses do not respond -- use forwarding + smt = malloc_zone_malloc (_objc_create_zone(), sizeof(struct objc_method)); + smt->method_name = sel; + smt->method_types = ""; + smt->method_imp = &_objc_msgForward; + _cache_fill (cls, smt, sel); + methodPC = &_objc_msgForward; + } + #ifndef OBJC_COLLECTING_CACHE - // Unlock the lock - if (calledSingleThreaded) - OBJC_UNLOCK(&messageLock); + // Unlock the lock + if (calledSingleThreaded) + OBJC_UNLOCK(&messageLock); #endif - ptrace(0xb30f, (int)methodPC, 0, 0); - - return methodPC; + trace(0xb30f, (int)methodPC, 0, 0); + + return methodPC; } /*********************************************************************** - * SubtypeUntil. - * - * Delegation. - **********************************************************************/ +* SubtypeUntil. +* +* Delegation. +**********************************************************************/ static int SubtypeUntil (const char * type, - char end) -{ - int level = 0; - const char * head = type; - - // - while (*type) - { - if (!*type || (!level && (*type == end))) - return (int)(type - head); - - switch (*type) - { - case ']': case '}': case ')': level--; break; - case '[': case '{': case '(': level += 1; break; - } - - type += 1; - } - - _objc_fatal ("Object: SubtypeUntil: end of type encountered prematurely\n"); - return 0; -} - -/*********************************************************************** - * SkipFirstType. - **********************************************************************/ -static const char * SkipFirstType (const char * type) -{ - while (1) - { - switch (*type++) - { - case 'O': /* bycopy */ - case 'n': /* in */ - case 'o': /* out */ - case 'N': /* inout */ - case 'r': /* const */ - case 'V': /* oneway */ - case '^': /* pointers */ - break; - - /* arrays */ - case '[': - while ((*type >= '0') && (*type <= '9')) - type += 1; - return type + SubtypeUntil (type, ']') + 1; - - /* structures */ - case '{': - return type + SubtypeUntil (type, '}') + 1; - - /* unions */ - case '(': - return type + SubtypeUntil (type, ')') + 1; - - /* basic types */ - default: - return type; - } - } -} - -/*********************************************************************** - * method_getNumberOfArguments. - **********************************************************************/ + char end) +{ + int level = 0; + const char * head = type; + + // + while (*type) + { + if (!*type || (!level && (*type == end))) + return (int)(type - head); + + switch (*type) + { + case ']': case '}': case ')': level--; break; + case '[': case '{': case '(': level += 1; break; + } + + type += 1; + } + + _objc_fatal ("Object: SubtypeUntil: end of type encountered prematurely\n"); + return 0; +} + +/*********************************************************************** +* SkipFirstType. +**********************************************************************/ +static const char * SkipFirstType (const char * type) +{ + while (1) + { + switch (*type++) + { + case 'O': /* bycopy */ + case 'n': /* in */ + case 'o': /* out */ + case 'N': /* inout */ + case 'r': /* const */ + case 'V': /* oneway */ + case '^': /* pointers */ + break; + + /* arrays */ + case '[': + while ((*type >= '0') && (*type <= '9')) + type += 1; + return type + SubtypeUntil (type, ']') + 1; + + /* structures */ + case '{': + return type + SubtypeUntil (type, '}') + 1; + + /* unions */ + case '(': + return type + SubtypeUntil (type, ')') + 1; + + /* basic types */ + default: + return type; + } + } +} + +/*********************************************************************** +* method_getNumberOfArguments. +**********************************************************************/ unsigned method_getNumberOfArguments (Method method) { - const char * typedesc; - unsigned nargs; - - // First, skip the return type - typedesc = method->method_types; - typedesc = SkipFirstType (typedesc); - - // Next, skip stack size - while ((*typedesc >= '0') && (*typedesc <= '9')) - typedesc += 1; - - // Now, we have the arguments - count how many - nargs = 0; - while (*typedesc) - { - // Traverse argument type - typedesc = SkipFirstType (typedesc); - - // Traverse (possibly negative) argument offset - if (*typedesc == '-') - typedesc += 1; - while ((*typedesc >= '0') && (*typedesc <= '9')) - typedesc += 1; - - // Made it past an argument - nargs += 1; - } - - return nargs; -} - -/*********************************************************************** - * method_getSizeOfArguments. - **********************************************************************/ + const char * typedesc; + unsigned nargs; + + // First, skip the return type + typedesc = method->method_types; + typedesc = SkipFirstType (typedesc); + + // Next, skip stack size + while ((*typedesc >= '0') && (*typedesc <= '9')) + typedesc += 1; + + // Now, we have the arguments - count how many + nargs = 0; + while (*typedesc) + { + // Traverse argument type + typedesc = SkipFirstType (typedesc); + + // Traverse (possibly negative) argument offset + if (*typedesc == '-') + typedesc += 1; + while ((*typedesc >= '0') && (*typedesc <= '9')) + typedesc += 1; + + // Made it past an argument + nargs += 1; + } + + return nargs; +} + +/*********************************************************************** +* method_getSizeOfArguments. +**********************************************************************/ #ifndef __alpha__ unsigned method_getSizeOfArguments (Method method) { - const char * typedesc; - unsigned stack_size; + const char * typedesc; + unsigned stack_size; #if defined(__ppc__) || defined(ppc) - unsigned trueBaseOffset; - unsigned foundBaseOffset; + unsigned trueBaseOffset; + unsigned foundBaseOffset; #endif - - // Get our starting points - stack_size = 0; - typedesc = method->method_types; - // Skip the return type + // Get our starting points + stack_size = 0; + typedesc = method->method_types; + + // Skip the return type #if defined (__ppc__) || defined(ppc) - // Struct returns cause the parameters to be bumped - // by a register, so the offset to the receiver is - // 4 instead of the normal 0. - trueBaseOffset = (*typedesc == '{') ? 4 : 0; + // Struct returns cause the parameters to be bumped + // by a register, so the offset to the receiver is + // 4 instead of the normal 0. + trueBaseOffset = (*typedesc == '{') ? 4 : 0; #endif - typedesc = SkipFirstType (typedesc); - - // Convert ASCII number string to integer - while ((*typedesc >= '0') && (*typedesc <= '9')) - stack_size = (stack_size * 10) + (*typedesc++ - '0'); + typedesc = SkipFirstType (typedesc); + + // Convert ASCII number string to integer + while ((*typedesc >= '0') && (*typedesc <= '9')) + stack_size = (stack_size * 10) + (*typedesc++ - '0'); #if defined (__ppc__) || defined(ppc) - // NOTE: This is a temporary measure pending a compiler fix. - // Work around PowerPC compiler bug wherein the method argument - // string contains an incorrect value for the "stack size." - // Generally, the size is reported 4 bytes too small, so we apply - // that fudge factor. Unfortunately, there is at least one case - // where the error is something other than -4: when the last - // parameter is a double, the reported stack is much too high - // (about 32 bytes). We do not attempt to detect that case. - // The result of returning a too-high value is that objc_msgSendv - // can bus error if the destination of the marg_list copying - // butts up against excluded memory. - // This fix disables itself when it sees a correctly built - // type string (i.e. the offset for the Id is correct). This - // keeps us out of lockstep with the compiler. - - // skip the '@' marking the Id field - typedesc = SkipFirstType (typedesc); - - // pick up the offset for the Id field - foundBaseOffset = 0; - while ((*typedesc >= '0') && (*typedesc <= '9')) - foundBaseOffset = (foundBaseOffset * 10) + (*typedesc++ - '0'); - - // add fudge factor iff the Id field offset was wrong - if (foundBaseOffset != trueBaseOffset) - stack_size += 4; + // NOTE: This is a temporary measure pending a compiler fix. + // Work around PowerPC compiler bug wherein the method argument + // string contains an incorrect value for the "stack size." + // Generally, the size is reported 4 bytes too small, so we apply + // that fudge factor. Unfortunately, there is at least one case + // where the error is something other than -4: when the last + // parameter is a double, the reported stack is much too high + // (about 32 bytes). We do not attempt to detect that case. + // The result of returning a too-high value is that objc_msgSendv + // can bus error if the destination of the marg_list copying + // butts up against excluded memory. + // This fix disables itself when it sees a correctly built + // type string (i.e. the offset for the Id is correct). This + // keeps us out of lockstep with the compiler. + + // skip the '@' marking the Id field + typedesc = SkipFirstType (typedesc); + + // pick up the offset for the Id field + foundBaseOffset = 0; + while ((*typedesc >= '0') && (*typedesc <= '9')) + foundBaseOffset = (foundBaseOffset * 10) + (*typedesc++ - '0'); + + // add fudge factor iff the Id field offset was wrong + if (foundBaseOffset != trueBaseOffset) + stack_size += 4; #endif - return stack_size; + return stack_size; } #else // __alpha__ -// XXX Getting the size of a type is done all over the place -// (Here, Foundation, remote project)! - Should unify + // XXX Getting the size of a type is done all over the place + // (Here, Foundation, remote project)! - Should unify unsigned int getSizeOfType (const char * type, unsigned int * alignPtr); unsigned method_getSizeOfArguments (Method method) { - const char * type; - int size; - int index; - int align; - int offset; - unsigned stack_size; - int nargs; - - nargs = method_getNumberOfArguments (method); - stack_size = (*method->method_types == '{') ? sizeof(void *) : 0; - - for (index = 0; index < nargs; index += 1) - { - (void) method_getArgumentInfo (method, index, &type, &offset); - size = getSizeOfType (type, &align); - stack_size += ((size + 7) & ~7); - } - - return stack_size; + const char * type; + int size; + int index; + int align; + int offset; + unsigned stack_size; + int nargs; + + nargs = method_getNumberOfArguments (method); + stack_size = (*method->method_types == '{') ? sizeof(void *) : 0; + + for (index = 0; index < nargs; index += 1) + { + (void) method_getArgumentInfo (method, index, &type, &offset); + size = getSizeOfType (type, &align); + stack_size += ((size + 7) & ~7); + } + + return stack_size; } #endif // __alpha__ /*********************************************************************** - * method_getArgumentInfo. - **********************************************************************/ +* method_getArgumentInfo. +**********************************************************************/ unsigned method_getArgumentInfo (Method method, - int arg, - const char ** type, - int * offset) -{ - const char * typedesc = method->method_types; - unsigned nargs = 0; - unsigned self_offset = 0; - BOOL offset_is_negative = NO; - - // First, skip the return type - typedesc = SkipFirstType (typedesc); - - // Next, skip stack size - while ((*typedesc >= '0') && (*typedesc <= '9')) - typedesc += 1; - - // Now, we have the arguments - position typedesc to the appropriate argument - while (*typedesc && nargs != arg) - { - - // Skip argument type - typedesc = SkipFirstType (typedesc); - - if (nargs == 0) - { - // Skip negative sign in offset - if (*typedesc == '-') - { - offset_is_negative = YES; - typedesc += 1; - } - else - offset_is_negative = NO; - - while ((*typedesc >= '0') && (*typedesc <= '9')) - self_offset = self_offset * 10 + (*typedesc++ - '0'); - if (offset_is_negative) - self_offset = -(self_offset); - - } - - else - { - // Skip (possibly negative) argument offset - if (*typedesc == '-') - typedesc += 1; - while ((*typedesc >= '0') && (*typedesc <= '9')) - typedesc += 1; - } - - nargs += 1; - } - - if (*typedesc) - { - unsigned arg_offset = 0; - - *type = typedesc; - typedesc = SkipFirstType (typedesc); - - if (arg == 0) - { + int arg, + const char ** type, + int * offset) +{ + const char * typedesc = method->method_types; + unsigned nargs = 0; + unsigned self_offset = 0; + BOOL offset_is_negative = NO; + + // First, skip the return type + typedesc = SkipFirstType (typedesc); + + // Next, skip stack size + while ((*typedesc >= '0') && (*typedesc <= '9')) + typedesc += 1; + + // Now, we have the arguments - position typedesc to the appropriate argument + while (*typedesc && nargs != arg) + { + + // Skip argument type + typedesc = SkipFirstType (typedesc); + + if (nargs == 0) + { + // Skip negative sign in offset + if (*typedesc == '-') + { + offset_is_negative = YES; + typedesc += 1; + } + else + offset_is_negative = NO; + + while ((*typedesc >= '0') && (*typedesc <= '9')) + self_offset = self_offset * 10 + (*typedesc++ - '0'); + if (offset_is_negative) + self_offset = -(self_offset); + + } + + else + { + // Skip (possibly negative) argument offset + if (*typedesc == '-') + typedesc += 1; + while ((*typedesc >= '0') && (*typedesc <= '9')) + typedesc += 1; + } + + nargs += 1; + } + + if (*typedesc) + { + unsigned arg_offset = 0; + + *type = typedesc; + typedesc = SkipFirstType (typedesc); + + if (arg == 0) + { #ifdef hppa - *offset = -sizeof(id); + *offset = -sizeof(id); #else - *offset = 0; -#endif // hppa - } - - else - { - // Pick up (possibly negative) argument offset - if (*typedesc == '-') - { - offset_is_negative = YES; - typedesc += 1; - } - else - offset_is_negative = NO; - - while ((*typedesc >= '0') && (*typedesc <= '9')) - arg_offset = arg_offset * 10 + (*typedesc++ - '0'); - if (offset_is_negative) - arg_offset = - arg_offset; - + *offset = 0; +#endif // hppa + } + + else + { + // Pick up (possibly negative) argument offset + if (*typedesc == '-') + { + offset_is_negative = YES; + typedesc += 1; + } + else + offset_is_negative = NO; + + while ((*typedesc >= '0') && (*typedesc <= '9')) + arg_offset = arg_offset * 10 + (*typedesc++ - '0'); + if (offset_is_negative) + arg_offset = - arg_offset; + #ifdef hppa - // For stacks which grow up, since margs points - // to the top of the stack or the END of the args, - // the first offset is at -sizeof(id) rather than 0. - self_offset += sizeof(id); + // For stacks which grow up, since margs points + // to the top of the stack or the END of the args, + // the first offset is at -sizeof(id) rather than 0. + self_offset += sizeof(id); #endif - *offset = arg_offset - self_offset; - } - - } - - else - { - *type = 0; - *offset = 0; - } - - return nargs; + *offset = arg_offset - self_offset; + } + + } + + else + { + *type = 0; + *offset = 0; + } + + return nargs; } /*********************************************************************** - * _objc_create_zone. - **********************************************************************/ +* _objc_create_zone. +**********************************************************************/ void * _objc_create_zone (void) { - static void *_objc_z = (void *)0xffffffff; - if ( _objc_z == (void *)0xffffffff ) { - char *s = getenv("OBJC_USE_OBJC_ZONE"); - if ( s ) { - if ( (*s == '1') || (*s == 'y') || (*s == 'Y') ) { - _objc_z = malloc_create_zone(vm_page_size, 0); - malloc_set_zone_name(_objc_z, "ObjC"); - } - } - if ( _objc_z == (void *)0xffffffff ) { - _objc_z = malloc_default_zone(); + static void *_objc_z = (void *)0xffffffff; + if ( _objc_z == (void *)0xffffffff ) { + char *s = getenv("OBJC_USE_OBJC_ZONE"); + if ( s ) { + if ( (*s == '1') || (*s == 'y') || (*s == 'Y') ) { + _objc_z = malloc_create_zone(vm_page_size, 0); + malloc_set_zone_name(_objc_z, "ObjC"); } - } - return _objc_z; + } + if ( _objc_z == (void *)0xffffffff ) { + _objc_z = malloc_default_zone(); + } + } + return _objc_z; } /*********************************************************************** - * cache collection. - **********************************************************************/ +* cache collection. +**********************************************************************/ #ifdef OBJC_COLLECTING_CACHE static unsigned long _get_pc_for_thread (mach_port_t thread) #ifdef hppa { - struct hp_pa_frame_thread_state state; - unsigned int count = HPPA_FRAME_THREAD_STATE_COUNT; - thread_get_state (thread, HPPA_FRAME_THREAD_STATE, (thread_state_t)&state, &count); - return state.ts_pcoq_front; + struct hp_pa_frame_thread_state state; + unsigned int count = HPPA_FRAME_THREAD_STATE_COUNT; + thread_get_state (thread, HPPA_FRAME_THREAD_STATE, (thread_state_t)&state, &count); + return state.ts_pcoq_front; } #elif defined(sparc) { - struct sparc_thread_state_regs state; - unsigned int count = SPARC_THREAD_STATE_REGS_COUNT; - thread_get_state (thread, SPARC_THREAD_STATE_REGS, (thread_state_t)&state, &count); - return state.regs.r_pc; + struct sparc_thread_state_regs state; + unsigned int count = SPARC_THREAD_STATE_REGS_COUNT; + thread_get_state (thread, SPARC_THREAD_STATE_REGS, (thread_state_t)&state, &count); + return state.regs.r_pc; } #elif defined(__i386__) || defined(i386) { - i386_thread_state_t state; - unsigned int count = i386_THREAD_STATE_COUNT; - thread_get_state (thread, i386_THREAD_STATE, (thread_state_t)&state, &count); - return state.eip; + i386_thread_state_t state; + unsigned int count = i386_THREAD_STATE_COUNT; + thread_get_state (thread, i386_THREAD_STATE, (thread_state_t)&state, &count); + return state.eip; } #elif defined(m68k) { - struct m68k_thread_state_regs state; - unsigned int count = M68K_THREAD_STATE_REGS_COUNT; - thread_get_state (thread, M68K_THREAD_STATE_REGS, (thread_state_t)&state, &count); - return state.pc; + struct m68k_thread_state_regs state; + unsigned int count = M68K_THREAD_STATE_REGS_COUNT; + thread_get_state (thread, M68K_THREAD_STATE_REGS, (thread_state_t)&state, &count); + return state.pc; } #elif defined(__ppc__) || defined(ppc) { - struct ppc_thread_state state; - unsigned int count = PPC_THREAD_STATE_COUNT; - thread_get_state (thread, PPC_THREAD_STATE, (thread_state_t)&state, &count); - return state.srr0; -} + struct ppc_thread_state state; + unsigned int count = PPC_THREAD_STATE_COUNT; + thread_get_state (thread, PPC_THREAD_STATE, (thread_state_t)&state, &count); + return state.srr0; +} #else { - #error _get_pc_for_thread () not implemented for this architecture +#error _get_pc_for_thread () not implemented for this architecture } #endif /*********************************************************************** - * _collecting_in_critical. - **********************************************************************/ +* _collecting_in_critical. +**********************************************************************/ OBJC_EXPORT unsigned long objc_entryPoints[]; OBJC_EXPORT unsigned long objc_exitPoints[]; static int _collecting_in_critical (void) { - thread_act_port_array_t threads; - unsigned number; - unsigned count; - kern_return_t ret; - int result; - mach_port_t mythread = pthread_mach_thread_np(pthread_self()); - - // Get a list of all the threads in the current task - ret = task_threads (mach_task_self (), &threads, &number); - if (ret != KERN_SUCCESS) - { - _objc_inform ("objc: task_thread failed\n"); - exit (1); - } - - // Check whether any thread is in the cache lookup code - result = 0; - for (count = 0; !result && (count < number); count += 1) - { - int region; - unsigned long pc; - - // Don't bother checking ourselves - if (threads[count] == mythread) - continue; - - // Find out where thread is executing - pc = _get_pc_for_thread (threads[count]); - - // Check whether it is in the cache lookup code - for (region = 0; !result && (objc_entryPoints[region] != 0); region += 1) - { - if ((pc >= objc_entryPoints[region]) && - (pc <= objc_exitPoints[region])) - result = 1; - } - } - // Deallocate the port rights for the threads - for (count = 0; count < number; count++) { - mach_port_deallocate(mach_task_self (), threads[count]); - } - - // Deallocate the thread list - vm_deallocate (mach_task_self (), (vm_address_t) threads, sizeof(threads) * number); - - // Return our finding - return result; -} - -/*********************************************************************** - * _garbage_make_room. Ensure that there is enough room for at least - * one more ref in the garbage. - **********************************************************************/ + thread_act_port_array_t threads; + unsigned number; + unsigned count; + kern_return_t ret; + int result; + mach_port_t mythread = pthread_mach_thread_np(pthread_self()); + + // Get a list of all the threads in the current task + ret = task_threads (mach_task_self (), &threads, &number); + if (ret != KERN_SUCCESS) + { + _objc_inform ("objc: task_thread failed\n"); + exit (1); + } + + // Check whether any thread is in the cache lookup code + result = 0; + for (count = 0; !result && (count < number); count += 1) + { + int region; + unsigned long pc; + + // Don't bother checking ourselves + if (threads[count] == mythread) + continue; + + // Find out where thread is executing + pc = _get_pc_for_thread (threads[count]); + + // Check whether it is in the cache lookup code + for (region = 0; !result && (objc_entryPoints[region] != 0); region += 1) + { + if ((pc >= objc_entryPoints[region]) && + (pc <= objc_exitPoints[region])) + result = 1; + } + } + // Deallocate the port rights for the threads + for (count = 0; count < number; count++) { + mach_port_deallocate(mach_task_self (), threads[count]); + } + + // Deallocate the thread list + vm_deallocate (mach_task_self (), (vm_address_t) threads, sizeof(threads) * number); + + // Return our finding + return result; +} + +/*********************************************************************** +* _garbage_make_room. Ensure that there is enough room for at least +* one more ref in the garbage. +**********************************************************************/ // amount of memory represented by all refs in the garbage static int garbage_byte_size = 0; @@ -2534,716 +2531,716 @@ static int garbage_max = 0; // capacity of initial garbage_refs enum { - INIT_GARBAGE_COUNT = 128 + INIT_GARBAGE_COUNT = 128 }; static void _garbage_make_room (void) { - static int first = 1; - volatile void * tempGarbage; - - // Create the collection table the first time it is needed - if (first) - { - first = 0; - garbage_refs = malloc_zone_malloc (_objc_create_zone(), - INIT_GARBAGE_COUNT * sizeof(void *)); - garbage_max = INIT_GARBAGE_COUNT; - } - - // Double the table if it is full - else if (garbage_count == garbage_max) - { - tempGarbage = malloc_zone_realloc ((void *) _objc_create_zone(), - (void *) garbage_refs, - (size_t) garbage_max * 2 * sizeof(void *)); - garbage_refs = (void **) tempGarbage; - garbage_max *= 2; - } -} - -/*********************************************************************** - * _cache_collect_free. Add the specified malloc'd memory to the list - * of them to free at some later point. - **********************************************************************/ + static int first = 1; + volatile void * tempGarbage; + + // Create the collection table the first time it is needed + if (first) + { + first = 0; + garbage_refs = malloc_zone_malloc (_objc_create_zone(), + INIT_GARBAGE_COUNT * sizeof(void *)); + garbage_max = INIT_GARBAGE_COUNT; + } + + // Double the table if it is full + else if (garbage_count == garbage_max) + { + tempGarbage = malloc_zone_realloc ((void *) _objc_create_zone(), + (void *) garbage_refs, + (size_t) garbage_max * 2 * sizeof(void *)); + garbage_refs = (void **) tempGarbage; + garbage_max *= 2; + } +} + +/*********************************************************************** +* _cache_collect_free. Add the specified malloc'd memory to the list +* of them to free at some later point. +**********************************************************************/ static void _cache_collect_free (void * data, - BOOL tryCollect) -{ - static char *report_garbage = (char *)0xffffffff; - - if ((char *)0xffffffff == report_garbage) { - // Check whether to log our activity - report_garbage = getenv ("OBJC_REPORT_GARBAGE"); - } - - // Synchronize - OBJC_LOCK(&cacheCollectionLock); - - // Insert new element in garbage list - // Note that we do this even if we end up free'ing everything - _garbage_make_room (); - garbage_byte_size += malloc_size (data); - garbage_refs[garbage_count++] = data; - - // Log our progress - if (tryCollect && report_garbage) - _objc_inform ("total of %d bytes of garbage ...", garbage_byte_size); - - // Done if caller says not to empty or the garbage is not full - if (!tryCollect || (garbage_byte_size < garbage_threshold)) - { - OBJC_UNLOCK(&cacheCollectionLock); - if (tryCollect && report_garbage) - _objc_inform ("below threshold\n"); - - return; - } - - // Synchronize garbage collection with messageLock holders - if (OBJC_TRYLOCK(&messageLock)) - { - // Synchronize garbage collection with cache lookers - if (!_collecting_in_critical ()) - { - // Log our progress - if (tryCollect && report_garbage) - _objc_inform ("collecting!\n"); - - // Dispose all refs now in the garbage - while (garbage_count) - free (garbage_refs[--garbage_count]); - - // Clear the total size indicator - garbage_byte_size = 0; - } - - // Someone is actively looking in the cache - else if (tryCollect && report_garbage) - _objc_inform ("in critical region\n"); - - OBJC_UNLOCK(&messageLock); - } - - // Someone already holds messageLock - else if (tryCollect && report_garbage) - _objc_inform ("messageLock taken\n"); - - OBJC_UNLOCK(&cacheCollectionLock); + BOOL tryCollect) +{ + static char *report_garbage = (char *)0xffffffff; + + if ((char *)0xffffffff == report_garbage) { + // Check whether to log our activity + report_garbage = getenv ("OBJC_REPORT_GARBAGE"); + } + + // Synchronize + OBJC_LOCK(&cacheCollectionLock); + + // Insert new element in garbage list + // Note that we do this even if we end up free'ing everything + _garbage_make_room (); + garbage_byte_size += malloc_size (data); + garbage_refs[garbage_count++] = data; + + // Log our progress + if (tryCollect && report_garbage) + _objc_inform ("total of %d bytes of garbage ...", garbage_byte_size); + + // Done if caller says not to empty or the garbage is not full + if (!tryCollect || (garbage_byte_size < garbage_threshold)) + { + OBJC_UNLOCK(&cacheCollectionLock); + if (tryCollect && report_garbage) + _objc_inform ("below threshold\n"); + + return; + } + + // Synchronize garbage collection with messageLock holders + if (OBJC_TRYLOCK(&messageLock)) + { + // Synchronize garbage collection with cache lookers + if (!_collecting_in_critical ()) + { + // Log our progress + if (tryCollect && report_garbage) + _objc_inform ("collecting!\n"); + + // Dispose all refs now in the garbage + while (garbage_count) + free (garbage_refs[--garbage_count]); + + // Clear the total size indicator + garbage_byte_size = 0; + } + + // Someone is actively looking in the cache + else if (tryCollect && report_garbage) + _objc_inform ("in critical region\n"); + + OBJC_UNLOCK(&messageLock); + } + + // Someone already holds messageLock + else if (tryCollect && report_garbage) + _objc_inform ("messageLock taken\n"); + + OBJC_UNLOCK(&cacheCollectionLock); } #endif // OBJC_COLLECTING_CACHE /*********************************************************************** - * _cache_print. - **********************************************************************/ +* _cache_print. +**********************************************************************/ static void _cache_print (Cache cache) { - unsigned int index; - unsigned int count; - - count = cache->mask + 1; - for (index = 0; index < count; index += 1) - if (CACHE_BUCKET_VALID(cache->buckets[index])) - { - if (CACHE_BUCKET_IMP(cache->buckets[index]) == &_objc_msgForward) - printf ("does not recognize: \n"); - printf ("%s\n", (const char *) CACHE_BUCKET_NAME(cache->buckets[index])); - } + unsigned int index; + unsigned int count; + + count = cache->mask + 1; + for (index = 0; index < count; index += 1) + if (CACHE_BUCKET_VALID(cache->buckets[index])) + { + if (CACHE_BUCKET_IMP(cache->buckets[index]) == &_objc_msgForward) + printf ("does not recognize: \n"); + printf ("%s\n", (const char *) CACHE_BUCKET_NAME(cache->buckets[index])); + } } /*********************************************************************** - * _class_printMethodCaches. - **********************************************************************/ +* _class_printMethodCaches. +**********************************************************************/ void _class_printMethodCaches (Class cls) { - if (((struct objc_class *)cls)->cache == &emptyCache) - printf ("no instance-method cache for class %s\n", ((struct objc_class *)cls)->name); - - else - { - printf ("instance-method cache for class %s:\n", ((struct objc_class *)cls)->name); - _cache_print (((struct objc_class *)cls)->cache); - } - - if (((struct objc_class * )((struct objc_class * )cls)->isa)->cache == &emptyCache) - printf ("no class-method cache for class %s\n", ((struct objc_class *)cls)->name); - - else - { - printf ("class-method cache for class %s:\n", ((struct objc_class *)cls)->name); - _cache_print (((struct objc_class * )((struct objc_class * )cls)->isa)->cache); - } -} - -/*********************************************************************** - * log2. - **********************************************************************/ + if (((struct objc_class *)cls)->cache == &emptyCache) + printf ("no instance-method cache for class %s\n", ((struct objc_class *)cls)->name); + + else + { + printf ("instance-method cache for class %s:\n", ((struct objc_class *)cls)->name); + _cache_print (((struct objc_class *)cls)->cache); + } + + if (((struct objc_class * )((struct objc_class * )cls)->isa)->cache == &emptyCache) + printf ("no class-method cache for class %s\n", ((struct objc_class *)cls)->name); + + else + { + printf ("class-method cache for class %s:\n", ((struct objc_class *)cls)->name); + _cache_print (((struct objc_class * )((struct objc_class * )cls)->isa)->cache); + } +} + +/*********************************************************************** +* log2. +**********************************************************************/ static unsigned int log2 (unsigned int x) { - unsigned int log; - - log = 0; - while (x >>= 1) - log += 1; - - return log; -} - -/*********************************************************************** - * _class_printDuplicateCacheEntries. - **********************************************************************/ -void _class_printDuplicateCacheEntries (BOOL detail) -{ - NXHashTable * class_hash; - NXHashState state; - struct objc_class * cls; - unsigned int duplicates; - unsigned int index1; - unsigned int index2; - unsigned int mask; - unsigned int count; - unsigned int isMeta; - Cache cache; - - - printf ("Checking for duplicate cache entries \n"); - - // Outermost loop - iterate over all classes - class_hash = objc_getClasses (); - state = NXInitHashState (class_hash); - duplicates = 0; - while (NXNextHashState (class_hash, &state, (void **) &cls)) - { - // Control loop - do given class' cache, then its isa's cache - for (isMeta = 0; isMeta <= 1; isMeta += 1) - { - // Select cache of interest and make sure it exists - cache = isMeta ? cls->isa->cache : ((struct objc_class *)cls)->cache; - if (cache == &emptyCache) - continue; - - // Middle loop - check each entry in the given cache - mask = cache->mask; - count = mask + 1; - for (index1 = 0; index1 < count; index1 += 1) - { - // Skip invalid entry - if (!CACHE_BUCKET_VALID(cache->buckets[index1])) - continue; - - // Inner loop - check that given entry matches no later entry - for (index2 = index1 + 1; index2 < count; index2 += 1) - { - // Skip invalid entry - if (!CACHE_BUCKET_VALID(cache->buckets[index2])) - continue; - - // Check for duplication by method name comparison - if (strcmp ((char *) CACHE_BUCKET_NAME(cache->buckets[index1]), - (char *) CACHE_BUCKET_NAME(cache->buckets[index2])) == 0) - { - if (detail) - printf ("%s %s\n", ((struct objc_class *)cls)->name, (char *) CACHE_BUCKET_NAME(cache->buckets[index1])); - duplicates += 1; - break; - } - } - } - } - } - - // Log the findings - printf ("duplicates = %d\n", duplicates); - printf ("total cache fills = %d\n", totalCacheFills); -} - -/*********************************************************************** - * PrintCacheHeader. - **********************************************************************/ + unsigned int log; + + log = 0; + while (x >>= 1) + log += 1; + + return log; +} + +/*********************************************************************** +* _class_printDuplicateCacheEntries. +**********************************************************************/ +void _class_printDuplicateCacheEntries (BOOL detail) +{ + NXHashTable * class_hash; + NXHashState state; + struct objc_class * cls; + unsigned int duplicates; + unsigned int index1; + unsigned int index2; + unsigned int mask; + unsigned int count; + unsigned int isMeta; + Cache cache; + + + printf ("Checking for duplicate cache entries \n"); + + // Outermost loop - iterate over all classes + class_hash = objc_getClasses (); + state = NXInitHashState (class_hash); + duplicates = 0; + while (NXNextHashState (class_hash, &state, (void **) &cls)) + { + // Control loop - do given class' cache, then its isa's cache + for (isMeta = 0; isMeta <= 1; isMeta += 1) + { + // Select cache of interest and make sure it exists + cache = isMeta ? cls->isa->cache : ((struct objc_class *)cls)->cache; + if (cache == &emptyCache) + continue; + + // Middle loop - check each entry in the given cache + mask = cache->mask; + count = mask + 1; + for (index1 = 0; index1 < count; index1 += 1) + { + // Skip invalid entry + if (!CACHE_BUCKET_VALID(cache->buckets[index1])) + continue; + + // Inner loop - check that given entry matches no later entry + for (index2 = index1 + 1; index2 < count; index2 += 1) + { + // Skip invalid entry + if (!CACHE_BUCKET_VALID(cache->buckets[index2])) + continue; + + // Check for duplication by method name comparison + if (strcmp ((char *) CACHE_BUCKET_NAME(cache->buckets[index1]), + (char *) CACHE_BUCKET_NAME(cache->buckets[index2])) == 0) + { + if (detail) + printf ("%s %s\n", ((struct objc_class *)cls)->name, (char *) CACHE_BUCKET_NAME(cache->buckets[index1])); + duplicates += 1; + break; + } + } + } + } + } + + // Log the findings + printf ("duplicates = %d\n", duplicates); + printf ("total cache fills = %d\n", totalCacheFills); +} + +/*********************************************************************** +* PrintCacheHeader. +**********************************************************************/ static void PrintCacheHeader (void) { #ifdef OBJC_INSTRUMENTED - printf ("Cache Cache Slots Avg Max AvgS MaxS AvgS MaxS TotalD AvgD MaxD TotalD AvgD MaxD TotD AvgD MaxD\n"); - printf ("Size Count Used Used Used Hit Hit Miss Miss Hits Prbs Prbs Misses Prbs Prbs Flsh Flsh Flsh\n"); - printf ("----- ----- ----- ----- ---- ---- ---- ---- ---- ------- ---- ---- ------- ---- ---- ---- ---- ----\n"); + printf ("Cache Cache Slots Avg Max AvgS MaxS AvgS MaxS TotalD AvgD MaxD TotalD AvgD MaxD TotD AvgD MaxD\n"); + printf ("Size Count Used Used Used Hit Hit Miss Miss Hits Prbs Prbs Misses Prbs Prbs Flsh Flsh Flsh\n"); + printf ("----- ----- ----- ----- ---- ---- ---- ---- ---- ------- ---- ---- ------- ---- ---- ---- ---- ----\n"); #else - printf ("Cache Cache Slots Avg Max AvgS MaxS AvgS MaxS\n"); - printf ("Size Count Used Used Used Hit Hit Miss Miss\n"); - printf ("----- ----- ----- ----- ---- ---- ---- ---- ----\n"); + printf ("Cache Cache Slots Avg Max AvgS MaxS AvgS MaxS\n"); + printf ("Size Count Used Used Used Hit Hit Miss Miss\n"); + printf ("----- ----- ----- ----- ---- ---- ---- ---- ----\n"); #endif } /*********************************************************************** - * PrintCacheInfo. - **********************************************************************/ +* PrintCacheInfo. +**********************************************************************/ static void PrintCacheInfo (unsigned int cacheSize, - unsigned int cacheCount, - unsigned int slotsUsed, - float avgUsed, - unsigned int maxUsed, - float avgSHit, - unsigned int maxSHit, - float avgSMiss, - unsigned int maxSMiss + unsigned int cacheCount, + unsigned int slotsUsed, + float avgUsed, + unsigned int maxUsed, + float avgSHit, + unsigned int maxSHit, + float avgSMiss, + unsigned int maxSMiss #ifdef OBJC_INSTRUMENTED - , unsigned int totDHits, - float avgDHit, - unsigned int maxDHit, - unsigned int totDMisses, - float avgDMiss, - unsigned int maxDMiss, - unsigned int totDFlsh, - float avgDFlsh, - unsigned int maxDFlsh + , unsigned int totDHits, + float avgDHit, + unsigned int maxDHit, + unsigned int totDMisses, + float avgDMiss, + unsigned int maxDMiss, + unsigned int totDFlsh, + float avgDFlsh, + unsigned int maxDFlsh #endif - ) + ) { #ifdef OBJC_INSTRUMENTED - printf ("%5u %5u %5u %5.1f %4u %4.1f %4u %4.1f %4u %7u %4.1f %4u %7u %4.1f %4u %4u %4.1f %4u\n", + printf ("%5u %5u %5u %5.1f %4u %4.1f %4u %4.1f %4u %7u %4.1f %4u %7u %4.1f %4u %4u %4.1f %4u\n", #else - printf ("%5u %5u %5u %5.1f %4u %4.1f %4u %4.1f %4u\n", + printf ("%5u %5u %5u %5.1f %4u %4.1f %4u %4.1f %4u\n", #endif - cacheSize, cacheCount, slotsUsed, avgUsed, maxUsed, avgSHit, maxSHit, avgSMiss, maxSMiss + cacheSize, cacheCount, slotsUsed, avgUsed, maxUsed, avgSHit, maxSHit, avgSMiss, maxSMiss #ifdef OBJC_INSTRUMENTED - , totDHits, avgDHit, maxDHit, totDMisses, avgDMiss, maxDMiss, totDFlsh, avgDFlsh, maxDFlsh + , totDHits, avgDHit, maxDHit, totDMisses, avgDMiss, maxDMiss, totDFlsh, avgDFlsh, maxDFlsh #endif - ); - + ); + } #ifdef OBJC_INSTRUMENTED /*********************************************************************** - * PrintCacheHistogram. Show the non-zero entries from the specified - * cache histogram. - **********************************************************************/ +* PrintCacheHistogram. Show the non-zero entries from the specified +* cache histogram. +**********************************************************************/ static void PrintCacheHistogram (char * title, - unsigned int * firstEntry, - unsigned int entryCount) -{ - unsigned int index; - unsigned int * thisEntry; - - printf ("%s\n", title); - printf (" Probes Tally\n"); - printf (" ------ -----\n"); - for (index = 0, thisEntry = firstEntry; - index < entryCount; - index += 1, thisEntry += 1) - { - if (*thisEntry == 0) - continue; - - printf (" %6d %5d\n", index, *thisEntry); - } + unsigned int * firstEntry, + unsigned int entryCount) +{ + unsigned int index; + unsigned int * thisEntry; + + printf ("%s\n", title); + printf (" Probes Tally\n"); + printf (" ------ -----\n"); + for (index = 0, thisEntry = firstEntry; + index < entryCount; + index += 1, thisEntry += 1) + { + if (*thisEntry == 0) + continue; + + printf (" %6d %5d\n", index, *thisEntry); + } } #endif /*********************************************************************** - * _class_printMethodCacheStatistics. - **********************************************************************/ +* _class_printMethodCacheStatistics. +**********************************************************************/ #define MAX_LOG2_SIZE 32 #define MAX_CHAIN_SIZE 100 void _class_printMethodCacheStatistics (void) { - unsigned int isMeta; - unsigned int index; - NXHashTable * class_hash; - NXHashState state; - struct objc_class * cls; - unsigned int totalChain; - unsigned int totalMissChain; - unsigned int maxChain; - unsigned int maxMissChain; - unsigned int classCount; - unsigned int negativeEntryCount; - unsigned int cacheExpandCount; - unsigned int cacheCountBySize[2][MAX_LOG2_SIZE] = {{0}}; - unsigned int totalEntriesBySize[2][MAX_LOG2_SIZE] = {{0}}; - unsigned int maxEntriesBySize[2][MAX_LOG2_SIZE] = {{0}}; - unsigned int totalChainBySize[2][MAX_LOG2_SIZE] = {{0}}; - unsigned int totalMissChainBySize[2][MAX_LOG2_SIZE] = {{0}}; - unsigned int totalMaxChainBySize[2][MAX_LOG2_SIZE] = {{0}}; - unsigned int totalMaxMissChainBySize[2][MAX_LOG2_SIZE] = {{0}}; - unsigned int maxChainBySize[2][MAX_LOG2_SIZE] = {{0}}; - unsigned int maxMissChainBySize[2][MAX_LOG2_SIZE] = {{0}}; - unsigned int chainCount[MAX_CHAIN_SIZE] = {0}; - unsigned int missChainCount[MAX_CHAIN_SIZE] = {0}; + unsigned int isMeta; + unsigned int index; + NXHashTable * class_hash; + NXHashState state; + struct objc_class * cls; + unsigned int totalChain; + unsigned int totalMissChain; + unsigned int maxChain; + unsigned int maxMissChain; + unsigned int classCount; + unsigned int negativeEntryCount; + unsigned int cacheExpandCount; + unsigned int cacheCountBySize[2][MAX_LOG2_SIZE] = {{0}}; + unsigned int totalEntriesBySize[2][MAX_LOG2_SIZE] = {{0}}; + unsigned int maxEntriesBySize[2][MAX_LOG2_SIZE] = {{0}}; + unsigned int totalChainBySize[2][MAX_LOG2_SIZE] = {{0}}; + unsigned int totalMissChainBySize[2][MAX_LOG2_SIZE] = {{0}}; + unsigned int totalMaxChainBySize[2][MAX_LOG2_SIZE] = {{0}}; + unsigned int totalMaxMissChainBySize[2][MAX_LOG2_SIZE] = {{0}}; + unsigned int maxChainBySize[2][MAX_LOG2_SIZE] = {{0}}; + unsigned int maxMissChainBySize[2][MAX_LOG2_SIZE] = {{0}}; + unsigned int chainCount[MAX_CHAIN_SIZE] = {0}; + unsigned int missChainCount[MAX_CHAIN_SIZE] = {0}; #ifdef OBJC_INSTRUMENTED - unsigned int hitCountBySize[2][MAX_LOG2_SIZE] = {{0}}; - unsigned int hitProbesBySize[2][MAX_LOG2_SIZE] = {{0}}; - unsigned int maxHitProbesBySize[2][MAX_LOG2_SIZE] = {{0}}; - unsigned int missCountBySize[2][MAX_LOG2_SIZE] = {{0}}; - unsigned int missProbesBySize[2][MAX_LOG2_SIZE] = {{0}}; - unsigned int maxMissProbesBySize[2][MAX_LOG2_SIZE] = {{0}}; - unsigned int flushCountBySize[2][MAX_LOG2_SIZE] = {{0}}; - unsigned int flushedEntriesBySize[2][MAX_LOG2_SIZE] = {{0}}; - unsigned int maxFlushedEntriesBySize[2][MAX_LOG2_SIZE] = {{0}}; + unsigned int hitCountBySize[2][MAX_LOG2_SIZE] = {{0}}; + unsigned int hitProbesBySize[2][MAX_LOG2_SIZE] = {{0}}; + unsigned int maxHitProbesBySize[2][MAX_LOG2_SIZE] = {{0}}; + unsigned int missCountBySize[2][MAX_LOG2_SIZE] = {{0}}; + unsigned int missProbesBySize[2][MAX_LOG2_SIZE] = {{0}}; + unsigned int maxMissProbesBySize[2][MAX_LOG2_SIZE] = {{0}}; + unsigned int flushCountBySize[2][MAX_LOG2_SIZE] = {{0}}; + unsigned int flushedEntriesBySize[2][MAX_LOG2_SIZE] = {{0}}; + unsigned int maxFlushedEntriesBySize[2][MAX_LOG2_SIZE] = {{0}}; #endif - printf ("Printing cache statistics\n"); - - // Outermost loop - iterate over all classes - class_hash = objc_getClasses (); - state = NXInitHashState (class_hash); - classCount = 0; - negativeEntryCount = 0; - cacheExpandCount = 0; - while (NXNextHashState (class_hash, &state, (void **) &cls)) - { - // Tally classes - classCount += 1; - - // Control loop - do given class' cache, then its isa's cache - for (isMeta = 0; isMeta <= 1; isMeta += 1) - { - Cache cache; - unsigned int mask; - unsigned int log2Size; - unsigned int entryCount; - - // Select cache of interest - cache = isMeta ? cls->isa->cache : ((struct objc_class *)cls)->cache; - - // Ignore empty cache... should we? - if (cache == &emptyCache) - continue; - - // Middle loop - do each entry in the given cache - mask = cache->mask; - entryCount = 0; - totalChain = 0; - totalMissChain = 0; - maxChain = 0; - maxMissChain = 0; - for (index = 0; index < mask + 1; index += 1) - { - Method * buckets; - Method method; - uarith_t hash; - uarith_t methodChain; - uarith_t methodMissChain; - uarith_t index2; - - // If entry is invalid, the only item of - // interest is that future insert hashes - // to this entry can use it directly. - buckets = cache->buckets; - if (!CACHE_BUCKET_VALID(buckets[index])) - { - missChainCount[0] += 1; - continue; - } - - method = buckets[index]; - - // Tally valid entries - entryCount += 1; - - // Tally "forward::" entries - if (CACHE_BUCKET_IMP(method) == &_objc_msgForward) - negativeEntryCount += 1; - - // Calculate search distance (chain length) for this method - hash = (uarith_t) CACHE_BUCKET_NAME(method); - methodChain = ((index - hash) & mask); - - // Tally chains of this length - if (methodChain < MAX_CHAIN_SIZE) - chainCount[methodChain] += 1; - - // Keep sum of all chain lengths - totalChain += methodChain; - - // Record greatest chain length - if (methodChain > maxChain) - maxChain = methodChain; - - // Calculate search distance for miss that hashes here - index2 = index; - while (CACHE_BUCKET_VALID(buckets[index2])) - { - index2 += 1; - index2 &= mask; - } - methodMissChain = ((index2 - index) & mask); - - // Tally miss chains of this length - if (methodMissChain < MAX_CHAIN_SIZE) - missChainCount[methodMissChain] += 1; - - // Keep sum of all miss chain lengths in this class - totalMissChain += methodMissChain; - - // Record greatest miss chain length - if (methodMissChain > maxMissChain) - maxMissChain = methodMissChain; - } - - // Factor this cache into statistics about caches of the same - // type and size (all caches are a power of two in size) - log2Size = log2 (mask + 1); - cacheCountBySize[isMeta][log2Size] += 1; - totalEntriesBySize[isMeta][log2Size] += entryCount; - if (entryCount > maxEntriesBySize[isMeta][log2Size]) - maxEntriesBySize[isMeta][log2Size] = entryCount; - totalChainBySize[isMeta][log2Size] += totalChain; - totalMissChainBySize[isMeta][log2Size] += totalMissChain; - totalMaxChainBySize[isMeta][log2Size] += maxChain; - totalMaxMissChainBySize[isMeta][log2Size] += maxMissChain; - if (maxChain > maxChainBySize[isMeta][log2Size]) - maxChainBySize[isMeta][log2Size] = maxChain; - if (maxMissChain > maxMissChainBySize[isMeta][log2Size]) - maxMissChainBySize[isMeta][log2Size] = maxMissChain; + printf ("Printing cache statistics\n"); + + // Outermost loop - iterate over all classes + class_hash = objc_getClasses (); + state = NXInitHashState (class_hash); + classCount = 0; + negativeEntryCount = 0; + cacheExpandCount = 0; + while (NXNextHashState (class_hash, &state, (void **) &cls)) + { + // Tally classes + classCount += 1; + + // Control loop - do given class' cache, then its isa's cache + for (isMeta = 0; isMeta <= 1; isMeta += 1) + { + Cache cache; + unsigned int mask; + unsigned int log2Size; + unsigned int entryCount; + + // Select cache of interest + cache = isMeta ? cls->isa->cache : ((struct objc_class *)cls)->cache; + + // Ignore empty cache... should we? + if (cache == &emptyCache) + continue; + + // Middle loop - do each entry in the given cache + mask = cache->mask; + entryCount = 0; + totalChain = 0; + totalMissChain = 0; + maxChain = 0; + maxMissChain = 0; + for (index = 0; index < mask + 1; index += 1) + { + Method * buckets; + Method method; + uarith_t hash; + uarith_t methodChain; + uarith_t methodMissChain; + uarith_t index2; + + // If entry is invalid, the only item of + // interest is that future insert hashes + // to this entry can use it directly. + buckets = cache->buckets; + if (!CACHE_BUCKET_VALID(buckets[index])) + { + missChainCount[0] += 1; + continue; + } + + method = buckets[index]; + + // Tally valid entries + entryCount += 1; + + // Tally "forward::" entries + if (CACHE_BUCKET_IMP(method) == &_objc_msgForward) + negativeEntryCount += 1; + + // Calculate search distance (chain length) for this method + hash = (uarith_t) CACHE_BUCKET_NAME(method); + methodChain = ((index - hash) & mask); + + // Tally chains of this length + if (methodChain < MAX_CHAIN_SIZE) + chainCount[methodChain] += 1; + + // Keep sum of all chain lengths + totalChain += methodChain; + + // Record greatest chain length + if (methodChain > maxChain) + maxChain = methodChain; + + // Calculate search distance for miss that hashes here + index2 = index; + while (CACHE_BUCKET_VALID(buckets[index2])) + { + index2 += 1; + index2 &= mask; + } + methodMissChain = ((index2 - index) & mask); + + // Tally miss chains of this length + if (methodMissChain < MAX_CHAIN_SIZE) + missChainCount[methodMissChain] += 1; + + // Keep sum of all miss chain lengths in this class + totalMissChain += methodMissChain; + + // Record greatest miss chain length + if (methodMissChain > maxMissChain) + maxMissChain = methodMissChain; + } + + // Factor this cache into statistics about caches of the same + // type and size (all caches are a power of two in size) + log2Size = log2 (mask + 1); + cacheCountBySize[isMeta][log2Size] += 1; + totalEntriesBySize[isMeta][log2Size] += entryCount; + if (entryCount > maxEntriesBySize[isMeta][log2Size]) + maxEntriesBySize[isMeta][log2Size] = entryCount; + totalChainBySize[isMeta][log2Size] += totalChain; + totalMissChainBySize[isMeta][log2Size] += totalMissChain; + totalMaxChainBySize[isMeta][log2Size] += maxChain; + totalMaxMissChainBySize[isMeta][log2Size] += maxMissChain; + if (maxChain > maxChainBySize[isMeta][log2Size]) + maxChainBySize[isMeta][log2Size] = maxChain; + if (maxMissChain > maxMissChainBySize[isMeta][log2Size]) + maxMissChainBySize[isMeta][log2Size] = maxMissChain; #ifdef OBJC_INSTRUMENTED - { - CacheInstrumentation * cacheData; - - cacheData = CACHE_INSTRUMENTATION(cache); - hitCountBySize[isMeta][log2Size] += cacheData->hitCount; - hitProbesBySize[isMeta][log2Size] += cacheData->hitProbes; - if (cacheData->maxHitProbes > maxHitProbesBySize[isMeta][log2Size]) - maxHitProbesBySize[isMeta][log2Size] = cacheData->maxHitProbes; - missCountBySize[isMeta][log2Size] += cacheData->missCount; - missProbesBySize[isMeta][log2Size] += cacheData->missProbes; - if (cacheData->maxMissProbes > maxMissProbesBySize[isMeta][log2Size]) - maxMissProbesBySize[isMeta][log2Size] = cacheData->maxMissProbes; - flushCountBySize[isMeta][log2Size] += cacheData->flushCount; - flushedEntriesBySize[isMeta][log2Size] += cacheData->flushedEntries; - if (cacheData->maxFlushedEntries > maxFlushedEntriesBySize[isMeta][log2Size]) - maxFlushedEntriesBySize[isMeta][log2Size] = cacheData->maxFlushedEntries; - } + { + CacheInstrumentation * cacheData; + + cacheData = CACHE_INSTRUMENTATION(cache); + hitCountBySize[isMeta][log2Size] += cacheData->hitCount; + hitProbesBySize[isMeta][log2Size] += cacheData->hitProbes; + if (cacheData->maxHitProbes > maxHitProbesBySize[isMeta][log2Size]) + maxHitProbesBySize[isMeta][log2Size] = cacheData->maxHitProbes; + missCountBySize[isMeta][log2Size] += cacheData->missCount; + missProbesBySize[isMeta][log2Size] += cacheData->missProbes; + if (cacheData->maxMissProbes > maxMissProbesBySize[isMeta][log2Size]) + maxMissProbesBySize[isMeta][log2Size] = cacheData->maxMissProbes; + flushCountBySize[isMeta][log2Size] += cacheData->flushCount; + flushedEntriesBySize[isMeta][log2Size] += cacheData->flushedEntries; + if (cacheData->maxFlushedEntries > maxFlushedEntriesBySize[isMeta][log2Size]) + maxFlushedEntriesBySize[isMeta][log2Size] = cacheData->maxFlushedEntries; + } #endif - // Caches start with a power of two number of entries, and grow by doubling, so - // we can calculate the number of times this cache has expanded - if (isMeta) - cacheExpandCount += log2Size - INIT_META_CACHE_SIZE_LOG2; - else - cacheExpandCount += log2Size - INIT_CACHE_SIZE_LOG2; - - } - } - - { - unsigned int cacheCountByType[2] = {0}; - unsigned int totalCacheCount = 0; - unsigned int totalEntries = 0; - unsigned int maxEntries = 0; - unsigned int totalSlots = 0; + // Caches start with a power of two number of entries, and grow by doubling, so + // we can calculate the number of times this cache has expanded + if (isMeta) + cacheExpandCount += log2Size - INIT_META_CACHE_SIZE_LOG2; + else + cacheExpandCount += log2Size - INIT_CACHE_SIZE_LOG2; + + } + } + + { + unsigned int cacheCountByType[2] = {0}; + unsigned int totalCacheCount = 0; + unsigned int totalEntries = 0; + unsigned int maxEntries = 0; + unsigned int totalSlots = 0; #ifdef OBJC_INSTRUMENTED - unsigned int totalHitCount = 0; - unsigned int totalHitProbes = 0; - unsigned int maxHitProbes = 0; - unsigned int totalMissCount = 0; - unsigned int totalMissProbes = 0; - unsigned int maxMissProbes = 0; - unsigned int totalFlushCount = 0; - unsigned int totalFlushedEntries = 0; - unsigned int maxFlushedEntries = 0; + unsigned int totalHitCount = 0; + unsigned int totalHitProbes = 0; + unsigned int maxHitProbes = 0; + unsigned int totalMissCount = 0; + unsigned int totalMissProbes = 0; + unsigned int maxMissProbes = 0; + unsigned int totalFlushCount = 0; + unsigned int totalFlushedEntries = 0; + unsigned int maxFlushedEntries = 0; #endif - - totalChain = 0; - maxChain = 0; - totalMissChain = 0; - maxMissChain = 0; - - // Sum information over all caches - for (isMeta = 0; isMeta <= 1; isMeta += 1) - { - for (index = 0; index < MAX_LOG2_SIZE; index += 1) - { - cacheCountByType[isMeta] += cacheCountBySize[isMeta][index]; - totalEntries += totalEntriesBySize[isMeta][index]; - totalSlots += cacheCountBySize[isMeta][index] * (1 << index); - totalChain += totalChainBySize[isMeta][index]; - if (maxEntriesBySize[isMeta][index] > maxEntries) - maxEntries = maxEntriesBySize[isMeta][index]; - if (maxChainBySize[isMeta][index] > maxChain) - maxChain = maxChainBySize[isMeta][index]; - totalMissChain += totalMissChainBySize[isMeta][index]; - if (maxMissChainBySize[isMeta][index] > maxMissChain) - maxMissChain = maxMissChainBySize[isMeta][index]; + + totalChain = 0; + maxChain = 0; + totalMissChain = 0; + maxMissChain = 0; + + // Sum information over all caches + for (isMeta = 0; isMeta <= 1; isMeta += 1) + { + for (index = 0; index < MAX_LOG2_SIZE; index += 1) + { + cacheCountByType[isMeta] += cacheCountBySize[isMeta][index]; + totalEntries += totalEntriesBySize[isMeta][index]; + totalSlots += cacheCountBySize[isMeta][index] * (1 << index); + totalChain += totalChainBySize[isMeta][index]; + if (maxEntriesBySize[isMeta][index] > maxEntries) + maxEntries = maxEntriesBySize[isMeta][index]; + if (maxChainBySize[isMeta][index] > maxChain) + maxChain = maxChainBySize[isMeta][index]; + totalMissChain += totalMissChainBySize[isMeta][index]; + if (maxMissChainBySize[isMeta][index] > maxMissChain) + maxMissChain = maxMissChainBySize[isMeta][index]; #ifdef OBJC_INSTRUMENTED - totalHitCount += hitCountBySize[isMeta][index]; - totalHitProbes += hitProbesBySize[isMeta][index]; - if (maxHitProbesBySize[isMeta][index] > maxHitProbes) - maxHitProbes = maxHitProbesBySize[isMeta][index]; - totalMissCount += missCountBySize[isMeta][index]; - totalMissProbes += missProbesBySize[isMeta][index]; - if (maxMissProbesBySize[isMeta][index] > maxMissProbes) - maxMissProbes = maxMissProbesBySize[isMeta][index]; - totalFlushCount += flushCountBySize[isMeta][index]; - totalFlushedEntries += flushedEntriesBySize[isMeta][index]; - if (maxFlushedEntriesBySize[isMeta][index] > maxFlushedEntries) - maxFlushedEntries = maxFlushedEntriesBySize[isMeta][index]; + totalHitCount += hitCountBySize[isMeta][index]; + totalHitProbes += hitProbesBySize[isMeta][index]; + if (maxHitProbesBySize[isMeta][index] > maxHitProbes) + maxHitProbes = maxHitProbesBySize[isMeta][index]; + totalMissCount += missCountBySize[isMeta][index]; + totalMissProbes += missProbesBySize[isMeta][index]; + if (maxMissProbesBySize[isMeta][index] > maxMissProbes) + maxMissProbes = maxMissProbesBySize[isMeta][index]; + totalFlushCount += flushCountBySize[isMeta][index]; + totalFlushedEntries += flushedEntriesBySize[isMeta][index]; + if (maxFlushedEntriesBySize[isMeta][index] > maxFlushedEntries) + maxFlushedEntries = maxFlushedEntriesBySize[isMeta][index]; #endif - } - - totalCacheCount += cacheCountByType[isMeta]; - } - - // Log our findings - printf ("There are %u classes\n", classCount); - - for (isMeta = 0; isMeta <= 1; isMeta += 1) - { - // Number of this type of class - printf ("\nThere are %u %s-method caches, broken down by size (slot count):\n", - cacheCountByType[isMeta], - isMeta ? "class" : "instance"); - - // Print header - PrintCacheHeader (); - - // Keep format consistent even if there are caches of this kind - if (cacheCountByType[isMeta] == 0) - { - printf ("(none)\n"); - continue; - } - - // Usage information by cache size - for (index = 0; index < MAX_LOG2_SIZE; index += 1) - { - unsigned int cacheCount; - unsigned int cacheSlotCount; - unsigned int cacheEntryCount; - - // Get number of caches of this type and size - cacheCount = cacheCountBySize[isMeta][index]; - if (cacheCount == 0) - continue; - - // Get the cache slot count and the total number of valid entries - cacheSlotCount = (1 << index); - cacheEntryCount = totalEntriesBySize[isMeta][index]; - - // Give the analysis - PrintCacheInfo (cacheSlotCount, - cacheCount, - cacheEntryCount, - (float) cacheEntryCount / (float) cacheCount, - maxEntriesBySize[isMeta][index], - (float) totalChainBySize[isMeta][index] / (float) cacheEntryCount, - maxChainBySize[isMeta][index], - (float) totalMissChainBySize[isMeta][index] / (float) (cacheCount * cacheSlotCount), - maxMissChainBySize[isMeta][index] + } + + totalCacheCount += cacheCountByType[isMeta]; + } + + // Log our findings + printf ("There are %u classes\n", classCount); + + for (isMeta = 0; isMeta <= 1; isMeta += 1) + { + // Number of this type of class + printf ("\nThere are %u %s-method caches, broken down by size (slot count):\n", + cacheCountByType[isMeta], + isMeta ? "class" : "instance"); + + // Print header + PrintCacheHeader (); + + // Keep format consistent even if there are caches of this kind + if (cacheCountByType[isMeta] == 0) + { + printf ("(none)\n"); + continue; + } + + // Usage information by cache size + for (index = 0; index < MAX_LOG2_SIZE; index += 1) + { + unsigned int cacheCount; + unsigned int cacheSlotCount; + unsigned int cacheEntryCount; + + // Get number of caches of this type and size + cacheCount = cacheCountBySize[isMeta][index]; + if (cacheCount == 0) + continue; + + // Get the cache slot count and the total number of valid entries + cacheSlotCount = (1 << index); + cacheEntryCount = totalEntriesBySize[isMeta][index]; + + // Give the analysis + PrintCacheInfo (cacheSlotCount, + cacheCount, + cacheEntryCount, + (float) cacheEntryCount / (float) cacheCount, + maxEntriesBySize[isMeta][index], + (float) totalChainBySize[isMeta][index] / (float) cacheEntryCount, + maxChainBySize[isMeta][index], + (float) totalMissChainBySize[isMeta][index] / (float) (cacheCount * cacheSlotCount), + maxMissChainBySize[isMeta][index] #ifdef OBJC_INSTRUMENTED - , hitCountBySize[isMeta][index], - hitCountBySize[isMeta][index] ? - (float) hitProbesBySize[isMeta][index] / (float) hitCountBySize[isMeta][index] : 0.0, - maxHitProbesBySize[isMeta][index], - missCountBySize[isMeta][index], - missCountBySize[isMeta][index] ? - (float) missProbesBySize[isMeta][index] / (float) missCountBySize[isMeta][index] : 0.0, - maxMissProbesBySize[isMeta][index], - flushCountBySize[isMeta][index], - flushCountBySize[isMeta][index] ? - (float) flushedEntriesBySize[isMeta][index] / (float) flushCountBySize[isMeta][index] : 0.0, - maxFlushedEntriesBySize[isMeta][index] + , hitCountBySize[isMeta][index], + hitCountBySize[isMeta][index] ? + (float) hitProbesBySize[isMeta][index] / (float) hitCountBySize[isMeta][index] : 0.0, + maxHitProbesBySize[isMeta][index], + missCountBySize[isMeta][index], + missCountBySize[isMeta][index] ? + (float) missProbesBySize[isMeta][index] / (float) missCountBySize[isMeta][index] : 0.0, + maxMissProbesBySize[isMeta][index], + flushCountBySize[isMeta][index], + flushCountBySize[isMeta][index] ? + (float) flushedEntriesBySize[isMeta][index] / (float) flushCountBySize[isMeta][index] : 0.0, + maxFlushedEntriesBySize[isMeta][index] #endif - ); - } - } - - // Give overall numbers - printf ("\nCumulative:\n"); - PrintCacheHeader (); - PrintCacheInfo (totalSlots, - totalCacheCount, - totalEntries, - (float) totalEntries / (float) totalCacheCount, - maxEntries, - (float) totalChain / (float) totalEntries, - maxChain, - (float) totalMissChain / (float) totalSlots, - maxMissChain + ); + } + } + + // Give overall numbers + printf ("\nCumulative:\n"); + PrintCacheHeader (); + PrintCacheInfo (totalSlots, + totalCacheCount, + totalEntries, + (float) totalEntries / (float) totalCacheCount, + maxEntries, + (float) totalChain / (float) totalEntries, + maxChain, + (float) totalMissChain / (float) totalSlots, + maxMissChain #ifdef OBJC_INSTRUMENTED - , totalHitCount, - totalHitCount ? - (float) totalHitProbes / (float) totalHitCount : 0.0, - maxHitProbes, - totalMissCount, - totalMissCount ? - (float) totalMissProbes / (float) totalMissCount : 0.0, - maxMissProbes, - totalFlushCount, - totalFlushCount ? - (float) totalFlushedEntries / (float) totalFlushCount : 0.0, - maxFlushedEntries + , totalHitCount, + totalHitCount ? + (float) totalHitProbes / (float) totalHitCount : 0.0, + maxHitProbes, + totalMissCount, + totalMissCount ? + (float) totalMissProbes / (float) totalMissCount : 0.0, + maxMissProbes, + totalFlushCount, + totalFlushCount ? + (float) totalFlushedEntries / (float) totalFlushCount : 0.0, + maxFlushedEntries #endif - ); + ); - printf ("\nNumber of \"forward::\" entries: %d\n", negativeEntryCount); - printf ("Number of cache expansions: %d\n", cacheExpandCount); + printf ("\nNumber of \"forward::\" entries: %d\n", negativeEntryCount); + printf ("Number of cache expansions: %d\n", cacheExpandCount); #ifdef OBJC_INSTRUMENTED - printf ("flush_caches: total calls total visits average visits max visits total classes visits/class\n"); - printf (" ----------- ------------ -------------- ---------- ------------- -------------\n"); - printf (" linear %11u %12u %14.1f %10u %13u %12.2f\n", - LinearFlushCachesCount, - LinearFlushCachesVisitedCount, - LinearFlushCachesCount ? - (float) LinearFlushCachesVisitedCount / (float) LinearFlushCachesCount : 0.0, - MaxLinearFlushCachesVisitedCount, - LinearFlushCachesVisitedCount, - 1.0); - printf (" nonlinear %11u %12u %14.1f %10u %13u %12.2f\n", - NonlinearFlushCachesCount, - NonlinearFlushCachesVisitedCount, - NonlinearFlushCachesCount ? - (float) NonlinearFlushCachesVisitedCount / (float) NonlinearFlushCachesCount : 0.0, - MaxNonlinearFlushCachesVisitedCount, - NonlinearFlushCachesClassCount, - NonlinearFlushCachesClassCount ? - (float) NonlinearFlushCachesVisitedCount / (float) NonlinearFlushCachesClassCount : 0.0); - printf (" ideal %11u %12u %14.1f %10u %13u %12.2f\n", - LinearFlushCachesCount + NonlinearFlushCachesCount, - IdealFlushCachesCount, - LinearFlushCachesCount + NonlinearFlushCachesCount ? - (float) IdealFlushCachesCount / (float) (LinearFlushCachesCount + NonlinearFlushCachesCount) : 0.0, - MaxIdealFlushCachesCount, - LinearFlushCachesVisitedCount + NonlinearFlushCachesClassCount, - LinearFlushCachesVisitedCount + NonlinearFlushCachesClassCount ? - (float) IdealFlushCachesCount / (float) (LinearFlushCachesVisitedCount + NonlinearFlushCachesClassCount) : 0.0); - - PrintCacheHistogram ("\nCache hit histogram:", &CacheHitHistogram[0], CACHE_HISTOGRAM_SIZE); - PrintCacheHistogram ("\nCache miss histogram:", &CacheMissHistogram[0], CACHE_HISTOGRAM_SIZE); + printf ("flush_caches: total calls total visits average visits max visits total classes visits/class\n"); + printf (" ----------- ------------ -------------- ---------- ------------- -------------\n"); + printf (" linear %11u %12u %14.1f %10u %13u %12.2f\n", + LinearFlushCachesCount, + LinearFlushCachesVisitedCount, + LinearFlushCachesCount ? + (float) LinearFlushCachesVisitedCount / (float) LinearFlushCachesCount : 0.0, + MaxLinearFlushCachesVisitedCount, + LinearFlushCachesVisitedCount, + 1.0); + printf (" nonlinear %11u %12u %14.1f %10u %13u %12.2f\n", + NonlinearFlushCachesCount, + NonlinearFlushCachesVisitedCount, + NonlinearFlushCachesCount ? + (float) NonlinearFlushCachesVisitedCount / (float) NonlinearFlushCachesCount : 0.0, + MaxNonlinearFlushCachesVisitedCount, + NonlinearFlushCachesClassCount, + NonlinearFlushCachesClassCount ? + (float) NonlinearFlushCachesVisitedCount / (float) NonlinearFlushCachesClassCount : 0.0); + printf (" ideal %11u %12u %14.1f %10u %13u %12.2f\n", + LinearFlushCachesCount + NonlinearFlushCachesCount, + IdealFlushCachesCount, + LinearFlushCachesCount + NonlinearFlushCachesCount ? + (float) IdealFlushCachesCount / (float) (LinearFlushCachesCount + NonlinearFlushCachesCount) : 0.0, + MaxIdealFlushCachesCount, + LinearFlushCachesVisitedCount + NonlinearFlushCachesClassCount, + LinearFlushCachesVisitedCount + NonlinearFlushCachesClassCount ? + (float) IdealFlushCachesCount / (float) (LinearFlushCachesVisitedCount + NonlinearFlushCachesClassCount) : 0.0); + + PrintCacheHistogram ("\nCache hit histogram:", &CacheHitHistogram[0], CACHE_HISTOGRAM_SIZE); + PrintCacheHistogram ("\nCache miss histogram:", &CacheMissHistogram[0], CACHE_HISTOGRAM_SIZE); #endif #if 0 - printf ("\nLookup chains:"); - for (index = 0; index < MAX_CHAIN_SIZE; index += 1) - { - if (chainCount[index] != 0) - printf (" %u:%u", index, chainCount[index]); - } - - printf ("\nMiss chains:"); - for (index = 0; index < MAX_CHAIN_SIZE; index += 1) - { - if (missChainCount[index] != 0) - printf (" %u:%u", index, missChainCount[index]); - } - - printf ("\nTotal memory usage for cache data structures: %lu bytes\n", - totalCacheCount * (sizeof(struct objc_cache) - sizeof(Method)) + - totalSlots * sizeof(Method) + - negativeEntryCount * sizeof(struct objc_method)); + printf ("\nLookup chains:"); + for (index = 0; index < MAX_CHAIN_SIZE; index += 1) + { + if (chainCount[index] != 0) + printf (" %u:%u", index, chainCount[index]); + } + + printf ("\nMiss chains:"); + for (index = 0; index < MAX_CHAIN_SIZE; index += 1) + { + if (missChainCount[index] != 0) + printf (" %u:%u", index, missChainCount[index]); + } + + printf ("\nTotal memory usage for cache data structures: %lu bytes\n", + totalCacheCount * (sizeof(struct objc_cache) - sizeof(Method)) + + totalSlots * sizeof(Method) + + negativeEntryCount * sizeof(struct objc_method)); #endif - } + } } /*********************************************************************** - * checkUniqueness. - **********************************************************************/ +* checkUniqueness. +**********************************************************************/ void checkUniqueness (SEL s1, - SEL s2) + SEL s2) { - if (s1 == s2) - return; - - if (s1 && s2 && (strcmp ((const char *) s1, (const char *) s2) == 0)) - _NXLogError ("%p != %p but !strcmp (%s, %s)\n", s1, s2, (char *) s1, (char *) s2); + if (s1 == s2) + return; + + if (s1 && s2 && (strcmp ((const char *) s1, (const char *) s2) == 0)) + _objc_inform ("%p != %p but !strcmp (%s, %s)\n", s1, s2, (char *) s1, (char *) s2); } diff --git a/runtime/objc-errors.m b/runtime/objc-errors.m index 0718b91..3b5d34b 100644 --- a/runtime/objc-errors.m +++ b/runtime/objc-errors.m @@ -23,40 +23,50 @@ */ /* * objc-errors.m - * Copyright 1988-1996, NeXT Software, Inc. + * Copyright 1988-2001, NeXT Software, Inc., Apple Computer, Inc. */ -/* - NXLogObjcError was snarfed from "logErrorInc.c" in the kit. - - Contains code for writing error messages to stderr or syslog. - - This code is included in errors.m in the kit, and in pbs.c - so pbs can use it also. -*/ - -#if defined(WIN32) - #import - #import - #import - #import - #import - #define syslog(a, b, c) fprintf(stderr, b, c) -#else - #import -#endif - - #if defined(NeXT_PDO) - #if !defined(WIN32) - #include // major head banging in attempt to find syslog - #import - #include // close - #endif - #import // file open flags - #endif + +#include +#include +#include +#include + #import "objc-private.h" +static int hasTerminal() +{ + static char hasTerm = -1; + + if (hasTerm == -1) { + int fd = open("/dev/tty", O_RDWR, 0); + if (fd >= 0) { + (void)close(fd); + hasTerm = 1; + } else + hasTerm = 0; + } + return hasTerm; +} +void _objc_syslog(const char *format, ...) +{ + va_list ap; + char bigBuffer[4*1024]; + + va_start(ap, format); + vsprintf(bigBuffer, format, ap); + va_end(ap); + + + if (hasTerminal()) { + fwrite(bigBuffer, sizeof(char), strlen(bigBuffer), stderr); + if (bigBuffer[strlen(bigBuffer)-1] != '\n') + fputc('\n', stderr); + } else { + syslog(LOG_ERR, "%s", bigBuffer); + } +} /* * this routine handles errors that involve an object (or class). */ @@ -82,13 +92,9 @@ volatile void _objc_error(id self, const char *fmt, va_list ap) char bigBuffer[4*1024]; vsprintf (bigBuffer, fmt, ap); - _NXLogError ("objc: %s: %s", object_getClassName (self), bigBuffer); + _objc_syslog ("objc: %s: %s", object_getClassName (self), bigBuffer); -#if defined(WIN32) - RaiseException(0xdead, EXCEPTION_NONCONTINUABLE, 0, NULL); -#else abort(); /* generates a core file */ -#endif } /* @@ -97,12 +103,8 @@ volatile void _objc_error(id self, const char *fmt, va_list ap) */ volatile void _objc_fatal(const char *msg) { - _NXLogError("objc: %s\n", msg); -#if defined(WIN32) - RaiseException(0xdead, EXCEPTION_NONCONTINUABLE, 0, NULL); -#else + _objc_syslog("objc: %s\n", msg); exit(1); -#endif } /* @@ -116,7 +118,7 @@ void _objc_inform(const char *fmt, ...) va_start (ap,fmt); vsprintf (bigBuffer, fmt, ap); - _NXLogError ("objc: %s", bigBuffer); + _objc_syslog ("objc: %s", bigBuffer); va_end (ap); } diff --git a/runtime/objc-file.m b/runtime/objc-file.m index 795b7f7..21dff7c 100644 --- a/runtime/objc-file.m +++ b/runtime/objc-file.m @@ -23,7 +23,6 @@ */ // Copyright 1988-1996 NeXT Software, Inc. -#if defined(__APPLE__) && defined(__MACH__) #import "objc-private.h" #import #import @@ -124,13 +123,8 @@ const char *_getObjcHeaderName(headerType *header) const headerType *execHeader; const struct fvmlib_command *libCmd, *endOfCmds; char **argv; -#if !defined(NeXT_PDO) extern char ***_NSGetArgv(); argv = *_NSGetArgv(); -#else - extern char **NXArgv; - argv = NXArgv; -#endif if (header && ((headerType *)header)->filetype == MH_FVMLIB) { execHeader = _getExecHeader(); @@ -154,675 +148,3 @@ const char *_getObjcHeaderName(headerType *header) } } -#elif defined(hpux) || defined(__hpux__) - -/* - * Objective-C runtime information module. - * This module is specific to hp-ux a.out format files. - */ - -#import // place where padding_bug would be -#include -#include "objc-private.h" - -OBJC_EXPORT int __argc_value; -OBJC_EXPORT char **__argv_value; -int NXArgc = 0; -char **NXArgv = NULL; - -OBJC_EXPORT unsigned SEG_OBJC_CLASS_START; -OBJC_EXPORT unsigned SEG_OBJC_METACLASS_START; -OBJC_EXPORT unsigned SEG_OBJC_CAT_CLS_METH_START; -OBJC_EXPORT unsigned SEG_OBJC_CAT_INST_METH_START; -OBJC_EXPORT unsigned SEG_OBJC_CLS_METH_START; -OBJC_EXPORT unsigned SEG_OBJC_INST_METHODS_START; -OBJC_EXPORT unsigned SEG_OBJC_MESSAGE_REFS_START; -OBJC_EXPORT unsigned SEG_OBJC_SYMBOLS_START; -OBJC_EXPORT unsigned SEG_OBJC_CATEGORY_START; -OBJC_EXPORT unsigned SEG_OBJC_PROTOCOL_START; -OBJC_EXPORT unsigned SEG_OBJC_CLASS_VARS_START; -OBJC_EXPORT unsigned SEG_OBJC_INSTANCE_VARS_START; -OBJC_EXPORT unsigned SEG_OBJC_MODULES_START; -OBJC_EXPORT unsigned SEG_OBJC_STRING_OBJECT_START; -OBJC_EXPORT unsigned SEG_OBJC_CLASS_NAMES_START; -OBJC_EXPORT unsigned SEG_OBJC_METH_VAR_NAMES_START; -OBJC_EXPORT unsigned SEG_OBJC_METH_VAR_TYPES_START; -OBJC_EXPORT unsigned SEG_OBJC_CLS_REFS_START; - -OBJC_EXPORT unsigned SEG_OBJC_CLASS_END; -OBJC_EXPORT unsigned SEG_OBJC_METACLASS_END; -OBJC_EXPORT unsigned SEG_OBJC_CAT_CLS_METH_END; -OBJC_EXPORT unsigned SEG_OBJC_CAT_INST_METH_END; -OBJC_EXPORT unsigned SEG_OBJC_CLS_METH_END; -OBJC_EXPORT unsigned SEG_OBJC_INST_METHODS_END; -OBJC_EXPORT unsigned SEG_OBJC_MESSAGE_REFS_END; -OBJC_EXPORT unsigned SEG_OBJC_SYMBOLS_END; -OBJC_EXPORT unsigned SEG_OBJC_CATEGORY_END; -OBJC_EXPORT unsigned SEG_OBJC_PROTOCOL_END; -OBJC_EXPORT unsigned SEG_OBJC_CLASS_VARS_END; -OBJC_EXPORT unsigned SEG_OBJC_INSTANCE_VARS_END; -OBJC_EXPORT unsigned SEG_OBJC_MODULES_END; -OBJC_EXPORT unsigned SEG_OBJC_STRING_OBJECT_END; -OBJC_EXPORT unsigned SEG_OBJC_CLASS_NAMES_END; -OBJC_EXPORT unsigned SEG_OBJC_METH_VAR_NAMES_END; -OBJC_EXPORT unsigned SEG_OBJC_METH_VAR_TYPES_END; -OBJC_EXPORT unsigned SEG_OBJC_CLS_REFS_END; - -typedef struct _simple_header_struct { - char * subspace_name ; - void * start_address ; - void * end_address ; - } simple_header_struct ; - -static simple_header_struct our_objc_header[] = { - { "$$OBJC_CLASS$$", &SEG_OBJC_CLASS_START, &SEG_OBJC_CLASS_END }, - { "$$OBJC_METACLASS$$", &SEG_OBJC_METACLASS_START, &SEG_OBJC_METACLASS_END }, - { "$$OBJC_CAT_CLS_METH$$", &SEG_OBJC_CAT_CLS_METH_START, &SEG_OBJC_CAT_CLS_METH_END }, - { "$$OBJC_CAT_INST_METH$$", &SEG_OBJC_CAT_INST_METH_START, &SEG_OBJC_CAT_INST_METH_END }, - { "$$OBJC_CLS_METH$$", &SEG_OBJC_CLS_METH_START, &SEG_OBJC_CLS_METH_END }, - { "$$OBJC_INST_METHODS$$", &SEG_OBJC_INST_METHODS_START, &SEG_OBJC_INST_METHODS_END }, - { "$$OBJC_MESSAGE_REFS$$", &SEG_OBJC_MESSAGE_REFS_START, &SEG_OBJC_MESSAGE_REFS_END }, - { "$$OBJC_SYMBOLS$$", &SEG_OBJC_SYMBOLS_START, &SEG_OBJC_SYMBOLS_END }, - { "$$OBJC_CATEGORY$$", &SEG_OBJC_CATEGORY_START, &SEG_OBJC_CATEGORY_END }, - { "$$OBJC_PROTOCOL$$", &SEG_OBJC_PROTOCOL_START, &SEG_OBJC_PROTOCOL_END }, - { "$$OBJC_CLASS_VARS$$", &SEG_OBJC_CLASS_VARS_START, &SEG_OBJC_CLASS_VARS_END }, - { "$$OBJC_INSTANCE_VARS$$", &SEG_OBJC_INSTANCE_VARS_START, &SEG_OBJC_INSTANCE_VARS_END }, - { "$$OBJC_MODULES$$", &SEG_OBJC_MODULES_START, &SEG_OBJC_MODULES_END }, - { "$$OBJC_STRING_OBJECT$$", &SEG_OBJC_STRING_OBJECT_START, &SEG_OBJC_STRING_OBJECT_END }, - { "$$OBJC_CLASS_NAMES$$", &SEG_OBJC_CLASS_NAMES_START, &SEG_OBJC_CLASS_NAMES_END }, - { "$$OBJC_METH_VAR_NAMES$$", &SEG_OBJC_METH_VAR_TYPES_START, &SEG_OBJC_METH_VAR_NAMES_END }, - { "$$OBJC_METH_VAR_TYPES$$", &SEG_OBJC_METH_VAR_TYPES_START, &SEG_OBJC_METH_VAR_TYPES_END }, - { "$$OBJC_CLS_REFS$$", &SEG_OBJC_CLS_REFS_START, &SEG_OBJC_CLS_REFS_END }, - { NULL, NULL, NULL } - }; - -/* Returns an array of all the objc headers in the executable (and shlibs) - * Caller is responsible for freeing. - */ -headerType **_getObjcHeaders() -{ - - /* Will need to fill in with any shlib info later as well. Need more - * info on this. - */ - - /* - * this is truly ugly, hpux does not map in the header so we have to - * try and find it and map it in. their crt0 has some global vars - * that hold argv[0] which we will use to find the executable file - */ - - headerType **hdrs = (headerType**)malloc(2 * sizeof(headerType*)); - NXArgv = __argv_value; - NXArgc = __argc_value; - hdrs[0] = &our_objc_header; - hdrs[1] = 0; - return hdrs; -} - -// I think we are getting the address of the table (ie the table itself) -// isn't that expensive ? -static void *getsubspace(headerType *objchead, char *sname, unsigned *size) -{ - simple_header_struct *table = (simple_header_struct *)objchead; - int i = 0; - - while ( table[i].subspace_name){ - if (!strcmp(table[i].subspace_name, sname)){ - *size = table[i].end_address - table[i].start_address; - return table[i].start_address; - } - i++; - } - *size = 0; - return nil; -} - -Module _getObjcModules(headerType *head, int *nmodules) -{ - unsigned size; - void *mods = getsubspace(head,"$$OBJC_MODULES$$",&size); - *nmodules = size / sizeof(struct objc_module); - return (Module)mods; -} - -SEL *_getObjcMessageRefs(headerType *head, int *nmess) -{ - unsigned size; - void *refs = getsubspace (head,"$$OBJC_MESSAGE_REFS$$", &size); - *nmess = size / sizeof(SEL); - return (SEL *)refs; -} - -struct proto_template *_getObjcProtocols(headerType *head, int *nprotos) -{ - unsigned size; - char *p; - char *end; - char *start; - - start = getsubspace (head,"$$OBJC_PROTOCOL$$", &size); - -#ifdef PADDING_BUG - /* - * XXX: Look for padding of 4 zero bytes and remove it. - * XXX: Depends upon first four bytes of a proto_template never being 0. - * XXX: Somebody should check to see if this is really the case. - */ - end = start + size; - for (p = start; p < end; p += sizeof(struct proto_template)) { - if (!p[0] && !p[1] && !p[2] && !p[3]) { - memcpy(p, p + sizeof(long), (end - p) - sizeof(long)); - end -= sizeof(long); - } - } - size = end - start; -#endif - *nprotos = size / sizeof(struct proto_template); - return ((struct proto_template *)start); -} - -NXConstantStringTemplate *_getObjcStringObjects(headerType *head, int *nstrs) -{ - unsigned size; - void *str = getsubspace (head,"$$OBJC_STRING_OBJECT$$", &size); - *nstrs = size / sizeof(NXConstantStringTemplate); - return (NXConstantStringTemplate *)str; -} - -Class *_getObjcClassRefs(headerType *head, int *nclasses) -{ - unsigned size; - void *classes = getsubspace (head,"$$OBJC_CLS_REFS$$", &size); - *nclasses = size / sizeof(Class); - return (Class *)classes; -} - -/* returns start of all objective-c info and the size of the data */ -void *_getObjcHeaderData(headerType *head, unsigned *size) -{ -#warning _getObjcHeaderData not implemented yet - *size = 0; - return nil; -} - - -const char *_getObjcHeaderName(headerType *header) -{ - return "oh poo"; -} - -#else - -/* - * Objective-C runtime information module. - * This module is generic for all object format files. - */ - -#import -#import -#import "objc-private.h" -#if defined(WIN32) - #import -#endif - -int NXArgc = 0; -char ** NXArgv = NULL; - - -char ***_NSGetArgv(void) -{ - return &NXArgv; -} - -int *_NSGetArgc(void) -{ - return &NXArgc; - -} - -#if defined(WIN32) - OBJC_EXPORT char ***_environ_dll; -#elif defined(NeXT_PDO) - OBJC_EXPORT char ***environ; -#endif - -char ***_NSGetEnviron(void) -{ -#if defined(WIN32) - return (char ***)_environ_dll; -#elif defined(NeXT_PDO) - return (char ***)&environ; -#else - #warning "_NSGetEnviron() is unimplemented for this architecture" - return (char ***)NULL; -#endif -} - - -#if !defined(__hpux__) && !defined(hpux) && !defined(__osf__) - const char OBJC_METH_VAR_NAME_FORWARD[10]="forward::"; -#else - OBJC_EXPORT char OBJC_METH_VAR_NAME_FORWARD[]; -#endif - -static objcSectionStruct objcHeaders = {0,0,sizeof(objcModHeader)}; -objcModHeader *CMH = 0; // Current Module Header - -int _objcModuleCount() { - return objcHeaders.count; -} - -const char *_objcModuleNameAtIndex(int i) { - if ( i < 0 || i >= objcHeaders.count) - return NULL; - return ((objcModHeader*)objcHeaders.data + i)->name; -} - -static inline void allocElements (objcSectionStruct *ptr, int nelmts) -{ - if (ptr->data == 0) { - ptr->data = (void*)malloc ((ptr->count+nelmts) * ptr->size); - } else { - volatile void *tempData = (void *)realloc(ptr->data, (ptr->count+nelmts) * ptr->size); - ptr->data = (void **)tempData; - } - - bzero((char*)ptr->data + ptr->count * ptr->size, ptr->size * nelmts); -} - -OBJC_EXPORT void _objcInit(void); -void objc_finish_header (void) -{ - _objcInit (); - CMH = (objcModHeader *)0; - // leaking like a stuck pig. -} - -void objc_register_header_name (const char * name) { - if (name) { - CMH->name = malloc(strlen(name)+1); -#if defined(WIN32) || defined(__svr4__) - bzero(CMH->name, (strlen(name)+1)); -#endif - strcpy(CMH->name, name); - } -} - -void objc_register_header (const char * name) -{ - if (CMH) { - // we've already registered a header (probably via __objc_execClass), - // so just update the name. - if (CMH->name) - free(CMH->name); - } else { - allocElements (&objcHeaders, 1); - CMH = (objcModHeader *)objcHeaders.data + objcHeaders.count; - objcHeaders.count++; - bzero(CMH, sizeof(objcModHeader)); - - CMH->Modules.size = sizeof(struct objc_module); - CMH->Classes.size = sizeof(void *); - CMH->Protocols.size = sizeof(void *); - CMH->StringObjects.size = sizeof(void *); - } - objc_register_header_name(name); -} - -#if defined(DEBUG) -void printModule(Module mod) -{ - printf("name=\"%s\", symtab=%x\n", mod->name, mod->symtab); -} - -void dumpModules(void) -{ - int i,j; - Module mod; - objcModHeader *cmh; - - printf("dumpModules(): found %d header(s)\n", objcHeaders.count); - for (j=0; jname, cmh->Modules.count); - - - mod = (Module)cmh->Modules.data; - - for (i=0; iModules.count; i++) { - printf("\tname=\"%s\", symtab=%x, sel_ref_cnt=%d\n", mod->name, mod->symtab, (Symtab)(mod->symtab)->sel_ref_cnt); - mod++; - } - } -} -#endif // DEBUG - -static inline void addObjcProtocols(struct objc_protocol_list * pl) -{ - if ( !pl ) - return; - else { - int count = 0; - struct objc_protocol_list *list = pl; - while ( list ) { - count += list->count; - list = list->next; - } - allocElements( &CMH->Protocols, count ); - - list = pl; - while ( list ) { - int i = 0; - while ( i < list->count ) - CMH->Protocols.data[ CMH->Protocols.count++ ] = (void*) list->list[i++]; - list = list->next; - } - - list = pl; - while ( list ) { - int i = 0; - while ( i < list->count ) - addObjcProtocols( ((ProtocolTemplate*)list->list[i++])->protocol_list ); - list = list->next; - } - } -} - -static void -_parseObjcModule(struct objc_symtab *symtab) -{ - int i=0, j=0, k; - SEL *refs = symtab->refs, sel; - - - // Add the selector references - - if (refs) - { - symtab->sel_ref_cnt = 0; - - while (*refs) - { - symtab->sel_ref_cnt++; - // don't touvh the VM page if not necessary - if ( (sel = sel_registerNameNoCopy ((const char *)*refs)) != *refs ) { - *refs = sel; - } - refs++; - } - } - - // Walk through all of the ObjC Classes - - if ((k = symtab->cls_def_cnt)) - { - allocElements (&CMH->Classes, k); - - for ( i=0, j = symtab->cls_def_cnt; i < j; i++ ) - { - struct objc_class *class; - unsigned loop; - - class = (struct objc_class *)symtab->defs[i]; - objc_addClass(class); - CMH->Classes.data[ CMH->Classes.count++ ] = (void*) class->name; - addObjcProtocols (class->protocols); - - // ignore fixing up the selectors to be unique (for now; done lazily later) - - } - } - - // Walk through all of the ObjC Categories - - if ((k = symtab->cat_def_cnt)) - { - allocElements (&CMH->Classes, k); - - for ( j += symtab->cat_def_cnt; - i < j; - i++ ) - { - struct objc_category *category; - - category = (struct objc_category *)symtab->defs[i]; - CMH->Classes.data[ CMH->Classes.count++ ] = - (void*) category->class_name; - - addObjcProtocols (category->protocols); - - // ignore fixing the selectors to be unique - // this is now done lazily upon use - //_objc_inlined_fixup_selectors_in_method_list(category->instance_methods); - //_objc_inlined_fixup_selectors_in_method_list(category->class_methods); - } - } - - - // Walk through all of the ObjC Static Strings - - if ((k = symtab->obj_defs)) - { - allocElements (&CMH->StringObjects, k); - - for ( j += symtab->obj_defs; - i < j; - i++ ) - { - NXConstantStringTemplate *string = ( NXConstantStringTemplate *)symtab->defs[i]; - CMH->StringObjects.data[ CMH->StringObjects.count++ ] = - (void*) string; - } - } - - // Walk through all of the ObjC Static Protocols - - if ((k = symtab->proto_defs)) - { - allocElements (&CMH->Protocols, k); - - for ( j += symtab->proto_defs; - i < j; - i++ ) - { - ProtocolTemplate *proto = ( ProtocolTemplate *)symtab->defs[i]; - allocElements (&CMH->Protocols, 1); - CMH->Protocols.data[ CMH->Protocols.count++ ] = - (void*) proto; - - addObjcProtocols(proto->protocol_list); - } - } -} - -// used only as a dll initializer on Windows and/or hppa (!) -void __objc_execClass(Module mod) -{ - sel_registerName ((const char *)OBJC_METH_VAR_NAME_FORWARD); - - if (CMH == 0) { - objc_register_header(NXArgv ? NXArgv[0] : ""); - } - - allocElements (&CMH->Modules, 1); - - memcpy( (Module)CMH->Modules.data - + CMH->Modules.count, - mod, - sizeof(struct objc_module)); - CMH->Modules.count++; - - _parseObjcModule(mod->symtab); -} - -const char * NSModulePathForClass(Class cls) -{ -#if defined(WIN32) - int i, j, k; - - for (i = 0; i < objcHeaders.count; i++) { - volatile objcModHeader *aHeader = (objcModHeader *)objcHeaders.data + i; - for (j = 0; j < aHeader->Modules.count; j++) { - Module mod = (void *)(aHeader->Modules.data) + j * aHeader->Modules.size; - struct objc_symtab *symtab = mod->symtab; - for (k = 0; k < symtab->cls_def_cnt; k++) { - if (cls == (Class)symtab->defs[k]) - return aHeader->name; - } - } - } -#else - #warning "NSModulePathForClass is not fully implemented!" -#endif - return NULL; -} - -unsigned int _objc_goff_headerCount (void) -{ - return objcHeaders.count; -} - -/* Build the header vector, of all headers seen so far. */ - -struct header_info *_objc_goff_headerVector () -{ - unsigned int hidx; - struct header_info *hdrVec; - - hdrVec = malloc_zone_malloc (_objc_create_zone(), - objcHeaders.count * sizeof (struct header_info)); -#if defined(WIN32) || defined(__svr4__) - bzero(hdrVec, (objcHeaders.count * sizeof (struct header_info))); -#endif - - for (hidx = 0; hidx < objcHeaders.count; hidx++) - { - objcModHeader *aHeader = (objcModHeader *)objcHeaders.data + hidx; - - hdrVec[hidx].mhdr = (headerType**) aHeader; - hdrVec[hidx].mod_ptr = (Module)(aHeader->Modules.data); - } - return hdrVec; -} - - -#if defined(sparc) - int __NXArgc = 0; - char ** __NXArgv = 0; -#endif - -/* Returns an array of all the objc headers in the executable (and shlibs) - * Caller is responsible for freeing. - */ -headerType **_getObjcHeaders() -{ - -#if defined(__hpux__) || defined(hpux) - OBJC_EXPORT int __argc_value; - OBJC_EXPORT char ** __argv_value; -#endif - - /* Will need to fill in with any shlib info later as well. Need more - * info on this. - */ - - headerType **hdrs = (headerType**)malloc(2 * sizeof(headerType*)); -#if defined(WIN32) || defined(__svr4__) - bzero(hdrs, (2 * sizeof(headerType*))); -#endif -#if defined(__hpux__) || defined(hpux) - NXArgv = __argv_value; - NXArgc = __argc_value; -#else /* __hpux__ || hpux */ -#if defined(sparc) - NXArgv = __NXArgv; - NXArgc = __NXArgc; -#endif /* sparc */ -#endif /* __hpux__ || hpux */ - - hdrs[0] = (headerType*)CMH; - hdrs[1] = 0; - return hdrs; -} - -static objcModHeader *_getObjcModHeader(headerType *head) -{ - return (objcModHeader *)head; -} - -Module _getObjcModules(headerType *head, int *size) -{ - objcModHeader *modHdr = _getObjcModHeader(head); - if (modHdr) { - *size = modHdr->Modules.count; - return (Module)(modHdr->Modules.data); - } - else { - *size = 0; - return (Module)0; - } -} - -ProtocolTemplate **_getObjcProtocols(headerType *head, int *nprotos) -{ - objcModHeader *modHdr = _getObjcModHeader(head); - - if (modHdr) { - *nprotos = modHdr->Protocols.count; - return (ProtocolTemplate **)modHdr->Protocols.data; - } - else { - *nprotos = 0; - return (ProtocolTemplate **)0; - } -} - - -NXConstantStringTemplate **_getObjcStringObjects(headerType *head, int *nstrs) -{ - objcModHeader *modHdr = _getObjcModHeader(head); - - if (modHdr) { - *nstrs = modHdr->StringObjects.count; - return (NXConstantStringTemplate **)modHdr->StringObjects.data; - } - else { - *nstrs = 0; - return (NXConstantStringTemplate **)0; - } -} - -Class *_getObjcClassRefs(headerType *head, int *nclasses) -{ - objcModHeader *modHdr = _getObjcModHeader(head); - - if (modHdr) { - *nclasses = modHdr->Classes.count; - return (Class *)modHdr->Classes.data; - } - else { - *nclasses = 0; - return (Class *)0; - } -} - -/* returns start of all objective-c info and the size of the data */ -void *_getObjcHeaderData(headerType *head, unsigned *size) -{ - *size = 0; - return NULL; -} - -SEL *_getObjcMessageRefs(headerType *head, int *nmess) -{ - *nmess = 0; - return (SEL *)NULL; -} - -const char *_getObjcHeaderName(headerType *header) -{ - return "InvalidHeaderName"; -} -#endif diff --git a/runtime/objc-load.h b/runtime/objc-load.h index b0e0836..499ff0c 100644 --- a/runtime/objc-load.h +++ b/runtime/objc-load.h @@ -29,7 +29,6 @@ #ifndef _OBJC_LOAD_H_ #define _OBJC_LOAD_H_ -#if !defined(NeXT_PDO) #import #import @@ -60,5 +59,5 @@ OBJC_EXPORT void objc_register_header( char *name /* input */ ); -#endif NeXT_PDO + #endif /* _OBJC_LOAD_H_ */ diff --git a/runtime/objc-load.m b/runtime/objc-load.m index 68c0b4b..8f02cf2 100644 --- a/runtime/objc-load.m +++ b/runtime/objc-load.m @@ -1,8 +1,8 @@ /* * Copyright (c) 1999 Apple Computer, Inc. All rights reserved. - * + * * @APPLE_LICENSE_HEADER_START@ - * + * * Portions Copyright (c) 1999 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 @@ -20,7 +20,7 @@ * under the License. * * @APPLE_LICENSE_HEADER_END@ - */ + */ /* * objc-load.m @@ -35,28 +35,12 @@ #import #import -#if defined(__MACH__) || defined(WIN32) -#import -#endif +//#import +#include -#if !defined(NeXT_PDO) - // MACH - #include -#endif -#if defined(WIN32) - #import - #import -#endif -#if defined(__svr4__) - #import -#endif - -#if defined(__hpux__) || defined(hpux) - #import "objc_hpux_register_shlib.c" -#endif extern char * getsectdatafromheader (const headerType * mhp, const char * segname, const char * sectname, int * size); @@ -73,248 +57,131 @@ struct objc_method_list **get_base_method_list(Class cls) { } -#if defined(NeXT_PDO) // GENERIC_OBJ_FILE - void send_load_message_to_class(Class cls, void *header_addr) +/********************************************************************************** +* objc_loadModule. +* +* NOTE: Loading isn't really thread safe. If a load message recursively calls +* objc_loadModules() both sets will be loaded correctly, but if the original +* caller calls objc_unloadModules() it will probably unload the wrong modules. +* If a load message calls objc_unloadModules(), then it will unload +* the modules currently being loaded, which will probably cause a crash. +* +* Error handling is still somewhat crude. If we encounter errors while +* linking up classes or categories, we will not recover correctly. +* +* I removed attempts to lock the class hashtable, since this introduced +* deadlock which was hard to remove. The only way you can get into trouble +* is if one thread loads a module while another thread tries to access the +* loaded classes (using objc_lookUpClass) before the load is complete. +**********************************************************************************/ +int objc_loadModule(const char *moduleName, void (*class_callback) (Class, const char *categoryName), int *errorCode) +{ + int successFlag = 1; + int locErrorCode; + NSObjectFileImage objectFileImage; + NSObjectFileImageReturnCode code; + + // So we don't have to check this everywhere + if (errorCode == NULL) + errorCode = &locErrorCode; + + if (moduleName == NULL) { - struct objc_method_list **mlistp = get_base_method_list(cls->isa); - struct objc_method_list *mlist = mlistp ? *mlistp : NULL; - IMP load_method; - - if (mlist) { - load_method = - class_lookupNamedMethodInMethodList(mlist, "finishLoading:"); - - /* go directly there, we do not want to accidentally send - the finishLoading: message to one of its categories... - */ - if (load_method) - (*load_method)((id)cls, @selector(finishLoading:), - header_addr); - } + *errorCode = NSObjectFileImageInappropriateFile; + return 0; } - void send_load_message_to_category(Category cat, void *header_addr) + if (_dyld_present () == 0) { - struct objc_method_list *mlist = cat->class_methods; - IMP load_method; - Class cls; - - if (mlist) { - load_method = - class_lookupNamedMethodInMethodList(mlist, "finishLoading:"); - - cls = objc_getClass (cat->class_name); - - /* go directly there, we do not want to accidentally send - the finishLoading: message to one of its categories... - */ - if (load_method) - (*load_method)(cls, @selector(finishLoading:), - header_addr); - } + *errorCode = NSObjectFileImageFailure; + return 0; } -#endif // GENERIC_OBJ_FILE - -/********************************************************************************** - * objc_loadModule. - * - * NOTE: Loading isn't really thread safe. If a load message recursively calls - * objc_loadModules() both sets will be loaded correctly, but if the original - * caller calls objc_unloadModules() it will probably unload the wrong modules. - * If a load message calls objc_unloadModules(), then it will unload - * the modules currently being loaded, which will probably cause a crash. - * - * Error handling is still somewhat crude. If we encounter errors while - * linking up classes or categories, we will not recover correctly. - * - * I removed attempts to lock the class hashtable, since this introduced - * deadlock which was hard to remove. The only way you can get into trouble - * is if one thread loads a module while another thread tries to access the - * loaded classes (using objc_lookUpClass) before the load is complete. - **********************************************************************************/ -int objc_loadModule (const char * moduleName, - void (*class_callback) (Class, const char *categoryName), - int * errorCode) -{ - int successFlag = 1; - int locErrorCode; -#if defined(__MACH__) - NSObjectFileImage objectFileImage; - NSObjectFileImageReturnCode code; -#endif -#if defined(WIN32) || defined(__svr4__) || defined(__hpux__) || defined(hpux) - void * handle; - void (*save_class_callback) (Class, const char *) = load_class_callback; -#endif - - // So we don't have to check this everywhere - if (errorCode == NULL) - errorCode = &locErrorCode; - -#if defined(__MACH__) - if (moduleName == NULL) - { - *errorCode = NSObjectFileImageInappropriateFile; - return 0; - } - - if (_dyld_present () == 0) - { - *errorCode = NSObjectFileImageFailure; - return 0; - } - - callbackFunction = class_callback; - code = NSCreateObjectFileImageFromFile (moduleName, &objectFileImage); - if (code != NSObjectFileImageSuccess) - { - *errorCode = code; - return 0; - } - -#if !defined(__OBJC_DONT_USE_NEW_NSLINK_OPTION__) - if (NSLinkModule(objectFileImage, moduleName, NSLINKMODULE_OPTION_RETURN_ON_ERROR) == NULL) { - NSLinkEditErrors error; - int errorNum; - char *fileName, *errorString; - NSLinkEditError(&error, &errorNum, &fileName, &errorString); - // These errors may overlap with other errors that objc_loadModule returns in other failure cases. - *errorCode = error; - return 0; - } -#else - (void)NSLinkModule(objectFileImage, moduleName, NSLINKMODULE_OPTION_NONE); -#endif - callbackFunction = NULL; - -#else - // The PDO cases - if (moduleName == NULL) - { - *errorCode = 0; - return 0; - } - - OBJC_LOCK(&loadLock); - -#if defined(WIN32) || defined(__svr4__) || defined(__hpux__) || defined(hpux) - - load_class_callback = class_callback; - -#if defined(WIN32) - if ((handle = LoadLibrary (moduleName)) == NULL) - { - FreeLibrary(moduleName); - *errorCode = 0; - successFlag = 0; - } - -#elif defined(__svr4__) - handle = dlopen(moduleName, (RTLD_NOW | RTLD_GLOBAL)); - if (handle == 0) - { - *errorCode = 0; - successFlag = 0; - } - else - { - objc_register_header(moduleName); - objc_finish_header(); - } - -#else - handle = shl_load(moduleName, BIND_IMMEDIATE | BIND_VERBOSE, 0L); - if (handle == 0) - { - *errorCode = 0; - successFlag = 0; - } - else - ; // Don't do anything here: the shlib should have been built - // with the +I'objc_hpux_register_shlib' option -#endif - load_class_callback = save_class_callback; - -#elif defined(NeXT_PDO) - // NOTHING YET... - successFlag = 0; -#endif // WIN32 + callbackFunction = class_callback; + code = NSCreateObjectFileImageFromFile (moduleName, &objectFileImage); + if (code != NSObjectFileImageSuccess) + { + *errorCode = code; + return 0; + } - OBJC_UNLOCK (&loadLock); + if (NSLinkModule(objectFileImage, moduleName, NSLINKMODULE_OPTION_RETURN_ON_ERROR) == NULL) { + NSLinkEditErrors error; + int errorNum; + char *fileName, *errorString; + NSLinkEditError(&error, &errorNum, &fileName, &errorString); + // These errors may overlap with other errors that objc_loadModule returns in other failure cases. + *errorCode = error; + return 0; + } + callbackFunction = NULL; -#endif // MACH - return successFlag; + return successFlag; } /********************************************************************************** - * objc_loadModules. - **********************************************************************************/ - /* Lock for dynamic loading and unloading. */ - static OBJC_DECLARE_LOCK (loadLock); -#if defined(NeXT_PDO) // GENERIC_OBJ_FILE - void (*load_class_callback) (Class, const char *); -#endif - - -long objc_loadModules (char * modlist[], - void * errStream, - void (*class_callback) (Class, const char *), - headerType ** hdr_addr, - char * debug_file) +* objc_loadModules. +**********************************************************************************/ +/* Lock for dynamic loading and unloading. */ +// static OBJC_DECLARE_LOCK (loadLock); + + +long objc_loadModules (char * modlist[], + void * errStream, + void (*class_callback) (Class, const char *), + headerType ** hdr_addr, + char * debug_file) { - char ** modules; - int code; - int itWorked; - - if (modlist == 0) - return 0; - - for (modules = &modlist[0]; *modules != 0; modules++) - { - itWorked = objc_loadModule (*modules, class_callback, &code); - if (itWorked == 0) - { -#if defined(__MACH__) || defined(WIN32) - if (errStream) - NXPrintf ((NXStream *) errStream, "objc_loadModules(%s) code = %d\n", *modules, code); -#endif - return 1; - } - - if (hdr_addr) - *(hdr_addr++) = 0; - } - - return 0; + char ** modules; + int code; + int itWorked; + + if (modlist == 0) + return 0; + + for (modules = &modlist[0]; *modules != 0; modules++) + { + itWorked = objc_loadModule (*modules, class_callback, &code); + if (itWorked == 0) + { + //if (errStream) + // NXPrintf ((NXStream *) errStream, "objc_loadModules(%s) code = %d\n", *modules, code); + return 1; + } + + if (hdr_addr) + *(hdr_addr++) = 0; + } + + return 0; } /********************************************************************************** - * objc_unloadModules. - * - * NOTE: Unloading isn't really thread safe. If an unload message calls - * objc_loadModules() or objc_unloadModules(), then the current call - * to objc_unloadModules() will probably unload the wrong stuff. - **********************************************************************************/ +* objc_unloadModules. +* +* NOTE: Unloading isn't really thread safe. If an unload message calls +* objc_loadModules() or objc_unloadModules(), then the current call +* to objc_unloadModules() will probably unload the wrong stuff. +**********************************************************************************/ long objc_unloadModules (void * errStream, - void (*unload_callback) (Class, Category)) + void (*unload_callback) (Class, Category)) { - headerType * header_addr = 0; - int errflag = 0; + headerType * header_addr = 0; + int errflag = 0; - // TODO: to make unloading work, should get the current header + // TODO: to make unloading work, should get the current header - if (header_addr) - { - ; // TODO: unload the current header - } - else - { - errflag = 1; - } + if (header_addr) + { + ; // TODO: unload the current header + } + else + { + errflag = 1; + } - return errflag; + return errflag; } diff --git a/runtime/objc-moninit.c b/runtime/objc-moninit.c index 02c6d90..b82fa36 100644 --- a/runtime/objc-moninit.c +++ b/runtime/objc-moninit.c @@ -28,8 +28,8 @@ unsigned long * moninitobjc(unsigned long moncount_addr) { - extern void _NXLogError(const char *format, ...); - _NXLogError ("moninitobjc is obsoleted, refer to documentation for how to do profiling\n"); + extern void _objc_inform(const char *format, ...); + _objc_inform ("moninitobjc is obsoleted, refer to documentation for how to do profiling\n"); return (0); } diff --git a/runtime/objc-private.h b/runtime/objc-private.h index 3b22986..a178b19 100644 --- a/runtime/objc-private.h +++ b/runtime/objc-private.h @@ -35,28 +35,16 @@ #import "objc-config.h" - #if defined(NeXT_PDO) - #define LITERAL_STRING_OBJECTS - #import - #if defined(WIN32) - #import - #import - #else - #import // for pdo_malloc and pdo_free defines - #import - #endif - #else - #import - #define mutex_alloc() (pthread_mutex_t*)calloc(1, sizeof(pthread_mutex_t)) - #define mutex_init(m) pthread_mutex_init(m, NULL) - #define mutex_lock(m) pthread_mutex_lock(m) - #define mutex_try_lock(m) (! pthread_mutex_trylock(m)) - #define mutex_unlock(m) pthread_mutex_unlock(m) - #define mutex_clear(m) - #define mutex_t pthread_mutex_t* - #define mutex MUTEX_DEFINE_ERROR - #import - #endif + #import + #define mutex_alloc() (pthread_mutex_t*)calloc(1, sizeof(pthread_mutex_t)) + #define mutex_init(m) pthread_mutex_init(m, NULL) + #define mutex_lock(m) pthread_mutex_lock(m) + #define mutex_try_lock(m) (! pthread_mutex_trylock(m)) + #define mutex_unlock(m) pthread_mutex_unlock(m) + #define mutex_clear(m) + #define mutex_t pthread_mutex_t* + #define mutex MUTEX_DEFINE_ERROR + #import #import #import @@ -111,29 +99,31 @@ OBJC_EXPORT Class * _getObjcClassRefs(headerType *head, int *nclasses); OBJC_EXPORT void * _getObjcHeaderData(headerType *head, unsigned *size); OBJC_EXPORT const char * _getObjcHeaderName(headerType *head); -#if defined(NeXT_PDO) // GENERIC_OBJ_FILE - OBJC_EXPORT ProtocolTemplate ** _getObjcProtocols(headerType *head, int *nprotos); - OBJC_EXPORT NXConstantStringTemplate **_getObjcStringObjects(headerType *head, int *nstrs); -#elif defined(__MACH__) - OBJC_EXPORT ProtocolTemplate * _getObjcProtocols(headerType *head, int *nprotos); - OBJC_EXPORT NXConstantStringTemplate *_getObjcStringObjects(headerType *head, int *nstrs); - OBJC_EXPORT SEL * _getObjcMessageRefs(headerType *head, int *nmess); -#endif +// internal routines for delaying binding +void _objc_resolve_categories_for_class (struct objc_class * cls); +void _objc_bindModuleContainingClass(struct objc_class * cls); + +// someday a logging facility +// ObjC is assigned the range 0xb000 - 0xbfff for first parameter +#define trace(a, b, c, d) do {} while (0) + + - #define END_OF_METHODS_LIST ((struct objc_method_list*)-1) +OBJC_EXPORT ProtocolTemplate * _getObjcProtocols(headerType *head, int *nprotos); +OBJC_EXPORT NXConstantStringTemplate *_getObjcStringObjects(headerType *head, int *nstrs); +OBJC_EXPORT SEL * _getObjcMessageRefs(headerType *head, int *nmess); - struct header_info +#define END_OF_METHODS_LIST ((struct objc_method_list*)-1) + + typedef struct _header_info { const headerType * mhdr; - Module mod_ptr; - unsigned int mod_count; - unsigned long image_slide; - unsigned int objcSize; - }; - typedef struct header_info header_info; - OBJC_EXPORT header_info *_objc_headerVector (const headerType * const *machhdrs); - OBJC_EXPORT unsigned int _objc_headerCount (void); - OBJC_EXPORT void _objc_addHeader (const headerType *header, unsigned long vmaddr_slide); + Module mod_ptr; + unsigned int mod_count; + unsigned long image_slide; + struct _header_info * next; + } header_info; + OBJC_EXPORT header_info *_objc_headerStart (); OBJC_EXPORT int _objcModuleCount(); OBJC_EXPORT const char *_objcModuleNameAtIndex(int i); @@ -147,7 +137,6 @@ OBJC_EXPORT const char * _getObjcHeaderName(headerType *head); /* initialize */ OBJC_EXPORT void _sel_resolve_conflicts(headerType * header, unsigned long slide); OBJC_EXPORT void _class_install_relationships(Class, long); - OBJC_EXPORT void _objc_add_category(Category, int); OBJC_EXPORT void *_objc_create_zone(void); OBJC_EXPORT SEL sel_registerNameNoCopy(const char *str); @@ -219,7 +208,7 @@ OBJC_EXPORT const char * _getObjcHeaderName(headerType *head); OBJC_EXPORT volatile void _objc_error(id, const char *, va_list); OBJC_EXPORT volatile void __objc_error(id, const char *, ...); OBJC_EXPORT void _objc_inform(const char *fmt, ...); - OBJC_EXPORT void _NXLogError(const char *format, ...); + OBJC_EXPORT void _objc_syslog(const char *fmt, ...); /* magic */ OBJC_EXPORT Class _objc_getFreedObjectClass (void); @@ -227,32 +216,10 @@ OBJC_EXPORT const char * _getObjcHeaderName(headerType *head); OBJC_EXPORT void _objc_flush_caches (Class cls); /* locking */ - #if defined(NeXT_PDO) - #if defined(WIN32) - #define MUTEX_TYPE long - #define OBJC_DECLARE_LOCK(MUTEX) MUTEX_TYPE MUTEX = 0L; - #elif defined(sparc) - #define MUTEX_TYPE long - #define OBJC_DECLARE_LOCK(MUTEX) MUTEX_TYPE MUTEX = 0L; - #elif defined(__alpha__) - #define MUTEX_TYPE long - #define OBJC_DECLARE_LOCK(MUTEX) MUTEX_TYPE MUTEX = 0L; - #elif defined(__hpux__) || defined(hpux) - typedef struct { int a; int b; int c; int d; } __mutex_struct; - #define MUTEX_TYPE __mutex_struct - #define OBJC_DECLARE_LOCK(MUTEX) MUTEX_TYPE MUTEX = { 1, 1, 1, 1 }; - #else // unknown pdo platform - #define MUTEX_TYPE long - #define OBJC_DECLARE_LOCK(MUTEX) struct mutex MUTEX = { 0 }; - #endif // WIN32 - OBJC_EXPORT MUTEX_TYPE classLock; - OBJC_EXPORT MUTEX_TYPE messageLock; - #else - #define MUTEX_TYPE pthread_mutex_t* - #define OBJC_DECLARE_LOCK(MTX) pthread_mutex_t MTX = PTHREAD_MUTEX_INITIALIZER - OBJC_EXPORT pthread_mutex_t classLock; - OBJC_EXPORT pthread_mutex_t messageLock; - #endif // NeXT_PDO + #define MUTEX_TYPE pthread_mutex_t* + #define OBJC_DECLARE_LOCK(MTX) pthread_mutex_t MTX = PTHREAD_MUTEX_INITIALIZER + OBJC_EXPORT pthread_mutex_t classLock; + OBJC_EXPORT pthread_mutex_t messageLock; OBJC_EXPORT int _objc_multithread_mask; @@ -266,9 +233,6 @@ OBJC_EXPORT const char * _getObjcHeaderName(headerType *head); } FixupEntry; static inline int selEqual( SEL s1, SEL s2 ) { - OBJC_EXPORT int rocketLaunchingDebug; - if ( rocketLaunchingDebug ) - checkUniqueness(s1, s2); return (s1 == s2); } @@ -276,29 +240,7 @@ OBJC_EXPORT const char * _getObjcHeaderName(headerType *head); #define OBJC_LOCK(MUTEX) mutex_lock (MUTEX) #define OBJC_UNLOCK(MUTEX) mutex_unlock (MUTEX) #define OBJC_TRYLOCK(MUTEX) mutex_try_lock (MUTEX) - #elif defined(NeXT_PDO) - #if !defined(WIN32) - /* Where are these defined? NT should probably be using them! */ - OBJC_EXPORT void _objc_private_lock(MUTEX_TYPE*); - OBJC_EXPORT void _objc_private_unlock(MUTEX_TYPE*); - - /* I don't think this should be commented out for NT, should it? */ - #define OBJC_LOCK(MUTEX) \ - do {if (!_objc_multithread_mask) \ - _objc_private_lock(MUTEX);} while(0) - #define OBJC_UNLOCK(MUTEX) \ - do {if (!_objc_multithread_mask) \ - _objc_private_unlock(MUTEX);} while(0) - #else - #define OBJC_LOCK(MUTEX) \ - do {if (!_objc_multithread_mask) \ - if( *MUTEX == 0 ) *MUTEX = 1;} while(0) - #define OBJC_UNLOCK(MUTEX) \ - do {if (!_objc_multithread_mask) \ - *MUTEX = 0;} while(0) - #endif // WIN32 - - #else // not NeXT_PDO + #else // not OBJC_COLLECTING_CACHE #define OBJC_LOCK(MUTEX) \ do \ { \ @@ -320,28 +262,7 @@ OBJC_EXPORT const char * _getObjcHeaderName(headerType *head); #define SEG_OBJC "__OBJC" /* objective-C runtime segment */ #endif -#if defined(NeXT_PDO) - // GENERIC_OBJ_FILE - void send_load_message_to_category(Category cat, void *header_addr); - void send_load_message_to_class(Class cls, void *header_addr); -#endif -#if !defined(__MACH__) -typedef struct _objcSectionStruct { - void **data; /* Pointer to array */ - int count; /* # of elements */ - int size; /* sizeof an element */ -} objcSectionStruct; - -typedef struct _objcModHeader { - char * name; - objcSectionStruct Modules; - objcSectionStruct Classes; - objcSectionStruct Methods; - objcSectionStruct Protocols; - objcSectionStruct StringObjects; -} objcModHeader; -#endif static __inline__ int _objc_strcmp(const unsigned char *s1, const unsigned char *s2) { diff --git a/runtime/objc-runtime.h b/runtime/objc-runtime.h index 59b1f6f..1b94c3b 100644 --- a/runtime/objc-runtime.h +++ b/runtime/objc-runtime.h @@ -151,16 +151,7 @@ OBJC_EXPORT id (*_zoneAlloc)(Class, unsigned int, void *); OBJC_EXPORT id (*_zoneRealloc)(id, unsigned int, void *); OBJC_EXPORT id (*_zoneCopy)(id, unsigned int, void *); -#if defined(NeXT_PDO) - OBJC_EXPORT void (*_error)(); -#else - OBJC_EXPORT void (*_error)(id, const char *, va_list); -#endif +OBJC_EXPORT void (*_error)(id, const char *, va_list); -#if defined(WIN32) -/* This seems like a strange place to put this, but there's really - no very appropriate place! */ -OBJC_EXPORT const char* NSRootDirectory(void); -#endif #endif /* _OBJC_RUNTIME_H_ */ diff --git a/runtime/objc-runtime.m b/runtime/objc-runtime.m index 4d1b9ce..86036ef 100644 --- a/runtime/objc-runtime.m +++ b/runtime/objc-runtime.m @@ -2,7 +2,7 @@ * Copyright (c) 1999 Apple Computer, Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ - * + * * Portions Copyright (c) 1999 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 @@ -10,7 +10,7 @@ * except in compliance with the License. Please obtain a copy of the * License at http://www.apple.com/publicsource 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, @@ -18,32 +18,27 @@ * FITNESS FOR A PARTICULAR PURPOSE OR NON- INFRINGEMENT. Please see the * License for the specific language governing rights and limitations * under the License. - * + * * @APPLE_LICENSE_HEADER_END@ */ /*********************************************************************** - * objc-runtime.m - * Copyright 1988-1996, NeXT Software, Inc. - * Author: s. naroff - * - **********************************************************************/ +* objc-runtime.m +* Copyright 1988-1996, NeXT Software, Inc. +* Author: s. naroff +* +**********************************************************************/ /*********************************************************************** - * Imports. - **********************************************************************/ +* Imports. +**********************************************************************/ -#if defined(WIN32) -#include -#endif -#if defined(NeXT_PDO) -#import // for pdo_malloc and pdo_free defines -#elif defined(__MACH__) #include #include #include -#endif +// project headers first, otherwise we get the installed ones +#import "objc-class.h" #import #import #import "maptable.h" @@ -51,59 +46,49 @@ #import #import -#if !defined(WIN32) #include #include -#endif -OBJC_EXPORT Class _objc_getNonexistentClass (void); +OBJC_EXPORT Class _objc_getNonexistentClass(void); -#if defined(NeXT_PDO) // GENERIC_OBJ_FILE -OBJC_EXPORT void (*load_class_callback) (Class, Category); -OBJC_EXPORT unsigned int _objc_goff_headerCount (void); -OBJC_EXPORT header_info * _objc_goff_headerVector (void); -#endif -OBJC_EXPORT Class getOriginalClassForPosingClass (Class); +OBJC_EXPORT Class getOriginalClassForPosingClass(Class); -#if defined(WIN32) || defined(__svr4__) -// Current Module Header -extern objcModHeader * CMH; -#endif /*********************************************************************** - * Constants and macros internal to this module. - **********************************************************************/ +* Constants and macros internal to this module. +**********************************************************************/ /* Turn on support for literal string objects. */ #define LITERAL_STRING_OBJECTS /*********************************************************************** - * Types internal to this module. - **********************************************************************/ +* Types internal to this module. +**********************************************************************/ typedef struct _objc_unresolved_category { - struct _objc_unresolved_category * next; - struct objc_category * cat; - long version; + struct _objc_unresolved_category * next; + struct objc_category * cat; + long version; + int bindme; } _objc_unresolved_category; typedef struct _PendingClass { - struct objc_class * * ref; - struct objc_class * classToSetUp; - const char * nameof_superclass; - int version; - struct _PendingClass * next; + struct objc_class * * ref; + struct objc_class * classToSetUp; + const char * nameof_superclass; + int version; + struct _PendingClass * next; } PendingClass; /*********************************************************************** - * Exports. - **********************************************************************/ +* Exports. +**********************************************************************/ // Mask which specifies whether we are multi-threaded or not. -// A value of (-1) means single-threaded, 0 means multi-threaded. +// A value of (-1) means single-threaded, 0 means multi-threaded. int _objc_multithread_mask = (-1); // Function to call when message sent to nil object. @@ -112,77 +97,58 @@ void (*_objc_msgNil)(id, SEL) = NULL; // Function called after class has been fixed up (MACH only) void (*callbackFunction)(Class, const char *) = 0; -// Prototype for function passed to +// Prototype for function passed to typedef void (*NilObjectMsgCallback) (id nilObject, SEL selector); // Lock for class hashtable OBJC_DECLARE_LOCK (classLock); // Condition for logging load progress -int rocketLaunchingDebug = -1; +static int LaunchingDebug = -1; /*********************************************************************** - * Function prototypes internal to this module. - **********************************************************************/ +* Function prototypes internal to this module. +**********************************************************************/ static unsigned classHash (void * info, struct objc_class * data); static int classIsEqual (void * info, struct objc_class * name, struct objc_class * cls); static int _objc_defaultClassHandler (const char * clsName); static void _objcTweakMethodListPointerForClass (struct objc_class * cls); -static void __objc_add_category (struct objc_category * category, int version); -static void _objc_resolve_categories_for_class (struct objc_class * cls); -static void _objc_register_category (struct objc_category * cat, long version); +static void _objc_add_category_flush_caches(struct objc_class * cls, struct objc_category * category, int version); +static void _objc_add_category(struct objc_class * cls, struct objc_category * category, int version); +static void _objc_register_category (struct objc_category * cat, long version, int bindme); static void _objc_add_categories_from_image (header_info * hi); -#if defined(__MACH__) static const header_info * _headerForClass (struct objc_class * cls); -#endif -static void checkForPendingClassReferences (struct objc_class * cls); static PendingClass * newPending (void); static NXMapTable * pendingClassRefsMapTable (void); -static NXHashTable * _objc_get_classes_from_image (NXHashTable * clsHash, header_info * hi); +static void _objc_add_classes_from_image (NXHashTable * clsHash, header_info * hi); static void _objc_fixup_string_objects_for_image(header_info * hi); static void _objc_map_class_refs_for_image (header_info * hi); static void map_selrefs (SEL * sels, unsigned int cnt); static void map_method_descs (struct objc_method_description_list * methods); static void _objc_fixup_protocol_objects_for_image (header_info * hi); -#if defined(__MACH__) static void _objc_bindModuleContainingCategory(Category cat); -static void _objc_bindModuleContainingClass(struct objc_class * cls); -#endif static const char * libraryNameForMachHeader (const headerType * themh); static void _objc_fixup_selector_refs (const header_info * hi); static void _objc_call_loads_for_image (header_info * header); -#if defined(__MACH__) -static void _objc_map_image_callback (headerType * mh, unsigned long vmaddr_slide); -static void _objc_link_module_callback (NSModule mod); -static void _objc_unlink_module_callback (NSModule mod); -#endif - -#if defined(__MACH__) -extern int ptrace(int, int, int, int); -// ObjC is assigned the range 0xb000 - 0xbfff for first parameter -#else -#define ptrace(a, b, c, d) do {} while (0) -#endif +static void _objc_checkForPendingClassReferences (struct objc_class * cls); +static void _objc_map_image(headerType *mh, unsigned long vmaddr_slide); +static void _objc_unmap_image(headerType *mh, unsigned long vmaddr_slide); /*********************************************************************** - * Static data internal to this module. - **********************************************************************/ +* Static data internal to this module. +**********************************************************************/ -// System vectors created at runtime by reading the `__OBJC' segments -// that are a part of the application. -// We do not lock these variables, since they are only set during startup. -static header_info * header_vector = 0; -static unsigned int header_count = 0; -static unsigned int header_vector_size = 0; +// we keep a linked list of header_info's describing each image as told to us by dyld +static header_info * FirstHeader = 0; // Hash table of classes static NXHashTable * class_hash = 0; -static NXHashTablePrototype classHashPrototype = +static NXHashTablePrototype classHashPrototype = { - (unsigned (*) (const void *, const void *)) classHash, - (int (*)(const void *, const void *, const void *)) classIsEqual, - NXNoEffectFree, 0 + (unsigned (*) (const void *, const void *)) classHash, + (int (*)(const void *, const void *, const void *)) classIsEqual, + NXNoEffectFree, 0 }; // Function pointer objc_getClass calls through when class is not found @@ -192,1705 +158,1524 @@ static int (*objc_classHandler) (const char *) = _objc_defaultClassHandler; static NXMapTable * category_hash = NULL; -static int map_selectors_pended = 0; +static int Postpone_install_relationships = 0; static NXMapTable * pendingClassRefsMap = 0; /*********************************************************************** - * objc_dump_class_hash. Log names of all known classes. - **********************************************************************/ +* objc_dump_class_hash. Log names of all known classes. +**********************************************************************/ void objc_dump_class_hash (void) { - NXHashTable * table; - unsigned count; - struct objc_class * * data; - NXHashState state; - - table = class_hash; - count = 0; - state = NXInitHashState (table); - while (NXNextHashState (table, &state, (void **) &data)) - printf ("class %d: %s\n", ++count, (*data)->name); + NXHashTable * table; + unsigned count; + struct objc_class * * data; + NXHashState state; + + table = class_hash; + count = 0; + state = NXInitHashState (table); + while (NXNextHashState (table, &state, (void **) &data)) + printf ("class %d: %s\n", ++count, (*data)->name); } /*********************************************************************** - * classHash. - **********************************************************************/ +* classHash. +**********************************************************************/ static unsigned classHash (void * info, - struct objc_class * data) + struct objc_class * data) { - // Nil classes hash to zero - if (!data) - return 0; - - // Call through to real hash function - return _objc_strhash ((unsigned char *) ((struct objc_class *) data)->name); + // Nil classes hash to zero + if (!data) + return 0; + + // Call through to real hash function + return _objc_strhash ((unsigned char *) ((struct objc_class *) data)->name); } /*********************************************************************** - * classIsEqual. Returns whether the class names match. If we ever - * check more than the name, routines like objc_lookUpClass have to - * change as well. - **********************************************************************/ +* classIsEqual. Returns whether the class names match. If we ever +* check more than the name, routines like objc_lookUpClass have to +* change as well. +**********************************************************************/ static int classIsEqual (void * info, - struct objc_class * name, - struct objc_class * cls) + struct objc_class * name, + struct objc_class * cls) { - // Standard string comparison - return ((name->name[0] == cls->name[0]) && - (strcmp (name->name, cls->name) == 0)); + // Standard string comparison + return ((name->name[0] == cls->name[0]) && + (strcmp (name->name, cls->name) == 0)); } /*********************************************************************** - * _objc_init_class_hash. Return the class lookup table, create it if - * necessary. - **********************************************************************/ +* _objc_init_class_hash. Return the class lookup table, create it if +* necessary. +**********************************************************************/ void _objc_init_class_hash (void) { - // Do nothing if class hash table already exists - if (class_hash) - return; - - // Provide a generous initial capacity to cut down on rehashes - // at launch time. A smallish Foundation+AppKit program will have - // about 520 classes. Larger apps (like IB or WOB) have more like - // 800 classes. Some customers have massive quantities of classes. - // Foundation-only programs aren't likely to notice the ~6K loss. - class_hash = NXCreateHashTableFromZone (classHashPrototype, - 1024, - nil, - _objc_create_zone ()); + // Do nothing if class hash table already exists + if (class_hash) + return; + + // Provide a generous initial capacity to cut down on rehashes + // at launch time. A smallish Foundation+AppKit program will have + // about 520 classes. Larger apps (like IB or WOB) have more like + // 800 classes. Some customers have massive quantities of classes. + // Foundation-only programs aren't likely to notice the ~6K loss. + class_hash = NXCreateHashTableFromZone (classHashPrototype, + 1024, + nil, + _objc_create_zone ()); } /*********************************************************************** - * objc_getClassList. Return the known classes. - **********************************************************************/ +* objc_getClassList. Return the known classes. +**********************************************************************/ int objc_getClassList(Class *buffer, int bufferLen) { - NXHashState state; - struct objc_class * class; - int cnt, num; - - OBJC_LOCK(&classLock); - num = NXCountHashTable(class_hash); - if (NULL == buffer) { - OBJC_UNLOCK(&classLock); - return num; - } - cnt = 0; - state = NXInitHashState(class_hash); - while (cnt < num && NXNextHashState(class_hash, &state, (void **)&class)) { - buffer[cnt++] = class; - } - OBJC_UNLOCK(&classLock); - return num; + NXHashState state; + struct objc_class * class; + int cnt, num; + + OBJC_LOCK(&classLock); + num = NXCountHashTable(class_hash); + if (NULL == buffer) { + OBJC_UNLOCK(&classLock); + return num; + } + cnt = 0; + state = NXInitHashState(class_hash); + while (cnt < num && NXNextHashState(class_hash, &state, (void **)&class)) { + buffer[cnt++] = class; + } + OBJC_UNLOCK(&classLock); + return num; } /*********************************************************************** - * objc_getClasses. Return class lookup table. - * - * NOTE: This function is very dangerous, since you cannot safely use - * the hashtable without locking it, and the lock is private! - **********************************************************************/ +* objc_getClasses. Return class lookup table. +* +* NOTE: This function is very dangerous, since you cannot safely use +* the hashtable without locking it, and the lock is private! +**********************************************************************/ void * objc_getClasses (void) { -#if defined(NeXT_PDO) - // Make sure a hash table exists - if (!class_hash) - _objc_init_class_hash (); -#endif - - // Return the class lookup hash table - return class_hash; + // Return the class lookup hash table + return class_hash; } /*********************************************************************** - * _objc_defaultClassHandler. Default objc_classHandler. Does nothing. - **********************************************************************/ +* _objc_defaultClassHandler. Default objc_classHandler. Does nothing. +**********************************************************************/ static int _objc_defaultClassHandler (const char * clsName) { - // Return zero so objc_getClass doesn't bother re-searching - return 0; + // Return zero so objc_getClass doesn't bother re-searching + return 0; } /*********************************************************************** - * objc_setClassHandler. Set objc_classHandler to the specified value. - * - * NOTE: This should probably deal with userSuppliedHandler being NULL, - * because the objc_classHandler caller does not check... it would bus - * error. It would make sense to handle NULL by restoring the default - * handler. Is anyone hacking with this, though? - **********************************************************************/ +* objc_setClassHandler. Set objc_classHandler to the specified value. +* +* NOTE: This should probably deal with userSuppliedHandler being NULL, +* because the objc_classHandler caller does not check... it would bus +* error. It would make sense to handle NULL by restoring the default +* handler. Is anyone hacking with this, though? +**********************************************************************/ void objc_setClassHandler (int (*userSuppliedHandler) (const char *)) { - objc_classHandler = userSuppliedHandler; + objc_classHandler = userSuppliedHandler; } /*********************************************************************** - * objc_getClass. Return the id of the named class. If the class does - * not exist, call the objc_classHandler routine with the class name. - * If the objc_classHandler returns a non-zero value, try once more to - * find the class. Default objc_classHandler always returns zero. - * objc_setClassHandler is how someone can install a non-default routine. - **********************************************************************/ +* objc_getClass. Return the id of the named class. If the class does +* not exist, call the objc_classHandler routine with the class name. +* If the objc_classHandler returns a non-zero value, try once more to +* find the class. Default objc_classHandler always returns zero. +* objc_setClassHandler is how someone can install a non-default routine. +**********************************************************************/ id objc_getClass (const char * aClassName) -{ - struct objc_class cls; - id ret; - - // Synchronize access to hash table - OBJC_LOCK (&classLock); - - // Check the hash table - cls.name = aClassName; - ret = (id) NXHashGet (class_hash, &cls); - OBJC_UNLOCK (&classLock); - - // If not found, go call objc_classHandler and try again - if (!ret && (*objc_classHandler)(aClassName)) - { - OBJC_LOCK (&classLock); - ret = (id) NXHashGet (class_hash, &cls); - OBJC_UNLOCK (&classLock); - } - - return ret; +{ + struct objc_class cls; + id ret; + + // Synchronize access to hash table + OBJC_LOCK (&classLock); + + // Check the hash table + cls.name = aClassName; + ret = (id) NXHashGet (class_hash, &cls); + OBJC_UNLOCK (&classLock); + + // If not found, go call objc_classHandler and try again + if (!ret && (*objc_classHandler)(aClassName)) + { + OBJC_LOCK (&classLock); + ret = (id) NXHashGet (class_hash, &cls); + OBJC_UNLOCK (&classLock); + } + + return ret; } /*********************************************************************** - * objc_lookUpClass. Return the id of the named class. - * - * Formerly objc_getClassWithoutWarning () - **********************************************************************/ +* objc_lookUpClass. Return the id of the named class. +* +* Formerly objc_getClassWithoutWarning () +**********************************************************************/ id objc_lookUpClass (const char * aClassName) -{ - struct objc_class cls; - id ret; - - // Synchronize access to hash table - OBJC_LOCK (&classLock); - - // Check the hash table - cls.name = aClassName; - ret = (id) NXHashGet (class_hash, &cls); - - // Desynchronize - OBJC_UNLOCK (&classLock); - return ret; +{ + struct objc_class cls; + id ret; + + // Synchronize access to hash table + OBJC_LOCK (&classLock); + + // Check the hash table + cls.name = aClassName; + ret = (id) NXHashGet (class_hash, &cls); + + // Desynchronize + OBJC_UNLOCK (&classLock); + return ret; } /*********************************************************************** - * objc_getMetaClass. Return the id of the meta class the named class. - **********************************************************************/ -id objc_getMetaClass (const char * aClassName) -{ - struct objc_class * cls; - - cls = objc_getClass (aClassName); - if (!cls) - { - _objc_inform ("class `%s' not linked into application", aClassName); - return Nil; - } - - return cls->isa; +* objc_getMetaClass. Return the id of the meta class the named class. +**********************************************************************/ +id objc_getMetaClass (const char * aClassName) +{ + struct objc_class * cls; + + cls = objc_getClass (aClassName); + if (!cls) + { + _objc_inform ("class `%s' not linked into application", aClassName); + return Nil; + } + + return cls->isa; } /*********************************************************************** - * objc_addClass. Add the specified class to the table of known classes, - * after doing a little verification and fixup. - **********************************************************************/ -void objc_addClass (Class cls) +* objc_addClass. Add the specified class to the table of known classes, +* after doing a little verification and fixup. +**********************************************************************/ +void objc_addClass (Class cls) { - // Synchronize access to hash table - OBJC_LOCK (&classLock); - - // Make sure both the class and the metaclass have caches! - // Clear all bits of the info fields except CLS_CLASS and CLS_META. - // Normally these bits are already clear but if someone tries to cons - // up their own class on the fly they might need to be cleared. - if (((struct objc_class *)cls)->cache == NULL) - { - ((struct objc_class *)cls)->cache = (Cache) &emptyCache; - ((struct objc_class *)cls)->info = CLS_CLASS; - } - - if (((struct objc_class *)cls)->isa->cache == NULL) - { - ((struct objc_class *)cls)->isa->cache = (Cache) &emptyCache; - ((struct objc_class *)cls)->isa->info = CLS_META; - } - - // Add the class to the table - (void) NXHashInsert (class_hash, cls); - - // Desynchronize - OBJC_UNLOCK (&classLock); + // Synchronize access to hash table + OBJC_LOCK (&classLock); + + // Make sure both the class and the metaclass have caches! + // Clear all bits of the info fields except CLS_CLASS and CLS_META. + // Normally these bits are already clear but if someone tries to cons + // up their own class on the fly they might need to be cleared. + if (((struct objc_class *)cls)->cache == NULL) + { + ((struct objc_class *)cls)->cache = (Cache) &emptyCache; + ((struct objc_class *)cls)->info = CLS_CLASS; + } + + if (((struct objc_class *)cls)->isa->cache == NULL) + { + ((struct objc_class *)cls)->isa->cache = (Cache) &emptyCache; + ((struct objc_class *)cls)->isa->info = CLS_META; + } + + // Add the class to the table + (void) NXHashInsert (class_hash, cls); + + // Desynchronize + OBJC_UNLOCK (&classLock); } /*********************************************************************** - * _objcTweakMethodListPointerForClass. - **********************************************************************/ +* _objcTweakMethodListPointerForClass. +**********************************************************************/ static void _objcTweakMethodListPointerForClass (struct objc_class * cls) { - struct objc_method_list * originalList; - const int initialEntries = 4; - int mallocSize; - struct objc_method_list ** ptr; - - // Remember existing list - originalList = (struct objc_method_list *) cls->methodLists; - - // Allocate and zero a method list array - mallocSize = sizeof(struct objc_method_list *) * initialEntries; - ptr = (struct objc_method_list **) malloc_zone_calloc (_objc_create_zone (), 1, mallocSize); - - // Insert the existing list into the array - ptr[initialEntries - 1] = END_OF_METHODS_LIST; - ptr[0] = originalList; - - // Replace existing list with array - ((struct objc_class *)cls)->methodLists = ptr; - ((struct objc_class *)cls)->info |= CLS_METHOD_ARRAY; - - // Do the same thing to the meta-class - if (((((struct objc_class *)cls)->info & CLS_CLASS) != 0) && cls->isa) - _objcTweakMethodListPointerForClass (cls->isa); + struct objc_method_list * originalList; + const int initialEntries = 4; + int mallocSize; + struct objc_method_list ** ptr; + + // Remember existing list + originalList = (struct objc_method_list *) cls->methodLists; + + // Allocate and zero a method list array + mallocSize = sizeof(struct objc_method_list *) * initialEntries; + ptr = (struct objc_method_list **) malloc_zone_calloc (_objc_create_zone (), 1, mallocSize); + + // Insert the existing list into the array + ptr[initialEntries - 1] = END_OF_METHODS_LIST; + ptr[0] = originalList; + + // Replace existing list with array + ((struct objc_class *)cls)->methodLists = ptr; + ((struct objc_class *)cls)->info |= CLS_METHOD_ARRAY; + + // Do the same thing to the meta-class + if (((((struct objc_class *)cls)->info & CLS_CLASS) != 0) && cls->isa) + _objcTweakMethodListPointerForClass (cls->isa); } /*********************************************************************** - * _objc_insertMethods. - **********************************************************************/ +* _objc_insertMethods. +**********************************************************************/ void _objc_insertMethods (struct objc_method_list * mlist, - struct objc_method_list *** list) + struct objc_method_list *** list) { - struct objc_method_list ** ptr; - volatile struct objc_method_list ** tempList; - int endIndex; - int oldSize; - int newSize; - - // Locate unused entry for insertion point - ptr = *list; - while ((*ptr != 0) && (*ptr != END_OF_METHODS_LIST)) - ptr += 1; - - // If array is full, double it - if (*ptr == END_OF_METHODS_LIST) - { - // Calculate old and new dimensions - endIndex = ptr - *list; - oldSize = (endIndex + 1) * sizeof(void *); - newSize = oldSize + sizeof(struct objc_method_list *); // only increase by 1 - - // Replace existing array with copy twice its size - tempList = (struct objc_method_list **) malloc_zone_realloc ((void *) _objc_create_zone (), - (void *) *list, - (size_t) newSize); - *list = tempList; - - // Zero out addition part of new array - bzero (&((*list)[endIndex]), newSize - oldSize); - - // Place new end marker - (*list)[(newSize/sizeof(void *)) - 1] = END_OF_METHODS_LIST; - - // Insertion point corresponds to old array end - ptr = &((*list)[endIndex]); - } - - // Right shift existing entries by one - bcopy (*list, (*list) + 1, ((void *) ptr) - ((void *) *list)); - - // Insert at method list at beginning of array - **list = mlist; + struct objc_method_list ** ptr; + volatile struct objc_method_list ** tempList; + int endIndex; + int oldSize; + int newSize; + + // Locate unused entry for insertion point + ptr = *list; + while ((*ptr != 0) && (*ptr != END_OF_METHODS_LIST)) + ptr += 1; + + // If array is full, double it + if (*ptr == END_OF_METHODS_LIST) + { + // Calculate old and new dimensions + endIndex = ptr - *list; + oldSize = (endIndex + 1) * sizeof(void *); + newSize = oldSize + sizeof(struct objc_method_list *); // only increase by 1 + + // Replace existing array with copy twice its size + tempList = (struct objc_method_list **) malloc_zone_realloc ((void *) _objc_create_zone (), + (void *) *list, + (size_t) newSize); + *list = tempList; + + // Zero out addition part of new array + bzero (&((*list)[endIndex]), newSize - oldSize); + + // Place new end marker + (*list)[(newSize/sizeof(void *)) - 1] = END_OF_METHODS_LIST; + + // Insertion point corresponds to old array end + ptr = &((*list)[endIndex]); + } + + // Right shift existing entries by one + bcopy (*list, (*list) + 1, ((void *) ptr) - ((void *) *list)); + + // Insert at method list at beginning of array + **list = mlist; } /*********************************************************************** - * _objc_removeMethods. - **********************************************************************/ +* _objc_removeMethods. +**********************************************************************/ void _objc_removeMethods (struct objc_method_list * mlist, - struct objc_method_list *** list) + struct objc_method_list *** list) { - struct objc_method_list ** ptr; - - // Locate list in the array - ptr = *list; - while (*ptr != mlist) { - // fix for radar # 2538790 - if ( *ptr == END_OF_METHODS_LIST ) return; - ptr += 1; - } - - // Remove this entry - *ptr = 0; - - // Left shift the following entries - while (*(++ptr) != END_OF_METHODS_LIST) - *(ptr-1) = *ptr; - *(ptr-1) = 0; + struct objc_method_list ** ptr; + + // Locate list in the array + ptr = *list; + while (*ptr != mlist) { + // fix for radar # 2538790 + if ( *ptr == END_OF_METHODS_LIST ) return; + ptr += 1; + } + + // Remove this entry + *ptr = 0; + + // Left shift the following entries + while (*(++ptr) != END_OF_METHODS_LIST) + *(ptr-1) = *ptr; + *(ptr-1) = 0; } /*********************************************************************** - * __objc_add_category. Install the specified category's methods and - * protocols into the class it augments. - **********************************************************************/ -static inline void __objc_add_category (struct objc_category * category, - int version) +* _objc_add_category. Install the specified category's methods and +* protocols into the class it augments. +**********************************************************************/ +static inline void _objc_add_category(struct objc_class *cls, struct objc_category *category, int version) { - struct objc_class * cls; - - // Locate the class that the category will extend - cls = (struct objc_class *) objc_getClass (category->class_name); - if (!cls) - { - _objc_inform ("unable to add category %s...\n", category->category_name); - _objc_inform ("class `%s' not linked into application\n", category->class_name); - return; - } - - // Augment instance methods - if (category->instance_methods) - _objc_insertMethods (category->instance_methods, &cls->methodLists); - - // Augment class methods - if (category->class_methods) - _objc_insertMethods (category->class_methods, &cls->isa->methodLists); - - // Augment protocols - if ((version >= 5) && category->protocols) - { - if (cls->isa->version >= 5) - { - category->protocols->next = cls->protocols; - cls->protocols = category->protocols; - cls->isa->protocols = category->protocols; - } - else - { - _objc_inform ("unable to add protocols from category %s...\n", category->category_name); - _objc_inform ("class `%s' must be recompiled\n", category->class_name); - } - } - -#if defined(NeXT_PDO) // GENERIC_OBJ_FILE - // Call back - if (load_class_callback) - (*load_class_callback) (cls, 0); - - // Call +finishLoading:: from the category's method list - send_load_message_to_category (category, (void *) header_vector[0].mhdr); -#endif + // Augment instance methods + if (category->instance_methods) + _objc_insertMethods (category->instance_methods, &cls->methodLists); + + // Augment class methods + if (category->class_methods) + _objc_insertMethods (category->class_methods, &cls->isa->methodLists); + + // Augment protocols + if ((version >= 5) && category->protocols) + { + if (cls->isa->version >= 5) + { + category->protocols->next = cls->protocols; + cls->protocols = category->protocols; + cls->isa->protocols = category->protocols; + } + else + { + _objc_inform ("unable to add protocols from category %s...\n", category->category_name); + _objc_inform ("class `%s' must be recompiled\n", category->class_name); + } + } } /*********************************************************************** - * _objc_add_category. Install the specified category's methods into - * the class it augments, and flush the class' method cache. - * - * Private extern used by objc_loadModules () - **********************************************************************/ -void _objc_add_category (struct objc_category * category, - int version) +* _objc_add_category_flush_caches. Install the specified category's methods into +* the class it augments, and flush the class' method cache. +* +**********************************************************************/ +static void _objc_add_category_flush_caches(struct objc_class *cls, struct objc_category *category, int version) { - // Install the category's methods into its intended class - __objc_add_category (category, version); - - // Flush caches so category's methods can get called - _objc_flush_caches (objc_lookUpClass (category->class_name)); + // Install the category's methods into its intended class + _objc_add_category (cls, category, version); + + // Flush caches so category's methods can get called + _objc_flush_caches (cls); } /*********************************************************************** - * _objc_resolve_categories_for_class. Install all categories intended - * for the specified class, in reverse order from the order in which we - * found the categories in the image. - **********************************************************************/ -static void _objc_resolve_categories_for_class (struct objc_class * cls) +* _objc_resolve_categories_for_class. Install all categories intended +* for the specified class, in reverse order from the order in which we +* found the categories in the image. +* This is done as lazily as we can. +**********************************************************************/ +void _objc_resolve_categories_for_class (struct objc_class * cls) { - _objc_unresolved_category * cat; - _objc_unresolved_category * next; - - // Nothing to do if there are no categories at all - if (!category_hash) - return; - - // Locate and remove first element in category list - // associated with this class - cat = NXMapRemove (category_hash, cls->name); - - // Traverse the list of categories, if any, registered for this class - while (cat) - { - // Install the category - _objc_add_category (cat->cat, cat->version); - - // Delink and reclaim this registration - next = cat->next; - free (cat); - cat = next; - } + _objc_unresolved_category * cat; + _objc_unresolved_category * next; + + // Nothing to do if there are no categories at all + if (!category_hash) + return; + + // Locate and remove first element in category list + // associated with this class + cat = NXMapRemove (category_hash, cls->name); + + // Traverse the list of categories, if any, registered for this class + while (cat) + { + if (cat->bindme) { + _objc_bindModuleContainingCategory(cat->cat); + } + // Install the category + // use the non-flush-cache version since we are only + // called from the class intialization code + _objc_add_category (cls, cat->cat, cat->version); + + // Delink and reclaim this registration + next = cat->next; + free (cat); + cat = next; + } } /*********************************************************************** - * _objc_register_category. Add the specified category to the registry - * of categories to be installed later (once we know for sure which - * classes we have). If there are multiple categories on a given class, - * they will be processed in reverse order from the order in which they - * were found in the image. - **********************************************************************/ +* _objc_register_category. Add the specified category to the registry +* of categories to be installed later (once we know for sure which + * classes we have). If there are multiple categories on a given class, +* they will be processed in reverse order from the order in which they +* were found in the image. +**********************************************************************/ static void _objc_register_category (struct objc_category * cat, - long version) + long version, + int bindme) { - _objc_unresolved_category * new_cat; - _objc_unresolved_category * old; - - - // If the category's class exists, just add the category - if (objc_lookUpClass (cat->class_name)) - { - _objc_add_category (cat, version); - return; - } - - // Create category lookup table if needed - if (!category_hash) - category_hash = NXCreateMapTableFromZone (NXStrValueMapPrototype, - 128, - _objc_create_zone ()); - - // Locate an existing category, if any, for the class. This is linked - // after the new entry, so list is LIFO. - old = NXMapGet (category_hash, cat->class_name); - - // Register the category to be fixed up later - new_cat = malloc_zone_malloc (_objc_create_zone (), - sizeof(_objc_unresolved_category)); - new_cat->next = old; - new_cat->cat = cat; - new_cat->version = version; - (void) NXMapInsert (category_hash, cat->class_name , new_cat); + _objc_unresolved_category * new_cat; + _objc_unresolved_category * old; + struct objc_class *theClass; + + + // If the category's class exists, just add the category + // We could check to see if its initted, and if not, defer this + // work until _objc_resolve_categories_for_class for all cases + // The only trick then is whether we need to bind it. This + // might be doable if we store an obscured pointer so that we + // avoid touching the memory... [BG 5/2001 still in think mode] + if (theClass = objc_lookUpClass (cat->class_name)) + { + if (bindme) { + _objc_bindModuleContainingCategory(cat); + } + _objc_add_category_flush_caches (theClass, cat, version); + return; + } + + // Create category lookup table if needed + if (!category_hash) + category_hash = NXCreateMapTableFromZone (NXStrValueMapPrototype, + 128, + _objc_create_zone ()); + + // Locate an existing category, if any, for the class. This is linked + // after the new entry, so list is LIFO. + old = NXMapGet (category_hash, cat->class_name); + + // Register the category to be fixed up later + new_cat = malloc_zone_malloc (_objc_create_zone (), + sizeof(_objc_unresolved_category)); + new_cat->next = old; + new_cat->cat = cat; + new_cat->version = version; + new_cat->bindme = bindme; // could use a bit in the next pointer instead of a whole word + (void) NXMapInsert (category_hash, cat->class_name , new_cat); } /*********************************************************************** - * _objc_add_categories_from_image. - **********************************************************************/ +* _objc_add_categories_from_image. +**********************************************************************/ static void _objc_add_categories_from_image (header_info * hi) { - Module mods; - unsigned int midx; - - // Major loop - process all modules in the header - mods = (Module) ((unsigned long) hi->mod_ptr + hi->image_slide); - -// ptrace(0xb120, hi->mod_count, 0, 0); - - for (midx = 0; midx < hi->mod_count; midx += 1) - { - unsigned int index; - unsigned int total; - - // Nothing to do for a module without a symbol table - if (mods[midx].symtab == NULL) - continue; - - // Total entries in symbol table (class entries followed - // by category entries) - total = mods[midx].symtab->cls_def_cnt + - mods[midx].symtab->cat_def_cnt; - -#if defined(__MACH__) - if ((hi->mhdr->filetype == MH_DYLIB) || - (hi->mhdr->filetype == MH_BUNDLE)) - { - void ** defs; - - defs = mods[midx].symtab->defs; - -// ptrace(0xb121, midx, mods[midx].symtab->cls_def_cnt, mods[midx].symtab->cat_def_cnt); - - for (index = 0; index < mods[midx].symtab->cls_def_cnt; index += 1) - _objc_bindModuleContainingClass (defs[index]); - - for (index = mods[midx].symtab->cls_def_cnt; index < total; index += 1) - _objc_bindModuleContainingCategory (defs[index]); - -// ptrace(0xb122, midx, 0, 0); - } -#endif - -// ptrace(0xb123, midx, mods[midx].symtab->cat_def_cnt, 0); - - // Minor loop - register all categories from given module - for (index = mods[midx].symtab->cls_def_cnt; index < total; index += 1) - { - _objc_register_category (mods[midx].symtab->defs[index], - mods[midx].version); - } - -// ptrace(0xb124, midx, 0, 0); - } - -// ptrace(0xb12f, 0, 0, 0); + Module mods; + unsigned int midx; + int isDynamic = (hi->mhdr->filetype == MH_DYLIB) || (hi->mhdr->filetype == MH_BUNDLE); + + // Major loop - process all modules in the header + mods = (Module) ((unsigned long) hi->mod_ptr + hi->image_slide); + + trace(0xb120, hi->mod_count, 0, 0); + + for (midx = 0; midx < hi->mod_count; midx += 1) + { + unsigned int index; + unsigned int total; + + // Nothing to do for a module without a symbol table + if (mods[midx].symtab == NULL) + continue; + + // Total entries in symbol table (class entries followed + // by category entries) + total = mods[midx].symtab->cls_def_cnt + + mods[midx].symtab->cat_def_cnt; + + + trace(0xb123, midx, mods[midx].symtab->cat_def_cnt, 0); + + // Minor loop - register all categories from given module + for (index = mods[midx].symtab->cls_def_cnt; index < total; index += 1) + { + _objc_register_category(mods[midx].symtab->defs[index], mods[midx].version, isDynamic); + } + + trace(0xb124, midx, 0, 0); + } + + trace(0xb12f, 0, 0, 0); } -#if defined(__MACH__) /*********************************************************************** - * _headerForClass. - **********************************************************************/ +* _headerForClass. +**********************************************************************/ static const header_info * _headerForClass (struct objc_class * cls) { - const struct segment_command * objcSeg; - unsigned int hidx; - unsigned int size; - unsigned long vmaddrPlus; - - // Check all headers in the vector - for (hidx = 0; hidx < header_count; hidx += 1) - { - // Locate header data, if any - objcSeg = _getObjcHeaderData ((headerType *) header_vector[hidx].mhdr, &size); - if (!objcSeg) - continue; - - // Is the class in this header? - vmaddrPlus = (unsigned long) objcSeg->vmaddr + header_vector[hidx].image_slide; - if ((vmaddrPlus <= (unsigned long) cls) && - ((unsigned long) cls < (vmaddrPlus + size))) - return &(header_vector[hidx]); - } - - // Not found - return 0; + const struct segment_command * objcSeg; + unsigned int size; + unsigned long vmaddrPlus; + header_info * hInfo; + + // Check all headers in the vector + for (hInfo = FirstHeader; hInfo != NULL; hInfo = hInfo->next) + { + // Locate header data, if any + objcSeg = _getObjcHeaderData ((headerType *) hInfo->mhdr, &size); + if (!objcSeg) + continue; + + // Is the class in this header? + vmaddrPlus = (unsigned long) objcSeg->vmaddr + hInfo->image_slide; + if ((vmaddrPlus <= (unsigned long) cls) && + ((unsigned long) cls < (vmaddrPlus + size))) + return hInfo; + } + + // Not found + return 0; } -#endif // __MACH__ /*********************************************************************** - * _nameForHeader. - **********************************************************************/ +* _nameForHeader. +**********************************************************************/ const char * _nameForHeader (const headerType * header) { - return _getObjcHeaderName ((headerType *) header); + return _getObjcHeaderName ((headerType *) header); } /*********************************************************************** - * checkForPendingClassReferences. Complete any fixups registered for - * this class. - **********************************************************************/ -static void checkForPendingClassReferences (struct objc_class * cls) +* checkForPendingClassReferences. Complete any fixups registered for +* this class. +**********************************************************************/ +static void _objc_checkForPendingClassReferences (struct objc_class * cls) { - PendingClass * pending; - - // Nothing to do if there are no pending classes - if (!pendingClassRefsMap) - return; - - // Get pending list for this class - pending = NXMapGet (pendingClassRefsMap, cls->name); - if (!pending) - return; - - // Remove the list from the table - (void) NXMapRemove (pendingClassRefsMap, cls->name); - - // Process all elements in the list - while (pending) - { - PendingClass * next; - - // Remember follower for loop - next = pending->next; - - // Fill in a pointer to Class - // (satisfies caller of objc_pendClassReference) - if (pending->ref) - *pending->ref = objc_getClass (cls->name); - - // Fill in super, isa, cache, and version for the class - // and its meta-class - // (satisfies caller of objc_pendClassInstallation) - // NOTE: There must be no more than one of these for - // any given classToSetUp - if (pending->classToSetUp) - { - struct objc_class * fixCls; - - // Locate the Class to be fixed up - fixCls = pending->classToSetUp; - - // Set up super class fields with names to be replaced by pointers - fixCls->super_class = (struct objc_class *) pending->nameof_superclass; - fixCls->isa->super_class = (struct objc_class *) pending->nameof_superclass; - - // Fix up class pointers, version, and cache pointers - _class_install_relationships (fixCls, pending->version); - } - - // Reclaim the element - free (pending); - - // Move on - pending = next; - } + PendingClass * pending; + + // Nothing to do if there are no pending classes + if (!pendingClassRefsMap) + return; + + // Get pending list for this class + pending = NXMapGet (pendingClassRefsMap, cls->name); + if (!pending) + return; + + // Remove the list from the table + (void) NXMapRemove (pendingClassRefsMap, cls->name); + + // Process all elements in the list + while (pending) + { + PendingClass * next; + + // Remember follower for loop + next = pending->next; + + // Fill in a pointer to Class + // (satisfies caller of objc_pendClassReference) + if (pending->ref) + *pending->ref = objc_getClass (cls->name); + + // Fill in super, isa, cache, and version for the class + // and its meta-class + // (satisfies caller of objc_pendClassInstallation) + // NOTE: There must be no more than one of these for + // any given classToSetUp + if (pending->classToSetUp) + { + struct objc_class * fixCls; + + // Locate the Class to be fixed up + fixCls = pending->classToSetUp; + + // Set up super class fields with names to be replaced by pointers + fixCls->super_class = (struct objc_class *) pending->nameof_superclass; + fixCls->isa->super_class = (struct objc_class *) pending->nameof_superclass; + + // Fix up class pointers, version, and cache pointers + _class_install_relationships (fixCls, pending->version); + } + + // Reclaim the element + free (pending); + + // Move on + pending = next; + } } /*********************************************************************** - * newPending. Allocate and zero a PendingClass structure. - **********************************************************************/ +* newPending. Allocate and zero a PendingClass structure. +**********************************************************************/ static inline PendingClass * newPending (void) { - PendingClass * pending; - - pending = (PendingClass *) malloc_zone_calloc (_objc_create_zone (), 1, sizeof(PendingClass)); - - return pending; + PendingClass * pending; + + pending = (PendingClass *) malloc_zone_calloc (_objc_create_zone (), 1, sizeof(PendingClass)); + + return pending; } /*********************************************************************** - * pendingClassRefsMapTable. Return a pointer to the lookup table for - * pending classes. - **********************************************************************/ +* pendingClassRefsMapTable. Return a pointer to the lookup table for +* pending classes. +**********************************************************************/ static inline NXMapTable * pendingClassRefsMapTable (void) { - // Allocate table if needed - if (!pendingClassRefsMap) - pendingClassRefsMap = NXCreateMapTableFromZone (NXStrValueMapPrototype, 10, _objc_create_zone ()); - - // Return table pointer - return pendingClassRefsMap; + // Allocate table if needed + if (!pendingClassRefsMap) + pendingClassRefsMap = NXCreateMapTableFromZone (NXStrValueMapPrototype, 10, _objc_create_zone ()); + + // Return table pointer + return pendingClassRefsMap; } /*********************************************************************** - * objc_pendClassReference. Register the specified class pointer (ref) - * to be filled in later with a pointer to the class having the specified - * name. - **********************************************************************/ +* objc_pendClassReference. Register the specified class pointer (ref) +* to be filled in later with a pointer to the class having the specified +* name. +**********************************************************************/ void objc_pendClassReference (const char * className, - struct objc_class * * ref) + struct objc_class * * ref) { - NXMapTable * table; - PendingClass * pending; - - // Create and/or locate pending class lookup table - table = pendingClassRefsMapTable (); - - // Create entry containing the class reference - pending = newPending (); - pending->ref = ref; - - // Link new entry into head of list of entries for this class - pending->next = NXMapGet (pendingClassRefsMap, className); - - // (Re)place entry list in the table - (void) NXMapInsert (table, className, pending); + NXMapTable * table; + PendingClass * pending; + + // Create and/or locate pending class lookup table + table = pendingClassRefsMapTable (); + + // Create entry containing the class reference + pending = newPending (); + pending->ref = ref; + + // Link new entry into head of list of entries for this class + pending->next = NXMapGet (pendingClassRefsMap, className); + + // (Re)place entry list in the table + (void) NXMapInsert (table, className, pending); } /*********************************************************************** - * objc_pendClassInstallation. Register the specified class to have its - * super class pointers filled in later because the superclass is not - * yet found. - **********************************************************************/ -void objc_pendClassInstallation (struct objc_class * cls, - int version) +* objc_pendClassInstallation. Register the specified class to have its +* super class pointers filled in later because the superclass is not +* yet found. +**********************************************************************/ +void objc_pendClassInstallation (struct objc_class *cls, int version) { - NXMapTable * table; - PendingClass * pending; - - // Create and/or locate pending class lookup table - table = pendingClassRefsMapTable (); - - // Create entry referring to this class - pending = newPending (); - pending->classToSetUp = cls; - pending->nameof_superclass = (const char *) cls->super_class; - pending->version = version; - - // Link new entry into head of list of entries for this class - pending->next = NXMapGet (pendingClassRefsMap, cls->super_class); - - // (Re)place entry list in the table - (void) NXMapInsert (table, cls->super_class, pending); + NXMapTable * table; + PendingClass * pending; + + // Create and/or locate pending class lookup table + table = pendingClassRefsMapTable (); + + // Create entry referring to this class + pending = newPending (); + pending->classToSetUp = cls; + pending->nameof_superclass = (const char *) cls->super_class; + pending->version = version; + + // Link new entry into head of list of entries for this class + pending->next = NXMapGet (pendingClassRefsMap, cls->super_class); + + // (Re)place entry list in the table + (void) NXMapInsert (table, cls->super_class, pending); } /*********************************************************************** - * _objc_get_classes_from_image. Install all classes contained in the - * specified image. - **********************************************************************/ -static NXHashTable * _objc_get_classes_from_image (NXHashTable * clsHash, - header_info * hi) +* _objc_add_classes_from_image. Install all classes contained in the +* specified image. +**********************************************************************/ +static void _objc_add_classes_from_image(NXHashTable *clsHash, header_info *hi) { - unsigned int index; - unsigned int midx; - Module mods; - - // Major loop - process all modules in the image - mods = (Module) ((unsigned long) hi->mod_ptr + hi->image_slide); - for (midx = 0; midx < hi->mod_count; midx += 1) - { - // Skip module containing no classes - if (mods[midx].symtab == NULL) - continue; - - // Minor loop - process all the classes in given module - for (index = 0; index < mods[midx].symtab->cls_def_cnt; index += 1) - { - struct objc_class * oldCls; - struct objc_class * newCls; - - // Locate the class description pointer - newCls = mods[midx].symtab->defs[index]; - - // Convert old style method list to the new style - _objcTweakMethodListPointerForClass (newCls); - - oldCls = NXHashInsert (clsHash, newCls); - - // Non-Nil oldCls is a class that NXHashInsert just - // bumped from table because it has the same name - // as newCls - if (oldCls) - { -#if defined(__MACH__) - const header_info * oldHeader; - const header_info * newHeader; - const char * oldName; - const char * newName; - - // Log the duplication - oldHeader = _headerForClass (oldCls); - newHeader = _headerForClass (newCls); - oldName = _nameForHeader (oldHeader->mhdr); - newName = _nameForHeader (newHeader->mhdr); - _objc_inform ("Both %s and %s have implementations of class %s.", - oldName, newName, oldCls->name); - _objc_inform ("Using implementation from %s.", newName); -#endif - - // Use the chosen class - // NOTE: Isn't this a NOP? - newCls = objc_lookUpClass (oldCls->name); - } - - // Unless newCls was a duplicate, and we chose the - // existing one instead, set the version in the meta-class - if (newCls != oldCls) - newCls->isa->version = mods[midx].version; - - // Install new categories intended for this class - // NOTE: But, if we displaced an existing "isEqual" - // class, the categories have already been installed - // on an old class and are gone from the registry!! - _objc_resolve_categories_for_class (newCls); - - // Resolve (a) pointers to the named class, and/or - // (b) the super_class, cache, and version - // fields of newCls and its meta-class - // NOTE: But, if we displaced an existing "isEqual" - // class, this has already been done... with an - // old-now-"unused" class!! - checkForPendingClassReferences (newCls); - -#if defined(NeXT_PDO) // GENERIC_OBJ_FILE - // Invoke registered callback - if (load_class_callback) - (*load_class_callback) (newCls, 0); - - // Call +finishLoading:: from the class' method list - send_load_message_to_class (newCls, (headerType *) hi->mhdr); -#endif - } - } - - // Return the table the caller passed - return clsHash; + unsigned int index; + unsigned int midx; + Module mods; + int isDynamic = (hi->mhdr->filetype == MH_DYLIB) || (hi->mhdr->filetype == MH_BUNDLE); + + // Major loop - process all modules in the image + mods = (Module) ((unsigned long) hi->mod_ptr + hi->image_slide); + for (midx = 0; midx < hi->mod_count; midx += 1) + { + // Skip module containing no classes + if (mods[midx].symtab == NULL) + continue; + + // Minor loop - process all the classes in given module + for (index = 0; index < mods[midx].symtab->cls_def_cnt; index += 1) + { + struct objc_class * oldCls; + struct objc_class * newCls; + + // Locate the class description pointer + newCls = mods[midx].symtab->defs[index]; + + // remember to bind the module on initialization + if (isDynamic) + newCls->info |= CLS_NEED_BIND ; + + // Convert old style method list to the new style + _objcTweakMethodListPointerForClass (newCls); + + oldCls = NXHashInsert (clsHash, newCls); + + // Non-Nil oldCls is a class that NXHashInsert just + // bumped from table because it has the same name + // as newCls + if (oldCls) + { + const header_info * oldHeader; + const header_info * newHeader; + const char * oldName; + const char * newName; + + // Log the duplication + oldHeader = _headerForClass (oldCls); + newHeader = _headerForClass (newCls); + oldName = _nameForHeader (oldHeader->mhdr); + newName = _nameForHeader (newHeader->mhdr); + _objc_inform ("Both %s and %s have implementations of class %s.", + oldName, newName, oldCls->name); + _objc_inform ("Using implementation from %s.", newName); + + // Use the chosen class + // NOTE: Isn't this a NOP? + newCls = objc_lookUpClass (oldCls->name); + } + + // Unless newCls was a duplicate, and we chose the + // existing one instead, set the version in the meta-class + if (newCls != oldCls) + newCls->isa->version = mods[midx].version; + + // Install new categories intended for this class + // NOTE: But, if we displaced an existing "isEqual" + // class, the categories have already been installed + // on an old class and are gone from the registry!! + + // we defer this work until the class is initialized. + //_objc_resolve_categories_for_class (newCls); + + // Resolve (a) pointers to the named class, and/or + // (b) the super_class, cache, and version + // fields of newCls and its meta-class + // NOTE: But, if we displaced an existing "isEqual" + // class, this has already been done... with an + // old-now-"unused" class!! + _objc_checkForPendingClassReferences (newCls); + + } + } } /*********************************************************************** - * _objc_fixup_string_objects_for_image. Initialize the isa pointers - * of all NSConstantString objects. - **********************************************************************/ +* _objc_fixup_string_objects_for_image. Initialize the isa pointers +* of all NSConstantString objects. +**********************************************************************/ static void _objc_fixup_string_objects_for_image (header_info * hi) { - unsigned int size; - OBJC_CONSTANT_STRING_PTR section; - struct objc_class * constantStringClass; - unsigned int index; - - // Locate section holding string objects - section = _getObjcStringObjects ((headerType *) hi->mhdr, &size); - if (!section || !size) - return; - section = (OBJC_CONSTANT_STRING_PTR) ((unsigned long) section + hi->image_slide); -#if defined(NeXT_PDO) // GENERIC_OBJ_FILE - if (!(*section)) - return; -#endif - - // Luckily NXConstantString is the same size as NSConstantString - constantStringClass = objc_getClass ("NSConstantString"); - - // Process each string object in the section - for (index = 0; index < size; index += 1) - { - struct objc_class * * isaptr; - - isaptr = (struct objc_class * *) OBJC_CONSTANT_STRING_DEREF section[index]; - if (*isaptr == 0) - *isaptr = constantStringClass; - } + unsigned int size; + OBJC_CONSTANT_STRING_PTR section; + struct objc_class * constantStringClass; + unsigned int index; + + // Locate section holding string objects + section = _getObjcStringObjects ((headerType *) hi->mhdr, &size); + if (!section || !size) + return; + section = (OBJC_CONSTANT_STRING_PTR) ((unsigned long) section + hi->image_slide); + + // Luckily NXConstantString is the same size as NSConstantString + constantStringClass = objc_getClass ("NSConstantString"); + + // Process each string object in the section + for (index = 0; index < size; index += 1) + { + struct objc_class * * isaptr; + + isaptr = (struct objc_class * *) OBJC_CONSTANT_STRING_DEREF section[index]; + if (*isaptr == 0) + *isaptr = constantStringClass; + } } /*********************************************************************** - * _objc_map_class_refs_for_image. Convert the class ref entries from - * a class name string pointer to a class pointer. If the class does - * not yet exist, the reference is added to a list of pending references - * to be fixed up at a later date. - **********************************************************************/ +* _objc_map_class_refs_for_image. Convert the class ref entries from +* a class name string pointer to a class pointer. If the class does +* not yet exist, the reference is added to a list of pending references +* to be fixed up at a later date. +**********************************************************************/ static void _objc_map_class_refs_for_image (header_info * hi) { - struct objc_class * * cls_refs; - unsigned int size; - unsigned int index; - - // Locate class refs in image - cls_refs = _getObjcClassRefs ((headerType *) hi->mhdr, &size); - if (!cls_refs) - return; - cls_refs = (struct objc_class * *) ((unsigned long) cls_refs + hi->image_slide); - - // Process each class ref - for (index = 0; index < size; index += 1) - { - const char * ref; - struct objc_class * cls; - - // Get ref to convert from name string to class pointer - ref = (const char *) cls_refs[index]; - - // Get pointer to class of this name - cls = (struct objc_class *)objc_lookUpClass (ref); - - // If class isn't there yet, use pending mechanism - if (!cls) - { - // Register this ref to be set later - objc_pendClassReference (ref, &cls_refs[index]); - - // Use place-holder class - cls_refs[index] = _objc_getNonexistentClass (); - } - - // Replace name string pointer with class pointer - else - cls_refs[index] = cls; - } + struct objc_class * * cls_refs; + unsigned int size; + unsigned int index; + + // Locate class refs in image + cls_refs = _getObjcClassRefs ((headerType *) hi->mhdr, &size); + if (!cls_refs) + return; + cls_refs = (struct objc_class * *) ((unsigned long) cls_refs + hi->image_slide); + + // Process each class ref + for (index = 0; index < size; index += 1) + { + const char * ref; + struct objc_class * cls; + + // Get ref to convert from name string to class pointer + ref = (const char *) cls_refs[index]; + + // Get pointer to class of this name + cls = (struct objc_class *)objc_lookUpClass (ref); + + // If class isn't there yet, use pending mechanism + if (!cls) + { + // Register this ref to be set later + objc_pendClassReference (ref, &cls_refs[index]); + + // Use place-holder class + cls_refs[index] = _objc_getNonexistentClass (); + } + + // Replace name string pointer with class pointer + else + cls_refs[index] = cls; + } } /*********************************************************************** - * map_selrefs. Register each selector in the specified array. If a - * given selector is already registered, update this array to point to - * the registered selector string. - **********************************************************************/ -static inline void map_selrefs (SEL * sels, - unsigned int cnt) -{ - unsigned int index; - - // Process each selector - for (index = 0; index < cnt; index += 1) - { - SEL sel; - - // Lookup pointer to uniqued string - sel = sel_registerNameNoCopy ((const char *) sels[index]); - - // Replace this selector with uniqued one (avoid - // modifying the VM page if this would be a NOP) - if (sels[index] != sel) - sels[index] = sel; - } +* map_selrefs. Register each selector in the specified array. If a +* given selector is already registered, update this array to point to +* the registered selector string. +**********************************************************************/ +static inline void map_selrefs(SEL *sels, unsigned int cnt) +{ + unsigned int index; + + // Process each selector + for (index = 0; index < cnt; index += 1) + { + SEL sel; + + // Lookup pointer to uniqued string + sel = sel_registerNameNoCopy ((const char *) sels[index]); + + // Replace this selector with uniqued one (avoid + // modifying the VM page if this would be a NOP) + if (sels[index] != sel) + sels[index] = sel; + } } /*********************************************************************** - * map_method_descs. For each method in the specified method list, - * replace the name pointer with a uniqued selector. - **********************************************************************/ +* map_method_descs. For each method in the specified method list, +* replace the name pointer with a uniqued selector. +**********************************************************************/ static void map_method_descs (struct objc_method_description_list * methods) { - unsigned int index; - - // Process each method - for (index = 0; index < methods->count; index += 1) - { - struct objc_method_description * method; - SEL sel; - - // Get method entry to fix up - method = &methods->list[index]; - - // Lookup pointer to uniqued string - sel = sel_registerNameNoCopy ((const char *) method->name); - - // Replace this selector with uniqued one (avoid - // modifying the VM page if this would be a NOP) - if (method->name != sel) - method->name = sel; - } + unsigned int index; + + // Process each method + for (index = 0; index < methods->count; index += 1) + { + struct objc_method_description * method; + SEL sel; + + // Get method entry to fix up + method = &methods->list[index]; + + // Lookup pointer to uniqued string + sel = sel_registerNameNoCopy ((const char *) method->name); + + // Replace this selector with uniqued one (avoid + // modifying the VM page if this would be a NOP) + if (method->name != sel) + method->name = sel; + } } /*********************************************************************** - * _fixup. - **********************************************************************/ +* _fixup. +**********************************************************************/ @interface Protocol(RuntimePrivate) + _fixup: (OBJC_PROTOCOL_PTR)protos numElements: (int) nentries; @end /*********************************************************************** - * _objc_fixup_protocol_objects_for_image. For each protocol in the - * specified image, selectorize the method names and call +_fixup. - **********************************************************************/ +* _objc_fixup_protocol_objects_for_image. For each protocol in the +* specified image, selectorize the method names and call +_fixup. +**********************************************************************/ static void _objc_fixup_protocol_objects_for_image (header_info * hi) { - unsigned int size; - OBJC_PROTOCOL_PTR protos; - unsigned int index; - - // Locate protocals in the image - protos = (OBJC_PROTOCOL_PTR) _getObjcProtocols ((headerType *) hi->mhdr, &size); - if (!protos) - return; - - // Apply the slide bias - protos = (OBJC_PROTOCOL_PTR) ((unsigned long) protos + hi->image_slide); - - // Process each protocol - for (index = 0; index < size; index += 1) - { - // Selectorize the instance methods - if (protos[index] OBJC_PROTOCOL_DEREF instance_methods) - map_method_descs (protos[index] OBJC_PROTOCOL_DEREF instance_methods); - - // Selectorize the class methods - if (protos[index] OBJC_PROTOCOL_DEREF class_methods) - map_method_descs (protos[index] OBJC_PROTOCOL_DEREF class_methods); - } - - // Invoke Protocol class method to fix up the protocol - [Protocol _fixup:(OBJC_PROTOCOL_PTR)protos numElements:size]; + unsigned int size; + OBJC_PROTOCOL_PTR protos; + unsigned int index; + + // Locate protocals in the image + protos = (OBJC_PROTOCOL_PTR) _getObjcProtocols ((headerType *) hi->mhdr, &size); + if (!protos) + return; + + // Apply the slide bias + protos = (OBJC_PROTOCOL_PTR) ((unsigned long) protos + hi->image_slide); + + // Process each protocol + for (index = 0; index < size; index += 1) + { + // Selectorize the instance methods + if (protos[index] OBJC_PROTOCOL_DEREF instance_methods) + map_method_descs (protos[index] OBJC_PROTOCOL_DEREF instance_methods); + + // Selectorize the class methods + if (protos[index] OBJC_PROTOCOL_DEREF class_methods) + map_method_descs (protos[index] OBJC_PROTOCOL_DEREF class_methods); + } + + // Invoke Protocol class method to fix up the protocol + [Protocol _fixup:(OBJC_PROTOCOL_PTR)protos numElements:size]; } /*********************************************************************** - * _objc_headerVector. Build the header vector, sorting it as - * _objc_map_selectors () expects. - **********************************************************************/ -header_info * _objc_headerVector (const headerType * const * machhdrs) +* _objc_headerStart. Return what headers we know about. +**********************************************************************/ +header_info * _objc_headerStart () { - unsigned int hidx; - header_info * hdrVec; - -#if defined(__MACH__) // not GENERIC_OBJ_FILE - // Take advatage of our previous work - if (header_vector) - return header_vector; -#else // GENERIC_OBJ_FILE - // If no headers specified, vectorize generically - if (!machhdrs) - return _objc_goff_headerVector (); - - // Start from scratch - header_count = 0; -#endif - - // Count headers - for (hidx = 0; machhdrs[hidx]; hidx += 1) - header_count += 1; - - header_vector_size = header_count * 3; // very big - - // Allocate vector large enough to have entries for all of them - hdrVec = malloc_zone_malloc (_objc_create_zone (), - header_vector_size * sizeof(header_info)); - if (!hdrVec) - _objc_fatal ("unable to allocate module vector"); - - // Fill vector entry for each header - for (hidx = 0; hidx < header_count; hidx += 1) - { - int size; -#if defined(__MACH__) - const struct segment_command * objcSeg = NULL; -#endif - - hdrVec[hidx].mhdr = machhdrs[hidx]; - hdrVec[hidx].image_slide = 0; - hdrVec[hidx].mod_ptr = _getObjcModules ((headerType *) machhdrs[hidx], &size); - hdrVec[hidx].mod_count = size; - hdrVec[hidx].objcSize = 0; - -#if defined(__MACH__) // not GENERIC_OBJ_FILE - objcSeg = (struct segment_command *) _getObjcHeaderData ((headerType *) machhdrs[hidx], &size); - if (objcSeg) - hdrVec[hidx].objcSize = ((struct segment_command *) objcSeg)->filesize; -#endif - } - - return hdrVec; + + // Take advatage of our previous work + return FirstHeader; } -#if defined(__MACH__) void _objc_bindModuleContainingList() { -/* We define this for backwards binary compat with things which should not - * have been using it (cough OmniWeb), but now it does nothing for them. - */ + /* We define this for backwards binary compat with things which should not + * have been using it (cough OmniWeb), but now it does nothing for them. + */ +} + +/********************************************************************** +* _objc_bind_symbol. Bind the module containing the symbol. Use 2-level namespace API +* Only look in images that we know to have ObjC symbols (e.g. 9 for Mail 7/2001) +* Radar 2701686 +***********************************************************************/ +static void _objc_bind_symbol(const char *name) +{ + int i; + static header_info *lastHeader = NULL; + header_info *hInfo; + const headerType *imageHeader = lastHeader ? lastHeader->mhdr : NULL; + + // Ideally we would have a way to not even process a symbol in a module + // we've already visited + + + // First assume there is some locality and search where we last found a symbol + if ( imageHeader + && NSIsSymbolNameDefinedInImage(imageHeader, name) + && NSLookupSymbolInImage(imageHeader, name, NSLOOKUPSYMBOLINIMAGE_OPTION_BIND) != NULL ) + { + // Found + return; + } + + // Symbol wasn't found in the image we last searched + // Search in all the images known to contain ObjcC + for ( hInfo = FirstHeader; hInfo != NULL; hInfo = hInfo->next) + { + imageHeader = hInfo->mhdr; + if ( hInfo != lastHeader + && NSIsSymbolNameDefinedInImage(imageHeader, name) + && NSLookupSymbolInImage(imageHeader, name, NSLOOKUPSYMBOLINIMAGE_OPTION_BIND) != NULL ) + { + // found + lastHeader = hInfo; + return; + } + } + // die now, or later ?? + // _objc_fatal("could not find %s", name); } /*********************************************************************** - * _objc_bindModuleContainingCategory. Bind the module containing the - * category. - **********************************************************************/ +* _objc_bindModuleContainingCategory. Bind the module containing the +* category. +**********************************************************************/ static void _objc_bindModuleContainingCategory (Category cat) { - char * class_name; - char * category_name; - char * name; - char tmp_buf[128]; - unsigned int name_len; - - // Bind ".objc_category_name__", - // where is the class name with the leading - // '%'s stripped. - class_name = cat->class_name; - category_name = cat->category_name; - name_len = strlen(class_name) + strlen(category_name) + 30; - if ( name_len > 128 ) - name = malloc(name_len); - else - name = tmp_buf; - while (*class_name == '%') - class_name += 1; - strcpy (name, ".objc_category_name_"); - strcat (name, class_name); - strcat (name, "_"); - strcat (name, category_name); - if (NSIsSymbolNameDefined(name)) _dyld_lookup_and_bind_objc(name, 0, 0); - if ( name != tmp_buf ) - free(name); + char * class_name; + char * category_name; + char * name; + char tmp_buf[128]; + unsigned int name_len; + + // Bind ".objc_category_name__", + // where is the class name with the leading + // '%'s stripped. + class_name = cat->class_name; + category_name = cat->category_name; + name_len = strlen(class_name) + strlen(category_name) + 30; + if ( name_len > 128 ) + name = malloc(name_len); + else + name = tmp_buf; + while (*class_name == '%') + class_name += 1; + strcpy (name, ".objc_category_name_"); + strcat (name, class_name); + strcat (name, "_"); + strcat (name, category_name); + if (LaunchingDebug) { _objc_syslog("_objc_bindModuleContainingCategory for %s on %s", category_name, class_name); } + _objc_bind_symbol(name); + if ( name != tmp_buf ) + free(name); } /*********************************************************************** - * _objc_bindModuleContainingClass. Bind the module containing the - * class. - **********************************************************************/ -static void _objc_bindModuleContainingClass (struct objc_class * cls) -{ - struct objc_method_list * mList; - const char * class_name; - char * name; - char tmp_buf[128]; - unsigned int name_len; - - // Use the real class behind the poser - if (CLS_GETINFO (cls, CLS_POSING)) - cls = getOriginalClassForPosingClass (cls); - - // Bind ".objc_class_name_", where - // is the class name with the leading '%'s stripped. - class_name = cls->name; - name_len = strlen(class_name) + 20; - if ( name_len > 128 ) - name = malloc(name_len); - else - name = tmp_buf; - while (*class_name == '%') - class_name += 1; - strcpy (name, ".objc_class_name_"); - strcat (name, class_name); - if (NSIsSymbolNameDefined(name)) _dyld_lookup_and_bind_objc(name, 0, 0); - if ( name != tmp_buf ) - free(name); +* _objc_bindModuleContainingClass. Bind the module containing the +* class. +* This is done lazily, just after initializing the class (if needed) +**********************************************************************/ + +void _objc_bindModuleContainingClass (struct objc_class * cls) { + char * name; + const char * class_name; + char tmp_buf[128]; + unsigned int name_len; + + // Use the real class behind the poser + if (CLS_GETINFO (cls, CLS_POSING)) + cls = getOriginalClassForPosingClass (cls); + class_name = cls->name; + + name_len = strlen(class_name) + 20; + if ( name_len > 128 ) + name = malloc(name_len); + else + name = tmp_buf; + + while (*class_name == '%') + class_name += 1; + strcpy (name, ".objc_class_name_"); + strcat (name, class_name); + if (LaunchingDebug) { _objc_syslog("_objc_bindModuleContainingClass for %s", class_name); } + _objc_bind_symbol(name); + if ( name != tmp_buf ) + free(name); } -#endif // __MACH__ - + + /*********************************************************************** - * _objc_headerCount. Return the currently known number of `__OBJC' - * segments that are a part of the application - **********************************************************************/ -unsigned int _objc_headerCount (void) +* _objc_addHeader. +* +**********************************************************************/ + +// tested with 2; typical case is 4, but OmniWeb & Mail push it towards 20 +#define HINFO_SIZE 16 + +static int HeaderInfoCounter = 0; +static header_info HeaderInfoTable[HINFO_SIZE] = { {0} }; + +static header_info * _objc_addHeader(const headerType *header, unsigned long vmaddr_slide) { -#if defined(__MACH__) // not GENERIC_OBJ_FILE - return header_count; -#else - return _objc_goff_headerCount (); -#endif + int mod_count; + Module mod_ptr = _getObjcModules ((headerType *) header, &mod_count); + header_info *result; + + // if there is no objc data - ignore this entry! + if (mod_ptr == NULL) { + return NULL; + } + + if (HeaderInfoCounter < HINFO_SIZE) { + // avoid mallocs for the common case + result = &HeaderInfoTable[HeaderInfoCounter++]; + } + else { + result = malloc_zone_malloc(_objc_create_zone(), sizeof(header_info)); + } + + // Set up the new vector entry + result->mhdr = header; + result->mod_ptr = mod_ptr; + result->mod_count = mod_count; + result->image_slide = vmaddr_slide; + + // chain it on + // (a simple lock here would go a long way towards thread safety) + result->next = FirstHeader; + FirstHeader = result; + + return result; } -/*********************************************************************** - * _objc_addHeader. - * - * NOTE: Yet another wildly inefficient routine. - **********************************************************************/ -void _objc_addHeader (const headerType * header, - unsigned long vmaddr_slide) +/********************************************************************** +* _objc_fatalHeader +* +* If we have it we're in trouble +**************************************************************************/ +void _objc_fatalHeader(const headerType *header) { - // Account for addition - header_count += 1; - - // Create vector table if needed - if (header_vector == 0) - { - header_vector_size = 100; - header_vector = malloc_zone_malloc (_objc_create_zone (), - header_vector_size * sizeof(header_info)); -#if defined(WIN32) || defined(__svr4__) - bzero (header_vector, (header_vector_size * sizeof(header_info))); -#endif - } - - - // Malloc a new vector table one bigger than before - else if (header_count > header_vector_size) - { - void * old; - - header_vector_size *= 2; - old = (void *) header_vector; - header_vector = malloc_zone_malloc (_objc_create_zone (), - header_vector_size * sizeof(header_info)); - -#if defined(WIN32) || defined(__svr4__) - bzero (header_vector, (header_vector_size * sizeof(header_info))); -#endif - memcpy ((void *) header_vector, old, (header_count - 1) * sizeof(header_info)); - malloc_zone_free (_objc_create_zone (), old); - } - - // Set up the new vector entry - header_vector[header_count - 1].mhdr = header; - header_vector[header_count - 1].mod_ptr = NULL; - header_vector[header_count - 1].mod_count = 0; - header_vector[header_count - 1].image_slide = vmaddr_slide; - header_vector[header_count - 1].objcSize = 0; + header_info *hInfo; + + for (hInfo = FirstHeader; hInfo != NULL; hInfo = hInfo->next) { + if (hInfo->mhdr == header) { + _objc_fatal("cannot unmap an image containing ObjC data"); + } + } } /*********************************************************************** - * libraryNameForMachHeader. +* libraryNameForMachHeader. **********************************************************************/ static const char * libraryNameForMachHeader (const headerType * themh) { -#if defined(NeXT_PDO) - return ""; -#else - unsigned long index; - unsigned long imageCount; - headerType * mh; - - // Search images for matching type - imageCount = _dyld_image_count (); - for (index = 0; index < imageCount ; index += 1) - { - // Return name of image with matching type - mh = _dyld_get_image_header (index); - if (mh == themh) - return _dyld_get_image_name (index); - } - - // Not found - return 0; -#endif + unsigned long index; + unsigned long imageCount; + headerType * mh; + + // Search images for matching type + imageCount = _dyld_image_count (); + for (index = 0; index < imageCount ; index += 1) + { + // Return name of image with matching type + mh = _dyld_get_image_header (index); + if (mh == themh) + return _dyld_get_image_name (index); + } + + // Not found + return 0; } /*********************************************************************** - * _objc_fixup_selector_refs. Register all of the selectors in each - * image, and fix them all up. - * - **********************************************************************/ +* _objc_fixup_selector_refs. Register all of the selectors in each +* image, and fix them all up. +* +**********************************************************************/ static void _objc_fixup_selector_refs (const header_info * hi) { - unsigned int midx; - unsigned int size; - OBJC_PROTOCOL_PTR protos; - Module mods; - unsigned int index; -#if defined(__MACH__) - SEL * messages_refs; -#endif // __MACH__ - - mods = (Module) ((unsigned long) hi->mod_ptr + hi->image_slide); - - if ( rocketLaunchingDebug ) - { - printf ("uniquing selectors for %s\n", libraryNameForMachHeader(hi->mhdr)); - printf (" uniquing message_refs\n"); - } - -#if defined(__MACH__) - // Fix up message refs - messages_refs = (SEL *) _getObjcMessageRefs ((headerType *) hi->mhdr, &size); - if (messages_refs) - { - messages_refs = (SEL *) ((unsigned long) messages_refs + hi->image_slide); - map_selrefs (messages_refs, size); - } -#endif // __MACH__ - - -#if !defined(__MACH__) - // This is redundant with the fixup done in _objc_fixup_protocol_objects_for_image() - // in a little while, at least on MACH. - - // Fix up protocols - protos = (OBJC_PROTOCOL_PTR) _getObjcProtocols ((headerType *) hi->mhdr, &size); - if (protos) - { - protos = (OBJC_PROTOCOL_PTR)((unsigned long)protos + hi->image_slide); - - for (index = 0; index < size; index += 1) - { - // Fix up instance method names - if (protos[index] OBJC_PROTOCOL_DEREF instance_methods) - map_method_descs (protos[index] OBJC_PROTOCOL_DEREF instance_methods); - - // Fix up class method names - if (protos[index] OBJC_PROTOCOL_DEREF class_methods) - map_method_descs (protos[index] OBJC_PROTOCOL_DEREF class_methods); - } - } -#endif + unsigned int midx; + unsigned int size; + OBJC_PROTOCOL_PTR protos; + Module mods; + unsigned int index; + SEL * messages_refs; + + mods = (Module) ((unsigned long) hi->mod_ptr + hi->image_slide); + + // Fix up message refs + messages_refs = (SEL *) _getObjcMessageRefs ((headerType *) hi->mhdr, &size); + if (messages_refs) + { + messages_refs = (SEL *) ((unsigned long) messages_refs + hi->image_slide); + map_selrefs (messages_refs, size); + } } /*********************************************************************** - * _objc_call_loads_for_image. - **********************************************************************/ +* _objc_call_loads_for_image. +**********************************************************************/ static void _objc_call_loads_for_image (header_info * header) { - struct objc_class * cls; - struct objc_class * * pClass; - Category * pCategory; - IMP load_method; - unsigned int nModules; - unsigned int nClasses; - unsigned int nCategories; - struct objc_symtab * symtab; - struct objc_module * module; - - // Major loop - process all modules named in header - module = (struct objc_module *) ((unsigned long) header->mod_ptr + header->image_slide); - for (nModules = header->mod_count; nModules; nModules -= 1, module += 1) - { - symtab = module->symtab; - if (symtab == NULL) - continue; - - // Minor loop - call the +load from each class in the given module - for (nClasses = symtab->cls_def_cnt, pClass = (Class *) symtab->defs; - nClasses; - nClasses -= 1, pClass += 1) - { - struct objc_method_list **mlistp; - cls = (struct objc_class *)*pClass; - mlistp = get_base_method_list(cls->isa); - if (cls->isa->methodLists && mlistp) - { - // Look up the method manually (vs messaging the class) to bypass - // +initialize and cache fill on class that is not even loaded yet - load_method = class_lookupNamedMethodInMethodList (*mlistp, "load"); - if (load_method) - (*load_method) ((id) cls, @selector(load)); - } - } - - // Minor loop - call the +load from augmented class of - // each category in the given module - for (nCategories = symtab->cat_def_cnt, - pCategory = (Category *) &symtab->defs[symtab->cls_def_cnt]; - nCategories; - nCategories -= 1, pCategory += 1) - { - struct objc_method_list * methods; - - cls = objc_getClass ((*pCategory)->class_name); - methods = (*pCategory)->class_methods; - if (methods) - { - load_method = class_lookupNamedMethodInMethodList (methods, "load"); - if (load_method) - (*load_method) ((id) cls, @selector(load)); - } - } - } + struct objc_class * cls; + struct objc_class * * pClass; + Category * pCategory; + IMP load_method; + unsigned int nModules; + unsigned int nClasses; + unsigned int nCategories; + struct objc_symtab * symtab; + struct objc_module * module; + + // Major loop - process all modules named in header + module = (struct objc_module *) ((unsigned long) header->mod_ptr + header->image_slide); + for (nModules = header->mod_count; nModules; nModules -= 1, module += 1) + { + symtab = module->symtab; + if (symtab == NULL) + continue; + + // Minor loop - call the +load from each class in the given module + for (nClasses = symtab->cls_def_cnt, pClass = (Class *) symtab->defs; + nClasses; + nClasses -= 1, pClass += 1) + { + struct objc_method_list **mlistp; + cls = (struct objc_class *)*pClass; + mlistp = get_base_method_list(cls->isa); + if (cls->isa->methodLists && mlistp) + { + // Look up the method manually (vs messaging the class) to bypass + // +initialize and cache fill on class that is not even loaded yet + load_method = class_lookupNamedMethodInMethodList (*mlistp, "load"); + if (load_method) { + if (cls->info & CLS_NEED_BIND) { + cls->info &= ~CLS_NEED_BIND; + _objc_bindModuleContainingClass(cls); + } + (*load_method) ((id) cls, @selector(load)); + } + } + } + + // Minor loop - call the +load from augmented class of + // each category in the given module + for (nCategories = symtab->cat_def_cnt, + pCategory = (Category *) &symtab->defs[symtab->cls_def_cnt]; + nCategories; + nCategories -= 1, pCategory += 1) + { + struct objc_method_list * methods; + + methods = (*pCategory)->class_methods; + if (methods) + { + load_method = class_lookupNamedMethodInMethodList (methods, "load"); + if (load_method) { + // Strictly speaking we shouldn't need (and don't want) to get the class here + // The side effect we're looking for is to load it if needed. + // Since category +loads are rare we could spend some cycles finding out + // if we have a "bindme" TBD and do it here, saving a class load. + // But chances are the +load will cause class initialization anyway + cls = objc_getClass ((*pCategory)->class_name); + // the class & all categories are now bound in + (*load_method) ((id) cls, @selector(load)); + } + } + } + } } /*********************************************************************** - * objc_setMultithreaded. - **********************************************************************/ +* runtime configuration +**********************************************************************/ +static void objc_setConfiguration() { + if ( LaunchingDebug == -1 ) { + // watch image loading and binding + LaunchingDebug = getenv("LaunchingDebug") != NULL; + } +} +/*********************************************************************** +* objc_setMultithreaded. +**********************************************************************/ void objc_setMultithreaded (BOOL flag) { - if (flag == YES) - _objc_multithread_mask = 0; - else - _objc_multithread_mask = (-1); + if (flag == YES) + _objc_multithread_mask = 0; + else + _objc_multithread_mask = (-1); } +/*********************************************************************** +* _objcInit. +* Library initializer called by dyld & from crt0 +**********************************************************************/ -/* Library initializer called by dyld. */ -void __initialize_objc(void) { - int hidx; +void _objcInit(void) { + header_info *hInfo; + static int _done = 0; + extern void __CFInitialize(void); + extern int ptrace(int, int, int, int); // a system call visible to sc_trace -#if defined(NeXT_PDO) - const headerType * const * headers; + /* Protect against multiple invocations, as all library + * initializers should. */ + if (0 != _done) return; + _done = 1; - if ( rocketLaunchingDebug == -1 ) { - if ( getenv("OBJC_UNIQUE_DEBUG") ) rocketLaunchingDebug = 1; - else rocketLaunchingDebug = 0; - } + ptrace(0xb000, 0, 0, 0); + trace(0xb000, 0, 0, 0); + + // make sure CF is initialized before we go further; + // someday this can be removed, as it'll probably be automatic + __CFInitialize(); + + // Create the class lookup table + _objc_init_class_hash (); + + trace(0xb001, 0, 0, 0); + + objc_setConfiguration(); // Get our configuration + + trace(0xb003, 0, 0, 0); + + // a pre-cheetah comment: + // XXXXX BEFORE HERE *NO* PAGES ARE STOMPED ON; + + // Register our image mapping routine with dyld so it + // gets invoked when an image is added. This also invokes + // the callback right now on any images already present. + + // The modules present in the application and the existing + // mapped images are treated differently than a newly discovered + // mapped image - we process all modules for classes before + // trying to install_relationships (glue up their superclasses) + // or trying to send them any +load methods. + + // So we tell the map_image dyld callback to not do this part... + + Postpone_install_relationships = 1; + + // register for unmapping first so we can't miss any during load attempts + _dyld_register_func_for_remove_image (&_objc_unmap_image); + + // finally, register for images + _dyld_register_func_for_add_image (&_objc_map_image); + + // a pre-cheetah comment: + // XXXXX BEFORE HERE *ALL* PAGES ARE STOMPED ON - // Get architecture dependent module headers - headers = (const headerType * const *) _getObjcHeaders (); - if (headers) - { - // Create vector from these headers - header_vector = _objc_headerVector (headers); - if (header_vector) - { - // Load classes from all images in the vector - for (hidx = 0; hidx < header_count; hidx += 1) - (void) _objc_get_classes_from_image (class_hash, &header_vector[hidx]); - } - } -#endif -#if defined(__MACH__) - static int _done = 0; - extern void __CFInitialize(void); - - /* Protect against multiple invocations, as all library - * initializers should. */ - if (0 != _done) return; - _done = 1; - - ptrace(0xb000, 0, 0, 0); - - // make sure CF is initialized before we go further; - // someday this can be removed, as it'll probably be automatic - __CFInitialize(); - - // Create the class lookup table - _objc_init_class_hash (); - -// ptrace(0xb001, 0, 0, 0); - - // Get our configuration - if ( rocketLaunchingDebug == -1 ) { - if ( getenv("OBJC_UNIQUE_DEBUG") ) rocketLaunchingDebug = 1; - else rocketLaunchingDebug = 0; + Postpone_install_relationships = 0; + + trace(0xb006, 0, 0, 0); + + // Install relations on classes that were found + for (hInfo = FirstHeader; hInfo != NULL; hInfo = hInfo->next) + { + int nModules; + int index; + struct objc_module * module; + struct objc_class * cls; + + module = (struct objc_module *) ((unsigned long) hInfo->mod_ptr + hInfo->image_slide); + for (nModules = hInfo->mod_count; nModules; nModules -= 1) + { + for (index = 0; index < module->symtab->cls_def_cnt; index += 1) + { + cls = (struct objc_class *) module->symtab->defs[index]; + _class_install_relationships (cls, module->version); + } + + module += 1; } -// ptrace(0xb003, 0, 0, 0); - - map_selectors_pended = 1; - -// XXXXX BEFORE HERE *NO* PAGES ARE STOMPED ON - - // Register our image mapping routine with dyld so it - // gets invoked when an image is added. This also invokes - // the callback right now on any images already present. - _dyld_register_func_for_add_image (&_objc_map_image_callback); - -// XXXXX BEFORE HERE *ALL* PAGES ARE STOMPED ON - - map_selectors_pended = 0; - -// ptrace(0xb005, 0, 0, 0); - - // Register module link callback with dyld - _dyld_register_func_for_link_module (&_objc_link_module_callback); - - // Register callback with dyld - _dyld_register_func_for_unlink_module (&_objc_unlink_module_callback); -#endif // MACH - -// ptrace(0xb006, header_count, 0, 0); - - // Install relations on classes that were found - for (hidx = 0; hidx < header_count; hidx += 1) - { - int nModules; - int index; - struct objc_module * module; - struct objc_class * cls; - - module = (struct objc_module *) ((unsigned long) header_vector[hidx].mod_ptr + header_vector[hidx].image_slide); - for (nModules = header_vector[hidx].mod_count; nModules; nModules -= 1) - { - for (index = 0; index < module->symtab->cls_def_cnt; index += 1) - { - cls = (struct objc_class *) module->symtab->defs[index]; - _class_install_relationships (cls, module->version); - } - - module += 1; - } - -// ptrace(0xb007, hidx, header_vector[hidx].mod_count, 0); - - } - -// ptrace(0xb008, header_count, 0, 0); - - for (hidx = 0; hidx < header_count; hidx += 1) - { -#if !defined(__MACH__) - (void)_objc_add_categories_from_image (&header_vector[hidx]); - (void) _objc_fixup_selector_refs (&header_vector[hidx]); -#endif - // Initialize the isa pointers of all NXConstantString objects - (void)_objc_fixup_string_objects_for_image (&header_vector[hidx]); - - // Convert class refs from name pointers to ids - (void)_objc_map_class_refs_for_image (&header_vector[hidx]); - } - -// ptrace(0xb00a, 0, 0, 0); - - // For each image selectorize the method names and +_fixup each of - // protocols in the image - for (hidx = 0; hidx < header_count; hidx += 1) - _objc_fixup_protocol_objects_for_image (&header_vector[hidx]); - -#if defined(WIN32) || defined(__svr4__) - CMH = (objcModHeader *) 0; -#endif - - ptrace(0xb00f, 0, 0, 0); // end of ObjC init -} + trace(0xb007, hInfo, hInfo->mod_count, 0); -void _objcInit(void) { - static int _done = 0; - int hidx; - /* Protect against multiple invocations, as all library - * initializers should. */ - if (0 != _done) return; - _done = 1; - ptrace(0xb010, 0, 0, 0); // marks call to _objcInit - __initialize_objc(); - /* We delay this until here, because dyld cannot detect and - * properly order calls to ObjC initializers amongst the - * calls to module and library initializers. */ - for (hidx = 0; hidx < header_count; hidx += 1) - _objc_call_loads_for_image (&header_vector[hidx]); - ptrace(0xb01f, 0, 0, 0); // marks call to _objcInit + } + + trace(0xb008, 0, 0, 0); + + for (hInfo = FirstHeader; hInfo != NULL; hInfo = hInfo->next) + { + // Initialize the isa pointers of all NXConstantString objects + (void)_objc_fixup_string_objects_for_image (hInfo); + + // Convert class refs from name pointers to ids + (void)_objc_map_class_refs_for_image (hInfo); + } + + trace(0xb00a, 0, 0, 0); + + // For each image selectorize the method names and +_fixup each of + // protocols in the image + for (hInfo = FirstHeader; hInfo != NULL; hInfo = hInfo->next) + _objc_fixup_protocol_objects_for_image (hInfo); + + for (hInfo = FirstHeader; hInfo != NULL; hInfo = hInfo->next) + _objc_call_loads_for_image (hInfo); + + ptrace(0xb00f, 0, 0, 0); // end of __initialize_objc ObjC init + trace(0xb00f, 0, 0, 0); // end of __initialize_objc ObjC init } -#if defined(__MACH__) + /*********************************************************************** - * _objc_map_image. - **********************************************************************/ -static void _objc_map_image(headerType * mh, - unsigned long vmaddr_slide) +* _objc_map_image. +**********************************************************************/ +static void _objc_map_image(headerType *mh, unsigned long vmaddr_slide) { - static int dumpClasses = -1; - header_info * hInfo; - const struct segment_command * objcSeg; - unsigned int size; - - if ( dumpClasses == -1 ) { - if ( getenv("OBJC_DUMP_CLASSES") ) dumpClasses = 1; - else dumpClasses = 0; + static int dumpClasses = -1; + header_info *hInfo; + unsigned int size; + + if ( dumpClasses == -1 ) { + if ( getenv("OBJC_DUMP_CLASSES") ) dumpClasses = 1; + else dumpClasses = 0; + } + + trace(0xb100, 0, 0, 0); + + // Add this header to the chain + hInfo = _objc_addHeader (mh, vmaddr_slide); + + if (!hInfo) return; + + if (LaunchingDebug) { _objc_syslog("objc_map_image for %s\n", _nameForHeader(mh)); } + + trace(0xb101, 0, 0, 0); + + // Register any categories and/or classes and/or selectors this image contains + _objc_add_categories_from_image (hInfo); + + trace(0xb103, 0, 0, 0); + + _objc_add_classes_from_image (class_hash, hInfo); + + trace(0xb104, 0, 0, 0); + + _objc_fixup_selector_refs (hInfo); + + trace(0xb105, 0, 0, 0); + + // Log all known class names, if asked + if ( dumpClasses ) + { + printf ("classes...\n"); + objc_dump_class_hash (); + } + + if (!Postpone_install_relationships) + { + int nModules; + int index; + struct objc_module * module; + + // Major loop - process each module + module = (struct objc_module *) ((unsigned long) hInfo->mod_ptr + hInfo->image_slide); + + trace(0xb106, hInfo->mod_count, 0, 0); + + for (nModules = hInfo->mod_count; nModules; nModules -= 1) + { + // Minor loop - process each class in a given module + for (index = 0; index < module->symtab->cls_def_cnt; index += 1) + { + struct objc_class * cls; + + // Locate the class description + cls = (struct objc_class *) module->symtab->defs[index]; + + // If there is no superclass or the superclass can be found, + // install this class, and invoke the expected callback + if (!((struct objc_class *)cls)->super_class || objc_lookUpClass ((char *) ((struct objc_class *)cls)->super_class)) + { + _class_install_relationships (cls, module->version); + if (callbackFunction) + (*callbackFunction) (cls, 0); + } + else + { + // Super class can not be found yet, arrange for this class to + // be filled in later + objc_pendClassInstallation (cls, module->version); + ((struct objc_class *)cls)->super_class = _objc_getNonexistentClass (); + ((struct objc_class *)cls)->isa->super_class = _objc_getNonexistentClass (); + } + } + + // Move on + module += 1; } - ptrace(0xb100, 0, 0, 0); - - // Add this header to the header_vector - _objc_addHeader (mh, vmaddr_slide); - -// ptrace(0xb101, 0, 0, 0); - - // Touch up the vector entry we just added (yuck) - hInfo = &(header_vector[header_count-1]); - hInfo->mod_ptr = (Module) _getObjcModules ((headerType *) hInfo->mhdr, &size); - hInfo->mod_count = size; - objcSeg = (struct segment_command *) _getObjcHeaderData ((headerType *) mh, &size); - if (objcSeg) - hInfo->objcSize = objcSeg->filesize; - else - hInfo->objcSize = 0; - -// ptrace(0xb102, 0, 0, 0); - - // Register any categories and/or classes and/or selectors this image contains - _objc_add_categories_from_image (hInfo); - -// ptrace(0xb103, 0, 0, 0); - - class_hash = _objc_get_classes_from_image (class_hash, hInfo); - -// ptrace(0xb104, 0, 0, 0); - - _objc_fixup_selector_refs (hInfo); - -// ptrace(0xb105, 0, 0, 0); - - // Log all known class names, if asked - if ( dumpClasses ) - { - printf ("classes...\n"); - objc_dump_class_hash (); - } - - if (!map_selectors_pended) - { - int nModules; - int index; - struct objc_module * module; - - // Major loop - process each module - module = (struct objc_module *) ((unsigned long) hInfo->mod_ptr + hInfo->image_slide); - -// ptrace(0xb106, hInfo->mod_count, 0, 0); - - for (nModules = hInfo->mod_count; nModules; nModules -= 1) - { - // Minor loop - process each class in a given module - for (index = 0; index < module->symtab->cls_def_cnt; index += 1) - { - struct objc_class * cls; - - // Locate the class description - cls = (struct objc_class *) module->symtab->defs[index]; - - // If there is no superclass or the superclass can be found, - // install this class, and invoke the expected callback - if (!((struct objc_class *)cls)->super_class || objc_lookUpClass ((char *) ((struct objc_class *)cls)->super_class)) - { - _class_install_relationships (cls, module->version); - if (callbackFunction) - (*callbackFunction) (cls, 0); - } - - // Super class can not be found yet, arrange for this class to - // be filled in later - else - { - objc_pendClassInstallation (cls, module->version); - ((struct objc_class *)cls)->super_class = _objc_getNonexistentClass (); - ((struct objc_class *)cls)->isa->super_class = _objc_getNonexistentClass (); - } - } - - // Move on - module += 1; - } - -// ptrace(0xb108, 0, 0, 0); - - // Initialize the isa pointers of all NXConstantString objects - _objc_fixup_string_objects_for_image (hInfo); - -// ptrace(0xb109, 0, 0, 0); - - // Convert class refs from name pointers to ids - _objc_map_class_refs_for_image (hInfo); - -// ptrace(0xb10a, 0, 0, 0); - - // Selectorize the method names and +_fixup each of - // protocols in the image - _objc_fixup_protocol_objects_for_image (hInfo); - -// ptrace(0xb10b, 0, 0, 0); - - // Call +load on all classes and categorized classes - _objc_call_loads_for_image (hInfo); - -// ptrace(0xb10c, 0, 0, 0); - } - - ptrace(0xb10f, 0, 0, 0); -} + trace(0xb108, 0, 0, 0); -static volatile int handling_in_progress = 0; -static volatile int pended_callbacks_count = 0; -static volatile struct { - headerType * mh; - unsigned long vmaddr_slide; -} pended_callbacks[250] = {{0, 0}}; + // Initialize the isa pointers of all NXConstantString objects + _objc_fixup_string_objects_for_image (hInfo); -static void _objc_map_image_callback (headerType * mh, - unsigned long vmaddr_slide) -{ - pended_callbacks[pended_callbacks_count].mh = mh; - pended_callbacks[pended_callbacks_count].vmaddr_slide = vmaddr_slide; - pended_callbacks_count++; - if (0 != handling_in_progress) return; - handling_in_progress = 1; - while (0 < pended_callbacks_count) { - pended_callbacks_count--; - _objc_map_image(pended_callbacks[pended_callbacks_count].mh, pended_callbacks[pended_callbacks_count].vmaddr_slide); - } - handling_in_progress = 0; -} + trace(0xb109, 0, 0, 0); -#endif // __MACH__ + // Convert class refs from name pointers to ids + _objc_map_class_refs_for_image (hInfo); -#if defined(__MACH__) -/*********************************************************************** - * _objc_link_module_callback. Callback installed with - * _dyld_register_func_for_link_module. - * - * NOTE: Why does this exist? The old comment said "This will install - * class relations for the executable and dylibs." Hmm. - **********************************************************************/ -static void _objc_link_module_callback (NSModule mod) -{ -} + trace(0xb10a, 0, 0, 0); -/*********************************************************************** - * _objc_unlink_module_callback. Callback installed with - * _dyld_register_func_for_unlink_module. - **********************************************************************/ -static void _objc_unlink_module_callback (NSModule mod) -{ - _objc_fatal ("unlinking is not supported in this version of Objective C\n"); + // Selectorize the method names and +_fixup each of + // protocols in the image + _objc_fixup_protocol_objects_for_image (hInfo); + + trace(0xb10b, 0, 0, 0); + + // Call +load on all classes and categorized classes + _objc_call_loads_for_image (hInfo); + + trace(0xb10c, 0, 0, 0); + } + + trace(0xb10f, 0, 0, 0); } -#endif // __MACH__ -#if defined(WIN32) -#import /*********************************************************************** - * NSRootDirectory. Returns the value of the root directory that the - * product was installed to. - **********************************************************************/ -const char * NSRootDirectory (void) -{ - static char *root = (char *)0; - - if ( ! root ) { - char *p = getenv("NEXT_ROOT"); - if ( p ) { - root = malloc_zone_malloc(malloc_default_zone(), strlen(p)+1); - (void)strcpy(root, p); - } - else root = ""; - } - return (const char *)root; +* _objc_unmap_image. +**********************************************************************/ +static void _objc_unmap_image(headerType *mh, unsigned long vmaddr_slide) { + // we shouldn't have it if it didn't have objc data + // if we do have it, do a fatal + _objc_fatalHeader(mh); } -#endif /*********************************************************************** - * objc_setNilObjectMsgHandler. - **********************************************************************/ +* objc_setNilObjectMsgHandler. +**********************************************************************/ void objc_setNilObjectMsgHandler (NilObjectMsgCallback nilObjMsgCallback) { - _objc_msgNil = nilObjMsgCallback; + _objc_msgNil = nilObjMsgCallback; } /*********************************************************************** - * objc_getNilObjectMsgHandler. - **********************************************************************/ +* objc_getNilObjectMsgHandler. +**********************************************************************/ NilObjectMsgCallback objc_getNilObjectMsgHandler (void) { - return _objc_msgNil; + return _objc_msgNil; } -#if defined(NeXT_PDO) -// so we have a symbol for libgcc2.c when running PDO -arith_t _objcInit_addr = (arith_t) _objcInit; -#endif diff --git a/runtime/objc_dllMain.c b/runtime/objc_dllMain.c deleted file mode 100644 index 29394ae..0000000 --- a/runtime/objc_dllMain.c +++ /dev/null @@ -1,49 +0,0 @@ -/* - * Copyright (c) 1999 Apple Computer, Inc. All rights reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * Portions Copyright (c) 1999 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 1.1 (the "License"). You may not use this file - * except in compliance with the License. Please obtain a copy of the - * License at http://www.apple.com/publicsource 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 OR NON- INFRINGEMENT. Please see the - * License for the specific language governing rights and limitations - * under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ -// Copyright 1988-1996 NeXT Software, Inc. - -#include -#include - -extern void __do_global_ctors(); - -BOOL APIENTRY DllMain( HANDLE hModule, - DWORD ul_reason_for_call, - LPVOID lpReserved ) -{ - _NXLogError( "DllMain got called!\n" ); - - switch( ul_reason_for_call ) { - case DLL_PROCESS_ATTACH: - __do_global_ctors(); - break; - case DLL_THREAD_ATTACH: - break; - case DLL_THREAD_DETACH: - break; - case DLL_PROCESS_DETACH: - break; - } - return TRUE; -} diff --git a/runtime/objc_hpux_register_shlib.c b/runtime/objc_hpux_register_shlib.c deleted file mode 100644 index 1e698a4..0000000 --- a/runtime/objc_hpux_register_shlib.c +++ /dev/null @@ -1,640 +0,0 @@ -/* - * Copyright (c) 1999 Apple Computer, Inc. All rights reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * Portions Copyright (c) 1999 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 1.1 (the "License"). You may not use this file - * except in compliance with the License. Please obtain a copy of the - * License at http://www.apple.com/publicsource 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 OR NON- INFRINGEMENT. Please see the - * License for the specific language governing rights and limitations - * under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ - -/* - * objc_hpux_register_shlib.c - * Author: Laurent Ramontianu - */ - -#warning "OBJC SHLIB SUPPORT WARNING:" -#warning "Compiling objc_hpux_register_shlib.c" -#warning "Shlibs containing objc code must be built using" -#warning "the ld option: +I'objc_hpux_register_shlib_$(NAME)'" -#warning "Be advised that if collect isn't fixed to ignore" -#warning "shlibs, your app may (and will) CRASH!!!" - -#include -#include -#include -#include -#include -#include -#include -#include - -static char *_loaded_shlibs_init[128] = { - "java", - "cl", - "isamstub", - "c", - "m", - "dld", - "gen", - "pthread", - "lwp" -}; - -static unsigned _loaded_shlibs_size = 128; -static unsigned _loaded_shlibs_count = 9; - -static char **_loaded_shlibs = _loaded_shlibs_init; - -static void dump_loaded_shlibs() { - int i; - printf("**** Loaded shlibs ****\n"); - for ( i=0; i<_loaded_shlibs_count; i++ ) { - printf("\t%s\n", _loaded_shlibs[i]); - } - printf("--- ----\n"); -} - - -static char *my_basename(char *path) -{ - char *res = 0; - unsigned idx = strlen(path) - 1; - - if ( path[idx] == '/' ) idx--; - for ( ; (idx > 0) && (path[idx] != '/') ; idx-- ) { - if ( path[idx] == '.' ) path[idx] = '\000'; - } - if ( path[idx] == '/') idx++; - res = strstr(&path[idx], "lib"); - if ( !res ) { - return &path[idx]; - } - if ( res == &path[idx] ) { - return &path[idx+3]; - } - return &path[idx]; -} - - -extern void *malloc(unsigned); -extern void free(void *); - -// Hooks if we decide to provide alternate malloc/free functions -static void*(*_malloc_ptr)(unsigned) = malloc; -static void(*_free_ptr)(void*) = free; - - -static char *dep_shlibs_temp[128]; -static unsigned dep_shlibs_temp_count = 0; - -static void dump_dependent_shlibs() { - int i; - printf("**** Dependent shlibs ****\n"); - for ( i=0; i"); - - size = 0; - for ( idx = 0; idx < dep_shlibs_temp_count; idx++ ) { - size += sizeof(char*) + strlen(dep_shlibs_temp[idx]) + 1; - } - - if ( ! (ptr = _malloc_ptr(size)) ) { - fprintf(stderr, "dependent_shlibs: fatal - malloc() failed\n"); - exit(-1); - } - - ref_size = dep_shlibs_temp_count * sizeof(char*); - size = 0; - for ( idx = 0; idx < dep_shlibs_temp_count; idx++ ) { - name = ptr + ref_size + size; - *((char **)ptr + idx) = name; - strcpy(name, dep_shlibs_temp[idx]); - size += strlen(name) + 1; - } - - dep_shlibs_temp_count = 0; - return (char **)ptr; -} - - -static char **__objc_get_referenced_shlibs(char *path) -{ - static char **dict[128]; - static unsigned dict_size = 0; - static char *res_nil[] = { "" }; - static char file_name[48]; - - int fd; - int child_pid; - unsigned long size; - void *addr; - - char *ptr; - char *ptr2; - char buf[256], *name; - unsigned idx; - - strcpy(buf, path); - name = my_basename(buf); - - for (idx = 0; idx < dict_size; idx++ ) { - if ( ! strcmp(name, *(dict[idx])) ) - return dict[idx]+1; - } - - child_pid = vfork(); - if ( child_pid < 0 ) { - fprintf(stderr, "__objc_get_referenced_shlibs: fatal - vfork() failed\n"); - exit(-1); - } - - if ( child_pid > 0 ) { - wait(0); - sprintf(file_name, "/tmp/apple_shlib_reg.%d", child_pid); - if ( (fd = open(file_name, O_RDONLY)) < 0 ) { - fprintf(stderr, "__objc_get_referenced_shlibs: fatal - open() failed\n"); - exit(-1); - } - size = lseek(fd, 0, SEEK_END); - addr = mmap(0, size, PROT_READ | PROT_WRITE, MAP_PRIVATE, fd, 0); - - init_dependent_shlibs(name); - if ( ptr = strstr(addr, "list:") ) { - ptr2 = strtok(ptr, " \n\t"); - for ( ; ; ) { - ptr2 = strtok(0, " \n\t"); - if ( ! ptr2 || strcmp(ptr2, "dynamic") ) break; - ptr2 = strtok(0, " \n\t"); - if ( ! ptr2 ) { - fprintf(stderr, "__objc_get_referenced_shlibs: fatal - %s has bad format\n", file_name); - exit(-1); - } - insert_dependent_shlib(ptr2); - } - } - - dict[dict_size] = dependent_shlibs(); - munmap(addr, size); - close(fd); - unlink(file_name); - return dict[dict_size++]; - } - else { - sprintf(file_name, "/tmp/apple_shlib_reg.%d", getpid()); - close(1); - if ( open(file_name, O_WRONLY | O_CREAT, 0) < 0 ) { exit(-1); } -// Uncomment next 2 lines if it's needed to redirect stderr as well -/* - close(2); - dup(1); -*/ - /* aB. For some reason the file seems to be created with no read permission if done as a normal user */ - chmod(file_name, S_IRUSR | S_IRGRP | S_IROTH); - execl("/usr/bin/chatr", "chatr", path, 0); - fprintf(stderr, "__objc_get_referenced_shlibs: failed to exec chatr\n"); - exit(-1); - } - - return res_nil; -} - - -static int _verbose = -1; -static int _reg_mechanism = -1; - -#define OBJC_SHLIB_INIT_REGISTRATION if (_reg_mechanism == -1) {registration_init();} -#define REG_METHOD_CHATR 0 -#define REG_METHOD_DLD 1 - -static void registration_init() { - const char *str_value = getenv("OBJC_SHOW_SHLIB_REGISTRATION"); - if ( str_value ) { - if ( !strcmp(str_value, "ALL") ) _verbose = 4; - else if ( !strcmp(str_value, "LIBS") ) _verbose = 1; - else if ( !strcmp(str_value, "LIST") ) _verbose = 2; - else if ( !strcmp(str_value, "CTORS") ) _verbose = 3; - else _verbose = 0; - } - else _verbose = 0; - - str_value = getenv("OBJC_SHLIB_REGISTRATION_METHOD"); - if ( str_value ) { - if ( !strcmp(str_value, "DLD") ) _reg_mechanism = REG_METHOD_DLD; - else if ( !strcmp(str_value, "AB") ) _reg_mechanism = REG_METHOD_DLD; - else if ( !strcmp(str_value, "NEW") ) _reg_mechanism = REG_METHOD_DLD; - else _reg_mechanism = REG_METHOD_CHATR; - } - else _reg_mechanism = REG_METHOD_DLD; - - if (_verbose > 0) { - if (_reg_mechanism == REG_METHOD_CHATR) { - fprintf(stderr, "objc_hpux_register_shlib(): Using old (chatr) registration method\n"); - } else { - fprintf(stderr, "objc_hpux_register_shlib(): Using new (dld) registration method\n"); - } - } -} - - -static void insert_loaded_shlib(char *path); - -static int already_loaded(char *path) -{ - static int first_time_here = 1; - unsigned idx; - char buf[256], *name; - - strcpy(buf, path); - name = my_basename(buf); - - OBJC_SHLIB_INIT_REGISTRATION; - - for ( idx = 0; idx < _loaded_shlibs_count; idx++ ) { - if ( ! strcmp(_loaded_shlibs[idx], name) ) { - return 1; - } - } - - if ( first_time_here ) { // the root executable is the first shlib(sic) - first_time_here = 0; - insert_loaded_shlib(path); - return 1; - } - - return 0; -} - -static void insert_loaded_shlib(char *path) -{ - char **_loaded_shlibs_temp; - char buf[256], *name; - - strcpy(buf, path); - name = my_basename(buf); - - if ( already_loaded(path) ) { - return; - } - if ( _loaded_shlibs_count >= _loaded_shlibs_size ) { - _loaded_shlibs_temp = _loaded_shlibs; - _loaded_shlibs_size += 32; - _loaded_shlibs = (char **)_malloc_ptr(_loaded_shlibs_size*sizeof(char *)); - if ( ! _loaded_shlibs ) { - fprintf(stderr, "objc_hpux_register_shlib() - fatal: Failed to malloc _loaded_shlibs list. Exit\n"); - exit(-1); - } - memcpy(_loaded_shlibs, _loaded_shlibs_temp, _loaded_shlibs_count); - if ( _loaded_shlibs_temp != _loaded_shlibs_init ) { - _free_ptr(_loaded_shlibs_temp); - } - } - - if ( ! (_loaded_shlibs[_loaded_shlibs_count] = _malloc_ptr(strlen(name)+1)) ) { - fprintf(stderr, "objc_hpux_register_shlib() - fatal: Failed to malloc _loaded_shlibs entry. Exit\n"); - exit(-1); - } - strcpy(_loaded_shlibs[_loaded_shlibs_count++], name); - return; -} - - -static char *_pending_shlibs_init[128] = { "nhnd" }; - -static unsigned _pending_shlibs_size = 128; -static unsigned _pending_shlibs_count = 1; - -static char **_pending_shlibs = _pending_shlibs_init; - -static void dump_pending_shlibs() { - int i; - printf("**** Pending shlibs ****\n"); - for ( i=0; i<_pending_shlibs_count; i++ ) { - printf("\t%s\n", _pending_shlibs[i]+sizeof(void*)); - } - printf("--- ----\n"); -} - - -static int already_pending(const char *path) -{ - unsigned idx; - for ( idx = 0; idx < _pending_shlibs_count; idx++ ) { - if ( ! strcmp(_pending_shlibs[idx]+sizeof(void*), path) ) { - if (_verbose > 1) { - fprintf(stderr, "already_pending(): Already pended shlib %s\n", path); - } - return 1; - } - } - if (_verbose > 1) { - fprintf(stderr, "already_pending(): Pending shlib %s\n", path); - } - return 0; -} - -static void insert_pending_shlib(struct shl_descriptor *desc) -{ - char **_pending_shlibs_temp; - char *ptr; - int mask; - - if (_verbose > 1) { - fprintf(stderr, "insert_pending_shlib(): Inserting shlib %s\n", desc->filename); - } - - if ( already_pending(desc->filename) ) - return; - - if ( _pending_shlibs_count >= _pending_shlibs_size ) { - _pending_shlibs_temp = _pending_shlibs; - _pending_shlibs_size += 32; - _pending_shlibs = (char **)_malloc_ptr(_pending_shlibs_size*sizeof(char *)); - if ( ! _pending_shlibs ) { - fprintf(stderr, "objc_hpux_register_shlib() - fatal: Failed to malloc _pending_shlibs list. Exit\n"); - exit(-1); - } - memcpy(_pending_shlibs, _pending_shlibs_temp, _pending_shlibs_count); - if ( _pending_shlibs_temp != _pending_shlibs_init ) { - _free_ptr(_pending_shlibs_temp); - } - } - - if ( ! (ptr = _malloc_ptr(strlen(desc->filename)+1+sizeof(void *)*2)) ) { - fprintf(stderr, "objc_hpux_register_shlib() - fatal: Failed to malloc _pending_shlibs entry. Exit\n"); - exit(-1); - } - strcpy(ptr+sizeof(void*), desc->filename); - *(void **)ptr = desc->handle; - _pending_shlibs[_pending_shlibs_count] = ptr; - return; -} - -static void delete_pending_shlib(const char *path) -{ - unsigned idx; - char *ptr; - - if (_verbose > 1) { - fprintf(stderr, "delete_pending_shlib(): Deleting shlib %s\n", path); - } - - for ( idx = 0; idx < _pending_shlibs_count; idx++ ) { - ptr = _pending_shlibs[idx]+sizeof(void*); - if ( ! strcmp(ptr, path) ) { - if ( strcmp(ptr, "") ) { - _free_ptr(_pending_shlibs[idx]); - _pending_shlibs[idx] = ""; - if (_verbose > 1) { - fprintf(stderr, "delete_pending_shlib(): Found and deleted shlib %s\n", path); - } - } - return; - } - } -} - -static int more_pending_shlibs() -{ - unsigned idx; - char *ptr; - - for ( idx = 0; idx < _pending_shlibs_count; idx++ ) { - ptr = _pending_shlibs[idx]+sizeof(void*); - if ( strcmp(ptr, "") ) { - return 0; - } - } - if (_verbose > 1) { - fprintf(stderr, "more_pending_shlib(): Pending shlibs remain\n"); - } - return 1; -} - - -static int dependencies_resolved(char *path) -{ - char **referenced_shlibs; - - referenced_shlibs = __objc_get_referenced_shlibs(path); - referenced_shlibs++; - for ( ; strcmp(*referenced_shlibs, ""); referenced_shlibs++ ) { - if ( !already_loaded(*referenced_shlibs) ) { - if (_verbose > 1) { - fprintf(stderr, "dependencies_resolved(): Dependencies remaining for shlib %s\n", path); - } - return 0; - } - } - if (_verbose > 1) { - fprintf(stderr, "dependencies_resolved(): Dependencies resolved for shlib %s\n", path); - } - return 1; -} - - -void objc_hpux_register_shlib_handle(void *handle); - -static void resolve_pending_shlibs() -{ - char *ptr; - unsigned idx; - - for ( idx = 0; idx < _pending_shlibs_count; idx++ ) { - ptr = _pending_shlibs[idx]+sizeof(void*); - if ( dependencies_resolved(ptr) ) { - if ( _verbose >= 1 ) { - fprintf(stderr, "resolve_pending_shlibs(): Examining shlib %s\n", ptr); - } - objc_hpux_register_shlib_handle(*(void **)_pending_shlibs[idx]); - delete_pending_shlib(ptr); - insert_loaded_shlib(ptr); - } - } -} - - -void objc_hpux_register_shlib_handle(void *handle) -{ - extern void *CMH; - extern objc_finish_header(); - - int isCMHReset; - int sym_count, sym_idx; - struct shl_symbol *symbols; - - // use malloc and not _malloc_ptr - sym_count = shl_getsymbols(handle, TYPE_PROCEDURE, - EXPORT_SYMBOLS, malloc, &symbols); - if ( sym_count == -1 ) { - fprintf(stderr, "objc_hpux_register_shlib_handle() - WARNING: shl_getsymbols failed. Continue at your own risk...\n"); - //exit(-1); - return; - } - - isCMHReset = 0; - for ( sym_idx = 0; sym_idx < sym_count; sym_idx++ ) { - if ( !strncmp(symbols[sym_idx].name, "_GLOBAL_$I$", 11) ) { - if ( ! isCMHReset ) { - CMH = (void *)0; - isCMHReset = 1; - } - if ( _verbose >= 3 ) - fprintf(stderr, "objc_hpux_register_shlib_handle(): found ctor %s...\n", symbols[sym_idx].name); - ((void (*)())(symbols[sym_idx].value))(); - if ( _verbose >= 3 ) - fprintf(stderr, "objc_hpux_register_shlib_handle(): ... and executed it\n"); - } - } - if ( isCMHReset ) - objc_finish_header(); - - // use free and not _free_ptr - free(symbols); - return; -} - -void objc_hpux_register_shlib() -{ - int idx; - int registered_at_least_one_shlib; - struct shl_descriptor desc; - - OBJC_SHLIB_INIT_REGISTRATION; - - if (_reg_mechanism != REG_METHOD_CHATR) return; - - if ( _verbose == 2 || _verbose == 4 ) - fprintf(stderr, "---- ----\n"); - - registered_at_least_one_shlib = 0; - for ( idx = 0; !shl_get_r(idx, &desc); idx++ ) { - if ( already_loaded(desc.filename) ) { - if ( _verbose == 2 || _verbose == 4 ) - fprintf(stderr, "objc_hpux_register_shlib(): Skipping shlib %s\n", desc.filename); - continue; - } - - if ( !dependencies_resolved(desc.filename) ) { - insert_pending_shlib(&desc); - continue; - } - - if ( _verbose >= 1 || _verbose == 4 ) - fprintf(stderr, "objc_hpux_register_shlib(): Examining shlib %s\n", desc.filename); - objc_hpux_register_shlib_handle(desc.handle); - delete_pending_shlib(desc.filename); - insert_loaded_shlib(desc.filename); - registered_at_least_one_shlib = 1; - } - - // This is the last call and the last chance to resolve them all! - if ( ! registered_at_least_one_shlib ) { - while ( more_pending_shlibs() ) - resolve_pending_shlibs(); - } - - if ( _verbose == 2 || _verbose == 4) - fprintf(stderr, "---- ----\n\n"); - - return; -} - -/* - * An alternative, more efficient shlib registration that relies on the initializer - * functions in each shlib being called in the correct order. This was initially deemed not to work. aB. - */ -void objc_hpux_register_named_shlib(const char *shlib_name) -{ - int idx; - struct shl_descriptor desc; - char buf1[256], *p1; - char buf2[256], *p2; - - OBJC_SHLIB_INIT_REGISTRATION; - - strcpy(buf1, shlib_name); - p1 = my_basename(buf1); - - /* Do we use the new registration method or not ? */ - if (_reg_mechanism == REG_METHOD_DLD) { - if ( _verbose >= 1 ) { - fprintf(stderr, "objc_hpux_register_named_shlib(): Registering shlib %s\n", shlib_name); - } - for ( idx = 0; !shl_get_r(idx, &desc); idx++ ) { - strcpy(buf2, desc.filename); - p2 = my_basename(buf2); - /* Avoid registering the main executable (initializer == NULL) */ - if ( strcmp(p1, p2) == 0 && desc.initializer != NULL) { - objc_hpux_register_shlib_handle(desc.handle); - if ( _verbose >= 1 ) { - fprintf(stderr, "objc_hpux_register_named_shlib(): Registered shlib %s desc.initializer %x\n", desc.filename, desc.initializer); - } - break; - } - } - } else { - /* Just do things the old way */ - objc_hpux_register_shlib(); - } - -} - -/* Hardcoded in here for now as libpdo is built in a special manner */ -void objc_hpux_register_shlib_pdo() -{ - objc_hpux_register_named_shlib("libpdo.sl"); -} - - -unsigned __objc_msg_spew(unsigned self_obj, unsigned self_cls, unsigned addr) -{ - fprintf(stderr, "\n\n**** __objc_msg_spew(self:0x%08x self->isa:0x%08x cls:0x%08x) ****\n\n", self_obj, *(unsigned *)self_obj, self_cls); - return addr; -}