--- /dev/null
+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."
+# 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
+++ /dev/null
-
-ifeq "$(PLATFORM_OS)" "macos"
- BEFORE_INSTALL += profile
-endif
-
+++ /dev/null
-{
- 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";
-}
--- /dev/null
+# 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
+
+++ /dev/null
-#
-# 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
+++ /dev/null
-###############################################################################
-# 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:
-
+++ /dev/null
-###############################################################################
-# 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
-
+++ /dev/null
-#
-# 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
+++ /dev/null
-###############################################################################
-# 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.
-#
+++ /dev/null
-###############################################################################
-# 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
+++ /dev/null
-{
- 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";
-}
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.
.data
.globl _objc_entryPoints
_objc_entryPoints:
+ .long __cache_getImp
+ .long __cache_getMethod
.long _objc_msgSend
.long _objc_msgSend_stret
.long _objc_msgSendSuper
.globl _objc_exitPoints
_objc_exitPoints:
+ .long LGetImpExit
+ .long LGetMethodExit
.long LMsgSendExit
.long LMsgSendStretExit
.long LMsgSendSuperExit
.long LMsgSendSuperStretExit
.long 0
-#endif
/********************************************************************
/////////////////////////////////////////////////////////////////////
//
//
-// 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
//
/////////////////////////////////////////////////////////////////////
// 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
.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
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
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
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
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
.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
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)
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
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
// 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
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
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
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,...);
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
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)
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
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
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
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)
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
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
#endif
pushl %ecx
pushl (self_stret+16)(%esp)
- call _objc_msgSend_stret
+ call _objc_msgSend
movl %ebp,%esp
popl %ebp
ret
* 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
.data
.globl _objc_entryPoints
_objc_entryPoints:
+ .long __cache_getImp
+ .long __cache_getMethod
.long _objc_msgSend
.long _objc_msgSend_stret
.long _objc_msgSendSuper
.globl _objc_exitPoints
_objc_exitPoints:
+ .long LGetImpExit
+ .long LGetMethodExit
.long LMsgSendExit
.long LMsgSendStretExit
.long LMsgSendSuperExit
.long LMsgSendSuperFewExit
.long LMsgSendSuperFewStretExit
.long 0
-#endif
/********************************************************************
*
#if defined(__DYNAMIC__)
mflr r0
- bl 1f
+ bcl 20,31,1f ; 31 is cr7[so]
1: mflr $0
mtlr r0
.if $2 == EXTERNAL_SYMBOL
.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
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
-; 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.
;
; 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
; 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)
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
#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)
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
#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
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
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) ;
.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
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
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) ;
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
#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,
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;
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
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;
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
; 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
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
; 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
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
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;
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
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;
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
; 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
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
; 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
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
/* 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);
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>
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
*/
-#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_
+++ /dev/null
-#
-# 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
+++ /dev/null
-
-OTHER_PROJECT_HEADERS = $(PUBLIC_HEADERS) $(OTHER_PRIVATE_HEADERS)
-
-PUBLIC_HEADER_DIR_SUFFIX = /objc
-PRIVATE_HEADER_DIR_SUFFIX = /objc
-
-
+++ /dev/null
-{
- 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";
-}
+++ /dev/null
-{
- 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";
-}
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_
*/
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)
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_
*************************************************************************/
/* 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 {
Created by Bertrand Serlet, Feb 89
*/
-#if defined(NeXT_PDO)
-#import <pdo.h>
-#endif
-
#import <objc/hashtable2.h>
#import "objc-private.h"
#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
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
// 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
*/
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 *);
*/
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;
#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 */
#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;
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
//
* 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.
**********************************************************************/
// 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
/***********************************************************************
// 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.
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);
// 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;
// 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
*
* 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;
#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;
}
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.
// (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;
MaxIdealFlushCachesCount = subclassCount;
#endif
+ OBJC_UNLOCK(&cacheUpdateLock);
free(classes);
return;
}
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)
Class original)
{
struct objc_class * clsObject;
- char imposterName[256];
char * imposterNamePtr;
NXHashTable * class_hash;
NXHashState state;
// 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
__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.
_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.
*
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;
-
}
*
* 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);
}
/***********************************************************************
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;
/***********************************************************************
* _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)
{
// 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
}
}
// 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
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
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
}
}
}
((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;
}
// 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,
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)
}
}
- // 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
// 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
// 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)
{
// Locate cache. Ignore unused cache.
cache = ((struct objc_class *)cls)->cache;
- if (cache == &emptyCache)
+ if (cache == NULL || cache == &emptyCache)
return;
#ifdef OBJC_INSTRUMENTED
// 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
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.
*
SEL sel)
{
struct objc_class * curClass;
- Method smt;
- BOOL calledSingleThreaded;
- IMP methodPC;
+ Method meth;
+ IMP methodPC = NULL;
trace(0xb300, 0, 0, 0);
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);
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.
*
// 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;
// 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'))
if (nargs == 0)
{
+ // Skip GNU runtime's register parameter hint
+ if (*typedesc == '+') typedesc++;
+
// Skip negative sign in offset
if (*typedesc == '-')
{
else
{
+ // Skip GNU runtime's register parameter hint
+ if (*typedesc == '+') typedesc++;
+
// Skip (possibly negative) argument offset
if (*typedesc == '-')
typedesc += 1;
else
{
+ // Skip GNU register parameter hint
+ if (*typedesc == '+') typedesc++;
+
// Pick up (possibly negative) argument offset
if (*typedesc == '-')
{
/***********************************************************************
* cache collection.
**********************************************************************/
-#ifdef OBJC_COLLECTING_CACHE
static unsigned long _get_pc_for_thread (mach_port_t thread)
#ifdef hppa
/***********************************************************************
* _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[];
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)
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]);
/***********************************************************************
* _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)
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 ();
// 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
/***********************************************************************
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)
// 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.
#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
char bigBuffer[4*1024];
va_start(ap, format);
- vsprintf(bigBuffer, format, ap);
+ vsnprintf(bigBuffer, sizeof(bigBuffer), format, ap);
va_end(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 */
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);
}
*
* 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>
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();
// 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
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, ...);
#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
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 */
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_ */
#ifndef _OBJC_RUNTIME_H_
#define _OBJC_RUNTIME_H_
-#ifndef NeXT_PDO
#import <stdarg.h>
-#endif
#import <objc/objc.h>
#import <objc/objc-class.h>
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 */
};
Symtab symtab;
};
-#ifdef __cplusplus
-extern "Objective-C" {
-#endif
struct objc_super {
id receiver;
Class class;
};
-#ifdef __cplusplus
-}
-#endif
/* kernel operations */
* 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;
// 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.
**********************************************************************/
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);
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;
{
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);
}
/***********************************************************************
1024,
nil,
_objc_create_zone ());
+ _objc_debug_class_hash = class_hash;
}
/***********************************************************************
* 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)
{
/***********************************************************************
* 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)
{
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;
***********************************************************************/
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;
}
+/***********************************************************************
+* _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.
*
*
* If we have it we're in trouble
**************************************************************************/
-void _objc_fatalHeader(const headerType *header)
+static void _objc_fatalHeader(const headerType *header)
{
header_info *hInfo;
}
}
-/***********************************************************************
-* 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.
**********************************************************************/
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);
// +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));
}
}
**********************************************************************/
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
// 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 ();
{
static int dumpClasses = -1;
header_info *hInfo;
- unsigned int size;
if ( dumpClasses == -1 ) {
if ( getenv("OBJC_DUMP_CLASSES") ) dumpClasses = 1;
#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;
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;
}