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
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 =
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
$(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
# 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 =
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:
#
-# Generated by the NeXT Project Builder.
+# Generated by the Apple Project Builder.
#
# NOTE: Do NOT change this file -- Project Builder maintains it.
#
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
# 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
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 = ();
};
+++ /dev/null
-/*
- * 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 ; <delay slot> 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 ; <delay slot> 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 ; <delay slot> 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 ; <delay slot> 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 ; <delay slot> 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 ; <delay slot> 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 ; <delay slot> 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 ; <delay slot> 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) ; <delay slot>
-L36: bl _objc_msgSend,%r2
- nop
- copy %r4,%r30 ; deallocate
- ldw -36(0,%r30), %r4
- ldw -20(0,%r30), %r2
- bv,n 0(%r2)
-
-
+++ /dev/null
-/*
- * 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 ; <delay slot> 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 ; <delay slot> 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 ; <delay slot> 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 ; <delay slot> 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) ; <delay slot>
-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)
-
-
+++ /dev/null
-/*
- * 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 ; <delay slot> 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 ; <ds>
-
-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 ; <delay slot> 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 ; <ds>
-
-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 ; <delay slot> 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) ; <delay slot>
-
-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 ; <ds>
- .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) ; <ds> 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
-
+++ /dev/null
-/*
- * 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 ; <ds> 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 ; <delay slot> 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 ; <delay slot> 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 ; <ds>
- b L$continue ; rejoin mainline
- nop ; <ds>
-
-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) ; <ds> 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 ; <delay slot> 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 ; <ds> 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 ; <delay slot> 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 ; <ds>
- b L$scontinue ; rejoin mainline
- nop ; <ds>
-
-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) ; <ds> 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 ; <delay slot> 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 ; <delay slot> 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) ; <delay slot>
-
- .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 ; <ds>
- .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) ; <ds> 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
-
+++ /dev/null
-/*
- * 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
+++ /dev/null
-/*
- * 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 |
+++ /dev/null
-/*
- * 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 |
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
.endif
; locate the cache
+; Locking idea:
+;LGetMask_$0_$1_$2
+
.if $0 == WORD_RETURN ; WORD_RETURN
.if $1 == MSG_SEND ; MSG_SEND
.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
.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
+++ /dev/null
-/*
- * 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 // <ds> 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 // <ds> 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 // <ds> index &= mask
-.L_cacheMiss:
- call _class_lookupMethodAndLoadCache,0
- mov %i1,%o1 // <ds> Selector goes into arg1
-.L_cacheHit:
- tst %l2 // If mutithreaded is zero
- bz,a .L_unlocked // Then multithreaded, so unlock
- swap [%l7],%g0 // <ds> in the delay slot!
-.L_unlocked:
- jmp %o0 // Go to method imp
- restore // <ds> 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 // <ds>
-.L_struct_returnSend:
- jmp %i7 + 12 // convention for returning structs
- restore // <ds>
-.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 // <ds> lock code (1)
- b .L_continue // Head back to mainline
- ld [%l1+32],%o0 // <ds> 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 // <ds> 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 // <ds> 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 // <ds> Get implementation address
- add %i0,1,%i0 // Increment index
- b .L_super_loop // Loop again
- and %i0,%o2,%i0 // <ds> and with mask
-.L_super_cacheMiss:
- call _class_lookupMethodAndLoadCache,0
- mov %i1,%o1 // <ds> 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 // <ds> in the delay slot!
-.L_super_unlocked:
- restore // Restore the stack
- jmp %g1 // Go to the method
- ld [%sp+68],%o0 // <ds> 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 // <ds> lock code (1)
- b .L_super_continue// Head back to mainline
- st %l1,[%fp+68] // <ds> 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 // <ds> 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 // <ds> 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 // <ds> 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
+++ /dev/null
-/*
- * 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 // <ds>
-L_struct_returnSend0:
- jmp %i7 + 12 // convention for returning structs
- restore // <ds>
-
-! 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] ! <delay slot> 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 // <ds>
-L_struct_returnSend1:
- jmp %i7 + 12 // convention for returning structs
- restore // <ds>
-
-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 ! <ds> 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
#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"
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;
Responsibility: Bertrand Serlet
*/
-#if defined(__svr4__) || defined(__hpux__) || defined(hpux)
- #import <strings.h> // for bcmp()
-#elif defined(WIN32)
- #import <pdo.h> // for bcopy()
-#endif
#import <stdlib.h>
#import <stdio.h>
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",
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;
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 */
Copyright 1991-1996 NeXT Software, Inc.
*/
-#if defined(WIN32)
- #include <winnt-pdo.h>
-#endif
#include "objc-private.h"
#import <objc/Protocol.h>
#include <objc/objc-runtime.h>
#include <stdlib.h>
-#if defined(__MACH__)
- #include <mach-o/dyld.h>
- #include <mach-o/ldsyms.h>
-#endif
+#include <mach-o/dyld.h>
+#include <mach-o/ldsyms.h>
/* some forward declarations */
#include <setjmp.h>
#import <objc/objc-api.h>
-#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 */
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);
(void) NXHashInsert (prototypes, proto);
proto = NXHashGet (prototypes, &prototype);
if (! proto) {
- _NXLogError ("*** NXCreateHashTable: bug\n");
+ _objc_syslog ("*** NXCreateHashTable: bug\n");
return NULL;
};
};
(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);
};
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;
Created by Bertrand Serlet, August 1990
*/
-#if defined(WIN32)
- #include <winnt-pdo.h>
-#endif
#import "objc-private.h"
#import "maptable.h"
#import <objc/Object.h>
#import <objc/hashtable2.h>
-#if defined(NeXT_PDO)
- #import <pdo.h>
-#endif
/****** Macros and utilities ****************************/
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);
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);
}
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 ++;
}
}
/* no room: can't happen! */
- _NXLogError("**** NXMapInsert: bug\n");
+ _objc_syslog("**** NXMapInsert: bug\n");
return NULL;
}
}
}
}
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];
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);
}
*/
// 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
#endif
-// obsolete
-#if !defined(NEXTPDO)
- #if defined(WIN32)
- #define NEXTPDO __declspec(dllimport) extern
- #else
- #define NEXTPDO extern
- #endif
-#endif
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;
#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
*/
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__
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
#define marg_adjustedOffset(method, offset) \
(marg_prearg_size + offset)
-#endif /* hppa */
+
#define marg_getRef(margs, offset, type) \
( 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_ */
* 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
* 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,
* 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 <mach/mach_interface.h>
- #include <mach-o/ldsyms.h>
- #include <mach-o/dyld.h>
-#endif
+#import <mach/mach_interface.h>
+#include <mach-o/ldsyms.h>
+#include <mach-o/dyld.h>
-#ifdef WIN32
- #include <io.h>
- #include <fcntl.h>
- #include <winnt-pdo.h>
-#else
- #include <sys/types.h>
- #include <unistd.h>
- #include <stdlib.h>
- #include <sys/uio.h>
- #ifdef __svr4__
- #include <fcntl.h>
- #else
- #include <sys/fcntl.h>
- #endif
-#endif
-
-#if defined(__svr4__) || defined(__hpux__) || defined(hpux)
- #import <pdo.h>
-#endif
+#include <sys/types.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <sys/uio.h>
+#include <sys/fcntl.h>
+
+#import "objc-class.h"
#import <objc/Object.h>
#import <objc/objc-runtime.h>
// Needed kernel interface
#import <mach/mach.h>
-#ifdef __MACH__
#import <mach/thread_status.h>
-#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
// 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];
#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
#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;
#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);
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);
#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
static int traceDuplicates = 0;
static int traceDuplicatesVerbose = 0;
static int cacheFillDuplicates = 0;
-#endif
+#endif
#ifdef OBJC_INSTRUMENTED
// Instrumentation
// 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) {
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);
}
}
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;
}
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;
}
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;
}
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;
}
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;
// 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);
}
*/
/*
* 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 <winnt-pdo.h>
- #import <windows.h>
- #import <sys/types.h>
- #import <sys/stat.h>
- #import <io.h>
- #define syslog(a, b, c) fprintf(stderr, b, c)
-#else
- #import <syslog.h>
-#endif
-
- #if defined(NeXT_PDO)
- #if !defined(WIN32)
- #include <syslog.h> // major head banging in attempt to find syslog
- #import <stdarg.h>
- #include <unistd.h> // close
- #endif
- #import <fcntl.h> // file open flags
- #endif
+
+#include <stdarg.h>
+#include <unistd.h>
+#include <syslog.h>
+#include <sys/fcntl.h>
+
#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).
*/
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
}
/*
*/
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
}
/*
va_start (ap,fmt);
vsprintf (bigBuffer, fmt, ap);
- _NXLogError ("objc: %s", bigBuffer);
+ _objc_syslog ("objc: %s", bigBuffer);
va_end (ap);
}
*/
// Copyright 1988-1996 NeXT Software, Inc.
-#if defined(__APPLE__) && defined(__MACH__)
#import "objc-private.h"
#import <mach-o/ldsyms.h>
#import <mach-o/dyld.h>
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();
}
}
-#elif defined(hpux) || defined(__hpux__)
-
-/*
- * Objective-C runtime information module.
- * This module is specific to hp-ux a.out format files.
- */
-
-#import <pdo.h> // place where padding_bug would be
-#include <a.out.h>
-#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 <pdo.h>
-#import <Protocol.h>
-#import "objc-private.h"
-#if defined(WIN32)
- #import <stdlib.h>
-#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; j<objcHeaders.count; ++j) {
- cmh = (objcModHeader *)objcHeaders.data + j;
-
- printf("===%s, found %d modules\n", cmh->name, cmh->Modules.count);
-
-
- mod = (Module)cmh->Modules.data;
-
- for (i=0; i<cmh->Modules.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
#ifndef _OBJC_LOAD_H_
#define _OBJC_LOAD_H_
-#if !defined(NeXT_PDO)
#import <objc/objc-class.h>
#import <mach-o/loader.h>
char *name /* input */
);
-#endif NeXT_PDO
+
#endif /* _OBJC_LOAD_H_ */
/*
* 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
* under the License.
*
* @APPLE_LICENSE_HEADER_END@
- */
+ */
/*
* objc-load.m
#import <objc/Object.h>
#import <objc/Protocol.h>
-#if defined(__MACH__) || defined(WIN32)
-#import <streams/streams.h>
-#endif
+//#import <streams/streams.h>
+#include <mach-o/dyld.h>
-#if !defined(NeXT_PDO)
- // MACH
- #include <mach-o/dyld.h>
-#endif
-#if defined(WIN32)
- #import <winnt-pdo.h>
- #import <windows.h>
-#endif
-#if defined(__svr4__)
- #import <dlfcn.h>
-#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);
}
-#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;
}
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);
}
#import "objc-config.h"
- #if defined(NeXT_PDO)
- #define LITERAL_STRING_OBJECTS
- #import <mach/cthreads_private.h>
- #if defined(WIN32)
- #import <winnt-pdo.h>
- #import <ntunix.h>
- #else
- #import <pdo.h> // for pdo_malloc and pdo_free defines
- #import <sys/time.h>
- #endif
- #else
- #import <pthread.h>
- #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 <sys/time.h>
- #endif
+ #import <pthread.h>
+ #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 <sys/time.h>
#import <stdlib.h>
#import <stdarg.h>
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);
/* 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);
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);
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;
} FixupEntry;
static inline int selEqual( SEL s1, SEL s2 ) {
- OBJC_EXPORT int rocketLaunchingDebug;
- if ( rocketLaunchingDebug )
- checkUniqueness(s1, s2);
return (s1 == s2);
}
#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 \
{ \
#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) {
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_ */
* 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
* 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,
* 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 <winnt-pdo.h>
-#endif
-#if defined(NeXT_PDO)
-#import <pdo.h> // for pdo_malloc and pdo_free defines
-#elif defined(__MACH__)
#include <mach-o/ldsyms.h>
#include <mach-o/dyld.h>
#include <mach/vm_statistics.h>
-#endif
+// project headers first, otherwise we get the installed ones
+#import "objc-class.h"
#import <objc/objc-runtime.h>
#import <objc/hashtable2.h>
#import "maptable.h"
#import <objc/Object.h>
#import <objc/Protocol.h>
-#if !defined(WIN32)
#include <sys/time.h>
#include <sys/resource.h>
-#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.
// 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
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_<classname>_<categoryname>",
- // where <classname> 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_<classname>_<categoryname>",
+ // where <classname> 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_<classname>", where <classname>
- // 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 <stdlib.h>
/***********************************************************************
- * 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
+++ /dev/null
-/*
- * 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 <winnt-pdo.h>
-#include <windows.h>
-
-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;
-}
+++ /dev/null
-/*
- * 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 <dl.h>
-#include <stdlib.h>
-#include <stdio.h>
-#include <string.h>
-#include <fcntl.h>
-#include <sys/mman.h>
-#include <sys/unistd.h>
-#include <sys/stat.h>
-
-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<dep_shlibs_temp_count; i++ ) {
- printf("\t%s\n", dep_shlibs_temp[i]);
- }
- printf("--- ----\n");
-}
-
-
-static void init_dependent_shlibs(char *name)
-{
- dep_shlibs_temp[0] = name;
- dep_shlibs_temp_count = 1;
-}
-
-
-static int already_loaded(char *path);
-
-static void insert_dependent_shlib(char *path)
-{
- if ( ! already_loaded(path) ) {
- dep_shlibs_temp[dep_shlibs_temp_count] = path;
- dep_shlibs_temp_count++;
- return;
- }
-}
-
-static char **dependent_shlibs()
-{
- unsigned size;
- unsigned idx;
- char *ptr;
- char *name;
- unsigned ref_size;
-
- insert_dependent_shlib("<NULL>");
-
- 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[] = { "<NULL>" };
- 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<NULL>" };
-
-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, "<NULL>") ) {
- _free_ptr(_pending_shlibs[idx]);
- _pending_shlibs[idx] = "<NULL>";
- 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, "<NULL>") ) {
- 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, "<NULL>"); 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;
-}