]> git.saurik.com Git - apple/objc4.git/commitdiff
objc4-222.tar.gz mac-os-x-102 mac-os-x-1021 mac-os-x-1022 mac-os-x-1023 mac-os-x-1024 mac-os-x-1025 mac-os-x-1026 mac-os-x-1027 mac-os-x-1028 mac-os-x-1028g5 v222
authorApple <opensource@apple.com>
Wed, 3 Jul 2002 19:44:03 +0000 (19:44 +0000)
committerApple <opensource@apple.com>
Wed, 3 Jul 2002 19:44:03 +0000 (19:44 +0000)
34 files changed:
APPLE_LICENSE [new file with mode: 0644]
Makefile
Makefile.postamble [deleted file]
Makefile.preamble [deleted file]
PB.project [deleted file]
objc-exports [new file with mode: 0644]
runtime/Makefile [deleted file]
runtime/Makefile.postamble [deleted file]
runtime/Makefile.preamble [deleted file]
runtime/Messengers.subproj/Makefile [deleted file]
runtime/Messengers.subproj/Makefile.postamble [deleted file]
runtime/Messengers.subproj/Makefile.preamble [deleted file]
runtime/Messengers.subproj/PB.project [deleted file]
runtime/Messengers.subproj/objc-msg-i386.s
runtime/Messengers.subproj/objc-msg-ppc.s
runtime/Object.h
runtime/Object.m
runtime/OldClasses.subproj/List.h
runtime/OldClasses.subproj/Makefile [deleted file]
runtime/OldClasses.subproj/Makefile.preamble [deleted file]
runtime/OldClasses.subproj/PB.project [deleted file]
runtime/PB.project [deleted file]
runtime/error.h
runtime/hashtable2.h
runtime/hashtable2.m
runtime/objc-api.h
runtime/objc-class.h
runtime/objc-class.m
runtime/objc-config.h
runtime/objc-errors.m
runtime/objc-private.h
runtime/objc-runtime.h
runtime/objc-runtime.m
runtime/objc-sel.m

diff --git a/APPLE_LICENSE b/APPLE_LICENSE
new file mode 100644 (file)
index 0000000..84687a4
--- /dev/null
@@ -0,0 +1,372 @@
+APPLE PUBLIC SOURCE LICENSE
+Version 1.1 - April 19,1999
+
+Please read this License carefully before downloading this software.
+By downloading and using this software, you are agreeing to be bound
+by the terms of this License.  If you do not or cannot agree to the
+terms of this License, please do not download or use the software.
+
+1. General; Definitions.  This License applies to any program or other
+work which Apple Computer, Inc. ("Apple") publicly announces as
+subject to this Apple Public Source License and which contains a
+notice placed by Apple identifying such program or work as "Original
+Code" and stating that it is subject to the terms of this Apple Public
+Source License version 1.1 (or subsequent version thereof), as it may
+be revised from time to time by Apple ("License").  As used in this
+License:
+
+1.1 "Affected Original Code" means only those specific portions of
+Original Code that allegedly infringe upon any party's intellectual
+property rights or are otherwise the subject of a claim of
+infringement.
+
+1.2 "Applicable Patent Rights" mean: (a) in the case where Apple is
+the grantor of rights, (i) claims of patents that are now or hereafter
+acquired, owned by or assigned to Apple and (ii) that cover subject
+matter contained in the Original Code, but only to the extent
+necessary to use, reproduce and/or distribute the Original Code
+without infringement; and (b) in the case where You are the grantor of
+rights, (i) claims of patents that are now or hereafter acquired,
+owned by or assigned to You and (ii) that cover subject matter in Your
+Modifications, taken alone or in combination with Original Code.
+
+1.3 "Covered Code" means the Original Code, Modifications, the
+combination of Original Code and any Modifications, and/or any
+respective portions thereof.
+
+1.4 "Deploy" means to use, sublicense or distribute Covered Code other
+than for Your internal research and development (R&D), and includes
+without limitation, any and all internal use or distribution of
+Covered Code within Your business or organization except for R&D use,
+as well as direct or indirect sublicensing or distribution of Covered
+Code by You to any third party in any form or manner.
+
+1.5 "Larger Work" means a work which combines Covered Code or portions
+thereof with code not governed by the terms of this License.
+
+1.6 "Modifications" mean any addition to, deletion from, and/or change
+to, the substance and/or structure of Covered Code.  When code is
+released as a series of files, a Modification is: (a) any addition to
+or deletion from the contents of a file containing Covered Code;
+and/or (b) any new file or other representation of computer program
+statements that contains any part of Covered Code.
+
+1.7 "Original Code" means (a) the Source Code of a program or other
+work as originally made available by Apple under this License,
+including the Source Code of any updates or upgrades to such programs
+or works made available by Apple under this License, and that has been
+expressly identified by Apple as such in the header file(s) of such
+work; and (b) the object code compiled from such Source Code and
+originally made available by Apple under this License.
+
+1.8 "Source Code" means the human readable form of a program or other
+work that is suitable for making modifications to it, including all
+modules it contains, plus any associated interface definition files,
+scripts used to control compilation and installation of an executable
+(object code).
+
+1.9 "You" or "Your" means an individual or a legal entity exercising
+rights under this License.  For legal entities, "You" or "Your"
+includes any entity which controls, is controlled by, or is under
+common control with, You, where "control" means (a) the power, direct
+or indirect, to cause the direction or management of such entity,
+whether by contract or otherwise, or (b) ownership of fifty percent
+(50%) or more of the outstanding shares or beneficial ownership of
+such entity.
+
+2. Permitted Uses; Conditions & Restrictions.  Subject to the terms
+and conditions of this License, Apple hereby grants You, effective on
+the date You accept this License and download the Original Code, a
+world-wide, royalty-free, non- exclusive license, to the extent of
+Apple's Applicable Patent Rights and copyrights covering the Original
+Code, to do the following:
+
+2.1 You may use, copy, modify and distribute Original Code, with or
+without Modifications, solely for Your internal research and
+development, provided that You must in each instance:
+
+(a) retain and reproduce in all copies of Original Code the copyright
+and other proprietary notices and disclaimers of Apple as they appear
+in the Original Code, and keep intact all notices in the Original Code
+that refer to this License;
+
+(b) include a copy of this License with every copy of Source Code of
+Covered Code and documentation You distribute, and You may not offer
+or impose any terms on such Source Code that alter or restrict this
+License or the recipients' rights hereunder, except as permitted under
+Section 6; and
+
+(c) completely and accurately document all Modifications that you have
+made and the date of each such Modification, designate the version of
+the Original Code you used, prominently include a file carrying such
+information with the Modifications, and duplicate the notice in
+Exhibit A in each file of the Source Code of all such Modifications.
+
+2.2 You may Deploy Covered Code, provided that You must in each
+  instance:
+
+(a) satisfy all the conditions of Section 2.1 with respect to the
+Source Code of the Covered Code;
+
+(b) make all Your Deployed Modifications publicly available in Source
+Code form via electronic distribution (e.g. download from a web site)
+under the terms of this License and subject to the license grants set
+forth in Section 3 below, and any additional terms You may choose to
+offer under Section 6.  You must continue to make the Source Code of
+Your Deployed Modifications available for as long as you Deploy the
+Covered Code or twelve (12) months from the date of initial
+Deployment, whichever is longer;
+
+(c) if You Deploy Covered Code containing Modifications made by You,
+inform others of how to obtain those Modifications by filling out and
+submitting the information found at
+http://www.apple.com/publicsource/modifications.html, if available;
+and
+
+(d) if You Deploy Covered Code in object code, executable form only,
+include a prominent notice, in the code itself as well as in related
+documentation, stating that Source Code of the Covered Code is
+available under the terms of this License with information on how and
+where to obtain such Source Code.
+
+3. Your Grants.  In consideration of, and as a condition to, the
+licenses granted to You under this License:
+
+(a) You hereby grant to Apple and all third parties a non-exclusive,
+royalty-free license, under Your Applicable Patent Rights and other
+intellectual property rights owned or controlled by You, to use,
+reproduce, modify, distribute and Deploy Your Modifications of the
+same scope and extent as Apple's licenses under Sections 2.1 and 2.2;
+and
+
+(b) You hereby grant to Apple and its subsidiaries a non-exclusive,
+worldwide, royalty-free, perpetual and irrevocable license, under Your
+Applicable Patent Rights and other intellectual property rights owned
+or controlled by You, to use, reproduce, execute, compile, display,
+perform, modify or have modified (for Apple and/or its subsidiaries),
+sublicense and distribute Your Modifications, in any form, through
+multiple tiers of distribution.
+
+4. Larger Works.  You may create a Larger Work by combining Covered
+Code with other code not governed by the terms of this License and
+distribute the Larger Work as a single product.  In each such
+instance, You must make sure the requirements of this License are
+fulfilled for the Covered Code or any portion thereof.
+
+5. Limitations on Patent License.  Except as expressly stated in
+Section 2, no other patent rights, express or implied, are granted by
+Apple herein.  Modifications and/or Larger Works may require
+additional patent licenses from Apple which Apple may grant in its
+sole discretion.
+
+6. Additional Terms.  You may choose to offer, and to charge a fee
+for, warranty, support, indemnity or liability obligations and/or
+other rights consistent with the scope of the license granted herein
+("Additional Terms") to one or more recipients of Covered
+Code. However, You may do so only on Your own behalf and as Your sole
+responsibility, and not on behalf of Apple. You must obtain the
+recipient's agreement that any such Additional Terms are offered by
+You alone, and You hereby agree to indemnify, defend and hold Apple
+harmless for any liability incurred by or claims asserted against
+Apple by reason of any such Additional Terms.
+
+7. Versions of the License.  Apple may publish revised and/or new
+versions of this License from time to time.  Each version will be
+given a distinguishing version number.  Once Original Code has been
+published under a particular version of this License, You may continue
+to use it under the terms of that version. You may also choose to use
+such Original Code under the terms of any subsequent version of this
+License published by Apple.  No one other than Apple has the right to
+modify the terms applicable to Covered Code created under this
+License.
+
+8. NO WARRANTY OR SUPPORT.  The Original Code may contain in whole or
+in part pre-release, untested, or not fully tested works.  The
+Original Code may contain errors that could cause failures or loss of
+data, and may be incomplete or contain inaccuracies.  You expressly
+acknowledge and agree that use of the Original Code, or any portion
+thereof, is at Your sole and entire risk.  THE ORIGINAL CODE IS
+PROVIDED "AS IS" AND WITHOUT WARRANTY, UPGRADES OR SUPPORT OF ANY KIND
+AND APPLE AND APPLE'S LICENSOR(S) (FOR THE PURPOSES OF SECTIONS 8 AND
+9, APPLE AND APPLE'S LICENSOR(S) ARE COLLECTIVELY REFERRED TO AS
+"APPLE") EXPRESSLY DISCLAIM ALL WARRANTIES AND/OR CONDITIONS, EXPRESS
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+AND/OR CONDITIONS OF MERCHANTABILITY OR SATISFACTORY QUALITY AND
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY
+RIGHTS.  APPLE DOES NOT WARRANT THAT THE FUNCTIONS CONTAINED IN THE
+ORIGINAL CODE WILL MEET YOUR REQUIREMENTS, OR THAT THE OPERATION OF
+THE ORIGINAL CODE WILL BE UNINTERRUPTED OR ERROR- FREE, OR THAT
+DEFECTS IN THE ORIGINAL CODE WILL BE CORRECTED.  NO ORAL OR WRITTEN
+INFORMATION OR ADVICE GIVEN BY APPLE OR AN APPLE AUTHORIZED
+REPRESENTATIVE SHALL CREATE A WARRANTY OR IN ANY WAY INCREASE THE
+SCOPE OF THIS WARRANTY.  You acknowledge that the Original Code is not
+intended for use in the operation of nuclear facilities, aircraft
+navigation, communication systems, or air traffic control machines in
+which case the failure of the Original Code could lead to death,
+personal injury, or severe physical or environmental damage.
+
+9. Liability.
+
+9.1 Infringement.  If any portion of, or functionality implemented by,
+the Original Code becomes the subject of a claim of infringement,
+Apple may, at its option: (a) attempt to procure the rights necessary
+for Apple and You to continue using the Affected Original Code; (b)
+modify the Affected Original Code so that it is no longer infringing;
+or (c) suspend Your rights to use, reproduce, modify, sublicense and
+distribute the Affected Original Code until a final determination of
+the claim is made by a court or governmental administrative agency of
+competent jurisdiction and Apple lifts the suspension as set forth
+below.  Such suspension of rights will be effective immediately upon
+Apple's posting of a notice to such effect on the Apple web site that
+is used for implementation of this License.  Upon such final
+determination being made, if Apple is legally able, without the
+payment of a fee or royalty, to resume use, reproduction,
+modification, sublicensing and distribution of the Affected Original
+Code, Apple will lift the suspension of rights to the Affected
+Original Code by posting a notice to such effect on the Apple web site
+that is used for implementation of this License.  If Apple suspends
+Your rights to Affected Original Code, nothing in this License shall
+be construed to restrict You, at Your option and subject to applicable
+law, from replacing the Affected Original Code with non-infringing
+code or independently negotiating for necessary rights from such third
+party.
+
+9.2 LIMITATION OF LIABILITY.  UNDER NO CIRCUMSTANCES SHALL APPLE BE
+LIABLE FOR ANY INCIDENTAL, SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES
+ARISING OUT OF OR RELATING TO THIS LICENSE OR YOUR USE OR INABILITY TO
+USE THE ORIGINAL CODE, OR ANY PORTION THEREOF, WHETHER UNDER A THEORY
+OF CONTRACT, WARRANTY, TORT (INCLUDING NEGLIGENCE), PRODUCTS LIABILITY
+OR OTHERWISE, EVEN IF APPLE HAS BEEN ADVISED OF THE POSSIBILITY OF
+SUCH DAMAGES AND NOTWITHSTANDING THE FAILURE OF ESSENTIAL PURPOSE OF
+ANY REMEDY.  In no event shall Apple's total liability to You for all
+damages under this License exceed the amount of fifty dollars
+($50.00).
+
+10. Trademarks.  This License does not grant any rights to use the
+trademarks or trade names "Apple", "Apple Computer", "Mac OS X", "Mac
+OS X Server" or any other trademarks or trade names belonging to Apple
+(collectively "Apple Marks") and no Apple Marks may be used to endorse
+or promote products derived from the Original Code other than as
+permitted by and in strict compliance at all times with Apple's third
+party trademark usage guidelines which are posted at
+http://www.apple.com/legal/guidelinesfor3rdparties.html.
+
+11. Ownership.  Apple retains all rights, title and interest in and to
+the Original Code and any Modifications made by or on behalf of Apple
+("Apple Modifications"), and such Apple Modifications will not be
+automatically subject to this License.  Apple may, at its sole
+discretion, choose to license such Apple Modifications under this
+License, or on different terms from those contained in this License or
+may choose not to license them at all.  Apple's development, use,
+reproduction, modification, sublicensing and distribution of Covered
+Code will not be subject to this License.
+
+12. Termination.
+
+12.1 Termination.  This License and the rights granted hereunder will
+   terminate:
+
+(a) automatically without notice from Apple if You fail to comply with
+any term(s) of this License and fail to cure such breach within 30
+days of becoming aware of such breach; (b) immediately in the event of
+the circumstances described in Section 13.5(b); or (c) automatically
+without notice from Apple if You, at any time during the term of this
+License, commence an action for patent infringement against Apple.
+
+12.2 Effect of Termination.  Upon termination, You agree to
+immediately stop any further use, reproduction, modification,
+sublicensing and distribution of the Covered Code and to destroy all
+copies of the Covered Code that are in your possession or control.
+All sublicenses to the Covered Code which have been properly granted
+prior to termination shall survive any termination of this License.
+Provisions which, by their nature, should remain in effect beyond the
+termination of this License shall survive, including but not limited
+to Sections 3, 5, 8, 9, 10, 11, 12.2 and 13.  Neither party will be
+liable to the other for compensation, indemnity or damages of any sort
+solely as a result of terminating this License in accordance with its
+terms, and termination of this License will be without prejudice to
+any other right or remedy of either party.
+
+13.  Miscellaneous.
+
+13.1 Government End Users.  The Covered Code is a "commercial item" as
+defined in FAR 2.101.  Government software and technical data rights
+in the Covered Code include only those rights customarily provided to
+the public as defined in this License. This customary commercial
+license in technical data and software is provided in accordance with
+FAR 12.211 (Technical Data) and 12.212 (Computer Software) and, for
+Department of Defense purchases, DFAR 252.227-7015 (Technical Data --
+Commercial Items) and 227.7202-3 (Rights in Commercial Computer
+Software or Computer Software Documentation).  Accordingly, all U.S.
+Government End Users acquire Covered Code with only those rights set
+forth herein.
+
+13.2 Relationship of Parties.  This License will not be construed as
+creating an agency, partnership, joint venture or any other form of
+legal association between You and Apple, and You will not represent to
+the contrary, whether expressly, by implication, appearance or
+otherwise.
+
+13.3 Independent Development.  Nothing in this License will impair
+Apple's right to acquire, license, develop, have others develop for
+it, market and/or distribute technology or products that perform the
+same or similar functions as, or otherwise compete with,
+Modifications, Larger Works, technology or products that You may
+develop, produce, market or distribute.
+
+13.4 Waiver; Construction.  Failure by Apple to enforce any provision
+of this License will not be deemed a waiver of future enforcement of
+that or any other provision.  Any law or regulation which provides
+that the language of a contract shall be construed against the drafter
+will not apply to this License.
+
+13.5 Severability.  (a) If for any reason a court of competent
+jurisdiction finds any provision of this License, or portion thereof,
+to be unenforceable, that provision of the License will be enforced to
+the maximum extent permissible so as to effect the economic benefits
+and intent of the parties, and the remainder of this License will
+continue in full force and effect.  (b) Notwithstanding the foregoing,
+if applicable law prohibits or restricts You from fully and/or
+specifically complying with Sections 2 and/or 3 or prevents the
+enforceability of either of those Sections, this License will
+immediately terminate and You must immediately discontinue any use of
+the Covered Code and destroy all copies of it that are in your
+possession or control.
+
+13.6 Dispute Resolution.  Any litigation or other dispute resolution
+between You and Apple relating to this License shall take place in the
+Northern District of California, and You and Apple hereby consent to
+the personal jurisdiction of, and venue in, the state and federal
+courts within that District with respect to this License. The
+application of the United Nations Convention on Contracts for the
+International Sale of Goods is expressly excluded.
+
+13.7 Entire Agreement; Governing Law.  This License constitutes the
+entire agreement between the parties with respect to the subject
+matter hereof.  This License shall be governed by the laws of the
+United States and the State of California, except that body of
+California law concerning conflicts of law.
+
+Where You are located in the province of Quebec, Canada, the following
+clause applies: The parties hereby confirm that they have requested
+that this License and all related documents be drafted in English. Les
+parties ont exige que le present contrat et tous les documents
+connexes soient rediges en anglais.
+
+EXHIBIT A.
+
+"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."
index 977ac33e2e28d46bc1745596ceb94d04dff3fde5..e7c89b0bac4345d62ba26067182e14e48c4d319b 100644 (file)
--- a/Makefile
+++ b/Makefile
+# use LDFLAGS not LFLAGS
+# seg-addr-table, sect-order
 #
-# Generated by the Apple Project Builder.
+# Simple makefile for building objc4 on Darwin
 #
-# NOTE: Do NOT change this file -- Project Builder maintains it.
+# These make variables (or environment variables) are used
+# if defined:
+#      SRCROOT         path location of root of source hierarchy;
+#                      defaults to ".", but must be set to a
+#                      destination path for installsrc target.
+#      OBJROOT         path location where .o files will be put;
+#                      defaults to SRCROOT.
+#      SYMROOT         path location where build products will be
+#                      put; defaults to SRCROOT.
+#      DSTROOT         path location where installed products will
+#                      be put; defaults to / .
+# OBJROOT and SYMROOT should not be directories shared with other
+# built projects.
+#      PLATFORM        name of platform being built on
+#      USER            name of user building the project
+#      ARCHS           list of archs for which to build
+#      RC_ARCHS        more archs for which to build (build system)
+#      OTHER_CFLAGS    other flags to be passed to compiler
+#      RC_CFLAGS       more flags to be passed to compiler (build system)
+#      OTHER_LDFLAGS   other flags to be passed to the link stage
 #
-# Put all of your customizations in files called Makefile.preamble
-# and Makefile.postamble (both optional), and Makefile will include them.
+
+# Default targets
+default: build
+all: build
+
+.SUFFIXES:
+.PHONY: default all build optimized debug profile installsrc installhdrs install clean prebuild build-optimized build-debug build-profile prebuild-optimized prevuild-debug prebuild-profile compile-optimized compile-debug compile-profile link-optimized link-debug link-profile postbuild
+
+CURRENT_PROJECT_VERSION = 218
+
+VERSION_NAME = A
+
+# First figure out the platform if not specified, so we can use it in the
+# rest of this file.  Currently defined values: Darwin
+ifeq "$(PLATFORM)" ""
+PLATFORM := $(shell uname)
+endif
+
+ifndef SRCROOT
+SRCROOT = .
+endif
+
+ifndef OBJROOT
+OBJROOT = $(SRCROOT)
+endif
+
+ifndef SYMROOT
+SYMROOT = $(SRCROOT)
+endif
+
+ifndef DSTROOT
+DSTROOT = /
+endif
+
+ifeq "$(PLATFORM)" "Darwin"
+CC = /usr/bin/cc
+else
+CC = /usr/bin/gcc
+endif
+
+ECHO = @/bin/echo
+MKDIRS = /bin/mkdir -p
+CD = cd
+COPY = /bin/cp
+COPY_RECUR = /bin/cp -r
+REMOVE = /bin/rm
+REMOVE_RECUR = /bin/rm -rf
+SYMLINK = /bin/ln -s
+CHMOD = /bin/chmod
+CHOWN = /usr/sbin/chown
+TAR = /usr/bin/tar
+STRIP = /usr/bin/strip
+NMEDIT = /usr/bin/nmedit
+
+ifeq "$(PLATFORM)" "Darwin"
+WARNING_FLAGS = -Wmost -Wno-precomp -Wno-four-char-constants
+endif
+
+ARCH_LIST= 
+ifeq "$(PLATFORM)" "Darwin"
+
+ifneq "$(ARCHS)" ""
+ARCH_LIST += $(ARCHS)
+else
+ifneq "$(RC_ARCHS)" ""
+ARCH_LIST += $(RC_ARCHS)
+else
+ARCH_LIST += ppc
+endif
+endif
+
+ARCH_FLAGS = $(foreach A, $(ARCH_LIST), $(addprefix -arch , $(A)))
+
+endif
+
+
+
+ifeq "$(USER)" ""
+USER = unknown
+endif
+
+CFLAGS = -g -fno-common -pipe $(PLATFORM_CFLAGS) $(WARNING_FLAGS) -I$(SYMROOT) -I. -I$(SYMROOT)/ProjectHeaders
+LDFLAGS = -framework CoreFoundation
+
+LIBRARY_EXT = .dylib
+
+PUBLIC_HEADER_INSTALLDIR = usr/include/objc
+OTHER_HEADER_INSTALLDIR = usr/local/include/objc
+INSTALLDIR = usr/lib
+
+ifeq "$(PLATFORM)" "Darwin"
+CFLAGS += $(ARCH_FLAGS)
+LDFLAGS += $(ARCH_FLAGS) -dynamiclib -dynamic -compatibility_version 1 -current_version $(CURRENT_PROJECT_VERSION) 
+endif
+
+CFLAGS += $(OTHER_CFLAGS) $(RC_CFLAGS)
+LDFLAGS += $(OTHER_LDFLAGS)
+
+ifndef OPTIMIZATION_CFLAGS
+OPTIMIZATION_CFLAGS = -Os
+endif
+ifndef DEBUG_CFLAGS
+DEBUG_CFLAGS = -DDEBUG
+endif
+ifndef PROFILE_CFLAGS
+PROFILE_CFLAGS = -DPROFILE -pg -Os
+endif
+
+CFLAGS_OPTIMIZED = $(CFLAGS) $(OPTIMIZATION_CFLAGS)
+CFLAGS_DEBUG     = $(CFLAGS) $(DEBUG_CFLAGS)
+CFLAGS_PROFILE   = $(CFLAGS) $(PROFILE_CFLAGS)
+
+LDFLAGS_OPTIMIZED = $(LDFLAGS)
+LDFLAGS_DEBUG     = $(LDFLAGS) -g
+LDFLAGS_PROFILE   = $(LDFLAGS) -g -pg
+
+SUBDIRS = . runtime runtime/OldClasses.subproj runtime/Messengers.subproj
+
+# files to compile
+SOURCES=
+# files to not compile
+OTHER_SOURCES=
+# headers to install in /usr/include/objc
+PUBLIC_HEADERS=
+# headers that don't get installed
+PRIVATE_HEADERS=
+# headers to install in /usr/local/include/objc
+OTHER_HEADERS=
+
+# runtime
+SOURCES += $(addprefix runtime/, \
+        Object.m Protocol.m hashtable2.m maptable.m objc-class.m objc-errors.m \
+        objc-file.m objc-load.m objc-moninit.c objc-runtime.m objc-sel.m \
+        )
+PUBLIC_HEADERS += $(addprefix runtime/, \
+        objc-class.h objc-api.h objc-load.h objc-runtime.h objc.h Object.h \
+        Protocol.h error.h hashtable2.h \
+        )
+PRIVATE_HEADERS += runtime/objc-private.h runtime/objc-config.h
+OTHER_HEADERS += runtime/maptable.h
+
+# OldClasses
+SOURCES += runtime/OldClasses.subproj/List.m
+PUBLIC_HEADERS += runtime/OldClasses.subproj/List.h
+
+# Messengers
+SOURCES += runtime/Messengers.subproj/objc-msg.s
+OTHER_SOURCES += runtime/Messengers.subproj/objc-msg-ppc.s runtime/Messengers.subproj/objc-msg-i386.s
+
+# project root
+OTHER_SOURCES += Makefile APPLE_LICENSE objc-exports
+
+OBJECTS = $(addprefix $(OBJROOT)/, $(addsuffix .o, $(basename $(SOURCES) ) ) )
+OBJECTS_OPTIMIZED = $(OBJECTS:.o=.opt.o)
+OBJECTS_DEBUG = $(OBJECTS:.o=.debug.o)
+OBJECTS_PROFILE = $(OBJECTS:.o=.profile.o)
+
+# For simplicity, each object target depends on all objc headers. Most of 
+# them come close to requiring this anyway, and rebuild from scratch is fast.
+DEPEND_HEADERS = $(addprefix $(SRCROOT)/, \
+        $(PUBLIC_HEADERS) $(PRIVATE_HEADERS) $(OTHER_HEADERS) )
+
+$(OBJROOT)/%.opt.o :     $(SRCROOT)/%.m  $(DEPEND_HEADERS)
+       $(SILENT) $(ECHO) "    ... $<"
+       $(SILENT) $(CC) $(CFLAGS_OPTIMIZED) "$<" -c -o "$@"
+
+$(OBJROOT)/%.debug.o :   $(SRCROOT)/%.m  $(DEPEND_HEADERS)
+       $(SILENT) $(ECHO) "    ... $<"
+       $(SILENT) $(CC) $(CFLAGS_DEBUG)     "$<" -c -o "$@"
+
+$(OBJROOT)/%.profile.o : $(SRCROOT)/%.m  $(DEPEND_HEADERS)
+       $(SILENT) $(ECHO) "    ... $<"
+       $(SILENT) $(CC) $(CFLAGS_PROFILE)   "$<" -c -o "$@"
+
+$(OBJROOT)/%.opt.o :     $(SRCROOT)/%.c  $(DEPEND_HEADERS)
+       $(SILENT) $(ECHO) "    ... $<"
+       $(SILENT) $(CC) $(CFLAGS_OPTIMIZED) "$<" -c -o "$@"
+
+$(OBJROOT)/%.debug.o :   $(SRCROOT)/%.c  $(DEPEND_HEADERS)
+       $(SILENT) $(ECHO) "    ... $<"
+       $(SILENT) $(CC) $(CFLAGS_DEBUG)     "$<" -c -o "$@"
+
+$(OBJROOT)/%.profile.o : $(SRCROOT)/%.c  $(DEPEND_HEADERS)
+       $(SILENT) $(ECHO) "    ... $<"
+       $(SILENT) $(CC) $(CFLAGS_PROFILE)   "$<" -c -o "$@"
+
+$(OBJROOT)/%.opt.o :     $(SRCROOT)/%.s  $(DEPEND_HEADERS)
+       $(SILENT) $(ECHO) "    ... $<"
+       $(SILENT) $(CC) $(CFLAGS_OPTIMIZED) "$<" -c -o "$@"
+
+$(OBJROOT)/%.debug.o :   $(SRCROOT)/%.s  $(DEPEND_HEADERS)
+       $(SILENT) $(ECHO) "    ... $<"
+       $(SILENT) $(CC) $(CFLAGS_DEBUG)     "$<" -c -o "$@"
+
+$(OBJROOT)/%.profile.o : $(SRCROOT)/%.s  $(DEPEND_HEADERS)
+       $(SILENT) $(ECHO) "    ... $<"
+       $(SILENT) $(CC) $(CFLAGS_PROFILE)   "$<" -c -o "$@"
+
+# Additional dependency: objc-msg.s depends on objc-msg-ppc.s and 
+# objc-msg-i386.s, which it includes.
+$(OBJROOT)/runtime/Messengers.subproj/objc-msg.opt.o \
+$(OBJROOT)/runtime/Messengers.subproj/objc-msg.debug.o \
+$(OBJROOT)/runtime/Messengers.subproj/objc-msg.profile.o : \
+       $(SRCROOT)/runtime/Messengers.subproj/objc-msg-ppc.s \
+       $(SRCROOT)/runtime/Messengers.subproj/objc-msg-i386.s
+
+
+# These are the main targets:
+#    build             builds the library to OBJROOT and SYMROOT
+#    installsrc                copies the sources to SRCROOT
+#    installhdrs       install only the headers to DSTROOT
+#    install           build, then install the headers and library to DSTROOT
+#    clean             removes build products in OBJROOT and SYMROOT
 #
+#    optimized          same as 'build' but builds optimized library only
+#    debug              same as 'build' but builds debug library only
+#    profile            same as 'build' but builds profile library only
+
+# Default build doesn't currently build the debug library.
+build: prebuild build-optimized build-profile postbuild
+
+optimized: prebuild build-optimized postbuild
+debug: prebuild build-debug postbuild
+profile: prebuild build-profile postbuild
+
+installsrc:
+       $(SILENT) $(ECHO) "Installing source from . to $(SRCROOT)..."
+ifeq "$(SRCROOT)" "."
+       $(SILENT) $(ECHO) "SRCROOT must be defined to be the destination directory; it cannot be '.'"
+       exit 1
+endif
+       $(SILENT) $(TAR) -cf $(SRCROOT)/objc4.sources.tar $(SOURCES) $(PUBLIC_HEADERS) $(PRIVATE_HEADERS) $(OTHER_HEADERS) $(OTHER_SOURCES)
+       $(SILENT) $(CD) $(SRCROOT) && $(TAR) -xf $(SRCROOT)/objc4.sources.tar 
+       $(SILENT) $(REMOVE) -f $(SRCROOT)/objc4.sources.tar
+
+installhdrs:
+       $(SILENT) $(ECHO) "Installing headers from $(SRCROOT) to $(DSTROOT)/$(HEADER_INSTALLDIR)..."
+
+       $(SILENT) $(MKDIRS) $(DSTROOT)/$(PUBLIC_HEADER_INSTALLDIR)
+       -$(SILENT) $(CHMOD) +w $(DSTROOT)/$(PUBLIC_HEADER_INSTALLDIR)/*.h
+       $(SILENT) $(COPY) $(addprefix $(SRCROOT)/, $(PUBLIC_HEADERS) ) \
+                          $(DSTROOT)/$(PUBLIC_HEADER_INSTALLDIR)
+# duplicate hashtable2.h to hashtable.h
+       $(SILENT) $(COPY) $(DSTROOT)/$(PUBLIC_HEADER_INSTALLDIR)/hashtable2.h \
+                         $(DSTROOT)/$(PUBLIC_HEADER_INSTALLDIR)/hashtable.h
+       $(SILENT) $(CHMOD) -w  $(DSTROOT)/$(PUBLIC_HEADER_INSTALLDIR)/*.h
+       $(SILENT) $(CHMOD) a+r $(DSTROOT)/$(PUBLIC_HEADER_INSTALLDIR)/*.h
+
+       $(SILENT) $(MKDIRS) $(DSTROOT)/$(OTHER_HEADER_INSTALLDIR)
+       -$(SILENT) $(CHMOD) +w $(DSTROOT)/$(OTHER_HEADER_INSTALLDIR)/*.h
+       $(SILENT) $(COPY) $(addprefix $(SRCROOT)/, $(OTHER_HEADERS) ) \
+                          $(DSTROOT)/$(OTHER_HEADER_INSTALLDIR)
+       $(SILENT) $(CHMOD) -w  $(DSTROOT)/$(OTHER_HEADER_INSTALLDIR)/*.h
+       $(SILENT) $(CHMOD) a+r $(DSTROOT)/$(OTHER_HEADER_INSTALLDIR)/*.h
+
+
+       $(SILENT) $(RM) -f $(DSTROOT)$(PUBLIC_HEADER_DIR)$(PUBLIC_HEADER_DIR_SUFFIX)/hashtable.h
+
+
+install: build installhdrs
+       $(SILENT) $(ECHO) "Installing products from $(SYMROOT) to $(DSTROOT)..."
+
+       $(SILENT) $(MKDIRS) $(DSTROOT)/$(INSTALLDIR)
+       -$(SILENT) $(CHMOD) +w $(DSTROOT)/$(INSTALLDIR)
+
+       $(SILENT) $(REMOVE) -f $(DSTROOT)/$(INSTALLDIR)/libobjc.$(VERSION_NAME)$(LIBRARY_EXT)
+       $(SILENT) $(REMOVE) -f $(DSTROOT)/$(INSTALLDIR)/libobjc_debug.$(VERSION_NAME)$(LIBRARY_EXT)
+       $(SILENT) $(REMOVE) -f $(DSTROOT)/$(INSTALLDIR)/libobjc_profile.$(VERSION_NAME)$(LIBRARY_EXT)
+
+# optimized
+       $(SILENT) $(COPY) $(SYMROOT)/libobjc.$(VERSION_NAME)$(LIBRARY_EXT) $(DSTROOT)/$(INSTALLDIR)
+       -$(SILENT) $(CHOWN) root:wheel $(DSTROOT)/$(INSTALLDIR)/libobjc.$(VERSION_NAME)$(LIBRARY_EXT)
+       $(SILENT) $(CHMOD) 755 $(DSTROOT)/$(INSTALLDIR)/libobjc.$(VERSION_NAME)$(LIBRARY_EXT)
+       $(SILENT) $(CD) $(DSTROOT)/$(INSTALLDIR)  &&  \
+               $(SYMLINK) libobjc.$(VERSION_NAME)$(LIBRARY_EXT) libobjc$(LIBRARY_EXT)
+
+# debug (allowed not to exist)
+       -$(SILENT) $(COPY) $(SYMROOT)/libobjc_debug.$(VERSION_NAME)$(LIBRARY_EXT) $(DSTROOT)/$(INSTALLDIR)
+       -$(SILENT) $(CHOWN) root:wheel $(DSTROOT)/$(INSTALLDIR)/libobjc_debug.$(VERSION_NAME)$(LIBRARY_EXT)
+       -$(SILENT) $(CHMOD) 755 $(DSTROOT)/$(INSTALLDIR)/libobjc_debug.$(VERSION_NAME)$(LIBRARY_EXT)
+       -$(SILENT) $(CD) $(DSTROOT)/$(INSTALLDIR)  &&  \
+               test -e libobjc_debug.$(VERSION_NAME)$(LIBRARY_EXT)  &&  \
+               $(SYMLINK) libobjc_debug.$(VERSION_NAME)$(LIBRARY_EXT) libobjc_debug$(LIBRARY_EXT)  &&  \
+               $(SYMLINK) libobjc_debug.$(VERSION_NAME)$(LIBRARY_EXT) libobjc.$(VERSION_NAME)_debug$(LIBRARY_EXT)
+
+
+# profile (allowed not to exist)
+       -$(SILENT) $(COPY) $(SYMROOT)/libobjc_profile.$(VERSION_NAME)$(LIBRARY_EXT) $(DSTROOT)/$(INSTALLDIR)
+       -$(SILENT) $(CHOWN) root:wheel $(DSTROOT)/$(INSTALLDIR)/libobjc_profile.$(VERSION_NAME)$(LIBRARY_EXT)
+       -$(SILENT) $(CHMOD) 755 $(DSTROOT)/$(INSTALLDIR)/libobjc_profile.$(VERSION_NAME)$(LIBRARY_EXT)
+       -$(SILENT) $(CD) $(DSTROOT)/$(INSTALLDIR)  &&  \
+               test -e libobjc_profile.$(VERSION_NAME)$(LIBRARY_EXT)  &&  \
+               $(SYMLINK) libobjc_profile.$(VERSION_NAME)$(LIBRARY_EXT) libobjc_profile$(LIBRARY_EXT)  &&  \
+               $(SYMLINK) libobjc_profile.$(VERSION_NAME)$(LIBRARY_EXT) libobjc.$(VERSION_NAME)_profile$(LIBRARY_EXT)
+
+
+clean:
+       $(SILENT) $(ECHO) "Deleting build products..."
+       $(foreach A, $(ARCH_LIST), \
+               $(SILENT) $(REMOVE) -f $(OBJROOT)/libobjc_debug.$A.o $(OBJROOT)/libobjc_profile.$A.o $(OBJROOT)/libobjc.$A.o ; )
+
+       $(SILENT) $(REMOVE) -f $(SYMROOT)/libobjc.optimized.o
+       $(SILENT) $(REMOVE) -f $(SYMROOT)/libobjc.debug.o
+       $(SILENT) $(REMOVE) -f $(SYMROOT)/libobjc.profile.o
+
+       $(SILENT) $(REMOVE) -f $(SYMROOT)/libobjc.$(VERSION_NAME)$(LIBRARY_EXT)
+       $(SILENT) $(REMOVE) -f $(SYMROOT)/libobjc_debug.$(VERSION_NAME)$(LIBRARY_EXT)
+       $(SILENT) $(REMOVE) -f $(SYMROOT)/libobjc_profile.$(VERSION_NAME)$(LIBRARY_EXT)
+
+       $(SILENT) $(REMOVE) -f $(OBJECTS_OPTIMIZED)
+       $(SILENT) $(REMOVE) -f $(OBJECTS_DEBUG)
+       $(SILENT) $(REMOVE) -f $(OBJECTS_PROFILE)
+
+       $(SILENT) $(REMOVE) -rf $(SYMROOT)/ProjectHeaders
+
+prebuild:
+       $(SILENT) $(ECHO) "Prebuild-setup..."
+
+# Install headers into $(SYMROOT)/ProjectHeaders so #includes can find them 
+# even if they're not installed in /usr. 
+       $(SILENT) $(MKDIRS) $(SYMROOT)
+       $(SILENT) $(REMOVE_RECUR) $(SYMROOT)/ProjectHeaders
+       $(SILENT) $(MKDIRS) $(SYMROOT)/ProjectHeaders
+       $(SILENT) $(ECHO) "Copying headers from $(SRCROOT) to $(SYMROOT)/ProjectHeaders..."
+       $(SILENT) $(COPY) $(addprefix $(SRCROOT)/, $(PRIVATE_HEADERS) ) $(SYMROOT)/ProjectHeaders
+       $(SILENT) $(MKDIRS) $(SYMROOT)/ProjectHeaders/objc
+       $(SILENT) $(COPY) $(addprefix $(SRCROOT)/, $(PUBLIC_HEADERS) ) $(SYMROOT)/ProjectHeaders/objc
+       $(SILENT) $(COPY) $(addprefix $(SRCROOT)/, $(OTHER_HEADERS) ) $(SYMROOT)/ProjectHeaders/objc
+
+
+
+build-optimized: prebuild-optimized compile-optimized link-optimized
+build-debug: prebuild-debug compile-debug link-debug
+build-profile: prebuild-profile compile-profile link-profile
+
+
+prebuild-optimized:
+       $(SILENT) $(ECHO) "Building (optimized) ..."
+       $(SILENT) $(MKDIRS) $(foreach S, $(SUBDIRS), $(OBJROOT)/$(S) )
+
+prebuild-debug:
+       $(SILENT) $(ECHO) "Building (debug) ..."
+       $(SILENT) $(MKDIRS) $(foreach S, $(SUBDIRS), $(OBJROOT)/$(S) )
+
+prebuild-profile:
+       $(SILENT) $(ECHO) "Building (profile) ..."
+       $(SILENT) $(MKDIRS) $(foreach S, $(SUBDIRS), $(OBJROOT)/$(S) )
+
 
-NAME = objc4
+compile-optimized: $(OBJECTS_OPTIMIZED)
+compile-debug: $(OBJECTS_DEBUG)
+compile-profile: $(OBJECTS_PROFILE)
 
-PROJECTVERSION = 2.8
-PROJECT_TYPE = Aggregate
 
-LIBRARIES = runtime
+# link lib-suffix, LDFLAGS, OBJECTS
+#  libsuffix should be "" or _debug or _profile
+ifeq "$(PLATFORM)" "Darwin"
 
-OTHERSRCS = Makefile.preamble Makefile Makefile.postamble
+define link
+       $(foreach A, $(ARCH_LIST), \
+               $(SILENT) $(LD) -arch $A -r -o $(OBJROOT)/libobjc$1.$A.o $3 ; )
+       $(foreach A, $(ARCH_LIST), \
+               -$(SILENT) $(NMEDIT) -s $(SRCROOT)/objc-exports \
+                       $(OBJROOT)/libobjc$1.$A.o ; )
+       $(SILENT) $(CC) $2 \
+                -Wl,-init,__objcInit \
+                -install_name /$(INSTALLDIR)/libobjc$1.$(VERSION_NAME)$(LIBRARY_EXT) \
+                -o $(SYMROOT)/libobjc$1.$(VERSION_NAME)$(LIBRARY_EXT) \
+               $(foreach A, $(ARCH_LIST), $(OBJROOT)/libobjc$1.$A.o )
+endef
 
-MAKEFILEDIR = $(MAKEFILEPATH)/pb_makefiles
-CODE_GEN_STYLE = DYNAMIC
-MAKEFILE = aggregate.make
-LIBS = 
-DEBUG_LIBS = $(LIBS)
-PROF_LIBS = $(LIBS)
+else
+# PLATFORM != Darwin
+define link
+       $(SILENT) $(ECHO) "Don't know how to link for platform '$(PLATFORM)'"
+endef
 
+endif
 
 
+link-optimized:
+       $(SILENT) $(ECHO) "Linking (optimized)..."
+       $(call link,,$(LDFLAGS_OPTIMIZED),$(OBJECTS_OPTIMIZED) )
+       $(SILENT) $(STRIP) -x $(SYMROOT)/libobjc.$(VERSION_NAME)$(LIBRARY_EXT)
 
-NEXTSTEP_OBJCPLUS_COMPILER = /usr/bin/cc
-WINDOWS_OBJCPLUS_COMPILER = $(DEVDIR)/gcc
-PDO_UNIX_OBJCPLUS_COMPILER = $(NEXTDEV_BIN)/gcc
-NEXTSTEP_JAVA_COMPILER = /usr/bin/javac
-WINDOWS_JAVA_COMPILER = $(JDKBINDIR)/javac.exe
-PDO_UNIX_JAVA_COMPILER = $(JDKBINDIR)/javac
+link-debug:
+       $(SILENT) $(ECHO) "Linking (debug)..."
+       $(call link,_debug,$(LDFLAGS_DEBUG),$(OBJECTS_DEBUG) )
 
-include $(MAKEFILEDIR)/platform.make
+link-profile:
+       $(SILENT) $(ECHO) "Linking (profile)..."
+       $(call link,_profile,$(LDFLAGS_PROFILE),$(OBJECTS_PROFILE))
 
--include Makefile.preamble
 
-include $(MAKEFILEDIR)/$(MAKEFILE)
+postbuild:
+       $(SILENT) $(ECHO) "Done!"
 
--include Makefile.postamble
 
--include Makefile.dependencies
diff --git a/Makefile.postamble b/Makefile.postamble
deleted file mode 100644 (file)
index e69de29..0000000
diff --git a/Makefile.preamble b/Makefile.preamble
deleted file mode 100644 (file)
index e41455c..0000000
+++ /dev/null
@@ -1,5 +0,0 @@
-
-ifeq "$(PLATFORM_OS)" "macos"
-       BEFORE_INSTALL += profile
-endif
-
diff --git a/PB.project b/PB.project
deleted file mode 100644 (file)
index a8d3155..0000000
+++ /dev/null
@@ -1,24 +0,0 @@
-{
-    DYNAMIC_CODE_GEN = YES; 
-    FILESTABLE = {
-        CLASSES = (); 
-        H_FILES = (); 
-        OTHER_SOURCES = (Makefile.preamble, Makefile, Makefile.postamble); 
-        SUBPROJECTS = (runtime); 
-    }; 
-    LANGUAGE = English; 
-    LOCALIZABLE_FILES = {}; 
-    MAKEFILEDIR = "$(MAKEFILEPATH)/pb_makefiles"; 
-    NEXTSTEP_BUILDTOOL = /bin/gnumake; 
-    NEXTSTEP_JAVA_COMPILER = /usr/bin/javac; 
-    NEXTSTEP_OBJCPLUS_COMPILER = /usr/bin/cc; 
-    PDO_UNIX_BUILDTOOL = $NEXT_ROOT/Developer/bin/make; 
-    PDO_UNIX_JAVA_COMPILER = "$(JDKBINDIR)/javac"; 
-    PDO_UNIX_OBJCPLUS_COMPILER = "$(NEXTDEV_BIN)/gcc"; 
-    PROJECTNAME = objc4; 
-    PROJECTTYPE = Aggregate; 
-    PROJECTVERSION = 2.8; 
-    WINDOWS_BUILDTOOL = $NEXT_ROOT/Developer/Executables/make; 
-    WINDOWS_JAVA_COMPILER = "$(JDKBINDIR)/javac.exe"; 
-    WINDOWS_OBJCPLUS_COMPILER = "$(DEVDIR)/gcc"; 
-}
diff --git a/objc-exports b/objc-exports
new file mode 100644 (file)
index 0000000..df930c8
--- /dev/null
@@ -0,0 +1,144 @@
+# Functions and variables explicitly exported from ObjC.
+# GrP 2002-2-4
+# Note that some commonly used functions are *not* listed in the 
+# ObjC headers (e.g. objc_flush_caches())
+# List.h
+.objc_class_name_List
+# objc-class.h
+_object_setInstanceVariable
+_object_getInstanceVariable
+_class_createInstance
+_class_createInstanceFromZone
+_class_setVersion
+_class_getVersion
+_class_getInstanceVariable
+_class_getInstanceMethod
+_class_getClassMethod
+_class_addMethods
+_class_removeMethods
+_class_poseAs
+_method_getNumberOfArguments
+_method_getSizeOfArguments
+_method_getArgumentInfo
+_class_nextMethodList
+# objc-load.h
+_objc_loadModules
+_objc_loadModule
+_objc_unloadModules
+# objc-runtime.h
+# fixme does anybody use objc_msgSendFew* ?
+_objc_getClass
+_objc_getMetaClass
+_objc_msgSend
+_objc_msgSend_stret
+_objc_msgSendSuper
+_objc_msgSendSuper_stret
+_objc_msgSendv
+_objc_msgSendv_stret
+_objc_getClassList
+_objc_getClasses
+_objc_lookUpClass
+_objc_addClass
+_objc_setClassHandler
+_objc_setMultithreaded
+__alloc
+__copy
+__realloc
+__dealloc
+__zoneAlloc
+__zoneRealloc
+__zoneCopy
+__error
+# objc.h
+_sel_isMapped
+_sel_getName
+_sel_getUid
+_sel_registerName
+_object_getClassName
+_object_getIndexedIvars
+# Object.h
+.objc_class_name_Object
+_object_dispose
+_object_copy
+_object_copyFromZone
+_object_realloc
+_object_reallocFromZone
+# Protocol.h
+.objc_class_name_Protocol
+# error.h
+# everything inside is declared but no longer defined?!
+# hashtable2.h
+_NXCreateHashTableFromZone
+_NXCreateHashTable
+_NXFreeHashTable
+_NXEmptyHashTable
+_NXResetHashTable
+_NXCompareHashTables
+_NXCopyHashTable
+_NXCountHashTable
+_NXHashMember
+_NXHashGet
+_NXHashInsert
+_NXHashInsertIfAbsent
+_NXHashRemove
+_NXInitHashState
+_NXNextHashState
+_NXPtrHash
+_NXStrHash
+_NXPtrIsEqual
+_NXStrIsEqual
+_NXNoEffectFree
+_NXReallyFree
+_NXPtrPrototype
+_NXStrPrototype
+_NXPtrStructKeyPrototype
+_NXStrStructKeyPrototype
+_NXUniqueString
+_NXUniqueStringWithLength
+_NXUniqueStringNoCopy
+_NXCopyStringBuffer
+_NXCopyStringBufferFromZone
+# maptable.h
+_NXCreateMapTableFromZone
+_NXCreateMapTable
+_NXFreeMapTable
+_NXResetMapTable
+_NXCompareMapTables
+_NXCountMapTable
+_NXMapMember
+_NXMapGet
+_NXMapInsert
+_NXMapRemove
+_NXInitMapState
+_NXNextMapState
+_NXPtrValueMapPrototype
+_NXStrValueMapPrototype
+_NXObjectMapPrototype
+#
+# Functions that aren't in the headers but are used or are useful.
+#
+# sudo find / -xdev -type f -perm -0111 \! -name "libobjc*dylib" -print -exec nm -u {} \; > /tmp/all-used-symbols
+# (repeat with any other disks you want checked, appending to the same file)
+# nm /usr/lib/libobjc.dylib | awk '$2 ~ /^[ADST]$/' | colrm 1 11 | sort -u > /tmp/objc-exports
+# (note that you need an unstripped, un-nmedited libobjc.dylib)
+# grep -f /tmp/objc-exports /tmp/all-used-symbols | sort -u > /tmp/used-objc-symbols
+# grep -v -f /tmp/used-objc-symbols /tmp/objc-exports | sort -u > /tmp/unused-objc-symbols
+#
+__class_printDuplicateCacheEntries
+__class_printMethodCaches
+__class_printMethodCacheStatistics
+__objc_create_zone
+__objc_error
+__objc_flush_caches
+__objc_msgForward
+__objcInit
+_class_lookupMethod
+_class_respondsToMethod
+_instrumentObjcMessageSends
+_objc_getOrigClass
+# magic, or garbage?
+__dummy 
+_do_not_remove_this_dummy_function
+# used by debugging tools like heap
+__objc_debug_class_hash
+
diff --git a/runtime/Makefile b/runtime/Makefile
deleted file mode 100644 (file)
index ec9acaa..0000000
+++ /dev/null
@@ -1,65 +0,0 @@
-#
-# Generated by the Apple Project Builder.
-#
-# NOTE: Do NOT change this file -- Project Builder maintains it.
-#
-# Put all of your customizations in files called Makefile.preamble
-# and Makefile.postamble (both optional), and Makefile will include them.
-#
-
-NAME = runtime
-
-PROJECTVERSION = 2.8
-PROJECT_TYPE = Library
-
-HFILES = error.h hashtable2.h maptable.h objc-api.h objc-class.h\
-         objc-config.h objc-load.h objc-private.h objc-runtime.h\
-         objc.h Object.h Protocol.h
-
-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
-
-CFILES = objc-moninit.c
-
-SUBPROJECTS = Messengers.subproj OldClasses.subproj
-
-OTHERSRCS = Makefile.preamble Makefile Makefile.postamble
-
-
-MAKEFILEDIR = $(MAKEFILEPATH)/pb_makefiles
-CURRENTLY_ACTIVE_VERSION = YES
-DEPLOY_WITH_VERSION_NAME = A
-CODE_GEN_STYLE = DYNAMIC
-MAKEFILE = library.make
-NEXTSTEP_INSTALLDIR = /usr/lib
-WINDOWS_INSTALLDIR = /.
-PDO_UNIX_INSTALLDIR = $(LOCAL_DEVELOPER_DIR)/Libraries
-LIBS = 
-DEBUG_LIBS = $(LIBS)
-PROF_LIBS = $(LIBS)
-
-
-PUBLIC_HEADERS = objc-class.h objc-api.h objc-load.h objc-runtime.h\
-                 objc.h Object.h Protocol.h error.h hashtable2.h
-
-PROJECT_HEADERS = objc-runtime.h objc-class.h
-
-
-
-NEXTSTEP_OBJCPLUS_COMPILER = /usr/bin/cc
-WINDOWS_OBJCPLUS_COMPILER = $(DEVDIR)/gcc
-PDO_UNIX_OBJCPLUS_COMPILER = $(NEXTDEV_BIN)/gcc
-NEXTSTEP_JAVA_COMPILER = /usr/bin/javac
-WINDOWS_JAVA_COMPILER = $(JDKBINDIR)/javac.exe
-PDO_UNIX_JAVA_COMPILER = $(NEXTDEV_BIN)/javac
-
-include $(MAKEFILEDIR)/platform.make
-
--include Makefile.preamble
-
-include $(MAKEFILEDIR)/$(MAKEFILE)
-
--include Makefile.postamble
-
--include Makefile.dependencies
diff --git a/runtime/Makefile.postamble b/runtime/Makefile.postamble
deleted file mode 100644 (file)
index 193b70c..0000000
+++ /dev/null
@@ -1,27 +0,0 @@
-###############################################################################
-#  Makefile.postamble
-#  Copyright 1997,2000 Apple Computer, Inc.
-###############################################################################
-
-ifeq "$(PLATFORM_OS)" "macos"
-
-PROFILE_PRODUCT = $(PRODUCT_DIR)/$(LIBRARY_PREFIX)$(NAME)$(PROFILE_SUFFIX)$(LIBRARY_EXT)
-VERSIONED_PROFILE_PRODUCT = $(PRODUCT_DIR)/$(LIBRARY_PREFIX)$(NAME)$(PROFILE_SUFFIX).$(VERSION_NAME)$(LIBRARY_EXT)
-PRODUCTS += $(PROFILE_PRODUCT) $(VERSIONED_PROFILE_PRODUCT) 
-STRIPPED_PRODUCTS += $(VERSIONED_PROFILE_PRODUCT)
-DYLIB_INSTALL_NAME = $(LIBRARY_PREFIX)$(NAME)$(BUILD_TYPE_SUFFIX).$(VERSION_NAME)$(LIBRARY_EXT)
-PRODUCT = $(PRODUCT_DIR)/$(DYLIB_INSTALL_NAME)
-
-endif
-
-create-profile-lib-compat-link:
-       $(SYMLINK) $(notdir $(VERSIONED_PROFILE_PRODUCT)) $(DSTROOT)$(INSTALLDIR)/libobjc.A_profile.dylib
-
-link-hashtable:
-       $(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
-       true
-
-# from AFTER_POSTINSTALL
-postprocess:
-
diff --git a/runtime/Makefile.preamble b/runtime/Makefile.preamble
deleted file mode 100644 (file)
index 83a3305..0000000
+++ /dev/null
@@ -1,31 +0,0 @@
-###############################################################################
-#  Makefile.preamble
-#  Copyright 1997,2000 Apple Computer, Inc.
-###############################################################################
-
-
-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
-
-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:
-PUBLIC_HEADER_DIR_SUFFIX = /objc
-PRIVATE_HEADER_DIR_SUFFIX = /objc
-
-OTHER_PUBLIC_HEADERS = 
-OTHER_PRIVATE_HEADERS = maptable.h 
-OTHER_PROJECT_HEADERS = $(PUBLIC_HEADERS) $(OTHER_PRIVATE_HEADERS) objc-private.h objc-config.h
-
diff --git a/runtime/Messengers.subproj/Makefile b/runtime/Messengers.subproj/Makefile
deleted file mode 100644 (file)
index df1daed..0000000
+++ /dev/null
@@ -1,47 +0,0 @@
-#
-# Generated by the Apple Project Builder.
-#
-# NOTE: Do NOT change this file -- Project Builder maintains it.
-#
-# Put all of your customizations in files called Makefile.preamble
-# and Makefile.postamble (both optional), and Makefile will include them.
-#
-
-NAME = Messengers
-
-PROJECTVERSION = 2.8
-PROJECT_TYPE = Component
-
-OTHERLINKED = objc-msg.s
-
-OTHERSRCS = Makefile.preamble Makefile Makefile.postamble\
-            objc-msg-i386.s objc-msg-ppc.s
-
-OTHERLINKEDOFILES = objc-msg.o
-
-MAKEFILEDIR = $(MAKEFILEPATH)/pb_makefiles
-CODE_GEN_STYLE = DYNAMIC
-MAKEFILE = subproj.make
-LIBS = 
-DEBUG_LIBS = $(LIBS)
-PROF_LIBS = $(LIBS)
-
-
-
-
-NEXTSTEP_OBJCPLUS_COMPILER = /usr/bin/cc
-WINDOWS_OBJCPLUS_COMPILER = $(DEVDIR)/gcc
-PDO_UNIX_OBJCPLUS_COMPILER = $(NEXTDEV_BIN)/gcc
-NEXTSTEP_JAVA_COMPILER = /usr/bin/javac
-WINDOWS_JAVA_COMPILER = $(JDKBINDIR)/javac.exe
-PDO_UNIX_JAVA_COMPILER = $(NEXTDEV_BIN)/javac
-
-include $(MAKEFILEDIR)/platform.make
-
--include Makefile.preamble
-
-include $(MAKEFILEDIR)/$(MAKEFILE)
-
--include Makefile.postamble
-
--include Makefile.dependencies
diff --git a/runtime/Messengers.subproj/Makefile.postamble b/runtime/Messengers.subproj/Makefile.postamble
deleted file mode 100644 (file)
index db6b4a2..0000000
+++ /dev/null
@@ -1,100 +0,0 @@
-###############################################################################
-#  Makefile.postamble
-#  Copyright 1997, Apple Computer, Inc.
-#
-#  Use this makefile, which is imported after all other makefiles, to
-#  override attributes for a project's Makefile environment. This allows you  
-#  to take advantage of the environment set up by the other Makefiles. 
-#  You can also define custom rules at the end of this file.
-#
-###############################################################################
-# 
-# These variables are exported by the standard makefiles and can be 
-# used in any customizations you make.  They are *outputs* of
-# the Makefiles and should be used, not set.
-# 
-#  PRODUCTS: products to install.  All of these products will be placed in
-#       the directory $(DSTROOT)$(INSTALLDIR)
-#  GLOBAL_RESOURCE_DIR: The directory to which resources are copied.
-#  LOCAL_RESOURCE_DIR: The directory to which localized resources are copied.
-#  OFILE_DIR: Directory into which .o object files are generated.
-#  DERIVED_SRC_DIR: Directory used for all other derived files
-#
-#  ALL_CFLAGS:  flags to pass when compiling .c files
-#  ALL_MFLAGS:  flags to pass when compiling .m files
-#  ALL_CCFLAGS:  flags to pass when compiling .cc, .cxx, and .C files
-#  ALL_MMFLAGS:  flags to pass when compiling .mm, .mxx, and .M files
-#  ALL_PRECOMPFLAGS:  flags to pass when precompiling .h files
-#  ALL_LDFLAGS:  flags to pass when linking object files
-#  ALL_LIBTOOL_FLAGS:  flags to pass when libtooling object files
-#  ALL_PSWFLAGS:  flags to pass when processing .psw and .pswm (pswrap) files
-#  ALL_RPCFLAGS:  flags to pass when processing .rpc (rpcgen) files
-#  ALL_YFLAGS:  flags to pass when processing .y (yacc) files
-#  ALL_LFLAGS:  flags to pass when processing .l (lex) files
-#
-#  NAME: name of application, bundle, subproject, palette, etc.
-#  LANGUAGE: langage in which the project is written (default "English")
-#  LOCAL_RESOURCES: localized resources (e.g. nib's, images) of project
-#  GLOBAL_RESOURCES: non-localized resources of project
-#
-#  SRCROOT:  base directory in which to place the new source files
-#  SRCPATH:  relative path from SRCROOT to present subdirectory
-#
-#  INSTALLDIR: Directory the product will be installed into by 'install' target
-#  PUBLIC_HDR_INSTALLDIR: where to install public headers.  Don't forget
-#        to prefix this with DSTROOT when you use it.
-#  PRIVATE_HDR_INSTALLDIR: where to install private headers.  Don't forget
-#       to prefix this with DSTROOT when you use it.
-#
-#  EXECUTABLE_EXT: Executable extension for the platform (i.e. .exe on Windows)
-#
-###############################################################################
-
-# Some compiler flags can be overridden here for certain build situations.
-#
-#    WARNING_CFLAGS:  flag used to set warning level (defaults to -Wmost)
-#    DEBUG_SYMBOLS_CFLAGS:  debug-symbol flag passed to all builds (defaults
-#      to -g)
-#    DEBUG_BUILD_CFLAGS:  flags passed during debug builds (defaults to -DDEBUG)
-#    OPTIMIZE_BUILD_CFLAGS:  flags passed during optimized builds (defaults
-#      to -O)
-#    PROFILE_BUILD_CFLAGS:  flags passed during profile builds (defaults
-#      to -pg -DPROFILE)
-#    LOCAL_DIR_INCLUDE_DIRECTIVE:  flag used to add current directory to
-#      the include path (defaults to -I.)
-#    DEBUG_BUILD_LDFLAGS, OPTIMIZE_BUILD_LDFLAGS, PROFILE_BUILD_LDFLAGS: flags
-#      passed to ld/libtool (defaults to nothing)
-
-
-# Library and Framework projects only:
-#    INSTALL_NAME_DIRECTIVE:  This directive ensures that executables linked
-#      against the framework will run against the correct version even if
-#      the current version of the framework changes.  You may override this
-#      to "" as an alternative to using the DYLD_LIBRARY_PATH during your
-#      development cycle, but be sure to restore it before installing.
-
-
-# Ownership and permissions of files installed by 'install' target
-
-#INSTALL_AS_USER = root
-        # User/group ownership 
-#INSTALL_AS_GROUP = wheel
-        # (probably want to set both of these) 
-#INSTALL_PERMISSIONS =
-        # If set, 'install' chmod's executable to this
-
-
-# Options to strip.  Note: -S strips debugging symbols (executables can be stripped
-# down further with -x or, if they load no bundles, with no options at all).
-
-#STRIPFLAGS = -S
-
-
-#########################################################################
-# Put rules to extend the behavior of the standard Makefiles here.  Include them in
-# the dependency tree via cvariables like AFTER_INSTALL in the Makefile.preamble.
-#
-# You should avoid redefining things like "install" or "app", as they are
-# owned by the top-level Makefile API and no context has been set up for where 
-# derived files should go.
-#
diff --git a/runtime/Messengers.subproj/Makefile.preamble b/runtime/Messengers.subproj/Makefile.preamble
deleted file mode 100644 (file)
index 83f25c7..0000000
+++ /dev/null
@@ -1,123 +0,0 @@
-###############################################################################
-#  Makefile.preamble
-#  Copyright 1997, Apple Computer, Inc.
-#
-#  Use this makefile for configuring the standard application makefiles 
-#  associated with ProjectBuilder. It is included before the main makefile.
-#  In Makefile.preamble you set attributes for a project, so they are available
-#  to the project's makefiles.  In contrast, you typically write additional rules or 
-#  override built-in behavior in the Makefile.postamble.
-#  
-#  Each directory in a project tree (main project plus subprojects) should 
-#  have its own Makefile.preamble and Makefile.postamble.
-###############################################################################
-#
-# Before the main makefile is included for this project, you may set:
-#
-#    MAKEFILEDIR: Directory in which to find $(MAKEFILE)
-#    MAKEFILE: Top level mechanism Makefile (e.g., app.make, bundle.make)
-
-# Compiler/linker flags added to the defaults:  The OTHER_* variables will be 
-# inherited by all nested sub-projects, but the LOCAL_ versions of the same
-# variables will not.  Put your -I, -D, -U, and -L flags in ProjectBuilder's
-# Build Attributes inspector if at all possible.  To override the default flags
-# that get passed to ${CC} (e.g. change -O to -O2), see Makefile.postamble.  The
-# variables below are *inputs* to the build process and distinct from the override
-# settings done (less often) in the Makefile.postamble.
-#
-#    OTHER_CFLAGS, LOCAL_CFLAGS:  additional flags to pass to the compiler
-#      Note that $(OTHER_CFLAGS) and $(LOCAL_CFLAGS) are used for .h, ...c, .m,
-#      .cc, .cxx, .C, and .M files.  There is no need to respecify the
-#      flags in OTHER_MFLAGS, etc.
-#    OTHER_MFLAGS, LOCAL_MFLAGS:  additional flags for .m files
-#    OTHER_CCFLAGS, LOCAL_CCFLAGS:  additional flags for .cc, .cxx, and ...C files
-#    OTHER_MMFLAGS, LOCAL_MMFLAGS:  additional flags for .mm and .M files
-#    OTHER_PRECOMPFLAGS, LOCAL_PRECOMPFLAGS:  additional flags used when
-#      precompiling header files
-#    OTHER_LDFLAGS, LOCAL_LDFLAGS:  additional flags passed to ld and libtool
-#    OTHER_PSWFLAGS, LOCAL_PSWFLAGS:  additional flags passed to pswrap
-#    OTHER_RPCFLAGS, LOCAL_RPCFLAGS:  additional flags passed to rpcgen
-#    OTHER_YFLAGS, LOCAL_YFLAGS:  additional flags passed to yacc
-#    OTHER_LFLAGS, LOCAL_LFLAGS:  additional flags passed to lex
-
-# These variables provide hooks enabling you to add behavior at almost every 
-# stage of the make:
-#
-#    BEFORE_PREBUILD: targets to build before installing headers for a subproject
-#    AFTER_PREBUILD: targets to build after installing headers for a subproject
-#    BEFORE_BUILD_RECURSION: targets to make before building subprojects
-#    BEFORE_BUILD: targets to make before a build, but after subprojects
-#    AFTER_BUILD: targets to make after a build
-#
-#    BEFORE_INSTALL: targets to build before installing the product
-#    AFTER_INSTALL: targets to build after installing the product
-#    BEFORE_POSTINSTALL: targets to build before postinstalling every subproject
-#    AFTER_POSTINSTALL: targts to build after postinstalling every subproject
-#
-#    BEFORE_INSTALLHDRS: targets to build before installing headers for a 
-#         subproject
-#    AFTER_INSTALLHDRS: targets to build after installing headers for a subproject
-#    BEFORE_INSTALLSRC: targets to build before installing source for a subproject
-#    AFTER_INSTALLSRC: targets to build after installing source for a subproject
-#
-#    BEFORE_DEPEND: targets to build before building dependencies for a
-#        subproject
-#    AFTER_DEPEND: targets to build after building dependencies for a
-#        subproject
-#
-#    AUTOMATIC_DEPENDENCY_INFO: if YES, then the dependency file is
-#        updated every time the project is built.  If NO, the dependency
-#        file is only built when the depend target is invoked.
-
-# Framework-related variables:
-#    FRAMEWORK_DLL_INSTALLDIR:  On Windows platforms, this variable indicates
-#      where to put the framework's DLL.  This variable defaults to 
-#      $(INSTALLDIR)/../Executables
-
-# Library-related variables:
-#    PUBLIC_HEADER_DIR:  Determines where public exported header files
-#      should be installed.  Do not include $(DSTROOT) in this value --
-#      it is prefixed automatically.
-#    PRIVATE_HEADER_DIR:  Determines where private exported header files
-#      should be installed.  Do not include $(DSTROOT) in this value --
-#      it is prefixed automatically.
-#    LIBRARY_STYLE:  This may be either STATIC or DYNAMIC, and determines
-#      whether the libraries produced are statically linked when they
-#      are used or if they are dynamically loadable. <<default?>>
-#    LIBRARY_DLL_INSTALLDIR:  On Windows platforms, this variable indicates
-#      where to put the library's DLL.  This variable defaults to 
-#      $(INSTALLDIR)/../Executables
-#
-#    INSTALL_AS_USER: owner of the intalled products (default root)
-#    INSTALL_AS_GROUP: group of the installed products (default wheel)
-#    INSTALL_PERMISSION: permissions of the installed product (default o+rX)
-#
-#    OTHER_RECURSIVE_VARIABLES: The names of variables which you want to be
-#      passed on the command line to recursive invocations of make.  Note that
-#      the values in OTHER_*FLAGS are inherited by subprojects automatically --
-#      you do not have to (and shouldn't) add OTHER_*FLAGS to 
-#      OTHER_RECURSIVE_VARIABLES. 
-
-# Additional headers to export beyond those in the PB.project:
-#    OTHER_PUBLIC_HEADERS
-#    OTHER_PROJECT_HEADERS
-#    OTHER_PRIVATE_HEADERS
-
-# Additional files for the project's product: <<path relative to proj?>>
-#    OTHER_RESOURCES: (non-localized) resources for this project
-#    OTHER_OFILES: relocatables to be linked into this project
-#    OTHER_LIBS: more libraries to link against
-#    OTHER_PRODUCT_DEPENDS: other dependencies of this project
-#    OTHER_SOURCEFILES: other source files maintained by .pre/postamble
-#    OTHER_GARBAGE: additional files to be removed by `make clean'
-
-# Set this to YES if you don't want a final libtool call for a library/framework.
-#    BUILD_OFILES_LIST_ONLY
-
-# To include a version string, project source must exist in a directory named 
-# $(NAME).%d[.%d][.%d] and the following line must be uncommented.
-# OTHER_GENERATED_OFILES = $(VERS_OFILE)
-
-# This definition will suppress stripping of debug symbols when an executable
-# is installed.  By default it is YES.
-# STRIP_ON_INSTALL = NO
diff --git a/runtime/Messengers.subproj/PB.project b/runtime/Messengers.subproj/PB.project
deleted file mode 100644 (file)
index d82efb2..0000000
+++ /dev/null
@@ -1,31 +0,0 @@
-{
-    DYNAMIC_CODE_GEN = YES; 
-    FILESTABLE = {
-        CLASSES = (); 
-        H_FILES = (); 
-        OTHER_LINKED = ("objc-msg.s"); 
-        OTHER_SOURCES = (
-            Makefile.preamble, 
-            Makefile, 
-            Makefile.postamble, 
-            "objc-msg-i386.s", 
-            "objc-msg-ppc.s"
-        ); 
-        SUBPROJECTS = (); 
-    }; 
-    LANGUAGE = English; 
-    LOCALIZABLE_FILES = {}; 
-    MAKEFILEDIR = "$(MAKEFILEPATH)/pb_makefiles"; 
-    NEXTSTEP_BUILDTOOL = /bin/gnumake; 
-    NEXTSTEP_JAVA_COMPILER = /usr/bin/javac; 
-    NEXTSTEP_OBJCPLUS_COMPILER = /usr/bin/cc; 
-    PDO_UNIX_BUILDTOOL = $NEXT_ROOT/Developer/bin/make; 
-    PDO_UNIX_JAVA_COMPILER = "$(NEXTDEV_BIN)/javac"; 
-    PDO_UNIX_OBJCPLUS_COMPILER = "$(NEXTDEV_BIN)/gcc"; 
-    PROJECTNAME = Messengers; 
-    PROJECTTYPE = Component; 
-    PROJECTVERSION = 2.8; 
-    WINDOWS_BUILDTOOL = $NEXT_ROOT/Developer/Executables/make; 
-    WINDOWS_JAVA_COMPILER = "$(JDKBINDIR)/javac.exe"; 
-    WINDOWS_OBJCPLUS_COMPILER = "$(DEVDIR)/gcc"; 
-}
index 6bd3565fc7fc5133b69fc448429d8d686318a437..efd482def5b54954b030f50336fcd054e1529b73 100644 (file)
@@ -39,7 +39,6 @@
        kEight                  = 8
 #endif
 
-#if defined(OBJC_COLLECTING_CACHE)
 // _objc_entryPoints and _objc_exitPoints are used by objc
 // to get the critical regions for which method caches 
 // cannot be garbage collected.
@@ -47,6 +46,8 @@
        .data
 .globl         _objc_entryPoints
 _objc_entryPoints:
+       .long   __cache_getImp
+       .long   __cache_getMethod
        .long   _objc_msgSend
        .long   _objc_msgSend_stret
        .long   _objc_msgSendSuper
@@ -55,12 +56,13 @@ _objc_entryPoints:
 
 .globl         _objc_exitPoints
 _objc_exitPoints:
+       .long   LGetImpExit
+       .long   LGetMethodExit
        .long   LMsgSendExit
        .long   LMsgSendStretExit
        .long   LMsgSendSuperExit
        .long   LMsgSendSuperStretExit
        .long   0
-#endif
 
 
 /********************************************************************
@@ -271,18 +273,20 @@ $0:
 /////////////////////////////////////////////////////////////////////
 //
 //
-// CacheLookup WORD_RETURN | STRUCT_RETURN, MSG_SEND | MSG_SENDSUPER, cacheMissLabel
+// CacheLookup WORD_RETURN | STRUCT_RETURN, MSG_SEND | MSG_SENDSUPER | CACHE_GET, cacheMissLabel
 //
 // Locate the implementation for a selector in a class method cache.
 //
 // Takes: WORD_RETURN  (first parameter is at sp+4)
 //       STRUCT_RETURN (struct address is at sp+4, first parameter at sp+8)
-//        MSG_SEND     (first parameter is receiver)
+//       MSG_SEND      (first parameter is receiver)
 //       MSG_SENDSUPER (first parameter is address of objc_super structure)
+//       CACHE_GET     (first parameter is class; return method triplet)
 //
 //       cacheMissLabel = label to branch to iff method is not cached
 //
-// On exit:    (found) imp in eax register
+// On exit:    (found) MSG_SEND and MSG_SENDSUPER: return imp in eax
+//             (found) CACHE_GET: return method triplet in eax
 //             (not found) jumps to cacheMissLabel
 //     
 /////////////////////////////////////////////////////////////////////
@@ -295,8 +299,9 @@ STRUCT_RETURN       = 1
 
 // Values to specify to method lookup macros whether the first argument
 // is an object/class reference or a 'objc_super' structure.
-MSG_SEND       = 0
-MSG_SENDSUPER  = 1
+MSG_SEND       = 0     // first argument is receiver, search the isa
+MSG_SENDSUPER  = 1     // first argument is objc_super, search the class
+CACHE_GET      = 2     // first argument is class, search that class
 
 .macro CacheLookup
 
@@ -306,19 +311,23 @@ MSG_SENDSUPER     = 1
 .if $1 == MSG_SEND                     // MSG_SEND
        movl    isa(%eax), %eax         //   class = self->isa
        movl    selector(%esp), %ecx    //   get selector
-.else                                  // MSG_SENDSUPER
+.elseif $1 == MSG_SENDSUPER            // MSG_SENDSUPER
        movl    super(%esp), %eax       //   get objc_super address
        movl    class(%eax), %eax       //   class = caller->class
        movl    selector(%esp), %ecx    //   get selector
+.else                                  // CACHE_GET
+       movl    selector(%esp), %ecx    //   get selector - class already in eax
 .endif
 .else                                  // Struct return
 .if $1 == MSG_SEND                     // MSG_SEND (stret)
        movl    isa(%eax), %eax         //   class = self->isa
        movl    (selector_stret)(%esp), %ecx    //   get selector
-.else                                  // MSG_SENDSUPER (stret)
+.elseif $1 == MSG_SENDSUPER            // MSG_SENDSUPER (stret)
        movl    super_stret(%esp), %eax //   get objc_super address
        movl    class(%eax), %eax       //   class = caller->class
        movl    (selector_stret)(%esp), %ecx    //   get selector
+.else                                  // CACHE_GET
+       !! This should not happen.
 .endif
 .endif
 
@@ -334,9 +343,14 @@ MSG_SENDSUPER      = 1
        leal    buckets(%eax), %edi     // buckets = &cache->buckets
        movl    mask(%eax), %esi                // mask = cache->mask
        movl    %ecx, %edx              // index = selector
+#ifdef NO_MACRO_CONSTS
+       shrl    $kTwo, %edx             // index = selector >> 2
+#else
+       shrl    $2, %edx                // index = selector >> 2
+#endif
 
 // search the receiver's cache
-LMsgSendProbeCache_$0_$1:
+LMsgSendProbeCache_$0_$1_$2:
 #if defined(OBJC_INSTRUMENTED)
        inc     %ebx                    // probeCount += 1
 #endif
@@ -344,19 +358,19 @@ LMsgSendProbeCache_$0_$1:
        movl    (%edi, %edx, 4), %eax   // method = buckets[index]
 
        testl   %eax, %eax              // check for end of bucket
-       je      LMsgSendCacheMiss_$0_$1 // go to cache miss code
+       je      LMsgSendCacheMiss_$0_$1_$2      // go to cache miss code
        cmpl    method_name(%eax), %ecx // check for method name match
-       je      LMsgSendCacheHit_$0_$1  // go handle cache hit
+       je      LMsgSendCacheHit_$0_$1_$2       // go handle cache hit
        inc     %edx                    // bump index ...
-       jmp     LMsgSendProbeCache_$0_$1// ... and loop
+       jmp     LMsgSendProbeCache_$0_$1_$2 // ... and loop
 
 // not found in cache: restore state and go to callers handler
-LMsgSendCacheMiss_$0_$1:
+LMsgSendCacheMiss_$0_$1_$2:
 #if defined(OBJC_INSTRUMENTED)
        popl    %edx                    // retrieve cache pointer
        movl    mask(%edx), %esi                // mask = cache->mask
        testl   %esi, %esi              // a mask of zero is only for the...
-       je      LMsgSendMissInstrumentDone_$0   // ... emptyCache, do not record anything
+       je      LMsgSendMissInstrumentDone_$0_$1_$2     // ... emptyCache, do not record anything
 
        // locate and update the CacheInstrumentation structure
        inc     %esi                    // entryCount = mask + 1
@@ -376,15 +390,15 @@ LMsgSendCacheMiss_$0_$1:
        movl    %edi, missProbes(%esi)  // cacheData->missProbes += probeCount
        movl    maxMissProbes(%esi), %edi// if (cacheData->maxMissProbes < probeCount)
        cmpl    %ebx, %edi              // 
-       jge     LMsgSendMaxMissProbeOK_$0       // 
+       jge     LMsgSendMaxMissProbeOK_$0_$1_$2 // 
        movl    %ebx, maxMissProbes(%esi)// cacheData->maxMissProbes = probeCount
-LMsgSendMaxMissProbeOK_$0:
+LMsgSendMaxMissProbeOK_$0_$1_$2:
 
        // update cache miss probe histogram
        cmpl    $CACHE_HISTOGRAM_SIZE, %ebx     // pin probeCount to max index
-       jl      LMsgSendMissHistoIndexSet_$0
+       jl      LMsgSendMissHistoIndexSet_$0_$1_$2
        movl    $(CACHE_HISTOGRAM_SIZE-1), %ebx
-LMsgSendMissHistoIndexSet_$0:
+LMsgSendMissHistoIndexSet_$0_$1_$2:
        LEA_STATIC_DATA %esi, _CacheMissHistogram, EXTERNAL_SYMBOL
 #ifdef NO_MACRO_CONSTS
        shll    $kTwo, %ebx             // convert probeCount to histogram index
@@ -395,7 +409,7 @@ LMsgSendMissHistoIndexSet_$0:
        movl    0(%esi), %edi           // get current tally
        inc     %edi                    // 
        movl    %edi, 0(%esi)           // tally += 1
-LMsgSendMissInstrumentDone_$0:
+LMsgSendMissInstrumentDone_$0_$1_$2:
        popl    %ebx                    // restore non-volatile register
 #endif
 
@@ -403,9 +417,9 @@ LMsgSendMissInstrumentDone_$0:
 .if $1 == MSG_SEND                     // MSG_SEND
        popl    %esi                    //  restore callers register
        popl    %edi                    //  restore callers register
-       movl    self(%esp), %eax                //  get messaged object
+       movl    self(%esp), %eax        //  get messaged object
        movl    isa(%eax), %eax         //  get objects class
-.else                                  // MSG_SENDSUPER
+.elseif $1 == MSG_SENDSUPER            // MSG_SENDSUPER
        // replace "super" arg with "receiver"
        movl    super+8(%esp), %edi     //  get super structure
        movl    receiver(%edi), %esi    //  get messaged object
@@ -413,6 +427,9 @@ LMsgSendMissInstrumentDone_$0:
        movl    class(%edi), %eax       //  get messaged class
        popl    %esi                    //  restore callers register
        popl    %edi                    //  restore callers register
+.else                                  // CACHE_GET
+       popl    %esi                    //  restore callers register
+       popl    %edi                    //  restore callers register
 .endif
 .else                                  // Struct return
 .if $1 == MSG_SEND                     // MSG_SEND (stret)
@@ -420,7 +437,7 @@ LMsgSendMissInstrumentDone_$0:
        popl    %edi                    //  restore callers register
        movl    self_stret(%esp), %eax  //  get messaged object
        movl    isa(%eax), %eax         //  get objects class
-.else                                  // MSG_SENDSUPER (stret)
+.elseif $1 == MSG_SENDSUPER            // MSG_SENDSUPER (stret)
        // replace "super" arg with "receiver"
        movl    super_stret+8(%esp), %edi//  get super structure
        movl    receiver(%edi), %esi    //  get messaged object
@@ -428,6 +445,8 @@ LMsgSendMissInstrumentDone_$0:
        movl    class(%edi), %eax       //  get messaged class
        popl    %esi                    //  restore callers register
        popl    %edi                    //  restore callers register
+.else                                  // CACHE_GET
+       !! This should not happen.
 .endif
 .endif
 
@@ -435,12 +454,12 @@ LMsgSendMissInstrumentDone_$0:
 
 // eax points to matching cache entry
        .align  4, 0x90
-LMsgSendCacheHit_$0_$1:
+LMsgSendCacheHit_$0_$1_$2:
 #if defined(OBJC_INSTRUMENTED)
        popl    %edx                    // retrieve cache pointer
        movl    mask(%edx), %esi                // mask = cache->mask
        testl   %esi, %esi              // a mask of zero is only for the...
-       je      LMsgSendHitInstrumentDone_$0_$1 // ... emptyCache, do not record anything
+       je      LMsgSendHitInstrumentDone_$0_$1_$2      // ... emptyCache, do not record anything
 
        // locate and update the CacheInstrumentation structure
        inc     %esi                    // entryCount = mask + 1
@@ -460,15 +479,15 @@ LMsgSendCacheHit_$0_$1:
        movl    %edi, hitProbes(%esi)   // cacheData->hitProbes += probeCount
        movl    maxHitProbes(%esi), %edi// if (cacheData->maxHitProbes < probeCount)
        cmpl    %ebx, %edi
-       jge     LMsgSendMaxHitProbeOK_$0_$1
+       jge     LMsgSendMaxHitProbeOK_$0_$1_$2
        movl    %ebx, maxHitProbes(%esi)// cacheData->maxHitProbes = probeCount
-LMsgSendMaxHitProbeOK_$0_$1:
+LMsgSendMaxHitProbeOK_$0_$1_$2:
 
        // update cache hit probe histogram
        cmpl    $CACHE_HISTOGRAM_SIZE, %ebx     // pin probeCount to max index
-       jl      LMsgSendHitHistoIndexSet_$0_$1
+       jl      LMsgSendHitHistoIndexSet_$0_$1_$2
        movl    $(CACHE_HISTOGRAM_SIZE-1), %ebx
-LMsgSendHitHistoIndexSet_$0_$1:
+LMsgSendHitHistoIndexSet_$0_$1_$2:
        LEA_STATIC_DATA %esi, _CacheHitHistogram, EXTERNAL_SYMBOL
 #ifdef NO_MACRO_CONSTS
        shll    $kTwo, %ebx             // convert probeCount to histogram index
@@ -479,12 +498,16 @@ LMsgSendHitHistoIndexSet_$0_$1:
        movl    0(%esi), %edi           // get current tally
        inc     %edi                    // 
        movl    %edi, 0(%esi)           // tally += 1
-LMsgSendHitInstrumentDone_$0_$1:
+LMsgSendHitInstrumentDone_$0_$1_$2:
        popl    %ebx                    // restore non-volatile register
 #endif
 
 // load implementation address, restore state, and we're done
+.if $1 == CACHE_GET
+       // method triplet is already in eax
+.else
        movl    method_imp(%eax), %eax  // imp = method->method_imp
+.endif
 
 .if $0 == WORD_RETURN                  // Regular word return
 .if $1 == MSG_SENDSUPER                        // MSG_SENDSUPER
@@ -555,6 +578,73 @@ HAVE_CALL_EXTERN_lookupMethodAndLoadCache = 1
        PICIFY(func)                  ; \
        jmp     %edx                  ; 
 
+
+
+
+/********************************************************************
+ * Method _cache_getMethod(Class cls, SEL sel)
+ *
+ * If found, returns method triplet pointer.
+ * If not found, returns NULL.
+ *
+ * NOTE: _cache_getMethod never returns any cache entry whose implementation
+ * is _objc_msgForward. It returns NULL instead. This prevents thread-
+ * safety and memory management bugs in _class_lookupMethodAndLoadCache. 
+ * See _class_lookupMethodAndLoadCache for details. 
+ ********************************************************************/
+        
+        ENTRY __cache_getMethod
+
+// load the class into eax
+       movl    self(%esp), %eax
+
+// do lookup
+        CacheLookup WORD_RETURN, CACHE_GET, LGetMethodMiss
+
+// cache hit, method triplet in %eax
+// check for _objc_msgForward
+        LEA_STATIC_DATA %ecx, __objc_msgForward, LOCAL_SYMBOL // eats edx
+        cmpl    method_imp(%eax), %ecx
+        je      LGetMethodMiss          // if (imp==_objc_msgForward) return nil
+        ret                             // else return method triplet address
+
+LGetMethodMiss:
+// cache miss, return nil
+        xorl    %eax, %eax      // zero %eax
+        ret
+
+LGetMethodExit:
+        END_ENTRY __cache_getMethod
+
+
+/********************************************************************
+ * IMP _cache_getImp(Class cls, SEL sel)
+ *
+ * If found, returns method implementation.
+ * If not found, returns NULL.
+ ********************************************************************/
+
+        ENTRY __cache_getImp
+
+// load the class into eax
+       movl    self(%esp), %eax
+
+// do lookup
+        CacheLookup WORD_RETURN, CACHE_GET, LGetImpMiss
+
+// cache hit, method triplet in %eax
+        movl    method_imp(%eax), %eax  // return method imp
+        ret
+
+LGetImpMiss:
+// cache miss, return nil
+        xorl    %eax, %eax      // zero %eax
+        ret
+
+LGetImpExit:
+        END_ENTRY __cache_getImp
+
+
 /********************************************************************
  *
  * id objc_msgSend(id self, SEL        _cmd,...);
@@ -570,14 +660,7 @@ HAVE_CALL_EXTERN_lookupMethodAndLoadCache = 1
        testl   %eax, %eax
        je      LMsgSendNilSelf
 
-#if !defined(OBJC_COLLECTING_CACHE)
-// check whether context is multithreaded
-       EXTERN_TO_REG(__objc_multithread_mask,%ecx)
-       testl   %ecx, %ecx
-       je      LMsgSendMT
-#endif
-
-// single threaded and receiver is non-nil: search the cache
+// receiver is non-nil: search the cache
        CacheLookup WORD_RETURN, MSG_SEND, LMsgSendCacheMiss
        movl    $kFwdMsgSend, %edx      // flag word-return for _objc_msgForward
        jmp     *%eax                   // goto *imp
@@ -588,32 +671,6 @@ LMsgSendCacheMiss:
        movl    $kFwdMsgSend, %edx      // flag word-return for _objc_msgForward
        jmp     *%eax                   // goto *imp
 
-#if !defined(OBJC_COLLECTING_CACHE)
-// multithreaded: hold _messageLock while accessing cache
-LMsgSendMT:
-       movl    $1, %ecx                        // acquire _messageLock
-       LEA_STATIC_DATA %eax, _messageLock, EXTERNAL_SYMBOL
-LMsgSendLockSpin:
-       xchgl   %ecx, (%eax)
-       cmpl    $0, %ecx
-       jne     LMsgSendLockSpin
-       movl    self(%esp), %eax                // restore eax
-
-       CacheLookup WORD_RETURN, MSG_SEND, LMsgSendMTCacheMiss
-       LEA_STATIC_DATA %ecx, _messageLock, EXTERNAL_SYMBOL
-       movl    $0, (%ecx)              // unlock
-       movl    $kFwdMsgSend, %edx      // flag word-return for _objc_msgForward
-       jmp     *%eax                   // goto *imp
-
-// cache miss: go search the method lists
-LMsgSendMTCacheMiss:
-       MethodTableLookup WORD_RETURN, MSG_SEND
-       LEA_STATIC_DATA %ecx, _messageLock, EXTERNAL_SYMBOL
-       movl    $0, (%ecx)              // unlock
-       movl    $kFwdMsgSend, %edx      // flag word-return for _objc_msgForward
-       jmp     *%eax                   // goto *imp
-#endif
-
 // message sent to nil object: call optional handler and return nil
 LMsgSendNilSelf:
        EXTERN_TO_REG(__objc_msgNil,%eax)
@@ -643,14 +700,7 @@ LMsgSendExit:
 
        movl    super(%esp), %eax
 
-#if !defined(OBJC_COLLECTING_CACHE)
-// check whether context is multithreaded
-       EXTERN_TO_REG_AGAIN(__objc_multithread_mask,%ecx)
-       testl   %ecx, %ecx
-       je      LMsgSendSuperMT
-#endif
-
-// single threaded and receiver is non-nil: search the cache
+// receiver is non-nil: search the cache
        CacheLookup WORD_RETURN, MSG_SENDSUPER, LMsgSendSuperCacheMiss
        movl    $kFwdMsgSend, %edx      // flag word-return for _objc_msgForward
        jmp     *%eax                   // goto *imp
@@ -661,32 +711,6 @@ LMsgSendSuperCacheMiss:
        movl    $kFwdMsgSend, %edx      // flag word-return for _objc_msgForward
        jmp     *%eax                   // goto *imp
 
-#if !defined(OBJC_COLLECTING_CACHE)
-LMsgSendSuperMT:
-// multithreaded: hold _messageLock while accessing cache
-       movl    $1, %ecx                        // acquire _messageLock
-       LEA_STATIC_DATA %eax, _messageLock, EXTERNAL_SYMBOL
-LMsgSendSuperLockSpin:
-       xchgl   %ecx, (%eax)
-       cmpl    $0, %ecx
-       jne     LMsgSendSuperLockSpin
-       movl    super(%esp), %eax       // restore eax
-
-       CacheLookup WORD_RETURN, MSG_SENDSUPER, LMsgSendSuperMTCacheMiss
-       LEA_STATIC_DATA %ecx, _messageLock, EXTERNAL_SYMBOL
-       movl    $0, (%ecx)              // unlock
-       movl    $kFwdMsgSend, %edx      // flag word-return for _objc_msgForward
-       jmp     *%eax                   // goto *imp
-
-// cache miss: go search the method lists
-LMsgSendSuperMTCacheMiss:
-       MethodTableLookup WORD_RETURN, MSG_SENDSUPER
-       LEA_STATIC_DATA %ecx, _messageLock, EXTERNAL_SYMBOL
-       movl    $0, (%ecx)              // unlock
-       movl    $kFwdMsgSend, %edx      // flag word-return for _objc_msgForward
-       jmp     *%eax                   // goto *imp
-#endif
-
 LMsgSendSuperExit:
        END_ENTRY       _objc_msgSendSuper
 
@@ -757,14 +781,7 @@ LMsgSendvArgsOK:
        testl   %eax, %eax
        je      LMsgSendStretNilSelf
 
-#if !defined(OBJC_COLLECTING_CACHE)
-// check whether context is multithreaded
-       EXTERN_TO_REG_AGAIN(__objc_multithread_mask,%ecx)
-       testl   %ecx, %ecx
-       je      LMsgSendStretMT
-#endif
-
-// single threaded and receiver is non-nil: search the cache
+// receiver is non-nil: search the cache
        CacheLookup STRUCT_RETURN, MSG_SEND, LMsgSendStretCacheMiss
        movl    $kFwdMsgSendStret, %edx // flag struct-return for _objc_msgForward
        jmp     *%eax                   // goto *imp
@@ -775,32 +792,6 @@ LMsgSendStretCacheMiss:
        movl    $kFwdMsgSendStret, %edx // flag struct-return for _objc_msgForward
        jmp     *%eax                   // goto *imp
 
-#if !defined(OBJC_COLLECTING_CACHE)
-// multithreaded: hold _messageLock while accessing cache
-LMsgSendStretMT:
-       movl    $1, %ecx                        // acquire _messageLock
-       LEA_STATIC_DATA %eax, _messageLock, EXTERNAL_SYMBOL
-LMsgSendStretLockSpin:
-       xchgl   %ecx, (%eax)
-       cmpl    $0, %ecx
-       jne     LMsgSendStretLockSpin
-       movl    self_stret(%esp), %eax  // restore eax
-
-       CacheLookup STRUCT_RETURN, MSG_SEND, LMsgSendStretMTCacheMiss
-       LEA_STATIC_DATA %ecx, _messageLock, EXTERNAL_SYMBOL
-       movl    $0, (%ecx)              // unlock
-       movl    $kFwdMsgSendStret, %edx // flag struct-return for _objc_msgForward
-       jmp     *%eax                   // goto *imp
-
-// cache miss: go search the method lists
-LMsgSendStretMTCacheMiss:
-       MethodTableLookup STRUCT_RETURN, MSG_SEND
-       LEA_STATIC_DATA %ecx, _messageLock, EXTERNAL_SYMBOL
-       movl    $0, (%ecx)              // unlock
-       movl    $kFwdMsgSendStret, %edx // flag struct-return for _objc_msgForward
-       jmp     *%eax                   // goto *imp
-#endif
-
 // message sent to nil object: call optional handler and return nil
 LMsgSendStretNilSelf:
        EXTERN_TO_REG_AGAIN(__objc_msgNil,%eax)
@@ -840,14 +831,7 @@ LMsgSendStretExit:
 
        movl    super_stret(%esp), %eax
 
-#if !defined(OBJC_COLLECTING_CACHE)
-// check whether context is multithreaded
-       EXTERN_TO_REG_AGAIN(__objc_multithread_mask,%ecx)
-       testl   %ecx, %ecx
-       je      LMsgSendSuperStretMT
-#endif
-
-// single threaded and receiver is non-nil: search the cache
+// receiver is non-nil: search the cache
        CacheLookup STRUCT_RETURN, MSG_SENDSUPER, LMsgSendSuperStretCacheMiss
        movl    $kFwdMsgSendStret, %edx // flag struct-return for _objc_msgForward
        jmp     *%eax                   // goto *imp
@@ -858,32 +842,6 @@ LMsgSendSuperStretCacheMiss:
        movl    $kFwdMsgSendStret, %edx // flag struct-return for _objc_msgForward
        jmp     *%eax                   // goto *imp
 
-#if !defined(OBJC_COLLECTING_CACHE)
-LMsgSendStretSuperMT:
-// multithreaded: hold _messageLock while accessing cache
-       movl    $1, %ecx                        // acquire _messageLock
-       LEA_STATIC_DATA %eax, _messageLock, EXTERNAL_SYMBOL
-LMsgSendSuperStretLockSpin:
-       xchgl   %ecx, (%eax)
-       cmpl    $0, %ecx
-       jne     LMsgSendSuperStretLockSpin
-       movl    super_stret(%esp), %eax // restore eax
-
-       CacheLookup STRUCT_RETURN, MSG_SENDSUPER, LMsgSendSuperStretMTCacheMiss
-       LEA_STATIC_DATA %ecx, _messageLock, EXTERNAL_SYMBOL
-       movl    $0, (%ecx)              // unlock
-       movl    $kFwdMsgSendStret, %edx // flag struct-return for _objc_msgForward
-       jmp     *%eax                   // goto *imp
-
-// cache miss: go search the method lists
-LMsgSendSuperStretMTCacheMiss:
-       MethodTableLookup MSG_SENDSUPER
-       LEA_STATIC_DATA %ecx, _messageLock, EXTERNAL_SYMBOL
-       movl    $0, (%ecx)              // unlock
-       movl    $kFwdMsgSendStret, %edx // flag struct-return for _objc_msgForward
-       jmp     *%eax                   // goto *imp
-#endif
-
 LMsgSendSuperStretExit:
        END_ENTRY       _objc_msgSendSuper_stret
 
@@ -1043,7 +1001,7 @@ L__objc_msgForwardStret$pic_base:
 #endif
        pushl   %ecx
        pushl   (self_stret+16)(%esp)
-       call    _objc_msgSend_stret
+       call    _objc_msgSend
        movl    %ebp,%esp
        popl    %ebp
        ret
index 005780ba4ddca2a8abd43cddfd54957e78f8ad97..f3061dcfab4747c9679fda241ebbffbd327dbbfe 100644 (file)
@@ -49,7 +49,6 @@
  *             Created from m98k.
  ********************************************************************/
 
-#if defined(OBJC_COLLECTING_CACHE)
 ; _objc_entryPoints and _objc_exitPoints are used by method dispatch
 ; caching code to figure out whether any threads are actively 
 ; in the cache for dispatching.  The labels surround the asm code
@@ -57,6 +56,8 @@
        .data
 .globl _objc_entryPoints
 _objc_entryPoints:
+       .long   __cache_getImp
+       .long   __cache_getMethod
        .long   _objc_msgSend
        .long   _objc_msgSend_stret
        .long   _objc_msgSendSuper
@@ -69,6 +70,8 @@ _objc_entryPoints:
 
 .globl _objc_exitPoints
 _objc_exitPoints:
+       .long   LGetImpExit
+       .long   LGetMethodExit
        .long   LMsgSendExit
        .long   LMsgSendStretExit
        .long   LMsgSendSuperExit
@@ -78,7 +81,6 @@ _objc_exitPoints:
        .long   LMsgSendSuperFewExit
        .long   LMsgSendSuperFewStretExit
        .long   0
-#endif
 
 /********************************************************************
  *
@@ -157,7 +159,7 @@ EXTERNAL_SYMBOL     = 1
 
 #if defined(__DYNAMIC__)
        mflr            r0
-       bl              1f
+       bcl             20,31,1f        ; 31 is cr7[so]
 1:     mflr            $0
        mtlr            r0
 .if $2 == EXTERNAL_SYMBOL
@@ -194,7 +196,7 @@ EXTERNAL_SYMBOL     = 1
 .macro LEA_STATIC_DATA
 #if defined(__DYNAMIC__)
        mflr            r0
-       bl              1f
+       bcl             20,31,1f        ; 31 is cr7[so]
 1:     mflr            $0
        mtlr            r0
 .if $2 == EXTERNAL_SYMBOL
@@ -291,7 +293,7 @@ $0:
 
 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 ;
-; CacheLookup  WORD_RETURN | STRUCT_RETURN, MSG_SEND | MSG_SENDSUPER, cacheMissLabel, FEW_ARGS | MANY_ARGS
+; CacheLookup  WORD_RETURN | STRUCT_RETURN, MSG_SEND | MSG_SENDSUPER | CACHE_GET, cacheMissLabel, FEW_ARGS | MANY_ARGS
 ;
 ; Locate the implementation for a selector in a class method cache.
 ;
@@ -299,13 +301,20 @@ $0:
 ;      STRUCT_RETURN   (r3 is structure return address, r4 is first parameter)
 ;      MSG_SEND        (first parameter is receiver)
 ;      MSG_SENDSUPER   (first parameter is address of objc_super structure)
+;      CACHE_GET       (first parameter is class; return method triplet)
 ;
 ;      cacheMissLabel = label to branch to iff method is not cached
 ;
 ; Eats: r0, r11, r12
-; On exit:     (found) imp in ctr register
+; On exit:     (found) MSG_SEND and MSG_SENDSUPER: return imp in r12 and ctr
+;              (found) CACHE_GET: return method triplet in r12
 ;              (not found) jumps to cacheMissLabel
-;      
+;
+; For MSG_SEND and MSG_SENDSUPER, the messenger jumps to the imp 
+; in ctr. The same imp in r12 is used by the method itself for its
+; relative addressing. This saves the usual "jump to next line and 
+; fetch link register" construct inside the method.
+;
 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 
 ; Values to specify to method lookup macros whether the return type of
@@ -317,6 +326,7 @@ STRUCT_RETURN       = 1
 ; the method is an integer or structure.
 MSG_SEND       = 0
 MSG_SENDSUPER  = 1
+CACHE_GET      = 2
 
 ; Values to specify to method lookup macros whether this is a "few args" call or not
 ; (number of args < 5 , including self and _cmd)
@@ -332,30 +342,29 @@ MANY_ARGS = 1
        li              r7,0                    ; no probes so far!
 #endif
 
-       stw             r8,44(r1)               ; save r8
 .if $3 == MANY_ARGS
        stw             r9,48(r1)               ; save r9 and r10
        stw             r10,52(r1)              ;
 .endif
 
-; locate the cache
-; Locking idea:
-;LGetMask_$0_$1_$2
-
 .if $0 == WORD_RETURN                          ; WORD_RETURN
 
 .if $1 == MSG_SEND                             ; MSG_SEND
        lwz             r12,isa(r3)             ; class = receiver->isa
-.else                                          ; MSG_SENDSUPER
+.elseif $1 == MSG_SENDSUPER                    ; MSG_SENDSUPER
        lwz             r12,class(r3)           ; class = super->class
+.else                                          ; CACHE_GET
+       mr              r12,r3                  ; class = class
 .endif
 
 .else  
                                                ; STRUCT_RETURN
 .if $1 == MSG_SEND                             ; MSG_SEND
        lwz             r12,isa(r4)             ; class = receiver->isa
-.else                                          ; MSG_SENDSUPER
+.elseif $1 == MSG_SENDSUPER                    ; MSG_SENDSUPER
        lwz             r12,class(r4)           ; class = super->class
+.else                                          ; CACHE_GET
+       mr              r12,r4                  ; class = class
 .endif
 
 .endif
@@ -365,21 +374,14 @@ MANY_ARGS = 1
 #if defined(OBJC_INSTRUMENTED)
        mr              r6,r12                  ; save cache pointer
 #endif
-       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
+       lwz             r11,mask(r12)           ; mask = cache->mask
 
        addi            r9,r12,buckets          ; buckets = cache->buckets
+       slwi            r11,r11,2               ; r11 = mask << 2 
 .if $0 == WORD_RETURN                          ; WORD_RETURN
-       and             r12,r4,r11              ; index = selector & mask
+       and             r12,r4,r11              ; bytes = sel & (mask<<2)
 .else                                          ; STRUCT_RETURN
-       and             r12,r5,r11              ; index = selector & mask
+       and             r12,r5,r11              ; bytes = sel & (mask<<2)
 .endif
 
 #if defined(OBJC_INSTRUMENTED)
@@ -391,17 +393,17 @@ LMiss_$0_$1_$2:
        addi            r9,r9,1                 ;
        slwi            r9,r9,2                 ; tableSize = entryCount * sizeof(entry)
        addi            r9,r9,buckets           ; offset = buckets + tableSize
-       add             r8,r6,r9                ; cacheData = &cache->buckets[mask+1]
-       lwz             r9,missCount(r8)        ; cacheData->missCount += 1
+       add             r11,r6,r9               ; cacheData = &cache->buckets[mask+1]
+       lwz             r9,missCount(r11)       ; cacheData->missCount += 1
        addi            r9,r9,1                 ; 
-       stw             r9,missCount(r8)        ; 
-       lwz             r9,missProbes(r8)       ; cacheData->missProbes += probeCount
+       stw             r9,missCount(r11)       ; 
+       lwz             r9,missProbes(r11)      ; cacheData->missProbes += probeCount
        add             r9,r9,r7                ; 
-       stw             r9,missProbes(r8)       ; 
-       lwz             r9,maxMissProbes(r8)    ; if (probeCount > cacheData->maxMissProbes)
+       stw             r9,missProbes(r11)      ; 
+       lwz             r9,maxMissProbes(r11)   ; if (probeCount > cacheData->maxMissProbes)
        cmplw           r7,r9                   ; maxMissProbes = probeCount
        ble             .+8                     ; 
-       stw             r7,maxMissProbes(r8)    ;
+       stw             r7,maxMissProbes(r11)   ;
 
        lwz             r6,36(r1)               ; restore r6
        lwz             r7,40(r1)               ; restore r7
@@ -414,8 +416,9 @@ LLoop_$0_$1_$2:
 #if defined(OBJC_INSTRUMENTED)
        addi            r7,r7,1                 ; probeCount += 1
 #endif
-       slwi            r0,r12,2                ; convert word index into byte count
-       lwzx            r10,r9,r0               ; method = cache->buckets[index]
+
+       lwzx            r10,r9,r12              ; method = buckets[bytes/4]
+       addi            r12,r12,4               ; bytes += 4
        cmplwi          r10,0                   ; if (method == NULL)
 #if defined(OBJC_INSTRUMENTED)
        beq             LMiss_$0_$1_$2
@@ -423,28 +426,25 @@ LLoop_$0_$1_$2:
        beq             $2                      ; goto cacheMissLabel
 #endif
 
-       addi            r12,r12,1               ; index += 1
-       lwz             r8,method_name(r10)     ; name  = method->method_name
-       and             r12,r12,r11             ; index &= mask
-       lwz             r10,method_imp(r10)     ; imp = method->method_imp
+       lwz             r0,method_name(r10)     ; name  = method->method_name
+       and             r12,r12,r11             ; bytes &= (mask<<2)
 .if $0 == WORD_RETURN                          ; WORD_RETURN
-       cmplw           r8,r4                   ; if (name != selector)
+       cmplw           r0,r4                   ; if (name != selector)
 .else                                          ; STRUCT_RETURN
-       cmplw           r8,r5                   ; if (name != selector)
+       cmplw           r0,r5                   ; if (name != selector)
 .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
+; cache hit, r10 == method triplet address
+.if $1 == CACHE_GET
+       ;  return method triplet in r12
+       mr              r12,r10
+.else
+       ; return method imp in ctr and r12
+       lwz             r10,method_imp(r10)     ; imp = method->method_imp
        mr              r12,r10                 ; copy implementation to r12
        mtctr           r10                     ; ctr = imp
+.endif
 
 #if defined(OBJC_INSTRUMENTED)
        ; r6 = cache, r7 = probeCount
@@ -452,23 +452,22 @@ LLoop_$0_$1_$2:
        addi            r9,r9,1                 ;
        slwi            r9,r9,2                 ; tableSize = entryCount * sizeof(entry)
        addi            r9,r9,buckets           ; offset = buckets + tableSize
-       add             r8,r6,r9                ; cacheData = &cache->buckets[mask+1]
-       lwz             r9,hitCount(r8)         ; cache->hitCount += 1
+       add             r11,r6,r9               ; cacheData = &cache->buckets[mask+1]
+       lwz             r9,hitCount(r11)        ; cache->hitCount += 1
        addi            r9,r9,1                 ; 
-       stw             r9,hitCount(r8)         ; 
-       lwz             r9,hitProbes(r8)        ; cache->hitProbes += probeCount
+       stw             r9,hitCount(r11)        ; 
+       lwz             r9,hitProbes(r11)       ; cache->hitProbes += probeCount
        add             r9,r9,r7                ; 
-       stw             r9,hitProbes(r8)        ; 
-       lwz             r9,maxHitProbes(r8)     ; if (probeCount > cache->maxMissProbes)
+       stw             r9,hitProbes(r11)       ; 
+       lwz             r9,maxHitProbes(r11)    ; if (probeCount > cache->maxMissProbes)
        cmplw           r7,r9                   ;maxMissProbes = probeCount
        ble             .+8                     ; 
-       stw             r7,maxHitProbes(r8)     ; 
+       stw             r7,maxHitProbes(r11)    ; 
 
        lwz             r6,36(r1)               ; restore r6
        lwz             r7,40(r1)               ; restore r7
 #endif
 
-       lwz             r8,44(r1)               ; restore r8
 .if $3 == MANY_ARGS
        lwz             r9,48(r1)               ; restore r9 and r10
        lwz             r10,52(r1)              ;
@@ -476,19 +475,56 @@ LLoop_$0_$1_$2:
 
 .endmacro
 
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;
+; CacheLookup cache locking - 2001-11-12
+; The collecting cache mechanism precludes the need for a cache lock 
+; in objc_msgSend. The cost of the collecting cache is small: a few 
+; K of memory for uncollected caches, and less than 1 ms per collection. 
+; A large app will only run collection a few times.
+; Using the code below to lock the cache almost doubles messaging time, 
+; costing several seconds of CPU across several minutes of operation.
+; The code below probably could be improved, but almost all of the 
+; locking slowdown is in the sync and isync.
+;
+; 40 million message test times (G4 1x667):
+;   no lock  4.390u 0.030s 0:04.59 96.2%     0+0k 0+1io 0pf+0w
+; with lock  9.120u 0.010s 0:09.83 92.8%     0+0k 0+0io 0pf+0w
+;
+;; LockCache mask_dest, cache
+;.macro LockCache
+;        ; LOCKED mask is NEGATIVE
+;        lwarx   $0, mask, $1    ; mask = reserve(cache->mask)
+;        cmpwi   $0, 0           ;
+;        blt     .-8             ; try again if mask < 0
+;        neg     r0, $0          ;
+;        stwcx.  r0, mask, $1    ; cache->mask = -mask ($0 keeps +mask)
+;        bne     .-20            ; try again if lost reserve
+;        isync                   ; flush prefetched instructions after locking
+;.endmacro
+;        
+;; UnlockCache (mask<<2), cache
+;.macro UnlockCache
+;        sync                    ; finish previous instructions before unlocking
+;        srwi    r0, $0, 2       ; r0 = (mask<<2) >> 2
+;        stw     r0, mask($1)    ; cache->mask = +mask
+;.endmacro
+;
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
 
 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 ;
 ;
 ; MethodTableLookup WORD_RETURN | STRUCT_RETURN, MSG_SEND | MSG_SENDSUPER, FEW_ARGS | MANY_ARGS
 ;
-; Takes: WORD_RETURN    (r3 is first parameter)
+; Takes: WORD_RETURN   (r3 is first parameter)
 ;      STRUCT_RETURN   (r3 is structure return address, r4 is first parameter)
 ;      MSG_SEND        (first parameter is receiver)
 ;      MSG_SENDSUPER   (first parameter is address of objc_super structure)
 ;
 ; Eats: r0, r11, r12
-; On exit: restores registers r8 and possibly, r9 and r10, saved by CacheLookup
+; On exit: if MANY_ARGS, restores r9,r10 saved by CacheLookup
 ;      imp in ctr
 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 
@@ -500,7 +536,8 @@ HAVE_CALL_EXTERN_lookupMethodAndLoadCache   = 0
        stw             r5, 32(r1)              ;
        stw             r6, 36(r1)              ;
        stw             r7, 40(r1)              ;
-       ; r8 and possibly, r9 and r10, were saved by CacheLookup
+       stw             r8, 44(r1)              ;
+       ; if MANY_ARGS, r9 and r10 were saved by CacheLookup
 
        mflr            r0                      ; save lr
        stw             r0,8(r1)                ;
@@ -585,10 +622,10 @@ HAVE_CALL_EXTERN_lookupMethodAndLoadCache = 1
        lwz             r5, 32(r1)              ;
        lwz             r6, 36(r1)              ;
        lwz             r7, 40(r1)              ;
+       lwz             r8, 44(r1)              ;
 
-       lwz             r8, 44(r1)              ; restore leftovers from CacheLookup...
 .if $2 == MANY_ARGS
-       lwz             r9, 48(r1)              ;
+       lwz             r9, 48(r1)              ; restore saves from CacheLookup
        lwz             r10,52(r1)              ;
 .endif
 
@@ -683,6 +720,77 @@ HAVE_CALL_EXTERN_mcount = 1
 #endif
        .endmacro
 
+
+/********************************************************************
+ * Method _cache_getMethod(Class cls, SEL sel)
+ *
+ * On entry:    r3 = class whose cache is to be searched
+ *              r4 = selector to search for
+ *
+ * If found, returns method triplet pointer.
+ * If not found, returns NULL.
+ *
+ * NOTE: _cache_getMethod never returns any cache entry whose implementation
+ * is _objc_msgForward. It returns NULL instead. This prevents thread-
+ * safety and memory management bugs in _class_lookupMethodAndLoadCache. 
+ * See _class_lookupMethodAndLoadCache for details. 
+ ********************************************************************/
+        
+        ENTRY __cache_getMethod
+; do profiling if enabled
+        CALL_MCOUNT
+
+; do lookup
+        CacheLookup     WORD_RETURN, CACHE_GET, LGetMethodMiss, MANY_ARGS
+        
+; cache hit, method triplet in r12
+; check for _objc_msgForward
+        lwz     r11, method_imp(r12)    ; get the imp
+        LEA_STATIC_DATA r10, __objc_msgForward, LOCAL_SYMBOL
+        cmplw   r11, r10
+        beq     LGetMethodMiss          ; if (imp==_objc_msgForward) return nil
+        mr      r3, r12                 ; else return method triplet address
+        blr
+        
+LGetMethodMiss:
+; cache miss, return nil
+        li      r3, 0           ; return nil
+        blr
+
+LGetMethodExit: 
+        END_ENTRY __cache_getMethod
+
+
+/********************************************************************
+ * IMP _cache_getImp(Class cls, SEL sel)
+ *
+ * On entry:    r3 = class whose cache is to be searched
+ *              r4 = selector to search for
+ *
+ * If found, returns method implementation.
+ * If not found, returns NULL.
+ ********************************************************************/
+
+        ENTRY __cache_getImp
+; do profiling if enabled
+        CALL_MCOUNT
+
+; do lookup
+        CacheLookup WORD_RETURN, CACHE_GET, LGetImpMiss, MANY_ARGS
+        
+; cache hit, method triplet in r12
+        lwz     r3, method_imp(r12)    ; return method imp address
+        blr
+        
+LGetImpMiss:
+; cache miss, return nil
+        li      r3, 0           ; return nil
+        blr
+
+LGetImpExit: 
+        END_ENTRY __cache_getImp
+
+
 /********************************************************************
  * id          objc_msgSend(id self,
  *                     SEL     op,
@@ -709,15 +817,7 @@ L__objc_msgNil:
        cmplwi          r3,0                    ; receiver nil?
        beq             LMsgSendNilSelf         ; if so, call handler or return nil
 
-#if !defined(OBJC_COLLECTING_CACHE)
-; check whether context is multithreaded
-       lis             r11,ha16(__objc_multithread_mask)
-       lwz             r11,lo16(__objc_multithread_mask)(r11)
-       cmplwi          r11,0                   ; objc_multithread_mask zero?
-       beq             LMsgSendMT              ; branch to the locking case
-#endif
-
-; single threaded and receiver is non-nil: search the cache
+; receiver is non-nil: search the cache
        CacheLookup WORD_RETURN, MSG_SEND, LMsgSendCacheMiss, MANY_ARGS
        li              r11,kFwdMsgSend         ; indicate word-return to _objc_msgForward
        bctr                                    ; goto *imp;
@@ -728,23 +828,6 @@ LMsgSendCacheMiss:
        li              r11,kFwdMsgSend         ; indicate word-return to _objc_msgForward
        bctr                                    ; goto *imp;
 
-#if !defined(OBJC_COLLECTING_CACHE)
-; multithreaded: hold _messageLock while accessing cache
-LMsgSendMT:
-       PLOCK   r11, _messageLock
-       CacheLookup WORD_RETURN, MSG_SEND, LMsgSendMTCacheMiss, MANY_ARGS
-       PUNLOCK r11, _messageLock
-       li              r11,kFwdMsgSend         ; indicate word-return to _objc_msgForward
-       bctr                                    ; goto *imp;
-
-; cache miss: go search the method lists
-LMsgSendMTCacheMiss:
-       MethodTableLookup WORD_RETURN, MSG_SEND, MANY_ARGS
-       PUNLOCK r11, _messageLock
-       li              r11,kFwdMsgSend         ; indicate word-return to _objc_msgForward
-       bctr                                    ; goto *imp;
-#endif
-
 ; message sent to nil object call: optional handler and return nil
 LMsgSendNilSelf:
        LOAD_STATIC_WORD r11, __objc_msgNil, EXTERNAL_SYMBOL
@@ -789,15 +872,7 @@ LMsgSendExit:
        cmplwi          r4,0                    ; receiver nil?
        beq             LMsgSendStretNilSelf    ; if so, call handler or just return
 
-#if !defined(OBJC_COLLECTING_CACHE)
-; check whether context is multithreaded
-       lis             r11,ha16(__objc_multithread_mask)
-       lwz             r11,lo16(__objc_multithread_mask)(r11)
-       cmplwi          r11,0                   ; objc_multithread_mask zero?
-       beq             LMsgSendStretMT         ; branch to the locking case
-#endif
-
-; single threaded and receiver is non-nil: search the cache
+; receiver is non-nil: search the cache
        CacheLookup STRUCT_RETURN, MSG_SEND, LMsgSendStretCacheMiss, MANY_ARGS
        li              r11,kFwdMsgSendStret    ; indicate struct-return to _objc_msgForward
        bctr                                    ; goto *imp;
@@ -808,23 +883,6 @@ LMsgSendStretCacheMiss:
        li              r11,kFwdMsgSendStret    ; indicate struct-return to _objc_msgForward
        bctr                                    ; goto *imp;
 
-#if !defined(OBJC_COLLECTING_CACHE)
-; multithreaded: hold _messageLock while accessing cache
-LMsgSendStretMT:       
-       PLOCK   r11, _messageLock
-       CacheLookup STRUCT_RETURN, MSG_SEND, LMsgSendStretMTCacheMiss, MANY_ARGS
-       PUNLOCK r11, _messageLock
-       li              r11,kFwdMsgSendStret    ; indicate struct-return to _objc_msgForward
-       bctr                                    ; goto *imp;
-
-; cache miss: go search the method lists
-LMsgSendStretMTCacheMiss:
-       MethodTableLookup STRUCT_RETURN, MSG_SEND, MANY_ARGS
-       PUNLOCK r11, _messageLock
-       li              r11,kFwdMsgSendStret    ; indicate struct-return to _objc_msgForward
-       bctr                                    ; goto *imp;
-#endif
-
 ; message sent to nil object call optional handler and return nil
 LMsgSendStretNilSelf:
        LOAD_STATIC_WORD r11, __objc_msgNil, EXTERNAL_SYMBOL
@@ -863,15 +921,7 @@ LMsgSendStretExit:
 ; do profiling when enabled
        CALL_MCOUNT
 
-#if !defined(OBJC_COLLECTING_CACHE)
-; check whether context is multithreaded
-       lis             r11,ha16(__objc_multithread_mask)
-       lwz             r11,lo16(__objc_multithread_mask)(r11)
-       cmplwi          r11,0                   ; objc_multithread_mask zero?
-       beq             LMsgSendSuperMT         ; branch to the locking case
-#endif
-
-; single threaded: search the cache
+; search the cache
        CacheLookup WORD_RETURN, MSG_SENDSUPER, LMsgSendSuperCacheMiss, MANY_ARGS
        lwz             r3,receiver(r3)         ; receiver is the first arg
        li              r11,kFwdMsgSend         ; indicate word-return to _objc_msgForward
@@ -884,25 +934,6 @@ LMsgSendSuperCacheMiss:
        li              r11,kFwdMsgSend         ; indicate word-return to _objc_msgForward
        bctr                                    ; goto *imp;
 
-#if !defined(OBJC_COLLECTING_CACHE)
-; multithreaded: hold _messageLock while accessing cache
-LMsgSendSuperMT:       
-       PLOCK   r11, _messageLock
-       CacheLookup WORD_RETURN, MSG_SENDSUPER, LMsgSendSuperMTCacheMiss, MANY_ARGS
-       PUNLOCK r11, _messageLock
-       lwz             r3,receiver(r3)         ; receiver is the first arg
-       li              r11,kFwdMsgSend         ; indicate word-return to _objc_msgForward
-       bctr                                    ; goto *imp;
-
-; cache miss: go search the method lists
-LMsgSendSuperMTCacheMiss:
-       MethodTableLookup WORD_RETURN, MSG_SENDSUPER, MANY_ARGS
-       PUNLOCK r11, _messageLock
-       lwz             r3,receiver(r3)         ; receiver is the first arg
-       li              r11,kFwdMsgSend         ; indicate word-return to _objc_msgForward
-       bctr                                    ; goto *imp;
-#endif
-
 LMsgSendSuperExit:
        END_ENTRY       _objc_msgSendSuper
 
@@ -931,15 +962,7 @@ LMsgSendSuperExit:
 ; do profiling when enabled
        CALL_MCOUNT
 
-#if !defined(OBJC_COLLECTING_CACHE)
-; check whether context is multithreaded
-       lis             r11,ha16(__objc_multithread_mask)
-       lwz             r11,lo16(__objc_multithread_mask)(r11)
-       cmplwi          r11,0                   ; objc_multithread_mask zero?
-       beq             LMsgSendSuperStretMT    ; branch to the locking case
-#endif
-
-; single threaded: search the cache
+; search the cache
        CacheLookup STRUCT_RETURN, MSG_SENDSUPER, LMsgSendSuperStretCacheMiss, MANY_ARGS
        lwz             r4,receiver(r4)         ; receiver is the first arg
        li              r11,kFwdMsgSendStret    ; indicate struct-return to _objc_msgForward
@@ -952,25 +975,6 @@ LMsgSendSuperStretCacheMiss:
        li              r11,kFwdMsgSendStret    ; indicate struct-return to _objc_msgForward
        bctr                                    ; goto *imp;
 
-#if !defined(OBJC_COLLECTING_CACHE)
-; multithreaded: hold _messageLock while accessing cache
-LMsgSendSuperStretMT:  
-       PLOCK   r11, _messageLock
-       CacheLookup STRUCT_RETURN, MSG_SENDSUPER, LMsgSendSuperStretMTCacheMiss, MANY_ARGS
-       PUNLOCK r11, _messageLock
-       lwz             r4,receiver(r4)         ; receiver is the first arg
-       li              r11,kFwdMsgSendStret    ; indicate struct-return to _objc_msgForward
-       bctr                                    ; goto *imp;
-
-; cache miss: go search the method lists
-LMsgSendSuperStretMTCacheMiss:
-       MethodTableLookup STRUCT_RETURN, MSG_SENDSUPER, MANY_ARGS
-       PUNLOCK r11, _messageLock
-       lwz             r4,receiver(r4)         ; receiver is the first arg
-       li              r11,kFwdMsgSendStret    ; indicate struct-return to _objc_msgForward
-       bctr                                    ; goto *imp;
-#endif
-
 LMsgSendSuperStretExit:
        END_ENTRY       _objc_msgSendSuper_stret
 
@@ -1359,15 +1363,7 @@ LMsgSendvStretSendIt:
        cmplwi          r3,0                    ; receiver nil?
        beq             LMsgSendFewNilSelf      ; if so, call handler or return nil
 
-#if !defined(OBJC_COLLECTING_CACHE)
-; check whether context is multithreaded
-       lis             r11,ha16(__objc_multithread_mask)
-       lwz             r11,lo16(__objc_multithread_mask)(r11)
-       cmplwi          r11,0                   ; objc_multithread_mask zero?
-       beq             LMsgSendFewMT           ; branch to the locking case
-#endif
-
-; single threaded and receiver is non-nil: search the cache
+; receiver is non-nil: search the cache
        CacheLookup WORD_RETURN, MSG_SEND, LMsgSendFewCacheMiss, FEW_ARGS
        li              r11,kFwdMsgSend         ; indicate word-return to _objc_msgForward
        bctr                                    ; goto *imp;
@@ -1378,23 +1374,6 @@ LMsgSendFewCacheMiss:
        li              r11,kFwdMsgSend         ; indicate word-return to _objc_msgForward
        bctr                                    ; goto *imp;
 
-#if !defined(OBJC_COLLECTING_CACHE)
-; multithreaded: hold _messageLock while accessing cache
-LMsgSendFewMT:
-       PLOCK   r11, _messageLock
-       CacheLookup WORD_RETURN, MSG_SEND, LMsgSendFewMTCacheMiss, FEW_ARGS
-       PUNLOCK r11, _messageLock
-       li              r11,kFwdMsgSend         ; indicate word-return to _objc_msgForward
-       bctr                                    ; goto *imp;
-
-; cache miss: go search the method lists
-LMsgSendFewMTCacheMiss:
-       MethodTableLookup WORD_RETURN, MSG_SEND, FEW_ARGS
-       PUNLOCK r11, _messageLock
-       li              r11,kFwdMsgSend         ; indicate word-return to _objc_msgForward
-       bctr                                    ; goto *imp;
-#endif
-
 ; message sent to nil object call: optional handler and return nil
 LMsgSendFewNilSelf:
        LOAD_STATIC_WORD r11, __objc_msgNil, EXTERNAL_SYMBOL
@@ -1439,15 +1418,7 @@ LMsgSendFewExit:
        cmplwi          r4,0                    ; receiver nil?
        beq             LMsgSendFewStretNilSelf ; if so, call handler or just return
 
-#if !defined(OBJC_COLLECTING_CACHE)
-; check whether context is multithreaded
-       lis             r11,ha16(__objc_multithread_mask)
-       lwz             r11,lo16(__objc_multithread_mask)(r11)
-       cmplwi          r11,0                   ; objc_multithread_mask zero?
-       beq             LMsgSendFewStretMT      ; branch to the locking case
-#endif
-
-; single threaded and receiver is non-nil: search the cache
+; receiver is non-nil: search the cache
        CacheLookup STRUCT_RETURN, MSG_SEND, LMsgSendFewStretCacheMiss, FEW_ARGS
        li              r11,kFwdMsgSendStret    ; indicate struct-return to _objc_msgForward
        bctr                                    ; goto *imp;
@@ -1458,23 +1429,6 @@ LMsgSendFewStretCacheMiss:
        li              r11,kFwdMsgSendStret    ; indicate struct-return to _objc_msgForward
        bctr                                    ; goto *imp;
 
-#if !defined(OBJC_COLLECTING_CACHE)
-; multithreaded: hold _messageLock while accessing cache
-LMsgSendFewStretMT:    
-       PLOCK   r11, _messageLock
-       CacheLookup STRUCT_RETURN, MSG_SEND, LMsgSendFewStretMTCacheMiss, FEW_ARGS
-       PUNLOCK r11, _messageLock
-       li              r11,kFwdMsgSendStret    ; indicate struct-return to _objc_msgForward
-       bctr                                    ; goto *imp;
-
-; cache miss: go search the method lists
-LMsgSendFewStretMTCacheMiss:
-       MethodTableLookup STRUCT_RETURN, MSG_SEND, FEW_ARGS
-       PUNLOCK r11, _messageLock
-       li              r11,kFwdMsgSendStret    ; indicate struct-return to _objc_msgForward
-       bctr                                    ; goto *imp;
-#endif
-
 ; message sent to nil object call optional handler and return nil
 LMsgSendFewStretNilSelf:
        LOAD_STATIC_WORD r11, __objc_msgNil, EXTERNAL_SYMBOL
@@ -1513,15 +1467,7 @@ LMsgSendFewStretExit:
 ; do profiling when enabled
        CALL_MCOUNT
 
-#if !defined(OBJC_COLLECTING_CACHE)
-; check whether context is multithreaded
-       lis             r11,ha16(__objc_multithread_mask)
-       lwz             r11,lo16(__objc_multithread_mask)(r11)
-       cmplwi          r11,0                   ; objc_multithread_mask zero?
-       beq             LMsgSendSuperFewMT      ; branch to the locking case
-#endif
-
-; single threaded: search the cache
+; search the cache
        CacheLookup WORD_RETURN, MSG_SENDSUPER, LMsgSendSuperFewCacheMiss, FEW_ARGS
        lwz             r3,receiver(r3)         ; receiver is the first arg
        li              r11,kFwdMsgSend         ; indicate word-return to _objc_msgForward
@@ -1534,25 +1480,6 @@ LMsgSendSuperFewCacheMiss:
        li              r11,kFwdMsgSend         ; indicate word-return to _objc_msgForward
        bctr                                    ; goto *imp;
 
-#if !defined(OBJC_COLLECTING_CACHE)
-; multithreaded: hold _messageLock while accessing cache
-LMsgSendSuperFewMT:    
-       PLOCK   r11, _messageLock
-       CacheLookup WORD_RETURN, MSG_SENDSUPER, LMsgSendSuperFewMTCacheMiss, FEW_ARGS
-       PUNLOCK r11, _messageLock
-       lwz             r3,receiver(r3)         ; receiver is the first arg
-       li              r11,kFwdMsgSend         ; indicate word-return to _objc_msgForward
-       bctr                                    ; goto *imp;
-
-; cache miss: go search the method lists
-LMsgSendSuperFewMTCacheMiss:
-       MethodTableLookup WORD_RETURN, MSG_SENDSUPER, FEW_ARGS
-       PUNLOCK r11, _messageLock
-       lwz             r3,receiver(r3)         ; receiver is the first arg
-       li              r11,kFwdMsgSend         ; indicate word-return to _objc_msgForward
-       bctr                                    ; goto *imp;
-#endif
-
 LMsgSendSuperFewExit:
        END_ENTRY       _objc_msgSendSuperFew
 
@@ -1581,15 +1508,7 @@ LMsgSendSuperFewExit:
 ; do profiling when enabled
        CALL_MCOUNT
 
-#if !defined(OBJC_COLLECTING_CACHE)
-; check whether context is multithreaded
-       lis             r11,ha16(__objc_multithread_mask)
-       lwz             r11,lo16(__objc_multithread_mask)(r11)
-       cmplwi          r11,0                   ; objc_multithread_mask zero?
-       beq             LMsgSendSuperFewStretMT ; branch to the locking case
-#endif
-
-; single threaded: search the cache
+; search the cache
        CacheLookup STRUCT_RETURN, MSG_SENDSUPER, LMsgSendSuperFewStretCacheMiss, FEW_ARGS
        lwz             r4,receiver(r4)         ; receiver is the first arg
        li              r11,kFwdMsgSendStret    ; indicate struct-return to _objc_msgForward
@@ -1602,25 +1521,6 @@ LMsgSendSuperFewStretCacheMiss:
        li              r11,kFwdMsgSendStret    ; indicate struct-return to _objc_msgForward
        bctr                                    ; goto *imp;
 
-#if !defined(OBJC_COLLECTING_CACHE)
-; multithreaded: hold _messageLock while accessing cache
-LMsgSendSuperFewStretMT:       
-       PLOCK   r11, _messageLock
-       CacheLookup STRUCT_RETURN, MSG_SENDSUPER, LMsgSendSuperFewStretMTCacheMiss, FEW_ARGS
-       PUNLOCK r11, _messageLock
-       lwz             r4,receiver(r4)         ; receiver is the first arg
-       li              r11,kFwdMsgSendStret    ; indicate struct-return to _objc_msgForward
-       bctr                                    ; goto *imp;
-
-; cache miss: go search the method lists
-LMsgSendSuperFewStretMTCacheMiss:
-       MethodTableLookup STRUCT_RETURN, MSG_SENDSUPER, FEW_ARGS
-       PUNLOCK r11, _messageLock
-       lwz             r4,receiver(r4)         ; receiver is the first arg
-       li              r11,kFwdMsgSendStret    ; indicate struct-return to _objc_msgForward
-       bctr                                    ; goto *imp;
-#endif
-
 LMsgSendSuperFewStretExit:
        END_ENTRY       _objc_msgSendSuperFew_stret
 
index c7cb936c8f6b13d39fd46a4a465cad49fc11e64f..312d2e06dff2236106a5cd88981a103301da11ca 100644 (file)
 
 /* Abstract Protocol for Dynamic Loading */
 
-#if !defined(NeXT_PDO)
 @interface Object (DynamicLoading)
 
 //+ finishLoading:(headerType *)header;
 + startUnloading;
 
 @end
-#endif
 
 OBJC_EXPORT id object_dispose(Object *anObject);
 OBJC_EXPORT id object_copy(Object *anObject, unsigned nBytes);
index 08a6df4ea6faddb67df762fb2f966446ab3b3679..e3552b6f1ef355b7feeef609eba414904b45c97d 100644 (file)
        Copyright 1988-1996 NeXT Software, Inc.
 */
 
-#ifdef WINNT
-#include <winnt-pdo.h>
-#endif
-
-#ifdef NeXT_PDO                        // pickup BUG fix flags
-#import <pdo.h>
-#endif
-
 #import <objc/Object.h>
 #import "objc-private.h"
 #import <objc/objc-runtime.h>
@@ -44,7 +36,6 @@
 OBJC_EXPORT id (*_cvtToId)(const char *);
 OBJC_EXPORT id (*_poseAs)();
 
-#define ISMETA(cls)            (((struct objc_class *)cls)->info & CLS_META) 
 
 // Error Messages
 static const char
index e7326f5827271306ec22e1c25e12d628cc350e9e..c9de42ef0d84a283b11ac1b2a6b196d8f1376e53 100644 (file)
@@ -30,7 +30,7 @@
 
 */
 
-#warning the API in this header is obsolete
+#warning The API in this header is obsoleted by NSArray.
 
 #ifndef _OBJC_LIST_H_
 #define _OBJC_LIST_H_
diff --git a/runtime/OldClasses.subproj/Makefile b/runtime/OldClasses.subproj/Makefile
deleted file mode 100644 (file)
index 2f15e0f..0000000
+++ /dev/null
@@ -1,49 +0,0 @@
-#
-# Generated by the Apple Project Builder.
-#
-# NOTE: Do NOT change this file -- Project Builder maintains it.
-#
-# Put all of your customizations in files called Makefile.preamble
-# and Makefile.postamble (both optional), and Makefile will include them.
-#
-
-NAME = OldClasses
-
-PROJECTVERSION = 2.8
-PROJECT_TYPE = Component
-
-HFILES = List.h
-
-MFILES = List.m
-
-OTHERSRCS = Makefile.preamble Makefile
-
-
-MAKEFILEDIR = $(MAKEFILEPATH)/pb_makefiles
-CODE_GEN_STYLE = DYNAMIC
-MAKEFILE = subproj.make
-LIBS = 
-DEBUG_LIBS = $(LIBS)
-PROF_LIBS = $(LIBS)
-
-
-PUBLIC_HEADERS = List.h
-
-
-
-NEXTSTEP_OBJCPLUS_COMPILER = /usr/bin/cc
-WINDOWS_OBJCPLUS_COMPILER = $(DEVDIR)/gcc
-PDO_UNIX_OBJCPLUS_COMPILER = $(NEXTDEV_BIN)/gcc
-NEXTSTEP_JAVA_COMPILER = /usr/bin/javac
-WINDOWS_JAVA_COMPILER = $(JDKBINDIR)/javac.exe
-PDO_UNIX_JAVA_COMPILER = $(NEXTDEV_BIN)/javac
-
-include $(MAKEFILEDIR)/platform.make
-
--include Makefile.preamble
-
-include $(MAKEFILEDIR)/$(MAKEFILE)
-
--include Makefile.postamble
-
--include Makefile.dependencies
diff --git a/runtime/OldClasses.subproj/Makefile.preamble b/runtime/OldClasses.subproj/Makefile.preamble
deleted file mode 100644 (file)
index 2b5897a..0000000
+++ /dev/null
@@ -1,7 +0,0 @@
-
-OTHER_PROJECT_HEADERS = $(PUBLIC_HEADERS) $(OTHER_PRIVATE_HEADERS)
-
-PUBLIC_HEADER_DIR_SUFFIX = /objc
-PRIVATE_HEADER_DIR_SUFFIX = /objc
-
-
diff --git a/runtime/OldClasses.subproj/PB.project b/runtime/OldClasses.subproj/PB.project
deleted file mode 100644 (file)
index da9c064..0000000
+++ /dev/null
@@ -1,27 +0,0 @@
-{
-    DYNAMIC_CODE_GEN = YES; 
-    FILESTABLE = {
-        CLASSES = (); 
-        H_FILES = (List.h); 
-        OTHER_LINKED = (List.m); 
-        OTHER_SOURCES = (Makefile.preamble, Makefile); 
-        PROJECT_HEADERS = (); 
-        PUBLIC_HEADERS = (List.h); 
-        SUBPROJECTS = (); 
-    }; 
-    LANGUAGE = English; 
-    LOCALIZABLE_FILES = {}; 
-    MAKEFILEDIR = "$(MAKEFILEPATH)/pb_makefiles"; 
-    NEXTSTEP_BUILDTOOL = /bin/gnumake; 
-    NEXTSTEP_JAVA_COMPILER = /usr/bin/javac; 
-    NEXTSTEP_OBJCPLUS_COMPILER = /usr/bin/cc; 
-    PDO_UNIX_BUILDTOOL = $NEXT_ROOT/Developer/bin/make; 
-    PDO_UNIX_JAVA_COMPILER = "$(NEXTDEV_BIN)/javac"; 
-    PDO_UNIX_OBJCPLUS_COMPILER = "$(NEXTDEV_BIN)/gcc"; 
-    PROJECTNAME = OldClasses; 
-    PROJECTTYPE = Component; 
-    PROJECTVERSION = 2.8; 
-    WINDOWS_BUILDTOOL = $NEXT_ROOT/Developer/Executables/make; 
-    WINDOWS_JAVA_COMPILER = "$(JDKBINDIR)/javac.exe"; 
-    WINDOWS_OBJCPLUS_COMPILER = "$(DEVDIR)/gcc"; 
-}
diff --git a/runtime/PB.project b/runtime/PB.project
deleted file mode 100644 (file)
index e197c50..0000000
+++ /dev/null
@@ -1,68 +0,0 @@
-{
-    CURRENTLY_ACTIVE_VERSION = YES; 
-    DEPLOY_WITH_VERSION_NAME = A; 
-    DYNAMIC_CODE_GEN = YES; 
-    FILESTABLE = {
-        CLASSES = (); 
-        HEADERSEARCH = (); 
-        H_FILES = (
-            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
-        ); 
-        OTHER_LINKED = (
-            hashtable2.m, 
-            maptable.m, 
-            "objc-class.m", 
-            "objc-errors.m", 
-            "objc-file.m", 
-            "objc-load.m", 
-            "objc-moninit.c", 
-            "objc-runtime.m", 
-            "objc-sel.m", 
-            Object.m, 
-            Protocol.m
-        ); 
-        OTHER_SOURCES = (Makefile.preamble, Makefile, Makefile.postamble); 
-        PROJECT_HEADERS = ("objc-runtime.h", "objc-class.h"); 
-        PUBLIC_HEADERS = (
-            "objc-class.h", 
-            "objc-api.h", 
-            "objc-load.h", 
-            "objc-runtime.h", 
-            objc.h, 
-            Object.h, 
-            Protocol.h, 
-            error.h, 
-            hashtable2.h
-        ); 
-        SUBPROJECTS = (Messengers.subproj, OldClasses.subproj); 
-    }; 
-    LANGUAGE = English; 
-    LOCALIZABLE_FILES = {}; 
-    MAKEFILEDIR = "$(MAKEFILEPATH)/pb_makefiles"; 
-    NEXTSTEP_BUILDTOOL = /usr/bin/gnumake; 
-    NEXTSTEP_INSTALLDIR = /usr/lib; 
-    NEXTSTEP_JAVA_COMPILER = /usr/bin/javac; 
-    NEXTSTEP_OBJCPLUS_COMPILER = /usr/bin/cc; 
-    PDO_UNIX_BUILDTOOL = $NEXT_ROOT/Developer/bin/make; 
-    PDO_UNIX_INSTALLDIR = "$(LOCAL_DEVELOPER_DIR)/Libraries"; 
-    PDO_UNIX_JAVA_COMPILER = "$(NEXTDEV_BIN)/javac"; 
-    PDO_UNIX_OBJCPLUS_COMPILER = "$(NEXTDEV_BIN)/gcc"; 
-    PROJECTNAME = runtime; 
-    PROJECTTYPE = Library; 
-    PROJECTVERSION = 2.8; 
-    WINDOWS_BUILDTOOL = $NEXT_ROOT/Developer/Executables/make; 
-    WINDOWS_INSTALLDIR = /.; 
-    WINDOWS_JAVA_COMPILER = "$(JDKBINDIR)/javac.exe"; 
-    WINDOWS_OBJCPLUS_COMPILER = "$(DEVDIR)/gcc"; 
-}
index 3faf3d5a752f1fbeecc0eab7254a973e6eb90707..acbefbad6401b6aa078c7476737e45925be28eb6 100644 (file)
@@ -31,7 +31,7 @@
     All rights reserved.
 */
 
-#warning the API in this header is obsolete
+#warning The API in this header is obsoleted by NSException et al.
 
 #ifndef _OBJC_ERROR_H_
 #define _OBJC_ERROR_H_
@@ -100,7 +100,7 @@ OBJC_EXPORT void _NXRemoveHandler( NXHandler *handler );
  */
 
 OBJC_EXPORT
-#if defined(__GNUC__) && !defined(__STRICT_ANSI__) && !defined(NeXT_PDO)
+#if defined(__GNUC__) && !defined(__STRICT_ANSI__)
     volatile   /* never returns */
 #endif 
 void _NXRaiseError(int code, const void *data1, const void *data2)
index ecb94be58556a320bf4214087f9cb4b81abb81ec..0f13973d12765fcb8e951c11501eb6ca7e28b6ec 100644 (file)
@@ -27,7 +27,7 @@
     Copyright 1989-1996 NeXT Software, Inc.
 */
 
-#warning the API in this header is obsolete
+#warning The API in this header is obsoleted by NSHashtable.h
 
 #ifndef _OBJC_LITTLE_HASHTABLE_H_
 #define _OBJC_LITTLE_HASHTABLE_H_
@@ -39,7 +39,7 @@
  *************************************************************************/
 
 /* This module allows hashing of arbitrary data.  Such data must be pointers or integers, and client is responsible for allocating/deallocating this data.  A deallocation call-back is provided.
-The objective C class HashTable is prefered when dealing with (key, values) associations because it is easier to use in that situation.
+The objective C class HashTable is preferred when dealing with (key, values) associations because it is easier to use in that situation.
 As well-behaved scalable data structures, hash tables double in size when they start becoming full, thus guaranteeing both average constant time access and linear size. */
 
 typedef struct {
index 26b88e1fae3cb1c31eda5f870468e47adbea11b6..8cfca838760af635a857fd9f8022d0b1b3a04313 100644 (file)
        Created by Bertrand Serlet, Feb 89
  */
 
-#if defined(NeXT_PDO)
-#import <pdo.h>
-#endif
-
 #import <objc/hashtable2.h>
 #import "objc-private.h"
 
index 2b139e1e2226561a830ee881d5836a158c153066..c911378e8a5849ec8b1e7ad2c361d3c6667233b7 100644 (file)
 
 
 #if !defined(OBJC_EXPORT)
+#if defined(__cplusplus)
+    #define OBJC_EXPORT extern "C" 
+#else
     #define OBJC_EXPORT extern
 #endif
+#endif
 
 #if !defined(OBJC_IMPORT)
     #define OBJC_IMPORT extern
index 7d3be02b5002701ba177f45ba6c73d2b279c2b1e..b1b61c34ab1402bb782e58f9923782bd17cfc577 100644 (file)
@@ -47,8 +47,8 @@ struct objc_class {
        struct objc_cache *cache;
        struct objc_protocol_list *protocols;
 };
-#define CLS_GETINFO(cls,infomask)      ((cls)->info & infomask)
-#define CLS_SETINFO(cls,infomask)      ((cls)->info |= infomask)
+#define CLS_GETINFO(cls,infomask)      ((cls)->info & (infomask))
+#define CLS_SETINFO(cls,infomask)      ((cls)->info |= (infomask))
 
 #define CLS_CLASS              0x1L
 #define CLS_META               0x2L
@@ -62,6 +62,51 @@ struct objc_class {
 // the JavaBridge constructs classes with these markers
 #define CLS_JAVA_HYBRID                0x200L
 #define CLS_JAVA_CLASS         0x400L
+// thread-safe +initialize
+#define CLS_INITIALIZING       0x800
+
+/*
+ * (true as of 2001-9-24)
+ * Thread-safety note: changes to these flags are not atomic, so 
+ * the only thing preventing lost updates is the timing of the changes.
+ *
+ * As long as the following are isolated from each other for any one class, 
+ * nearly all flag updates will be safe:
+ * - compile-time
+ * - loading in one thread (not including +load) without messaging
+ * - initializing in one thread with messaging from that thread only
+ * - multi-threaded messaging with method caching
+ *
+ * The current code doesn't protect loading yet.
+ *
+ * Times when the flags may change:
+ * CLS_CLASS: compile-time, hand-built classes
+ * CLS_META: compile time, hand-built classes
+ * CLS_INITIALIZED: initialize
+ * CLS_POSING: unsafe, but posing has other thread-safety problems
+ * CLS_MAPPED: compile-time
+ * CLS_FLUSH_CACHE: messaging
+ * CLS_GROW_CACHE: messaging
+ *   FLUSH_CACHE and GROW_CACHE are protected from each other by the 
+ *   cacheUpdateLock.
+ * CLS_NEED_BIND: load, initialize
+ * CLS_METHOD_ARRAY: load
+ * CLS_JAVA_HYBRID: hand-built classes
+ * CLS_JAVA_CLASS: hand-built classes, initialize
+ * CLS_INITIALIZING: initialize
+ *
+ * The only unsafe updates are:
+ * - posing (unsafe anyway)
+ * - hand-built classes (including JavaBridge classes)
+ *   There is a short time between objc_addClass inserts the new class 
+ *   into the class_hash and the builder setting the right flags. 
+ *   A thread looking at the class_hash could send a message to the class 
+ *   and trigger initialization, and the changes to the initialization 
+ *   flags and the hand-adjusted flags could collide. 
+ *   Solution: don't do that. 
+ */
+
+
 /* 
  *     Category Template
  */
@@ -74,24 +119,27 @@ struct objc_category {
        struct objc_method_list *class_methods;
        struct objc_protocol_list *protocols;
 };
+
 /* 
  *     Instance Variable Template
  */
 typedef struct objc_ivar *Ivar;
 
-struct objc_ivar_list {
-       int ivar_count;
+struct objc_ivar {
+       char *ivar_name;
+       char *ivar_type;
+       int ivar_offset;
 #ifdef __alpha__
        int space;
 #endif
-       struct objc_ivar {
-               char *ivar_name;
-               char *ivar_type;
-               int ivar_offset;
+};
+
+struct objc_ivar_list {
+       int ivar_count;
 #ifdef __alpha__
-               int space;
+       int space;
 #endif
-       } ivar_list[1];                 /* variable length structure */
+       struct objc_ivar ivar_list[1];          /* variable length structure */
 };
 
 OBJC_EXPORT Ivar object_setInstanceVariable(id, const char *name, void *);
@@ -102,6 +150,12 @@ OBJC_EXPORT Ivar object_getInstanceVariable(id, const char *name, void **);
  */
 typedef struct objc_method *Method;
 
+struct objc_method {
+       SEL method_name;
+       char *method_types;
+       IMP method_imp;
+};
+
 struct objc_method_list {
        struct objc_method_list *obsolete;
 
@@ -109,11 +163,7 @@ struct objc_method_list {
 #ifdef __alpha__
        int space;
 #endif
-       struct objc_method {
-               SEL method_name;
-               char *method_types;
-                IMP method_imp;
-       } method_list[1];               /* variable length structure */
+       struct objc_method method_list[1];      /* variable length structure */
 };
 
 /* Protocol support */
@@ -160,6 +210,7 @@ typedef struct objc_cache * Cache;
 #define CACHE_BUCKET_NAME(B)  ((B)->method_name)
 #define CACHE_BUCKET_IMP(B)   ((B)->method_imp)
 #define CACHE_BUCKET_VALID(B) (B)
+#define CACHE_HASH(sel, mask) (((uarith_t)(sel)>>2) & (mask))
 struct objc_cache {
        unsigned int mask;            /* total = mask + 1 */
        unsigned int occupied;        
@@ -185,7 +236,6 @@ OBJC_EXPORT Class class_poseAs(Class imposter, Class original);
 OBJC_EXPORT unsigned method_getNumberOfArguments(Method);
 OBJC_EXPORT unsigned method_getSizeOfArguments(Method);
 OBJC_EXPORT unsigned method_getArgumentInfo(Method m, int arg, const char **type, int *offset);
-OBJC_EXPORT const char * NSModulePathForClass (Class aClass);
 
 // usage for nextMethodList
 //
index cfb47f2db8daf199f10af8eb3264026f3679e932..16d474d97b74ed9b737b681815f13ecc3c6f4dd1 100644 (file)
 *      Author: s. naroff
 **********************************************************************/
 
+
+/***********************************************************************
+ * Method cache locking (GrP 2001-1-14)
+ *
+ * For speed, objc_msgSend does not acquire any locks when it reads 
+ * method caches. Instead, all cache changes are performed so that any 
+ * objc_msgSend running concurrently with the cache mutator will not 
+ * crash or hang or get an incorrect result from the cache. 
+ *
+ * When cache memory becomes unused (e.g. the old cache after cache 
+ * expansion), it is not immediately freed, because a concurrent 
+ * objc_msgSend could still be using it. Instead, the memory is 
+ * disconnected from the data structures and placed on a garbage list. 
+ * The memory is now only accessible to instances of objc_msgSend that 
+ * were running when the memory was disconnected; any further calls to 
+ * objc_msgSend will not see the garbage memory because the other data 
+ * structures don't point to it anymore. The collecting_in_critical
+ * function checks the PC of all threads and returns FALSE when all threads 
+ * are found to be outside objc_msgSend. This means any call to objc_msgSend 
+ * that could have had access to the garbage has finished or moved past the 
+ * cache lookup stage, so it is safe to free the memory.
+ *
+ * All functions that modify cache data or structures must acquire the 
+ * cacheUpdateLock to prevent interference from concurrent modifications.
+ * The function that frees cache garbage must acquire the cacheUpdateLock 
+ * and use collecting_in_critical() to flush out cache readers.
+ *
+ * Cache readers (PC-checked by collecting_in_critical())
+ * objc_msgSend*
+ * _cache_getImp
+ * _cache_getMethod
+ *
+ * Cache writers (hold cacheUpdateLock while reading or writing; not PC-checked)
+ * _cache_fill         (acquires lock)
+ * _cache_expand       (only called from cache_fill)
+ * _cache_create       (only called from cache_expand)
+ * bcopy               (only called from instrumented cache_expand)
+ * flush_caches        (acquires lock)
+ * _cache_flush        (only called from cache_fill and flush_caches)
+ * _cache_collect_free (only called from cache_expand and cache_flush)
+ *
+ * UNPROTECTED cache readers (NOT thread-safe; used for debug info only)
+ * _cache_print
+ * _class_printMethodCaches
+ * _class_printDuplicateCacheEntries
+ * _class_printMethodCacheStatistics
+ *
+ * _class_lookupMethodAndLoadCache is a special case. It may read a 
+ * method triplet out of one cache and store it in another cache. This 
+ * is unsafe if the method triplet is a forward:: entry, because the 
+ * triplet itself could be freed unless _class_lookupMethodAndLoadCache 
+ * were PC-checked or used a lock. Additionally, storing the method 
+ * triplet in both caches would result in double-freeing if both caches 
+ * were flushed or expanded. The solution is for _cache_getMethod to 
+ * ignore all entries whose implementation is _objc_msgForward, so 
+ * _class_lookupMethodAndLoadCache cannot look at a forward:: entry
+ * unsafely or place it in multiple caches.
+ ***********************************************************************/
+
+/***********************************************************************
+ * Thread-safety during class initialization (GrP 2001-9-24)
+ *
+ * Initial state: CLS_INITIALIZING and CLS_INITIALIZED both clear. 
+ * During initialization: CLS_INITIALIZING is set
+ * After initialization: CLS_INITIALIZING clear and CLS_INITIALIZED set.
+ * CLS_INITIALIZING and CLS_INITIALIZED are never set at the same time.
+ * CLS_INITIALIZED is never cleared once set.
+ *
+ * Only one thread is allowed to actually initialize a class and send 
+ * +initialize. Enforced by allowing only one thread to set CLS_INITIALIZING.
+ *
+ * Additionally, threads trying to send messages to a class must wait for 
+ * +initialize to finish. During initialization of a class, that class's 
+ * method cache is kept empty. objc_msgSend will revert to 
+ * class_lookupMethodAndLoadCache, which checks CLS_INITIALIZED before 
+ * messaging. If CLS_INITIALIZED is clear but CLS_INITIALIZING is set, 
+ * the thread must block, unless it is the thread that started 
+ * initializing the class in the first place. 
+ *
+ * Each thread keeps a list of classes it's initializing. 
+ * The global classInitLock is used to synchronize changes to CLS_INITIALIZED 
+ * and CLS_INITIALIZING: the transition to CLS_INITIALIZING must be 
+ * an atomic test-and-set with respect to itself and the transition 
+ * to CLS_INITIALIZED.
+ * The global classInitWaitCond is used to block threads waiting for an 
+ * initialization to complete. The classInitLock synchronizes
+ * condition checking and the condition variable.
+ **********************************************************************/
+
+/***********************************************************************
+ *  +initialize deadlock case when a class is marked initializing while 
+ *  its superclass is initialized. Solved by completely initializing 
+ *  superclasses before beginning to initialize a class.
+ *
+ *  OmniWeb class hierarchy:
+ *                 OBObject 
+ *                     |    ` OBPostLoader
+ *                 OFObject
+ *                 /     \
+ *      OWAddressEntry  OWController
+ *                        | 
+ *                      OWConsoleController
+ *
+ *  Thread 1 (evil testing thread):
+ *    initialize OWAddressEntry
+ *    super init OFObject
+ *    super init OBObject                   
+ *    [OBObject initialize] runs OBPostLoader, which inits lots of classes...
+ *    initialize OWConsoleController
+ *    super init OWController - wait for Thread 2 to finish OWController init
+ *
+ *  Thread 2 (normal OmniWeb thread):
+ *    initialize OWController
+ *    super init OFObject - wait for Thread 1 to finish OFObject init
+ *
+ *  deadlock!
+ *
+ *  Solution: fully initialize super classes before beginning to initialize 
+ *  a subclass. Then the initializing+initialized part of the class hierarchy
+ *  will be a contiguous subtree starting at the root, so other threads 
+ *  can't jump into the middle between two initializing classes, and we won't 
+ *  get stuck while a superclass waits for its subclass which waits for the 
+ *  superclass.
+ **********************************************************************/
+
+
+
 /***********************************************************************
 * Imports.
 **********************************************************************/
@@ -73,6 +200,9 @@ size_t malloc_size (const void * ptr);
 // purpose
 // See radar 2364264 about incorrectly propogating _objc_forward entries
 // and double freeing them, first, before turning this on!
+// (Radar 2364264 is now "inactive".)
+// Double-freeing is also a potential problem when this is off. See 
+// note about _class_lookupMethodAndLoadCache in "Method cache locking".
 //#define PRELOAD_SUPERCLASS_CACHES
 
 /***********************************************************************
@@ -104,12 +234,6 @@ enum {
 // one entry is embedded in the cache structure itself
 #define TABLE_SIZE(count)      ((count - 1) * sizeof(Method))
 
-// Class state
-#define ISCLASS(cls)           ((((struct objc_class *) cls)->info & CLS_CLASS) != 0)
-#define ISMETA(cls)            ((((struct objc_class *) cls)->info & CLS_META) != 0)
-#define GETMETA(cls)           (ISMETA(cls) ? ((struct objc_class *) cls) : ((struct objc_class *) cls)->isa)
-#define ISINITIALIZED(cls)     ((GETMETA(cls)->info & CLS_INITIALIZED) != 0)
-#define MARKINITIALIZED(cls)   (GETMETA(cls)->info |= CLS_INITIALIZED)
 
 /***********************************************************************
 * Types internal to this module.
@@ -144,22 +268,19 @@ static void               addClassToOriginalClass (Class posingClass, Class originalClass);
 static void            _objc_addOrigClass              (Class origClass);
 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             class_initialize                (Class cls);
 static Cache   _cache_expand                   (Class cls);
 static int             LogObjCMessageSend              (BOOL isClassMethod, const char * objectsClass, const char * implementingClass, SEL selector);
-static void            _cache_fill                             (Class cls, Method smt, SEL sel);
+static BOOL            _cache_fill                             (Class cls, Method smt, SEL sel);
+static void _cache_addForwardEntry(Class cls, 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);
 
-#ifdef OBJC_COLLECTING_CACHE
 static unsigned long   _get_pc_for_thread      (mach_port_t thread);
 static int             _collecting_in_critical (void);
 static void            _garbage_make_room              (void);
 static void            _cache_collect_free             (void * data, BOOL tryCollect);
-#endif
 
 static void            _cache_print                    (Cache cache);
 static unsigned int    log2                            (unsigned int x);
@@ -183,23 +304,20 @@ static int        _class_uncache          = 1;
 // caches are grown every time.
 static int     _class_slow_grow        = 1;
 
-// Locks for cache access
-#ifdef OBJC_COLLECTING_CACHE
-// Held when adding an entry to the cache
+// Lock for cache access.
+// Held when modifying a cache in place.
+// Held when installing a new cache on a class. 
+// Held when adding to the cache garbage list.
+// Held when disposing cache garbage.
+// See "Method cache locking" above for notes about cache locking.
 static OBJC_DECLARE_LOCK(cacheUpdateLock);
 
-// Held when freeing memory from garbage
-static OBJC_DECLARE_LOCK(cacheCollectionLock);
-#endif
-
-// Held when looking in, adding to, or freeing the cache.
-#ifdef OBJC_COLLECTING_CACHE
-// For speed, messageLock is not held by the method dispatch code.
-// Instead the cache freeing code checks thread PCs to ensure no
-// one is dispatching.  messageLock is held, though, during less
-// time critical operations.
-#endif
-OBJC_DECLARE_LOCK(messageLock);
+// classInitLock protects classInitWaitCond and examination and modification 
+// of CLS_INITIALIZED and CLS_INITIALIZING.
+OBJC_DECLARE_LOCK(classInitLock);
+// classInitWaitCond is signalled when any class is done initializing. 
+// Threads that are waiting for a class to finish initializing wait on this.
+pthread_cond_t classInitWaitCond = PTHREAD_COND_INITIALIZER;
 
 CFMutableDictionaryRef _classIMPTables = NULL;
 
@@ -207,11 +325,9 @@ CFMutableDictionaryRef _classIMPTables = NULL;
 // being encached is already there.  The number of times it finds a match
 // is tallied in cacheFillDuplicates.  When traceDuplicatesVerbose is
 // non-zero, each duplication is logged when found in this way.
-#ifdef OBJC_COLLECTING_CACHE
 static int     traceDuplicates         = 0;
 static int     traceDuplicatesVerbose  = 0;
 static int     cacheFillDuplicates     = 0;
-#endif
 
 #ifdef OBJC_INSTRUMENTED
 // Instrumentation
@@ -604,8 +720,7 @@ Ivar        class_getInstanceVariable              (Class           aClass,
 *
 * Specifying Nil for the class "all classes."
 **********************************************************************/
-static void    flush_caches           (Class           cls,
-                                 BOOL          flush_meta)
+static void flush_caches(Class cls, BOOL flush_meta)
 {
     int                numClasses = 0, newNumClasses;
     struct objc_class * *              classes = NULL;
@@ -617,6 +732,7 @@ static void flush_caches           (Class           cls,
 #endif
 
     // Do nothing if class has no cache
+    // This check is safe to do without any cache locks.
     if (cls && !((struct objc_class *) cls)->cache)
         return;
 
@@ -628,6 +744,8 @@ static void flush_caches           (Class           cls,
     }
     numClasses = newNumClasses;
 
+    OBJC_LOCK(&cacheUpdateLock);
+
     // 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.
@@ -651,19 +769,20 @@ static void       flush_caches           (Class           cls,
             // (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))
+            metaClsObject = clsObject->isa;
+            if (cls  &&  metaClsObject  &&  cls->isa != metaClsObject->isa)
+            {
                 continue;
+            }
 
 #ifdef OBJC_INSTRUMENTED
             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);
+            _cache_flush (clsObject);
+            if (flush_meta  &&  metaClsObject != NULL) {
+                _cache_flush (metaClsObject);
+            }
         }
 #ifdef OBJC_INSTRUMENTED
         LinearFlushCachesVisitedCount += classesVisited;
@@ -674,6 +793,7 @@ static void flush_caches           (Class           cls,
             MaxIdealFlushCachesCount = subclassCount;
 #endif
 
+        OBJC_UNLOCK(&cacheUpdateLock);
         free(classes);
         return;
     }
@@ -753,14 +873,14 @@ static void       flush_caches           (Class           cls,
         MaxIdealFlushCachesCount = subclassCount;
 #endif
 
-    // Relinquish access to class hash table
+    OBJC_UNLOCK(&cacheUpdateLock);
     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
+* 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)
@@ -940,7 +1060,6 @@ Class              class_poseAs           (Class           imposter,
                             Class              original)
 {
     struct objc_class * clsObject;
-    char                       imposterName[256];
     char *                     imposterNamePtr;
     NXHashTable *              class_hash;
     NXHashState                state;
@@ -955,21 +1074,20 @@ Class            class_poseAs           (Class           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);
+    #define imposterNamePrefix "_%"
+    imposterNamePtr = malloc_zone_malloc(_objc_create_zone(), strlen(((struct objc_class *)original)->name) + strlen(imposterNamePrefix) + 1);
+    strcpy(imposterNamePtr, imposterNamePrefix);
+    strcat(imposterNamePtr, ((struct objc_class *)original)->name);
+    #undef imposterNamePrefix
 
     // We lock the class hashtable, so we are thread safe with respect to
     // calls to objc_getClass ().  However, the class names are not
@@ -1085,83 +1203,6 @@ static void      _nonexistentHandler    (id              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
-**********************************************************************/
-static void    class_initialize               (Class           clsDesc)
-{
-    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);
-
-    // 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);
-
-    // 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);
-#endif
-
-    // 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);
-#endif
-
-    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.
@@ -1241,21 +1282,6 @@ Error:
         _objc_fatal ("please link appropriate classes in your program");
 }
 
-/***********************************************************************
-* objc_malloc.
-**********************************************************************/
-static void *          objc_malloc                (int         byteCount)
-{
-    void *             space;
-
-    space = malloc_zone_malloc (_objc_create_zone (), byteCount);
-    if (!space && byteCount)
-        _objc_fatal ("unable to allocate space");
-
-    return space;
-}
-
-
 /***********************************************************************
 * class_respondsToMethod.
 *
@@ -1264,60 +1290,31 @@ static void *           objc_malloc                (int         byteCount)
 BOOL   class_respondsToMethod         (Class           cls,
                                     SEL                sel)
 {
-    struct objc_class *                                thisCls;
-    arith_t                            index;
-    arith_t                            mask;
-    Method *                   buckets;
     Method                             meth;
+    IMP imp;
 
     // 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;
+    imp = _cache_getImp(cls, sel);
+    if (imp) {
+        // Found method in cache. 
+        // If the cache entry is forward::, the class does not respond to sel.
+        return (imp != &_objc_msgForward);
     }
 
     // Handle cache miss
     meth = _getMethod(cls, sel);
     if (meth) {
-        OBJC_UNLOCK(&messageLock);
-        _cache_fill (cls, meth, sel);
+        _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);
-    }
+    // Not implemented.  Use _objc_msgForward.
+    _cache_addForwardEntry(cls, sel);
 
-    OBJC_UNLOCK(&messageLock);
     return NO;
-
 }
 
 
@@ -1326,45 +1323,22 @@ BOOL    class_respondsToMethod         (Class           cls,
 *
 * Called from -[Object methodFor:] and +[Object instanceMethodFor:]
 **********************************************************************/
-
+// GrP is this used anymore?
 IMP            class_lookupMethod             (Class           cls,
                                 SEL            sel)
 {
-    Method *   buckets;
-    arith_t            index;
-    arith_t            mask;
-    IMP                result;
+    IMP imp;
 
     // 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;
-    }
+    imp = _cache_getImp(cls, sel);
+    if (imp) return imp;
 
     // Handle cache miss
-    result = _class_lookupMethodAndLoadCache (cls, sel);
-    OBJC_UNLOCK(&messageLock);
-    return result;
+    return _class_lookupMethodAndLoadCache (cls, sel);
 }
 
 /***********************************************************************
@@ -1386,49 +1360,48 @@ IMP     class_lookupNamedMethodInMethodList(struct objc_method_list *mlist,
     return (m ? m->method_imp : NULL);
 }
 
+
 /***********************************************************************
-* _cache_create.
+* _cache_malloc.
 *
-* Called from _cache_expand () and objc_addClass ()
+* Called from _cache_create() and cache_expand()
 **********************************************************************/
-Cache          _cache_create           (Class          cls)
+static Cache _cache_malloc(int slotCount)
 {
-    Cache              new_cache;
-    int                        slotCount;
-    int                        index;
-
-    // Select appropriate size
-    slotCount = (ISMETA(cls)) ? INIT_META_CACHE_SIZE : INIT_CACHE_SIZE;
+    Cache new_cache;
+    size_t size;
 
     // Allocate table (why not check for failure?)
+    size = sizeof(struct objc_cache) + TABLE_SIZE(slotCount);
 #ifdef OBJC_INSTRUMENTED
-    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));
+    size += sizeof(CacheInstrumentation);
 #endif
+    new_cache = malloc_zone_calloc (_objc_create_zone(), size, 1);
 
-    // Invalidate all the buckets
-    for (index = 0; index < slotCount; index += 1)
-        CACHE_BUCKET_VALID(new_cache->buckets[index]) = NULL;
+    // [c|v]allocated memory is zeroed, so all buckets are invalidated 
+    // and occupied == 0 and all instrumentation is zero.
 
-    // 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;
+    return new_cache;
+}
 
-        // Zero out the cache dynamic instrumention data
-        cacheData = CACHE_INSTRUMENTATION(new_cache);
-        bzero ((char *) cacheData, sizeof(CacheInstrumentation));
-    }
-#endif
+
+/***********************************************************************
+* _cache_create.
+*
+* Called from _cache_expand().
+* Cache locks: cacheUpdateLock must be held by the caller.
+**********************************************************************/
+Cache          _cache_create           (Class          cls)
+{
+    Cache              new_cache;
+    int                        slotCount;
+
+    // Select appropriate size
+    slotCount = (ISMETA(cls)) ? INIT_META_CACHE_SIZE : INIT_CACHE_SIZE;
+
+    new_cache = _cache_malloc(slotCount);
 
     // Install the cache
     ((struct objc_class *)cls)->cache = new_cache;
@@ -1450,11 +1423,8 @@ Cache            _cache_create           (Class          cls)
 /***********************************************************************
 * _cache_expand.
 *
-* #ifdef OBJC_COLLECTING_CACHE
-*      The cacheUpdateLock is assumed to be taken at this point.
-* #endif
-*
 * Called from _cache_fill ()
+* Cache locks: cacheUpdateLock must be held by the caller.
 **********************************************************************/
 static Cache           _cache_expand          (Class           cls)
 {
@@ -1500,11 +1470,7 @@ static   Cache           _cache_expand          (Class           cls)
                 // Deallocate "forward::" entry
                 if (CACHE_BUCKET_IMP(oldEntry) == &_objc_msgForward)
                 {
-#ifdef OBJC_COLLECTING_CACHE
                     _cache_collect_free (oldEntry, NO);
-#else
-                    malloc_zone_free (_objc_create_zone(), oldEntry);
-#endif
                 }
             }
 
@@ -1520,21 +1486,7 @@ static   Cache           _cache_expand          (Class           cls)
     // 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));
-#else
-    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;
+    new_cache = _cache_malloc(slotCount);
 
 #ifdef OBJC_INSTRUMENTED
     // Propagate the instrumentation data
@@ -1565,7 +1517,8 @@ static    Cache           _cache_expand          (Class           cls)
                 continue;
 
             // Hash the old entry into the new table
-            index2 = ((unsigned int) CACHE_BUCKET_NAME(old_cache->buckets[index]) & newMask);
+            index2 = CACHE_HASH(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
@@ -1598,11 +1551,7 @@ static   Cache           _cache_expand          (Class           cls)
             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);
-#else
-                malloc_zone_free (_objc_create_zone(), old_cache->buckets[index]);
-#endif
             }
         }
     }
@@ -1611,11 +1560,7 @@ static   Cache           _cache_expand          (Class           cls)
     ((struct objc_class *)cls)->cache = new_cache;
 
     // Deallocate old cache, try freeing all the garbage
-#ifdef OBJC_COLLECTING_CACHE
     _cache_collect_free (old_cache, YES);
-#else
-    malloc_zone_free (_objc_create_zone(), old_cache);
-#endif
     return new_cache;
 }
 
@@ -1632,12 +1577,12 @@ static int      LogObjCMessageSend (BOOL                        isClassMethod,
     // Create/open the log file
     if (objcMsgLogFD == (-1))
     {
-        sprintf (buf, "/tmp/msgSends-%d", (int) getpid ());
+        snprintf (buf, sizeof(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",
+    snprintf(buf, sizeof(buf), "%c %s %s %s\n",
             isClassMethod ? '+' : '-',
             objectsClass,
             implementingClass,
@@ -1685,52 +1630,42 @@ void    logObjcMessageSends      (ObjCLogProc   logProc)
         fsync (objcMsgLogFD);
 }
 
+
 /***********************************************************************
 * _cache_fill.  Add the specified method to the specified class' cache.
+* Returns NO if the cache entry wasn't added: cache was busy, 
+*  class is still being initialized, new entry is a duplicate.
 *
 * Called only from _class_lookupMethodAndLoadCache and
-* class_respondsToMethod.
+* class_respondsToMethod and _cache_addForwardEntry.
 *
-* #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 locks: cacheUpdateLock must not be held.
 **********************************************************************/
-
-static void    _cache_fill    (Class           cls,
-                            Method             smt,
-                            SEL                        sel)
+static BOOL    _cache_fill(Class cls, Method smt, SEL sel)
 {
-    Cache                              cache;
-    Method *                   buckets;
-
-    arith_t                            index;
-    arith_t                            mask;
     unsigned int               newOccupied;
+    arith_t index;
+    Method *buckets;
+    Cache cache;
+
+    // Never cache before +initialize is done
+    if (!ISINITIALIZED(cls)) {
+        return NO;
+    }
 
     // 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;
+    OBJC_LOCK(&cacheUpdateLock);
 
-    // Set up invariants for cache traversals
-    cache      = ((struct objc_class *)cls)->cache;
-    mask       = cache->mask;
-    buckets    = cache->buckets;
+    cache = ((struct objc_class *)cls)->cache;
 
     // Check for duplicate entries, if we're in the mode
     if (traceDuplicates)
     {
         int    index2;
+        arith_t mask = cache->mask;
+        buckets        = cache->buckets;        
 
         // Scan the cache
         for (index2 = 0; index2 < mask + 1; index2 += 1)
@@ -1753,44 +1688,26 @@ static  void    _cache_fill    (Class           cls,
         }
     }
 
-    // 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 the entry wasn't added to the cache by some other thread 
+    // before we grabbed the cacheUpdateLock.
+    // Don't use _cache_getMethod() because _cache_getMethod() doesn't 
+    // return forward:: entries.
+    if (_cache_getImp(cls, sel)) {
+        OBJC_UNLOCK(&cacheUpdateLock);
+        return NO; // entry is already cached, didn't add new one
     }
 
-#else // not OBJC_COLLECTING_CACHE
-    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)
+    if ((newOccupied * 4) <= (cache->mask + 1) * 3) {
+        // Cache is less than 3/4 full.
         cache->occupied = newOccupied;
-
-    // Cache is getting full
-    else
-    {
-        // Flush the cache
-        if ((((struct objc_class * )cls)->info & CLS_FLUSH_CACHE) != 0)
+    } else {
+        // Cache is too full. Flush it or expand it.
+        if ((((struct objc_class * )cls)->info & CLS_FLUSH_CACHE) != 0) {
             _cache_flush (cls);
-
-        // Expand the cache
-        else
-        {
+        } else {
             cache = _cache_expand (cls);
-            mask  = cache->mask;
         }
 
         // Account for the addition
@@ -1809,7 +1726,7 @@ static    void    _cache_fill    (Class           cls,
     // are two kinds of entries, so there have to be two ways
     // to slide them.
     buckets    = cache->buckets;
-    index      = ((unsigned int) sel & mask);
+    index      = CACHE_HASH(sel, cache->mask); 
     for (;;)
     {
         // Slide existing entries down by one
@@ -1830,19 +1747,43 @@ static  void    _cache_fill    (Class           cls,
 
         // Move on to next slot
         index += 1;
-        index &= mask;
+        index &= cache->mask;
     }
 
-#ifdef OBJC_COLLECTING_CACHE
     OBJC_UNLOCK(&cacheUpdateLock);
-#endif
+
+    return YES; // successfully added new cache entry
 }
 
+
+/***********************************************************************
+* _cache_addForwardEntry
+* Add a forward:: entry  for the given selector to cls's method cache.
+* Does nothing if the cache addition fails for any reason.
+* Called from class_respondsToMethod and _class_lookupMethodAndLoadCache.
+* Cache locks: cacheUpdateLock must not be held.
+**********************************************************************/
+static void _cache_addForwardEntry(Class cls, SEL sel)
+{
+    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;
+    if (! _cache_fill(cls, smt, sel)) {
+        // Entry not added to cache. Don't leak the method struct.
+        malloc_zone_free(_objc_create_zone(), smt);
+    }
+}
+
+
 /***********************************************************************
 * _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 ().
+* Called from flush_caches() and _cache_fill()
+* Cache locks: cacheUpdateLock must be held by the caller.
 **********************************************************************/
 static void    _cache_flush            (Class          cls)
 {
@@ -1851,7 +1792,7 @@ static void       _cache_flush            (Class          cls)
 
     // Locate cache.  Ignore unused cache.
     cache = ((struct objc_class *)cls)->cache;
-    if (cache == &emptyCache)
+    if (cache == NULL  ||  cache == &emptyCache)
         return;
 
 #ifdef OBJC_INSTRUMENTED
@@ -1879,11 +1820,7 @@ static void      _cache_flush            (Class          cls)
 
         // Deallocate "forward::" entry
         if (oldEntry && oldEntry->method_imp == &_objc_msgForward)
-#ifdef OBJC_COLLECTING_CACHE
             _cache_collect_free (oldEntry, NO);
-#else
-        malloc_zone_free (_objc_create_zone(), oldEntry);
-#endif
     }
 
     // Clear the valid-entry counter
@@ -1916,6 +1853,267 @@ Class           _objc_getNonexistentClass          (void)
     return (Class) &nonexistentObjectClass;
 }
 
+
+/***********************************************************************
+* struct _objc_initializing_classes
+* Per-thread list of classes currently being initialized by that thread. 
+* During initialization, that thread is allowed to send messages to that 
+* class, but other threads have to wait.
+* The list is a simple array of metaclasses (the metaclass stores 
+* the initialization state). 
+**********************************************************************/
+typedef struct _objc_initializing_classes {
+    int classesAllocated;
+    struct objc_class** metaclasses;
+} _objc_initializing_classes;
+
+
+/***********************************************************************
+* _fetchInitializingClassList
+* Return the list of classes being initialized by this thread.
+* If create == YES, create the list when no classes are being initialized by this thread.
+* If create == NO, return NULL when no classes are being initialized by this thread.
+**********************************************************************/
+static _objc_initializing_classes *_fetchInitializingClassList(BOOL create)
+{
+    _objc_pthread_data *data;
+    _objc_initializing_classes *list;
+    struct objc_class **classes;
+
+    data = pthread_getspecific(_objc_pthread_key);
+    if (data == NULL) {
+        if (!create) {
+            return NULL;
+        } else {
+            data = calloc(1, sizeof(_objc_pthread_data));
+            pthread_setspecific(_objc_pthread_key, data);
+        }
+    }
+
+    list = data->initializingClasses;
+    if (list == NULL) {
+        if (!create) {
+            return NULL;
+        } else {
+            list = calloc(1, sizeof(_objc_initializing_classes));
+            data->initializingClasses = list;
+        }
+    }
+
+    classes = list->metaclasses;
+    if (classes == NULL) {
+        // If _objc_initializing_classes exists, allocate metaclass array, 
+        // even if create == NO.
+        // Allow 4 simultaneous class inits on this thread before realloc.
+        list->classesAllocated = 4;
+        classes = calloc(list->classesAllocated, sizeof(struct objc_class *));
+        list->metaclasses = classes;
+    }
+    return list;
+}
+
+
+/***********************************************************************
+* _destroyInitializingClassList
+* Deallocate memory used by the given initialization list. 
+* Any part of the list may be NULL.
+* Called from _objc_pthread_destroyspecific().
+**********************************************************************/
+void _destroyInitializingClassList(_objc_initializing_classes *list)
+{
+    if (list != NULL) {
+        if (list->metaclasses != NULL) {
+            free(list->metaclasses);
+        }
+        free(list);
+    }
+}
+
+
+/***********************************************************************
+* _thisThreadIsInitializingClass
+* Return TRUE if this thread is currently initializing the given class.
+**********************************************************************/
+static BOOL _thisThreadIsInitializingClass(struct objc_class *cls)
+{
+    int i;
+
+    _objc_initializing_classes *list = _fetchInitializingClassList(NO);
+    if (list) {
+        cls = GETMETA(cls);
+        for (i = 0; i < list->classesAllocated; i++) {
+            if (cls == list->metaclasses[i]) return YES;
+        }
+    }
+
+    // no list or not found in list
+    return NO;
+}
+
+
+/***********************************************************************
+* _setThisThreadIsInitializingClass
+* Record that this thread is currently initializing the given class. 
+* This thread will be allowed to send messages to the class, but 
+*   other threads will have to wait.
+**********************************************************************/
+static void _setThisThreadIsInitializingClass(struct objc_class *cls)
+{
+    int i;
+    _objc_initializing_classes *list = _fetchInitializingClassList(YES);
+    cls = GETMETA(cls);
+  
+    // paranoia: explicitly disallow duplicates
+    for (i = 0; i < list->classesAllocated; i++) {
+        if (cls == list->metaclasses[i]) {
+            _objc_fatal("thread is already initializing this class!");
+            return; // already the initializer
+        }
+    }
+  
+    for (i = 0; i < list->classesAllocated; i++) {
+        if (0   == list->metaclasses[i]) {
+            list->metaclasses[i] = cls;
+            return;
+        }
+    }
+
+    // class list is full - reallocate
+    list->classesAllocated = list->classesAllocated * 2 + 1;
+    list->metaclasses = realloc(list->metaclasses, list->classesAllocated * sizeof(struct objc_class *));
+    // zero out the new entries
+    list->metaclasses[i++] = cls;
+    for ( ; i < list->classesAllocated; i++) {
+        list->metaclasses[i] = NULL;
+    }
+}
+
+
+/***********************************************************************
+* _setThisThreadIsNotInitializingClass
+* Record that this thread is no longer initializing the given class. 
+**********************************************************************/
+static void _setThisThreadIsNotInitializingClass(struct objc_class *cls)
+{
+    int i;
+
+    _objc_initializing_classes *list = _fetchInitializingClassList(NO);
+    if (list) {
+        cls = GETMETA(cls);    
+        for (i = 0; i < list->classesAllocated; i++) {
+            if (cls == list->metaclasses[i]) {
+                list->metaclasses[i] = NULL;
+                return;
+            }
+        }
+    }
+
+    // no list or not found in list
+    _objc_fatal("thread is not initializing this class!");  
+}
+
+
+/***********************************************************************
+* class_initialize.  Send the '+initialize' message on demand to any
+* uninitialized class. Force initialization of superclasses first.
+*
+* Called only from _class_lookupMethodAndLoadCache (or itself).
+**********************************************************************/
+static void class_initialize(struct objc_class *cls)
+{
+    long *infoP = &GETMETA(cls)->info;
+    BOOL reallyInitialize = NO;
+
+    // Get the real class from the metaclass. The superclass chain 
+    // hangs off the real class only.
+    if (ISMETA(cls)) {
+        if (strncmp(cls->name, "_%", 2) == 0) {
+            // Posee's meta's name is smashed and isn't in the class_hash, 
+            // so objc_getClass doesn't work.
+            char *baseName = strchr(cls->name, '%'); // get posee's real name
+            cls = objc_getClass(baseName);
+        } else {
+            cls = objc_getClass(cls->name);
+        }
+    }
+
+    // Make sure super is done initializing BEFORE beginning to initialize cls.
+    // See note about deadlock above.
+    if (cls->super_class  &&  !ISINITIALIZED(cls->super_class)) {
+        class_initialize(cls->super_class);
+    }
+    
+    // Try to atomically set CLS_INITIALIZING.
+    pthread_mutex_lock(&classInitLock);
+    if (!ISINITIALIZED(cls) && !ISINITIALIZING(cls)) {
+        *infoP |= CLS_INITIALIZING;
+        reallyInitialize = YES;
+    }
+    pthread_mutex_unlock(&classInitLock);
+    
+    if (reallyInitialize) {
+        // We successfully set the CLS_INITIALIZING bit. Initialize the class.
+        
+        // Record that we're initializing this class so we can message it.
+        _setThisThreadIsInitializingClass(cls);
+        
+        // bind the module in - if it came from a bundle or dynamic library
+        _objc_bindClassIfNeeded(cls);
+        
+        // chain on the categories and bind them if necessary
+        _objc_resolve_categories_for_class(cls);
+        
+        // Send the +initialize message.
+        // Note that +initialize is sent to the superclass (again) if 
+        // this class doesn't implement +initialize. 2157218
+        [(id)cls initialize];
+        
+        // Done initializing. Update the info bits and notify waiting threads.
+        pthread_mutex_lock(&classInitLock);
+        *infoP = (*infoP | CLS_INITIALIZED) & ~CLS_INITIALIZING;
+        pthread_cond_broadcast(&classInitWaitCond);
+        pthread_mutex_unlock(&classInitLock);
+        _setThisThreadIsNotInitializingClass(cls);
+        return;
+    }
+    
+    else if (ISINITIALIZING(cls)) {
+        // We couldn't set INITIALIZING because INITIALIZING was already set.
+        // If this thread set it earlier, continue normally.
+        // If some other thread set it, block until initialize is done.
+        // It's ok if INITIALIZING changes to INITIALIZED while we're here, 
+        //   because we safely check for INITIALIZED inside the lock 
+        //   before blocking.
+        if (_thisThreadIsInitializingClass(cls)) {
+            return;
+        } else {
+            pthread_mutex_lock(&classInitLock);
+            while (!ISINITIALIZED(cls)) {
+                pthread_cond_wait(&classInitWaitCond, &classInitLock);
+            }
+            pthread_mutex_unlock(&classInitLock);
+            return;
+        }
+    }
+    
+    else if (ISINITIALIZED(cls)) {
+        // Set CLS_INITIALIZING failed because someone else already 
+        //   initialized the class. Continue normally.
+        // NOTE this check must come AFTER the ISINITIALIZING case.
+        // Otherwise: Another thread is initializing this class. ISINITIALIZED 
+        //   is false. Skip this clause. Then the other thread finishes 
+        //   initialization and sets INITIALIZING=no and INITIALIZED=yes. 
+        //   Skip the ISINITIALIZING clause. Die horribly.
+        return;
+    }
+    
+    else {
+        // We shouldn't be here. 
+        _objc_fatal("thread-safe class init in objc runtime is buggy!");
+    }
+}
+
+
 /***********************************************************************
 * _class_lookupMethodAndLoadCache.
 *
@@ -1925,9 +2123,8 @@ IMP       _class_lookupMethodAndLoadCache    (Class       cls,
                                         SEL            sel)
 {
     struct objc_class *        curClass;
-    Method     smt;
-    BOOL       calledSingleThreaded;
-    IMP                methodPC;
+    Method meth;
+    IMP methodPC = NULL;
 
     trace(0xb300, 0, 0, 0);
 
@@ -1939,119 +2136,80 @@ IMP    _class_lookupMethodAndLoadCache    (Class       cls,
     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);
-#endif
-
     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));
+    if (!ISINITIALIZED(cls)) {
+        class_initialize ((struct objc_class *)cls);
+        // If sel == initialize, class_initialize will send +initialize and 
+        // then the messenger will send +initialize again after this 
+        // procedure finishes. Of course, if this is not being called 
+        // from the messenger then it won't happen. 2778172
+    }
 
     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
 
         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)
-            {
+        // Beware of thread-unsafety and double-freeing of forward:: 
+        // entries here! See note in "Method cache locking" above.
+        // The upshot is that _cache_getMethod() will return NULL 
+        // instead of returning a forward:: entry.
+        meth = _cache_getMethod(curClass, sel);
+        if (meth) {
+            // Found the method in this class or a superclass.
+            // Cache the method in this class, unless we just found it in 
+            // this class's cache.
+            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);
+                    _cache_fill (curClass2, meth, sel);
+                _cache_fill (curClass, meth, sel);
 #else
-                _cache_fill (cls, buckets[idx], sel);
+                _cache_fill (cls, meth, sel);
 #endif
             }
 
-            // Return the implementation address
-            methodPC = CACHE_BUCKET_IMP(buckets[idx]);
+            methodPC = meth->method_imp;
             break;
         }
 
         trace(0xb304, (int)methodPC, 0, 0);
 
-        // Done if that found it
-        if (methodPC)
-            break;
-
-        smt = _findMethodInClass(curClass, sel);
+        // Cache scan failed. Search method list.
 
-        if (smt) {
+        meth = _findMethodInClass(curClass, sel);
+        if (meth) {
             // 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,
+                (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);
+                    _cache_fill (curClass2, meth, sel);
+                _cache_fill (curClass, meth, sel);
 #else
-                _cache_fill (cls, smt, sel);
+                _cache_fill (cls, meth, sel);
 #endif
             }
-            // Return the implementation
-            methodPC = smt->method_imp;
+
+            methodPC = meth->method_imp;
+            break;
         }
 
         trace(0xb305, (int)methodPC, 0, 0);
-
-        // Done if that found it
-        if (methodPC)
-            break;
     }
 
     trace(0xb306, (int)methodPC, 0, 0);
@@ -2059,25 +2217,16 @@ IMP     _class_lookupMethodAndLoadCache    (Class       cls,
     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);
+        _cache_addForwardEntry(cls, sel);
         methodPC = &_objc_msgForward;
     }
 
-#ifndef OBJC_COLLECTING_CACHE
-    // Unlock the lock
-    if (calledSingleThreaded)
-        OBJC_UNLOCK(&messageLock);
-#endif
-
     trace(0xb30f, (int)methodPC, 0, 0);
 
     return methodPC;
 }
 
+
 /***********************************************************************
 * SubtypeUntil.
 *
@@ -2170,6 +2319,9 @@ unsigned  method_getNumberOfArguments        (Method      method)
         // Traverse argument type
         typedesc = SkipFirstType (typedesc);
 
+        // Skip GNU runtime's register parameter hint
+        if (*typedesc == '+') typedesc++;
+
         // Traverse (possibly negative) argument offset
         if (*typedesc == '-')
             typedesc += 1;
@@ -2231,6 +2383,9 @@ unsigned  method_getSizeOfArguments       (Method         method)
     // skip the '@' marking the Id field
     typedesc = SkipFirstType (typedesc);
 
+    // Skip GNU runtime's register parameter hint
+    if (*typedesc == '+') typedesc++;
+
     // pick up the offset for the Id field
     foundBaseOffset = 0;
     while ((*typedesc >= '0') && (*typedesc <= '9'))
@@ -2303,6 +2458,9 @@ unsigned  method_getArgumentInfo         (Method          method,
 
         if (nargs == 0)
         {
+            // Skip GNU runtime's register parameter hint
+            if (*typedesc == '+') typedesc++;
+
             // Skip negative sign in offset
             if (*typedesc == '-')
             {
@@ -2321,6 +2479,9 @@ unsigned  method_getArgumentInfo         (Method          method,
 
         else
         {
+            // Skip GNU runtime's register parameter hint
+            if (*typedesc == '+') typedesc++;
+
             // Skip (possibly negative) argument offset
             if (*typedesc == '-')
                 typedesc += 1;
@@ -2349,6 +2510,9 @@ unsigned  method_getArgumentInfo         (Method          method,
 
         else
         {
+            // Skip GNU register parameter hint
+            if (*typedesc == '+') typedesc++;
+
             // Pick up (possibly negative) argument offset
             if (*typedesc == '-')
             {
@@ -2408,7 +2572,6 @@ void *            _objc_create_zone                  (void)
 /***********************************************************************
 * cache collection.
 **********************************************************************/
-#ifdef OBJC_COLLECTING_CACHE
 
 static unsigned long   _get_pc_for_thread     (mach_port_t     thread)
 #ifdef hppa
@@ -2454,6 +2617,10 @@ static unsigned long     _get_pc_for_thread     (mach_port_t     thread)
 
 /***********************************************************************
 * _collecting_in_critical.
+* Returns TRUE if some thread is currently executing a cache-reading 
+* function. Collection of cache garbage is not allowed when a cache-
+* reading function is in progress because it might still be using 
+* the garbage memory.
 **********************************************************************/
 OBJC_EXPORT unsigned long      objc_entryPoints[];
 OBJC_EXPORT unsigned long      objc_exitPoints[];
@@ -2465,22 +2632,23 @@ static int      _collecting_in_critical         (void)
     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");
+        _objc_inform ("task_thread failed (result %d)\n", ret);
         exit (1);
     }
 
     // Check whether any thread is in the cache lookup code
-    result = 0;
-    for (count = 0; !result && (count < number); count += 1)
+    result = FALSE;
+    for (count = 0; count < number; count++)
     {
-        int                            region;
-        unsigned long  pc;
+        int region;
+        unsigned long pc;
 
         // Don't bother checking ourselves
         if (threads[count] == mythread)
@@ -2490,13 +2658,18 @@ static int      _collecting_in_critical         (void)
         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)
+        for (region = 0; objc_entryPoints[region] != 0; region++)
         {
             if ((pc >= objc_entryPoints[region]) &&
-                (pc <= objc_exitPoints[region]))
-                result = 1;
+                (pc <= objc_exitPoints[region])) 
+            {
+                result = TRUE;
+                goto done;
+            }
         }
     }
+
+ done:
     // Deallocate the port rights for the threads
     for (count = 0; count < number; count++) {
         mach_port_deallocate(mach_task_self (), threads[count]);
@@ -2562,6 +2735,7 @@ static void       _garbage_make_room              (void)
 /***********************************************************************
 * _cache_collect_free.  Add the specified malloc'd memory to the list
 * of them to free at some later point.
+* Cache locks: cacheUpdateLock must be held by the caller.
 **********************************************************************/
 static void    _cache_collect_free    (void *          data,
                                     BOOL               tryCollect)
@@ -2573,9 +2747,6 @@ static void       _cache_collect_free    (void *          data,
         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 ();
@@ -2589,45 +2760,37 @@ static void     _cache_collect_free    (void *          data,
     // 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");
+            _objc_inform ("couldn't collect cache garbage: 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;
+    // tryCollect is guaranteed to be true after this point
+
+    // Synchronize garbage collection with objc_msgSend and other cache readers
+    if (!_collecting_in_critical ()) {
+        // No cache readers in progress - garbage is now deletable
+
+        // Log our progress
+        if (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;
+    }
+    else {     
+        // objc_msgSend (or other cache reader) is currently looking in the 
+        // cache and might still be using some garbage.
+        if (report_garbage) {
+            _objc_inform ("couldn't collect cache garbage: objc_msgSend in progress\n");
         }
-
-        // 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
 
 
 /***********************************************************************
@@ -2943,8 +3106,10 @@ void             _class_printMethodCacheStatistics               (void)
                     negativeEntryCount += 1;
 
                 // Calculate search distance (chain length) for this method
-                hash       = (uarith_t) CACHE_BUCKET_NAME(method);
-                methodChain = ((index - hash) & mask);
+                // The chain may wrap around to the beginning of the table.
+                hash = CACHE_HASH(CACHE_BUCKET_NAME(method), mask);
+                if (index >= hash) methodChain = index - hash;
+                else methodChain = (mask+1) + index - hash;
 
                 // Tally chains of this length
                 if (methodChain < MAX_CHAIN_SIZE)
index 9b0b334c49eb184e69794f4f4e0932c76d8ca5a5..82c89759d1b9ee6a57ddc8633fa679a4ff30f39c 100644 (file)
 // because objc-class.h is public and objc-config.h is not.
 //#define OBJC_INSTRUMENTED
 
-// OBJC_COLLECTING_CACHE controls whether the method dispatching caches
-// are lockless during dispatch.  This is a BIG speed win, but can be
-// implemented only when a thread can figure out the PCs of all the other
-// threads in the task.
-
-#if defined(hppa) || defined (__i386__) || defined (i386) || defined (m68k) || defined (__ppc__) || defined(ppc)
-    #if !defined(NeXT_PDO)
-        #define OBJC_COLLECTING_CACHE
-    #endif
-#endif
-
 // Turn on support for class refs
 #define OBJC_CLASS_REFS
 
     #define __S(x) x
 
-#if defined(NeXT_PDO)
-    #define GENERIC_OBJC_FILE
-#endif
-
 // Get the nice macros for subroutine calling, etc.
 // Not available on all architectures.  Not needed
 // (by us) on some configurations.
@@ -59,6 +44,6 @@
     #import <architecture/i386/asm_help.h>
 #elif defined (__ppc__) || defined(ppc)
     #import <architecture/ppc/asm_help.h>
-#elif (!defined(hppa) && !defined(sparc)) || !defined(NeXT_PDO)
+#else
     #error We need asm_help.h for this architecture
 #endif
index 3b5d34b2f56e19f752906c661f3173e9cecf118c..e45722acb778d87d1de97e76ee5488be6cd8b2d9 100644 (file)
@@ -55,7 +55,7 @@ void _objc_syslog(const char *format, ...)
     char bigBuffer[4*1024];
 
     va_start(ap, format);
-    vsprintf(bigBuffer, format, ap);
+    vsnprintf(bigBuffer, sizeof(bigBuffer), format, ap);
     va_end(ap);
 
 
@@ -91,7 +91,7 @@ volatile void _objc_error(id self, const char *fmt, va_list ap)
 { 
     char bigBuffer[4*1024];
 
-    vsprintf (bigBuffer, fmt, ap);
+    vsnprintf (bigBuffer, sizeof(bigBuffer), fmt, ap);
     _objc_syslog ("objc: %s: %s", object_getClassName (self), bigBuffer);
 
     abort();           /* generates a core file */
@@ -117,7 +117,7 @@ void _objc_inform(const char *fmt, ...)
     char bigBuffer[4*1024];
 
     va_start (ap,fmt); 
-    vsprintf (bigBuffer, fmt, ap);
+    vsnprintf (bigBuffer, sizeof(bigBuffer), fmt, ap);
     _objc_syslog ("objc: %s", bigBuffer);
     va_end (ap);
 }
index a178b19fdc987d05decd10fe2fb6d0e8464aa1fe..9e90500c64ac8b9c7fa4584d8906c703cc7e8ea8 100644 (file)
  *
  * had been: typedef void *objc_header;
  */
-#if defined(NeXT_PDO)
-    typedef void headerType;
-#else 
-    #import <mach-o/loader.h>
-    typedef struct mach_header headerType;
-#endif 
+#import <mach-o/loader.h>
+typedef struct mach_header headerType;
 
 #import <objc/Protocol.h>
 
@@ -80,17 +76,10 @@ typedef struct _NXConstantStringTemplate {
     unsigned int _length;
 } NXConstantStringTemplate;
    
-#if defined(NeXT_PDO)
-    #define OBJC_CONSTANT_STRING_PTR NXConstantStringTemplate**
-    #define OBJC_CONSTANT_STRING_DEREF
-    #define OBJC_PROTOCOL_PTR ProtocolTemplate**
-    #define OBJC_PROTOCOL_DEREF -> 
-#elif defined(__MACH__)
-    #define OBJC_CONSTANT_STRING_PTR NXConstantStringTemplate*
-    #define OBJC_CONSTANT_STRING_DEREF &
-    #define OBJC_PROTOCOL_PTR ProtocolTemplate*
-    #define OBJC_PROTOCOL_DEREF .
-#endif
+#define OBJC_CONSTANT_STRING_PTR NXConstantStringTemplate*
+#define OBJC_CONSTANT_STRING_DEREF &
+#define OBJC_PROTOCOL_PTR ProtocolTemplate*
+#define OBJC_PROTOCOL_DEREF .
 
 // both
 OBJC_EXPORT headerType **      _getObjcHeaders();
@@ -101,6 +90,7 @@ OBJC_EXPORT const char *     _getObjcHeaderName(headerType *head);
 
 // internal routines for delaying binding
 void _objc_resolve_categories_for_class        (struct objc_class * cls);
+void _objc_bindClassIfNeeded(struct objc_class *cls);
 void _objc_bindModuleContainingClass(struct objc_class * cls);
 
 // someday a logging facility
@@ -198,8 +188,10 @@ OBJC_EXPORT SEL *          _getObjcMessageRefs(headerType *head, int *nmess);
     OBJC_EXPORT void _objc_insertMethods( struct objc_method_list *mlist, struct objc_method_list ***list );
     OBJC_EXPORT void _objc_removeMethods( struct objc_method_list *mlist, struct objc_method_list ***list );
 
+    OBJC_EXPORT IMP _cache_getImp(Class cls, SEL sel);
+    OBJC_EXPORT Method _cache_getMethod(Class cls, SEL sel);
+
     /* message dispatcher */
-    OBJC_EXPORT Cache _cache_create(Class);
     OBJC_EXPORT IMP _class_lookupMethodAndLoadCache(Class, SEL);
     OBJC_EXPORT id _objc_msgForward (id self, SEL sel, ...);
 
@@ -219,9 +211,6 @@ OBJC_EXPORT SEL *           _getObjcMessageRefs(headerType *head, int *nmess);
     #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;
 
     // _objc_msgNil is actually (unsigned dummy, id, SEL) for i386;
     // currently not implemented for any sparc or hppa platforms
@@ -236,27 +225,9 @@ OBJC_EXPORT SEL *          _getObjcMessageRefs(headerType *head, int *nmess);
        return (s1 == s2);
     }
 
-        #if defined(OBJC_COLLECTING_CACHE)
-            #define OBJC_LOCK(MUTEX)   mutex_lock (MUTEX)
-            #define OBJC_UNLOCK(MUTEX) mutex_unlock (MUTEX)
-            #define OBJC_TRYLOCK(MUTEX)        mutex_try_lock (MUTEX)
-        #else // not OBJC_COLLECTING_CACHE
-            #define OBJC_LOCK(MUTEX)                   \
-              do                                       \
-                {                                      \
-                  if (!_objc_multithread_mask)         \
-               mutex_lock (MUTEX);                     \
-                }                                      \
-              while (0)
-
-            #define OBJC_UNLOCK(MUTEX)                 \
-              do                                       \
-                {                                      \
-                  if (!_objc_multithread_mask)         \
-               mutex_unlock (MUTEX);                   \
-                }                                      \
-              while (0)
-        #endif /* OBJC_COLLECTING_CACHE */
+    #define OBJC_LOCK(MUTEX)   mutex_lock (MUTEX)
+    #define OBJC_UNLOCK(MUTEX) mutex_unlock (MUTEX)
+    #define OBJC_TRYLOCK(MUTEX)        mutex_try_lock (MUTEX)
 
 #if !defined(SEG_OBJC)
 #define SEG_OBJC        "__OBJC"        /* objective-C runtime segment */
@@ -286,5 +257,25 @@ static __inline__ unsigned int _objc_strhash(const unsigned char *s) {
     return hash;
 }
 
+
+// objc per-thread storage
+OBJC_EXPORT pthread_key_t _objc_pthread_key;
+typedef struct {
+    struct _objc_initializing_classes *initializingClasses; // for +initialize
+
+    // If you add new fields here, don't forget to update 
+    // _objc_pthread_destroyspecific()
+
+} _objc_pthread_data;
+
+
+// Class state
+#define ISCLASS(cls)           ((((struct objc_class *) cls)->info & CLS_CLASS) != 0)
+#define ISMETA(cls)            ((((struct objc_class *) cls)->info & CLS_META) != 0)
+#define GETMETA(cls)           (ISMETA(cls) ? ((struct objc_class *) cls) : ((struct objc_class *) cls)->isa)
+#define ISINITIALIZED(cls)     ((((volatile long)GETMETA(cls)->info) & CLS_INITIALIZED) != 0)
+#define ISINITIALIZING(cls)    ((((volatile long)GETMETA(cls)->info) & CLS_INITIALIZING) != 0)
+
+
 #endif /* _OBJC_PRIVATE_H_ */
 
index 1b94c3bbd158559e3ac9070e536800dc6d109b35..18b677472c0ded21938fa76c5ede2e919381f1b4 100644 (file)
@@ -29,9 +29,7 @@
 #ifndef _OBJC_RUNTIME_H_
 #define _OBJC_RUNTIME_H_
 
-#ifndef NeXT_PDO
 #import <stdarg.h>
-#endif
 #import <objc/objc.h>
 #import <objc/objc-class.h>
 
@@ -42,10 +40,6 @@ struct objc_symtab {
        SEL             *refs;          
        unsigned short  cls_def_cnt;
        unsigned short  cat_def_cnt;
-#ifdef NeXT_PDO
-       arith_t        obj_defs;
-       arith_t        proto_defs;
-#endif
        void            *defs[1];       /* variable size */
 };
 
@@ -58,16 +52,10 @@ struct objc_module {
        Symtab          symtab; 
 };
 
-#ifdef __cplusplus
-extern "Objective-C" {
-#endif
 struct objc_super {
        id receiver;
        Class class;
 };
-#ifdef __cplusplus
-}
-#endif
 
 /* kernel operations */
 
index 86036ef5d1b764dca878e12b5b3c4f46d8de5c91..69f5f1c84a929ff9280fcf9811b7700abd707312 100644 (file)
@@ -87,10 +87,6 @@ typedef struct _PendingClass
 * Exports.
 **********************************************************************/
 
-// Mask which specifies whether we are multi-threaded or not.
-// 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.
 void           (*_objc_msgNil)(id, SEL) = NULL;
 
@@ -106,6 +102,9 @@ OBJC_DECLARE_LOCK (classLock);
 // Condition for logging load progress
 static int LaunchingDebug = -1;
 
+// objc's key for pthread_getspecific
+pthread_key_t _objc_pthread_key;
+
 /***********************************************************************
 * Function prototypes internal to this module.
 **********************************************************************/
@@ -128,7 +127,6 @@ 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);
 static void                            _objc_bindModuleContainingCategory(Category cat);
-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);
 static void                            _objc_checkForPendingClassReferences           (struct objc_class *     cls);
@@ -151,6 +149,9 @@ static NXHashTablePrototype classHashPrototype =
     NXNoEffectFree, 0
 };
 
+// Exported copy of class_hash variable (hook for debugging tools)
+NXHashTable *_objc_debug_class_hash = NULL;
+
 // Function pointer objc_getClass calls through when class is not found
 static int                     (*objc_classHandler) (const char *) = _objc_defaultClassHandler;
 
@@ -169,14 +170,14 @@ void      objc_dump_class_hash           (void)
 {
     NXHashTable *      table;
     unsigned           count;
-    struct objc_class *        *               data;
+    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);
+        printf ("class %d: %s\n", ++count, data->name);
 }
 
 /***********************************************************************
@@ -226,6 +227,7 @@ void        _objc_init_class_hash          (void)
                                             1024,
                                             nil,
                                             _objc_create_zone ());
+    _objc_debug_class_hash = class_hash;
 }
 
 /***********************************************************************
@@ -291,6 +293,7 @@ void        objc_setClassHandler    (int    (*userSuppliedHandler) (const char *))
 * 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.
+* Warning: doesn't work if aClassName is the name of a posed-for class's isa!
 **********************************************************************/
 id             objc_getClass          (const char *    aClassName)
 {
@@ -340,6 +343,7 @@ id          objc_lookUpClass       (const char *    aClassName)
 
 /***********************************************************************
 * objc_getMetaClass.  Return the id of the meta class the named class.
+* Warning: doesn't work if aClassName is the name of a posed-for class's isa!
 **********************************************************************/
 id             objc_getMetaClass       (const char *   aClassName)
 {
@@ -1073,7 +1077,7 @@ static void _objc_fixup_protocol_objects_for_image (header_info * hi)
     OBJC_PROTOCOL_PTR  protos;
     unsigned int       index;
 
-    // Locate protocals in the image
+    // Locate protocols in the image
     protos = (OBJC_PROTOCOL_PTR) _getObjcProtocols ((headerType *) hi->mhdr, &size);
     if (!protos)
         return;
@@ -1120,7 +1124,6 @@ void _objc_bindModuleContainingList() {
 ***********************************************************************/
 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;
@@ -1224,6 +1227,24 @@ void _objc_bindModuleContainingClass (struct objc_class * cls) {
 }
 
 
+/***********************************************************************
+* _objc_bindClassIfNeeded.
+* If the given class is still marked as needs-bind, bind the module 
+*   containing it.
+* Called during _objc_call_loads_for_image just before sending +load, 
+*   and during class_initialize just before sending +initialize.
+**********************************************************************/
+void _objc_bindClassIfNeeded(struct objc_class *cls)
+{
+    // Clear NEED_BIND *after* binding to prevent race
+    // This assumes that simultaneous binding of one module by two threads is ok.
+    if (cls->info & CLS_NEED_BIND) {
+        _objc_bindModuleContainingClass(cls);
+        cls->info &= ~CLS_NEED_BIND;
+    }
+}
+
+
 /***********************************************************************
 * _objc_addHeader.
 *
@@ -1273,7 +1294,7 @@ static header_info * _objc_addHeader(const headerType *header, unsigned long      vma
 *
 * If we have it we're in trouble
 **************************************************************************/
-void   _objc_fatalHeader(const headerType *header)
+static void    _objc_fatalHeader(const headerType *header)
 {
     header_info *hInfo;
     
@@ -1284,29 +1305,6 @@ void     _objc_fatalHeader(const headerType *header)
     }
 }
 
-/***********************************************************************
-* libraryNameForMachHeader.
-**********************************************************************/
-static const char *    libraryNameForMachHeader  (const headerType * themh)
-{
-    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.
@@ -1314,11 +1312,8 @@ static const char *      libraryNameForMachHeader  (const headerType * themh)
 **********************************************************************/
 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;
     SEL *              messages_refs;
 
     mods = (Module) ((unsigned long) hi->mod_ptr + hi->image_slide);
@@ -1370,10 +1365,7 @@ static void _objc_call_loads_for_image (header_info * header)
                 // +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);
-                    }
+                    _objc_bindClassIfNeeded(cls);
                     (*load_method) ((id) cls, @selector(load));
                 }
             }
@@ -1421,11 +1413,30 @@ static void objc_setConfiguration() {
 **********************************************************************/
 void objc_setMultithreaded (BOOL flag)
 {
-    if (flag == YES)
-        _objc_multithread_mask = 0;
-    else
-        _objc_multithread_mask = (-1);
+    // Nothing here. Thread synchronization in the runtime is always active.
 }
+
+
+
+/***********************************************************************
+* _objc_pthread_destroyspecific
+* Destructor for objc's per-thread data.
+* arg shouldn't be NULL, but we check anyway.
+**********************************************************************/
+extern void _destroyInitializingClassList(struct _objc_initializing_classes *list);
+void _objc_pthread_destroyspecific(void *arg)
+{
+    _objc_pthread_data *data = (_objc_pthread_data *)arg;
+    if (data != NULL) {
+        _destroyInitializingClassList(data->initializingClasses);
+
+        // add further cleanup here...
+
+        free(data);
+    }
+}
+
+
 /***********************************************************************
 * _objcInit.
 * Library initializer called by dyld & from crt0
@@ -1448,6 +1459,8 @@ void _objcInit(void) {
     // make sure CF is initialized before we go further;
     // someday this can be removed, as it'll probably be automatic
     __CFInitialize();
+    
+    pthread_key_create(&_objc_pthread_key, _objc_pthread_destroyspecific);
 
     // Create the class lookup table
     _objc_init_class_hash ();
@@ -1545,7 +1558,6 @@ static void       _objc_map_image(headerType *mh, unsigned long   vmaddr_slide)
 {
     static int dumpClasses = -1;
     header_info *hInfo;
-    unsigned int size;
 
     if ( dumpClasses == -1 ) {
         if ( getenv("OBJC_DUMP_CLASSES") ) dumpClasses = 1;
index 59c476ba486bac604daf087bd3b79a85024b88e0..c5db8c822eb7e2c8e63b6851a94f5bbe374b8ffe 100644 (file)
@@ -47,7 +47,7 @@ static SEL _objc_search_builtins(const char *key) {
 #if defined(DUMP_SELECTORS)
     if (NULL != key) printf("\t\"%s\",\n", key);
 #endif
-    /* The builtin table contains only sels starting with '[A-z]' */
+    /* The builtin table contains only sels starting with '[A-z]', including '_' */
     if (!key) return (SEL)0;
     if ('\0' == *key) return (SEL)_objc_empty_selector;
     if (*key < 'A' || 'z' < *key) return (SEL)0;
@@ -69,7 +69,7 @@ static CFMutableSetRef _objc_selectors = NULL;
 
 static Boolean _objc_equal_selector(const void *v1, const void *v2) {
     if (v1 == v2) return TRUE;
-    if ((!v1 && v2) || (v1 && !v2)) return FALSE;
+    if ((v1 == NULL) || (v2 == NULL)) return FALSE;
     return ((*(char *)v1 == *(char *)v2) && (0 == _objc_strcmp(v1, v2))) ? TRUE : FALSE;
 }