objc4-706

This commit is contained in:
Lubos Dolezel 2017-01-18 22:41:15 +01:00
commit adfc003729
108 changed files with 57373 additions and 0 deletions

367
APPLE_LICENSE Normal file
View File

@ -0,0 +1,367 @@
APPLE PUBLIC SOURCE LICENSE
Version 2.0 - August 6, 2003
Please read this License carefully before downloading this software.
By downloading or 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") makes publicly available 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 2.0 ("License"). As used in
this License:
1.1 "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.2 "Contributor" means any person or entity that creates or
contributes to the creation of Modifications.
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 "Externally Deploy" means: (a) to sublicense, distribute or
otherwise make Covered Code available, directly or indirectly, to
anyone other than You; and/or (b) to use Covered Code, alone or as
part of a Larger Work, in any way to provide a service, including but
not limited to delivery of content, through electronic communication
with a client other than You.
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 the Original Code, any previous
Modifications, the combination of Original Code and any previous
Modifications, and/or any respective portions thereof. 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 Unmodified Code. You may use, reproduce, display, perform,
internally distribute within Your organization, and Externally Deploy
verbatim, unmodified copies of the Original Code, for commercial or
non-commercial purposes, provided that in each instance:
(a) You must 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; and
(b) You must include a copy of this License with every copy of Source
Code of Covered Code and documentation You distribute or Externally
Deploy, 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.
2.2 Modified Code. You may modify Covered Code and use, reproduce,
display, perform, internally distribute within Your organization, and
Externally Deploy Your Modifications and Covered Code, for commercial
or non-commercial purposes, provided that in each instance You also
meet all of these conditions:
(a) You must satisfy all the conditions of Section 2.1 with respect to
the Source Code of the Covered Code;
(b) You must duplicate, to the extent it does not already exist, the
notice in Exhibit A in each file of the Source Code of all Your
Modifications, and cause the modified files to carry prominent notices
stating that You changed the files and the date of any change; and
(c) If You Externally Deploy Your Modifications, You must make
Source Code of all Your Externally Deployed Modifications either
available to those to whom You have Externally Deployed Your
Modifications, or publicly available. Source Code of Your Externally
Deployed Modifications must be released under the terms set forth in
this License, including the license grants set forth in Section 3
below, for as long as you Externally Deploy the Covered Code or twelve
(12) months from the date of initial External Deployment, whichever is
longer. You should preferably distribute the Source Code of Your
Externally Deployed Modifications electronically (e.g. download from a
web site).
2.3 Distribution of Executable Versions. In addition, if You
Externally Deploy Covered Code (Original Code and/or Modifications) in
object code, executable form only, You must 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.
2.4 Third Party Rights. You expressly acknowledge and agree that
although Apple and each Contributor grants the licenses to their
respective portions of the Covered Code set forth herein, no
assurances are provided by Apple or any Contributor that the Covered
Code does not infringe the patent or other intellectual property
rights of any other entity. Apple and each Contributor disclaim any
liability to You for claims brought by any other entity based on
infringement of intellectual property rights or otherwise. As a
condition to exercising the rights and licenses granted hereunder, You
hereby assume sole responsibility to secure any other intellectual
property rights needed, if any. For example, if a third party patent
license is required to allow You to distribute the Covered Code, it is
Your responsibility to acquire that license before distributing the
Covered Code.
3. Your Grants. In consideration of, and as a condition to, the
licenses granted to You under this License, You hereby grant to any
person or entity receiving or distributing Covered Code under this
License a non-exclusive, royalty-free, perpetual, irrevocable license,
under Your Applicable Patent Rights and other intellectual property
rights (other than patent) owned or controlled by You, to use,
reproduce, display, perform, modify, sublicense, distribute and
Externally Deploy Your Modifications of the same scope and extent as
Apple's licenses under Sections 2.1 and 2.2 above.
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 or any Contributor. 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 and every Contributor harmless for any liability
incurred by or claims asserted against Apple or such Contributor 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 Covered Code may contain in whole or in
part pre-release, untested, or not fully tested works. The Covered
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 Covered Code, or any portion thereof, is at
Your sole and entire risk. THE COVERED CODE IS PROVIDED "AS IS" AND
WITHOUT WARRANTY, UPGRADES OR SUPPORT OF ANY KIND AND APPLE AND
APPLE'S LICENSOR(S) (COLLECTIVELY REFERRED TO AS "APPLE" FOR THE
PURPOSES OF SECTIONS 8 AND 9) AND ALL CONTRIBUTORS EXPRESSLY DISCLAIM
ALL WARRANTIES AND/OR CONDITIONS, EXPRESS OR IMPLIED, INCLUDING, BUT
NOT LIMITED TO, THE IMPLIED WARRANTIES AND/OR CONDITIONS OF
MERCHANTABILITY, OF SATISFACTORY QUALITY, OF FITNESS FOR A PARTICULAR
PURPOSE, OF ACCURACY, OF QUIET ENJOYMENT, AND NONINFRINGEMENT OF THIRD
PARTY RIGHTS. APPLE AND EACH CONTRIBUTOR DOES NOT WARRANT AGAINST
INTERFERENCE WITH YOUR ENJOYMENT OF THE COVERED CODE, THAT THE
FUNCTIONS CONTAINED IN THE COVERED CODE WILL MEET YOUR REQUIREMENTS,
THAT THE OPERATION OF THE COVERED CODE WILL BE UNINTERRUPTED OR
ERROR-FREE, OR THAT DEFECTS IN THE COVERED CODE WILL BE CORRECTED. NO
ORAL OR WRITTEN INFORMATION OR ADVICE GIVEN BY APPLE, AN APPLE
AUTHORIZED REPRESENTATIVE OR ANY CONTRIBUTOR SHALL CREATE A WARRANTY.
You acknowledge that the Covered 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 Covered Code could lead to death, personal injury, or severe
physical or environmental damage.
9. LIMITATION OF LIABILITY. TO THE EXTENT NOT PROHIBITED BY LAW, IN NO
EVENT SHALL APPLE OR ANY CONTRIBUTOR 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 COVERED CODE, OR
ANY PORTION THEREOF, WHETHER UNDER A THEORY OF CONTRACT, WARRANTY,
TORT (INCLUDING NEGLIGENCE), PRODUCTS LIABILITY OR OTHERWISE, EVEN IF
APPLE OR SUCH CONTRIBUTOR HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
DAMAGES AND NOTWITHSTANDING THE FAILURE OF ESSENTIAL PURPOSE OF ANY
REMEDY. SOME JURISDICTIONS DO NOT ALLOW THE LIMITATION OF LIABILITY OF
INCIDENTAL OR CONSEQUENTIAL DAMAGES, SO THIS LIMITATION MAY NOT APPLY
TO YOU. In no event shall Apple's total liability to You for all
damages (other than as may be required by applicable law) 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", "Mac OS",
"QuickTime", "QuickTime Streaming Server" or any other trademarks,
service marks, logos or trade names belonging to Apple (collectively
"Apple Marks") or to any trademark, service mark, logo or trade name
belonging to any Contributor. You agree not to use any Apple Marks in
or as part of the name of products derived from the Original Code or
to endorse or promote products derived from the Original Code other
than as expressly 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. Subject to the licenses granted under this License,
each Contributor retains all rights, title and interest in and to any
Modifications made by such Contributor. 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.
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; provided that Apple did not first commence
an action for patent infringement against You in that instance.
12.2 Effect of Termination. Upon termination, You agree to immediately
stop any further use, reproduction, modification, sublicensing and
distribution of the Covered Code. 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. No party will be liable to any 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
any 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 or among You, Apple or any Contributor, 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 or any Contributor 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-2003 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 2.0 (the 'License'). You may not use this file except in
compliance with the License. Please obtain a copy of the License at
http://www.opensource.apple.com/apsl/ 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, QUIET ENJOYMENT OR NON-INFRINGEMENT.
Please see the License for the specific language governing rights and
limitations under the License."

358
ReleaseNotes.rtf Normal file
View File

@ -0,0 +1,358 @@
{\rtf1\mac\ansicpg10000\cocoartf824\cocoasubrtf420
{\fonttbl\f0\fswiss\fcharset77 Helvetica-Bold;\f1\fswiss\fcharset77 Helvetica;\f2\fnil\fcharset77 Monaco;
}
{\colortbl;\red255\green255\blue255;\red70\green130\blue100;}
\vieww11200\viewh14360\viewkind0
\pard\tx720\tx1440\tx2160\tx2880\tx3600\tx4320\tx5040\tx5760\tx6480\tx7200\tx7920\tx8640\ql\qnatural\pardirnatural
\f0\b\fs30 \cf0 Objective-C Release Notes\
\pard\tx720\tx1440\tx2160\tx2880\tx3600\tx4320\tx5040\tx5760\tx6480\tx7200\tx7920\tx8640\ql\qnatural\pardirnatural
\f1\b0\fs24 \cf0 \
\
\pard\tx720\tx1440\tx2160\tx2880\tx3600\tx4320\tx5040\tx5760\tx6480\tx7200\tx7920\tx8640\ql\qnatural\pardirnatural
\f0\b\fs30 \cf0 Mac OS X 10.5 Leopard
\f1\b0\fs24 \
\
\pard\tx720\tx1440\tx2160\tx2880\tx3600\tx4320\tx5040\tx5760\tx6480\tx7200\tx7920\tx8640\ql\qnatural\pardirnatural
\f0\b \cf0 Contents
\f1\b0 \
\'a5 Garbage Collection\
\'a5\'caProperties\
\'a5\'caLoading and Unloading Bundles\
\'a5 Method and Class Attributes\
\'a5\'ca@package Instance Variables\
\'a5\'caRuntime API changes\
\'a5\'ca64-bit ABI\
\'a5\'ca64-bit Class and Instance Variable Access Control\
\'a5\'ca64-bit Non-Fragile Instance Variables\
\'a5\'ca64-bit Zero-Cost C++-Compatible Exceptions\
\
\
\f0\b Garbage Collection\
\pard\tx720\tx1440\tx2160\tx2880\tx3600\tx4320\tx5040\tx5760\tx6480\tx7200\tx7920\tx8640\ql\qnatural\pardirnatural
\f1\b0 \cf0 \
The Objective-C runtime examines on startup the execution image to determine whether to run with garbage collection or not. Each object file has an info section and they must all agree for execution to proceed. Standard compilation results in an info section that indicates that no GC capability is present. Compiling with -fobjc-gc indicates that both GC and retain/release logic is present. Compiling with -fobjc-gc-only indicates that only GC logic is present. A non-GC executable that attempts to load a gc-only framework will fail, as will a GC capable executable that attemps to load a GC incapable framework (or bundle).\
\
The collector initially runs only on the main thread when requested via objc_collect_if_needed(1), which is called automatically from the autoreleasepool -drain method. The AppKit arranges to call objc_start_collector_thread() after launch and subsequently collections run on a dedicated thread and are responsive to pure allocation demand. The objc_set_collection_threshold and objc_set_collection_ratio calls are used to establish the "need" for a collection. Once every ratio times a full (complete) collection will occur; otherwise a generational collection will be done if allocations have exceeded the threshold.\
\
The garbage collector minimally pauses those threads which have been registered to it while collecting. Registration occurs during establishment of an NSThread, not simply a pthread.\
\
A critical assumption that the collector makes is that one thread never gains access to an object (or more generally any block of garbage collected memory) by way of a pointer to another thread's stack memory. In other words, the collector does not make provision for cross thread stack references. This enables the collector to avoid pausing all threads at the same time while it examines recursively all of their references.\
\
The compiler uses three "helper" functions for assignments of strong pointers to garbage collected memory into global memory (
\f2\fs20 objc_assign_global
\f1\fs24 ), garbage collected heap memory (
\f2\fs20 objc_assign_ivar
\f1\fs24 ), or into unknown memory (
\f2\fs20 objc_assign_strongCast
\f1\fs24 ). For assignments of weak pointers it uses objc_assign_weak and for reads it uses objc_read_weak.\
\
When copying memory in bulk into a garbage collected block one must use the API
\f2\fs20 objc_memmove_collectable(void *dst, const void *src, size_t size)
\f1\fs24 .\
\
Garbage Collection Errors\
\
The collector itself is found in
\f2\fs20 /usr/lib/libauto.dylib
\f1\fs24 . Its error messages are printed using
\f2\fs20 malloc_printf
\f1\fs24 . The ObjC runtime is found in
\f2\fs20 /usr/lib/libobjc.dylib
\f1\fs24 . Its errors are printed using
\f2\fs20 _objc_inform
\f1\fs24 . Currently we note resurrection and reference count underflow errors by calling the following routines:\
\
\pard\tx960\pardeftab960\ql\qnatural\pardirnatural
\f2\fs20 \cf2 \CocoaLigature0 objc_assign_global_error\
\pard\tx960\pardeftab960\ql\qnatural\pardirnatural
\cf0 objc_assign_ivar_error\
\pard\tx960\pardeftab960\ql\qnatural\pardirnatural
\cf2 objc_exception_during_finalize_error\
auto_zone_resurrection_error\cf0 \
\cf2 auto_refcount_underflow_error
\f1\fs24 \cf0 \CocoaLigature1 \
\pard\tx720\tx1440\tx2160\tx2880\tx3600\tx4320\tx5040\tx5760\tx6480\tx7200\tx7920\tx8640\ql\qnatural\pardirnatural
\cf0 \
\
\pard\tx720\tx1440\tx2160\tx2880\tx3600\tx4320\tx5040\tx5760\tx6480\tx7200\tx7920\tx8640\ql\qnatural\pardirnatural
\f0\b \cf0 Properties
\f1\b0 \
\
The syntax for Objective-C properties has been overhauled since WWDC 2006. See the property documentation for details.\
\
In summary, @property(attributes) type name introduces an implicit declaration of a "getter" and a "setter" method (unless a read-only property is requested) for the "variable" named. The setter= and getter= attributes allow one to specify the names of the methods, otherwise a "name" method and a "setName:" method are implicitly declared. They may also be explicitly named.\
\
By default, properties are assigned when set. For objects under non-GC this is often incorrect and a warning is issued unless the assignment semantic is explicitly named. There are three choices - assign, for non-retained object references, copy, for objects that are copied and implicitly retained, and simply retain, for objects that require being retained when set.\
\
Access to properties is atomic by default. This is trivial under GC for almost everything and also trivial under non-GC for everything but objects and structures. In particular atomic access to retained objects under non-GC conditions can be expensive. As such, a nonatomic property attribute is available.\
\
Pointers may be held strongly under GC by declaring them __strong, and they can be zeroing weak by declaring them __weak.\
\
The implementations for properties can be provided by the compiler and runtime through the use of the @synthesize statement in the @implementation section of the class (or class extension). The compiler expects an instance variable of the same name as the property. If one wishes a different name it can be supplied to the @synthesize statement.\
\
In particular the compiler and runtime will implement accessors to retained objects by using atomic compare and swap instructions. It is extremely dangerous to directly access an atomic object property through its instance variable since another thread might change its value unpredictably. As such the compiler will warn you about such unprotected accesses. The runtime, in fact, will temporarily use the least significant bit of the instance variable as a temporary lock while retaining the new value and releasing the old. Direct use of an atomic instance variable under non-GC is strongly discouraged.\
\
\
\f0\b Loading and Unloading Bundles\
\pard\tx720\tx1440\tx2160\tx2880\tx3600\tx4320\tx5040\tx5760\tx6480\tx7200\tx7920\tx8640\ql\qnatural\pardirnatural
\f1\b0 \cf0 \
Since Mac OS X Version 10.4 it has been possible to unload bundles containing Objective-C. No attempt is made to prevent this if objects are still present for classes that are unloaded. Subclasses of classes loaded in bundles are particularly vulnerable.\
\
\
\pard\tx720\tx1440\tx2160\tx2880\tx3600\tx4320\tx5040\tx5760\tx6480\tx7200\tx7920\tx8640\ql\qnatural\pardirnatural
\f0\b \cf0 Method and Class Attributes\
\
\pard\tx720\tx1440\tx2160\tx2880\tx3600\tx4320\tx5040\tx5760\tx6480\tx7200\tx7920\tx8640\ql\qnatural\pardirnatural
\f1\b0 \cf0 Objective-C now supports some gcc attributes for Objective-C methods. Syntactically, attributes for a method follow the method's declaration, and attributes for a method parameter sit between the parameter type and the parameter name. Supported attributes include:\
\
Deprecation and availability, including AvailabilityMacros.h\
\pard\tx720\tx1440\tx2160\tx2880\tx3600\tx4320\tx5040\tx5760\tx6480\tx7200\tx7920\tx8640\ql\qnatural\pardirnatural
\f2\fs20 \cf0 - (void)method:(id)param __attribute__((deprecated));\
\pard\tx720\tx1440\tx2160\tx2880\tx3600\tx4320\tx5040\tx5760\tx6480\tx7200\tx7920\tx8640\ql\qnatural\pardirnatural
\f1\fs24 \cf0 \
Unused parameters\
\pard\tx720\tx1440\tx2160\tx2880\tx3600\tx4320\tx5040\tx5760\tx6480\tx7200\tx7920\tx8640\ql\qnatural\pardirnatural
\f2\fs20 \cf0 - (void)method:(id) __attribute__((unused)) param;\
\pard\tx720\tx1440\tx2160\tx2880\tx3600\tx4320\tx5040\tx5760\tx6480\tx7200\tx7920\tx8640\ql\qnatural\pardirnatural
\f1\fs24 \cf0 \
Sentinel parameters, including
\f2\fs20 NS_REQUIRES_NIL_TERMINATION
\f1\fs24 \
\pard\tx720\tx1440\tx2160\tx2880\tx3600\tx4320\tx5040\tx5760\tx6480\tx7200\tx7920\tx8640\ql\qnatural\pardirnatural
\f2\fs20 \cf0 - (void)methodWithObjects:(id)obj, ... NS_REQUIRES_NIL_TERMINATION;\
\pard\tx720\tx1440\tx2160\tx2880\tx3600\tx4320\tx5040\tx5760\tx6480\tx7200\tx7920\tx8640\ql\qnatural\pardirnatural
\f1\fs24 \cf0 \
Objective-C also supports some gcc attributes for Objective-C classes. Syntactically, attributes for a class precede the class's
\f2\fs20 @interface
\f1\fs24 declaration. Supported attributes include:\
\
Deprecation and availability, including AvailabilityMacros.h\
\pard\tx720\tx1440\tx2160\tx2880\tx3600\tx4320\tx5040\tx5760\tx6480\tx7200\tx7920\tx8640\ql\qnatural\pardirnatural
\f2\fs20 \cf0 __attribute__((deprecated))\
@interface MyDeprecatedClass : SomeSuperclass\
\pard\tx720\tx1440\tx2160\tx2880\tx3600\tx4320\tx5040\tx5760\tx6480\tx7200\tx7920\tx8640\ql\qnatural\pardirnatural
\f1\fs24 \cf0 \
Visibility\
\pard\tx720\tx1440\tx2160\tx2880\tx3600\tx4320\tx5040\tx5760\tx6480\tx7200\tx7920\tx8640\ql\qnatural\pardirnatural
\f2\fs20 \cf0 __attribute__((visibility("hidden")))\
@interface MyPrivateClass : SomeSuperclass
\f1\fs24 \
\
\
\pard\tx720\tx1440\tx2160\tx2880\tx3600\tx4320\tx5040\tx5760\tx6480\tx7200\tx7920\tx8640\ql\qnatural\pardirnatural
\f0\b \cf0 @package Instance Variables
\f1\b0 \
\
\pard\tx720\tx1440\tx2160\tx2880\tx3600\tx4320\tx5040\tx5760\tx6480\tx7200\tx7920\tx8640\ql\qnatural\pardirnatural
\f2\fs20 \cf0 @package
\f1\fs24 is a new ivar protection class, like
\f2\fs20 @public
\f1\fs24 and
\f2\fs20 @protected
\f1\fs24 .
\f2\fs20 @package
\f1\fs24 ivars behave as follows:\
\'a5\'ca
\f2\fs20 @public
\f1\fs24 in 32-bit; \
\'a5\'ca
\f2\fs20 @public
\f1\fs24 in 64-bit, inside the framework that defined the class; \
\'a5\'ca
\f2\fs20 @private
\f1\fs24 in 64-bit, outside the framework that defined the class.\
\
In 64-bit, the ivar symbol for an
\f2\fs20 @package
\f1\fs24 ivar is not exported, so any attempt to use the ivar from outside the framework that defined the class will fail with a link error. See "64-bit Class and Instance Variable Access Control" for more about ivar symbols.\
\
\
\pard\tx720\tx1440\tx2160\tx2880\tx3600\tx4320\tx5040\tx5760\tx6480\tx7200\tx7920\tx8640\ql\qnatural\pardirnatural
\f0\b \cf0 Runtime API changes\
\
\pard\tx720\tx1440\tx2160\tx2880\tx3600\tx4320\tx5040\tx5760\tx6480\tx7200\tx7920\tx8640\ql\qnatural\pardirnatural
\f1\b0 \cf0 The C interface to the Objective-C runtime (in
\f2\fs20 <objc/*.h>
\f1\fs24 ) has changed significantly. Highlights include:\
\'a5\'caAlmost all structures are deprecated, including
\f2\fs20 struct objc_class
\f1\fs24 . Functional replacements for most of these are provided.\
\'a5\'ca
\f2\fs20 class_poseAs
\f1\fs24 is deprecated. Use method list manipulation functions instead.\
\'a5\'ca
\f2\fs20 class_nextMethodList
\f1\fs24 is deprecated. Use
\f2\fs20 class_copyMethodList
\f1\fs24 instead.\
\'a5\'ca
\f2\fs20 class_addMethods
\f1\fs24 is deprecated. Use
\f2\fs20 class_addMethod
\f1\fs24 instead.\
\'a5\'ca
\f2\fs20 objc_addClass
\f1\fs24 is deprecated. Use
\f2\fs20 objc_allocateClassPair
\f1\fs24 and
\f2\fs20 objc_registerClassPair
\f1\fs24 instead.\
\'a5\'caIn general, all deprecated declarations are absent in 64-bit.\
\'a5\'caThe API in objc/objc-runtime.h and objc/objc-class.h is now in objc/runtime.h and objc/message.h. The old header files simply #include the new ones.\
\
\
\pard\tx720\tx1440\tx2160\tx2880\tx3600\tx4320\tx5040\tx5760\tx6480\tx7200\tx7920\tx8640\ql\qnatural\pardirnatural
\f0\b \cf0 64-bit ABI\
\
\pard\tx720\tx1440\tx2160\tx2880\tx3600\tx4320\tx5040\tx5760\tx6480\tx7200\tx7920\tx8640\ql\qnatural\pardirnatural
\f1\b0 \cf0 The 64-bit Objective-C ABI is generally unlike the 32-bit ABI. The new ABI provides new features, better performance, and improved future adaptability. All aspects of the 64-bit ABI are private and subject to future change. Forthcoming documentation will describe the ABI for the use of compilers and developer tools only.\
\
\
\pard\tx720\tx1440\tx2160\tx2880\tx3600\tx4320\tx5040\tx5760\tx6480\tx7200\tx7920\tx8640\ql\qnatural\pardirnatural
\f0\b \cf0 64-bit Class and Instance Variable Access Control\
\
\pard\tx720\tx1440\tx2160\tx2880\tx3600\tx4320\tx5040\tx5760\tx6480\tx7200\tx7920\tx8640\ql\qnatural\pardirnatural
\f1\b0 \cf0 In 64-bit Objective-C, access control for classes and each class and instance variable has a symbol associated with it. All uses of a class or instance variable reference this symbol. These symbols are subject to access control by the linker.\
\
The upshot is that access to private classes and ivars is more strictly enforced. Illegal use of a private ivar may fail with a link error. Frameworks that provide classes and ivars must correctly export their symbols. In particular, frameworks built with
\f2\fs20 -fvisibility=hidden
\f1\fs24 or a linker export list may need to be changed.\
\
Class symbols have names of the form
\f2\fs20 _OBJC_CLASS_$_ClassName
\f1\fs24 and
\f2\fs20 _OBJC_METACLASS_$_ClassName
\f1\fs24 . The class symbol is used by clients who send messages to the class (i.e.
\f2\fs20 [ClassName someMessage]
\f1\fs24 ). The metaclass symbol is used by clients who subclass the class.\
\
By default, class symbols are exported. They are affected by gcc's symbol visibility flags, so
\f2\fs20 -fvisibility=hidden
\f1\fs24 will make the class symbols non-exported. The linker recognizes the old symbol name
\f2\fs20 .objc_class_name_ClassName
\f1\fs24 in linker export lists and translates it to these symbols. \
\
Visibility of a single class can be changed using an attribute.\
\pard\tx720\tx1440\tx2160\tx2880\tx3600\tx4320\tx5040\tx5760\tx6480\tx7200\tx7920\tx8640\ql\qnatural\pardirnatural
\f2\fs20 \cf0 __attribute__((visibility("hidden")))\
@interface ClassName : SomeSuperclass\
\pard\tx720\tx1440\tx2160\tx2880\tx3600\tx4320\tx5040\tx5760\tx6480\tx7200\tx7920\tx8640\ql\qnatural\pardirnatural
\f1\fs24 \cf0 For classes with
\f2\fs20 "default"
\f1\fs24 visibility, the class symbols are exported, and the ivar symbols are handled as described below. For classes with
\f2\fs20 "hidden"
\f1\fs24 visibility, the class symbols and ivar symbols are all not exported.\
\
Ivar symbols have the form
\f2\fs20 _OBJC_IVAR_$_ClassName.IvarName
\f1\fs24 . The ivar symbol is used by clients who read or write the ivar.\
\
By default, ivar symbols for
\f2\fs20 @private
\f1\fs24 and
\f2\fs20 @package
\f1\fs24 ivars are not exported, and ivar symbols for
\f2\fs20 @public
\f1\fs24 and
\f2\fs20 @protected
\f1\fs24 ivars are exported. This can be changed by export lists,
\f2\fs20 -fvisibility
\f1\fs24 , or a visibility attribute on the class. Visibility attributes on individual ivars are currently not supported.\
\
\
\pard\tx720\tx1440\tx2160\tx2880\tx3600\tx4320\tx5040\tx5760\tx6480\tx7200\tx7920\tx8640\ql\qnatural\pardirnatural
\f0\b \cf0 64-bit Non-Fragile Instance Variables\
\
\pard\tx720\tx1440\tx2160\tx2880\tx3600\tx4320\tx5040\tx5760\tx6480\tx7200\tx7920\tx8640\ql\qnatural\pardirnatural
\f1\b0 \cf0 All instance variables in 64-bit Objective-C are non-fragile. That is, existing compiled code that uses a class's ivars will not break when the class or a superclass changes its own ivar layout. In particular, framework classes may add new ivars without breaking subclasses compiled against a previous version of the framework.\
\
Ivars may be added or reordered freely; existing users of a reordered ivar will adapt transparently. Other ivar changes are safe except that they will break any existing users of the ivar: deleting an ivar, renaming an ivar, moving an ivar to a different class, and changing the type of an ivar. \
\
Do not use
\f2\fs20 @defs
\f1\fs24 . The ivar layout it presents cannot adapt to superclass changes.\
\
Do not use
\f2\fs20 sizeof(SomeClass)
\f1\fs24 . Use
\f2\fs20 class_getInstanceSize([SomeClass class])
\f1\fs24 instead.\
\
Do not use
\f2\fs20 offsetof(SomeClass, SomeIvar)
\f1\fs24 . Use
\f2\fs20 ivar_getOffset(class_getInstanceVariable([SomeClass class], "SomeIvar"))
\f1\fs24 instead.\
\
\
\pard\tx720\tx1440\tx2160\tx2880\tx3600\tx4320\tx5040\tx5760\tx6480\tx7200\tx7920\tx8640\ql\qnatural\pardirnatural
\f0\b \cf0 64-bit Zero-Cost C++-Compatible Exceptions\
\
\pard\tx720\tx1440\tx2160\tx2880\tx3600\tx4320\tx5040\tx5760\tx6480\tx7200\tx7920\tx8640\ql\qnatural\pardirnatural
\f1\b0 \cf0 In 64-bit, the implementation of Objective-C exceptions has been rewritten. The new system provides "zero-cost" try blocks and interoperability with C++. \
\
"Zero-cost" try blocks incur no time penalty when entering an
\f2\fs20 @try
\f1\fs24 block, unlike 32-bit which must call
\f2\fs20 setjmp()
\f1\fs24 and other additional bookkeeping. On the other hand, actually throwing an exception is much more expensive. For best performance in 64-bit, exceptions should be thrown only in exceptional cases.\
\
The Cocoa frameworks require that all exceptions be instances of NSException or its subclasses. Do not throw objects of other types.\
\
The Cocoa frameworks are generally not exception-safe. Their general pattern is that exceptions are reserved for programmer error only, and the program should quit soon after catching such an exception. Be careful when throwing exceptions across the Cocoa frameworks.\
\
In 64-bit, C++ exceptions and Objective-C exceptions are interoperable. In particular, C++ destructors and Objective-C
\f2\fs20 @finally
\f1\fs24 blocks are honored when unwinding any exception, and default catch clauses -
\f2\fs20 catch (...)
\f1\fs24 and
\f2\fs20 @catch (...)
\f1\fs24 - are able to catch and re-throw any exception.\
\
Objective-C
\f2\fs20 @catch (id e)
\f1\fs24 catches any Objective-C exception, but no C++ exceptions. Use
\f2\fs20 @catch (...)
\f1\fs24 to catch everything, and
\f2\fs20 @throw;
\f1\fs24 to re-throw caught exceptions.
\f2\fs20 @catch (...)
\f1\fs24 is allowed in 32-bit, and has the same effect there as
\f2\fs20 @catch (id e)
\f1\fs24 . \
}

358
libobjc.order Normal file
View File

@ -0,0 +1,358 @@
__objc_init
_environ_init
_tls_init
_lock_init
_recursive_mutex_init
_exception_init
_map_images
_map_images_nolock
__getObjcImageInfo
__hasObjcContents
__objc_appendHeader
_verify_gc_readiness
_gc_init
__objc_inform_on_crash
__objc_crashlog
_rtp_init
_gc_fixup_barrier_stubs
__objc_update_stubs_in_mach_header
_sel_init
_sel_lock
___sel_registerName
__objc_search_builtins
__ZNK8objc_opt13objc_selopt_t3getEPKc
__ZNK8objc_opt13objc_selopt_t4hashEPKc
_sel_unlock
_sel_registerName
_arr_init
__ZN4objc8DenseMapIP11objc_objectmLb1ENS_12DenseMapInfoIS2_EENS3_ImEEE4initEj
__read_images
__Z11initVtablesv
__Z17appendTrampolinesP22objc_trampoline_header
_gdb_objc_trampolines_changed
_crashlog_header_name
__getObjc2ClassList
_NXCreateMapTableFromZone
_NXCreateHashTable
_NXCreateHashTableFromZone
_NXHashGet
_NXHashInsert
__NXHashRehashToCapacity
_NXNextHashState
_freeBuckets
_NXNoEffectFree
_hashPrototype
_NXPtrHash
_isEqualPrototype
__Z13futureClassesv
_NXCountMapTable
__Z13addNamedClassP7class_tPKc
_NXMapGet
__mapStrHash
_NXMapInsert
__mapPtrHash
__Z10remapClassP7class_t
__Z15remappedClassesa
_NXMapMember
__NXMapMember
__mapStrIsEqual
__mapPtrIsEqual
__getObjc2ClassRefs
__getObjc2SuperRefs
_sel_preoptimizationValid
__getObjc2SelectorRefs
_sel_registerNameNoLock
___objc_sel_set_create
___objc_sel_set_add
___objc_sel_set_findBuckets
___objc_sel_set_get
__Z9protocolsv
__getObjc2ProtocolList
_NXMapKeyCopyingInsert
__NXMapRehash
__getObjc2ProtocolRefs
__Z13remapProtocolm
__getObjc2NonlazyClassList
__Z12realizeClassP7class_t
__Z11addSubclassP7class_tS0_
__Z17attachMethodListsP7class_tPP13method_list_tiaPa
__Z15fixupMethodListP13method_list_ta
_memdup
__ZNSt3__113__stable_sortIRN8method_t16SortBySELAddressEN13method_list_t15method_iteratorEEEvT0_S6_T_NS_15iterator_traitsIS6_E1
__Z9addMethodP7class_tP13objc_selectorPFP11objc_objectS3_S1_zEPKca
__Z23getMethodNoSuper_nolockP7class_tP13objc_selector
__ZN7class_t14setHasCustomRREv
__Z20unattachedCategoriesv
_NXMapRemove
__Z21attachCategoryMethodsP7class_tP13category_listPa
_objc_addRegisteredClass
_layout_bitmap_create
_set_bits
_layout_bitmap_free
__ZNSt3__116__insertion_sortIRN8method_t16SortBySELAddressEN13method_list_t15method_iteratorEEEvT0_S6_T_
__Z17buildProtocolListP13category_listPK15protocol_list_tPS3_
__Z17buildPropertyListPK15property_list_tP13category_lista
__ZNSt3__120get_temporary_bufferI8method_tEENS_4pairIPT_lEEl
__ZNSt3__118__stable_sort_moveIRN8method_t16SortBySELAddressEN13method_list_t15method_iteratorEEEvT0_S6_T_NS_15iterator_traitsI
__ZNSt3__122__merge_move_constructIRN8method_t16SortBySELAddressEN13method_list_t15method_iteratorES5_EEvT0_S6_T1_S7_PNS_15iter
__ZNSt3__119__merge_move_assignIRN8method_t16SortBySELAddressEPS1_S4_N13method_list_t15method_iteratorEEEvT0_S7_T1_S8_T2_T_
_NXPtrIsEqual
__getObjc2CategoryList
__Z29addUnattachedCategoryForClassP10category_tP7class_tP12_header_info
__Z16remethodizeClassP7class_t
__Z11flushCachesP7class_t
_flush_cache
__class_getCache
_load_images
_load_images_nolock
_prepare_load_methods
__Z19schedule_class_loadP7class_t
_add_class_to_loadable_list
__class_getLoadMethod
__getObjc2NonlazyCategoryList
_call_load_methods
+[Protocol load]
_objc_lookUpClass
_look_up_class
_object_getClass
_protocol_copyMethodDescriptionList
_class_getClassMethod
__class_getMeta
_look_up_method
__cache_getMethod
__class_getMethod
_method_getTypeEncoding
_method_getImplementation
_method_getName
_class_addMethod
_class_getInstanceMethod
__Z12flushVtablesP7class_t
__Z12updateVtableP7class_ta
_class_replaceMethod
__Z25_method_setImplementationP7class_tP8method_tPFP11objc_objectS4_P13objc_selectorzE
_class_addProtocol
_class_conformsToProtocol
_objc_setExceptionPreprocessor
_objc_setExceptionMatcher
_objc_setUncaughtExceptionHandler
_objc_setForwardHandler
_objc_setEnumerationMutationHandler
_objc_collectingEnabled
_objc_getFutureClass
_objc_assign_strongCast_non_gc
_objc_getClass
__objc_insert_tagged_isa
_objc_msgSend_fixup
__objc_fixupMessageRef
_objc_msgSend
__class_lookupMethodAndLoadCache3
_lookUpMethod
_prepareForMethodLookup
__class_initialize
__class_getNonMetaClass
__Z15getNonMetaClassP7class_t
__class_getSuperclass
__class_isInitialized
__class_isInitializing
__class_setInitializing
__fetchInitializingClassList
__objc_fetch_pthread_data
_lockForMethodLookup
__cache_getImp
__class_getMethodNoSuper_nolock
_log_and_fill_cache
__cache_fill
_unlockForMethodLookup
_objc_assign_global_non_gc
_class_setSuperclass
_class_setVersion
_objc_msgSend_vtable1
__objc_rootAlloc
_class_getInstanceSize
__class_getInstanceSize
_class_createInstance
_object_getClassName
__class_getName
_object_getIndexedIvars
_objc_msgSend_vtable0
__objc_rootAllocWithZone
__objc_rootInit
_objc_msgSend_vtable3
_objc_assign_ivar_non_gc
__objc_rootRetain
__ZN4objc8DenseMapIP11objc_objectmLb1ENS_12DenseMapInfoIS2_EENS3_ImEEE16FindAndConstructERKS2_
__ZNK4objc8DenseMapIP11objc_objectmLb1ENS_12DenseMapInfoIS2_EENS3_ImEEE15LookupBucketForERKS2_RPNSt3__14pairIS2_mEE
__ZN4objc8DenseMapIP11objc_objectmLb1ENS_12DenseMapInfoIS2_EENS3_ImEEE16InsertIntoBucketERKS2_RKmPNSt3__14pairIS2_mEE
__objc_rootRelease
__objc_rootReleaseWasZero
__ZN4objc8DenseMapIP11objc_objectmLb1ENS_12DenseMapInfoIS2_EENS3_ImEEE4findERKS2_
__finishInitializing
__class_setInitialized
_NXFreeMapTable
_NXResetMapTable
__cache_malloc
__class_setCache
__class_setGrowCache
_objc_initializeClassPair
__Z33objc_initializeClassPair_internalP10objc_classPKcS0_S0_
_objc_registerClassPair
_add_category_to_loadable_list
__category_getLoadMethod
__category_getClass
__class_isLoadable
_objc_msgSendSuper2
__objc_autoreleasePoolPush
_objc_autoreleasePoolPush
__ZN12_GLOBAL__N_119AutoreleasePoolPageC1EPS0_
__ZN12_GLOBAL__N_119AutoreleasePoolPage9fastcheckEb
_objc_destructInstance
_objc_clear_deallocating
__ZN4objc8DenseMapIP11objc_objectmLb1ENS_12DenseMapInfoIS2_EENS3_ImEEE5eraseERKS2_
_objc_msgSend_vtable9
__class_shouldGrowCache
__cache_collect_free
__cache_collect
_class_getSuperclass
_objc_msgSend_vtable2
_objc_msgSend_vtable13
_objc_msgSend_vtable14
_objc_memmove_collectable
_class_respondsToSelector
__class_resolveMethod
__class_isMetaClass
__cache_addForwardEntry
__objc_rootDealloc
_object_dispose
_objc_msgSend_fixedup
_class_getName
_objc_atomicCompareAndSwapPtrBarrier
_objc_msgSend_vtable7
__objc_rootAutorelease
__Z22_objc_rootAutorelease2P11objc_object
_objc_msgSend_vtable12
_objc_msgSend_vtable11
_objc_msgSend_vtable8
_objc_msgSend_vtable15
__objc_autoreleasePoolPop
__ZN12_GLOBAL__N_119AutoreleasePoolPage3popEPv
_objc_msgSend_vtable4
_objc_msgSend_vtable10
_objc_retain
_objc_atomicCompareAndSwapInstanceVariableBarrier
_objc_msgSendSuper2_fixup
_objc_msgSendSuper2_fixedup
__collecting_in_critical
__cache_free_block
_class_getVersion
_objc_finalizeOnMainThread
_class_getImageName
__objc_rootZone
__Z35_protocol_conformsToProtocol_nolockP10protocol_tS0_
_objc_msgSend_vtable5
_objc_sync_enter
_id2data
_fetch_cache
_objc_sync_exit
_gc_enforcer
_cache_region_calloc
_class_getMethodImplementation
_objc_msgSend_stret
__ZN4objc8DenseMapIP11objc_objectmLb1ENS_12DenseMapInfoIS2_EENS3_ImEEE4growEj
__objc_rootHash
_objc_assign_weak_non_gc
_objc_read_weak_non_gc
_sel_getName
_method_getArgumentType
_encoding_getArgumentType
_encoding_getArgumentInfo
_SkipFirstType
_class_isMetaClass
_objc_allocateClassPair
__calloc_class
_class_getInstanceVariable
__class_getVariable
__Z7getIvarP7class_tPKc
_object_setClass
__class_instancesHaveAssociatedObjects
_method_getNumberOfArguments
_encoding_getNumberOfArguments
_method_copyReturnType
_encoding_copyReturnType
_method_copyArgumentType
_encoding_copyArgumentType
__objc_rootRetainCount
_objc_getAssociatedObject_non_gc
__object_get_associative_reference
__ZN19AssociationsManagerC2Ev
__ZN19AssociationsManager12associationsEv
__ZNK23objc_references_support15ObjcPointerHashclEPv
_objc_release
_objc_removeAssociatedObjects
_objc_setProperty_non_gc
_objc_getProperty_non_gc
_objc_autoreleaseReturnValue
_objc_setAssociatedObject_non_gc
__object_set_associative_reference
__ZN9__gnu_cxx8hash_mapIPvPN23objc_references_support20ObjectAssociationMapENS2_15ObjcPointerHashENS2_16ObjcPointerEqualENS2_13
__ZNSt3__13mapIPvN23objc_references_support15ObjcAssociationENS2_17ObjectPointerLessENS2_13ObjcAllocatorINS_4pairIKS1_S3_EEEEEi
__ZNSt3__13mapIPvN23objc_references_support15ObjcAssociationENS2_17ObjectPointerLessENS2_13ObjcAllocatorINS_4pairIKS1_S3_EEEEE1
__ZNSt3__127__tree_balance_after_insertIPNS_16__tree_node_baseIPvEEEEvT_S5_
__class_setInstancesHaveAssociatedObjects
_ivar_getTypeEncoding
_object_getIvar
_ivar_getOffset
__class_usesAutomaticRetainRelease
__objc_msgForward_internal
__objc_msgForward
_class_copyProtocolList
_protocol_getMethodDescription
__protocol_getMethod
__Z26_protocol_getMethod_nolockP10protocol_tP13objc_selectoraa
_method_getDescription
_ivar_getName
_objc_addExceptionHandler
_read_address
_read_sleb
_fetch_handler_list
_objc_removeExceptionHandler
_SubtypeUntil
_objc_collecting_enabled
_objc_msgSend_vtable6
_objc_is_finalized
_class_copyPropertyList
_property_getName
_property_getAttributes
_objc_msgSendSuper2_stret
_object_setInstanceVariable
_object_setIvar
_objc_assign_ivar
__ZN12_GLOBAL__N_119AutoreleasePoolPage15autoreleaseSlowEP11objc_object
_objc_atomicCompareAndSwapPtr
_objc_atomicCompareAndSwapGlobalBarrier
_sel_getUid
__ZN12_GLOBAL__N_119AutoreleasePoolPage11tls_deallocEPv
__ZN12_GLOBAL__N_119AutoreleasePoolPage4killEv
__objc_constructOrFree
_object_cxxConstruct
_object_cxxConstructFromClass
__class_hasCxxStructors
_lookupMethodInClassAndLoadCache
__class_getMethodNoSuper
_object_cxxDestruct
_object_cxxDestructFromClass
_class_copyIvarList
__objc_rootRetain_slow
__objc_rootReleaseWasZero_slow
_object_copy
__Z20_object_copyFromZoneP11objc_objectmPv
__objc_pthread_destroyspecific
__destroyInitializingClassList
__destroySyncCache
__destroyAltHandlerList
__object_remove_assocations
__ZNSt3__114__split_bufferIN23objc_references_support15ObjcAssociationERNS1_13ObjcAllocatorIS2_EEE9push_backERKS2_
__ZNSt3__16vectorIN23objc_references_support15ObjcAssociationENS1_13ObjcAllocatorIS2_EEE26__swap_out_circular_bufferERNS_14__sp
__ZNSt3__112__hash_tableINS_4pairIPvPN23objc_references_support20ObjectAssociationMapEEEN9__gnu_cxx17__hash_map_hasherIS6_NS3_1
__ZNSt3__114__split_bufferIN23objc_references_support15ObjcAssociationERNS1_13ObjcAllocatorIS2_EEE10push_frontERKS2_
__ZNSt3__16__treeINS_4pairIPvN23objc_references_support15ObjcAssociationEEENS_19__map_value_compareIS2_S4_NS3_17ObjectPointerLe
__ZNSt3__113__tree_removeIPNS_16__tree_node_baseIPvEEEEvT_S5_

562
markgc.cpp Normal file
View File

@ -0,0 +1,562 @@
/*
* Copyright (c) 2007-2009 Apple Inc. All Rights Reserved.
*
* @APPLE_LICENSE_HEADER_START@
*
* 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 2.0 (the 'License'). You may not use this file except in
* compliance with the License. Please obtain a copy of the License at
* http://www.opensource.apple.com/apsl/ 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, QUIET ENJOYMENT OR NON-INFRINGEMENT.
* Please see the License for the specific language governing rights and
* limitations under the License.
*
* @APPLE_LICENSE_HEADER_END@
*/
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <stdio.h>
#include <stdbool.h>
#include <fcntl.h>
#include <limits.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <sys/errno.h>
#include <mach-o/fat.h>
#include <mach-o/arch.h>
#include <mach-o/loader.h>
// Some OS X SDKs don't define these.
#ifndef CPU_TYPE_ARM
#define CPU_TYPE_ARM ((cpu_type_t) 12)
#endif
#ifndef CPU_ARCH_ABI64
#define CPU_ARCH_ABI64 0x01000000 /* 64 bit ABI */
#endif
#ifndef CPU_TYPE_ARM64
#define CPU_TYPE_ARM64 (CPU_TYPE_ARM | CPU_ARCH_ABI64)
#endif
// File abstraction taken from ld64/FileAbstraction.hpp
// and ld64/MachOFileAbstraction.hpp.
#ifdef __OPTIMIZE__
#define INLINE __attribute__((always_inline))
#else
#define INLINE
#endif
//
// This abstraction layer is for use with file formats that have 64-bit/32-bit and Big-Endian/Little-Endian variants
//
// For example: to make a utility that handles 32-bit little enidan files use: Pointer32<LittleEndian>
//
//
// get16() read a 16-bit number from an E endian struct
// set16() write a 16-bit number to an E endian struct
// get32() read a 32-bit number from an E endian struct
// set32() write a 32-bit number to an E endian struct
// get64() read a 64-bit number from an E endian struct
// set64() write a 64-bit number to an E endian struct
//
// getBits() read a bit field from an E endian struct (bitCount=number of bits in field, firstBit=bit index of field)
// setBits() write a bit field to an E endian struct (bitCount=number of bits in field, firstBit=bit index of field)
//
// getBitsRaw() read a bit field from a struct with native endianness
// setBitsRaw() write a bit field from a struct with native endianness
//
class BigEndian
{
public:
static uint16_t get16(const uint16_t& from) INLINE { return OSReadBigInt16(&from, 0); }
static void set16(uint16_t& into, uint16_t value) INLINE { OSWriteBigInt16(&into, 0, value); }
static uint32_t get32(const uint32_t& from) INLINE { return OSReadBigInt32(&from, 0); }
static void set32(uint32_t& into, uint32_t value) INLINE { OSWriteBigInt32(&into, 0, value); }
static uint64_t get64(const uint64_t& from) INLINE { return OSReadBigInt64(&from, 0); }
static void set64(uint64_t& into, uint64_t value) INLINE { OSWriteBigInt64(&into, 0, value); }
static uint32_t getBits(const uint32_t& from,
uint8_t firstBit, uint8_t bitCount) INLINE { return getBitsRaw(get32(from), firstBit, bitCount); }
static void setBits(uint32_t& into, uint32_t value,
uint8_t firstBit, uint8_t bitCount) INLINE { uint32_t temp = get32(into); setBitsRaw(temp, value, firstBit, bitCount); set32(into, temp); }
static uint32_t getBitsRaw(const uint32_t& from,
uint8_t firstBit, uint8_t bitCount) INLINE { return ((from >> (32-firstBit-bitCount)) & ((1<<bitCount)-1)); }
static void setBitsRaw(uint32_t& into, uint32_t value,
uint8_t firstBit, uint8_t bitCount) INLINE { uint32_t temp = into;
const uint32_t mask = ((1<<bitCount)-1);
temp &= ~(mask << (32-firstBit-bitCount));
temp |= ((value & mask) << (32-firstBit-bitCount));
into = temp; }
enum { little_endian = 0 };
};
class LittleEndian
{
public:
static uint16_t get16(const uint16_t& from) INLINE { return OSReadLittleInt16(&from, 0); }
static void set16(uint16_t& into, uint16_t value) INLINE { OSWriteLittleInt16(&into, 0, value); }
static uint32_t get32(const uint32_t& from) INLINE { return OSReadLittleInt32(&from, 0); }
static void set32(uint32_t& into, uint32_t value) INLINE { OSWriteLittleInt32(&into, 0, value); }
static uint64_t get64(const uint64_t& from) INLINE { return OSReadLittleInt64(&from, 0); }
static void set64(uint64_t& into, uint64_t value) INLINE { OSWriteLittleInt64(&into, 0, value); }
static uint32_t getBits(const uint32_t& from,
uint8_t firstBit, uint8_t bitCount) INLINE { return getBitsRaw(get32(from), firstBit, bitCount); }
static void setBits(uint32_t& into, uint32_t value,
uint8_t firstBit, uint8_t bitCount) INLINE { uint32_t temp = get32(into); setBitsRaw(temp, value, firstBit, bitCount); set32(into, temp); }
static uint32_t getBitsRaw(const uint32_t& from,
uint8_t firstBit, uint8_t bitCount) INLINE { return ((from >> firstBit) & ((1<<bitCount)-1)); }
static void setBitsRaw(uint32_t& into, uint32_t value,
uint8_t firstBit, uint8_t bitCount) INLINE { uint32_t temp = into;
const uint32_t mask = ((1<<bitCount)-1);
temp &= ~(mask << firstBit);
temp |= ((value & mask) << firstBit);
into = temp; }
enum { little_endian = 1 };
};
#if __BIG_ENDIAN__
typedef BigEndian CurrentEndian;
typedef LittleEndian OtherEndian;
#elif __LITTLE_ENDIAN__
typedef LittleEndian CurrentEndian;
typedef BigEndian OtherEndian;
#else
#error unknown endianness
#endif
template <typename _E>
class Pointer32
{
public:
typedef uint32_t uint_t;
typedef int32_t sint_t;
typedef _E E;
static uint64_t getP(const uint_t& from) INLINE { return _E::get32(from); }
static void setP(uint_t& into, uint64_t value) INLINE { _E::set32(into, value); }
};
template <typename _E>
class Pointer64
{
public:
typedef uint64_t uint_t;
typedef int64_t sint_t;
typedef _E E;
static uint64_t getP(const uint_t& from) INLINE { return _E::get64(from); }
static void setP(uint_t& into, uint64_t value) INLINE { _E::set64(into, value); }
};
//
// mach-o file header
//
template <typename P> struct macho_header_content {};
template <> struct macho_header_content<Pointer32<BigEndian> > { mach_header fields; };
template <> struct macho_header_content<Pointer64<BigEndian> > { mach_header_64 fields; };
template <> struct macho_header_content<Pointer32<LittleEndian> > { mach_header fields; };
template <> struct macho_header_content<Pointer64<LittleEndian> > { mach_header_64 fields; };
template <typename P>
class macho_header {
public:
uint32_t magic() const INLINE { return E::get32(header.fields.magic); }
void set_magic(uint32_t value) INLINE { E::set32(header.fields.magic, value); }
uint32_t cputype() const INLINE { return E::get32(header.fields.cputype); }
void set_cputype(uint32_t value) INLINE { E::set32((uint32_t&)header.fields.cputype, value); }
uint32_t cpusubtype() const INLINE { return E::get32(header.fields.cpusubtype); }
void set_cpusubtype(uint32_t value) INLINE { E::set32((uint32_t&)header.fields.cpusubtype, value); }
uint32_t filetype() const INLINE { return E::get32(header.fields.filetype); }
void set_filetype(uint32_t value) INLINE { E::set32(header.fields.filetype, value); }
uint32_t ncmds() const INLINE { return E::get32(header.fields.ncmds); }
void set_ncmds(uint32_t value) INLINE { E::set32(header.fields.ncmds, value); }
uint32_t sizeofcmds() const INLINE { return E::get32(header.fields.sizeofcmds); }
void set_sizeofcmds(uint32_t value) INLINE { E::set32(header.fields.sizeofcmds, value); }
uint32_t flags() const INLINE { return E::get32(header.fields.flags); }
void set_flags(uint32_t value) INLINE { E::set32(header.fields.flags, value); }
uint32_t reserved() const INLINE { return E::get32(header.fields.reserved); }
void set_reserved(uint32_t value) INLINE { E::set32(header.fields.reserved, value); }
typedef typename P::E E;
private:
macho_header_content<P> header;
};
//
// mach-o load command
//
template <typename P>
class macho_load_command {
public:
uint32_t cmd() const INLINE { return E::get32(command.cmd); }
void set_cmd(uint32_t value) INLINE { E::set32(command.cmd, value); }
uint32_t cmdsize() const INLINE { return E::get32(command.cmdsize); }
void set_cmdsize(uint32_t value) INLINE { E::set32(command.cmdsize, value); }
typedef typename P::E E;
private:
load_command command;
};
//
// mach-o segment load command
//
template <typename P> struct macho_segment_content {};
template <> struct macho_segment_content<Pointer32<BigEndian> > { segment_command fields; enum { CMD = LC_SEGMENT }; };
template <> struct macho_segment_content<Pointer64<BigEndian> > { segment_command_64 fields; enum { CMD = LC_SEGMENT_64 }; };
template <> struct macho_segment_content<Pointer32<LittleEndian> > { segment_command fields; enum { CMD = LC_SEGMENT }; };
template <> struct macho_segment_content<Pointer64<LittleEndian> > { segment_command_64 fields; enum { CMD = LC_SEGMENT_64 }; };
template <typename P>
class macho_segment_command {
public:
uint32_t cmd() const INLINE { return E::get32(segment.fields.cmd); }
void set_cmd(uint32_t value) INLINE { E::set32(segment.fields.cmd, value); }
uint32_t cmdsize() const INLINE { return E::get32(segment.fields.cmdsize); }
void set_cmdsize(uint32_t value) INLINE { E::set32(segment.fields.cmdsize, value); }
const char* segname() const INLINE { return segment.fields.segname; }
void set_segname(const char* value) INLINE { strncpy(segment.fields.segname, value, 16); }
uint64_t vmaddr() const INLINE { return P::getP(segment.fields.vmaddr); }
void set_vmaddr(uint64_t value) INLINE { P::setP(segment.fields.vmaddr, value); }
uint64_t vmsize() const INLINE { return P::getP(segment.fields.vmsize); }
void set_vmsize(uint64_t value) INLINE { P::setP(segment.fields.vmsize, value); }
uint64_t fileoff() const INLINE { return P::getP(segment.fields.fileoff); }
void set_fileoff(uint64_t value) INLINE { P::setP(segment.fields.fileoff, value); }
uint64_t filesize() const INLINE { return P::getP(segment.fields.filesize); }
void set_filesize(uint64_t value) INLINE { P::setP(segment.fields.filesize, value); }
uint32_t maxprot() const INLINE { return E::get32(segment.fields.maxprot); }
void set_maxprot(uint32_t value) INLINE { E::set32((uint32_t&)segment.fields.maxprot, value); }
uint32_t initprot() const INLINE { return E::get32(segment.fields.initprot); }
void set_initprot(uint32_t value) INLINE { E::set32((uint32_t&)segment.fields.initprot, value); }
uint32_t nsects() const INLINE { return E::get32(segment.fields.nsects); }
void set_nsects(uint32_t value) INLINE { E::set32(segment.fields.nsects, value); }
uint32_t flags() const INLINE { return E::get32(segment.fields.flags); }
void set_flags(uint32_t value) INLINE { E::set32(segment.fields.flags, value); }
enum {
CMD = macho_segment_content<P>::CMD
};
typedef typename P::E E;
private:
macho_segment_content<P> segment;
};
//
// mach-o section
//
template <typename P> struct macho_section_content {};
template <> struct macho_section_content<Pointer32<BigEndian> > { section fields; };
template <> struct macho_section_content<Pointer64<BigEndian> > { section_64 fields; };
template <> struct macho_section_content<Pointer32<LittleEndian> > { section fields; };
template <> struct macho_section_content<Pointer64<LittleEndian> > { section_64 fields; };
template <typename P>
class macho_section {
public:
const char* sectname() const INLINE { return section.fields.sectname; }
void set_sectname(const char* value) INLINE { strncpy(section.fields.sectname, value, 16); }
const char* segname() const INLINE { return section.fields.segname; }
void set_segname(const char* value) INLINE { strncpy(section.fields.segname, value, 16); }
uint64_t addr() const INLINE { return P::getP(section.fields.addr); }
void set_addr(uint64_t value) INLINE { P::setP(section.fields.addr, value); }
uint64_t size() const INLINE { return P::getP(section.fields.size); }
void set_size(uint64_t value) INLINE { P::setP(section.fields.size, value); }
uint32_t offset() const INLINE { return E::get32(section.fields.offset); }
void set_offset(uint32_t value) INLINE { E::set32(section.fields.offset, value); }
uint32_t align() const INLINE { return E::get32(section.fields.align); }
void set_align(uint32_t value) INLINE { E::set32(section.fields.align, value); }
uint32_t reloff() const INLINE { return E::get32(section.fields.reloff); }
void set_reloff(uint32_t value) INLINE { E::set32(section.fields.reloff, value); }
uint32_t nreloc() const INLINE { return E::get32(section.fields.nreloc); }
void set_nreloc(uint32_t value) INLINE { E::set32(section.fields.nreloc, value); }
uint32_t flags() const INLINE { return E::get32(section.fields.flags); }
void set_flags(uint32_t value) INLINE { E::set32(section.fields.flags, value); }
uint32_t reserved1() const INLINE { return E::get32(section.fields.reserved1); }
void set_reserved1(uint32_t value) INLINE { E::set32(section.fields.reserved1, value); }
uint32_t reserved2() const INLINE { return E::get32(section.fields.reserved2); }
void set_reserved2(uint32_t value) INLINE { E::set32(section.fields.reserved2, value); }
typedef typename P::E E;
private:
macho_section_content<P> section;
};
static bool debug = true;
bool processFile(const char *filename);
int main(int argc, const char *argv[]) {
for (int i = 1; i < argc; ++i) {
if (!processFile(argv[i])) return 1;
}
return 0;
}
struct imageinfo {
uint32_t version;
uint32_t flags;
};
// Segment and section names are 16 bytes and may be un-terminated.
bool segnameEquals(const char *lhs, const char *rhs)
{
return 0 == strncmp(lhs, rhs, 16);
}
bool segnameStartsWith(const char *segname, const char *prefix)
{
return 0 == strncmp(segname, prefix, strlen(prefix));
}
bool sectnameEquals(const char *lhs, const char *rhs)
{
return segnameEquals(lhs, rhs);
}
template <typename P>
void dosect(uint8_t *start, macho_section<P> *sect)
{
if (debug) printf("section %.16s from segment %.16s\n",
sect->sectname(), sect->segname());
// Strip S_MOD_INIT/TERM_FUNC_POINTERS. We don't want dyld to call
// our init funcs because it is too late, and we don't want anyone to
// call our term funcs ever.
if (segnameStartsWith(sect->segname(), "__DATA") &&
sectnameEquals(sect->sectname(), "__mod_init_func"))
{
// section type 0 is S_REGULAR
sect->set_flags(sect->flags() & ~SECTION_TYPE);
sect->set_sectname("__objc_init_func");
if (debug) printf("disabled __mod_init_func section\n");
}
if (segnameStartsWith(sect->segname(), "__DATA") &&
sectnameEquals(sect->sectname(), "__mod_term_func"))
{
// section type 0 is S_REGULAR
sect->set_flags(sect->flags() & ~SECTION_TYPE);
sect->set_sectname("__objc_term_func");
if (debug) printf("disabled __mod_term_func section\n");
}
}
template <typename P>
void doseg(uint8_t *start, macho_segment_command<P> *seg)
{
if (debug) printf("segment name: %.16s, nsects %u\n",
seg->segname(), seg->nsects());
macho_section<P> *sect = (macho_section<P> *)(seg + 1);
for (uint32_t i = 0; i < seg->nsects(); ++i) {
dosect(start, &sect[i]);
}
}
template<typename P>
bool parse_macho(uint8_t *buffer)
{
macho_header<P>* mh = (macho_header<P>*)buffer;
uint8_t *cmds = (uint8_t *)(mh + 1);
for (uint32_t c = 0; c < mh->ncmds(); c++) {
macho_load_command<P>* cmd = (macho_load_command<P>*)cmds;
cmds += cmd->cmdsize();
if (cmd->cmd() == LC_SEGMENT || cmd->cmd() == LC_SEGMENT_64) {
doseg(buffer, (macho_segment_command<P>*)cmd);
}
}
return true;
}
bool parse_macho(uint8_t *buffer)
{
uint32_t magic = *(uint32_t *)buffer;
switch (magic) {
case MH_MAGIC_64:
return parse_macho<Pointer64<CurrentEndian>>(buffer);
case MH_MAGIC:
return parse_macho<Pointer32<CurrentEndian>>(buffer);
case MH_CIGAM_64:
return parse_macho<Pointer64<OtherEndian>>(buffer);
case MH_CIGAM:
return parse_macho<Pointer32<OtherEndian>>(buffer);
default:
printf("file is not mach-o (magic %x)\n", magic);
return false;
}
}
bool parse_fat(uint8_t *buffer, size_t size)
{
uint32_t magic;
if (size < sizeof(magic)) {
printf("file is too small\n");
return false;
}
magic = *(uint32_t *)buffer;
if (magic != FAT_MAGIC && magic != FAT_CIGAM) {
/* Not a fat file */
return parse_macho(buffer);
} else {
struct fat_header *fh;
uint32_t fat_magic, fat_nfat_arch;
struct fat_arch *archs;
if (size < sizeof(struct fat_header)) {
printf("file is too small\n");
return false;
}
fh = (struct fat_header *)buffer;
fat_magic = OSSwapBigToHostInt32(fh->magic);
fat_nfat_arch = OSSwapBigToHostInt32(fh->nfat_arch);
if (size < (sizeof(struct fat_header) + fat_nfat_arch * sizeof(struct fat_arch))) {
printf("file is too small\n");
return false;
}
archs = (struct fat_arch *)(buffer + sizeof(struct fat_header));
/* Special case hidden CPU_TYPE_ARM64 */
if (size >= (sizeof(struct fat_header) + (fat_nfat_arch + 1) * sizeof(struct fat_arch))) {
if (fat_nfat_arch > 0
&& OSSwapBigToHostInt32(archs[fat_nfat_arch].cputype) == CPU_TYPE_ARM64) {
fat_nfat_arch++;
}
}
/* End special case hidden CPU_TYPE_ARM64 */
if (debug) printf("%d fat architectures\n",
fat_nfat_arch);
for (uint32_t i = 0; i < fat_nfat_arch; i++) {
uint32_t arch_cputype = OSSwapBigToHostInt32(archs[i].cputype);
uint32_t arch_cpusubtype = OSSwapBigToHostInt32(archs[i].cpusubtype);
uint32_t arch_offset = OSSwapBigToHostInt32(archs[i].offset);
uint32_t arch_size = OSSwapBigToHostInt32(archs[i].size);
if (debug) printf("cputype %d cpusubtype %d\n",
arch_cputype, arch_cpusubtype);
/* Check that slice data is after all fat headers and archs */
if (arch_offset < (sizeof(struct fat_header) + fat_nfat_arch * sizeof(struct fat_arch))) {
printf("file is badly formed\n");
return false;
}
/* Check that the slice ends before the file does */
if (arch_offset > size) {
printf("file is badly formed\n");
return false;
}
if (arch_size > size) {
printf("file is badly formed\n");
return false;
}
if (arch_offset > (size - arch_size)) {
printf("file is badly formed\n");
return false;
}
bool ok = parse_macho(buffer + arch_offset);
if (!ok) return false;
}
return true;
}
}
bool processFile(const char *filename)
{
if (debug) printf("file %s\n", filename);
int fd = open(filename, O_RDWR);
if (fd < 0) {
printf("open %s: %s\n", filename, strerror(errno));
return false;
}
struct stat st;
if (fstat(fd, &st) < 0) {
printf("fstat %s: %s\n", filename, strerror(errno));
return false;
}
void *buffer = mmap(NULL, (size_t)st.st_size, PROT_READ|PROT_WRITE,
MAP_FILE|MAP_SHARED, fd, 0);
if (buffer == MAP_FAILED) {
printf("mmap %s: %s\n", filename, strerror(errno));
return false;
}
bool result = parse_fat((uint8_t *)buffer, (size_t)st.st_size);
munmap(buffer, (size_t)st.st_size);
close(fd);
return result;
}

34
objc.sln Executable file
View File

@ -0,0 +1,34 @@

Microsoft Visual Studio Solution File, Format Version 9.00
# Visual C++ Express 2005
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "objc", "objc.vcproj", "{B3408263-0CF1-47BE-83CC-56070EFC9BC1}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "objcrt", "objcrt\objcrt.vcproj", "{E38C1996-8B3D-4050-A4B2-DC85957B047D}"
ProjectSection(ProjectDependencies) = postProject
{B3408263-0CF1-47BE-83CC-56070EFC9BC1} = {B3408263-0CF1-47BE-83CC-56070EFC9BC1}
EndProjectSection
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Win32 = Debug|Win32
DebugDLL|Win32 = DebugDLL|Win32
Release|Win32 = Release|Win32
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{B3408263-0CF1-47BE-83CC-56070EFC9BC1}.Debug|Win32.ActiveCfg = Debug|Win32
{B3408263-0CF1-47BE-83CC-56070EFC9BC1}.Debug|Win32.Build.0 = Debug|Win32
{B3408263-0CF1-47BE-83CC-56070EFC9BC1}.DebugDLL|Win32.ActiveCfg = DebugDLL|Win32
{B3408263-0CF1-47BE-83CC-56070EFC9BC1}.DebugDLL|Win32.Build.0 = DebugDLL|Win32
{B3408263-0CF1-47BE-83CC-56070EFC9BC1}.Release|Win32.ActiveCfg = Release|Win32
{B3408263-0CF1-47BE-83CC-56070EFC9BC1}.Release|Win32.Build.0 = Release|Win32
{E38C1996-8B3D-4050-A4B2-DC85957B047D}.Debug|Win32.ActiveCfg = Debug|Win32
{E38C1996-8B3D-4050-A4B2-DC85957B047D}.Debug|Win32.Build.0 = Debug|Win32
{E38C1996-8B3D-4050-A4B2-DC85957B047D}.DebugDLL|Win32.ActiveCfg = Debug|Win32
{E38C1996-8B3D-4050-A4B2-DC85957B047D}.DebugDLL|Win32.Build.0 = Debug|Win32
{E38C1996-8B3D-4050-A4B2-DC85957B047D}.Release|Win32.ActiveCfg = Release|Win32
{E38C1996-8B3D-4050-A4B2-DC85957B047D}.Release|Win32.Build.0 = Release|Win32
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
EndGlobal

BIN
objc.suo Executable file

Binary file not shown.

1088
objc.vcproj Normal file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,823 @@
// !$*UTF8*$!
{
archiveVersion = 1;
classes = {
};
objectVersion = 46;
objects = {
/* Begin PBXAggregateTarget section */
837F67A81A771F63004D34FA /* objc-simulator */ = {
isa = PBXAggregateTarget;
buildConfigurationList = 837F67A91A771F63004D34FA /* Build configuration list for PBXAggregateTarget "objc-simulator" */;
buildPhases = (
);
dependencies = (
837F67AD1A771F6E004D34FA /* PBXTargetDependency */,
);
name = "objc-simulator";
productName = objc_simulator;
};
/* End PBXAggregateTarget section */
/* Begin PBXBuildFile section */
393CEAC00DC69E3E000B69DE /* objc-references.mm in Sources */ = {isa = PBXBuildFile; fileRef = 393CEABF0DC69E3E000B69DE /* objc-references.mm */; };
393CEAC60DC69E67000B69DE /* objc-references.h in Headers */ = {isa = PBXBuildFile; fileRef = 393CEAC50DC69E67000B69DE /* objc-references.h */; };
39ABD72312F0B61800D1054C /* objc-weak.h in Headers */ = {isa = PBXBuildFile; fileRef = 39ABD71F12F0B61800D1054C /* objc-weak.h */; };
39ABD72412F0B61800D1054C /* objc-weak.mm in Sources */ = {isa = PBXBuildFile; fileRef = 39ABD72012F0B61800D1054C /* objc-weak.mm */; };
830F2A740D737FB800392440 /* objc-msg-arm.s in Sources */ = {isa = PBXBuildFile; fileRef = 830F2A690D737FB800392440 /* objc-msg-arm.s */; };
830F2A750D737FB900392440 /* objc-msg-i386.s in Sources */ = {isa = PBXBuildFile; fileRef = 830F2A6A0D737FB800392440 /* objc-msg-i386.s */; };
830F2A7D0D737FBB00392440 /* objc-msg-x86_64.s in Sources */ = {isa = PBXBuildFile; fileRef = 830F2A720D737FB800392440 /* objc-msg-x86_64.s */; };
830F2A950D73876100392440 /* objc-accessors.mm in Sources */ = {isa = PBXBuildFile; fileRef = 830F2A930D73876100392440 /* objc-accessors.mm */; };
830F2A980D738DC200392440 /* hashtable.h in Headers */ = {isa = PBXBuildFile; fileRef = 830F2A970D738DC200392440 /* hashtable.h */; settings = {ATTRIBUTES = (Public, ); }; };
83112ED40F00599600A5FBAF /* objc-internal.h in Headers */ = {isa = PBXBuildFile; fileRef = 83112ED30F00599600A5FBAF /* objc-internal.h */; settings = {ATTRIBUTES = (Private, ); }; };
831C85D50E10CF850066E64C /* objc-os.h in Headers */ = {isa = PBXBuildFile; fileRef = 831C85D30E10CF850066E64C /* objc-os.h */; };
831C85D60E10CF850066E64C /* objc-os.mm in Sources */ = {isa = PBXBuildFile; fileRef = 831C85D40E10CF850066E64C /* objc-os.mm */; };
834266D80E665A8B002E4DA2 /* objc-gdb.h in Headers */ = {isa = PBXBuildFile; fileRef = 834266D70E665A8B002E4DA2 /* objc-gdb.h */; settings = {ATTRIBUTES = (Private, ); }; };
834DF8B715993EE1002F2BC9 /* objc-sel-old.mm in Sources */ = {isa = PBXBuildFile; fileRef = 834DF8B615993EE1002F2BC9 /* objc-sel-old.mm */; };
834EC0A411614167009B2563 /* objc-abi.h in Headers */ = {isa = PBXBuildFile; fileRef = 834EC0A311614167009B2563 /* objc-abi.h */; settings = {ATTRIBUTES = (Private, ); }; };
83725F4A14CA5BFA0014370E /* objc-opt.mm in Sources */ = {isa = PBXBuildFile; fileRef = 83725F4914CA5BFA0014370E /* objc-opt.mm */; };
8379996E13CBAF6F007C2B5F /* a1a2-blocktramps-arm64.s in Sources */ = {isa = PBXBuildFile; fileRef = 8379996D13CBAF6F007C2B5F /* a1a2-blocktramps-arm64.s */; };
8383A3A3122600E9009290B8 /* a1a2-blocktramps-arm.s in Sources */ = {isa = PBXBuildFile; fileRef = 8383A3A1122600E9009290B8 /* a1a2-blocktramps-arm.s */; };
8383A3A4122600E9009290B8 /* a2a3-blocktramps-arm.s in Sources */ = {isa = PBXBuildFile; fileRef = 8383A3A2122600E9009290B8 /* a2a3-blocktramps-arm.s */; };
838485BF0D6D687300CEA253 /* hashtable2.h in Headers */ = {isa = PBXBuildFile; fileRef = 838485B70D6D687300CEA253 /* hashtable2.h */; settings = {ATTRIBUTES = (Public, ); }; };
838485C00D6D687300CEA253 /* hashtable2.mm in Sources */ = {isa = PBXBuildFile; fileRef = 838485B80D6D687300CEA253 /* hashtable2.mm */; };
838485C30D6D687300CEA253 /* maptable.h in Headers */ = {isa = PBXBuildFile; fileRef = 838485BB0D6D687300CEA253 /* maptable.h */; settings = {ATTRIBUTES = (Private, ); }; };
838485C40D6D687300CEA253 /* maptable.mm in Sources */ = {isa = PBXBuildFile; fileRef = 838485BC0D6D687300CEA253 /* maptable.mm */; };
838485EF0D6D68A200CEA253 /* objc-api.h in Headers */ = {isa = PBXBuildFile; fileRef = 838485C80D6D68A200CEA253 /* objc-api.h */; settings = {ATTRIBUTES = (Public, ); }; };
838485F00D6D68A200CEA253 /* objc-auto.h in Headers */ = {isa = PBXBuildFile; fileRef = 838485C90D6D68A200CEA253 /* objc-auto.h */; settings = {ATTRIBUTES = (Public, ); }; };
838485F10D6D68A200CEA253 /* objc-auto.mm in Sources */ = {isa = PBXBuildFile; fileRef = 838485CA0D6D68A200CEA253 /* objc-auto.mm */; settings = {COMPILER_FLAGS = "-fexceptions"; }; };
838485F20D6D68A200CEA253 /* objc-cache.mm in Sources */ = {isa = PBXBuildFile; fileRef = 838485CB0D6D68A200CEA253 /* objc-cache.mm */; };
838485F30D6D68A200CEA253 /* objc-class-old.mm in Sources */ = {isa = PBXBuildFile; fileRef = 838485CC0D6D68A200CEA253 /* objc-class-old.mm */; };
838485F40D6D68A200CEA253 /* objc-class.h in Headers */ = {isa = PBXBuildFile; fileRef = 838485CD0D6D68A200CEA253 /* objc-class.h */; settings = {ATTRIBUTES = (Public, ); }; };
838485F50D6D68A200CEA253 /* objc-class.mm in Sources */ = {isa = PBXBuildFile; fileRef = 838485CE0D6D68A200CEA253 /* objc-class.mm */; };
838485F60D6D68A200CEA253 /* objc-config.h in Headers */ = {isa = PBXBuildFile; fileRef = 838485CF0D6D68A200CEA253 /* objc-config.h */; };
838485F70D6D68A200CEA253 /* objc-errors.mm in Sources */ = {isa = PBXBuildFile; fileRef = 838485D00D6D68A200CEA253 /* objc-errors.mm */; };
838485F80D6D68A200CEA253 /* objc-exception.h in Headers */ = {isa = PBXBuildFile; fileRef = 838485D10D6D68A200CEA253 /* objc-exception.h */; settings = {ATTRIBUTES = (Public, ); }; };
838485F90D6D68A200CEA253 /* objc-exception.mm in Sources */ = {isa = PBXBuildFile; fileRef = 838485D20D6D68A200CEA253 /* objc-exception.mm */; settings = {COMPILER_FLAGS = "-fexceptions"; }; };
838485FA0D6D68A200CEA253 /* objc-file.mm in Sources */ = {isa = PBXBuildFile; fileRef = 838485D30D6D68A200CEA253 /* objc-file.mm */; };
838485FB0D6D68A200CEA253 /* objc-initialize.h in Headers */ = {isa = PBXBuildFile; fileRef = 838485D40D6D68A200CEA253 /* objc-initialize.h */; };
838485FC0D6D68A200CEA253 /* objc-initialize.mm in Sources */ = {isa = PBXBuildFile; fileRef = 838485D50D6D68A200CEA253 /* objc-initialize.mm */; };
838485FD0D6D68A200CEA253 /* objc-layout.mm in Sources */ = {isa = PBXBuildFile; fileRef = 838485D60D6D68A200CEA253 /* objc-layout.mm */; };
838485FE0D6D68A200CEA253 /* objc-load.h in Headers */ = {isa = PBXBuildFile; fileRef = 838485D70D6D68A200CEA253 /* objc-load.h */; settings = {ATTRIBUTES = (Public, ); }; };
838485FF0D6D68A200CEA253 /* objc-load.mm in Sources */ = {isa = PBXBuildFile; fileRef = 838485D80D6D68A200CEA253 /* objc-load.mm */; };
838486000D6D68A200CEA253 /* objc-loadmethod.h in Headers */ = {isa = PBXBuildFile; fileRef = 838485D90D6D68A200CEA253 /* objc-loadmethod.h */; };
838486010D6D68A200CEA253 /* objc-loadmethod.mm in Sources */ = {isa = PBXBuildFile; fileRef = 838485DA0D6D68A200CEA253 /* objc-loadmethod.mm */; };
838486020D6D68A200CEA253 /* objc-lockdebug.mm in Sources */ = {isa = PBXBuildFile; fileRef = 838485DB0D6D68A200CEA253 /* objc-lockdebug.mm */; };
838486030D6D68A200CEA253 /* objc-private.h in Headers */ = {isa = PBXBuildFile; fileRef = 838485DC0D6D68A200CEA253 /* objc-private.h */; };
838486070D6D68A200CEA253 /* objc-runtime-new.h in Headers */ = {isa = PBXBuildFile; fileRef = 838485E00D6D68A200CEA253 /* objc-runtime-new.h */; };
838486080D6D68A200CEA253 /* objc-runtime-new.mm in Sources */ = {isa = PBXBuildFile; fileRef = 838485E10D6D68A200CEA253 /* objc-runtime-new.mm */; };
838486090D6D68A200CEA253 /* objc-runtime-old.mm in Sources */ = {isa = PBXBuildFile; fileRef = 838485E20D6D68A200CEA253 /* objc-runtime-old.mm */; };
8384860A0D6D68A200CEA253 /* objc-runtime.h in Headers */ = {isa = PBXBuildFile; fileRef = 838485E30D6D68A200CEA253 /* objc-runtime.h */; settings = {ATTRIBUTES = (Public, ); }; };
8384860B0D6D68A200CEA253 /* objc-runtime.mm in Sources */ = {isa = PBXBuildFile; fileRef = 838485E40D6D68A200CEA253 /* objc-runtime.mm */; };
8384860C0D6D68A200CEA253 /* objc-sel-set.h in Headers */ = {isa = PBXBuildFile; fileRef = 838485E50D6D68A200CEA253 /* objc-sel-set.h */; };
8384860D0D6D68A200CEA253 /* objc-sel-set.mm in Sources */ = {isa = PBXBuildFile; fileRef = 838485E60D6D68A200CEA253 /* objc-sel-set.mm */; };
8384860F0D6D68A200CEA253 /* objc-sel.mm in Sources */ = {isa = PBXBuildFile; fileRef = 838485E80D6D68A200CEA253 /* objc-sel.mm */; };
838486100D6D68A200CEA253 /* objc-sync.h in Headers */ = {isa = PBXBuildFile; fileRef = 838485E90D6D68A200CEA253 /* objc-sync.h */; settings = {ATTRIBUTES = (Public, ); }; };
838486110D6D68A200CEA253 /* objc-sync.mm in Sources */ = {isa = PBXBuildFile; fileRef = 838485EA0D6D68A200CEA253 /* objc-sync.mm */; };
838486120D6D68A200CEA253 /* objc-typeencoding.mm in Sources */ = {isa = PBXBuildFile; fileRef = 838485EB0D6D68A200CEA253 /* objc-typeencoding.mm */; };
838486130D6D68A200CEA253 /* objc.h in Headers */ = {isa = PBXBuildFile; fileRef = 838485EC0D6D68A200CEA253 /* objc.h */; settings = {ATTRIBUTES = (Public, ); }; };
838486140D6D68A200CEA253 /* Object.h in Headers */ = {isa = PBXBuildFile; fileRef = 838485ED0D6D68A200CEA253 /* Object.h */; settings = {ATTRIBUTES = (Public, ); }; };
838486150D6D68A200CEA253 /* Object.mm in Sources */ = {isa = PBXBuildFile; fileRef = 838485EE0D6D68A200CEA253 /* Object.mm */; };
8384861E0D6D68A800CEA253 /* Protocol.h in Headers */ = {isa = PBXBuildFile; fileRef = 838486180D6D68A800CEA253 /* Protocol.h */; settings = {ATTRIBUTES = (Public, ); }; };
8384861F0D6D68A800CEA253 /* Protocol.mm in Sources */ = {isa = PBXBuildFile; fileRef = 838486190D6D68A800CEA253 /* Protocol.mm */; };
838486200D6D68A800CEA253 /* runtime.h in Headers */ = {isa = PBXBuildFile; fileRef = 8384861A0D6D68A800CEA253 /* runtime.h */; settings = {ATTRIBUTES = (Public, ); }; };
838486250D6D68F000CEA253 /* List.m in Sources */ = {isa = PBXBuildFile; fileRef = 838486230D6D68F000CEA253 /* List.m */; };
838486260D6D68F000CEA253 /* List.h in Headers */ = {isa = PBXBuildFile; fileRef = 838486240D6D68F000CEA253 /* List.h */; settings = {ATTRIBUTES = (Public, ); }; };
838486280D6D6A2400CEA253 /* message.h in Headers */ = {isa = PBXBuildFile; fileRef = 838485BD0D6D687300CEA253 /* message.h */; settings = {ATTRIBUTES = (Public, ); }; };
83B1A8BE0FF1AC0D0019EA5B /* objc-msg-simulator-i386.s in Sources */ = {isa = PBXBuildFile; fileRef = 83B1A8BC0FF1AC0D0019EA5B /* objc-msg-simulator-i386.s */; };
83BE02E40FCCB23400661494 /* objc-file-old.mm in Sources */ = {isa = PBXBuildFile; fileRef = 83BE02E30FCCB23400661494 /* objc-file-old.mm */; };
83BE02E80FCCB24D00661494 /* objc-file-old.h in Headers */ = {isa = PBXBuildFile; fileRef = 83BE02E50FCCB24D00661494 /* objc-file-old.h */; };
83BE02E90FCCB24D00661494 /* objc-file.h in Headers */ = {isa = PBXBuildFile; fileRef = 83BE02E60FCCB24D00661494 /* objc-file.h */; };
83BE02EA0FCCB24D00661494 /* objc-runtime-old.h in Headers */ = {isa = PBXBuildFile; fileRef = 83BE02E70FCCB24D00661494 /* objc-runtime-old.h */; };
83C9C3391668B50E00F4E544 /* objc-msg-simulator-x86_64.s in Sources */ = {isa = PBXBuildFile; fileRef = 83C9C3381668B50E00F4E544 /* objc-msg-simulator-x86_64.s */; };
83D49E4F13C7C84F0057F1DD /* objc-msg-arm64.s in Sources */ = {isa = PBXBuildFile; fileRef = 83D49E4E13C7C84F0057F1DD /* objc-msg-arm64.s */; };
83EB007B121C9EC200B92C16 /* objc-sel-table.s in Sources */ = {isa = PBXBuildFile; fileRef = 83EB007A121C9EC200B92C16 /* objc-sel-table.s */; };
83F4B52815E843B100E0926F /* NSObjCRuntime.h in Headers */ = {isa = PBXBuildFile; fileRef = 83F4B52615E843B100E0926F /* NSObjCRuntime.h */; settings = {ATTRIBUTES = (Public, ); }; };
83F4B52915E843B100E0926F /* NSObject.h in Headers */ = {isa = PBXBuildFile; fileRef = 83F4B52715E843B100E0926F /* NSObject.h */; settings = {ATTRIBUTES = (Public, ); }; };
83F550E0155E030800E95D3B /* objc-cache-old.mm in Sources */ = {isa = PBXBuildFile; fileRef = 83F550DF155E030800E95D3B /* objc-cache-old.mm */; };
87BB4EA70EC39854005D08E1 /* objc-probes.d in Sources */ = {isa = PBXBuildFile; fileRef = 87BB4E900EC39633005D08E1 /* objc-probes.d */; };
9672F7EE14D5F488007CEC96 /* NSObject.mm in Sources */ = {isa = PBXBuildFile; fileRef = 9672F7ED14D5F488007CEC96 /* NSObject.mm */; };
E8923DA1116AB2820071B552 /* a1a2-blocktramps-i386.s in Sources */ = {isa = PBXBuildFile; fileRef = E8923D9C116AB2820071B552 /* a1a2-blocktramps-i386.s */; };
E8923DA2116AB2820071B552 /* a1a2-blocktramps-x86_64.s in Sources */ = {isa = PBXBuildFile; fileRef = E8923D9D116AB2820071B552 /* a1a2-blocktramps-x86_64.s */; };
E8923DA3116AB2820071B552 /* a2a3-blocktramps-i386.s in Sources */ = {isa = PBXBuildFile; fileRef = E8923D9E116AB2820071B552 /* a2a3-blocktramps-i386.s */; };
E8923DA4116AB2820071B552 /* a2a3-blocktramps-x86_64.s in Sources */ = {isa = PBXBuildFile; fileRef = E8923D9F116AB2820071B552 /* a2a3-blocktramps-x86_64.s */; };
E8923DA5116AB2820071B552 /* objc-block-trampolines.mm in Sources */ = {isa = PBXBuildFile; fileRef = E8923DA0116AB2820071B552 /* objc-block-trampolines.mm */; };
/* End PBXBuildFile section */
/* Begin PBXContainerItemProxy section */
837F67AC1A771F6E004D34FA /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy;
containerPortal = 08FB7793FE84155DC02AAC07 /* Project object */;
proxyType = 1;
remoteGlobalIDString = D2AAC0620554660B00DB518D;
remoteInfo = objc;
};
/* End PBXContainerItemProxy section */
/* Begin PBXFileReference section */
393CEABF0DC69E3E000B69DE /* objc-references.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = "objc-references.mm"; path = "runtime/objc-references.mm"; sourceTree = "<group>"; };
393CEAC50DC69E67000B69DE /* objc-references.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = "objc-references.h"; path = "runtime/objc-references.h"; sourceTree = "<group>"; };
39ABD71F12F0B61800D1054C /* objc-weak.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = "objc-weak.h"; path = "runtime/objc-weak.h"; sourceTree = "<group>"; };
39ABD72012F0B61800D1054C /* objc-weak.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = "objc-weak.mm"; path = "runtime/objc-weak.mm"; sourceTree = "<group>"; };
830F2A690D737FB800392440 /* objc-msg-arm.s */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.asm; name = "objc-msg-arm.s"; path = "runtime/Messengers.subproj/objc-msg-arm.s"; sourceTree = "<group>"; };
830F2A6A0D737FB800392440 /* objc-msg-i386.s */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.asm; name = "objc-msg-i386.s"; path = "runtime/Messengers.subproj/objc-msg-i386.s"; sourceTree = "<group>"; };
830F2A720D737FB800392440 /* objc-msg-x86_64.s */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.asm; name = "objc-msg-x86_64.s"; path = "runtime/Messengers.subproj/objc-msg-x86_64.s"; sourceTree = "<group>"; tabWidth = 8; usesTabs = 1; };
830F2A930D73876100392440 /* objc-accessors.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = "objc-accessors.mm"; path = "runtime/objc-accessors.mm"; sourceTree = "<group>"; };
830F2A970D738DC200392440 /* hashtable.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = hashtable.h; path = runtime/hashtable.h; sourceTree = "<group>"; };
830F2AA50D7394C200392440 /* markgc.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = markgc.cpp; sourceTree = "<group>"; };
83112ED30F00599600A5FBAF /* objc-internal.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = "objc-internal.h"; path = "runtime/objc-internal.h"; sourceTree = "<group>"; };
831C85D30E10CF850066E64C /* objc-os.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = "objc-os.h"; path = "runtime/objc-os.h"; sourceTree = "<group>"; };
831C85D40E10CF850066E64C /* objc-os.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = "objc-os.mm"; path = "runtime/objc-os.mm"; sourceTree = "<group>"; };
834266D70E665A8B002E4DA2 /* objc-gdb.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = "objc-gdb.h"; path = "runtime/objc-gdb.h"; sourceTree = "<group>"; };
834DF8B615993EE1002F2BC9 /* objc-sel-old.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = "objc-sel-old.mm"; path = "runtime/objc-sel-old.mm"; sourceTree = "<group>"; };
834EC0A311614167009B2563 /* objc-abi.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = "objc-abi.h"; path = "runtime/objc-abi.h"; sourceTree = "<group>"; };
83725F4914CA5BFA0014370E /* objc-opt.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = "objc-opt.mm"; path = "runtime/objc-opt.mm"; sourceTree = "<group>"; };
8379996D13CBAF6F007C2B5F /* a1a2-blocktramps-arm64.s */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.asm; name = "a1a2-blocktramps-arm64.s"; path = "runtime/a1a2-blocktramps-arm64.s"; sourceTree = "<group>"; };
8383A3A1122600E9009290B8 /* a1a2-blocktramps-arm.s */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.asm; name = "a1a2-blocktramps-arm.s"; path = "runtime/a1a2-blocktramps-arm.s"; sourceTree = "<group>"; };
8383A3A2122600E9009290B8 /* a2a3-blocktramps-arm.s */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.asm; name = "a2a3-blocktramps-arm.s"; path = "runtime/a2a3-blocktramps-arm.s"; sourceTree = "<group>"; };
838485B30D6D682B00CEA253 /* libobjc.order */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = libobjc.order; sourceTree = "<group>"; };
838485B40D6D683300CEA253 /* APPLE_LICENSE */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = APPLE_LICENSE; sourceTree = "<group>"; };
838485B50D6D683300CEA253 /* ReleaseNotes.rtf */ = {isa = PBXFileReference; lastKnownFileType = text.rtf; path = ReleaseNotes.rtf; sourceTree = "<group>"; };
838485B70D6D687300CEA253 /* hashtable2.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = hashtable2.h; path = runtime/hashtable2.h; sourceTree = "<group>"; };
838485B80D6D687300CEA253 /* hashtable2.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = hashtable2.mm; path = runtime/hashtable2.mm; sourceTree = "<group>"; };
838485BB0D6D687300CEA253 /* maptable.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = maptable.h; path = runtime/maptable.h; sourceTree = "<group>"; };
838485BC0D6D687300CEA253 /* maptable.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = maptable.mm; path = runtime/maptable.mm; sourceTree = "<group>"; };
838485BD0D6D687300CEA253 /* message.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = message.h; path = runtime/message.h; sourceTree = "<group>"; };
838485C80D6D68A200CEA253 /* objc-api.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = "objc-api.h"; path = "runtime/objc-api.h"; sourceTree = "<group>"; };
838485C90D6D68A200CEA253 /* objc-auto.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = "objc-auto.h"; path = "runtime/objc-auto.h"; sourceTree = "<group>"; };
838485CA0D6D68A200CEA253 /* objc-auto.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = "objc-auto.mm"; path = "runtime/objc-auto.mm"; sourceTree = "<group>"; };
838485CB0D6D68A200CEA253 /* objc-cache.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = "objc-cache.mm"; path = "runtime/objc-cache.mm"; sourceTree = "<group>"; };
838485CC0D6D68A200CEA253 /* objc-class-old.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = "objc-class-old.mm"; path = "runtime/objc-class-old.mm"; sourceTree = "<group>"; };
838485CD0D6D68A200CEA253 /* objc-class.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = "objc-class.h"; path = "runtime/objc-class.h"; sourceTree = "<group>"; };
838485CE0D6D68A200CEA253 /* objc-class.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = "objc-class.mm"; path = "runtime/objc-class.mm"; sourceTree = "<group>"; };
838485CF0D6D68A200CEA253 /* objc-config.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = "objc-config.h"; path = "runtime/objc-config.h"; sourceTree = "<group>"; };
838485D00D6D68A200CEA253 /* objc-errors.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = "objc-errors.mm"; path = "runtime/objc-errors.mm"; sourceTree = "<group>"; };
838485D10D6D68A200CEA253 /* objc-exception.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = "objc-exception.h"; path = "runtime/objc-exception.h"; sourceTree = "<group>"; };
838485D20D6D68A200CEA253 /* objc-exception.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = "objc-exception.mm"; path = "runtime/objc-exception.mm"; sourceTree = "<group>"; };
838485D30D6D68A200CEA253 /* objc-file.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = "objc-file.mm"; path = "runtime/objc-file.mm"; sourceTree = "<group>"; };
838485D40D6D68A200CEA253 /* objc-initialize.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = "objc-initialize.h"; path = "runtime/objc-initialize.h"; sourceTree = "<group>"; };
838485D50D6D68A200CEA253 /* objc-initialize.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = "objc-initialize.mm"; path = "runtime/objc-initialize.mm"; sourceTree = "<group>"; };
838485D60D6D68A200CEA253 /* objc-layout.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = "objc-layout.mm"; path = "runtime/objc-layout.mm"; sourceTree = "<group>"; };
838485D70D6D68A200CEA253 /* objc-load.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = "objc-load.h"; path = "runtime/objc-load.h"; sourceTree = "<group>"; };
838485D80D6D68A200CEA253 /* objc-load.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = "objc-load.mm"; path = "runtime/objc-load.mm"; sourceTree = "<group>"; };
838485D90D6D68A200CEA253 /* objc-loadmethod.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = "objc-loadmethod.h"; path = "runtime/objc-loadmethod.h"; sourceTree = "<group>"; };
838485DA0D6D68A200CEA253 /* objc-loadmethod.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = "objc-loadmethod.mm"; path = "runtime/objc-loadmethod.mm"; sourceTree = "<group>"; };
838485DB0D6D68A200CEA253 /* objc-lockdebug.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = "objc-lockdebug.mm"; path = "runtime/objc-lockdebug.mm"; sourceTree = "<group>"; };
838485DC0D6D68A200CEA253 /* objc-private.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = "objc-private.h"; path = "runtime/objc-private.h"; sourceTree = "<group>"; };
838485E00D6D68A200CEA253 /* objc-runtime-new.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = "objc-runtime-new.h"; path = "runtime/objc-runtime-new.h"; sourceTree = "<group>"; };
838485E10D6D68A200CEA253 /* objc-runtime-new.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = "objc-runtime-new.mm"; path = "runtime/objc-runtime-new.mm"; sourceTree = "<group>"; };
838485E20D6D68A200CEA253 /* objc-runtime-old.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = "objc-runtime-old.mm"; path = "runtime/objc-runtime-old.mm"; sourceTree = "<group>"; };
838485E30D6D68A200CEA253 /* objc-runtime.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = "objc-runtime.h"; path = "runtime/objc-runtime.h"; sourceTree = "<group>"; };
838485E40D6D68A200CEA253 /* objc-runtime.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = "objc-runtime.mm"; path = "runtime/objc-runtime.mm"; sourceTree = "<group>"; };
838485E50D6D68A200CEA253 /* objc-sel-set.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = "objc-sel-set.h"; path = "runtime/objc-sel-set.h"; sourceTree = "<group>"; };
838485E60D6D68A200CEA253 /* objc-sel-set.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = "objc-sel-set.mm"; path = "runtime/objc-sel-set.mm"; sourceTree = "<group>"; };
838485E80D6D68A200CEA253 /* objc-sel.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = "objc-sel.mm"; path = "runtime/objc-sel.mm"; sourceTree = "<group>"; };
838485E90D6D68A200CEA253 /* objc-sync.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = "objc-sync.h"; path = "runtime/objc-sync.h"; sourceTree = "<group>"; };
838485EA0D6D68A200CEA253 /* objc-sync.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = "objc-sync.mm"; path = "runtime/objc-sync.mm"; sourceTree = "<group>"; };
838485EB0D6D68A200CEA253 /* objc-typeencoding.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = "objc-typeencoding.mm"; path = "runtime/objc-typeencoding.mm"; sourceTree = "<group>"; };
838485EC0D6D68A200CEA253 /* objc.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = objc.h; path = runtime/objc.h; sourceTree = "<group>"; };
838485ED0D6D68A200CEA253 /* Object.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Object.h; path = runtime/Object.h; sourceTree = "<group>"; };
838485EE0D6D68A200CEA253 /* Object.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = Object.mm; path = runtime/Object.mm; sourceTree = "<group>"; };
838486180D6D68A800CEA253 /* Protocol.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Protocol.h; path = runtime/Protocol.h; sourceTree = "<group>"; };
838486190D6D68A800CEA253 /* Protocol.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = Protocol.mm; path = runtime/Protocol.mm; sourceTree = "<group>"; };
8384861A0D6D68A800CEA253 /* runtime.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = runtime.h; path = runtime/runtime.h; sourceTree = "<group>"; };
838486230D6D68F000CEA253 /* List.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = List.m; path = runtime/OldClasses.subproj/List.m; sourceTree = "<group>"; };
838486240D6D68F000CEA253 /* List.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = List.h; path = runtime/OldClasses.subproj/List.h; sourceTree = "<group>"; };
83B1A8BC0FF1AC0D0019EA5B /* objc-msg-simulator-i386.s */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.asm; name = "objc-msg-simulator-i386.s"; path = "runtime/Messengers.subproj/objc-msg-simulator-i386.s"; sourceTree = "<group>"; };
83BE02E30FCCB23400661494 /* objc-file-old.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = "objc-file-old.mm"; path = "runtime/objc-file-old.mm"; sourceTree = "<group>"; };
83BE02E50FCCB24D00661494 /* objc-file-old.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = "objc-file-old.h"; path = "runtime/objc-file-old.h"; sourceTree = "<group>"; };
83BE02E60FCCB24D00661494 /* objc-file.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = "objc-file.h"; path = "runtime/objc-file.h"; sourceTree = "<group>"; };
83BE02E70FCCB24D00661494 /* objc-runtime-old.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = "objc-runtime-old.h"; path = "runtime/objc-runtime-old.h"; sourceTree = "<group>"; };
83C9C3381668B50E00F4E544 /* objc-msg-simulator-x86_64.s */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.asm; name = "objc-msg-simulator-x86_64.s"; path = "runtime/Messengers.subproj/objc-msg-simulator-x86_64.s"; sourceTree = "<group>"; };
83D49E4E13C7C84F0057F1DD /* objc-msg-arm64.s */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.asm; name = "objc-msg-arm64.s"; path = "runtime/Messengers.subproj/objc-msg-arm64.s"; sourceTree = "<group>"; };
83EB007A121C9EC200B92C16 /* objc-sel-table.s */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.asm; name = "objc-sel-table.s"; path = "runtime/objc-sel-table.s"; sourceTree = "<group>"; };
83F4B52615E843B100E0926F /* NSObjCRuntime.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = NSObjCRuntime.h; path = runtime/NSObjCRuntime.h; sourceTree = "<group>"; };
83F4B52715E843B100E0926F /* NSObject.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = NSObject.h; path = runtime/NSObject.h; sourceTree = "<group>"; };
83F550DF155E030800E95D3B /* objc-cache-old.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = "objc-cache-old.mm"; path = "runtime/objc-cache-old.mm"; sourceTree = "<group>"; };
87BB4E900EC39633005D08E1 /* objc-probes.d */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.dtrace; name = "objc-probes.d"; path = "runtime/objc-probes.d"; sourceTree = "<group>"; };
9672F7ED14D5F488007CEC96 /* NSObject.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = NSObject.mm; path = runtime/NSObject.mm; sourceTree = "<group>"; };
BC8B5D1212D3D48100C78A5B /* libauto.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libauto.dylib; path = /usr/lib/libauto.dylib; sourceTree = "<absolute>"; };
D2AAC0630554660B00DB518D /* libobjc.A.dylib */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.dylib"; includeInIndex = 0; path = libobjc.A.dylib; sourceTree = BUILT_PRODUCTS_DIR; };
E8923D9C116AB2820071B552 /* a1a2-blocktramps-i386.s */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.asm; name = "a1a2-blocktramps-i386.s"; path = "runtime/a1a2-blocktramps-i386.s"; sourceTree = "<group>"; };
E8923D9D116AB2820071B552 /* a1a2-blocktramps-x86_64.s */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.asm; name = "a1a2-blocktramps-x86_64.s"; path = "runtime/a1a2-blocktramps-x86_64.s"; sourceTree = "<group>"; };
E8923D9E116AB2820071B552 /* a2a3-blocktramps-i386.s */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.asm; name = "a2a3-blocktramps-i386.s"; path = "runtime/a2a3-blocktramps-i386.s"; sourceTree = "<group>"; };
E8923D9F116AB2820071B552 /* a2a3-blocktramps-x86_64.s */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.asm; name = "a2a3-blocktramps-x86_64.s"; path = "runtime/a2a3-blocktramps-x86_64.s"; sourceTree = "<group>"; };
E8923DA0116AB2820071B552 /* objc-block-trampolines.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = "objc-block-trampolines.mm"; path = "runtime/objc-block-trampolines.mm"; sourceTree = "<group>"; };
/* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */
D289988505E68E00004EDB86 /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXFrameworksBuildPhase section */
/* Begin PBXGroup section */
08FB7794FE84155DC02AAC07 /* objc */ = {
isa = PBXGroup;
children = (
BC8B5D1212D3D48100C78A5B /* libauto.dylib */,
838485C60D6D687700CEA253 /* Public Headers */,
838485C70D6D688200CEA253 /* Private Headers */,
8384862A0D6D6ABC00CEA253 /* Project Headers */,
838486220D6D68E300CEA253 /* Obsolete Headers */,
838486270D6D690F00CEA253 /* Obsolete Source */,
08FB7795FE84155DC02AAC07 /* Source */,
838485B20D6D67F900CEA253 /* Other */,
1AB674ADFE9D54B511CA2CBB /* Products */,
);
name = objc;
sourceTree = "<group>";
};
08FB7795FE84155DC02AAC07 /* Source */ = {
isa = PBXGroup;
children = (
8383A3A1122600E9009290B8 /* a1a2-blocktramps-arm.s */,
8383A3A2122600E9009290B8 /* a2a3-blocktramps-arm.s */,
838485B80D6D687300CEA253 /* hashtable2.mm */,
838485BC0D6D687300CEA253 /* maptable.mm */,
9672F7ED14D5F488007CEC96 /* NSObject.mm */,
838486190D6D68A800CEA253 /* Protocol.mm */,
830F2A930D73876100392440 /* objc-accessors.mm */,
838485CA0D6D68A200CEA253 /* objc-auto.mm */,
39ABD72012F0B61800D1054C /* objc-weak.mm */,
E8923DA0116AB2820071B552 /* objc-block-trampolines.mm */,
838485CB0D6D68A200CEA253 /* objc-cache.mm */,
83F550DF155E030800E95D3B /* objc-cache-old.mm */,
838485CC0D6D68A200CEA253 /* objc-class-old.mm */,
838485CE0D6D68A200CEA253 /* objc-class.mm */,
838485D00D6D68A200CEA253 /* objc-errors.mm */,
838485D20D6D68A200CEA253 /* objc-exception.mm */,
838485D30D6D68A200CEA253 /* objc-file.mm */,
83BE02E30FCCB23400661494 /* objc-file-old.mm */,
838485D50D6D68A200CEA253 /* objc-initialize.mm */,
838485D60D6D68A200CEA253 /* objc-layout.mm */,
838485D80D6D68A200CEA253 /* objc-load.mm */,
838485DA0D6D68A200CEA253 /* objc-loadmethod.mm */,
838485DB0D6D68A200CEA253 /* objc-lockdebug.mm */,
83725F4914CA5BFA0014370E /* objc-opt.mm */,
831C85D40E10CF850066E64C /* objc-os.mm */,
393CEABF0DC69E3E000B69DE /* objc-references.mm */,
838485E10D6D68A200CEA253 /* objc-runtime-new.mm */,
838485E20D6D68A200CEA253 /* objc-runtime-old.mm */,
838485E40D6D68A200CEA253 /* objc-runtime.mm */,
838485E60D6D68A200CEA253 /* objc-sel-set.mm */,
83EB007A121C9EC200B92C16 /* objc-sel-table.s */,
838485E80D6D68A200CEA253 /* objc-sel.mm */,
834DF8B615993EE1002F2BC9 /* objc-sel-old.mm */,
838485EA0D6D68A200CEA253 /* objc-sync.mm */,
838485EB0D6D68A200CEA253 /* objc-typeencoding.mm */,
8379996D13CBAF6F007C2B5F /* a1a2-blocktramps-arm64.s */,
E8923D9C116AB2820071B552 /* a1a2-blocktramps-i386.s */,
E8923D9D116AB2820071B552 /* a1a2-blocktramps-x86_64.s */,
E8923D9E116AB2820071B552 /* a2a3-blocktramps-i386.s */,
E8923D9F116AB2820071B552 /* a2a3-blocktramps-x86_64.s */,
830F2A690D737FB800392440 /* objc-msg-arm.s */,
83D49E4E13C7C84F0057F1DD /* objc-msg-arm64.s */,
830F2A6A0D737FB800392440 /* objc-msg-i386.s */,
83B1A8BC0FF1AC0D0019EA5B /* objc-msg-simulator-i386.s */,
83C9C3381668B50E00F4E544 /* objc-msg-simulator-x86_64.s */,
830F2A720D737FB800392440 /* objc-msg-x86_64.s */,
87BB4E900EC39633005D08E1 /* objc-probes.d */,
);
name = Source;
sourceTree = "<group>";
};
1AB674ADFE9D54B511CA2CBB /* Products */ = {
isa = PBXGroup;
children = (
D2AAC0630554660B00DB518D /* libobjc.A.dylib */,
);
name = Products;
sourceTree = "<group>";
};
838485B20D6D67F900CEA253 /* Other */ = {
isa = PBXGroup;
children = (
830F2AA50D7394C200392440 /* markgc.cpp */,
838485B40D6D683300CEA253 /* APPLE_LICENSE */,
838485B50D6D683300CEA253 /* ReleaseNotes.rtf */,
838485B30D6D682B00CEA253 /* libobjc.order */,
);
name = Other;
sourceTree = "<group>";
};
838485C60D6D687700CEA253 /* Public Headers */ = {
isa = PBXGroup;
children = (
83F4B52615E843B100E0926F /* NSObjCRuntime.h */,
83F4B52715E843B100E0926F /* NSObject.h */,
838485BD0D6D687300CEA253 /* message.h */,
838485C80D6D68A200CEA253 /* objc-api.h */,
838485C90D6D68A200CEA253 /* objc-auto.h */,
838485D10D6D68A200CEA253 /* objc-exception.h */,
838485E90D6D68A200CEA253 /* objc-sync.h */,
838485EC0D6D68A200CEA253 /* objc.h */,
8384861A0D6D68A800CEA253 /* runtime.h */,
);
name = "Public Headers";
sourceTree = "<group>";
};
838485C70D6D688200CEA253 /* Private Headers */ = {
isa = PBXGroup;
children = (
83112ED30F00599600A5FBAF /* objc-internal.h */,
834EC0A311614167009B2563 /* objc-abi.h */,
838485BB0D6D687300CEA253 /* maptable.h */,
834266D70E665A8B002E4DA2 /* objc-gdb.h */,
);
name = "Private Headers";
sourceTree = "<group>";
};
838486220D6D68E300CEA253 /* Obsolete Headers */ = {
isa = PBXGroup;
children = (
830F2A970D738DC200392440 /* hashtable.h */,
838485B70D6D687300CEA253 /* hashtable2.h */,
838485CD0D6D68A200CEA253 /* objc-class.h */,
838485D70D6D68A200CEA253 /* objc-load.h */,
838485E30D6D68A200CEA253 /* objc-runtime.h */,
838486240D6D68F000CEA253 /* List.h */,
838485ED0D6D68A200CEA253 /* Object.h */,
838486180D6D68A800CEA253 /* Protocol.h */,
);
name = "Obsolete Headers";
sourceTree = "<group>";
};
838486270D6D690F00CEA253 /* Obsolete Source */ = {
isa = PBXGroup;
children = (
838486230D6D68F000CEA253 /* List.m */,
838485EE0D6D68A200CEA253 /* Object.mm */,
);
name = "Obsolete Source";
sourceTree = "<group>";
};
8384862A0D6D6ABC00CEA253 /* Project Headers */ = {
isa = PBXGroup;
children = (
838485CF0D6D68A200CEA253 /* objc-config.h */,
83BE02E60FCCB24D00661494 /* objc-file.h */,
83BE02E50FCCB24D00661494 /* objc-file-old.h */,
838485D40D6D68A200CEA253 /* objc-initialize.h */,
838485D90D6D68A200CEA253 /* objc-loadmethod.h */,
831C85D30E10CF850066E64C /* objc-os.h */,
838485DC0D6D68A200CEA253 /* objc-private.h */,
393CEAC50DC69E67000B69DE /* objc-references.h */,
838485E00D6D68A200CEA253 /* objc-runtime-new.h */,
83BE02E70FCCB24D00661494 /* objc-runtime-old.h */,
838485E50D6D68A200CEA253 /* objc-sel-set.h */,
39ABD71F12F0B61800D1054C /* objc-weak.h */,
);
name = "Project Headers";
sourceTree = "<group>";
};
/* End PBXGroup section */
/* Begin PBXHeadersBuildPhase section */
D2AAC0600554660B00DB518D /* Headers */ = {
isa = PBXHeadersBuildPhase;
buildActionMask = 2147483647;
files = (
830F2A980D738DC200392440 /* hashtable.h in Headers */,
838485BF0D6D687300CEA253 /* hashtable2.h in Headers */,
838486260D6D68F000CEA253 /* List.h in Headers */,
838485C30D6D687300CEA253 /* maptable.h in Headers */,
838486280D6D6A2400CEA253 /* message.h in Headers */,
834EC0A411614167009B2563 /* objc-abi.h in Headers */,
838485EF0D6D68A200CEA253 /* objc-api.h in Headers */,
838485F00D6D68A200CEA253 /* objc-auto.h in Headers */,
838485F40D6D68A200CEA253 /* objc-class.h in Headers */,
838485F60D6D68A200CEA253 /* objc-config.h in Headers */,
838485F80D6D68A200CEA253 /* objc-exception.h in Headers */,
83BE02E80FCCB24D00661494 /* objc-file-old.h in Headers */,
83BE02E90FCCB24D00661494 /* objc-file.h in Headers */,
834266D80E665A8B002E4DA2 /* objc-gdb.h in Headers */,
838485FB0D6D68A200CEA253 /* objc-initialize.h in Headers */,
83112ED40F00599600A5FBAF /* objc-internal.h in Headers */,
838485FE0D6D68A200CEA253 /* objc-load.h in Headers */,
838486000D6D68A200CEA253 /* objc-loadmethod.h in Headers */,
831C85D50E10CF850066E64C /* objc-os.h in Headers */,
838486030D6D68A200CEA253 /* objc-private.h in Headers */,
393CEAC60DC69E67000B69DE /* objc-references.h in Headers */,
838486070D6D68A200CEA253 /* objc-runtime-new.h in Headers */,
83BE02EA0FCCB24D00661494 /* objc-runtime-old.h in Headers */,
8384860A0D6D68A200CEA253 /* objc-runtime.h in Headers */,
8384860C0D6D68A200CEA253 /* objc-sel-set.h in Headers */,
838486100D6D68A200CEA253 /* objc-sync.h in Headers */,
838486130D6D68A200CEA253 /* objc.h in Headers */,
838486140D6D68A200CEA253 /* Object.h in Headers */,
8384861E0D6D68A800CEA253 /* Protocol.h in Headers */,
838486200D6D68A800CEA253 /* runtime.h in Headers */,
39ABD72312F0B61800D1054C /* objc-weak.h in Headers */,
83F4B52815E843B100E0926F /* NSObjCRuntime.h in Headers */,
83F4B52915E843B100E0926F /* NSObject.h in Headers */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXHeadersBuildPhase section */
/* Begin PBXNativeTarget section */
D2AAC0620554660B00DB518D /* objc */ = {
isa = PBXNativeTarget;
buildConfigurationList = 1DEB914A08733D8E0010E9CD /* Build configuration list for PBXNativeTarget "objc" */;
buildPhases = (
D2AAC0600554660B00DB518D /* Headers */,
D2AAC0610554660B00DB518D /* Sources */,
D289988505E68E00004EDB86 /* Frameworks */,
830F2AB60D739AB600392440 /* Run Script (markgc) */,
830F2AFA0D73BC5800392440 /* Run Script (symlink) */,
);
buildRules = (
);
dependencies = (
);
name = objc;
productName = objc;
productReference = D2AAC0630554660B00DB518D /* libobjc.A.dylib */;
productType = "com.apple.product-type.library.dynamic";
};
/* End PBXNativeTarget section */
/* Begin PBXProject section */
08FB7793FE84155DC02AAC07 /* Project object */ = {
isa = PBXProject;
attributes = {
BuildIndependentTargetsInParallel = NO;
LastUpgradeCheck = 0440;
TargetAttributes = {
837F67A81A771F63004D34FA = {
CreatedOnToolsVersion = 6.3;
};
};
};
buildConfigurationList = 1DEB914E08733D8E0010E9CD /* Build configuration list for PBXProject "objc" */;
compatibilityVersion = "Xcode 3.2";
developmentRegion = English;
hasScannedForEncodings = 1;
knownRegions = (
English,
Japanese,
French,
German,
);
mainGroup = 08FB7794FE84155DC02AAC07 /* objc */;
projectDirPath = "";
projectRoot = "";
targets = (
D2AAC0620554660B00DB518D /* objc */,
837F67A81A771F63004D34FA /* objc-simulator */,
);
};
/* End PBXProject section */
/* Begin PBXShellScriptBuildPhase section */
830F2AB60D739AB600392440 /* Run Script (markgc) */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
comments = "Modify the built dylib (mod_init_funcs and mod_term_funcs).";
files = (
);
inputPaths = (
);
name = "Run Script (markgc)";
outputPaths = (
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "set -x\n/usr/bin/xcrun -sdk macosx clang++ -Wall -mmacosx-version-min=10.9 -arch x86_64 -std=c++11 \"${SRCROOT}/markgc.cpp\" -o \"${BUILT_PRODUCTS_DIR}/markgc\"\n\"${BUILT_PRODUCTS_DIR}/markgc\" \"${BUILT_PRODUCTS_DIR}/libobjc.A.dylib\"";
};
830F2AFA0D73BC5800392440 /* Run Script (symlink) */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 8;
files = (
);
inputPaths = (
);
name = "Run Script (symlink)";
outputPaths = (
);
runOnlyForDeploymentPostprocessing = 1;
shellPath = /bin/sh;
shellScript = "cd \"${INSTALL_DIR}\"\n/bin/ln -s libobjc.A.dylib libobjc.dylib\n";
};
/* End PBXShellScriptBuildPhase section */
/* Begin PBXSourcesBuildPhase section */
D2AAC0610554660B00DB518D /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
838485C00D6D687300CEA253 /* hashtable2.mm in Sources */,
838485C40D6D687300CEA253 /* maptable.mm in Sources */,
838485F10D6D68A200CEA253 /* objc-auto.mm in Sources */,
838485F20D6D68A200CEA253 /* objc-cache.mm in Sources */,
838485F30D6D68A200CEA253 /* objc-class-old.mm in Sources */,
838485F50D6D68A200CEA253 /* objc-class.mm in Sources */,
838485F70D6D68A200CEA253 /* objc-errors.mm in Sources */,
838485F90D6D68A200CEA253 /* objc-exception.mm in Sources */,
838485FA0D6D68A200CEA253 /* objc-file.mm in Sources */,
838485FC0D6D68A200CEA253 /* objc-initialize.mm in Sources */,
838485FD0D6D68A200CEA253 /* objc-layout.mm in Sources */,
838485FF0D6D68A200CEA253 /* objc-load.mm in Sources */,
838486010D6D68A200CEA253 /* objc-loadmethod.mm in Sources */,
838486020D6D68A200CEA253 /* objc-lockdebug.mm in Sources */,
838486080D6D68A200CEA253 /* objc-runtime-new.mm in Sources */,
838486090D6D68A200CEA253 /* objc-runtime-old.mm in Sources */,
8384860B0D6D68A200CEA253 /* objc-runtime.mm in Sources */,
8384860D0D6D68A200CEA253 /* objc-sel-set.mm in Sources */,
8384860F0D6D68A200CEA253 /* objc-sel.mm in Sources */,
838486110D6D68A200CEA253 /* objc-sync.mm in Sources */,
838486120D6D68A200CEA253 /* objc-typeencoding.mm in Sources */,
838486150D6D68A200CEA253 /* Object.mm in Sources */,
8384861F0D6D68A800CEA253 /* Protocol.mm in Sources */,
838486250D6D68F000CEA253 /* List.m in Sources */,
830F2A740D737FB800392440 /* objc-msg-arm.s in Sources */,
830F2A750D737FB900392440 /* objc-msg-i386.s in Sources */,
830F2A7D0D737FBB00392440 /* objc-msg-x86_64.s in Sources */,
830F2A950D73876100392440 /* objc-accessors.mm in Sources */,
393CEAC00DC69E3E000B69DE /* objc-references.mm in Sources */,
831C85D60E10CF850066E64C /* objc-os.mm in Sources */,
87BB4EA70EC39854005D08E1 /* objc-probes.d in Sources */,
83BE02E40FCCB23400661494 /* objc-file-old.mm in Sources */,
E8923DA1116AB2820071B552 /* a1a2-blocktramps-i386.s in Sources */,
E8923DA2116AB2820071B552 /* a1a2-blocktramps-x86_64.s in Sources */,
E8923DA3116AB2820071B552 /* a2a3-blocktramps-i386.s in Sources */,
E8923DA4116AB2820071B552 /* a2a3-blocktramps-x86_64.s in Sources */,
E8923DA5116AB2820071B552 /* objc-block-trampolines.mm in Sources */,
83B1A8BE0FF1AC0D0019EA5B /* objc-msg-simulator-i386.s in Sources */,
83EB007B121C9EC200B92C16 /* objc-sel-table.s in Sources */,
8383A3A3122600E9009290B8 /* a1a2-blocktramps-arm.s in Sources */,
8383A3A4122600E9009290B8 /* a2a3-blocktramps-arm.s in Sources */,
39ABD72412F0B61800D1054C /* objc-weak.mm in Sources */,
83D49E4F13C7C84F0057F1DD /* objc-msg-arm64.s in Sources */,
8379996E13CBAF6F007C2B5F /* a1a2-blocktramps-arm64.s in Sources */,
9672F7EE14D5F488007CEC96 /* NSObject.mm in Sources */,
83725F4A14CA5BFA0014370E /* objc-opt.mm in Sources */,
83F550E0155E030800E95D3B /* objc-cache-old.mm in Sources */,
834DF8B715993EE1002F2BC9 /* objc-sel-old.mm in Sources */,
83C9C3391668B50E00F4E544 /* objc-msg-simulator-x86_64.s in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXSourcesBuildPhase section */
/* Begin PBXTargetDependency section */
837F67AD1A771F6E004D34FA /* PBXTargetDependency */ = {
isa = PBXTargetDependency;
target = D2AAC0620554660B00DB518D /* objc */;
targetProxy = 837F67AC1A771F6E004D34FA /* PBXContainerItemProxy */;
};
/* End PBXTargetDependency section */
/* Begin XCBuildConfiguration section */
1DEB914B08733D8E0010E9CD /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
ARCHS = "$(ARCHS_STANDARD_32_64_BIT)";
COPY_PHASE_STRIP = NO;
DYLIB_CURRENT_VERSION = 228;
EXECUTABLE_PREFIX = lib;
GCC_CW_ASM_SYNTAX = NO;
GCC_OPTIMIZATION_LEVEL = 0;
GCC_WARN_ABOUT_DEPRECATED_FUNCTIONS = NO;
HEADER_SEARCH_PATHS = (
"$(DSTROOT)/usr/include/**",
"$(DSTROOT)/usr/local/include/**",
"$(CONFIGURATION_BUILD_DIR)/usr/include/**",
"$(CONFIGURATION_BUILD_DIR)/usr/local/include/**",
/System/Library/Frameworks/System.framework/PrivateHeaders,
);
INSTALL_PATH = /usr/lib;
ORDER_FILE = "$(SDKROOT)/AppleInternal/OrderFiles/libobjc.order";
"ORDER_FILE[sdk=iphonesimulator*]" = "";
OTHER_CFLAGS = (
"-fdollars-in-identifiers",
"$(OTHER_CFLAGS)",
);
"OTHER_LDFLAGS[sdk=iphoneos*][arch=*]" = (
"-lc++abi",
"-Wl,-segalign,0x4000",
"-Xlinker",
"-sectalign",
"-Xlinker",
__DATA,
"-Xlinker",
__objc_data,
"-Xlinker",
0x1000,
);
"OTHER_LDFLAGS[sdk=iphonesimulator*][arch=*]" = "-lc++abi";
"OTHER_LDFLAGS[sdk=macosx*]" = (
"-lCrashReporterClient",
"-lauto",
"-lc++abi",
"-Xlinker",
"-sectalign",
"-Xlinker",
__DATA,
"-Xlinker",
__objc_data,
"-Xlinker",
0x1000,
);
PRIVATE_HEADERS_FOLDER_PATH = /usr/local/include/objc;
PRODUCT_NAME = objc.A;
PUBLIC_HEADERS_FOLDER_PATH = /usr/include/objc;
UNEXPORTED_SYMBOLS_FILE = unexported_symbols;
};
name = Debug;
};
1DEB914C08733D8E0010E9CD /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
DYLIB_CURRENT_VERSION = 228;
EXECUTABLE_PREFIX = lib;
GCC_CW_ASM_SYNTAX = NO;
GCC_WARN_ABOUT_DEPRECATED_FUNCTIONS = NO;
HEADER_SEARCH_PATHS = (
"$(DSTROOT)/usr/include/**",
"$(DSTROOT)/usr/local/include/**",
"$(CONFIGURATION_BUILD_DIR)/usr/include/**",
"$(CONFIGURATION_BUILD_DIR)/usr/local/include/**",
/System/Library/Frameworks/System.framework/PrivateHeaders,
);
INSTALL_PATH = /usr/lib;
ORDER_FILE = "$(SDKROOT)/AppleInternal/OrderFiles/libobjc.order";
"ORDER_FILE[sdk=iphonesimulator*]" = "";
OTHER_CFLAGS = (
"-fdollars-in-identifiers",
"$(OTHER_CFLAGS)",
);
"OTHER_LDFLAGS[sdk=iphoneos*][arch=*]" = (
"-lc++abi",
"-Wl,-segalign,0x4000",
"-Xlinker",
"-sectalign",
"-Xlinker",
__DATA,
"-Xlinker",
__objc_data,
"-Xlinker",
0x1000,
);
"OTHER_LDFLAGS[sdk=iphonesimulator*][arch=*]" = "-lc++abi";
"OTHER_LDFLAGS[sdk=macosx*]" = (
"-lCrashReporterClient",
"-lauto",
"-lc++abi",
"-Xlinker",
"-sectalign",
"-Xlinker",
__DATA,
"-Xlinker",
__objc_data,
"-Xlinker",
0x1000,
);
PRIVATE_HEADERS_FOLDER_PATH = /usr/local/include/objc;
PRODUCT_NAME = objc.A;
PUBLIC_HEADERS_FOLDER_PATH = /usr/include/objc;
UNEXPORTED_SYMBOLS_FILE = unexported_symbols;
};
name = Release;
};
1DEB914F08733D8E0010E9CD /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
CLANG_CXX_LIBRARY = "libc++";
CLANG_LINK_OBJC_RUNTIME = NO;
CLANG_OBJC_RUNTIME = NO;
DEBUG_INFORMATION_FORMAT = dwarf;
EXCLUDED_INSTALLSRC_SUBDIRECTORY_PATTERNS = "$(inherited) test";
GCC_ENABLE_CPP_EXCEPTIONS = NO;
GCC_ENABLE_CPP_RTTI = NO;
GCC_INLINES_ARE_PRIVATE_EXTERN = YES;
GCC_OPTIMIZATION_LEVEL = 0;
GCC_PREPROCESSOR_DEFINITIONS = "OS_OBJECT_USE_OBJC=0";
GCC_STRICT_ALIASING = YES;
GCC_SYMBOLS_PRIVATE_EXTERN = YES;
GCC_VERSION = com.apple.compilers.llvm.clang.1_0;
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
GCC_WARN_ABOUT_INVALID_OFFSETOF_MACRO = NO;
GCC_WARN_ABOUT_MISSING_NEWLINE = YES;
GCC_WARN_ABOUT_RETURN_TYPE = YES;
GCC_WARN_SHADOW = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
OTHER_CFLAGS = "";
"OTHER_CFLAGS[arch=x86_64]" = "-fobjc-legacy-dispatch";
OTHER_CPLUSPLUSFLAGS = (
"$(OTHER_CFLAGS)",
"-D_LIBCPP_VISIBLE=\"\"",
);
WARNING_CFLAGS = (
"-Wall",
"-Wextra",
"-Wstrict-aliasing=2",
"-Wstrict-overflow=4",
"-Wno-unused-parameter",
"-Wno-deprecated-objc-isa-usage",
"-Wno-cast-of-sel-type",
);
};
name = Debug;
};
1DEB915008733D8E0010E9CD /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
CLANG_CXX_LIBRARY = "libc++";
CLANG_LINK_OBJC_RUNTIME = NO;
CLANG_OBJC_RUNTIME = NO;
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
EXCLUDED_INSTALLSRC_SUBDIRECTORY_PATTERNS = "$(inherited) test";
GCC_ENABLE_CPP_EXCEPTIONS = NO;
GCC_ENABLE_CPP_RTTI = NO;
GCC_INLINES_ARE_PRIVATE_EXTERN = YES;
GCC_PREPROCESSOR_DEFINITIONS = (
"OS_OBJECT_USE_OBJC=0",
"NDEBUG=1",
);
GCC_STRICT_ALIASING = YES;
GCC_SYMBOLS_PRIVATE_EXTERN = YES;
GCC_VERSION = com.apple.compilers.llvm.clang.1_0;
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
GCC_WARN_ABOUT_INVALID_OFFSETOF_MACRO = NO;
GCC_WARN_ABOUT_MISSING_NEWLINE = YES;
GCC_WARN_ABOUT_RETURN_TYPE = YES;
GCC_WARN_SHADOW = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
"OTHER_CFLAGS[arch=i386]" = "-momit-leaf-frame-pointer";
"OTHER_CFLAGS[arch=x86_64]" = (
"-momit-leaf-frame-pointer",
"-fobjc-legacy-dispatch",
);
OTHER_CPLUSPLUSFLAGS = (
"$(OTHER_CFLAGS)",
"-D_LIBCPP_VISIBLE=\"\"",
);
WARNING_CFLAGS = (
"-Wall",
"-Wextra",
"-Wstrict-aliasing=2",
"-Wstrict-overflow=4",
"-Wno-unused-parameter",
"-Wno-deprecated-objc-isa-usage",
"-Wno-cast-of-sel-type",
);
};
name = Release;
};
837F67AA1A771F63004D34FA /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
PRODUCT_NAME = "$(TARGET_NAME)";
};
name = Debug;
};
837F67AB1A771F63004D34FA /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
PRODUCT_NAME = "$(TARGET_NAME)";
};
name = Release;
};
/* End XCBuildConfiguration section */
/* Begin XCConfigurationList section */
1DEB914A08733D8E0010E9CD /* Build configuration list for PBXNativeTarget "objc" */ = {
isa = XCConfigurationList;
buildConfigurations = (
1DEB914B08733D8E0010E9CD /* Debug */,
1DEB914C08733D8E0010E9CD /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
1DEB914E08733D8E0010E9CD /* Build configuration list for PBXProject "objc" */ = {
isa = XCConfigurationList;
buildConfigurations = (
1DEB914F08733D8E0010E9CD /* Debug */,
1DEB915008733D8E0010E9CD /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
837F67A91A771F63004D34FA /* Build configuration list for PBXAggregateTarget "objc-simulator" */ = {
isa = XCConfigurationList;
buildConfigurations = (
837F67AA1A771F63004D34FA /* Debug */,
837F67AB1A771F63004D34FA /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
/* End XCConfigurationList section */
};
rootObject = 08FB7793FE84155DC02AAC07 /* Project object */;
}

95
objcrt/objcrt.vcproj Executable file
View File

@ -0,0 +1,95 @@
<?xml version="1.0" encoding="Windows-1252"?>
<VisualStudioProject
ProjectType="Visual C++"
Version="8.00"
Name="objcrt"
ProjectGUID="{E38C1996-8B3D-4050-A4B2-DC85957B047D}"
RootNamespace="objcrt"
>
<Platforms>
<Platform
Name="Win32"
/>
</Platforms>
<ToolFiles>
</ToolFiles>
<Configurations>
<Configuration
Name="Debug|Win32"
OutputDirectory="$(SolutionDir)$(ConfigurationName)"
IntermediateDirectory="$(ConfigurationName)"
ConfigurationType="10"
CharacterSet="2"
>
<Tool
Name="VCPreBuildEventTool"
CommandLine="cl /nologo /c /MDd /D_DEBUG /Od /Zl /DYNAMICBASE /GS /I&quot;%DSTROOT%\AppleInternal\include&quot; /I&quot;%SRCROOT%\AppleInternal\include&quot; /I&quot;$(ProjectDir)\runtime&quot; /D&quot;_WINDOWS&quot; /Dnil=0 ..\runtime\objcrt.c /Fo&quot;$(OutDir)\objcrt_debug.obj"
/>
<Tool
Name="VCCustomBuildTool"
/>
<Tool
Name="VCMIDLTool"
/>
<Tool
Name="VCPostBuildEventTool"
CommandLine="xcopy /Y &quot;$(OutDir)\objcrt_debug.obj&quot; &quot;%DSTROOT%\AppleInternal\lib&quot;"
/>
</Configuration>
<Configuration
Name="Release|Win32"
OutputDirectory="$(SolutionDir)$(ConfigurationName)"
IntermediateDirectory="$(ConfigurationName)"
ConfigurationType="10"
CharacterSet="2"
WholeProgramOptimization="1"
>
<Tool
Name="VCPreBuildEventTool"
CommandLine="cl /nologo /c /MD /O1 /Zi /MP2 /DYNAMICBASE /GS /I&quot;%DSTROOT%\AppleInternal\include&quot; /I&quot;%SRCROOT%\AppleInternal\include&quot; /I&quot;$(ProjectDir)\..\runtime&quot; /D&quot;_WINDOWS&quot; /Dnil=0 ..\runtime\objcrt.c /Fo&quot;$(OutDir)\objcrt.obj"
/>
<Tool
Name="VCCustomBuildTool"
/>
<Tool
Name="VCMIDLTool"
/>
<Tool
Name="VCPostBuildEventTool"
CommandLine="xcopy /Y &quot;$(OutDir)\objcrt.obj&quot; &quot;%DSTROOT%\AppleInternal\lib&quot;"
/>
</Configuration>
</Configurations>
<References>
</References>
<Files>
<Filter
Name="Source Files"
Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx"
UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"
>
<File
RelativePath="..\runtime\objcrt.c"
>
</File>
</Filter>
<Filter
Name="Header Files"
Filter="h;hpp;hxx;hm;inl;inc;xsd"
UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"
>
<File
RelativePath="..\runtime\objcrt.h"
>
</File>
</Filter>
<Filter
Name="Resource Files"
Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav"
UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}"
>
</Filter>
</Files>
<Globals>
</Globals>
</VisualStudioProject>

15
prebuild.bat Executable file
View File

@ -0,0 +1,15 @@
@echo off
echo prebuild: installing headers
xcopy /Y "%ProjectDir%runtime\objc.h" "%DSTROOT%\AppleInternal\include\objc\"
xcopy /Y "%ProjectDir%runtime\objc-api.h" "%DSTROOT%\AppleInternal\include\objc\"
xcopy /Y "%ProjectDir%runtime\objc-auto.h" "%DSTROOT%\AppleInternal\include\objc\"
xcopy /Y "%ProjectDir%runtime\objc-exception.h" "%DSTROOT%\AppleInternal\include\objc\"
xcopy /Y "%ProjectDir%runtime\message.h" "%DSTROOT%\AppleInternal\include\objc\"
xcopy /Y "%ProjectDir%runtime\runtime.h" "%DSTROOT%\AppleInternal\include\objc\"
xcopy /Y "%ProjectDir%runtime\hashtable.h" "%DSTROOT%\AppleInternal\include\objc\"
xcopy /Y "%ProjectDir%runtime\hashtable2.h" "%DSTROOT%\AppleInternal\include\objc\"
xcopy /Y "%ProjectDir%runtime\maptable.h" "%DSTROOT%\AppleInternal\include\objc\"
echo prebuild: setting version
version

View File

@ -0,0 +1,911 @@
/*
* @APPLE_LICENSE_HEADER_START@
*
* Copyright (c) 1999-2007 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 2.0 (the 'License'). You may not use this file except in
* compliance with the License. Please obtain a copy of the License at
* http://www.opensource.apple.com/apsl/ 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, QUIET ENJOYMENT OR NON-INFRINGEMENT.
* Please see the License for the specific language governing rights and
* limitations under the License.
*
* @APPLE_LICENSE_HEADER_END@
*/
/********************************************************************
*
* objc-msg-arm.s - ARM code to support objc messaging
*
********************************************************************/
#ifdef __arm__
#include <arm/arch.h>
#ifndef _ARM_ARCH_7
# error requires armv7
#endif
// Set FP=1 on architectures that pass parameters in floating-point registers
#if __ARM_ARCH_7K__
# define FP 1
#else
# define FP 0
#endif
#if FP
# if !__ARM_NEON__
# error sorry
# endif
# define FP_RETURN_ZERO \
vmov.i32 q0, #0 ; \
vmov.i32 q1, #0 ; \
vmov.i32 q2, #0 ; \
vmov.i32 q3, #0
# define FP_SAVE \
vpush {q0-q3}
# define FP_RESTORE \
vpop {q0-q3}
#else
# define FP_RETURN_ZERO
# define FP_SAVE
# define FP_RESTORE
#endif
// Define SUPPORT_INDEXED_ISA for targets which store the class in the ISA as
// an index in to a class table.
// Note, keep this in sync with objc-config.h.
// FIXME: Remove this duplication. We should get this from objc-config.h.
#if __ARM_ARCH_7K__ >= 2
# define SUPPORT_INDEXED_ISA 1
#else
# define SUPPORT_INDEXED_ISA 0
#endif
// Note, keep these in sync with objc-private.h
#define ISA_INDEX_IS_NPI 1
#define ISA_INDEX_MASK 0x0001FFFC
#define ISA_INDEX_SHIFT 2
#define ISA_INDEX_BITS 15
#define ISA_INDEX_COUNT (1 << ISA_INDEX_BITS)
#define ISA_INDEX_MAGIC_MASK 0x001E0001
#define ISA_INDEX_MAGIC_VALUE 0x001C0001
.syntax unified
#define MI_EXTERN(var) \
.non_lazy_symbol_pointer ;\
L##var##$$non_lazy_ptr: ;\
.indirect_symbol var ;\
.long 0
#define MI_GET_EXTERN(reg,var) \
movw reg, :lower16:(L##var##$$non_lazy_ptr-7f-4) ;\
movt reg, :upper16:(L##var##$$non_lazy_ptr-7f-4) ;\
7: add reg, pc ;\
ldr reg, [reg]
#define MI_GET_ADDRESS(reg,var) \
movw reg, :lower16:(var-7f-4) ;\
movt reg, :upper16:(var-7f-4) ;\
7: add reg, pc ;\
.data
#if SUPPORT_INDEXED_ISA
.align 2
.globl _objc_indexed_classes
_objc_indexed_classes:
.fill ISA_INDEX_COUNT, 4, 0
#endif
// _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
// that do cache lookups. The tables are zero-terminated.
.align 2
.private_extern _objc_entryPoints
_objc_entryPoints:
.long _cache_getImp
.long _objc_msgSend
.long _objc_msgSend_stret
.long _objc_msgSendSuper
.long _objc_msgSendSuper_stret
.long _objc_msgSendSuper2
.long _objc_msgSendSuper2_stret
.long _objc_msgLookup
.long _objc_msgLookup_stret
.long _objc_msgLookupSuper2
.long _objc_msgLookupSuper2_stret
.long 0
.private_extern _objc_exitPoints
_objc_exitPoints:
.long LExit_cache_getImp
.long LExit_objc_msgSend
.long LExit_objc_msgSend_stret
.long LExit_objc_msgSendSuper
.long LExit_objc_msgSendSuper_stret
.long LExit_objc_msgSendSuper2
.long LExit_objc_msgSendSuper2_stret
.long LExit_objc_msgLookup
.long LExit_objc_msgLookup_stret
.long LExit_objc_msgLookupSuper2
.long LExit_objc_msgLookupSuper2_stret
.long 0
/********************************************************************
* List every exit insn from every messenger for debugger use.
* Format:
* (
* 1 word instruction's address
* 1 word type (ENTER or FAST_EXIT or SLOW_EXIT or NIL_EXIT)
* )
* 1 word zero
*
* ENTER is the start of a dispatcher
* FAST_EXIT is method dispatch
* SLOW_EXIT is uncached method lookup
* NIL_EXIT is returning zero from a message sent to nil
* These must match objc-gdb.h.
********************************************************************/
#define ENTER 1
#define FAST_EXIT 2
#define SLOW_EXIT 3
#define NIL_EXIT 4
.section __DATA,__objc_msg_break
.globl _gdb_objc_messenger_breakpoints
_gdb_objc_messenger_breakpoints:
// contents populated by the macros below
.macro MESSENGER_START
7:
.section __DATA,__objc_msg_break
.long 7b
.long ENTER
.text
.endmacro
.macro MESSENGER_END_FAST
7:
.section __DATA,__objc_msg_break
.long 7b
.long FAST_EXIT
.text
.endmacro
.macro MESSENGER_END_SLOW
7:
.section __DATA,__objc_msg_break
.long 7b
.long SLOW_EXIT
.text
.endmacro
.macro MESSENGER_END_NIL
7:
.section __DATA,__objc_msg_break
.long 7b
.long NIL_EXIT
.text
.endmacro
/********************************************************************
* Names for relative labels
* DO NOT USE THESE LABELS ELSEWHERE
* Reserved labels: 6: 7: 8: 9:
********************************************************************/
// 6: used by CacheLookup
// 7: used by MI_GET_ADDRESS etc and MESSENGER_START etc
// 8: used by CacheLookup
#define LNilReceiver 9
#define LNilReceiver_f 9f
#define LNilReceiver_b 9b
/********************************************************************
* Macro parameters
********************************************************************/
#define NORMAL 0
#define STRET 1
/********************************************************************
*
* Structure definitions.
*
********************************************************************/
/* objc_super parameter to sendSuper */
#define RECEIVER 0
#define CLASS 4
/* Selected field offsets in class structure */
#define ISA 0
#define SUPERCLASS 4
#define CACHE 8
#define CACHE_MASK 12
/* Selected field offsets in method structure */
#define METHOD_NAME 0
#define METHOD_TYPES 4
#define METHOD_IMP 8
//////////////////////////////////////////////////////////////////////
//
// ENTRY functionName
//
// Assembly directives to begin an exported function.
//
// Takes: functionName - name of the exported function
//////////////////////////////////////////////////////////////////////
.macro ENTRY /* name */
.text
.thumb
.align 5
.globl $0
.thumb_func
$0:
.endmacro
.macro STATIC_ENTRY /*name*/
.text
.thumb
.align 5
.private_extern $0
.thumb_func
$0:
.endmacro
//////////////////////////////////////////////////////////////////////
//
// END_ENTRY functionName
//
// Assembly directives to end an exported function. Just a placeholder,
// a close-parenthesis for ENTRY, until it is needed for something.
//
// Takes: functionName - name of the exported function
//////////////////////////////////////////////////////////////////////
.macro END_ENTRY /* name */
LExit$0:
.endmacro
/////////////////////////////////////////////////////////////////////
//
// CacheLookup NORMAL|STRET
// CacheLookup2 NORMAL|STRET
//
// Locate the implementation for a selector in a class's method cache.
//
// Takes:
// $0 = NORMAL, STRET
// r0 or r1 (STRET) = receiver
// r1 or r2 (STRET) = selector
// r9 = class to search in
//
// On exit: r9 clobbered
// (found) continues after CacheLookup, IMP in r12, eq set
// (not found) continues after CacheLookup2
//
/////////////////////////////////////////////////////////////////////
.macro CacheLookup
ldrh r12, [r9, #CACHE_MASK] // r12 = mask
ldr r9, [r9, #CACHE] // r9 = buckets
.if $0 == STRET
and r12, r12, r2 // r12 = index = SEL & mask
.else
and r12, r12, r1 // r12 = index = SEL & mask
.endif
add r9, r9, r12, LSL #3 // r9 = bucket = buckets+index*8
ldr r12, [r9] // r12 = bucket->sel
6:
.if $0 == STRET
teq r12, r2
.else
teq r12, r1
.endif
bne 8f
ldr r12, [r9, #4] // r12 = bucket->imp
.if $0 == STRET
tst r12, r12 // set ne for stret forwarding
.else
// eq already set for nonstret forwarding by `teq` above
.endif
.endmacro
.macro CacheLookup2
8:
cmp r12, #1
blo 8f // if (bucket->sel == 0) cache miss
it eq // if (bucket->sel == 1) cache wrap
ldreq r9, [r9, #4] // bucket->imp is before first bucket
ldr r12, [r9, #8]! // r12 = (++bucket)->sel
b 6b
8:
.endmacro
/////////////////////////////////////////////////////////////////////
//
// GetClassFromIsa return-type
//
// Given an Isa, return the class for the Isa.
//
// Takes:
// r9 = class
//
// On exit: r12 clobbered
// r9 contains the class for this Isa.
//
/////////////////////////////////////////////////////////////////////
.macro GetClassFromIsa
#if SUPPORT_INDEXED_ISA
// Note: We are doing a little wasted work here to load values we might not
// need. Branching turns out to be even worse when performance was measured.
MI_GET_ADDRESS(r12, _objc_indexed_classes)
tst.w r9, #ISA_INDEX_IS_NPI
itt ne
ubfxne r9, r9, #ISA_INDEX_SHIFT, #ISA_INDEX_BITS
ldrne.w r9, [r12, r9, lsl #2]
#endif
.endmacro
/********************************************************************
* IMP cache_getImp(Class cls, SEL sel)
*
* On entry: r0 = class whose cache is to be searched
* r1 = selector to search for
*
* If found, returns method implementation.
* If not found, returns NULL.
********************************************************************/
STATIC_ENTRY _cache_getImp
mov r9, r0
CacheLookup NORMAL
// cache hit, IMP in r12
mov r0, r12
bx lr // return imp
CacheLookup2 GETIMP
// cache miss, return nil
mov r0, #0
bx lr
END_ENTRY _cache_getImp
/********************************************************************
*
* id objc_msgSend(id self, SEL _cmd, ...);
* IMP objc_msgLookup(id self, SEL _cmd, ...);
*
* objc_msgLookup ABI:
* IMP returned in r12
* Forwarding returned in Z flag
* r9 reserved for our use but not used
*
********************************************************************/
ENTRY _objc_msgSend
MESSENGER_START
cbz r0, LNilReceiver_f
ldr r9, [r0] // r9 = self->isa
GetClassFromIsa // r9 = class
CacheLookup NORMAL
// cache hit, IMP in r12, eq already set for nonstret forwarding
MESSENGER_END_FAST
bx r12 // call imp
CacheLookup2 NORMAL
// cache miss
ldr r9, [r0] // r9 = self->isa
GetClassFromIsa // r9 = class
MESSENGER_END_SLOW
b __objc_msgSend_uncached
LNilReceiver:
// r0 is already zero
mov r1, #0
mov r2, #0
mov r3, #0
FP_RETURN_ZERO
MESSENGER_END_NIL
bx lr
END_ENTRY _objc_msgSend
ENTRY _objc_msgLookup
cbz r0, LNilReceiver_f
ldr r9, [r0] // r9 = self->isa
GetClassFromIsa // r9 = class
CacheLookup NORMAL
// cache hit, IMP in r12, eq already set for nonstret forwarding
bx lr
CacheLookup2 NORMAL
// cache miss
ldr r9, [r0] // r9 = self->isa
GetClassFromIsa // r9 = class
b __objc_msgLookup_uncached
LNilReceiver:
MI_GET_ADDRESS(r12, __objc_msgNil)
bx lr
END_ENTRY _objc_msgLookup
STATIC_ENTRY __objc_msgNil
// r0 is already zero
mov r1, #0
mov r2, #0
mov r3, #0
FP_RETURN_ZERO
bx lr
END_ENTRY __objc_msgNil
/********************************************************************
* void objc_msgSend_stret(void *st_addr, id self, SEL op, ...);
* IMP objc_msgLookup_stret(void *st_addr, id self, SEL op, ...);
*
* objc_msgSend_stret is the struct-return form of msgSend.
* The ABI calls for r0 to be used as the address of the structure
* being returned, with the parameters in the succeeding registers.
*
* On entry: r0 is the address where the structure is returned,
* r1 is the message receiver,
* r2 is the selector
********************************************************************/
ENTRY _objc_msgSend_stret
MESSENGER_START
cbz r1, LNilReceiver_f
ldr r9, [r1] // r9 = self->isa
GetClassFromIsa // r9 = class
CacheLookup STRET
// cache hit, IMP in r12, ne already set for stret forwarding
MESSENGER_END_FAST
bx r12
CacheLookup2 STRET
// cache miss
ldr r9, [r1] // r9 = self->isa
GetClassFromIsa // r9 = class
MESSENGER_END_SLOW
b __objc_msgSend_stret_uncached
LNilReceiver:
MESSENGER_END_NIL
bx lr
END_ENTRY _objc_msgSend_stret
ENTRY _objc_msgLookup_stret
cbz r1, LNilReceiver_f
ldr r9, [r1] // r9 = self->isa
GetClassFromIsa // r9 = class
CacheLookup STRET
// cache hit, IMP in r12, ne already set for stret forwarding
bx lr
CacheLookup2 STRET
// cache miss
ldr r9, [r1] // r9 = self->isa
GetClassFromIsa // r9 = class
b __objc_msgLookup_stret_uncached
LNilReceiver:
MI_GET_ADDRESS(r12, __objc_msgNil_stret)
bx lr
END_ENTRY _objc_msgLookup_stret
STATIC_ENTRY __objc_msgNil_stret
bx lr
END_ENTRY __objc_msgNil_stret
/********************************************************************
* id objc_msgSendSuper(struct objc_super *super, SEL op, ...)
*
* struct objc_super {
* id receiver;
* Class cls; // the class to search
* }
********************************************************************/
ENTRY _objc_msgSendSuper
MESSENGER_START
ldr r9, [r0, #CLASS] // r9 = struct super->class
CacheLookup NORMAL
// cache hit, IMP in r12, eq already set for nonstret forwarding
ldr r0, [r0, #RECEIVER] // load real receiver
MESSENGER_END_FAST
bx r12 // call imp
CacheLookup2 NORMAL
// cache miss
ldr r9, [r0, #CLASS] // r9 = struct super->class
ldr r0, [r0, #RECEIVER] // load real receiver
MESSENGER_END_SLOW
b __objc_msgSend_uncached
END_ENTRY _objc_msgSendSuper
/********************************************************************
* id objc_msgSendSuper2(struct objc_super *super, SEL op, ...)
*
* struct objc_super {
* id receiver;
* Class cls; // SUBCLASS of the class to search
* }
********************************************************************/
ENTRY _objc_msgSendSuper2
MESSENGER_START
ldr r9, [r0, #CLASS] // class = struct super->class
ldr r9, [r9, #SUPERCLASS] // class = class->superclass
CacheLookup NORMAL
// cache hit, IMP in r12, eq already set for nonstret forwarding
ldr r0, [r0, #RECEIVER] // load real receiver
MESSENGER_END_FAST
bx r12 // call imp
CacheLookup2 NORMAL
// cache miss
ldr r9, [r0, #CLASS] // class = struct super->class
ldr r9, [r9, #SUPERCLASS] // class = class->superclass
ldr r0, [r0, #RECEIVER] // load real receiver
MESSENGER_END_SLOW
b __objc_msgSend_uncached
END_ENTRY _objc_msgSendSuper2
ENTRY _objc_msgLookupSuper2
ldr r9, [r0, #CLASS] // class = struct super->class
ldr r9, [r9, #SUPERCLASS] // class = class->superclass
CacheLookup NORMAL
// cache hit, IMP in r12, eq already set for nonstret forwarding
ldr r0, [r0, #RECEIVER] // load real receiver
bx lr
CacheLookup2 NORMAL
// cache miss
ldr r9, [r0, #CLASS]
ldr r9, [r9, #SUPERCLASS] // r9 = class to search
ldr r0, [r0, #RECEIVER] // load real receiver
b __objc_msgLookup_uncached
END_ENTRY _objc_msgLookupSuper2
/********************************************************************
* void objc_msgSendSuper_stret(void *st_addr, objc_super *self, SEL op, ...);
*
* objc_msgSendSuper_stret is the struct-return form of msgSendSuper.
* The ABI calls for r0 to be used as the address of the structure
* being returned, with the parameters in the succeeding registers.
*
* On entry: r0 is the address where the structure is returned,
* r1 is the address of the objc_super structure,
* r2 is the selector
********************************************************************/
ENTRY _objc_msgSendSuper_stret
MESSENGER_START
ldr r9, [r1, #CLASS] // r9 = struct super->class
CacheLookup STRET
// cache hit, IMP in r12, ne already set for stret forwarding
ldr r1, [r1, #RECEIVER] // load real receiver
MESSENGER_END_FAST
bx r12 // call imp
CacheLookup2 STRET
// cache miss
ldr r9, [r1, #CLASS] // r9 = struct super->class
ldr r1, [r1, #RECEIVER] // load real receiver
MESSENGER_END_SLOW
b __objc_msgSend_stret_uncached
END_ENTRY _objc_msgSendSuper_stret
/********************************************************************
* id objc_msgSendSuper2_stret
********************************************************************/
ENTRY _objc_msgSendSuper2_stret
MESSENGER_START
ldr r9, [r1, #CLASS] // class = struct super->class
ldr r9, [r9, #SUPERCLASS] // class = class->superclass
CacheLookup STRET
// cache hit, IMP in r12, ne already set for stret forwarding
ldr r1, [r1, #RECEIVER] // load real receiver
MESSENGER_END_FAST
bx r12 // call imp
CacheLookup2 STRET
// cache miss
ldr r9, [r1, #CLASS] // class = struct super->class
ldr r9, [r9, #SUPERCLASS] // class = class->superclass
ldr r1, [r1, #RECEIVER] // load real receiver
MESSENGER_END_SLOW
b __objc_msgSend_stret_uncached
END_ENTRY _objc_msgSendSuper2_stret
ENTRY _objc_msgLookupSuper2_stret
ldr r9, [r1, #CLASS] // class = struct super->class
ldr r9, [r9, #SUPERCLASS] // class = class->superclass
CacheLookup STRET
// cache hit, IMP in r12, ne already set for stret forwarding
ldr r1, [r1, #RECEIVER] // load real receiver
bx lr
CacheLookup2 STRET
// cache miss
ldr r9, [r1, #CLASS]
ldr r9, [r9, #SUPERCLASS] // r9 = class to search
ldr r1, [r1, #RECEIVER] // load real receiver
b __objc_msgLookup_stret_uncached
END_ENTRY _objc_msgLookupSuper2_stret
/////////////////////////////////////////////////////////////////////
//
// MethodTableLookup NORMAL|STRET
//
// Locate the implementation for a selector in a class's method lists.
//
// Takes:
// $0 = NORMAL, STRET
// r0 or r1 (STRET) = receiver
// r1 or r2 (STRET) = selector
// r9 = class to search in
//
// On exit: IMP in r12, eq/ne set for forwarding
//
/////////////////////////////////////////////////////////////////////
.macro MethodTableLookup
stmfd sp!, {r0-r3,r7,lr}
add r7, sp, #16
sub sp, #8 // align stack
FP_SAVE
.if $0 == NORMAL
// receiver already in r0
// selector already in r1
.else
mov r0, r1 // receiver
mov r1, r2 // selector
.endif
mov r2, r9 // class to search
blx __class_lookupMethodAndLoadCache3
mov r12, r0 // r12 = IMP
.if $0 == NORMAL
cmp r12, r12 // set eq for nonstret forwarding
.else
tst r12, r12 // set ne for stret forwarding
.endif
FP_RESTORE
add sp, #8 // align stack
ldmfd sp!, {r0-r3,r7,lr}
.endmacro
/********************************************************************
*
* _objc_msgSend_uncached
* _objc_msgSend_stret_uncached
* _objc_msgLookup_uncached
* _objc_msgLookup_stret_uncached
* The uncached method lookup.
*
********************************************************************/
STATIC_ENTRY __objc_msgSend_uncached
// THIS IS NOT A CALLABLE C FUNCTION
// Out-of-band r9 is the class to search
MethodTableLookup NORMAL // returns IMP in r12
bx r12
END_ENTRY __objc_msgSend_uncached
STATIC_ENTRY __objc_msgSend_stret_uncached
// THIS IS NOT A CALLABLE C FUNCTION
// Out-of-band r9 is the class to search
MethodTableLookup STRET // returns IMP in r12
bx r12
END_ENTRY __objc_msgSend_stret_uncached
STATIC_ENTRY __objc_msgLookup_uncached
// THIS IS NOT A CALLABLE C FUNCTION
// Out-of-band r9 is the class to search
MethodTableLookup NORMAL // returns IMP in r12
bx lr
END_ENTRY __objc_msgLookup_uncached
STATIC_ENTRY __objc_msgLookup_stret_uncached
// THIS IS NOT A CALLABLE C FUNCTION
// Out-of-band r9 is the class to search
MethodTableLookup STRET // returns IMP in r12
bx lr
END_ENTRY __objc_msgLookup_stret_uncached
/********************************************************************
*
* id _objc_msgForward(id self, SEL _cmd,...);
*
* _objc_msgForward and _objc_msgForward_stret are the externally-callable
* functions returned by things like method_getImplementation().
* _objc_msgForward_impcache is the function pointer actually stored in
* method caches.
*
********************************************************************/
MI_EXTERN(__objc_forward_handler)
MI_EXTERN(__objc_forward_stret_handler)
STATIC_ENTRY __objc_msgForward_impcache
// Method cache version
// THIS IS NOT A CALLABLE C FUNCTION
// Out-of-band Z is 0 (EQ) for normal, 1 (NE) for stret
MESSENGER_START
nop
MESSENGER_END_SLOW
beq __objc_msgForward
b __objc_msgForward_stret
END_ENTRY __objc_msgForward_impcache
ENTRY __objc_msgForward
// Non-stret version
MI_GET_EXTERN(r12, __objc_forward_handler)
ldr r12, [r12]
bx r12
END_ENTRY __objc_msgForward
ENTRY __objc_msgForward_stret
// Struct-return version
MI_GET_EXTERN(r12, __objc_forward_stret_handler)
ldr r12, [r12]
bx r12
END_ENTRY __objc_msgForward_stret
ENTRY _objc_msgSend_noarg
b _objc_msgSend
END_ENTRY _objc_msgSend_noarg
ENTRY _objc_msgSend_debug
b _objc_msgSend
END_ENTRY _objc_msgSend_debug
ENTRY _objc_msgSendSuper2_debug
b _objc_msgSendSuper2
END_ENTRY _objc_msgSendSuper2_debug
ENTRY _objc_msgSend_stret_debug
b _objc_msgSend_stret
END_ENTRY _objc_msgSend_stret_debug
ENTRY _objc_msgSendSuper2_stret_debug
b _objc_msgSendSuper2_stret
END_ENTRY _objc_msgSendSuper2_stret_debug
ENTRY _method_invoke
// r1 is method triplet instead of SEL
ldr r12, [r1, #METHOD_IMP]
ldr r1, [r1, #METHOD_NAME]
bx r12
END_ENTRY _method_invoke
ENTRY _method_invoke_stret
// r2 is method triplet instead of SEL
ldr r12, [r2, #METHOD_IMP]
ldr r2, [r2, #METHOD_NAME]
bx r12
END_ENTRY _method_invoke_stret
.section __DATA,__objc_msg_break
.long 0
.long 0
#endif

View File

@ -0,0 +1,561 @@
/*
* @APPLE_LICENSE_HEADER_START@
*
* Copyright (c) 2011 Apple 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 2.0 (the 'License'). You may not use this file except in
* compliance with the License. Please obtain a copy of the License at
* http://www.opensource.apple.com/apsl/ 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, QUIET ENJOYMENT OR NON-INFRINGEMENT.
* Please see the License for the specific language governing rights and
* limitations under the License.
*
* @APPLE_LICENSE_HEADER_END@
*/
/********************************************************************
*
* objc-msg-arm64.s - ARM64 code to support objc messaging
*
********************************************************************/
#ifdef __arm64__
#include <arm/arch.h>
.data
// _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
// that do cache lookups. The tables are zero-terminated.
.align 4
.private_extern _objc_entryPoints
_objc_entryPoints:
.quad _cache_getImp
.quad _objc_msgSend
.quad _objc_msgSendSuper
.quad _objc_msgSendSuper2
.quad _objc_msgLookup
.quad _objc_msgLookupSuper2
.quad 0
.private_extern _objc_exitPoints
_objc_exitPoints:
.quad LExit_cache_getImp
.quad LExit_objc_msgSend
.quad LExit_objc_msgSendSuper
.quad LExit_objc_msgSendSuper2
.quad LExit_objc_msgLookup
.quad LExit_objc_msgLookupSuper2
.quad 0
/********************************************************************
* List every exit insn from every messenger for debugger use.
* Format:
* (
* 1 word instruction's address
* 1 word type (ENTER or FAST_EXIT or SLOW_EXIT or NIL_EXIT)
* )
* 1 word zero
*
* ENTER is the start of a dispatcher
* FAST_EXIT is method dispatch
* SLOW_EXIT is uncached method lookup
* NIL_EXIT is returning zero from a message sent to nil
* These must match objc-gdb.h.
********************************************************************/
#define ENTER 1
#define FAST_EXIT 2
#define SLOW_EXIT 3
#define NIL_EXIT 4
.section __DATA,__objc_msg_break
.globl _gdb_objc_messenger_breakpoints
_gdb_objc_messenger_breakpoints:
// contents populated by the macros below
.macro MESSENGER_START
4:
.section __DATA,__objc_msg_break
.quad 4b
.quad ENTER
.text
.endmacro
.macro MESSENGER_END_FAST
4:
.section __DATA,__objc_msg_break
.quad 4b
.quad FAST_EXIT
.text
.endmacro
.macro MESSENGER_END_SLOW
4:
.section __DATA,__objc_msg_break
.quad 4b
.quad SLOW_EXIT
.text
.endmacro
.macro MESSENGER_END_NIL
4:
.section __DATA,__objc_msg_break
.quad 4b
.quad NIL_EXIT
.text
.endmacro
/* objc_super parameter to sendSuper */
#define RECEIVER 0
#define CLASS 8
/* Selected field offsets in class structure */
#define SUPERCLASS 8
#define CACHE 16
/* Selected field offsets in isa field */
#define ISA_MASK 0x0000000ffffffff8
/* Selected field offsets in method structure */
#define METHOD_NAME 0
#define METHOD_TYPES 8
#define METHOD_IMP 16
/********************************************************************
* ENTRY functionName
* STATIC_ENTRY functionName
* END_ENTRY functionName
********************************************************************/
.macro ENTRY /* name */
.text
.align 5
.globl $0
$0:
.endmacro
.macro STATIC_ENTRY /*name*/
.text
.align 5
.private_extern $0
$0:
.endmacro
.macro END_ENTRY /* name */
LExit$0:
.endmacro
/********************************************************************
* UNWIND name, flags
* Unwind info generation
********************************************************************/
.macro UNWIND
.section __LD,__compact_unwind,regular,debug
.quad $0
.set LUnwind$0, LExit$0 - $0
.long LUnwind$0
.long $1
.quad 0 /* no personality */
.quad 0 /* no LSDA */
.text
.endmacro
#define NoFrame 0x02000000 // no frame, no SP adjustment
#define FrameWithNoSaves 0x04000000 // frame, no non-volatile saves
/********************************************************************
*
* CacheLookup NORMAL|GETIMP|LOOKUP
*
* Locate the implementation for a selector in a class method cache.
*
* Takes:
* x1 = selector
* x16 = class to be searched
*
* Kills:
* x9,x10,x11,x12, x17
*
* On exit: (found) calls or returns IMP
* with x16 = class, x17 = IMP
* (not found) jumps to LCacheMiss
*
********************************************************************/
#define NORMAL 0
#define GETIMP 1
#define LOOKUP 2
.macro CacheHit
.if $0 == NORMAL
MESSENGER_END_FAST
br x17 // call imp
.elseif $0 == GETIMP
mov x0, x17 // return imp
ret
.elseif $0 == LOOKUP
ret // return imp via x17
.else
.abort oops
.endif
.endmacro
.macro CheckMiss
// miss if bucket->sel == 0
.if $0 == GETIMP
cbz x9, LGetImpMiss
.elseif $0 == NORMAL
cbz x9, __objc_msgSend_uncached
.elseif $0 == LOOKUP
cbz x9, __objc_msgLookup_uncached
.else
.abort oops
.endif
.endmacro
.macro JumpMiss
.if $0 == GETIMP
b LGetImpMiss
.elseif $0 == NORMAL
b __objc_msgSend_uncached
.elseif $0 == LOOKUP
b __objc_msgLookup_uncached
.else
.abort oops
.endif
.endmacro
.macro CacheLookup
// x1 = SEL, x16 = isa
ldp x10, x11, [x16, #CACHE] // x10 = buckets, x11 = occupied|mask
and w12, w1, w11 // x12 = _cmd & mask
add x12, x10, x12, LSL #4 // x12 = buckets + ((_cmd & mask)<<4)
ldp x9, x17, [x12] // {x9, x17} = *bucket
1: cmp x9, x1 // if (bucket->sel != _cmd)
b.ne 2f // scan more
CacheHit $0 // call or return imp
2: // not hit: x12 = not-hit bucket
CheckMiss $0 // miss if bucket->sel == 0
cmp x12, x10 // wrap if bucket == buckets
b.eq 3f
ldp x9, x17, [x12, #-16]! // {x9, x17} = *--bucket
b 1b // loop
3: // wrap: x12 = first bucket, w11 = mask
add x12, x12, w11, UXTW #4 // x12 = buckets+(mask<<4)
// Clone scanning loop to miss instead of hang when cache is corrupt.
// The slow path may detect any corruption and halt later.
ldp x9, x17, [x12] // {x9, x17} = *bucket
1: cmp x9, x1 // if (bucket->sel != _cmd)
b.ne 2f // scan more
CacheHit $0 // call or return imp
2: // not hit: x12 = not-hit bucket
CheckMiss $0 // miss if bucket->sel == 0
cmp x12, x10 // wrap if bucket == buckets
b.eq 3f
ldp x9, x17, [x12, #-16]! // {x9, x17} = *--bucket
b 1b // loop
3: // double wrap
JumpMiss $0
.endmacro
/********************************************************************
*
* id objc_msgSend(id self, SEL _cmd, ...);
* IMP objc_msgLookup(id self, SEL _cmd, ...);
*
* objc_msgLookup ABI:
* IMP returned in x17
* x16 reserved for our use but not used
*
********************************************************************/
.data
.align 3
.globl _objc_debug_taggedpointer_classes
_objc_debug_taggedpointer_classes:
.fill 16, 8, 0
.globl _objc_debug_taggedpointer_ext_classes
_objc_debug_taggedpointer_ext_classes:
.fill 256, 8, 0
ENTRY _objc_msgSend
UNWIND _objc_msgSend, NoFrame
MESSENGER_START
cmp x0, #0 // nil check and tagged pointer check
b.le LNilOrTagged // (MSB tagged pointer looks negative)
ldr x13, [x0] // x13 = isa
and x16, x13, #ISA_MASK // x16 = class
LGetIsaDone:
CacheLookup NORMAL // calls imp or objc_msgSend_uncached
LNilOrTagged:
b.eq LReturnZero // nil check
// tagged
mov x10, #0xf000000000000000
cmp x0, x10
b.hs LExtTag
adrp x10, _objc_debug_taggedpointer_classes@PAGE
add x10, x10, _objc_debug_taggedpointer_classes@PAGEOFF
ubfx x11, x0, #60, #4
ldr x16, [x10, x11, LSL #3]
b LGetIsaDone
LExtTag:
// ext tagged
adrp x10, _objc_debug_taggedpointer_ext_classes@PAGE
add x10, x10, _objc_debug_taggedpointer_ext_classes@PAGEOFF
ubfx x11, x0, #52, #8
ldr x16, [x10, x11, LSL #3]
b LGetIsaDone
LReturnZero:
// x0 is already zero
mov x1, #0
movi d0, #0
movi d1, #0
movi d2, #0
movi d3, #0
MESSENGER_END_NIL
ret
END_ENTRY _objc_msgSend
ENTRY _objc_msgLookup
UNWIND _objc_msgLookup, NoFrame
cmp x0, #0 // nil check and tagged pointer check
b.le LLookup_NilOrTagged // (MSB tagged pointer looks negative)
ldr x13, [x0] // x13 = isa
and x16, x13, #ISA_MASK // x16 = class
LLookup_GetIsaDone:
CacheLookup LOOKUP // returns imp
LLookup_NilOrTagged:
b.eq LLookup_Nil // nil check
// tagged
mov x10, #0xf000000000000000
cmp x0, x10
b.hs LLookup_ExtTag
adrp x10, _objc_debug_taggedpointer_classes@PAGE
add x10, x10, _objc_debug_taggedpointer_classes@PAGEOFF
ubfx x11, x0, #60, #4
ldr x16, [x10, x11, LSL #3]
b LLookup_GetIsaDone
LLookup_ExtTag:
adrp x10, _objc_debug_taggedpointer_ext_classes@PAGE
add x10, x10, _objc_debug_taggedpointer_ext_classes@PAGEOFF
ubfx x11, x0, #52, #8
ldr x16, [x10, x11, LSL #3]
b LLookup_GetIsaDone
LLookup_Nil:
adrp x17, __objc_msgNil@PAGE
add x17, x17, __objc_msgNil@PAGEOFF
ret
END_ENTRY _objc_msgLookup
STATIC_ENTRY __objc_msgNil
// x0 is already zero
mov x1, #0
movi d0, #0
movi d1, #0
movi d2, #0
movi d3, #0
ret
END_ENTRY __objc_msgNil
ENTRY _objc_msgSendSuper
UNWIND _objc_msgSendSuper, NoFrame
MESSENGER_START
ldp x0, x16, [x0] // x0 = real receiver, x16 = class
CacheLookup NORMAL // calls imp or objc_msgSend_uncached
END_ENTRY _objc_msgSendSuper
// no _objc_msgLookupSuper
ENTRY _objc_msgSendSuper2
UNWIND _objc_msgSendSuper2, NoFrame
MESSENGER_START
ldp x0, x16, [x0] // x0 = real receiver, x16 = class
ldr x16, [x16, #SUPERCLASS] // x16 = class->superclass
CacheLookup NORMAL
END_ENTRY _objc_msgSendSuper2
ENTRY _objc_msgLookupSuper2
UNWIND _objc_msgLookupSuper2, NoFrame
ldp x0, x16, [x0] // x0 = real receiver, x16 = class
ldr x16, [x16, #SUPERCLASS] // x16 = class->superclass
CacheLookup LOOKUP
END_ENTRY _objc_msgLookupSuper2
.macro MethodTableLookup
// push frame
stp fp, lr, [sp, #-16]!
mov fp, sp
// save parameter registers: x0..x8, q0..q7
sub sp, sp, #(10*8 + 8*16)
stp q0, q1, [sp, #(0*16)]
stp q2, q3, [sp, #(2*16)]
stp q4, q5, [sp, #(4*16)]
stp q6, q7, [sp, #(6*16)]
stp x0, x1, [sp, #(8*16+0*8)]
stp x2, x3, [sp, #(8*16+2*8)]
stp x4, x5, [sp, #(8*16+4*8)]
stp x6, x7, [sp, #(8*16+6*8)]
str x8, [sp, #(8*16+8*8)]
// receiver and selector already in x0 and x1
mov x2, x16
bl __class_lookupMethodAndLoadCache3
// imp in x0
mov x17, x0
// restore registers and return
ldp q0, q1, [sp, #(0*16)]
ldp q2, q3, [sp, #(2*16)]
ldp q4, q5, [sp, #(4*16)]
ldp q6, q7, [sp, #(6*16)]
ldp x0, x1, [sp, #(8*16+0*8)]
ldp x2, x3, [sp, #(8*16+2*8)]
ldp x4, x5, [sp, #(8*16+4*8)]
ldp x6, x7, [sp, #(8*16+6*8)]
ldr x8, [sp, #(8*16+8*8)]
mov sp, fp
ldp fp, lr, [sp], #16
.endmacro
STATIC_ENTRY __objc_msgSend_uncached
UNWIND __objc_msgSend_uncached, FrameWithNoSaves
// THIS IS NOT A CALLABLE C FUNCTION
// Out-of-band x16 is the class to search
MethodTableLookup
br x17
END_ENTRY __objc_msgSend_uncached
STATIC_ENTRY __objc_msgLookup_uncached
UNWIND __objc_msgLookup_uncached, FrameWithNoSaves
// THIS IS NOT A CALLABLE C FUNCTION
// Out-of-band x16 is the class to search
MethodTableLookup
ret
END_ENTRY __objc_msgLookup_uncached
STATIC_ENTRY _cache_getImp
and x16, x0, #ISA_MASK
CacheLookup GETIMP
LGetImpMiss:
mov x0, #0
ret
END_ENTRY _cache_getImp
/********************************************************************
*
* id _objc_msgForward(id self, SEL _cmd,...);
*
* _objc_msgForward is the externally-callable
* function returned by things like method_getImplementation().
* _objc_msgForward_impcache is the function pointer actually stored in
* method caches.
*
********************************************************************/
STATIC_ENTRY __objc_msgForward_impcache
MESSENGER_START
nop
MESSENGER_END_SLOW
// No stret specialization.
b __objc_msgForward
END_ENTRY __objc_msgForward_impcache
ENTRY __objc_msgForward
adrp x17, __objc_forward_handler@PAGE
ldr x17, [x17, __objc_forward_handler@PAGEOFF]
br x17
END_ENTRY __objc_msgForward
ENTRY _objc_msgSend_noarg
b _objc_msgSend
END_ENTRY _objc_msgSend_noarg
ENTRY _objc_msgSend_debug
b _objc_msgSend
END_ENTRY _objc_msgSend_debug
ENTRY _objc_msgSendSuper2_debug
b _objc_msgSendSuper2
END_ENTRY _objc_msgSendSuper2_debug
ENTRY _method_invoke
// x1 is method triplet instead of SEL
ldr x17, [x1, #METHOD_IMP]
ldr x1, [x1, #METHOD_NAME]
br x17
END_ENTRY _method_invoke
#endif

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,520 @@
#include "objc-private.h"
// out-of-band parameter to objc_msgForward
#define kFwdMsgSend 1
#define kFwdMsgSendStret 0
// objc_msgSend parameters
#define SELF 8[ebp]
#define SUPER 8[ebp]
#define SELECTOR 12[ebp]
#define FIRST_ARG 16[ebp]
// objc_msgSend_stret parameters
#define STRUCT_ADDR 8[ebp]
#define SELF_STRET 12[ebp]
#define SUPER_STRET 12[ebp]
#define SELECTOR_STRET 16[ebp]
// objc_super parameter to sendSuper
#define super_receiver 0
#define super_class 4
// struct objc_class fields
#define isa 0
#define cache 32
// struct objc_method fields
#define method_name 0
#define method_imp 8
// struct objc_cache fields
#define mask 0
#define occupied 4
#define buckets 8
void *_objc_forward_handler = NULL;
void *_objc_forward_stret_handler = NULL;
__declspec(naked) Method _cache_getMethod(Class cls, SEL sel, IMP objc_msgForward_imp)
{
__asm {
push ebp
mov ebp, esp
mov ecx, SELECTOR
mov edx, SELF
// CacheLookup WORD_RETURN, CACHE_GET
push edi
mov edi, cache[edx]
push esi
mov esi, mask[edi]
mov edx, ecx
shr edx, 2
SCAN:
and edx, esi
mov eax, buckets[edi][edx*4]
test eax, eax
je MISS
cmp ecx, method_name[eax]
je HIT
add edx, 1
jmp SCAN
MISS:
xor eax, eax
pop esi
pop edi
leave
ret
HIT:
mov ecx, FIRST_ARG
cmp ecx, method_imp[eax]
je MISS
pop esi
pop edi
leave
ret
}
}
__declspec(naked) IMP _cache_getImp(Class cls, SEL sel)
{
__asm {
push ebp
mov ebp, esp
mov ecx, SELECTOR
mov edx, SELF
// CacheLookup WORD_RETURN, CACHE_GET
push edi
mov edi, cache[edx]
push esi
mov esi, mask[edi]
mov edx, ecx
shr edx, 2
SCAN:
and edx, esi
mov eax, buckets[edi][edx*4]
test eax, eax
je MISS
cmp ecx, method_name[eax]
je HIT
add edx, 1
jmp SCAN
MISS:
pop esi
pop edi
xor eax, eax
leave
ret
HIT:
pop esi
pop edi
mov eax, method_imp[eax]
leave
ret
}
}
OBJC_EXPORT __declspec(naked) id objc_msgSend(id a, SEL b, ...)
{
__asm {
push ebp
mov ebp, esp
// load receiver and selector
mov ecx, SELECTOR
mov eax, SELF
// check whether receiver is nil
test eax, eax
je NIL
// receiver (in eax) is non-nil: search the cache
mov edx, isa[eax]
// CacheLookup WORD_RETURN, MSG_SEND
push edi
mov edi, cache[edx]
push esi
mov esi, mask[edi]
mov edx, ecx
shr edx, 2
SCAN:
and edx, esi
mov eax, buckets[edi][edx*4]
test eax, eax
je MISS
cmp ecx, method_name[eax]
je HIT
add edx, 1
jmp SCAN
HIT:
mov eax, method_imp[eax]
pop esi
pop edi
mov edx, kFwdMsgSend
leave
jmp eax
// cache miss: search method lists
MISS:
pop esi
pop edi
mov edx, SELF
mov eax, isa[edx]
// MethodTableLookup WORD_RETURN, MSG_SEND
push eax
push ecx
push edx
call _class_lookupMethodAndLoadCache3
mov edx, kFwdMsgSend
leave
jmp eax
// message send to nil: return zero
NIL:
// eax is already zero
mov edx, 0
leave
ret
}
}
OBJC_EXPORT __declspec(naked) double objc_msgSend_fpret(id a, SEL b, ...)
{
__asm {
push ebp
mov ebp, esp
// load receiver and selector
mov ecx, SELECTOR
mov eax, SELF
// check whether receiver is nil
test eax, eax
je NIL
// receiver (in eax) is non-nil: search the cache
mov edx, isa[eax]
// CacheLookup WORD_RETURN, MSG_SEND
push edi
mov edi, cache[edx]
push esi
mov esi, mask[edi]
mov edx, ecx
shr edx, 2
SCAN:
and edx, esi
mov eax, buckets[edi][edx*4]
test eax, eax
je MISS
cmp ecx, method_name[eax]
je HIT
add edx, 1
jmp SCAN
HIT:
mov eax, method_imp[eax]
pop esi
pop edi
mov edx, kFwdMsgSend
leave
jmp eax
// cache miss: search method lists
MISS:
pop esi
pop edi
mov edx, SELF
mov eax, isa[edx]
// MethodTableLookup WORD_RETURN, MSG_SEND
push eax
push ecx
push edx
call _class_lookupMethodAndLoadCache3
mov edx, kFwdMsgSend
leave
jmp eax
// message send to nil: return zero
NIL:
fldz
leave
ret
}
}
OBJC_EXPORT __declspec(naked) id objc_msgSendSuper(struct objc_super *a, SEL b, ...)
{
__asm {
push ebp
mov ebp, esp
// load class and selector
mov eax, SUPER
mov ecx, SELECTOR
mov edx, super_class[eax]
// search the cache (class in edx)
// CacheLookup WORD_RETURN, MSG_SENDSUPER
push edi
mov edi, cache[edx]
push esi
mov esi, mask[edi]
mov edx, ecx
shr edx, 2
SCAN:
and edx, esi
mov eax, buckets[edi][edx*4]
test eax, eax
je MISS
cmp ecx, method_name[eax]
je HIT
add edx, 1
jmp SCAN
HIT:
mov eax, method_imp[eax]
pop esi
pop edi
mov edx, SUPER
mov edx, super_receiver[edx]
mov SUPER, edx
mov edx, kFwdMsgSend
leave
jmp eax
// cache miss: search method lists
MISS:
pop esi
pop edi
mov eax, SUPER
mov edx, super_receiver[eax]
mov SUPER, edx
mov eax, super_class[eax]
// MethodTableLookup WORD_RETURN, MSG_SENDSUPER
push eax
push ecx
push edx
call _class_lookupMethodAndLoadCache3
mov edx, kFwdMsgSend
leave
jmp eax
}
}
OBJC_EXPORT __declspec(naked) void objc_msgSend_stret(void)
{
__asm {
push ebp
mov ebp, esp
// load receiver and selector
mov ecx, SELECTOR_STRET
mov eax, SELF_STRET
// check whether receiver is nil
test eax, eax
je NIL
// receiver (in eax) is non-nil: search the cache
mov edx, isa[eax]
// CacheLookup WORD_RETURN, MSG_SEND
push edi
mov edi, cache[edx]
push esi
mov esi, mask[edi]
mov edx, ecx
shr edx, 2
SCAN:
and edx, esi
mov eax, buckets[edi][edx*4]
test eax, eax
je MISS
cmp ecx, method_name[eax]
je HIT
add edx, 1
jmp SCAN
HIT:
mov eax, method_imp[eax]
pop esi
pop edi
mov edx, kFwdMsgSendStret
leave
jmp eax
// cache miss: search method lists
MISS:
pop esi
pop edi
mov edx, SELF_STRET
mov eax, isa[edx]
// MethodTableLookup WORD_RETURN, MSG_SEND
push eax
push ecx
push edx
call _class_lookupMethodAndLoadCache3
mov edx, kFwdMsgSendStret
leave
jmp eax
// message send to nil: return zero
NIL:
// eax is already zero
mov edx, 0
leave
ret
}
}
OBJC_EXPORT __declspec(naked) id objc_msgSendSuper_stret(struct objc_super *a, SEL b, ...)
{
__asm {
push ebp
mov ebp, esp
// load class and selector
mov eax, SUPER_STRET
mov ecx, SELECTOR_STRET
mov edx, super_class[eax]
// search the cache (class in edx)
// CacheLookup WORD_RETURN, MSG_SENDSUPER
push edi
mov edi, cache[edx]
push esi
mov esi, mask[edi]
mov edx, ecx
shr edx, 2
SCAN:
and edx, esi
mov eax, buckets[edi][edx*4]
test eax, eax
je MISS
cmp ecx, method_name[eax]
je HIT
add edx, 1
jmp SCAN
HIT:
mov eax, method_imp[eax]
pop esi
pop edi
mov edx, SUPER_STRET
mov edx, super_receiver[edx]
mov SUPER_STRET, edx
mov edx, kFwdMsgSendStret
leave
jmp eax
// cache miss: search method lists
MISS:
pop esi
pop edi
mov eax, SUPER_STRET
mov edx, super_receiver[eax]
mov SUPER_STRET, edx
mov eax, super_class[eax]
// MethodTableLookup WORD_RETURN, MSG_SENDSUPER
push eax
push ecx
push edx
call _class_lookupMethodAndLoadCache3
mov edx, kFwdMsgSendStret
leave
jmp eax
}
}
OBJC_EXPORT __declspec(naked) id _objc_msgForward(id a, SEL b, ...)
{
__asm {
mov ecx, _objc_forward_handler
jmp ecx
}
}
OBJC_EXPORT __declspec(naked) id _objc_msgForward_stret(id a, SEL b, ...)
{
__asm {
mov ecx, _objc_forward_stret_handler
jmp ecx
}
}
__declspec(naked) id _objc_msgForward_cached(id a, SEL b, ...)
{
__asm {
cmp edx, kFwdMsgSendStret
je STRET
jmp _objc_msgForward
STRET:
jmp _objc_msgForward_stret
}
}
OBJC_EXPORT __declspec(naked) void method_invoke(void)
{
__asm {
push ebp
mov ebp, esp
mov ecx, SELECTOR
mov edx, method_name[ecx]
mov eax, method_imp[ecx]
mov SELECTOR, edx
leave
jmp eax
}
}
OBJC_EXPORT __declspec(naked) void method_invoke_stret(void)
{
__asm {
push ebp
mov ebp, esp
mov ecx, SELECTOR_STRET
mov edx, method_name[ecx]
mov eax, method_imp[ecx]
mov SELECTOR_STRET, edx
leave
jmp eax
}
}

File diff suppressed because it is too large Load Diff

33
runtime/NSObjCRuntime.h Normal file
View File

@ -0,0 +1,33 @@
/* NSObjCRuntime.h
Copyright (c) 1994-2012, Apple Inc. All rights reserved.
*/
#ifndef _OBJC_NSOBJCRUNTIME_H_
#define _OBJC_NSOBJCRUNTIME_H_
#include <TargetConditionals.h>
#include <objc/objc.h>
#if __LP64__ || (TARGET_OS_EMBEDDED && !TARGET_OS_IPHONE) || TARGET_OS_WIN32 || NS_BUILD_32_LIKE_64
typedef long NSInteger;
typedef unsigned long NSUInteger;
#else
typedef int NSInteger;
typedef unsigned int NSUInteger;
#endif
#define NSIntegerMax LONG_MAX
#define NSIntegerMin LONG_MIN
#define NSUIntegerMax ULONG_MAX
#define NSINTEGER_DEFINED 1
#ifndef NS_DESIGNATED_INITIALIZER
#if __has_attribute(objc_designated_initializer)
#define NS_DESIGNATED_INITIALIZER __attribute__((objc_designated_initializer))
#else
#define NS_DESIGNATED_INITIALIZER
#endif
#endif
#endif

109
runtime/NSObject.h Normal file
View File

@ -0,0 +1,109 @@
/* NSObject.h
Copyright (c) 1994-2012, Apple Inc. All rights reserved.
*/
#ifndef _OBJC_NSOBJECT_H_
#define _OBJC_NSOBJECT_H_
#if __OBJC__
#include <objc/objc.h>
#include <objc/NSObjCRuntime.h>
@class NSString, NSMethodSignature, NSInvocation;
@protocol NSObject
- (BOOL)isEqual:(id)object;
@property (readonly) NSUInteger hash;
@property (readonly) Class superclass;
- (Class)class OBJC_SWIFT_UNAVAILABLE("use 'anObject.dynamicType' instead");
- (instancetype)self;
- (id)performSelector:(SEL)aSelector;
- (id)performSelector:(SEL)aSelector withObject:(id)object;
- (id)performSelector:(SEL)aSelector withObject:(id)object1 withObject:(id)object2;
- (BOOL)isProxy;
- (BOOL)isKindOfClass:(Class)aClass;
- (BOOL)isMemberOfClass:(Class)aClass;
- (BOOL)conformsToProtocol:(Protocol *)aProtocol;
- (BOOL)respondsToSelector:(SEL)aSelector;
- (instancetype)retain OBJC_ARC_UNAVAILABLE;
- (oneway void)release OBJC_ARC_UNAVAILABLE;
- (instancetype)autorelease OBJC_ARC_UNAVAILABLE;
- (NSUInteger)retainCount OBJC_ARC_UNAVAILABLE;
- (struct _NSZone *)zone OBJC_ARC_UNAVAILABLE;
@property (readonly, copy) NSString *description;
@optional
@property (readonly, copy) NSString *debugDescription;
@end
OBJC_AVAILABLE(10.0, 2.0, 9.0, 1.0)
OBJC_ROOT_CLASS
OBJC_EXPORT
@interface NSObject <NSObject> {
Class isa OBJC_ISA_AVAILABILITY;
}
+ (void)load;
+ (void)initialize;
- (instancetype)init
#if NS_ENFORCE_NSOBJECT_DESIGNATED_INITIALIZER
NS_DESIGNATED_INITIALIZER
#endif
;
+ (instancetype)new OBJC_SWIFT_UNAVAILABLE("use object initializers instead");
+ (instancetype)allocWithZone:(struct _NSZone *)zone OBJC_SWIFT_UNAVAILABLE("use object initializers instead");
+ (instancetype)alloc OBJC_SWIFT_UNAVAILABLE("use object initializers instead");
- (void)dealloc OBJC_SWIFT_UNAVAILABLE("use 'deinit' to define a de-initializer");
- (void)finalize OBJC_DEPRECATED("Objective-C garbage collection is no longer supported");
- (id)copy;
- (id)mutableCopy;
+ (id)copyWithZone:(struct _NSZone *)zone OBJC_ARC_UNAVAILABLE;
+ (id)mutableCopyWithZone:(struct _NSZone *)zone OBJC_ARC_UNAVAILABLE;
+ (BOOL)instancesRespondToSelector:(SEL)aSelector;
+ (BOOL)conformsToProtocol:(Protocol *)protocol;
- (IMP)methodForSelector:(SEL)aSelector;
+ (IMP)instanceMethodForSelector:(SEL)aSelector;
- (void)doesNotRecognizeSelector:(SEL)aSelector;
- (id)forwardingTargetForSelector:(SEL)aSelector OBJC_AVAILABLE(10.5, 2.0, 9.0, 1.0);
- (void)forwardInvocation:(NSInvocation *)anInvocation OBJC_SWIFT_UNAVAILABLE("");
- (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector OBJC_SWIFT_UNAVAILABLE("");
+ (NSMethodSignature *)instanceMethodSignatureForSelector:(SEL)aSelector OBJC_SWIFT_UNAVAILABLE("");
- (BOOL)allowsWeakReference UNAVAILABLE_ATTRIBUTE;
- (BOOL)retainWeakReference UNAVAILABLE_ATTRIBUTE;
+ (BOOL)isSubclassOfClass:(Class)aClass;
+ (BOOL)resolveClassMethod:(SEL)sel OBJC_AVAILABLE(10.5, 2.0, 9.0, 1.0);
+ (BOOL)resolveInstanceMethod:(SEL)sel OBJC_AVAILABLE(10.5, 2.0, 9.0, 1.0);
+ (NSUInteger)hash;
+ (Class)superclass;
+ (Class)class OBJC_SWIFT_UNAVAILABLE("use 'aClass.self' instead");
+ (NSString *)description;
+ (NSString *)debugDescription;
@end
#endif
#endif

2352
runtime/NSObject.mm Normal file

File diff suppressed because it is too large Load Diff

167
runtime/Object.h Normal file
View File

@ -0,0 +1,167 @@
/*
* Copyright (c) 1999-2003, 2005-2007 Apple Inc. All Rights Reserved.
*
* @APPLE_LICENSE_HEADER_START@
*
* 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 2.0 (the 'License'). You may not use this file except in
* compliance with the License. Please obtain a copy of the License at
* http://www.opensource.apple.com/apsl/ 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, QUIET ENJOYMENT OR NON-INFRINGEMENT.
* Please see the License for the specific language governing rights and
* limitations under the License.
*
* @APPLE_LICENSE_HEADER_END@
*/
/*
Object.h
Copyright 1988-1996 NeXT Software, Inc.
DEFINED AS: A common class
HEADER FILES: <objc/Object.h>
*/
#ifndef _OBJC_OBJECT_H_
#define _OBJC_OBJECT_H_
#include <stdarg.h>
#include <objc/objc-runtime.h>
#if __OBJC__ && !__OBJC2__
__OSX_AVAILABLE(10.0)
__IOS_UNAVAILABLE __TVOS_UNAVAILABLE __WATCHOS_UNAVAILABLE
OBJC_ROOT_CLASS
@interface Object
{
Class isa; /* A pointer to the instance's class structure */
}
/* Initializing classes and instances */
+ (id)initialize;
- (id)init;
/* Creating, copying, and freeing instances */
+ (id)new;
+ (id)free;
- (id)free;
+ (id)alloc;
- (id)copy;
+ (id)allocFromZone:(void *)zone;
- (id)copyFromZone:(void *)zone;
- (void *)zone;
/* Identifying classes */
+ (id)class;
+ (id)superclass;
+ (const char *) name;
- (id)class;
- (id)superclass;
- (const char *) name;
/* Identifying and comparing instances */
- (id)self;
- (unsigned int) hash;
- (BOOL) isEqual:anObject;
/* Testing inheritance relationships */
- (BOOL) isKindOf: aClassObject;
- (BOOL) isMemberOf: aClassObject;
- (BOOL) isKindOfClassNamed: (const char *)aClassName;
- (BOOL) isMemberOfClassNamed: (const char *)aClassName;
/* Testing class functionality */
+ (BOOL) instancesRespondTo:(SEL)aSelector;
- (BOOL) respondsTo:(SEL)aSelector;
/* Testing protocol conformance */
- (BOOL) conformsTo: (Protocol *)aProtocolObject;
+ (BOOL) conformsTo: (Protocol *)aProtocolObject;
/* Obtaining method descriptors from protocols */
- (struct objc_method_description *) descriptionForMethod:(SEL)aSel;
+ (struct objc_method_description *) descriptionForInstanceMethod:(SEL)aSel;
/* Obtaining method handles */
- (IMP) methodFor:(SEL)aSelector;
+ (IMP) instanceMethodFor:(SEL)aSelector;
/* Sending messages determined at run time */
- (id)perform:(SEL)aSelector;
- (id)perform:(SEL)aSelector with:anObject;
- (id)perform:(SEL)aSelector with:object1 with:object2;
/* Posing */
+ (id)poseAs: aClassObject;
/* Enforcing intentions */
- (id)subclassResponsibility:(SEL)aSelector;
- (id)notImplemented:(SEL)aSelector;
/* Error handling */
- (id)doesNotRecognize:(SEL)aSelector;
- (id)error:(const char *)aString, ...;
/* Debugging */
- (void) printForDebugger:(void *)stream;
/* Archiving */
- (id)awake;
- (id)write:(void *)stream;
- (id)read:(void *)stream;
+ (int) version;
+ (id)setVersion: (int) aVersion;
/* Forwarding */
- (id)forward: (SEL)sel : (marg_list)args;
- (id)performv: (SEL)sel : (marg_list)args;
@end
/* Abstract Protocol for Archiving */
@interface Object (Archiving)
- (id)startArchiving: (void *)stream;
- (id)finishUnarchiving;
@end
/* Abstract Protocol for Dynamic Loading */
@interface Object (DynamicLoading)
//+ finishLoading:(headerType *)header;
struct mach_header;
+ (id)finishLoading:(struct mach_header *)header;
+ (id)startUnloading;
@end
#endif
#endif /* _OBJC_OBJECT_H_ */

558
runtime/Object.mm Normal file
View File

@ -0,0 +1,558 @@
/*
* Copyright (c) 1999-2007 Apple Inc. All Rights Reserved.
*
* @APPLE_LICENSE_HEADER_START@
*
* 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 2.0 (the 'License'). You may not use this file except in
* compliance with the License. Please obtain a copy of the License at
* http://www.opensource.apple.com/apsl/ 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, QUIET ENJOYMENT OR NON-INFRINGEMENT.
* Please see the License for the specific language governing rights and
* limitations under the License.
*
* @APPLE_LICENSE_HEADER_END@
*/
/*
Object.m
Copyright 1988-1996 NeXT Software, Inc.
*/
#include "objc-private.h"
#undef id
#undef Class
typedef struct objc_class *Class;
typedef struct objc_object *id;
#if __OBJC2__
__OSX_AVAILABLE(10.0)
__IOS_UNAVAILABLE __TVOS_UNAVAILABLE __WATCHOS_UNAVAILABLE
OBJC_ROOT_CLASS
@interface Object {
Class isa;
}
@end
@implementation Object
+ (id)initialize
{
return self;
}
+ (id)class
{
return self;
}
-(id) retain
{
return _objc_rootRetain(self);
}
-(void) release
{
_objc_rootRelease(self);
}
-(id) autorelease
{
return _objc_rootAutorelease(self);
}
+(id) retain
{
return self;
}
+(void) release
{
}
+(id) autorelease
{
return self;
}
@end
// __OBJC2__
#else
// not __OBJC2__
#include <stdlib.h>
#include <stdarg.h>
#include <string.h>
#include <malloc/malloc.h>
#include "Object.h"
#include "Protocol.h"
#include "objc-runtime.h"
// Error Messages
static const char
_errShouldHaveImp[] = "should have implemented the '%s' method.",
_errShouldNotImp[] = "should NOT have implemented the '%s' method.",
_errLeftUndone[] = "method '%s' not implemented",
_errBadSel[] = "method %s given invalid selector %s",
_errDoesntRecognize[] = "does not recognize selector %c%s";
@implementation Object
+ (id)initialize
{
return self;
}
- (id)awake
{
return self;
}
+ (id)poseAs: aFactory
{
return class_poseAs(self, aFactory);
}
+ (id)new
{
id newObject = (*_alloc)((Class)self, 0);
Class metaClass = self->ISA();
if (class_getVersion(metaClass) > 1)
return [newObject init];
else
return newObject;
}
+ (id)alloc
{
return (*_zoneAlloc)((Class)self, 0, malloc_default_zone());
}
+ (id)allocFromZone:(void *) z
{
return (*_zoneAlloc)((Class)self, 0, z);
}
- (id)init
{
return self;
}
- (const char *)name
{
return class_getName(isa);
}
+ (const char *)name
{
return class_getName((Class)self);
}
- (unsigned)hash
{
return (unsigned)(((uintptr_t)self) >> 2);
}
- (BOOL)isEqual:anObject
{
return anObject == self;
}
- (id)free
{
return (*_dealloc)(self);
}
+ (id)free
{
return nil;
}
- (id)self
{
return self;
}
-(id)class
{
return (id)isa;
}
+ (id)class
{
return self;
}
- (void *)zone
{
void *z = malloc_zone_from_ptr(self);
return z ? z : malloc_default_zone();
}
+ (id)superclass
{
return self->superclass;
}
- (id)superclass
{
return isa->superclass;
}
+ (int) version
{
return class_getVersion((Class)self);
}
+ (id)setVersion: (int) aVersion
{
class_setVersion((Class)self, aVersion);
return self;
}
- (BOOL)isKindOf:aClass
{
Class cls;
for (cls = isa; cls; cls = cls->superclass)
if (cls == (Class)aClass)
return YES;
return NO;
}
- (BOOL)isMemberOf:aClass
{
return isa == (Class)aClass;
}
- (BOOL)isKindOfClassNamed:(const char *)aClassName
{
Class cls;
for (cls = isa; cls; cls = cls->superclass)
if (strcmp(aClassName, class_getName(cls)) == 0)
return YES;
return NO;
}
- (BOOL)isMemberOfClassNamed:(const char *)aClassName
{
return strcmp(aClassName, class_getName(isa)) == 0;
}
+ (BOOL)instancesRespondTo:(SEL)aSelector
{
return class_respondsToMethod((Class)self, aSelector);
}
- (BOOL)respondsTo:(SEL)aSelector
{
return class_respondsToMethod(isa, aSelector);
}
- (id)copy
{
return [self copyFromZone: [self zone]];
}
- (id)copyFromZone:(void *)z
{
return (*_zoneCopy)(self, 0, z);
}
- (IMP)methodFor:(SEL)aSelector
{
return class_lookupMethod(isa, aSelector);
}
+ (IMP)instanceMethodFor:(SEL)aSelector
{
return class_lookupMethod(self, aSelector);
}
- (id)perform:(SEL)aSelector
{
if (aSelector)
return ((id(*)(id, SEL))objc_msgSend)(self, aSelector);
else
return [self error:_errBadSel, sel_getName(_cmd), aSelector];
}
- (id)perform:(SEL)aSelector with:anObject
{
if (aSelector)
return ((id(*)(id, SEL, id))objc_msgSend)(self, aSelector, anObject);
else
return [self error:_errBadSel, sel_getName(_cmd), aSelector];
}
- (id)perform:(SEL)aSelector with:obj1 with:obj2
{
if (aSelector)
return ((id(*)(id, SEL, id, id))objc_msgSend)(self, aSelector, obj1, obj2);
else
return [self error:_errBadSel, sel_getName(_cmd), aSelector];
}
- (id)subclassResponsibility:(SEL)aSelector
{
return [self error:_errShouldHaveImp, sel_getName(aSelector)];
}
- (id)notImplemented:(SEL)aSelector
{
return [self error:_errLeftUndone, sel_getName(aSelector)];
}
- (id)doesNotRecognize:(SEL)aMessage
{
return [self error:_errDoesntRecognize,
class_isMetaClass(isa) ? '+' : '-', sel_getName(aMessage)];
}
- (id)error:(const char *)aCStr, ...
{
va_list ap;
va_start(ap,aCStr);
(*_error)(self, aCStr, ap);
_objc_error (self, aCStr, ap); /* In case (*_error)() returns. */
va_end(ap);
return nil;
}
- (void) printForDebugger:(void *)stream
{
}
- (id)write:(void *) stream
{
return self;
}
- (id)read:(void *) stream
{
return self;
}
- (id)forward: (SEL) sel : (marg_list) args
{
return [self doesNotRecognize: sel];
}
/* this method is not part of the published API */
- (unsigned)methodArgSize:(SEL)sel
{
Method method = class_getInstanceMethod((Class)isa, sel);
if (! method) return 0;
return method_getSizeOfArguments(method);
}
- (id)performv: (SEL) sel : (marg_list) args
{
unsigned size;
// Messages to nil object always return nil
if (! self) return nil;
// Calculate size of the marg_list from the method's
// signature. This looks for the method in self
// and its superclasses.
size = [self methodArgSize: sel];
// If neither self nor its superclasses implement
// it, forward the message because self might know
// someone who does. This is a "chained" forward...
if (! size) return [self forward: sel: args];
// Message self with the specified selector and arguments
return objc_msgSendv (self, sel, size, args);
}
/* Testing protocol conformance */
- (BOOL) conformsTo: (Protocol *)aProtocolObj
{
return [(id)isa conformsTo:aProtocolObj];
}
+ (BOOL) conformsTo: (Protocol *)aProtocolObj
{
Class cls;
for (cls = self; cls; cls = cls->superclass)
{
if (class_conformsToProtocol(cls, aProtocolObj)) return YES;
}
return NO;
}
/* Looking up information for a method */
- (struct objc_method_description *) descriptionForMethod:(SEL)aSelector
{
Class cls;
struct objc_method_description *m;
/* Look in the protocols first. */
for (cls = isa; cls; cls = cls->superclass)
{
if (cls->ISA()->version >= 3)
{
struct objc_protocol_list *protocols =
(struct objc_protocol_list *)cls->protocols;
while (protocols)
{
int i;
for (i = 0; i < protocols->count; i++)
{
Protocol *p = protocols->list[i];
if (class_isMetaClass(cls))
m = [p descriptionForClassMethod:aSelector];
else
m = [p descriptionForInstanceMethod:aSelector];
if (m) {
return m;
}
}
if (cls->ISA()->version <= 4)
break;
protocols = protocols->next;
}
}
}
/* Then try the class implementations. */
for (cls = isa; cls; cls = cls->superclass) {
void *iterator = 0;
int i;
struct objc_method_list *mlist;
while ( (mlist = class_nextMethodList( cls, &iterator )) ) {
for (i = 0; i < mlist->method_count; i++)
if (mlist->method_list[i].method_name == aSelector) {
m = (struct objc_method_description *)&mlist->method_list[i];
return m;
}
}
}
return 0;
}
+ (struct objc_method_description *) descriptionForInstanceMethod:(SEL)aSelector
{
Class cls;
/* Look in the protocols first. */
for (cls = self; cls; cls = cls->superclass)
{
if (cls->ISA()->version >= 3)
{
struct objc_protocol_list *protocols =
(struct objc_protocol_list *)cls->protocols;
while (protocols)
{
int i;
for (i = 0; i < protocols->count; i++)
{
Protocol *p = protocols->list[i];
struct objc_method_description *m;
if ((m = [p descriptionForInstanceMethod:aSelector]))
return m;
}
if (cls->ISA()->version <= 4)
break;
protocols = protocols->next;
}
}
}
/* Then try the class implementations. */
for (cls = self; cls; cls = cls->superclass) {
void *iterator = 0;
int i;
struct objc_method_list *mlist;
while ( (mlist = class_nextMethodList( cls, &iterator )) ) {
for (i = 0; i < mlist->method_count; i++)
if (mlist->method_list[i].method_name == aSelector) {
struct objc_method_description *m;
m = (struct objc_method_description *)&mlist->method_list[i];
return m;
}
}
}
return 0;
}
/* Obsolete methods (for binary compatibility only). */
+ (id)superClass
{
return [self superclass];
}
- (id)superClass
{
return [self superclass];
}
- (BOOL)isKindOfGivenName:(const char *)aClassName
{
return [self isKindOfClassNamed: aClassName];
}
- (BOOL)isMemberOfGivenName:(const char *)aClassName
{
return [self isMemberOfClassNamed: aClassName];
}
- (struct objc_method_description *) methodDescFor:(SEL)aSelector
{
return [self descriptionForMethod: aSelector];
}
+ (struct objc_method_description *) instanceMethodDescFor:(SEL)aSelector
{
return [self descriptionForInstanceMethod: aSelector];
}
- (id)findClass:(const char *)aClassName
{
return objc_lookUpClass(aClassName);
}
- (id)shouldNotImplement:(SEL)aSelector
{
return [self error:_errShouldNotImp, sel_getName(aSelector)];
}
@end
#endif

View File

@ -0,0 +1,118 @@
/*
* Copyright (c) 1999-2002, 2005-2007 Apple Inc. All Rights Reserved.
*
* @APPLE_LICENSE_HEADER_START@
*
* 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 2.0 (the 'License'). You may not use this file except in
* compliance with the License. Please obtain a copy of the License at
* http://www.opensource.apple.com/apsl/ 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, QUIET ENJOYMENT OR NON-INFRINGEMENT.
* Please see the License for the specific language governing rights and
* limitations under the License.
*
* @APPLE_LICENSE_HEADER_END@
*/
/*
List.h
Copyright 1988-1996 NeXT Software, Inc.
DEFINED AS: A common class
HEADER FILES: objc/List.h
*/
#ifndef _OBJC_LIST_H_
#define _OBJC_LIST_H_
#if __OBJC__ && !__OBJC2__ && !__cplusplus && !__has_feature(objc_arc)
#include <objc/Object.h>
#include <Availability.h>
DEPRECATED_ATTRIBUTE
@interface List : Object
{
@public
id *dataPtr DEPRECATED_ATTRIBUTE; /* data of the List object */
unsigned numElements DEPRECATED_ATTRIBUTE; /* Actual number of elements */
unsigned maxElements DEPRECATED_ATTRIBUTE; /* Total allocated elements */
}
/* Creating, freeing */
- (id)free DEPRECATED_ATTRIBUTE;
- (id)freeObjects DEPRECATED_ATTRIBUTE;
- (id)copyFromZone:(void *)z DEPRECATED_ATTRIBUTE;
/* Initializing */
- (id)init DEPRECATED_ATTRIBUTE;
- (id)initCount:(unsigned)numSlots DEPRECATED_ATTRIBUTE;
/* Comparing two lists */
- (BOOL)isEqual: anObject DEPRECATED_ATTRIBUTE;
/* Managing the storage capacity */
- (unsigned)capacity DEPRECATED_ATTRIBUTE;
- (id)setAvailableCapacity:(unsigned)numSlots DEPRECATED_ATTRIBUTE;
/* Manipulating objects by index */
- (unsigned)count DEPRECATED_ATTRIBUTE;
- (id)objectAt:(unsigned)index DEPRECATED_ATTRIBUTE;
- (id)lastObject DEPRECATED_ATTRIBUTE;
- (id)addObject:anObject DEPRECATED_ATTRIBUTE;
- (id)insertObject:anObject at:(unsigned)index DEPRECATED_ATTRIBUTE;
- (id)removeObjectAt:(unsigned)index DEPRECATED_ATTRIBUTE;
- (id)removeLastObject DEPRECATED_ATTRIBUTE;
- (id)replaceObjectAt:(unsigned)index with:newObject DEPRECATED_ATTRIBUTE;
- (id)appendList: (List *)otherList DEPRECATED_ATTRIBUTE;
/* Manipulating objects by id */
- (unsigned)indexOf:anObject DEPRECATED_ATTRIBUTE;
- (id)addObjectIfAbsent:anObject DEPRECATED_ATTRIBUTE;
- (id)removeObject:anObject DEPRECATED_ATTRIBUTE;
- (id)replaceObject:anObject with:newObject DEPRECATED_ATTRIBUTE;
/* Emptying the list */
- (id)empty DEPRECATED_ATTRIBUTE;
/* Sending messages to elements of the list */
- (id)makeObjectsPerform:(SEL)aSelector DEPRECATED_ATTRIBUTE;
- (id)makeObjectsPerform:(SEL)aSelector with:anObject DEPRECATED_ATTRIBUTE;
/*
* The following new... methods are now obsolete. They remain in this
* interface file for backward compatibility only. Use Object's alloc method
* and the init... methods defined in this class instead.
*/
+ (id)new DEPRECATED_ATTRIBUTE;
+ (id)newCount:(unsigned)numSlots DEPRECATED_ATTRIBUTE;
@end
typedef struct {
@defs(List);
} NXListId DEPRECATED_ATTRIBUTE;
#define NX_ADDRESS(x) (((NXListId *)(x))->dataPtr)
#define NX_NOT_IN_LIST 0xffffffff
#endif
#endif /* _OBJC_LIST_H_ */

View File

@ -0,0 +1,294 @@
/*
* Copyright (c) 1999-2001, 2005-2006 Apple Inc. All Rights Reserved.
*
* @APPLE_LICENSE_HEADER_START@
*
* 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 2.0 (the 'License'). You may not use this file except in
* compliance with the License. Please obtain a copy of the License at
* http://www.opensource.apple.com/apsl/ 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, QUIET ENJOYMENT OR NON-INFRINGEMENT.
* Please see the License for the specific language governing rights and
* limitations under the License.
*
* @APPLE_LICENSE_HEADER_END@
*/
/*
List.m
Copyright 1988-1996 NeXT Software, Inc.
Written by: Bryan Yamamoto
Responsibility: Bertrand Serlet
*/
#ifndef __OBJC2__
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <objc/List.h>
#define DATASIZE(count) ((count) * sizeof(id))
@implementation List
+ (id)initialize
{
[self setVersion: 1];
return self;
}
- (id)initCount:(unsigned)numSlots
{
maxElements = numSlots;
if (maxElements)
dataPtr = (id *)malloc(DATASIZE(maxElements));
return self;
}
+ (id)newCount:(unsigned)numSlots
{
return [[self alloc] initCount:numSlots];
}
+ (id)new
{
return [self newCount:0];
}
- (id)init
{
return [self initCount:0];
}
- (id)free
{
free(dataPtr);
return [super free];
}
- (id)freeObjects
{
id element;
while ((element = [self removeLastObject]))
[element free];
return self;
}
- (id)copyFromZone:(void *)z
{
List *new = [[[self class] alloc] initCount: numElements];
new->numElements = numElements;
bcopy ((const char*)dataPtr, (char*)new->dataPtr, DATASIZE(numElements));
return new;
}
- (BOOL) isEqual: anObject
{
List *other;
if (! [anObject isKindOf: [self class]]) return NO;
other = (List *) anObject;
return (numElements == other->numElements)
&& (bcmp ((const char*)dataPtr, (const char*)other->dataPtr, DATASIZE(numElements)) == 0);
}
- (unsigned)capacity
{
return maxElements;
}
- (unsigned)count
{
return numElements;
}
- (id)objectAt:(unsigned)index
{
if (index >= numElements)
return nil;
return dataPtr[index];
}
- (unsigned)indexOf:anObject
{
register id *this = dataPtr;
register id *last = this + numElements;
while (this < last) {
if (*this == anObject)
return this - dataPtr;
this++;
}
return NX_NOT_IN_LIST;
}
- (id)lastObject
{
if (! numElements)
return nil;
return dataPtr[numElements - 1];
}
- (id)setAvailableCapacity:(unsigned)numSlots
{
volatile id *tempDataPtr;
if (numSlots < numElements) return nil;
tempDataPtr = (id *) realloc (dataPtr, DATASIZE(numSlots));
dataPtr = (id *)tempDataPtr;
maxElements = numSlots;
return self;
}
- (id)insertObject:anObject at:(unsigned)index
{
register id *this, *last, *prev;
if (! anObject) return nil;
if (index > numElements)
return nil;
if ((numElements + 1) > maxElements) {
volatile id *tempDataPtr;
/* we double the capacity, also a good size for malloc */
maxElements += maxElements + 1;
tempDataPtr = (id *) realloc (dataPtr, DATASIZE(maxElements));
dataPtr = (id*)tempDataPtr;
}
this = dataPtr + numElements;
prev = this - 1;
last = dataPtr + index;
while (this > last)
*this-- = *prev--;
*last = anObject;
numElements++;
return self;
}
- (id)addObject:anObject
{
return [self insertObject:anObject at:numElements];
}
- (id)addObjectIfAbsent:anObject
{
register id *this, *last;
if (! anObject) return nil;
this = dataPtr;
last = dataPtr + numElements;
while (this < last) {
if (*this == anObject)
return self;
this++;
}
return [self insertObject:anObject at:numElements];
}
- (id)removeObjectAt:(unsigned)index
{
register id *this, *last, *next;
id retval;
if (index >= numElements)
return nil;
this = dataPtr + index;
last = dataPtr + numElements;
next = this + 1;
retval = *this;
while (next < last)
*this++ = *next++;
numElements--;
return retval;
}
- (id)removeObject:anObject
{
register id *this, *last;
this = dataPtr;
last = dataPtr + numElements;
while (this < last) {
if (*this == anObject)
return [self removeObjectAt:this - dataPtr];
this++;
}
return nil;
}
- (id)removeLastObject
{
if (! numElements)
return nil;
return [self removeObjectAt: numElements - 1];
}
- (id)empty
{
numElements = 0;
return self;
}
- (id)replaceObject:anObject with:newObject
{
register id *this, *last;
if (! newObject)
return nil;
this = dataPtr;
last = dataPtr + numElements;
while (this < last) {
if (*this == anObject) {
*this = newObject;
return anObject;
}
this++;
}
return nil;
}
- (id)replaceObjectAt:(unsigned)index with:newObject
{
register id *this;
id retval;
if (! newObject)
return nil;
if (index >= numElements)
return nil;
this = dataPtr + index;
retval = *this;
*this = newObject;
return retval;
}
- (id)makeObjectsPerform:(SEL)aSelector
{
unsigned count = numElements;
while (count--)
[dataPtr[count] perform: aSelector];
return self;
}
- (id)makeObjectsPerform:(SEL)aSelector with:anObject
{
unsigned count = numElements;
while (count--)
[dataPtr[count] perform: aSelector with: anObject];
return self;
}
-(id)appendList: (List *)otherList
{
unsigned i, count;
for (i = 0, count = [otherList count]; i < count; i++)
[self addObject: [otherList objectAt: i]];
return self;
}
@end
#endif

88
runtime/Protocol.h Normal file
View File

@ -0,0 +1,88 @@
/*
* Copyright (c) 1999-2003, 2006-2007 Apple Inc. All Rights Reserved.
*
* @APPLE_LICENSE_HEADER_START@
*
* 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 2.0 (the 'License'). You may not use this file except in
* compliance with the License. Please obtain a copy of the License at
* http://www.opensource.apple.com/apsl/ 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, QUIET ENJOYMENT OR NON-INFRINGEMENT.
* Please see the License for the specific language governing rights and
* limitations under the License.
*
* @APPLE_LICENSE_HEADER_END@
*/
/*
Protocol.h
Copyright 1991-1996 NeXT Software, Inc.
*/
#ifndef _OBJC_PROTOCOL_H_
#define _OBJC_PROTOCOL_H_
#if !__OBJC__
// typedef Protocol is here:
#include <objc/runtime.h>
#elif __OBJC2__
#include <objc/NSObject.h>
// All methods of class Protocol are unavailable.
// Use the functions in objc/runtime.h instead.
OBJC_AVAILABLE(10.0, 2.0, 9.0, 1.0)
@interface Protocol : NSObject
@end
#else
#include <objc/Object.h>
OBJC_AVAILABLE(10.0, 2.0, 9.0, 1.0)
@interface Protocol : Object
{
@private
char *protocol_name OBJC2_UNAVAILABLE;
struct objc_protocol_list *protocol_list OBJC2_UNAVAILABLE;
struct objc_method_description_list *instance_methods OBJC2_UNAVAILABLE;
struct objc_method_description_list *class_methods OBJC2_UNAVAILABLE;
}
/* Obtaining attributes intrinsic to the protocol */
- (const char *)name OBJC2_UNAVAILABLE;
/* Testing protocol conformance */
- (BOOL) conformsTo: (Protocol *)aProtocolObject OBJC2_UNAVAILABLE;
/* Looking up information specific to a protocol */
- (struct objc_method_description *) descriptionForInstanceMethod:(SEL)aSel
__OSX_DEPRECATED(10.0, 10.5, "use protocol_getMethodDescription instead")
__IOS_DEPRECATED(2.0, 2.0, "use protocol_getMethodDescription instead")
__TVOS_DEPRECATED(9.0, 9.0, "use protocol_getMethodDescription instead")
__WATCHOS_DEPRECATED(1.0, 1.0, "use protocol_getMethodDescription instead");
- (struct objc_method_description *) descriptionForClassMethod:(SEL)aSel
__OSX_DEPRECATED(10.0, 10.5, "use protocol_getMethodDescription instead")
__IOS_DEPRECATED(2.0, 2.0, "use protocol_getMethodDescription instead")
__TVOS_DEPRECATED(9.0, 9.0, "use protocol_getMethodDescription instead")
__WATCHOS_DEPRECATED(1.0, 1.0, "use protocol_getMethodDescription instead");
@end
#endif
#endif /* _OBJC_PROTOCOL_H_ */

128
runtime/Protocol.mm Normal file
View File

@ -0,0 +1,128 @@
/*
* Copyright (c) 1999-2001, 2005-2007 Apple Inc. All Rights Reserved.
*
* @APPLE_LICENSE_HEADER_START@
*
* 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 2.0 (the 'License'). You may not use this file except in
* compliance with the License. Please obtain a copy of the License at
* http://www.opensource.apple.com/apsl/ 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, QUIET ENJOYMENT OR NON-INFRINGEMENT.
* Please see the License for the specific language governing rights and
* limitations under the License.
*
* @APPLE_LICENSE_HEADER_END@
*/
/*
Protocol.h
Copyright 1991-1996 NeXT Software, Inc.
*/
#include "objc-private.h"
#undef id
#undef Class
#include <stdlib.h>
#include <string.h>
#include <mach-o/dyld.h>
#include <mach-o/ldsyms.h>
#include "Protocol.h"
#include "NSObject.h"
// __IncompleteProtocol is used as the return type of objc_allocateProtocol().
// Old ABI uses NSObject as the superclass even though Protocol uses Object
// because the R/R implementation for class Protocol is added at runtime
// by CF, so __IncompleteProtocol would be left without an R/R implementation
// otherwise, which would break ARC.
@interface __IncompleteProtocol : NSObject @end
@implementation __IncompleteProtocol
#if __OBJC2__
// fixme hack - make __IncompleteProtocol a non-lazy class
+ (void) load { }
#endif
@end
@implementation Protocol
#if __OBJC2__
// fixme hack - make Protocol a non-lazy class
+ (void) load { }
#endif
- (BOOL) conformsTo: (Protocol *)aProtocolObj
{
return protocol_conformsToProtocol(self, aProtocolObj);
}
- (struct objc_method_description *) descriptionForInstanceMethod:(SEL)aSel
{
#if !__OBJC2__
return lookup_protocol_method((struct old_protocol *)self, aSel,
YES/*required*/, YES/*instance*/,
YES/*recursive*/);
#else
return method_getDescription(protocol_getMethod((struct protocol_t *)self,
aSel, YES, YES, YES));
#endif
}
- (struct objc_method_description *) descriptionForClassMethod:(SEL)aSel
{
#if !__OBJC2__
return lookup_protocol_method((struct old_protocol *)self, aSel,
YES/*required*/, NO/*instance*/,
YES/*recursive*/);
#else
return method_getDescription(protocol_getMethod((struct protocol_t *)self,
aSel, YES, NO, YES));
#endif
}
- (const char *)name
{
return protocol_getName(self);
}
- (BOOL)isEqual:other
{
#if __OBJC2__
// check isKindOf:
Class cls;
Class protoClass = objc_getClass("Protocol");
for (cls = object_getClass(other); cls; cls = cls->superclass) {
if (cls == protoClass) break;
}
if (!cls) return NO;
// check equality
return protocol_isEqual(self, other);
#else
return [other isKindOf:[Protocol class]] && [self conformsTo: other] && [other conformsTo: self];
#endif
}
#if __OBJC2__
- (NSUInteger)hash
{
return 23;
}
#else
- (unsigned)hash
{
return 23;
}
#endif
@end

View File

@ -0,0 +1,148 @@
#if __arm__
#include <arm/arch.h>
#include <mach/vm_param.h>
.syntax unified
.text
.private_extern __a1a2_tramphead
.private_extern __a1a2_firsttramp
.private_extern __a1a2_trampend
// Trampoline machinery assumes the trampolines are Thumb function pointers
#if !__thumb2__
# error sorry
#endif
.thumb
.thumb_func __a1a2_tramphead
.thumb_func __a1a2_firsttramp
.thumb_func __a1a2_trampend
.align PAGE_MAX_SHIFT
__a1a2_tramphead:
/*
r0 == self
r12 == pc of trampoline's first instruction + PC bias
lr == original return address
*/
mov r1, r0 // _cmd = self
// Trampoline's data is one page before the trampoline text.
// Also correct PC bias of 4 bytes.
sub r12, #PAGE_MAX_SIZE
ldr r0, [r12, #-4] // self = block object
ldr pc, [r0, #12] // tail call block->invoke
// not reached
// Align trampolines to 8 bytes
.align 3
.macro TrampolineEntry
mov r12, pc
b __a1a2_tramphead
.align 3
.endmacro
.macro TrampolineEntryX16
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
.endmacro
.macro TrampolineEntryX256
TrampolineEntryX16
TrampolineEntryX16
TrampolineEntryX16
TrampolineEntryX16
TrampolineEntryX16
TrampolineEntryX16
TrampolineEntryX16
TrampolineEntryX16
TrampolineEntryX16
TrampolineEntryX16
TrampolineEntryX16
TrampolineEntryX16
TrampolineEntryX16
TrampolineEntryX16
TrampolineEntryX16
TrampolineEntryX16
.endmacro
.private_extern __a1a2_firsttramp
__a1a2_firsttramp:
// 2048-2 trampolines to fill 16K page
TrampolineEntryX256
TrampolineEntryX256
TrampolineEntryX256
TrampolineEntryX256
TrampolineEntryX256
TrampolineEntryX256
TrampolineEntryX256
TrampolineEntryX16
TrampolineEntryX16
TrampolineEntryX16
TrampolineEntryX16
TrampolineEntryX16
TrampolineEntryX16
TrampolineEntryX16
TrampolineEntryX16
TrampolineEntryX16
TrampolineEntryX16
TrampolineEntryX16
TrampolineEntryX16
TrampolineEntryX16
TrampolineEntryX16
TrampolineEntryX16
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
// TrampolineEntry
// TrampolineEntry
.private_extern __a1a2_trampend
__a1a2_trampend:
#endif

View File

@ -0,0 +1,134 @@
#if __arm64__
#include <mach/vm_param.h>
.text
.private_extern __a1a2_tramphead
.private_extern __a1a2_firsttramp
.private_extern __a1a2_trampend
.align PAGE_MAX_SHIFT
__a1a2_tramphead:
L_a1a2_tramphead:
/*
x0 == self
x17 == address of called trampoline's data (1 page before its code)
lr == original return address
*/
mov x1, x0 // _cmd = self
ldr x0, [x17] // self = block object
ldr x16, [x0, #16] // tail call block->invoke
br x16
// pad up to TrampolineBlockPagePair header size
nop
nop
.macro TrampolineEntry
// load address of trampoline data (one page before this instruction)
adr x17, -PAGE_MAX_SIZE
b L_a1a2_tramphead
.endmacro
.macro TrampolineEntryX16
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
.endmacro
.macro TrampolineEntryX256
TrampolineEntryX16
TrampolineEntryX16
TrampolineEntryX16
TrampolineEntryX16
TrampolineEntryX16
TrampolineEntryX16
TrampolineEntryX16
TrampolineEntryX16
TrampolineEntryX16
TrampolineEntryX16
TrampolineEntryX16
TrampolineEntryX16
TrampolineEntryX16
TrampolineEntryX16
TrampolineEntryX16
TrampolineEntryX16
.endmacro
.align 3
.private_extern __a1a2_firsttramp
__a1a2_firsttramp:
// 2048-3 trampolines to fill 16K page
TrampolineEntryX256
TrampolineEntryX256
TrampolineEntryX256
TrampolineEntryX256
TrampolineEntryX256
TrampolineEntryX256
TrampolineEntryX256
TrampolineEntryX16
TrampolineEntryX16
TrampolineEntryX16
TrampolineEntryX16
TrampolineEntryX16
TrampolineEntryX16
TrampolineEntryX16
TrampolineEntryX16
TrampolineEntryX16
TrampolineEntryX16
TrampolineEntryX16
TrampolineEntryX16
TrampolineEntryX16
TrampolineEntryX16
TrampolineEntryX16
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
// TrampolineEntry
// TrampolineEntry
// TrampolineEntry
.private_extern __a1a2_trampend
__a1a2_trampend:
#endif

566
runtime/a1a2-blocktramps-i386.s Executable file
View File

@ -0,0 +1,566 @@
/*
* Copyright (c) 1999-2007 Apple Inc. All Rights Reserved.
*
* @APPLE_LICENSE_HEADER_START@
*
* 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 2.0 (the 'License'). You may not use this file except in
* compliance with the License. Please obtain a copy of the License at
* http://www.opensource.apple.com/apsl/ 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, QUIET ENJOYMENT OR NON-INFRINGEMENT.
* Please see the License for the specific language governing rights and
* limitations under the License.
*
* @APPLE_LICENSE_HEADER_END@
*/
#ifdef __i386__
#include <mach/vm_param.h>
.text
.private_extern __a1a2_tramphead
.private_extern __a1a2_firsttramp
.private_extern __a1a2_nexttramp
.private_extern __a1a2_trampend
.align PAGE_SHIFT
__a1a2_tramphead:
popl %eax
andl $0xFFFFFFF8, %eax
subl $ PAGE_SIZE, %eax
movl 4(%esp), %ecx // self -> ecx
movl %ecx, 8(%esp) // ecx -> _cmd
movl (%eax), %ecx // blockPtr -> ecx
movl %ecx, 4(%esp) // ecx -> self
jmp *12(%ecx) // tail to block->invoke
.macro TrampolineEntry
call __a1a2_tramphead
nop
nop
nop
.endmacro
.align 5
__a1a2_firsttramp:
TrampolineEntry
__a1a2_nexttramp: // used to calculate size of each trampoline
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
__a1a2_trampend:
#endif

564
runtime/a1a2-blocktramps-x86_64.s Executable file
View File

@ -0,0 +1,564 @@
/*
* Copyright (c) 1999-2007 Apple Inc. All Rights Reserved.
*
* @APPLE_LICENSE_HEADER_START@
*
* 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 2.0 (the 'License'). You may not use this file except in
* compliance with the License. Please obtain a copy of the License at
* http://www.opensource.apple.com/apsl/ 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, QUIET ENJOYMENT OR NON-INFRINGEMENT.
* Please see the License for the specific language governing rights and
* limitations under the License.
*
* @APPLE_LICENSE_HEADER_END@
*/
#ifdef __x86_64__
#include <mach/vm_param.h>
.text
.private_extern __a1a2_tramphead
.private_extern __a1a2_firsttramp
.private_extern __a1a2_nexttramp
.private_extern __a1a2_trampend
.align PAGE_SHIFT
__a1a2_tramphead:
popq %r10
andq $0xFFFFFFFFFFFFFFF8, %r10
subq $ PAGE_SIZE, %r10
movq %rdi, %rsi // arg1 -> arg2
movq (%r10), %rdi // block -> arg1
jmp *16(%rdi)
.macro TrampolineEntry
callq __a1a2_tramphead
nop
nop
nop
.endmacro
.align 5
__a1a2_firsttramp:
TrampolineEntry
__a1a2_nexttramp:
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
__a1a2_trampend:
#endif

View File

@ -0,0 +1,148 @@
#if __arm__
#include <arm/arch.h>
#include <mach/vm_param.h>
.syntax unified
.text
.private_extern __a2a3_tramphead
.private_extern __a2a3_firsttramp
.private_extern __a2a3_trampend
// Trampoline machinery assumes the trampolines are Thumb function pointers
#if !__thumb2__
# error sorry
#endif
.thumb
.thumb_func __a2a3_tramphead
.thumb_func __a2a3_firsttramp
.thumb_func __a2a3_trampend
.align PAGE_MAX_SHIFT
__a2a3_tramphead:
/*
r1 == self
r12 == pc of trampoline's first instruction + PC bias
lr == original return address
*/
mov r2, r1 // _cmd = self
// Trampoline's data is one page before the trampoline text.
// Also correct PC bias of 4 bytes.
sub r12, #PAGE_MAX_SIZE
ldr r1, [r12, #-4] // self = block object
ldr pc, [r1, #12] // tail call block->invoke
// not reached
// Align trampolines to 8 bytes
.align 3
.macro TrampolineEntry
mov r12, pc
b __a2a3_tramphead
.align 3
.endmacro
.macro TrampolineEntryX16
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
.endmacro
.macro TrampolineEntryX256
TrampolineEntryX16
TrampolineEntryX16
TrampolineEntryX16
TrampolineEntryX16
TrampolineEntryX16
TrampolineEntryX16
TrampolineEntryX16
TrampolineEntryX16
TrampolineEntryX16
TrampolineEntryX16
TrampolineEntryX16
TrampolineEntryX16
TrampolineEntryX16
TrampolineEntryX16
TrampolineEntryX16
TrampolineEntryX16
.endmacro
.private_extern __a2a3_firsttramp
__a2a3_firsttramp:
// 2048-2 trampolines to fill 16K page
TrampolineEntryX256
TrampolineEntryX256
TrampolineEntryX256
TrampolineEntryX256
TrampolineEntryX256
TrampolineEntryX256
TrampolineEntryX256
TrampolineEntryX16
TrampolineEntryX16
TrampolineEntryX16
TrampolineEntryX16
TrampolineEntryX16
TrampolineEntryX16
TrampolineEntryX16
TrampolineEntryX16
TrampolineEntryX16
TrampolineEntryX16
TrampolineEntryX16
TrampolineEntryX16
TrampolineEntryX16
TrampolineEntryX16
TrampolineEntryX16
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
// TrampolineEntry
// TrampolineEntry
.private_extern __a2a3_trampend
__a2a3_trampend:
#endif

566
runtime/a2a3-blocktramps-i386.s Executable file
View File

@ -0,0 +1,566 @@
/*
* Copyright (c) 1999-2007 Apple Inc. All Rights Reserved.
*
* @APPLE_LICENSE_HEADER_START@
*
* 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 2.0 (the 'License'). You may not use this file except in
* compliance with the License. Please obtain a copy of the License at
* http://www.opensource.apple.com/apsl/ 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, QUIET ENJOYMENT OR NON-INFRINGEMENT.
* Please see the License for the specific language governing rights and
* limitations under the License.
*
* @APPLE_LICENSE_HEADER_END@
*/
#ifdef __i386__
#include <mach/vm_param.h>
.text
.private_extern __a2a3_tramphead
.private_extern __a2a3_firsttramp
.private_extern __a2a3_nexttramp
.private_extern __a2a3_trampend
.align PAGE_SHIFT
__a2a3_tramphead:
popl %eax
andl $0xFFFFFFF8, %eax
subl $ PAGE_SIZE, %eax
movl 8(%esp), %ecx // self -> ecx
movl %ecx, 12(%esp) // ecx -> _cmd
movl (%eax), %ecx // blockPtr -> ecx
movl %ecx, 8(%esp) // ecx -> self
jmp *12(%ecx) // tail to block->invoke
.macro TrampolineEntry
call __a2a3_tramphead
nop
nop
nop
.endmacro
.align 5
__a2a3_firsttramp:
TrampolineEntry
__a2a3_nexttramp:
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
__a2a3_trampend:
#endif

565
runtime/a2a3-blocktramps-x86_64.s Executable file
View File

@ -0,0 +1,565 @@
/*
* Copyright (c) 1999-2007 Apple Inc. All Rights Reserved.
*
* @APPLE_LICENSE_HEADER_START@
*
* 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 2.0 (the 'License'). You may not use this file except in
* compliance with the License. Please obtain a copy of the License at
* http://www.opensource.apple.com/apsl/ 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, QUIET ENJOYMENT OR NON-INFRINGEMENT.
* Please see the License for the specific language governing rights and
* limitations under the License.
*
* @APPLE_LICENSE_HEADER_END@
*/
#ifdef __x86_64__
#include <mach/vm_param.h>
.text
.private_extern __a2a3_tramphead
.private_extern __a2a3_firsttramp
.private_extern __a2a3_nexttramp
.private_extern __a2a3_trampend
.align PAGE_SHIFT
__a2a3_tramphead:
popq %r10
andq $0xFFFFFFFFFFFFFFF8, %r10
subq $ PAGE_SIZE, %r10
// %rdi -- first arg -- is address of return value's space. Don't mess with it.
movq %rsi, %rdx // arg2 -> arg3
movq (%r10), %rsi // block -> arg2
jmp *16(%rsi)
.macro TrampolineEntry
callq __a2a3_tramphead
nop
nop
nop
.endmacro
.align 5
__a2a3_firsttramp:
TrampolineEntry
__a2a3_nexttramp:
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
TrampolineEntry
__a2a3_trampend:
#endif

2
runtime/hashtable.h Normal file
View File

@ -0,0 +1,2 @@
#include <objc/hashtable2.h>

229
runtime/hashtable2.h Normal file
View File

@ -0,0 +1,229 @@
/*
* Copyright (c) 1999-2006 Apple Inc. All Rights Reserved.
*
* @APPLE_LICENSE_HEADER_START@
*
* 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 2.0 (the 'License'). You may not use this file except in
* compliance with the License. Please obtain a copy of the License at
* http://www.opensource.apple.com/apsl/ 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, QUIET ENJOYMENT OR NON-INFRINGEMENT.
* Please see the License for the specific language governing rights and
* limitations under the License.
*
* @APPLE_LICENSE_HEADER_END@
*/
/*
hashtable2.h
Scalable hash table.
Copyright 1989-1996 NeXT Software, Inc.
*/
#ifndef _OBJC_LITTLE_HASHTABLE_H_
#define _OBJC_LITTLE_HASHTABLE_H_
#ifndef _OBJC_PRIVATE_H_
# define OBJC_HASH_AVAILABILITY \
__OSX_DEPRECATED(10.0, 10.1, "NXHashTable is deprecated") \
__IOS_UNAVAILABLE __TVOS_UNAVAILABLE __WATCHOS_UNAVAILABLE
#else
# define OBJC_HASH_AVAILABILITY
#endif
#include <objc/objc.h>
#include <stdint.h>
#include <TargetConditionals.h>
__BEGIN_DECLS
/*************************************************************************
* Hash tables of arbitrary data
*************************************************************************/
/* 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 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 {
uintptr_t (*hash)(const void *info, const void *data);
int (*isEqual)(const void *info, const void *data1, const void *data2);
void (*free)(const void *info, void *data);
int style; /* reserved for future expansion; currently 0 */
} NXHashTablePrototype;
/* the info argument allows a certain generality, such as freeing according to some owner information */
/* invariants assumed by the implementation:
1 - data1 = data2 => hash(data1) = hash(data2)
when data varies over time, hash(data) must remain invariant
e.g. if data hashes over a string key, the string must not be changed
2- isEqual (data1, data2) => data1= data2
*/
typedef struct {
const NXHashTablePrototype *prototype OBJC_HASH_AVAILABILITY;
unsigned count OBJC_HASH_AVAILABILITY;
unsigned nbBuckets OBJC_HASH_AVAILABILITY;
void *buckets OBJC_HASH_AVAILABILITY;
const void *info OBJC_HASH_AVAILABILITY;
} NXHashTable OBJC_HASH_AVAILABILITY;
/* private data structure; may change */
OBJC_EXPORT NXHashTable *NXCreateHashTableFromZone (NXHashTablePrototype prototype, unsigned capacity, const void *info, void *z) OBJC_HASH_AVAILABILITY;
OBJC_EXPORT NXHashTable *NXCreateHashTable (NXHashTablePrototype prototype, unsigned capacity, const void *info) OBJC_HASH_AVAILABILITY;
/* if hash is 0, pointer hash is assumed */
/* if isEqual is 0, pointer equality is assumed */
/* if free is 0, elements are not freed */
/* capacity is only a hint; 0 creates a small table */
/* info allows call backs to be very general */
OBJC_EXPORT void NXFreeHashTable (NXHashTable *table) OBJC_HASH_AVAILABILITY;
/* calls free for each data, and recovers table */
OBJC_EXPORT void NXEmptyHashTable (NXHashTable *table) OBJC_HASH_AVAILABILITY;
/* does not deallocate table nor data; keeps current capacity */
OBJC_EXPORT void NXResetHashTable (NXHashTable *table) OBJC_HASH_AVAILABILITY;
/* frees each entry; keeps current capacity */
OBJC_EXPORT BOOL NXCompareHashTables (NXHashTable *table1, NXHashTable *table2) OBJC_HASH_AVAILABILITY;
/* Returns YES if the two sets are equal (each member of table1 in table2, and table have same size) */
OBJC_EXPORT NXHashTable *NXCopyHashTable (NXHashTable *table) OBJC_HASH_AVAILABILITY;
/* makes a fresh table, copying data pointers, not data itself. */
OBJC_EXPORT unsigned NXCountHashTable (NXHashTable *table) OBJC_HASH_AVAILABILITY;
/* current number of data in table */
OBJC_EXPORT int NXHashMember (NXHashTable *table, const void *data) OBJC_HASH_AVAILABILITY;
/* returns non-0 iff data is present in table.
Example of use when the hashed data is a struct containing the key,
and when the callee only has a key:
MyStruct pseudo;
pseudo.key = myKey;
return NXHashMember (myTable, &pseudo)
*/
OBJC_EXPORT void *NXHashGet (NXHashTable *table, const void *data) OBJC_HASH_AVAILABILITY;
/* return original table data or NULL.
Example of use when the hashed data is a struct containing the key,
and when the callee only has a key:
MyStruct pseudo;
MyStruct *original;
pseudo.key = myKey;
original = NXHashGet (myTable, &pseudo)
*/
OBJC_EXPORT void *NXHashInsert (NXHashTable *table, const void *data) OBJC_HASH_AVAILABILITY;
/* previous data or NULL is returned. */
OBJC_EXPORT void *NXHashInsertIfAbsent (NXHashTable *table, const void *data) OBJC_HASH_AVAILABILITY;
/* If data already in table, returns the one in table
else adds argument to table and returns argument. */
OBJC_EXPORT void *NXHashRemove (NXHashTable *table, const void *data) OBJC_HASH_AVAILABILITY;
/* previous data or NULL is returned */
/* Iteration over all elements of a table consists in setting up an iteration state and then to progress until all entries have been visited. An example of use for counting elements in a table is:
unsigned count = 0;
MyData *data;
NXHashState state = NXInitHashState(table);
while (NXNextHashState(table, &state, &data)) {
count++;
}
*/
typedef struct {int i; int j;} NXHashState OBJC_HASH_AVAILABILITY;
/* callers should not rely on actual contents of the struct */
OBJC_EXPORT NXHashState NXInitHashState(NXHashTable *table) OBJC_HASH_AVAILABILITY;
OBJC_EXPORT int NXNextHashState(NXHashTable *table, NXHashState *state, void **data) OBJC_HASH_AVAILABILITY;
/* returns 0 when all elements have been visited */
/*************************************************************************
* Conveniences for writing hash, isEqual and free functions
* and common prototypes
*************************************************************************/
OBJC_EXPORT uintptr_t NXPtrHash(const void *info, const void *data) OBJC_HASH_AVAILABILITY;
/* scrambles the address bits; info unused */
OBJC_EXPORT uintptr_t NXStrHash(const void *info, const void *data) OBJC_HASH_AVAILABILITY;
/* string hashing; info unused */
OBJC_EXPORT int NXPtrIsEqual(const void *info, const void *data1, const void *data2) OBJC_HASH_AVAILABILITY;
/* pointer comparison; info unused */
OBJC_EXPORT int NXStrIsEqual(const void *info, const void *data1, const void *data2) OBJC_HASH_AVAILABILITY;
/* string comparison; NULL ok; info unused */
OBJC_EXPORT void NXNoEffectFree(const void *info, void *data) OBJC_HASH_AVAILABILITY;
/* no effect; info unused */
OBJC_EXPORT void NXReallyFree(const void *info, void *data) OBJC_HASH_AVAILABILITY;
/* frees it; info unused */
/* The two following prototypes are useful for manipulating set of pointers or set of strings; For them free is defined as NXNoEffectFree */
OBJC_EXPORT const NXHashTablePrototype NXPtrPrototype OBJC_HASH_AVAILABILITY;
/* prototype when data is a pointer (void *) */
OBJC_EXPORT const NXHashTablePrototype NXStrPrototype OBJC_HASH_AVAILABILITY;
/* prototype when data is a string (char *) */
/* following prototypes help describe mappings where the key is the first element of a struct and is either a pointer or a string.
For example NXStrStructKeyPrototype can be used to hash pointers to Example, where Example is:
typedef struct {
char *key;
int data1;
...
} Example
For the following prototypes, free is defined as NXReallyFree.
*/
OBJC_EXPORT const NXHashTablePrototype NXPtrStructKeyPrototype OBJC_HASH_AVAILABILITY;
OBJC_EXPORT const NXHashTablePrototype NXStrStructKeyPrototype OBJC_HASH_AVAILABILITY;
#if !__OBJC2__ && !TARGET_OS_WIN32
/*************************************************************************
* Unique strings and buffers
*************************************************************************/
/* Unique strings allows C users to enjoy the benefits of Lisp's atoms:
A unique string is a string that is allocated once for all (never de-allocated) and that has only one representant (thus allowing comparison with == instead of strcmp). A unique string should never be modified (and in fact some memory protection is done to ensure that). In order to more explicitly insist on the fact that the string has been uniqued, a synonym of (const char *) has been added, NXAtom. */
typedef const char *NXAtom OBJC_HASH_AVAILABILITY;
OBJC_EXPORT NXAtom NXUniqueString(const char *buffer) OBJC_HASH_AVAILABILITY;
/* assumes that buffer is \0 terminated, and returns
a previously created string or a new string that is a copy of buffer.
If NULL is passed returns NULL.
Returned string should never be modified. To ensure this invariant,
allocations are made in a special read only zone. */
OBJC_EXPORT NXAtom NXUniqueStringWithLength(const char *buffer, int length) OBJC_HASH_AVAILABILITY;
/* assumes that buffer is a non NULL buffer of at least
length characters. Returns a previously created string or
a new string that is a copy of buffer.
If buffer contains \0, string will be truncated.
As for NXUniqueString, returned string should never be modified. */
OBJC_EXPORT NXAtom NXUniqueStringNoCopy(const char *string) OBJC_HASH_AVAILABILITY;
/* If there is already a unique string equal to string, returns the original.
Otherwise, string is entered in the table, without making a copy. Argument should then never be modified. */
OBJC_EXPORT char *NXCopyStringBuffer(const char *buffer) OBJC_HASH_AVAILABILITY;
/* given a buffer, allocates a new string copy of buffer.
Buffer should be \0 terminated; returned string is \0 terminated. */
OBJC_EXPORT char *NXCopyStringBufferFromZone(const char *buffer, void *z) OBJC_HASH_AVAILABILITY;
/* given a buffer, allocates a new string copy of buffer.
Buffer should be \0 terminated; returned string is \0 terminated. */
#endif
__END_DECLS
#endif /* _OBJC_LITTLE_HASHTABLE_H_ */

646
runtime/hashtable2.mm Normal file
View File

@ -0,0 +1,646 @@
/*
* Copyright (c) 1999-2008 Apple Inc. All Rights Reserved.
*
* @APPLE_LICENSE_HEADER_START@
*
* 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 2.0 (the 'License'). You may not use this file except in
* compliance with the License. Please obtain a copy of the License at
* http://www.opensource.apple.com/apsl/ 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, QUIET ENJOYMENT OR NON-INFRINGEMENT.
* Please see the License for the specific language governing rights and
* limitations under the License.
*
* @APPLE_LICENSE_HEADER_END@
*/
/*
hashtable2.m
Copyright 1989-1996 NeXT Software, Inc.
Created by Bertrand Serlet, Feb 89
*/
#include "objc-private.h"
#include "hashtable2.h"
/* In order to improve efficiency, buckets contain a pointer to an array or directly the data when the array size is 1 */
typedef union {
const void *one;
const void **many;
} oneOrMany;
/* an optimization consists of storing directly data when count = 1 */
typedef struct {
unsigned count;
oneOrMany elements;
} HashBucket;
/* private data structure; may change */
/*************************************************************************
*
* Macros and utilities
*
*************************************************************************/
#define PTRSIZE sizeof(void *)
#if !SUPPORT_ZONES
# define DEFAULT_ZONE NULL
# define ZONE_FROM_PTR(p) NULL
# define ALLOCTABLE(z) ((NXHashTable *) malloc (sizeof (NXHashTable)))
# define ALLOCBUCKETS(z,nb)((HashBucket *) calloc (nb, sizeof (HashBucket)))
/* Return interior pointer so a table of classes doesn't look like objects */
# define ALLOCPAIRS(z,nb) (1+(const void **) calloc (nb+1, sizeof (void *)))
# define FREEPAIRS(p) (free((void*)(-1+p)))
#else
# define DEFAULT_ZONE malloc_default_zone()
# define ZONE_FROM_PTR(p) malloc_zone_from_ptr(p)
# define ALLOCTABLE(z) ((NXHashTable *) malloc_zone_malloc ((malloc_zone_t *)z,sizeof (NXHashTable)))
# define ALLOCBUCKETS(z,nb)((HashBucket *) malloc_zone_calloc ((malloc_zone_t *)z, nb, sizeof (HashBucket)))
/* Return interior pointer so a table of classes doesn't look like objects */
# define ALLOCPAIRS(z,nb) (1+(const void **) malloc_zone_calloc ((malloc_zone_t *)z, nb+1, sizeof (void *)))
# define FREEPAIRS(p) (free((void*)(-1+p)))
#endif
#if !SUPPORT_MOD
/* nbBuckets must be a power of 2 */
# define BUCKETOF(table, data) (((HashBucket *)table->buckets)+((*table->prototype->hash)(table->info, data) & (table->nbBuckets-1)))
# define GOOD_CAPACITY(c) (c <= 1 ? 1 : 1 << (log2u (c-1)+1))
# define MORE_CAPACITY(b) (b*2)
#else
/* iff necessary this modulo can be optimized since the nbBuckets is of the form 2**n-1 */
# define BUCKETOF(table, data) (((HashBucket *)table->buckets)+((*table->prototype->hash)(table->info, data) % table->nbBuckets))
# define GOOD_CAPACITY(c) (exp2m1u (log2u (c)+1))
# define MORE_CAPACITY(b) (b*2+1)
#endif
#define ISEQUAL(table, data1, data2) ((data1 == data2) || (*table->prototype->isEqual)(table->info, data1, data2))
/* beware of double evaluation */
/*************************************************************************
*
* Global data and bootstrap
*
*************************************************************************/
static int isEqualPrototype (const void *info, const void *data1, const void *data2) {
NXHashTablePrototype *proto1 = (NXHashTablePrototype *) data1;
NXHashTablePrototype *proto2 = (NXHashTablePrototype *) data2;
return (proto1->hash == proto2->hash) && (proto1->isEqual == proto2->isEqual) && (proto1->free == proto2->free) && (proto1->style == proto2->style);
};
static uintptr_t hashPrototype (const void *info, const void *data) {
NXHashTablePrototype *proto = (NXHashTablePrototype *) data;
return NXPtrHash(info, (void*)proto->hash) ^ NXPtrHash(info, (void*)proto->isEqual) ^ NXPtrHash(info, (void*)proto->free) ^ (uintptr_t) proto->style;
};
void NXNoEffectFree (const void *info, void *data) {};
static NXHashTablePrototype protoPrototype = {
hashPrototype, isEqualPrototype, NXNoEffectFree, 0
};
static NXHashTable *prototypes = NULL;
/* table of all prototypes */
static void bootstrap (void) {
free(malloc(8));
prototypes = ALLOCTABLE (DEFAULT_ZONE);
prototypes->prototype = &protoPrototype;
prototypes->count = 1;
prototypes->nbBuckets = 1; /* has to be 1 so that the right bucket is 0 */
prototypes->buckets = ALLOCBUCKETS(DEFAULT_ZONE, 1);
prototypes->info = NULL;
((HashBucket *) prototypes->buckets)[0].count = 1;
((HashBucket *) prototypes->buckets)[0].elements.one = &protoPrototype;
};
int NXPtrIsEqual (const void *info, const void *data1, const void *data2) {
return data1 == data2;
};
/*************************************************************************
*
* On z'y va
*
*************************************************************************/
NXHashTable *NXCreateHashTable (NXHashTablePrototype prototype, unsigned capacity, const void *info) {
return NXCreateHashTableFromZone(prototype, capacity, info, DEFAULT_ZONE);
}
NXHashTable *NXCreateHashTableFromZone (NXHashTablePrototype prototype, unsigned capacity, const void *info, void *z) {
NXHashTable *table;
NXHashTablePrototype *proto;
table = ALLOCTABLE(z);
if (! prototypes) bootstrap ();
if (! prototype.hash) prototype.hash = NXPtrHash;
if (! prototype.isEqual) prototype.isEqual = NXPtrIsEqual;
if (! prototype.free) prototype.free = NXNoEffectFree;
if (prototype.style) {
_objc_inform ("*** NXCreateHashTable: invalid style\n");
return NULL;
};
proto = (NXHashTablePrototype *)NXHashGet (prototypes, &prototype);
if (! proto) {
proto
= (NXHashTablePrototype *) malloc(sizeof (NXHashTablePrototype));
bcopy ((const char*)&prototype, (char*)proto, sizeof (NXHashTablePrototype));
(void) NXHashInsert (prototypes, proto);
proto = (NXHashTablePrototype *)NXHashGet (prototypes, &prototype);
if (! proto) {
_objc_inform ("*** NXCreateHashTable: bug\n");
return NULL;
};
};
table->prototype = proto; table->count = 0; table->info = info;
table->nbBuckets = GOOD_CAPACITY(capacity);
table->buckets = ALLOCBUCKETS(z, table->nbBuckets);
return table;
}
static void freeBucketPairs (void (*freeProc)(const void *info, void *data), HashBucket bucket, const void *info) {
unsigned j = bucket.count;
const void **pairs;
if (j == 1) {
(*freeProc) (info, (void *) bucket.elements.one);
return;
};
pairs = bucket.elements.many;
while (j--) {
(*freeProc) (info, (void *) *pairs);
pairs ++;
};
FREEPAIRS (bucket.elements.many);
};
static void freeBuckets (NXHashTable *table, int freeObjects) {
unsigned i = table->nbBuckets;
HashBucket *buckets = (HashBucket *) table->buckets;
while (i--) {
if (buckets->count) {
freeBucketPairs ((freeObjects) ? table->prototype->free : NXNoEffectFree, *buckets, table->info);
buckets->count = 0;
buckets->elements.one = NULL;
};
buckets++;
};
};
void NXFreeHashTable (NXHashTable *table) {
freeBuckets (table, YES);
free (table->buckets);
free (table);
};
void NXEmptyHashTable (NXHashTable *table) {
freeBuckets (table, NO);
table->count = 0;
}
void NXResetHashTable (NXHashTable *table) {
freeBuckets (table, YES);
table->count = 0;
}
BOOL NXCompareHashTables (NXHashTable *table1, NXHashTable *table2) {
if (table1 == table2) return YES;
if (NXCountHashTable (table1) != NXCountHashTable (table2)) return NO;
else {
void *data;
NXHashState state = NXInitHashState (table1);
while (NXNextHashState (table1, &state, &data)) {
if (! NXHashMember (table2, data)) return NO;
}
return YES;
}
}
NXHashTable *NXCopyHashTable (NXHashTable *table) {
NXHashTable *newt;
NXHashState state = NXInitHashState (table);
void *data;
__unused void *z = ZONE_FROM_PTR(table);
newt = ALLOCTABLE(z);
newt->prototype = table->prototype; newt->count = 0;
newt->info = table->info;
newt->nbBuckets = table->nbBuckets;
newt->buckets = ALLOCBUCKETS(z, newt->nbBuckets);
while (NXNextHashState (table, &state, &data))
NXHashInsert (newt, data);
return newt;
}
unsigned NXCountHashTable (NXHashTable *table) {
return table->count;
}
int NXHashMember (NXHashTable *table, const void *data) {
HashBucket *bucket = BUCKETOF(table, data);
unsigned j = bucket->count;
const void **pairs;
if (! j) return 0;
if (j == 1) {
return ISEQUAL(table, data, bucket->elements.one);
};
pairs = bucket->elements.many;
while (j--) {
/* we don't cache isEqual because lists are short */
if (ISEQUAL(table, data, *pairs)) return 1;
pairs ++;
};
return 0;
}
void *NXHashGet (NXHashTable *table, const void *data) {
HashBucket *bucket = BUCKETOF(table, data);
unsigned j = bucket->count;
const void **pairs;
if (! j) return NULL;
if (j == 1) {
return ISEQUAL(table, data, bucket->elements.one)
? (void *) bucket->elements.one : NULL;
};
pairs = bucket->elements.many;
while (j--) {
/* we don't cache isEqual because lists are short */
if (ISEQUAL(table, data, *pairs)) return (void *) *pairs;
pairs ++;
};
return NULL;
}
unsigned _NXHashCapacity (NXHashTable *table) {
return table->nbBuckets;
}
void _NXHashRehashToCapacity (NXHashTable *table, unsigned newCapacity) {
/* Rehash: we create a pseudo table pointing really to the old guys,
extend self, copy the old pairs, and free the pseudo table */
NXHashTable *old;
NXHashState state;
void *aux;
__unused void *z = ZONE_FROM_PTR(table);
old = ALLOCTABLE(z);
old->prototype = table->prototype; old->count = table->count;
old->nbBuckets = table->nbBuckets; old->buckets = table->buckets;
table->nbBuckets = newCapacity;
table->count = 0; table->buckets = ALLOCBUCKETS(z, table->nbBuckets);
state = NXInitHashState (old);
while (NXNextHashState (old, &state, &aux))
(void) NXHashInsert (table, aux);
freeBuckets (old, NO);
if (old->count != table->count)
_objc_inform("*** hashtable: count differs after rehashing; probably indicates a broken invariant: there are x and y such as isEqual(x, y) is TRUE but hash(x) != hash (y)\n");
free (old->buckets);
free (old);
}
static void _NXHashRehash (NXHashTable *table) {
_NXHashRehashToCapacity (table, MORE_CAPACITY(table->nbBuckets));
}
void *NXHashInsert (NXHashTable *table, const void *data) {
HashBucket *bucket = BUCKETOF(table, data);
unsigned j = bucket->count;
const void **pairs;
const void **newt;
__unused void *z = ZONE_FROM_PTR(table);
if (! j) {
bucket->count++; bucket->elements.one = data;
table->count++;
return NULL;
};
if (j == 1) {
if (ISEQUAL(table, data, bucket->elements.one)) {
const void *old = bucket->elements.one;
bucket->elements.one = data;
return (void *) old;
};
newt = ALLOCPAIRS(z, 2);
newt[1] = bucket->elements.one;
*newt = data;
bucket->count++; bucket->elements.many = newt;
table->count++;
if (table->count > table->nbBuckets) _NXHashRehash (table);
return NULL;
};
pairs = bucket->elements.many;
while (j--) {
/* we don't cache isEqual because lists are short */
if (ISEQUAL(table, data, *pairs)) {
const void *old = *pairs;
*pairs = data;
return (void *) old;
};
pairs ++;
};
/* we enlarge this bucket; and put new data in front */
newt = ALLOCPAIRS(z, bucket->count+1);
if (bucket->count) bcopy ((const char*)bucket->elements.many, (char*)(newt+1), bucket->count * PTRSIZE);
*newt = data;
FREEPAIRS (bucket->elements.many);
bucket->count++; bucket->elements.many = newt;
table->count++;
if (table->count > table->nbBuckets) _NXHashRehash (table);
return NULL;
}
void *NXHashInsertIfAbsent (NXHashTable *table, const void *data) {
HashBucket *bucket = BUCKETOF(table, data);
unsigned j = bucket->count;
const void **pairs;
const void **newt;
__unused void *z = ZONE_FROM_PTR(table);
if (! j) {
bucket->count++; bucket->elements.one = data;
table->count++;
return (void *) data;
};
if (j == 1) {
if (ISEQUAL(table, data, bucket->elements.one))
return (void *) bucket->elements.one;
newt = ALLOCPAIRS(z, 2);
newt[1] = bucket->elements.one;
*newt = data;
bucket->count++; bucket->elements.many = newt;
table->count++;
if (table->count > table->nbBuckets) _NXHashRehash (table);
return (void *) data;
};
pairs = bucket->elements.many;
while (j--) {
/* we don't cache isEqual because lists are short */
if (ISEQUAL(table, data, *pairs))
return (void *) *pairs;
pairs ++;
};
/* we enlarge this bucket; and put new data in front */
newt = ALLOCPAIRS(z, bucket->count+1);
if (bucket->count) bcopy ((const char*)bucket->elements.many, (char*)(newt+1), bucket->count * PTRSIZE);
*newt = data;
FREEPAIRS (bucket->elements.many);
bucket->count++; bucket->elements.many = newt;
table->count++;
if (table->count > table->nbBuckets) _NXHashRehash (table);
return (void *) data;
}
void *NXHashRemove (NXHashTable *table, const void *data) {
HashBucket *bucket = BUCKETOF(table, data);
unsigned j = bucket->count;
const void **pairs;
const void **newt;
__unused void *z = ZONE_FROM_PTR(table);
if (! j) return NULL;
if (j == 1) {
if (! ISEQUAL(table, data, bucket->elements.one)) return NULL;
data = bucket->elements.one;
table->count--; bucket->count--; bucket->elements.one = NULL;
return (void *) data;
};
pairs = bucket->elements.many;
if (j == 2) {
if (ISEQUAL(table, data, pairs[0])) {
bucket->elements.one = pairs[1]; data = pairs[0];
}
else if (ISEQUAL(table, data, pairs[1])) {
bucket->elements.one = pairs[0]; data = pairs[1];
}
else return NULL;
FREEPAIRS (pairs);
table->count--; bucket->count--;
return (void *) data;
};
while (j--) {
if (ISEQUAL(table, data, *pairs)) {
data = *pairs;
/* we shrink this bucket */
newt = (bucket->count-1)
? ALLOCPAIRS(z, bucket->count-1) : NULL;
if (bucket->count-1 != j)
bcopy ((const char*)bucket->elements.many, (char*)newt, PTRSIZE*(bucket->count-j-1));
if (j)
bcopy ((const char*)(bucket->elements.many + bucket->count-j), (char*)(newt+bucket->count-j-1), PTRSIZE*j);
FREEPAIRS (bucket->elements.many);
table->count--; bucket->count--; bucket->elements.many = newt;
return (void *) data;
};
pairs ++;
};
return NULL;
}
NXHashState NXInitHashState (NXHashTable *table) {
NXHashState state;
state.i = table->nbBuckets;
state.j = 0;
return state;
};
int NXNextHashState (NXHashTable *table, NXHashState *state, void **data) {
HashBucket *buckets = (HashBucket *) table->buckets;
while (state->j == 0) {
if (state->i == 0) return NO;
state->i--; state->j = buckets[state->i].count;
}
state->j--;
buckets += state->i;
*data = (void *) ((buckets->count == 1)
? buckets->elements.one : buckets->elements.many[state->j]);
return YES;
};
/*************************************************************************
*
* Conveniences
*
*************************************************************************/
uintptr_t NXPtrHash (const void *info, const void *data) {
return (((uintptr_t) data) >> 16) ^ ((uintptr_t) data);
};
uintptr_t NXStrHash (const void *info, const void *data) {
uintptr_t hash = 0;
unsigned char *s = (unsigned char *) data;
/* unsigned to avoid a sign-extend */
/* unroll the loop */
if (s) for (; ; ) {
if (*s == '\0') break;
hash ^= (uintptr_t) *s++;
if (*s == '\0') break;
hash ^= (uintptr_t) *s++ << 8;
if (*s == '\0') break;
hash ^= (uintptr_t) *s++ << 16;
if (*s == '\0') break;
hash ^= (uintptr_t) *s++ << 24;
}
return hash;
};
int NXStrIsEqual (const void *info, const void *data1, const void *data2) {
if (data1 == data2) return YES;
if (! data1) return ! strlen ((char *) data2);
if (! data2) return ! strlen ((char *) data1);
if (((char *) data1)[0] != ((char *) data2)[0]) return NO;
return (strcmp ((char *) data1, (char *) data2)) ? NO : YES;
};
void NXReallyFree (const void *info, void *data) {
free (data);
};
/* All the following functions are really private, made non-static only for the benefit of shlibs */
static uintptr_t hashPtrStructKey (const void *info, const void *data) {
return NXPtrHash(info, *((void **) data));
};
static int isEqualPtrStructKey (const void *info, const void *data1, const void *data2) {
return NXPtrIsEqual (info, *((void **) data1), *((void **) data2));
};
static uintptr_t hashStrStructKey (const void *info, const void *data) {
return NXStrHash(info, *((char **) data));
};
static int isEqualStrStructKey (const void *info, const void *data1, const void *data2) {
return NXStrIsEqual (info, *((char **) data1), *((char **) data2));
};
const NXHashTablePrototype NXPtrPrototype = {
NXPtrHash, NXPtrIsEqual, NXNoEffectFree, 0
};
const NXHashTablePrototype NXStrPrototype = {
NXStrHash, NXStrIsEqual, NXNoEffectFree, 0
};
const NXHashTablePrototype NXPtrStructKeyPrototype = {
hashPtrStructKey, isEqualPtrStructKey, NXReallyFree, 0
};
const NXHashTablePrototype NXStrStructKeyPrototype = {
hashStrStructKey, isEqualStrStructKey, NXReallyFree, 0
};
/*************************************************************************
*
* Unique strings
*
*************************************************************************/
#if !__OBJC2__ && !TARGET_OS_WIN32
/* the implementation could be made faster at the expense of memory if the size of the strings were kept around */
static NXHashTable *uniqueStrings = NULL;
/* this is based on most apps using a few K of strings, and an average string size of 15 using sqrt(2*dataAlloced*perChunkOverhead) */
#define CHUNK_SIZE 360
static int accessUniqueString = 0;
static char *z = NULL;
static size_t zSize = 0;
static mutex_t uniquerLock;
static const char *CopyIntoReadOnly (const char *str) {
size_t len = strlen (str) + 1;
char *result;
if (len > CHUNK_SIZE/2) { /* dont let big strings waste space */
result = (char *)malloc (len);
bcopy (str, result, len);
return result;
}
mutex_locker_t lock(uniquerLock);
if (zSize < len) {
zSize = CHUNK_SIZE *((len + CHUNK_SIZE - 1) / CHUNK_SIZE);
/* not enough room, we try to allocate. If no room left, too bad */
z = (char *)malloc (zSize);
};
result = z;
bcopy (str, result, len);
z += len;
zSize -= len;
return result;
};
NXAtom NXUniqueString (const char *buffer) {
const char *previous;
if (! buffer) return buffer;
accessUniqueString++;
if (! uniqueStrings)
uniqueStrings = NXCreateHashTable (NXStrPrototype, 0, NULL);
previous = (const char *) NXHashGet (uniqueStrings, buffer);
if (previous) return previous;
previous = CopyIntoReadOnly (buffer);
if (NXHashInsert (uniqueStrings, previous)) {
_objc_inform ("*** NXUniqueString: invariant broken\n");
return NULL;
};
return previous;
};
NXAtom NXUniqueStringNoCopy (const char *string) {
accessUniqueString++;
if (! uniqueStrings)
uniqueStrings = NXCreateHashTable (NXStrPrototype, 0, NULL);
return (const char *) NXHashInsertIfAbsent (uniqueStrings, string);
};
#define BUF_SIZE 256
NXAtom NXUniqueStringWithLength (const char *buffer, int length) {
NXAtom atom;
char *nullTermStr;
char stackBuf[BUF_SIZE];
if (length+1 > BUF_SIZE)
nullTermStr = (char *)malloc (length+1);
else
nullTermStr = stackBuf;
bcopy (buffer, nullTermStr, length);
nullTermStr[length] = '\0';
atom = NXUniqueString (nullTermStr);
if (length+1 > BUF_SIZE)
free (nullTermStr);
return atom;
};
char *NXCopyStringBufferFromZone (const char *str, void *zone) {
#if !SUPPORT_ZONES
return strdup(str);
#else
return strcpy ((char *) malloc_zone_malloc((malloc_zone_t *)zone, strlen (str) + 1), str);
#endif
};
char *NXCopyStringBuffer (const char *str) {
return strdup(str);
};
#endif

171
runtime/llvm-AlignOf.h Normal file
View File

@ -0,0 +1,171 @@
//===--- AlignOf.h - Portable calculation of type alignment -----*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file defines the AlignOf function that computes alignments for
// arbitrary types.
//
//===----------------------------------------------------------------------===//
// Taken from llvmCore-3425.0.31.
#ifndef LLVM_SUPPORT_ALIGNOF_H
#define LLVM_SUPPORT_ALIGNOF_H
#include <cstddef>
namespace objc {
template <typename T>
struct AlignmentCalcImpl {
char x;
T t;
private:
AlignmentCalcImpl() {} // Never instantiate.
};
/// AlignOf - A templated class that contains an enum value representing
/// the alignment of the template argument. For example,
/// AlignOf<int>::Alignment represents the alignment of type "int". The
/// alignment calculated is the minimum alignment, and not necessarily
/// the "desired" alignment returned by GCC's __alignof__ (for example). Note
/// that because the alignment is an enum value, it can be used as a
/// compile-time constant (e.g., for template instantiation).
template <typename T>
struct AlignOf {
enum { Alignment =
static_cast<unsigned int>(sizeof(AlignmentCalcImpl<T>) - sizeof(T)) };
enum { Alignment_GreaterEqual_2Bytes = Alignment >= 2 ? 1 : 0 };
enum { Alignment_GreaterEqual_4Bytes = Alignment >= 4 ? 1 : 0 };
enum { Alignment_GreaterEqual_8Bytes = Alignment >= 8 ? 1 : 0 };
enum { Alignment_GreaterEqual_16Bytes = Alignment >= 16 ? 1 : 0 };
enum { Alignment_LessEqual_2Bytes = Alignment <= 2 ? 1 : 0 };
enum { Alignment_LessEqual_4Bytes = Alignment <= 4 ? 1 : 0 };
enum { Alignment_LessEqual_8Bytes = Alignment <= 8 ? 1 : 0 };
enum { Alignment_LessEqual_16Bytes = Alignment <= 16 ? 1 : 0 };
};
/// alignOf - A templated function that returns the minimum alignment of
/// of a type. This provides no extra functionality beyond the AlignOf
/// class besides some cosmetic cleanliness. Example usage:
/// alignOf<int>() returns the alignment of an int.
template <typename T>
inline unsigned alignOf() { return AlignOf<T>::Alignment; }
/// \brief Helper for building an aligned character array type.
///
/// This template is used to explicitly build up a collection of aligned
/// character types. We have to build these up using a macro and explicit
/// specialization to cope with old versions of MSVC and GCC where only an
/// integer literal can be used to specify an alignment constraint. Once built
/// up here, we can then begin to indirect between these using normal C++
/// template parameters.
template <size_t Alignment> struct AlignedCharArrayImpl;
// MSVC requires special handling here.
#ifndef _MSC_VER
#if __has_feature(cxx_alignas)
#define LLVM_ALIGNEDCHARARRAY_TEMPLATE_ALIGNMENT(x) \
template <> struct AlignedCharArrayImpl<x> { \
char aligned alignas(x); \
}
#elif defined(__GNUC__)
#define LLVM_ALIGNEDCHARARRAY_TEMPLATE_ALIGNMENT(x) \
template <> struct AlignedCharArrayImpl<x> { \
char aligned __attribute__((aligned(x))); \
}
#else
# error No supported align as directive.
#endif
LLVM_ALIGNEDCHARARRAY_TEMPLATE_ALIGNMENT(1);
LLVM_ALIGNEDCHARARRAY_TEMPLATE_ALIGNMENT(2);
LLVM_ALIGNEDCHARARRAY_TEMPLATE_ALIGNMENT(4);
LLVM_ALIGNEDCHARARRAY_TEMPLATE_ALIGNMENT(8);
LLVM_ALIGNEDCHARARRAY_TEMPLATE_ALIGNMENT(16);
LLVM_ALIGNEDCHARARRAY_TEMPLATE_ALIGNMENT(32);
LLVM_ALIGNEDCHARARRAY_TEMPLATE_ALIGNMENT(64);
LLVM_ALIGNEDCHARARRAY_TEMPLATE_ALIGNMENT(128);
LLVM_ALIGNEDCHARARRAY_TEMPLATE_ALIGNMENT(512);
LLVM_ALIGNEDCHARARRAY_TEMPLATE_ALIGNMENT(1024);
LLVM_ALIGNEDCHARARRAY_TEMPLATE_ALIGNMENT(2048);
LLVM_ALIGNEDCHARARRAY_TEMPLATE_ALIGNMENT(4096);
LLVM_ALIGNEDCHARARRAY_TEMPLATE_ALIGNMENT(8192);
#undef LLVM_ALIGNEDCHARARRAY_TEMPLATE_ALIGNMENT
#else // _MSC_VER
// We provide special variations of this template for the most common
// alignments because __declspec(align(...)) doesn't actually work when it is
// a member of a by-value function argument in MSVC, even if the alignment
// request is something reasonably like 8-byte or 16-byte.
template <> struct AlignedCharArrayImpl<1> { char aligned; };
template <> struct AlignedCharArrayImpl<2> { short aligned; };
template <> struct AlignedCharArrayImpl<4> { int aligned; };
template <> struct AlignedCharArrayImpl<8> { double aligned; };
#define LLVM_ALIGNEDCHARARRAY_TEMPLATE_ALIGNMENT(x) \
template <> struct AlignedCharArrayImpl<x> { \
__declspec(align(x)) char aligned; \
}
LLVM_ALIGNEDCHARARRAY_TEMPLATE_ALIGNMENT(16);
LLVM_ALIGNEDCHARARRAY_TEMPLATE_ALIGNMENT(32);
LLVM_ALIGNEDCHARARRAY_TEMPLATE_ALIGNMENT(64);
LLVM_ALIGNEDCHARARRAY_TEMPLATE_ALIGNMENT(128);
LLVM_ALIGNEDCHARARRAY_TEMPLATE_ALIGNMENT(512);
LLVM_ALIGNEDCHARARRAY_TEMPLATE_ALIGNMENT(1024);
LLVM_ALIGNEDCHARARRAY_TEMPLATE_ALIGNMENT(2048);
LLVM_ALIGNEDCHARARRAY_TEMPLATE_ALIGNMENT(4096);
LLVM_ALIGNEDCHARARRAY_TEMPLATE_ALIGNMENT(8192);
// Any larger and MSVC complains.
#undef LLVM_ALIGNEDCHARARRAY_TEMPLATE_ALIGNMENT
#endif // _MSC_VER
/// \brief This union template exposes a suitably aligned and sized character
/// array member which can hold elements of any of up to four types.
///
/// These types may be arrays, structs, or any other types. The goal is to
/// produce a union type containing a character array which, when used, forms
/// storage suitable to placement new any of these types over. Support for more
/// than four types can be added at the cost of more boiler plate.
template <typename T1,
typename T2 = char, typename T3 = char, typename T4 = char>
union AlignedCharArrayUnion {
private:
class AlignerImpl {
T1 t1; T2 t2; T3 t3; T4 t4;
AlignerImpl(); // Never defined or instantiated.
};
union SizerImpl {
char arr1[sizeof(T1)], arr2[sizeof(T2)], arr3[sizeof(T3)], arr4[sizeof(T4)];
};
public:
/// \brief The character array buffer for use by clients.
///
/// No other member of this union should be referenced. The exist purely to
/// constrain the layout of this character array.
char buffer[sizeof(SizerImpl)];
private:
// Tests seem to indicate that both Clang and GCC will properly register the
// alignment of a struct containing an aligned member, and this alignment
// should carry over to the character array in the union.
AlignedCharArrayImpl<AlignOf<AlignerImpl>::Alignment> nonce_member;
};
} // end namespace objc
#endif

1097
runtime/llvm-DenseMap.h Normal file

File diff suppressed because it is too large Load Diff

200
runtime/llvm-DenseMapInfo.h Normal file
View File

@ -0,0 +1,200 @@
//===- llvm/ADT/DenseMapInfo.h - Type traits for DenseMap -------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file defines DenseMapInfo traits for DenseMap.
//
//===----------------------------------------------------------------------===//
// Taken from llvmCore-3425.0.31.
#ifndef LLVM_ADT_DENSEMAPINFO_H
#define LLVM_ADT_DENSEMAPINFO_H
#include "objc-private.h"
#include "llvm-type_traits.h"
namespace objc {
template<typename T>
struct DenseMapInfo {
//static inline T getEmptyKey();
//static inline T getTombstoneKey();
//static unsigned getHashValue(const T &Val);
//static bool isEqual(const T &LHS, const T &RHS);
};
// Provide DenseMapInfo for all pointers.
template<typename T>
struct DenseMapInfo<T*> {
static inline T* getEmptyKey() {
uintptr_t Val = static_cast<uintptr_t>(-1);
return reinterpret_cast<T*>(Val);
}
static inline T* getTombstoneKey() {
uintptr_t Val = static_cast<uintptr_t>(-2);
return reinterpret_cast<T*>(Val);
}
static unsigned getHashValue(const T *PtrVal) {
return ptr_hash((uintptr_t)PtrVal);
}
static bool isEqual(const T *LHS, const T *RHS) { return LHS == RHS; }
};
// Provide DenseMapInfo for disguised pointers.
template<typename T>
struct DenseMapInfo<DisguisedPtr<T>> {
static inline DisguisedPtr<T> getEmptyKey() {
return DisguisedPtr<T>((T*)(uintptr_t)-1);
}
static inline DisguisedPtr<T> getTombstoneKey() {
return DisguisedPtr<T>((T*)(uintptr_t)-2);
}
static unsigned getHashValue(const T *PtrVal) {
return ptr_hash((uintptr_t)PtrVal);
}
static bool isEqual(const DisguisedPtr<T> &LHS, const DisguisedPtr<T> &RHS) {
return LHS == RHS;
}
};
// Provide DenseMapInfo for cstrings.
template<> struct DenseMapInfo<const char*> {
static inline const char* getEmptyKey() {
return reinterpret_cast<const char *>((intptr_t)-1);
}
static inline const char* getTombstoneKey() {
return reinterpret_cast<const char *>((intptr_t)-2);
}
static unsigned getHashValue(const char* const &Val) {
return _objc_strhash(Val);
}
static bool isEqual(const char* const &LHS, const char* const &RHS) {
return 0 == strcmp(LHS, RHS);
}
};
// Provide DenseMapInfo for chars.
template<> struct DenseMapInfo<char> {
static inline char getEmptyKey() { return ~0; }
static inline char getTombstoneKey() { return ~0 - 1; }
static unsigned getHashValue(const char& Val) { return Val * 37U; }
static bool isEqual(const char &LHS, const char &RHS) {
return LHS == RHS;
}
};
// Provide DenseMapInfo for unsigned ints.
template<> struct DenseMapInfo<unsigned> {
static inline unsigned getEmptyKey() { return ~0U; }
static inline unsigned getTombstoneKey() { return ~0U - 1; }
static unsigned getHashValue(const unsigned& Val) { return Val * 37U; }
static bool isEqual(const unsigned& LHS, const unsigned& RHS) {
return LHS == RHS;
}
};
// Provide DenseMapInfo for unsigned longs.
template<> struct DenseMapInfo<unsigned long> {
static inline unsigned long getEmptyKey() { return ~0UL; }
static inline unsigned long getTombstoneKey() { return ~0UL - 1L; }
static unsigned getHashValue(const unsigned long& Val) {
return (unsigned)(Val * 37UL);
}
static bool isEqual(const unsigned long& LHS, const unsigned long& RHS) {
return LHS == RHS;
}
};
// Provide DenseMapInfo for unsigned long longs.
template<> struct DenseMapInfo<unsigned long long> {
static inline unsigned long long getEmptyKey() { return ~0ULL; }
static inline unsigned long long getTombstoneKey() { return ~0ULL - 1ULL; }
static unsigned getHashValue(const unsigned long long& Val) {
return (unsigned)(Val * 37ULL);
}
static bool isEqual(const unsigned long long& LHS,
const unsigned long long& RHS) {
return LHS == RHS;
}
};
// Provide DenseMapInfo for ints.
template<> struct DenseMapInfo<int> {
static inline int getEmptyKey() { return 0x7fffffff; }
static inline int getTombstoneKey() { return -0x7fffffff - 1; }
static unsigned getHashValue(const int& Val) { return (unsigned)(Val * 37U); }
static bool isEqual(const int& LHS, const int& RHS) {
return LHS == RHS;
}
};
// Provide DenseMapInfo for longs.
template<> struct DenseMapInfo<long> {
static inline long getEmptyKey() {
return (1UL << (sizeof(long) * 8 - 1)) - 1UL;
}
static inline long getTombstoneKey() { return getEmptyKey() - 1L; }
static unsigned getHashValue(const long& Val) {
return (unsigned)(Val * 37UL);
}
static bool isEqual(const long& LHS, const long& RHS) {
return LHS == RHS;
}
};
// Provide DenseMapInfo for long longs.
template<> struct DenseMapInfo<long long> {
static inline long long getEmptyKey() { return 0x7fffffffffffffffLL; }
static inline long long getTombstoneKey() { return -0x7fffffffffffffffLL-1; }
static unsigned getHashValue(const long long& Val) {
return (unsigned)(Val * 37ULL);
}
static bool isEqual(const long long& LHS,
const long long& RHS) {
return LHS == RHS;
}
};
// Provide DenseMapInfo for all pairs whose members have info.
template<typename T, typename U>
struct DenseMapInfo<std::pair<T, U> > {
typedef std::pair<T, U> Pair;
typedef DenseMapInfo<T> FirstInfo;
typedef DenseMapInfo<U> SecondInfo;
static inline Pair getEmptyKey() {
return std::make_pair(FirstInfo::getEmptyKey(),
SecondInfo::getEmptyKey());
}
static inline Pair getTombstoneKey() {
return std::make_pair(FirstInfo::getTombstoneKey(),
SecondInfo::getTombstoneKey());
}
static unsigned getHashValue(const Pair& PairVal) {
uint64_t key = (uint64_t)FirstInfo::getHashValue(PairVal.first) << 32
| (uint64_t)SecondInfo::getHashValue(PairVal.second);
key += ~(key << 32);
key ^= (key >> 22);
key += ~(key << 13);
key ^= (key >> 8);
key += (key << 3);
key ^= (key >> 15);
key += ~(key << 27);
key ^= (key >> 31);
return (unsigned)key;
}
static bool isEqual(const Pair &LHS, const Pair &RHS) {
return FirstInfo::isEqual(LHS.first, RHS.first) &&
SecondInfo::isEqual(LHS.second, RHS.second);
}
};
} // end namespace objc
#endif

480
runtime/llvm-MathExtras.h Normal file
View File

@ -0,0 +1,480 @@
//===-- llvm/Support/MathExtras.h - Useful math functions -------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file contains some functions that are useful for math stuff.
//
//===----------------------------------------------------------------------===//
// Taken from llvmCore-3425.0.31.
#ifndef LLVM_SUPPORT_MATHEXTRAS_H
#define LLVM_SUPPORT_MATHEXTRAS_H
namespace objc {
// NOTE: The following support functions use the _32/_64 extensions instead of
// type overloading so that signed and unsigned integers can be used without
// ambiguity.
/// Hi_32 - This function returns the high 32 bits of a 64 bit value.
inline uint32_t Hi_32(uint64_t Value) {
return static_cast<uint32_t>(Value >> 32);
}
/// Lo_32 - This function returns the low 32 bits of a 64 bit value.
inline uint32_t Lo_32(uint64_t Value) {
return static_cast<uint32_t>(Value);
}
/// isInt - Checks if an integer fits into the given bit width.
template<unsigned N>
inline bool isInt(int64_t x) {
return N >= 64 || (-(INT64_C(1)<<(N-1)) <= x && x < (INT64_C(1)<<(N-1)));
}
// Template specializations to get better code for common cases.
template<>
inline bool isInt<8>(int64_t x) {
return static_cast<int8_t>(x) == x;
}
template<>
inline bool isInt<16>(int64_t x) {
return static_cast<int16_t>(x) == x;
}
template<>
inline bool isInt<32>(int64_t x) {
return static_cast<int32_t>(x) == x;
}
/// isShiftedInt<N,S> - Checks if a signed integer is an N bit number shifted
/// left by S.
template<unsigned N, unsigned S>
inline bool isShiftedInt(int64_t x) {
return isInt<N+S>(x) && (x % (1<<S) == 0);
}
/// isUInt - Checks if an unsigned integer fits into the given bit width.
template<unsigned N>
inline bool isUInt(uint64_t x) {
return N >= 64 || x < (UINT64_C(1)<<N);
}
// Template specializations to get better code for common cases.
template<>
inline bool isUInt<8>(uint64_t x) {
return static_cast<uint8_t>(x) == x;
}
template<>
inline bool isUInt<16>(uint64_t x) {
return static_cast<uint16_t>(x) == x;
}
template<>
inline bool isUInt<32>(uint64_t x) {
return static_cast<uint32_t>(x) == x;
}
/// isShiftedUInt<N,S> - Checks if a unsigned integer is an N bit number shifted
/// left by S.
template<unsigned N, unsigned S>
inline bool isShiftedUInt(uint64_t x) {
return isUInt<N+S>(x) && (x % (1<<S) == 0);
}
/// isUIntN - Checks if an unsigned integer fits into the given (dynamic)
/// bit width.
inline bool isUIntN(unsigned N, uint64_t x) {
return x == (x & (~0ULL >> (64 - N)));
}
/// isIntN - Checks if an signed integer fits into the given (dynamic)
/// bit width.
inline bool isIntN(unsigned N, int64_t x) {
return N >= 64 || (-(INT64_C(1)<<(N-1)) <= x && x < (INT64_C(1)<<(N-1)));
}
/// isMask_32 - This function returns true if the argument is a sequence of ones
/// starting at the least significant bit with the remainder zero (32 bit
/// version). Ex. isMask_32(0x0000FFFFU) == true.
inline bool isMask_32(uint32_t Value) {
return Value && ((Value + 1) & Value) == 0;
}
/// isMask_64 - This function returns true if the argument is a sequence of ones
/// starting at the least significant bit with the remainder zero (64 bit
/// version).
inline bool isMask_64(uint64_t Value) {
return Value && ((Value + 1) & Value) == 0;
}
/// isShiftedMask_32 - This function returns true if the argument contains a
/// sequence of ones with the remainder zero (32 bit version.)
/// Ex. isShiftedMask_32(0x0000FF00U) == true.
inline bool isShiftedMask_32(uint32_t Value) {
return isMask_32((Value - 1) | Value);
}
/// isShiftedMask_64 - This function returns true if the argument contains a
/// sequence of ones with the remainder zero (64 bit version.)
inline bool isShiftedMask_64(uint64_t Value) {
return isMask_64((Value - 1) | Value);
}
/// isPowerOf2_32 - This function returns true if the argument is a power of
/// two > 0. Ex. isPowerOf2_32(0x00100000U) == true (32 bit edition.)
inline bool isPowerOf2_32(uint32_t Value) {
return Value && !(Value & (Value - 1));
}
/// isPowerOf2_64 - This function returns true if the argument is a power of two
/// > 0 (64 bit edition.)
inline bool isPowerOf2_64(uint64_t Value) {
return Value && !(Value & (Value - int64_t(1L)));
}
/// CountLeadingZeros_32 - this function performs the platform optimal form of
/// counting the number of zeros from the most significant bit to the first one
/// bit. Ex. CountLeadingZeros_32(0x00F000FF) == 8.
/// Returns 32 if the word is zero.
inline unsigned CountLeadingZeros_32(uint32_t Value) {
unsigned Count; // result
#if __GNUC__ >= 4
// PowerPC is defined for __builtin_clz(0)
#if !defined(__ppc__) && !defined(__ppc64__)
if (!Value) return 32;
#endif
Count = __builtin_clz(Value);
#else
if (!Value) return 32;
Count = 0;
// bisection method for count leading zeros
for (unsigned Shift = 32 >> 1; Shift; Shift >>= 1) {
uint32_t Tmp = Value >> Shift;
if (Tmp) {
Value = Tmp;
} else {
Count |= Shift;
}
}
#endif
return Count;
}
/// CountLeadingOnes_32 - this function performs the operation of
/// counting the number of ones from the most significant bit to the first zero
/// bit. Ex. CountLeadingOnes_32(0xFF0FFF00) == 8.
/// Returns 32 if the word is all ones.
inline unsigned CountLeadingOnes_32(uint32_t Value) {
return CountLeadingZeros_32(~Value);
}
/// CountLeadingZeros_64 - This function performs the platform optimal form
/// of counting the number of zeros from the most significant bit to the first
/// one bit (64 bit edition.)
/// Returns 64 if the word is zero.
inline unsigned CountLeadingZeros_64(uint64_t Value) {
unsigned Count; // result
#if __GNUC__ >= 4
// PowerPC is defined for __builtin_clzll(0)
#if !defined(__ppc__) && !defined(__ppc64__)
if (!Value) return 64;
#endif
Count = __builtin_clzll(Value);
#else
if (sizeof(long) == sizeof(int64_t)) {
if (!Value) return 64;
Count = 0;
// bisection method for count leading zeros
for (unsigned Shift = 64 >> 1; Shift; Shift >>= 1) {
uint64_t Tmp = Value >> Shift;
if (Tmp) {
Value = Tmp;
} else {
Count |= Shift;
}
}
} else {
// get hi portion
uint32_t Hi = Hi_32(Value);
// if some bits in hi portion
if (Hi) {
// leading zeros in hi portion plus all bits in lo portion
Count = CountLeadingZeros_32(Hi);
} else {
// get lo portion
uint32_t Lo = Lo_32(Value);
// same as 32 bit value
Count = CountLeadingZeros_32(Lo)+32;
}
}
#endif
return Count;
}
/// CountLeadingOnes_64 - This function performs the operation
/// of counting the number of ones from the most significant bit to the first
/// zero bit (64 bit edition.)
/// Returns 64 if the word is all ones.
inline unsigned CountLeadingOnes_64(uint64_t Value) {
return CountLeadingZeros_64(~Value);
}
/// CountTrailingZeros_32 - this function performs the platform optimal form of
/// counting the number of zeros from the least significant bit to the first one
/// bit. Ex. CountTrailingZeros_32(0xFF00FF00) == 8.
/// Returns 32 if the word is zero.
inline unsigned CountTrailingZeros_32(uint32_t Value) {
#if __GNUC__ >= 4
return Value ? __builtin_ctz(Value) : 32;
#else
static const unsigned Mod37BitPosition[] = {
32, 0, 1, 26, 2, 23, 27, 0, 3, 16, 24, 30, 28, 11, 0, 13,
4, 7, 17, 0, 25, 22, 31, 15, 29, 10, 12, 6, 0, 21, 14, 9,
5, 20, 8, 19, 18
};
return Mod37BitPosition[(-Value & Value) % 37];
#endif
}
/// CountTrailingOnes_32 - this function performs the operation of
/// counting the number of ones from the least significant bit to the first zero
/// bit. Ex. CountTrailingOnes_32(0x00FF00FF) == 8.
/// Returns 32 if the word is all ones.
inline unsigned CountTrailingOnes_32(uint32_t Value) {
return CountTrailingZeros_32(~Value);
}
/// CountTrailingZeros_64 - This function performs the platform optimal form
/// of counting the number of zeros from the least significant bit to the first
/// one bit (64 bit edition.)
/// Returns 64 if the word is zero.
inline unsigned CountTrailingZeros_64(uint64_t Value) {
#if __GNUC__ >= 4
return Value ? __builtin_ctzll(Value) : 64;
#else
static const unsigned Mod67Position[] = {
64, 0, 1, 39, 2, 15, 40, 23, 3, 12, 16, 59, 41, 19, 24, 54,
4, 64, 13, 10, 17, 62, 60, 28, 42, 30, 20, 51, 25, 44, 55,
47, 5, 32, 65, 38, 14, 22, 11, 58, 18, 53, 63, 9, 61, 27,
29, 50, 43, 46, 31, 37, 21, 57, 52, 8, 26, 49, 45, 36, 56,
7, 48, 35, 6, 34, 33, 0
};
return Mod67Position[(-Value & Value) % 67];
#endif
}
/// CountTrailingOnes_64 - This function performs the operation
/// of counting the number of ones from the least significant bit to the first
/// zero bit (64 bit edition.)
/// Returns 64 if the word is all ones.
inline unsigned CountTrailingOnes_64(uint64_t Value) {
return CountTrailingZeros_64(~Value);
}
/// CountPopulation_32 - this function counts the number of set bits in a value.
/// Ex. CountPopulation(0xF000F000) = 8
/// Returns 0 if the word is zero.
inline unsigned CountPopulation_32(uint32_t Value) {
#if __GNUC__ >= 4
return __builtin_popcount(Value);
#else
uint32_t v = Value - ((Value >> 1) & 0x55555555);
v = (v & 0x33333333) + ((v >> 2) & 0x33333333);
return ((v + (v >> 4) & 0xF0F0F0F) * 0x1010101) >> 24;
#endif
}
/// CountPopulation_64 - this function counts the number of set bits in a value,
/// (64 bit edition.)
inline unsigned CountPopulation_64(uint64_t Value) {
#if __GNUC__ >= 4
return __builtin_popcountll(Value);
#else
uint64_t v = Value - ((Value >> 1) & 0x5555555555555555ULL);
v = (v & 0x3333333333333333ULL) + ((v >> 2) & 0x3333333333333333ULL);
v = (v + (v >> 4)) & 0x0F0F0F0F0F0F0F0FULL;
return unsigned((uint64_t)(v * 0x0101010101010101ULL) >> 56);
#endif
}
/// Log2_32 - This function returns the floor log base 2 of the specified value,
/// -1 if the value is zero. (32 bit edition.)
/// Ex. Log2_32(32) == 5, Log2_32(1) == 0, Log2_32(0) == -1, Log2_32(6) == 2
inline unsigned Log2_32(uint32_t Value) {
return 31 - CountLeadingZeros_32(Value);
}
/// Log2_64 - This function returns the floor log base 2 of the specified value,
/// -1 if the value is zero. (64 bit edition.)
inline unsigned Log2_64(uint64_t Value) {
return 63 - CountLeadingZeros_64(Value);
}
/// Log2_32_Ceil - This function returns the ceil log base 2 of the specified
/// value, 32 if the value is zero. (32 bit edition).
/// Ex. Log2_32_Ceil(32) == 5, Log2_32_Ceil(1) == 0, Log2_32_Ceil(6) == 3
inline unsigned Log2_32_Ceil(uint32_t Value) {
return 32-CountLeadingZeros_32(Value-1);
}
/// Log2_64_Ceil - This function returns the ceil log base 2 of the specified
/// value, 64 if the value is zero. (64 bit edition.)
inline unsigned Log2_64_Ceil(uint64_t Value) {
return 64-CountLeadingZeros_64(Value-1);
}
/// GreatestCommonDivisor64 - Return the greatest common divisor of the two
/// values using Euclid's algorithm.
inline uint64_t GreatestCommonDivisor64(uint64_t A, uint64_t B) {
while (B) {
uint64_t T = B;
B = A % B;
A = T;
}
return A;
}
/// BitsToDouble - This function takes a 64-bit integer and returns the bit
/// equivalent double.
inline double BitsToDouble(uint64_t Bits) {
union {
uint64_t L;
double D;
} T;
T.L = Bits;
return T.D;
}
/// BitsToFloat - This function takes a 32-bit integer and returns the bit
/// equivalent float.
inline float BitsToFloat(uint32_t Bits) {
union {
uint32_t I;
float F;
} T;
T.I = Bits;
return T.F;
}
/// DoubleToBits - This function takes a double and returns the bit
/// equivalent 64-bit integer. Note that copying doubles around
/// changes the bits of NaNs on some hosts, notably x86, so this
/// routine cannot be used if these bits are needed.
inline uint64_t DoubleToBits(double Double) {
union {
uint64_t L;
double D;
} T;
T.D = Double;
return T.L;
}
/// FloatToBits - This function takes a float and returns the bit
/// equivalent 32-bit integer. Note that copying floats around
/// changes the bits of NaNs on some hosts, notably x86, so this
/// routine cannot be used if these bits are needed.
inline uint32_t FloatToBits(float Float) {
union {
uint32_t I;
float F;
} T;
T.F = Float;
return T.I;
}
/// Platform-independent wrappers for the C99 isnan() function.
int IsNAN(float f);
int IsNAN(double d);
/// Platform-independent wrappers for the C99 isinf() function.
int IsInf(float f);
int IsInf(double d);
/// MinAlign - A and B are either alignments or offsets. Return the minimum
/// alignment that may be assumed after adding the two together.
inline uint64_t MinAlign(uint64_t A, uint64_t B) {
// The largest power of 2 that divides both A and B.
return (A | B) & -(A | B);
}
/// NextPowerOf2 - Returns the next power of two (in 64-bits)
/// that is strictly greater than A. Returns zero on overflow.
inline uint64_t NextPowerOf2(uint64_t A) {
A |= (A >> 1);
A |= (A >> 2);
A |= (A >> 4);
A |= (A >> 8);
A |= (A >> 16);
A |= (A >> 32);
return A + 1;
}
/// NextPowerOf2 - Returns the next power of two (in 32-bits)
/// that is strictly greater than A. Returns zero on overflow.
inline uint32_t NextPowerOf2(uint32_t A) {
A |= (A >> 1);
A |= (A >> 2);
A |= (A >> 4);
A |= (A >> 8);
A |= (A >> 16);
return A + 1;
}
/// Returns the next integer (mod 2**64) that is greater than or equal to
/// \p Value and is a multiple of \p Align. \p Align must be non-zero.
///
/// Examples:
/// \code
/// RoundUpToAlignment(5, 8) = 8
/// RoundUpToAlignment(17, 8) = 24
/// RoundUpToAlignment(~0LL, 8) = 0
/// \endcode
inline uint64_t RoundUpToAlignment(uint64_t Value, uint64_t Align) {
return ((Value + Align - 1) / Align) * Align;
}
/// Returns the offset to the next integer (mod 2**64) that is greater than
/// or equal to \p Value and is a multiple of \p Align. \p Align must be
/// non-zero.
inline uint64_t OffsetToAlignment(uint64_t Value, uint64_t Align) {
return RoundUpToAlignment(Value, Align) - Value;
}
/// abs64 - absolute value of a 64-bit int. Not all environments support
/// "abs" on whatever their name for the 64-bit int type is. The absolute
/// value of the largest negative number is undefined, as with "abs".
inline int64_t abs64(int64_t x) {
return (x < 0) ? -x : x;
}
/// SignExtend32 - Sign extend B-bit number x to 32-bit int.
/// Usage int32_t r = SignExtend32<5>(x);
template <unsigned B> inline int32_t SignExtend32(uint32_t x) {
return int32_t(x << (32 - B)) >> (32 - B);
}
/// \brief Sign extend number in the bottom B bits of X to a 32-bit int.
/// Requires 0 < B <= 32.
inline int32_t SignExtend32(uint32_t X, unsigned B) {
return int32_t(X << (32 - B)) >> (32 - B);
}
/// SignExtend64 - Sign extend B-bit number x to 64-bit int.
/// Usage int64_t r = SignExtend64<5>(x);
template <unsigned B> inline int64_t SignExtend64(uint64_t x) {
return int64_t(x << (64 - B)) >> (64 - B);
}
/// \brief Sign extend number in the bottom B bits of X to a 64-bit int.
/// Requires 0 < B <= 64.
inline int64_t SignExtend64(uint64_t X, unsigned B) {
return int64_t(X << (64 - B)) >> (64 - B);
}
} // End llvm namespace
#endif

221
runtime/llvm-type_traits.h Normal file
View File

@ -0,0 +1,221 @@
//===- llvm/Support/type_traits.h - Simplfied type traits -------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file provides a template class that determines if a type is a class or
// not. The basic mechanism, based on using the pointer to member function of
// a zero argument to a function was "boosted" from the boost type_traits
// library. See http://www.boost.org/ for all the gory details.
//
//===----------------------------------------------------------------------===//
// Taken from llvmCore-3425.0.31.
#ifndef LLVM_SUPPORT_TYPE_TRAITS_H
#define LLVM_SUPPORT_TYPE_TRAITS_H
#include <cstddef>
#include <utility>
#ifndef __has_feature
#define LLVM_DEFINED_HAS_FEATURE
#define __has_feature(x) 0
#endif
// This is actually the conforming implementation which works with abstract
// classes. However, enough compilers have trouble with it that most will use
// the one in boost/type_traits/object_traits.hpp. This implementation actually
// works with VC7.0, but other interactions seem to fail when we use it.
namespace objc {
namespace dont_use
{
// These two functions should never be used. They are helpers to
// the is_class template below. They cannot be located inside
// is_class because doing so causes at least GCC to think that
// the value of the "value" enumerator is not constant. Placing
// them out here (for some strange reason) allows the sizeof
// operator against them to magically be constant. This is
// important to make the is_class<T>::value idiom zero cost. it
// evaluates to a constant 1 or 0 depending on whether the
// parameter T is a class or not (respectively).
template<typename T> char is_class_helper(void(T::*)());
template<typename T> double is_class_helper(...);
}
template <typename T>
struct is_class
{
// is_class<> metafunction due to Paul Mensonides (leavings@attbi.com). For
// more details:
// http://groups.google.com/groups?hl=en&selm=000001c1cc83%24e154d5e0%247772e50c%40c161550a&rnum=1
public:
static const bool value =
sizeof(char) == sizeof(dont_use::is_class_helper<T>(0));
};
/// isPodLike - This is a type trait that is used to determine whether a given
/// type can be copied around with memcpy instead of running ctors etc.
template <typename T>
struct isPodLike {
#if __has_feature(is_trivially_copyable)
// If the compiler supports the is_trivially_copyable trait use it, as it
// matches the definition of isPodLike closely.
static const bool value = __is_trivially_copyable(T);
#else
// If we don't know anything else, we can (at least) assume that all non-class
// types are PODs.
static const bool value = !is_class<T>::value;
#endif
};
// std::pair's are pod-like if their elements are.
template<typename T, typename U>
struct isPodLike<std::pair<T, U> > {
static const bool value = isPodLike<T>::value && isPodLike<U>::value;
};
template <class T, T v>
struct integral_constant {
typedef T value_type;
static const value_type value = v;
typedef integral_constant<T,v> type;
operator value_type() { return value; }
};
typedef integral_constant<bool, true> true_type;
typedef integral_constant<bool, false> false_type;
/// \brief Metafunction that determines whether the two given types are
/// equivalent.
template<typename T, typename U> struct is_same : public false_type {};
template<typename T> struct is_same<T, T> : public true_type {};
/// \brief Metafunction that removes const qualification from a type.
template <typename T> struct remove_const { typedef T type; };
template <typename T> struct remove_const<const T> { typedef T type; };
/// \brief Metafunction that removes volatile qualification from a type.
template <typename T> struct remove_volatile { typedef T type; };
template <typename T> struct remove_volatile<volatile T> { typedef T type; };
/// \brief Metafunction that removes both const and volatile qualification from
/// a type.
template <typename T> struct remove_cv {
typedef typename remove_const<typename remove_volatile<T>::type>::type type;
};
/// \brief Helper to implement is_integral metafunction.
template <typename T> struct is_integral_impl : false_type {};
template <> struct is_integral_impl< bool> : true_type {};
template <> struct is_integral_impl< char> : true_type {};
template <> struct is_integral_impl< signed char> : true_type {};
template <> struct is_integral_impl<unsigned char> : true_type {};
template <> struct is_integral_impl< wchar_t> : true_type {};
template <> struct is_integral_impl< short> : true_type {};
template <> struct is_integral_impl<unsigned short> : true_type {};
template <> struct is_integral_impl< int> : true_type {};
template <> struct is_integral_impl<unsigned int> : true_type {};
template <> struct is_integral_impl< long> : true_type {};
template <> struct is_integral_impl<unsigned long> : true_type {};
template <> struct is_integral_impl< long long> : true_type {};
template <> struct is_integral_impl<unsigned long long> : true_type {};
/// \brief Metafunction that determines whether the given type is an integral
/// type.
template <typename T>
struct is_integral : is_integral_impl<T> {};
/// \brief Metafunction to remove reference from a type.
template <typename T> struct remove_reference { typedef T type; };
template <typename T> struct remove_reference<T&> { typedef T type; };
/// \brief Metafunction that determines whether the given type is a pointer
/// type.
template <typename T> struct is_pointer : false_type {};
template <typename T> struct is_pointer<T*> : true_type {};
template <typename T> struct is_pointer<T* const> : true_type {};
template <typename T> struct is_pointer<T* volatile> : true_type {};
template <typename T> struct is_pointer<T* const volatile> : true_type {};
/// \brief Metafunction that determines whether the given type is either an
/// integral type or an enumeration type.
///
/// Note that this accepts potentially more integral types than we whitelist
/// above for is_integral because it is based on merely being convertible
/// implicitly to an integral type.
template <typename T> class is_integral_or_enum {
// Provide an overload which can be called with anything implicitly
// convertible to an unsigned long long. This should catch integer types and
// enumeration types at least. We blacklist classes with conversion operators
// below.
static double check_int_convertible(unsigned long long);
static char check_int_convertible(...);
typedef typename remove_reference<T>::type UnderlyingT;
static UnderlyingT &nonce_instance;
public:
static const bool
value = (!is_class<UnderlyingT>::value && !is_pointer<UnderlyingT>::value &&
!is_same<UnderlyingT, float>::value &&
!is_same<UnderlyingT, double>::value &&
sizeof(char) != sizeof(check_int_convertible(nonce_instance)));
};
// enable_if_c - Enable/disable a template based on a metafunction
template<bool Cond, typename T = void>
struct enable_if_c {
typedef T type;
};
template<typename T> struct enable_if_c<false, T> { };
// enable_if - Enable/disable a template based on a metafunction
template<typename Cond, typename T = void>
struct enable_if : public enable_if_c<Cond::value, T> { };
namespace dont_use {
template<typename Base> char base_of_helper(const volatile Base*);
template<typename Base> double base_of_helper(...);
}
/// is_base_of - Metafunction to determine whether one type is a base class of
/// (or identical to) another type.
template<typename Base, typename Derived>
struct is_base_of {
static const bool value
= is_class<Base>::value && is_class<Derived>::value &&
sizeof(char) == sizeof(dont_use::base_of_helper<Base>((Derived*)0));
};
// remove_pointer - Metafunction to turn Foo* into Foo. Defined in
// C++0x [meta.trans.ptr].
template <typename T> struct remove_pointer { typedef T type; };
template <typename T> struct remove_pointer<T*> { typedef T type; };
template <typename T> struct remove_pointer<T*const> { typedef T type; };
template <typename T> struct remove_pointer<T*volatile> { typedef T type; };
template <typename T> struct remove_pointer<T*const volatile> {
typedef T type; };
template <bool, typename T, typename F>
struct conditional { typedef T type; };
template <typename T, typename F>
struct conditional<false, T, F> { typedef F type; };
}
#ifdef LLVM_DEFINED_HAS_FEATURE
#undef __has_feature
#endif
#endif

138
runtime/maptable.h Normal file
View File

@ -0,0 +1,138 @@
/*
* Copyright (c) 1999-2003, 2006-2007 Apple Inc. All Rights Reserved.
*
* @APPLE_LICENSE_HEADER_START@
*
* 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 2.0 (the 'License'). You may not use this file except in
* compliance with the License. Please obtain a copy of the License at
* http://www.opensource.apple.com/apsl/ 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, QUIET ENJOYMENT OR NON-INFRINGEMENT.
* Please see the License for the specific language governing rights and
* limitations under the License.
*
* @APPLE_LICENSE_HEADER_END@
*/
/* maptable.h
Scalable hash table of mappings.
Bertrand, August 1990
Copyright 1990-1996 NeXT Software, Inc.
*/
#ifndef _OBJC_MAPTABLE_H_
#define _OBJC_MAPTABLE_H_
#ifndef _OBJC_PRIVATE_H_
# define OBJC_MAP_AVAILABILITY \
__OSX_DEPRECATED(10.0, 10.1, "NXMapTable is deprecated") \
__IOS_UNAVAILABLE __TVOS_UNAVAILABLE __WATCHOS_UNAVAILABLE
#else
# define OBJC_MAP_AVAILABILITY
#endif
#include <objc/objc.h>
__BEGIN_DECLS
/*************** Definitions ***************/
/* This module allows hashing of arbitrary associations [key -> value]. Keys and values must be pointers or integers, and client is responsible for allocating/deallocating this data. A deallocation call-back is provided.
NX_MAPNOTAKEY (-1) is used internally as a marker, and therefore keys must always be different from -1.
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 _NXMapTable {
/* private data structure; may change */
const struct _NXMapTablePrototype *prototype;
unsigned count;
unsigned nbBucketsMinusOne;
void *buckets;
} NXMapTable OBJC_MAP_AVAILABILITY;
typedef struct _NXMapTablePrototype {
unsigned (*hash)(NXMapTable *, const void *key);
int (*isEqual)(NXMapTable *, const void *key1, const void *key2);
void (*free)(NXMapTable *, void *key, void *value);
int style; /* reserved for future expansion; currently 0 */
} NXMapTablePrototype OBJC_MAP_AVAILABILITY;
/* invariants assumed by the implementation:
A - key != -1
B - key1 == key2 => hash(key1) == hash(key2)
when key varies over time, hash(key) must remain invariant
e.g. if string key, the string must not be changed
C - isEqual(key1, key2) => key1 == key2
*/
#define NX_MAPNOTAKEY ((void *)(-1))
/*************** Functions ***************/
OBJC_EXPORT NXMapTable *NXCreateMapTableFromZone(NXMapTablePrototype prototype, unsigned capacity, void *z) OBJC_MAP_AVAILABILITY;
OBJC_EXPORT NXMapTable *NXCreateMapTable(NXMapTablePrototype prototype, unsigned capacity) OBJC_MAP_AVAILABILITY;
/* capacity is only a hint; 0 creates a small table */
OBJC_EXPORT void NXFreeMapTable(NXMapTable *table) OBJC_MAP_AVAILABILITY;
/* call free for each pair, and recovers table */
OBJC_EXPORT void NXResetMapTable(NXMapTable *table) OBJC_MAP_AVAILABILITY;
/* free each pair; keep current capacity */
OBJC_EXPORT BOOL NXCompareMapTables(NXMapTable *table1, NXMapTable *table2) OBJC_MAP_AVAILABILITY;
/* Returns YES if the two sets are equal (each member of table1 in table2, and table have same size) */
OBJC_EXPORT unsigned NXCountMapTable(NXMapTable *table) OBJC_MAP_AVAILABILITY;
/* current number of data in table */
OBJC_EXPORT void *NXMapMember(NXMapTable *table, const void *key, void **value) OBJC_MAP_AVAILABILITY;
/* return original table key or NX_MAPNOTAKEY. If key is found, value is set */
OBJC_EXPORT void *NXMapGet(NXMapTable *table, const void *key) OBJC_MAP_AVAILABILITY;
/* return original corresponding value or NULL. When NULL need be stored as value, NXMapMember can be used to test for presence */
OBJC_EXPORT void *NXMapInsert(NXMapTable *table, const void *key, const void *value) OBJC_MAP_AVAILABILITY;
/* override preexisting pair; Return previous value or NULL. */
OBJC_EXPORT void *NXMapRemove(NXMapTable *table, const void *key) OBJC_MAP_AVAILABILITY;
/* previous value or NULL is returned */
/* Iteration over all elements of a table consists in setting up an iteration state and then to progress until all entries have been visited. An example of use for counting elements in a table is:
unsigned count = 0;
const MyKey *key;
const MyValue *value;
NXMapState state = NXInitMapState(table);
while(NXNextMapState(table, &state, &key, &value)) {
count++;
}
*/
typedef struct {int index;} NXMapState OBJC_MAP_AVAILABILITY;
/* callers should not rely on actual contents of the struct */
OBJC_EXPORT NXMapState NXInitMapState(NXMapTable *table) OBJC_MAP_AVAILABILITY;
OBJC_EXPORT int NXNextMapState(NXMapTable *table, NXMapState *state, const void **key, const void **value) OBJC_MAP_AVAILABILITY;
/* returns 0 when all elements have been visited */
/*************** Conveniences ***************/
OBJC_EXPORT const NXMapTablePrototype NXPtrValueMapPrototype OBJC_MAP_AVAILABILITY;
/* hashing is pointer/integer hashing;
isEqual is identity;
free is no-op. */
OBJC_EXPORT const NXMapTablePrototype NXStrValueMapPrototype OBJC_MAP_AVAILABILITY;
/* hashing is string hashing;
isEqual is strcmp;
free is no-op. */
OBJC_EXPORT const NXMapTablePrototype NXObjectMapPrototype OBJC2_UNAVAILABLE;
/* for objects; uses methods: hash, isEqual:, free, all for key. */
__END_DECLS
#endif /* _OBJC_MAPTABLE_H_ */

453
runtime/maptable.mm Normal file
View File

@ -0,0 +1,453 @@
/*
* Copyright (c) 1999-2003, 2005-2007 Apple Inc. All Rights Reserved.
*
* @APPLE_LICENSE_HEADER_START@
*
* 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 2.0 (the 'License'). You may not use this file except in
* compliance with the License. Please obtain a copy of the License at
* http://www.opensource.apple.com/apsl/ 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, QUIET ENJOYMENT OR NON-INFRINGEMENT.
* Please see the License for the specific language governing rights and
* limitations under the License.
*
* @APPLE_LICENSE_HEADER_END@
*/
/* maptable.m
Copyright 1990-1996 NeXT Software, Inc.
Created by Bertrand Serlet, August 1990
*/
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include "objc-private.h"
#include "maptable.h"
#include "hashtable2.h"
/****** Macros and utilities ****************************/
#if defined(DEBUG)
#define INLINE
#else
#define INLINE inline
#endif
typedef struct _MapPair {
const void *key;
const void *value;
} MapPair;
static INLINE unsigned xorHash(unsigned hash) {
unsigned xored = (hash & 0xffff) ^ (hash >> 16);
return ((xored * 65521) + hash);
}
static INLINE unsigned bucketOf(NXMapTable *table, const void *key) {
unsigned hash = (table->prototype->hash)(table, key);
return hash & table->nbBucketsMinusOne;
}
static INLINE int isEqual(NXMapTable *table, const void *key1, const void *key2) {
return (key1 == key2) ? 1 : (table->prototype->isEqual)(table, key1, key2);
}
static INLINE unsigned nextIndex(NXMapTable *table, unsigned index) {
return (index + 1) & table->nbBucketsMinusOne;
}
static INLINE void *allocBuckets(void *z, unsigned nb) {
MapPair *pairs = 1+(MapPair *)malloc_zone_malloc((malloc_zone_t *)z, ((nb+1) * sizeof(MapPair)));
MapPair *pair = pairs;
while (nb--) { pair->key = NX_MAPNOTAKEY; pair->value = NULL; pair++; }
return pairs;
}
static INLINE void freeBuckets(void *p) {
free(-1+(MapPair *)p);
}
/***** Global data and bootstrap **********************/
static int isEqualPrototype (const void *info, const void *data1, const void *data2) {
NXHashTablePrototype *proto1 = (NXHashTablePrototype *) data1;
NXHashTablePrototype *proto2 = (NXHashTablePrototype *) data2;
return (proto1->hash == proto2->hash) && (proto1->isEqual == proto2->isEqual) && (proto1->free == proto2->free) && (proto1->style == proto2->style);
};
static uintptr_t hashPrototype (const void *info, const void *data) {
NXHashTablePrototype *proto = (NXHashTablePrototype *) data;
return NXPtrHash(info, (void*)proto->hash) ^ NXPtrHash(info, (void*)proto->isEqual) ^ NXPtrHash(info, (void*)proto->free) ^ (uintptr_t) proto->style;
};
static NXHashTablePrototype protoPrototype = {
hashPrototype, isEqualPrototype, NXNoEffectFree, 0
};
static NXHashTable *prototypes = NULL;
/* table of all prototypes */
/**** Fundamentals Operations **************/
NXMapTable *NXCreateMapTableFromZone(NXMapTablePrototype prototype, unsigned capacity, void *z) {
NXMapTable *table = (NXMapTable *)malloc_zone_malloc((malloc_zone_t *)z, sizeof(NXMapTable));
NXMapTablePrototype *proto;
if (! prototypes) prototypes = NXCreateHashTable(protoPrototype, 0, NULL);
if (! prototype.hash || ! prototype.isEqual || ! prototype.free || prototype.style) {
_objc_inform("*** NXCreateMapTable: invalid creation parameters\n");
return NULL;
}
proto = (NXMapTablePrototype *)NXHashGet(prototypes, &prototype);
if (! proto) {
proto = (NXMapTablePrototype *)malloc(sizeof(NXMapTablePrototype));
*proto = prototype;
(void)NXHashInsert(prototypes, proto);
}
table->prototype = proto; table->count = 0;
table->nbBucketsMinusOne = exp2u(log2u(capacity)+1) - 1;
table->buckets = allocBuckets(z, table->nbBucketsMinusOne + 1);
return table;
}
NXMapTable *NXCreateMapTable(NXMapTablePrototype prototype, unsigned capacity) {
return NXCreateMapTableFromZone(prototype, capacity, malloc_default_zone());
}
void NXFreeMapTable(NXMapTable *table) {
NXResetMapTable(table);
freeBuckets(table->buckets);
free(table);
}
void NXResetMapTable(NXMapTable *table) {
MapPair *pairs = (MapPair *)table->buckets;
void (*freeProc)(struct _NXMapTable *, void *, void *) = table->prototype->free;
unsigned index = table->nbBucketsMinusOne + 1;
while (index--) {
if (pairs->key != NX_MAPNOTAKEY) {
freeProc(table, (void *)pairs->key, (void *)pairs->value);
pairs->key = NX_MAPNOTAKEY; pairs->value = NULL;
}
pairs++;
}
table->count = 0;
}
BOOL NXCompareMapTables(NXMapTable *table1, NXMapTable *table2) {
if (table1 == table2) return YES;
if (table1->count != table2->count) return NO;
else {
const void *key;
const void *value;
NXMapState state = NXInitMapState(table1);
while (NXNextMapState(table1, &state, &key, &value)) {
if (NXMapMember(table2, key, (void**)&value) == NX_MAPNOTAKEY) return NO;
}
return YES;
}
}
unsigned NXCountMapTable(NXMapTable *table) { return table->count; }
static INLINE void *_NXMapMember(NXMapTable *table, const void *key, void **value) {
MapPair *pairs = (MapPair *)table->buckets;
unsigned index = bucketOf(table, key);
MapPair *pair = pairs + index;
if (pair->key == NX_MAPNOTAKEY) return NX_MAPNOTAKEY;
if (isEqual(table, pair->key, key)) {
*value = (void *)pair->value;
return (void *)pair->key;
} else {
unsigned index2 = index;
while ((index2 = nextIndex(table, index2)) != index) {
pair = pairs + index2;
if (pair->key == NX_MAPNOTAKEY) return NX_MAPNOTAKEY;
if (isEqual(table, pair->key, key)) {
*value = (void *)pair->value;
return (void *)pair->key;
}
}
return NX_MAPNOTAKEY;
}
}
void *NXMapMember(NXMapTable *table, const void *key, void **value) {
return _NXMapMember(table, key, value);
}
void *NXMapGet(NXMapTable *table, const void *key) {
void *value;
return (_NXMapMember(table, key, &value) != NX_MAPNOTAKEY) ? value : NULL;
}
static void _NXMapRehash(NXMapTable *table) {
MapPair *pairs = (MapPair *)table->buckets;
MapPair *pair = pairs;
unsigned numBuckets = table->nbBucketsMinusOne + 1;
unsigned index = numBuckets;
unsigned oldCount = table->count;
table->nbBucketsMinusOne = 2 * numBuckets - 1;
table->count = 0;
table->buckets = allocBuckets(malloc_zone_from_ptr(table), table->nbBucketsMinusOne + 1);
while (index--) {
if (pair->key != NX_MAPNOTAKEY) {
(void)NXMapInsert(table, pair->key, pair->value);
}
pair++;
}
if (oldCount != table->count)
_objc_inform("*** maptable: count differs after rehashing; probably indicates a broken invariant: there are x and y such as isEqual(x, y) is TRUE but hash(x) != hash (y)\n");
freeBuckets(pairs);
}
void *NXMapInsert(NXMapTable *table, const void *key, const void *value) {
MapPair *pairs = (MapPair *)table->buckets;
unsigned index = bucketOf(table, key);
MapPair *pair = pairs + index;
if (key == NX_MAPNOTAKEY) {
_objc_inform("*** NXMapInsert: invalid key: -1\n");
return NULL;
}
unsigned numBuckets = table->nbBucketsMinusOne + 1;
if (pair->key == NX_MAPNOTAKEY) {
pair->key = key; pair->value = value;
table->count++;
if (table->count * 4 > numBuckets * 3) _NXMapRehash(table);
return NULL;
}
if (isEqual(table, pair->key, key)) {
const void *old = pair->value;
if (old != value) pair->value = value;/* avoid writing unless needed! */
return (void *)old;
} else if (table->count == numBuckets) {
/* no room: rehash and retry */
_NXMapRehash(table);
return NXMapInsert(table, key, value);
} else {
unsigned index2 = index;
while ((index2 = nextIndex(table, index2)) != index) {
pair = pairs + index2;
if (pair->key == NX_MAPNOTAKEY) {
pair->key = key; pair->value = value;
table->count++;
if (table->count * 4 > numBuckets * 3) _NXMapRehash(table);
return NULL;
}
if (isEqual(table, pair->key, key)) {
const void *old = pair->value;
if (old != value) pair->value = value;/* avoid writing unless needed! */
return (void *)old;
}
}
/* no room: can't happen! */
_objc_inform("**** NXMapInsert: bug\n");
return NULL;
}
}
static int mapRemove = 0;
void *NXMapRemove(NXMapTable *table, const void *key) {
MapPair *pairs = (MapPair *)table->buckets;
unsigned index = bucketOf(table, key);
MapPair *pair = pairs + index;
unsigned chain = 1; /* number of non-nil pairs in a row */
int found = 0;
const void *old = NULL;
if (pair->key == NX_MAPNOTAKEY) return NULL;
mapRemove ++;
/* compute chain */
{
unsigned index2 = index;
if (isEqual(table, pair->key, key)) {found ++; old = pair->value; }
while ((index2 = nextIndex(table, index2)) != index) {
pair = pairs + index2;
if (pair->key == NX_MAPNOTAKEY) break;
if (isEqual(table, pair->key, key)) {found ++; old = pair->value; }
chain++;
}
}
if (! found) return NULL;
if (found != 1) _objc_inform("**** NXMapRemove: incorrect table\n");
/* remove then reinsert */
{
MapPair buffer[16];
MapPair *aux = (chain > 16) ? (MapPair *)malloc(sizeof(MapPair)*(chain-1)) : buffer;
unsigned auxnb = 0;
int nb = chain;
unsigned index2 = index;
while (nb--) {
pair = pairs + index2;
if (! isEqual(table, pair->key, key)) aux[auxnb++] = *pair;
pair->key = NX_MAPNOTAKEY; pair->value = NULL;
index2 = nextIndex(table, index2);
}
table->count -= chain;
if (auxnb != chain-1) _objc_inform("**** NXMapRemove: bug\n");
while (auxnb--) NXMapInsert(table, aux[auxnb].key, aux[auxnb].value);
if (chain > 16) free(aux);
}
return (void *)old;
}
NXMapState NXInitMapState(NXMapTable *table) {
NXMapState state;
state.index = table->nbBucketsMinusOne + 1;
return state;
}
int NXNextMapState(NXMapTable *table, NXMapState *state, const void **key, const void **value) {
MapPair *pairs = (MapPair *)table->buckets;
while (state->index--) {
MapPair *pair = pairs + state->index;
if (pair->key != NX_MAPNOTAKEY) {
*key = pair->key; *value = pair->value;
return YES;
}
}
return NO;
}
/***********************************************************************
* NXMapKeyCopyingInsert
* Like NXMapInsert, but strdups the key if necessary.
* Used to prevent stale pointers when bundles are unloaded.
**********************************************************************/
void *NXMapKeyCopyingInsert(NXMapTable *table, const void *key, const void *value)
{
void *realKey;
void *realValue = NULL;
if ((realKey = NXMapMember(table, key, &realValue)) != NX_MAPNOTAKEY) {
// key DOES exist in table - use table's key for insertion
} else {
// key DOES NOT exist in table - copy the new key before insertion
realKey = (void *)strdupIfMutable((char *)key);
}
return NXMapInsert(table, realKey, value);
}
/***********************************************************************
* NXMapKeyFreeingRemove
* Like NXMapRemove, but frees the existing key if necessary.
* Used to prevent stale pointers when bundles are unloaded.
**********************************************************************/
void *NXMapKeyFreeingRemove(NXMapTable *table, const void *key)
{
void *realKey;
void *realValue = NULL;
if ((realKey = NXMapMember(table, key, &realValue)) != NX_MAPNOTAKEY) {
// key DOES exist in table - remove pair and free key
realValue = NXMapRemove(table, realKey);
// free the key from the table, not necessarily the one given
freeIfMutable((char *)realKey);
return realValue;
} else {
// key DOES NOT exist in table - nothing to do
return NULL;
}
}
/**** Conveniences *************************************/
static unsigned _mapPtrHash(NXMapTable *table, const void *key) {
#ifdef __LP64__
return (unsigned)(((uintptr_t)key) >> 3);
#else
return ((uintptr_t)key) >> 2;
#endif
}
static unsigned _mapStrHash(NXMapTable *table, const void *key) {
unsigned hash = 0;
unsigned char *s = (unsigned char *)key;
/* unsigned to avoid a sign-extend */
/* unroll the loop */
if (s) for (; ; ) {
if (*s == '\0') break;
hash ^= *s++;
if (*s == '\0') break;
hash ^= *s++ << 8;
if (*s == '\0') break;
hash ^= *s++ << 16;
if (*s == '\0') break;
hash ^= *s++ << 24;
}
return xorHash(hash);
}
static int _mapPtrIsEqual(NXMapTable *table, const void *key1, const void *key2) {
return key1 == key2;
}
static int _mapStrIsEqual(NXMapTable *table, const void *key1, const void *key2) {
if (key1 == key2) return YES;
if (! key1) return ! strlen ((char *) key2);
if (! key2) return ! strlen ((char *) key1);
if (((char *) key1)[0] != ((char *) key2)[0]) return NO;
return (strcmp((char *) key1, (char *) key2)) ? NO : YES;
}
static void _mapNoFree(NXMapTable *table, void *key, void *value) {}
const NXMapTablePrototype NXPtrValueMapPrototype = {
_mapPtrHash, _mapPtrIsEqual, _mapNoFree, 0
};
const NXMapTablePrototype NXStrValueMapPrototype = {
_mapStrHash, _mapStrIsEqual, _mapNoFree, 0
};
#if !__OBJC2__ && !TARGET_OS_WIN32
/* This only works with class Object, which is unavailable. */
/* Method prototypes */
@interface DoesNotExist
+ (id)class;
+ (id)initialize;
- (id)description;
- (const char *)UTF8String;
- (unsigned long)hash;
- (BOOL)isEqual:(id)object;
- (void)free;
@end
static unsigned _mapObjectHash(NXMapTable *table, const void *key) {
return [(id)key hash];
}
static int _mapObjectIsEqual(NXMapTable *table, const void *key1, const void *key2) {
return [(id)key1 isEqual:(id)key2];
}
static void _mapObjectFree(NXMapTable *table, void *key, void *value) {
[(id)key free];
}
const NXMapTablePrototype NXObjectMapPrototype = {
_mapObjectHash, _mapObjectIsEqual, _mapObjectFree, 0
};
#endif

333
runtime/message.h Normal file
View File

@ -0,0 +1,333 @@
/*
* Copyright (c) 1999-2007 Apple Inc. All Rights Reserved.
*
* @APPLE_LICENSE_HEADER_START@
*
* 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 2.0 (the 'License'). You may not use this file except in
* compliance with the License. Please obtain a copy of the License at
* http://www.opensource.apple.com/apsl/ 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, QUIET ENJOYMENT OR NON-INFRINGEMENT.
* Please see the License for the specific language governing rights and
* limitations under the License.
*
* @APPLE_LICENSE_HEADER_END@
*/
#ifndef _OBJC_MESSAGE_H
#define _OBJC_MESSAGE_H
#pragma GCC system_header
#include <objc/objc.h>
#include <objc/runtime.h>
#pragma GCC system_header
#ifndef OBJC_SUPER
#define OBJC_SUPER
/// Specifies the superclass of an instance.
struct objc_super {
/// Specifies an instance of a class.
__unsafe_unretained id receiver;
/// Specifies the particular superclass of the instance to message.
#if !defined(__cplusplus) && !__OBJC2__
/* For compatibility with old objc-runtime.h header */
__unsafe_unretained Class class;
#else
__unsafe_unretained Class super_class;
#endif
/* super_class is the first class to search */
};
#endif
/* Basic Messaging Primitives
*
* On some architectures, use objc_msgSend_stret for some struct return types.
* On some architectures, use objc_msgSend_fpret for some float return types.
* On some architectures, use objc_msgSend_fp2ret for some float return types.
*
* These functions must be cast to an appropriate function pointer type
* before being called.
*/
#if !OBJC_OLD_DISPATCH_PROTOTYPES
OBJC_EXPORT void objc_msgSend(void /* id self, SEL op, ... */ )
OBJC_AVAILABLE(10.0, 2.0, 9.0, 1.0);
OBJC_EXPORT void objc_msgSendSuper(void /* struct objc_super *super, SEL op, ... */ )
OBJC_AVAILABLE(10.0, 2.0, 9.0, 1.0);
#else
/**
* Sends a message with a simple return value to an instance of a class.
*
* @param self A pointer to the instance of the class that is to receive the message.
* @param op The selector of the method that handles the message.
* @param ...
* A variable argument list containing the arguments to the method.
*
* @return The return value of the method.
*
* @note When it encounters a method call, the compiler generates a call to one of the
* functions \c objc_msgSend, \c objc_msgSend_stret, \c objc_msgSendSuper, or \c objc_msgSendSuper_stret.
* Messages sent to an objects superclass (using the \c super keyword) are sent using \c objc_msgSendSuper;
* other messages are sent using \c objc_msgSend. Methods that have data structures as return values
* are sent using \c objc_msgSendSuper_stret and \c objc_msgSend_stret.
*/
OBJC_EXPORT id objc_msgSend(id self, SEL op, ...)
OBJC_AVAILABLE(10.0, 2.0, 9.0, 1.0);
/**
* Sends a message with a simple return value to the superclass of an instance of a class.
*
* @param super A pointer to an \c objc_super data structure. Pass values identifying the
* context the message was sent to, including the instance of the class that is to receive the
* message and the superclass at which to start searching for the method implementation.
* @param op A pointer of type SEL. Pass the selector of the method that will handle the message.
* @param ...
* A variable argument list containing the arguments to the method.
*
* @return The return value of the method identified by \e op.
*
* @see objc_msgSend
*/
OBJC_EXPORT id objc_msgSendSuper(struct objc_super *super, SEL op, ...)
OBJC_AVAILABLE(10.0, 2.0, 9.0, 1.0);
#endif
/* Struct-returning Messaging Primitives
*
* Use these functions to call methods that return structs on the stack.
* On some architectures, some structures are returned in registers.
* Consult your local function call ABI documentation for details.
*
* These functions must be cast to an appropriate function pointer type
* before being called.
*/
#if !OBJC_OLD_DISPATCH_PROTOTYPES
OBJC_EXPORT void objc_msgSend_stret(void /* id self, SEL op, ... */ )
OBJC_AVAILABLE(10.0, 2.0, 9.0, 1.0)
OBJC_ARM64_UNAVAILABLE;
OBJC_EXPORT void objc_msgSendSuper_stret(void /* struct objc_super *super, SEL op, ... */ )
OBJC_AVAILABLE(10.0, 2.0, 9.0, 1.0)
OBJC_ARM64_UNAVAILABLE;
#else
/**
* Sends a message with a data-structure return value to an instance of a class.
*
* @see objc_msgSend
*/
OBJC_EXPORT void objc_msgSend_stret(id self, SEL op, ...)
OBJC_AVAILABLE(10.0, 2.0, 9.0, 1.0)
OBJC_ARM64_UNAVAILABLE;
/**
* Sends a message with a data-structure return value to the superclass of an instance of a class.
*
* @see objc_msgSendSuper
*/
OBJC_EXPORT void objc_msgSendSuper_stret(struct objc_super *super, SEL op, ...)
OBJC_AVAILABLE(10.0, 2.0, 9.0, 1.0)
OBJC_ARM64_UNAVAILABLE;
#endif
/* Floating-point-returning Messaging Primitives
*
* Use these functions to call methods that return floating-point values
* on the stack.
* Consult your local function call ABI documentation for details.
*
* arm: objc_msgSend_fpret not used
* i386: objc_msgSend_fpret used for `float`, `double`, `long double`.
* x86-64: objc_msgSend_fpret used for `long double`.
*
* arm: objc_msgSend_fp2ret not used
* i386: objc_msgSend_fp2ret not used
* x86-64: objc_msgSend_fp2ret used for `_Complex long double`.
*
* These functions must be cast to an appropriate function pointer type
* before being called.
*/
#if !OBJC_OLD_DISPATCH_PROTOTYPES
# if defined(__i386__)
OBJC_EXPORT void objc_msgSend_fpret(void /* id self, SEL op, ... */ )
OBJC_AVAILABLE(10.4, 2.0, 9.0, 1.0);
# elif defined(__x86_64__)
OBJC_EXPORT void objc_msgSend_fpret(void /* id self, SEL op, ... */ )
OBJC_AVAILABLE(10.5, 2.0, 9.0, 1.0);
OBJC_EXPORT void objc_msgSend_fp2ret(void /* id self, SEL op, ... */ )
OBJC_AVAILABLE(10.5, 2.0, 9.0, 1.0);
# endif
// !OBJC_OLD_DISPATCH_PROTOTYPES
#else
// OBJC_OLD_DISPATCH_PROTOTYPES
# if defined(__i386__)
/**
* Sends a message with a floating-point return value to an instance of a class.
*
* @see objc_msgSend
* @note On the i386 platform, the ABI for functions returning a floating-point value is
* incompatible with that for functions returning an integral type. On the i386 platform, therefore,
* you must use \c objc_msgSend_fpret for functions returning non-integral type. For \c float or
* \c long \c double return types, cast the function to an appropriate function pointer type first.
*/
OBJC_EXPORT double objc_msgSend_fpret(id self, SEL op, ...)
OBJC_AVAILABLE(10.4, 2.0, 9.0, 1.0);
/* Use objc_msgSendSuper() for fp-returning messages to super. */
/* See also objc_msgSendv_fpret() below. */
# elif defined(__x86_64__)
/**
* Sends a message with a floating-point return value to an instance of a class.
*
* @see objc_msgSend
*/
OBJC_EXPORT long double objc_msgSend_fpret(id self, SEL op, ...)
OBJC_AVAILABLE(10.5, 2.0, 9.0, 1.0);
# if __STDC_VERSION__ >= 199901L
OBJC_EXPORT _Complex long double objc_msgSend_fp2ret(id self, SEL op, ...)
OBJC_AVAILABLE(10.5, 2.0, 9.0, 1.0);
# else
OBJC_EXPORT void objc_msgSend_fp2ret(id self, SEL op, ...)
OBJC_AVAILABLE(10.5, 2.0, 9.0, 1.0);
# endif
/* Use objc_msgSendSuper() for fp-returning messages to super. */
/* See also objc_msgSendv_fpret() below. */
# endif
// OBJC_OLD_DISPATCH_PROTOTYPES
#endif
/* Direct Method Invocation Primitives
* Use these functions to call the implementation of a given Method.
* This is faster than calling method_getImplementation() and method_getName().
*
* The receiver must not be nil.
*
* These functions must be cast to an appropriate function pointer type
* before being called.
*/
#if !OBJC_OLD_DISPATCH_PROTOTYPES
OBJC_EXPORT void method_invoke(void /* id receiver, Method m, ... */ )
OBJC_AVAILABLE(10.5, 2.0, 9.0, 1.0);
OBJC_EXPORT void method_invoke_stret(void /* id receiver, Method m, ... */ )
OBJC_AVAILABLE(10.5, 2.0, 9.0, 1.0)
OBJC_ARM64_UNAVAILABLE;
#else
OBJC_EXPORT id method_invoke(id receiver, Method m, ...)
OBJC_AVAILABLE(10.5, 2.0, 9.0, 1.0);
OBJC_EXPORT void method_invoke_stret(id receiver, Method m, ...)
OBJC_AVAILABLE(10.5, 2.0, 9.0, 1.0)
OBJC_ARM64_UNAVAILABLE;
#endif
/* Message Forwarding Primitives
* Use these functions to forward a message as if the receiver did not
* respond to it.
*
* The receiver must not be nil.
*
* class_getMethodImplementation() may return (IMP)_objc_msgForward.
* class_getMethodImplementation_stret() may return (IMP)_objc_msgForward_stret
*
* These functions must be cast to an appropriate function pointer type
* before being called.
*
* Before Mac OS X 10.6, _objc_msgForward must not be called directly
* but may be compared to other IMP values.
*/
#if !OBJC_OLD_DISPATCH_PROTOTYPES
OBJC_EXPORT void _objc_msgForward(void /* id receiver, SEL sel, ... */ )
OBJC_AVAILABLE(10.0, 2.0, 9.0, 1.0);
OBJC_EXPORT void _objc_msgForward_stret(void /* id receiver, SEL sel, ... */ )
OBJC_AVAILABLE(10.6, 3.0, 9.0, 1.0)
OBJC_ARM64_UNAVAILABLE;
#else
OBJC_EXPORT id _objc_msgForward(id receiver, SEL sel, ...)
OBJC_AVAILABLE(10.0, 2.0, 9.0, 1.0);
OBJC_EXPORT void _objc_msgForward_stret(id receiver, SEL sel, ...)
OBJC_AVAILABLE(10.6, 3.0, 9.0, 1.0)
OBJC_ARM64_UNAVAILABLE;
#endif
/* Variable-argument Messaging Primitives
*
* Use these functions to call methods with a list of arguments, such
* as the one passed to forward:: .
*
* The contents of the argument list are architecture-specific.
* Consult your local function call ABI documentation for details.
*
* These functions must be cast to an appropriate function pointer type
* before being called, except for objc_msgSendv_stret() which must not
* be cast to a struct-returning type.
*/
typedef void* marg_list;
OBJC_EXPORT id objc_msgSendv(id self, SEL op, size_t arg_size, marg_list arg_frame) OBJC2_UNAVAILABLE;
OBJC_EXPORT void objc_msgSendv_stret(void *stretAddr, id self, SEL op, size_t arg_size, marg_list arg_frame) OBJC2_UNAVAILABLE;
/* Note that objc_msgSendv_stret() does not return a structure type,
* and should not be cast to do so. This is unlike objc_msgSend_stret()
* and objc_msgSendSuper_stret().
*/
#if defined(__i386__)
OBJC_EXPORT double objc_msgSendv_fpret(id self, SEL op, unsigned arg_size, marg_list arg_frame) OBJC2_UNAVAILABLE;
#endif
/* The following marg_list macros are of marginal utility. They
* are included for compatibility with the old objc-class.h header. */
#if !__OBJC2__
#define marg_prearg_size 0
#define marg_malloc(margs, method) \
do { \
margs = (marg_list *)malloc (marg_prearg_size + ((7 + method_getSizeOfArguments(method)) & ~7)); \
} while (0)
#define marg_free(margs) \
do { \
free(margs); \
} while (0)
#define marg_adjustedOffset(method, offset) \
(marg_prearg_size + offset)
#define marg_getRef(margs, offset, type) \
( (type *)((char *)margs + marg_adjustedOffset(method,offset) ) )
#define marg_getValue(margs, offset, type) \
( *marg_getRef(margs, offset, type) )
#define marg_setValue(margs, offset, type, value) \
( marg_getValue(margs, offset, type) = (value) )
#endif
#endif

346
runtime/objc-abi.h Normal file
View File

@ -0,0 +1,346 @@
/*
* Copyright (c) 2009 Apple Inc. All Rights Reserved.
*
* @APPLE_LICENSE_HEADER_START@
*
* 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 2.0 (the 'License'). You may not use this file except in
* compliance with the License. Please obtain a copy of the License at
* http://www.opensource.apple.com/apsl/ 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, QUIET ENJOYMENT OR NON-INFRINGEMENT.
* Please see the License for the specific language governing rights and
* limitations under the License.
*
* @APPLE_LICENSE_HEADER_END@
*/
#ifndef _OBJC_ABI_H
#define _OBJC_ABI_H
/*
* WARNING DANGER HAZARD BEWARE EEK
*
* Everything in this file is for Apple Internal use only.
* These will change in arbitrary OS updates and in unpredictable ways.
* When your program breaks, you get to keep both pieces.
*/
/*
* objc-abi.h: Declarations for functions used by compiler codegen.
*/
#include <malloc/malloc.h>
#include <TargetConditionals.h>
#include <objc/objc.h>
#include <objc/runtime.h>
#include <objc/message.h>
/* Runtime startup. */
// Old static initializer. Used by old crt1.o and old bug workarounds.
OBJC_EXPORT void _objcInit(void)
OBJC_AVAILABLE(10.0, 2.0, 9.0, 1.0);
/* Images */
// Description of an Objective-C image.
// __DATA,__objc_imageinfo stores one of these.
typedef struct objc_image_info {
uint32_t version; // currently 0
uint32_t flags;
#if __cplusplus >= 201103L
private:
enum : uint32_t {
IsReplacement = 1<<0, // used for Fix&Continue, now ignored
SupportsGC = 1<<1, // image supports GC
RequiresGC = 1<<2, // image requires GC
OptimizedByDyld = 1<<3, // image is from an optimized shared cache
CorrectedSynthesize = 1<<4, // used for an old workaround, now ignored
IsSimulated = 1<<5, // image compiled for a simulator platform
HasCategoryClassProperties = 1<<6, // class properties in category_t
SwiftVersionMaskShift = 8,
SwiftVersionMask = 0xff << SwiftVersionMaskShift // Swift ABI version
};
public:
enum : uint32_t {
SwiftVersion1 = 1,
SwiftVersion1_2 = 2,
SwiftVersion2 = 3,
SwiftVersion3 = 4
};
public:
bool isReplacement() const { return flags & IsReplacement; }
bool supportsGC() const { return flags & SupportsGC; }
bool requiresGC() const { return flags & RequiresGC; }
bool optimizedByDyld() const { return flags & OptimizedByDyld; }
bool hasCategoryClassProperties() const { return flags & HasCategoryClassProperties; }
bool containsSwift() const { return (flags & SwiftVersionMask) != 0; }
uint32_t swiftVersion() const { return (flags & SwiftVersionMask) >> SwiftVersionMaskShift; }
#endif
} objc_image_info;
/*
IsReplacement:
Once used for Fix&Continue in old OS X object files (not final linked images)
Not currently used.
SupportsGC:
App: GC is required. Framework: GC is supported but not required.
RequiresGC:
Framework: GC is required.
OptimizedByDyld:
Assorted metadata precooked in the dyld shared cache.
Never set for images outside the shared cache file itself.
CorrectedSynthesize:
Once used on old iOS to mark images that did not have a particular
miscompile. Not used by the runtime.
IsSimulated:
Image was compiled for a simulator platform. Not used by the runtime.
HasClassProperties:
New ABI: category_t.classProperties fields are present.
Old ABI: Set by some compilers. Not used by the runtime.
*/
/* Properties */
// Read or write an object property. Not all object properties use these.
OBJC_EXPORT id objc_getProperty(id self, SEL _cmd, ptrdiff_t offset, BOOL atomic)
OBJC_AVAILABLE(10.5, 2.0, 9.0, 1.0);
OBJC_EXPORT void objc_setProperty(id self, SEL _cmd, ptrdiff_t offset, id newValue, BOOL atomic, signed char shouldCopy)
OBJC_AVAILABLE(10.5, 2.0, 9.0, 1.0);
OBJC_EXPORT void objc_setProperty_atomic(id self, SEL _cmd, id newValue, ptrdiff_t offset)
OBJC_AVAILABLE(10.8, 6.0, 9.0, 1.0);
OBJC_EXPORT void objc_setProperty_nonatomic(id self, SEL _cmd, id newValue, ptrdiff_t offset)
OBJC_AVAILABLE(10.8, 6.0, 9.0, 1.0);
OBJC_EXPORT void objc_setProperty_atomic_copy(id self, SEL _cmd, id newValue, ptrdiff_t offset)
OBJC_AVAILABLE(10.8, 6.0, 9.0, 1.0);
OBJC_EXPORT void objc_setProperty_nonatomic_copy(id self, SEL _cmd, id newValue, ptrdiff_t offset)
OBJC_AVAILABLE(10.8, 6.0, 9.0, 1.0);
// Read or write a non-object property. Not all uses are C structs,
// and not all C struct properties use this.
OBJC_EXPORT void objc_copyStruct(void *dest, const void *src, ptrdiff_t size, BOOL atomic, BOOL hasStrong)
OBJC_AVAILABLE(10.5, 2.0, 9.0, 1.0);
// Perform a copy of a C++ object using striped locks. Used by non-POD C++ typed atomic properties.
OBJC_EXPORT void objc_copyCppObjectAtomic(void *dest, const void *src, void (*copyHelper) (void *dest, const void *source))
OBJC_AVAILABLE(10.8, 6.0, 9.0, 1.0);
/* Classes. */
#if __OBJC2__
OBJC_EXPORT IMP _objc_empty_vtable
OBJC_AVAILABLE(10.5, 2.0, 9.0, 1.0);
#endif
OBJC_EXPORT struct objc_cache _objc_empty_cache
OBJC_AVAILABLE(10.0, 2.0, 9.0, 1.0);
/* Messages */
#if __OBJC2__
// objc_msgSendSuper2() takes the current search class, not its superclass.
OBJC_EXPORT id objc_msgSendSuper2(struct objc_super *super, SEL op, ...)
OBJC_AVAILABLE(10.6, 2.0, 9.0, 1.0);
OBJC_EXPORT void objc_msgSendSuper2_stret(struct objc_super *super, SEL op,...)
OBJC_AVAILABLE(10.6, 2.0, 9.0, 1.0)
OBJC_ARM64_UNAVAILABLE;
// objc_msgSend_noarg() may be faster for methods with no additional arguments.
OBJC_EXPORT id objc_msgSend_noarg(id self, SEL _cmd)
OBJC_AVAILABLE(10.7, 5.0, 9.0, 1.0);
#endif
#if __OBJC2__
// Debug messengers. Messengers used by the compiler have a debug flavor that
// may perform extra sanity checking.
// Old objc_msgSendSuper() does not have a debug version; this is OBJC2 only.
// *_fixup() do not have debug versions; use non-fixup only for debug mode.
OBJC_EXPORT id objc_msgSend_debug(id self, SEL op, ...)
OBJC_AVAILABLE(10.7, 5.0, 9.0, 1.0);
OBJC_EXPORT id objc_msgSendSuper2_debug(struct objc_super *super, SEL op, ...)
OBJC_AVAILABLE(10.7, 5.0, 9.0, 1.0);
OBJC_EXPORT void objc_msgSend_stret_debug(id self, SEL op, ...)
OBJC_AVAILABLE(10.7, 5.0, 9.0, 1.0)
OBJC_ARM64_UNAVAILABLE;
OBJC_EXPORT void objc_msgSendSuper2_stret_debug(struct objc_super *super, SEL op,...)
OBJC_AVAILABLE(10.7, 5.0, 9.0, 1.0)
OBJC_ARM64_UNAVAILABLE;
# if defined(__i386__)
OBJC_EXPORT double objc_msgSend_fpret_debug(id self, SEL op, ...)
OBJC_AVAILABLE(10.7, 5.0, 9.0, 1.0);
# elif defined(__x86_64__)
OBJC_EXPORT long double objc_msgSend_fpret_debug(id self, SEL op, ...)
OBJC_AVAILABLE(10.7, 5.0, 9.0, 1.0);
# if __STDC_VERSION__ >= 199901L
OBJC_EXPORT _Complex long double objc_msgSend_fp2ret_debug(id self, SEL op, ...)
OBJC_AVAILABLE(10.7, 5.0, 9.0, 1.0);
# else
OBJC_EXPORT void objc_msgSend_fp2ret_debug(id self, SEL op, ...)
OBJC_AVAILABLE(10.7, 5.0, 9.0, 1.0);
# endif
# endif
#endif
#if __OBJC2__
// Lookup messengers.
// These are not callable C functions. Do not call them directly.
// The caller should set the method parameters, call objc_msgLookup(),
// then immediately call the returned IMP.
//
// Generic ABI:
// - Callee-saved registers are preserved.
// - Receiver and selector registers may be modified. These values must
// be passed to the called IMP. Other parameter registers are preserved.
// - Caller-saved non-parameter registers are not preserved. Some of
// these registers are used to pass data from objc_msgLookup() to
// the called IMP and must not be disturbed by the caller.
// - Red zone is not preserved.
// See each architecture's implementation for details.
OBJC_EXPORT void objc_msgLookup(void)
OBJC_AVAILABLE(10.12, 10.0, 10.0, 3.0);
OBJC_EXPORT void objc_msgLookupSuper2(void)
OBJC_AVAILABLE(10.12, 10.0, 10.0, 3.0);
OBJC_EXPORT void objc_msgLookup_stret(void)
OBJC_AVAILABLE(10.12, 10.0, 10.0, 3.0)
OBJC_ARM64_UNAVAILABLE;
OBJC_EXPORT void objc_msgLookupSuper2_stret(void)
OBJC_AVAILABLE(10.12, 10.0, 10.0, 3.0)
OBJC_ARM64_UNAVAILABLE;
# if defined(__i386__)
OBJC_EXPORT void objc_msgLookup_fpret(void)
OBJC_AVAILABLE(10.12, 10.0, 10.0, 3.0);
# elif defined(__x86_64__)
OBJC_EXPORT void objc_msgLookup_fpret(void)
OBJC_AVAILABLE(10.12, 10.0, 10.0, 3.0);
OBJC_EXPORT void objc_msgLookup_fp2ret(void)
OBJC_AVAILABLE(10.12, 10.0, 10.0, 3.0);
# endif
#endif
#if TARGET_OS_OSX && defined(__x86_64__)
// objc_msgSend_fixup() is used for vtable-dispatchable call sites.
OBJC_EXPORT void objc_msgSend_fixup(void)
__OSX_DEPRECATED(10.5, 10.8, "fixup dispatch is no longer optimized")
__IOS_UNAVAILABLE __TVOS_UNAVAILABLE __WATCHOS_UNAVAILABLE;
OBJC_EXPORT void objc_msgSend_stret_fixup(void)
__OSX_DEPRECATED(10.5, 10.8, "fixup dispatch is no longer optimized")
__IOS_UNAVAILABLE __TVOS_UNAVAILABLE __WATCHOS_UNAVAILABLE;
OBJC_EXPORT void objc_msgSendSuper2_fixup(void)
__OSX_DEPRECATED(10.5, 10.8, "fixup dispatch is no longer optimized")
__IOS_UNAVAILABLE __TVOS_UNAVAILABLE __WATCHOS_UNAVAILABLE;
OBJC_EXPORT void objc_msgSendSuper2_stret_fixup(void)
__OSX_DEPRECATED(10.5, 10.8, "fixup dispatch is no longer optimized")
__IOS_UNAVAILABLE __TVOS_UNAVAILABLE __WATCHOS_UNAVAILABLE;
OBJC_EXPORT void objc_msgSend_fpret_fixup(void)
__OSX_DEPRECATED(10.5, 10.8, "fixup dispatch is no longer optimized")
__IOS_UNAVAILABLE __TVOS_UNAVAILABLE __WATCHOS_UNAVAILABLE;
OBJC_EXPORT void objc_msgSend_fp2ret_fixup(void)
__OSX_DEPRECATED(10.5, 10.8, "fixup dispatch is no longer optimized")
__IOS_UNAVAILABLE __TVOS_UNAVAILABLE __WATCHOS_UNAVAILABLE;
#endif
/* C++-compatible exception handling. */
#if __OBJC2__
// fixme these conflict with C++ compiler's internal definitions
#if !defined(__cplusplus)
// Vtable for C++ exception typeinfo for Objective-C types.
OBJC_EXPORT const void *objc_ehtype_vtable[]
OBJC_AVAILABLE(10.5, 2.0, 9.0, 1.0);
// C++ exception typeinfo for type `id`.
OBJC_EXPORT struct objc_typeinfo OBJC_EHTYPE_id
OBJC_AVAILABLE(10.5, 2.0, 9.0, 1.0);
#endif
// Exception personality function for Objective-C and Objective-C++ code.
struct _Unwind_Exception;
struct _Unwind_Context;
OBJC_EXPORT int
__objc_personality_v0(int version,
int actions,
uint64_t exceptionClass,
struct _Unwind_Exception *exceptionObject,
struct _Unwind_Context *context)
OBJC_AVAILABLE(10.5, 2.0, 9.0, 1.0);
#endif
/* ARC */
OBJC_EXPORT id objc_retainBlock(id)
OBJC_AVAILABLE(10.7, 5.0, 9.0, 1.0);
/* Non-pointer isa */
#if __OBJC2__
// Extract class pointer from an isa field.
#if TARGET_OS_SIMULATOR
// No simulators use nonpointer isa yet.
#elif __LP64__
# define OBJC_HAVE_NONPOINTER_ISA 1
# define OBJC_HAVE_PACKED_NONPOINTER_ISA 1
// Packed-isa version. This one is used directly by Swift code.
// (Class)(isa & (uintptr_t)&objc_absolute_packed_isa_class_mask) == class ptr
OBJC_EXPORT const struct { char c; } objc_absolute_packed_isa_class_mask
OBJC_AVAILABLE(10.12, 10.0, 10.0, 3.0);
#elif __ARM_ARCH_7K__ >= 2
# define OBJC_HAVE_NONPOINTER_ISA 1
# define OBJC_HAVE_INDEXED_NONPOINTER_ISA 1
// Indexed-isa version.
// if (isa & (uintptr_t)&objc_absolute_indexed_isa_magic_mask == (uintptr_t)&objc_absolute_indexed_isa_magic_value) {
// uintptr_t index = (isa & (uintptr_t)&objc_absolute_indexed_isa_index_mask) >> (uintptr_t)&objc_absolute_indexed_isa_index_shift;
// cls = objc_indexed_classes[index];
// } else
// cls = (Class)isa;
// }
OBJC_EXPORT const struct { char c; } objc_absolute_indexed_isa_magic_mask
OBJC_AVAILABLE(10.12, 10.0, 10.0, 3.0);
OBJC_EXPORT const struct { char c; } objc_absolute_indexed_isa_magic_value
OBJC_AVAILABLE(10.12, 10.0, 10.0, 3.0);
OBJC_EXPORT const struct { char c; } objc_absolute_indexed_isa_index_mask
OBJC_AVAILABLE(10.12, 10.0, 10.0, 3.0);
OBJC_EXPORT const struct { char c; } objc_absolute_indexed_isa_index_shift
OBJC_AVAILABLE(10.12, 10.0, 10.0, 3.0);
#endif
// OBJC2
#endif
// _OBJC_ABI_H
#endif

161
runtime/objc-accessors.mm Normal file
View File

@ -0,0 +1,161 @@
/*
* Copyright (c) 2006-2008 Apple Inc. All Rights Reserved.
*
* @APPLE_LICENSE_HEADER_START@
*
* 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 2.0 (the 'License'). You may not use this file except in
* compliance with the License. Please obtain a copy of the License at
* http://www.opensource.apple.com/apsl/ 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, QUIET ENJOYMENT OR NON-INFRINGEMENT.
* Please see the License for the specific language governing rights and
* limitations under the License.
*
* @APPLE_LICENSE_HEADER_END@
*/
#include <string.h>
#include <stddef.h>
#include <libkern/OSAtomic.h>
#include "objc-private.h"
#include "runtime.h"
// stub interface declarations to make compiler happy.
@interface __NSCopyable
- (id)copyWithZone:(void *)zone;
@end
@interface __NSMutableCopyable
- (id)mutableCopyWithZone:(void *)zone;
@end
// These locks must not be at function scope.
static StripedMap<spinlock_t> PropertyLocks;
static StripedMap<spinlock_t> StructLocks;
static StripedMap<spinlock_t> CppObjectLocks;
#define MUTABLE_COPY 2
id objc_getProperty(id self, SEL _cmd, ptrdiff_t offset, BOOL atomic) {
if (offset == 0) {
return object_getClass(self);
}
// Retain release world
id *slot = (id*) ((char*)self + offset);
if (!atomic) return *slot;
// Atomic retain release world
spinlock_t& slotlock = PropertyLocks[slot];
slotlock.lock();
id value = objc_retain(*slot);
slotlock.unlock();
// for performance, we (safely) issue the autorelease OUTSIDE of the spinlock.
return objc_autoreleaseReturnValue(value);
}
static inline void reallySetProperty(id self, SEL _cmd, id newValue, ptrdiff_t offset, bool atomic, bool copy, bool mutableCopy) __attribute__((always_inline));
static inline void reallySetProperty(id self, SEL _cmd, id newValue, ptrdiff_t offset, bool atomic, bool copy, bool mutableCopy)
{
if (offset == 0) {
object_setClass(self, newValue);
return;
}
id oldValue;
id *slot = (id*) ((char*)self + offset);
if (copy) {
newValue = [newValue copyWithZone:nil];
} else if (mutableCopy) {
newValue = [newValue mutableCopyWithZone:nil];
} else {
if (*slot == newValue) return;
newValue = objc_retain(newValue);
}
if (!atomic) {
oldValue = *slot;
*slot = newValue;
} else {
spinlock_t& slotlock = PropertyLocks[slot];
slotlock.lock();
oldValue = *slot;
*slot = newValue;
slotlock.unlock();
}
objc_release(oldValue);
}
void objc_setProperty(id self, SEL _cmd, ptrdiff_t offset, id newValue, BOOL atomic, signed char shouldCopy)
{
bool copy = (shouldCopy && shouldCopy != MUTABLE_COPY);
bool mutableCopy = (shouldCopy == MUTABLE_COPY);
reallySetProperty(self, _cmd, newValue, offset, atomic, copy, mutableCopy);
}
void objc_setProperty_atomic(id self, SEL _cmd, id newValue, ptrdiff_t offset)
{
reallySetProperty(self, _cmd, newValue, offset, true, false, false);
}
void objc_setProperty_nonatomic(id self, SEL _cmd, id newValue, ptrdiff_t offset)
{
reallySetProperty(self, _cmd, newValue, offset, false, false, false);
}
void objc_setProperty_atomic_copy(id self, SEL _cmd, id newValue, ptrdiff_t offset)
{
reallySetProperty(self, _cmd, newValue, offset, true, true, false);
}
void objc_setProperty_nonatomic_copy(id self, SEL _cmd, id newValue, ptrdiff_t offset)
{
reallySetProperty(self, _cmd, newValue, offset, false, true, false);
}
// This entry point was designed wrong. When used as a getter, src needs to be locked so that
// if simultaneously used for a setter then there would be contention on src.
// So we need two locks - one of which will be contended.
void objc_copyStruct(void *dest, const void *src, ptrdiff_t size, BOOL atomic, BOOL hasStrong __unused) {
spinlock_t *srcLock = nil;
spinlock_t *dstLock = nil;
if (atomic) {
srcLock = &StructLocks[src];
dstLock = &StructLocks[dest];
spinlock_t::lockTwo(srcLock, dstLock);
}
memmove(dest, src, size);
if (atomic) {
spinlock_t::unlockTwo(srcLock, dstLock);
}
}
void objc_copyCppObjectAtomic(void *dest, const void *src, void (*copyHelper) (void *dest, const void *source)) {
spinlock_t *srcLock = &CppObjectLocks[src];
spinlock_t *dstLock = &CppObjectLocks[dest];
spinlock_t::lockTwo(srcLock, dstLock);
// let C++ code perform the actual copy.
copyHelper(dest, src);
spinlock_t::unlockTwo(srcLock, dstLock);
}

232
runtime/objc-api.h Normal file
View File

@ -0,0 +1,232 @@
/*
* Copyright (c) 1999-2006 Apple Inc. All Rights Reserved.
*
* @APPLE_LICENSE_HEADER_START@
*
* 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 2.0 (the 'License'). You may not use this file except in
* compliance with the License. Please obtain a copy of the License at
* http://www.opensource.apple.com/apsl/ 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, QUIET ENJOYMENT OR NON-INFRINGEMENT.
* Please see the License for the specific language governing rights and
* limitations under the License.
*
* @APPLE_LICENSE_HEADER_END@
*/
// Copyright 1988-1996 NeXT Software, Inc.
#ifndef _OBJC_OBJC_API_H_
#define _OBJC_OBJC_API_H_
#include <Availability.h>
#include <AvailabilityMacros.h>
#include <TargetConditionals.h>
#ifndef __has_feature
# define __has_feature(x) 0
#endif
#ifndef __has_extension
# define __has_extension __has_feature
#endif
#ifndef __has_attribute
# define __has_attribute(x) 0
#endif
/*
* OBJC_API_VERSION 0 or undef: Tiger and earlier API only
* OBJC_API_VERSION 2: Leopard and later API available
*/
#if !defined(OBJC_API_VERSION)
# if defined(__MAC_OS_X_VERSION_MIN_REQUIRED) && __MAC_OS_X_VERSION_MIN_REQUIRED < __MAC_10_5
# define OBJC_API_VERSION 0
# else
# define OBJC_API_VERSION 2
# endif
#endif
/*
* OBJC_NO_GC 1: GC is not supported
* OBJC_NO_GC undef: GC is supported. This SDK no longer supports this mode.
*
* OBJC_NO_GC_API undef: Libraries must export any symbols that
* dual-mode code may links to.
* OBJC_NO_GC_API 1: Libraries need not export GC-related symbols.
*/
#if defined(__OBJC_GC__)
# error Objective-C garbage collection is not supported.
#elif TARGET_OS_OSX
/* GC is unsupported. GC API symbols are exported. */
# define OBJC_NO_GC 1
# undef OBJC_NO_GC_API
#else
/* GC is unsupported. GC API symbols are not exported. */
# define OBJC_NO_GC 1
# define OBJC_NO_GC_API 1
#endif
/* NS_ENFORCE_NSOBJECT_DESIGNATED_INITIALIZER == 1
* marks -[NSObject init] as a designated initializer. */
#if !defined(NS_ENFORCE_NSOBJECT_DESIGNATED_INITIALIZER)
# define NS_ENFORCE_NSOBJECT_DESIGNATED_INITIALIZER 1
#endif
/* OBJC_OLD_DISPATCH_PROTOTYPES == 0 enforces the rule that the dispatch
* functions must be cast to an appropriate function pointer type. */
#if !defined(OBJC_OLD_DISPATCH_PROTOTYPES)
# define OBJC_OLD_DISPATCH_PROTOTYPES 1
#endif
/* OBJC_AVAILABLE: shorthand for all-OS availability */
#if !defined(OBJC_AVAILABLE)
# define OBJC_AVAILABLE(x, i, t, w) \
__OSX_AVAILABLE(x) __IOS_AVAILABLE(i) \
__TVOS_AVAILABLE(t) __WATCHOS_AVAILABLE(w)
#endif
/* OBJC_ISA_AVAILABILITY: `isa` will be deprecated or unavailable
* in the future */
#if !defined(OBJC_ISA_AVAILABILITY)
# if __OBJC2__
# define OBJC_ISA_AVAILABILITY __attribute__((deprecated))
# else
# define OBJC_ISA_AVAILABILITY /* still available */
# endif
#endif
/* OBJC2_UNAVAILABLE: unavailable in objc 2.0, deprecated in Leopard */
#if !defined(OBJC2_UNAVAILABLE)
# if __OBJC2__
# define OBJC2_UNAVAILABLE UNAVAILABLE_ATTRIBUTE
# else
/* plain C code also falls here, but this is close enough */
# define OBJC2_UNAVAILABLE \
__OSX_DEPRECATED(10.5, 10.5, "not available in __OBJC2__") \
__IOS_DEPRECATED(2.0, 2.0, "not available in __OBJC2__") \
__TVOS_UNAVAILABLE __WATCHOS_UNAVAILABLE
# endif
#endif
/* OBJC_UNAVAILABLE: unavailable, with a message where supported */
#if !defined(OBJC_UNAVAILABLE)
# if __has_extension(attribute_unavailable_with_message)
# define OBJC_UNAVAILABLE(_msg) __attribute__((unavailable(_msg)))
# else
# define OBJC_UNAVAILABLE(_msg) __attribute__((unavailable))
# endif
#endif
/* OBJC_DEPRECATED: deprecated, with a message where supported */
#if !defined(OBJC_DEPRECATED)
# if __has_extension(attribute_deprecated_with_message)
# define OBJC_DEPRECATED(_msg) __attribute__((deprecated(_msg)))
# else
# define OBJC_DEPRECATED(_msg) __attribute__((deprecated))
# endif
#endif
/* OBJC_ARC_UNAVAILABLE: unavailable with -fobjc-arc */
#if !defined(OBJC_ARC_UNAVAILABLE)
# if __has_feature(objc_arc)
# define OBJC_ARC_UNAVAILABLE OBJC_UNAVAILABLE("not available in automatic reference counting mode")
# else
# define OBJC_ARC_UNAVAILABLE
# endif
#endif
/* OBJC_SWIFT_UNAVAILABLE: unavailable in Swift */
#if !defined(OBJC_SWIFT_UNAVAILABLE)
# if __has_feature(attribute_availability_swift)
# define OBJC_SWIFT_UNAVAILABLE(_msg) __attribute__((availability(swift, unavailable, message=_msg)))
# else
# define OBJC_SWIFT_UNAVAILABLE(_msg)
# endif
#endif
/* OBJC_ARM64_UNAVAILABLE: unavailable on arm64 (i.e. stret dispatch) */
#if !defined(OBJC_ARM64_UNAVAILABLE)
# if defined(__arm64__)
# define OBJC_ARM64_UNAVAILABLE OBJC_UNAVAILABLE("not available in arm64")
# else
# define OBJC_ARM64_UNAVAILABLE
# endif
#endif
/* OBJC_GC_UNAVAILABLE: unavailable with -fobjc-gc or -fobjc-gc-only */
#if !defined(OBJC_GC_UNAVAILABLE)
# define OBJC_GC_UNAVAILABLE
#endif
#if !defined(OBJC_EXTERN)
# if defined(__cplusplus)
# define OBJC_EXTERN extern "C"
# else
# define OBJC_EXTERN extern
# endif
#endif
#if !defined(OBJC_VISIBLE)
# if TARGET_OS_WIN32
# if defined(BUILDING_OBJC)
# define OBJC_VISIBLE __declspec(dllexport)
# else
# define OBJC_VISIBLE __declspec(dllimport)
# endif
# else
# define OBJC_VISIBLE __attribute__((visibility("default")))
# endif
#endif
#if !defined(OBJC_EXPORT)
# define OBJC_EXPORT OBJC_EXTERN OBJC_VISIBLE
#endif
#if !defined(OBJC_IMPORT)
# define OBJC_IMPORT extern
#endif
#if !defined(OBJC_ROOT_CLASS)
# if __has_attribute(objc_root_class)
# define OBJC_ROOT_CLASS __attribute__((objc_root_class))
# else
# define OBJC_ROOT_CLASS
# endif
#endif
#ifndef __DARWIN_NULL
#define __DARWIN_NULL NULL
#endif
#if !defined(OBJC_INLINE)
# define OBJC_INLINE __inline
#endif
// Declares an enum type or option bits type as appropriate for each language.
#if (__cplusplus && __cplusplus >= 201103L && (__has_extension(cxx_strong_enums) || __has_feature(objc_fixed_enum))) || (!__cplusplus && __has_feature(objc_fixed_enum))
#define OBJC_ENUM(_type, _name) enum _name : _type _name; enum _name : _type
#if (__cplusplus)
#define OBJC_OPTIONS(_type, _name) _type _name; enum : _type
#else
#define OBJC_OPTIONS(_type, _name) enum _name : _type _name; enum _name : _type
#endif
#else
#define OBJC_ENUM(_type, _name) _type _name; enum
#define OBJC_OPTIONS(_type, _name) _type _name; enum
#endif
#endif

255
runtime/objc-auto.h Normal file
View File

@ -0,0 +1,255 @@
/*
* Copyright (c) 2004-2007 Apple Inc. All rights reserved.
*
* @APPLE_LICENSE_HEADER_START@
*
* 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 2.0 (the 'License'). You may not use this file except in
* compliance with the License. Please obtain a copy of the License at
* http://www.opensource.apple.com/apsl/ 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, QUIET ENJOYMENT OR NON-INFRINGEMENT.
* Please see the License for the specific language governing rights and
* limitations under the License.
*
* @APPLE_LICENSE_HEADER_END@
*/
#ifndef _OBJC_AUTO_H_
#define _OBJC_AUTO_H_
#pragma GCC system_header
#include <objc/objc.h>
#include <malloc/malloc.h>
#include <stdint.h>
#include <stddef.h>
#include <string.h>
#include <Availability.h>
#include <TargetConditionals.h>
#include <sys/types.h>
#include <libkern/OSAtomic.h>
// Define OBJC_SILENCE_GC_DEPRECATIONS=1 to temporarily
// silence deprecation warnings for GC functions.
#if OBJC_SILENCE_GC_DEPRECATIONS
# define OBJC_GC_DEPRECATED(message)
#elif __has_extension(attribute_deprecated_with_message)
# define OBJC_GC_DEPRECATED(message) __attribute__((deprecated(message ". Define OBJC_SILENCE_GC_DEPRECATIONS=1 to temporarily silence this diagnostic.")))
#else
# define OBJC_GC_DEPRECATED(message) __attribute__((deprecated))
#endif
enum {
OBJC_RATIO_COLLECTION = (0 << 0),
OBJC_GENERATIONAL_COLLECTION = (1 << 0),
OBJC_FULL_COLLECTION = (2 << 0),
OBJC_EXHAUSTIVE_COLLECTION = (3 << 0),
OBJC_COLLECT_IF_NEEDED = (1 << 3),
OBJC_WAIT_UNTIL_DONE = (1 << 4),
};
enum {
OBJC_CLEAR_RESIDENT_STACK = (1 << 0)
};
#ifndef OBJC_NO_GC
/* Out-of-line declarations */
OBJC_EXPORT void objc_collect(unsigned long options)
__OSX_DEPRECATED(10.6, 10.8, "it does nothing") __IOS_UNAVAILABLE __TVOS_UNAVAILABLE __WATCHOS_UNAVAILABLE;
OBJC_EXPORT BOOL objc_collectingEnabled(void)
__OSX_DEPRECATED(10.5, 10.8, "it always returns NO") __IOS_UNAVAILABLE __TVOS_UNAVAILABLE __WATCHOS_UNAVAILABLE;
OBJC_EXPORT malloc_zone_t *objc_collectableZone(void)
__OSX_DEPRECATED(10.7, 10.8, "it always returns nil") __IOS_UNAVAILABLE __TVOS_UNAVAILABLE __WATCHOS_UNAVAILABLE;
OBJC_EXPORT void objc_setCollectionThreshold(size_t threshold)
__OSX_DEPRECATED(10.5, 10.8, "it does nothing") __IOS_UNAVAILABLE __TVOS_UNAVAILABLE __WATCHOS_UNAVAILABLE;
OBJC_EXPORT void objc_setCollectionRatio(size_t ratio)
__OSX_DEPRECATED(10.5, 10.8, "it does nothing") __IOS_UNAVAILABLE __TVOS_UNAVAILABLE __WATCHOS_UNAVAILABLE;
OBJC_EXPORT BOOL objc_atomicCompareAndSwapPtr(id predicate, id replacement, volatile id *objectLocation)
__OSX_DEPRECATED(10.6, 10.8, "use OSAtomicCompareAndSwapPtr instead") __IOS_UNAVAILABLE __TVOS_UNAVAILABLE __WATCHOS_UNAVAILABLE OBJC_ARC_UNAVAILABLE;
OBJC_EXPORT BOOL objc_atomicCompareAndSwapPtrBarrier(id predicate, id replacement, volatile id *objectLocation)
__OSX_DEPRECATED(10.6, 10.8, "use OSAtomicCompareAndSwapPtrBarrier instead") __IOS_UNAVAILABLE __TVOS_UNAVAILABLE __WATCHOS_UNAVAILABLE OBJC_ARC_UNAVAILABLE;
OBJC_EXPORT BOOL objc_atomicCompareAndSwapGlobal(id predicate, id replacement, volatile id *objectLocation)
__OSX_DEPRECATED(10.6, 10.8, "use OSAtomicCompareAndSwapPtr instead") __IOS_UNAVAILABLE __TVOS_UNAVAILABLE __WATCHOS_UNAVAILABLE OBJC_ARC_UNAVAILABLE;
OBJC_EXPORT BOOL objc_atomicCompareAndSwapGlobalBarrier(id predicate, id replacement, volatile id *objectLocation)
__OSX_DEPRECATED(10.6, 10.8, "use OSAtomicCompareAndSwapPtrBarrier instead") __IOS_UNAVAILABLE __TVOS_UNAVAILABLE __WATCHOS_UNAVAILABLE OBJC_ARC_UNAVAILABLE;
OBJC_EXPORT BOOL objc_atomicCompareAndSwapInstanceVariable(id predicate, id replacement, volatile id *objectLocation)
__OSX_DEPRECATED(10.6, 10.8, "use OSAtomicCompareAndSwapPtr instead") __IOS_UNAVAILABLE __TVOS_UNAVAILABLE __WATCHOS_UNAVAILABLE OBJC_ARC_UNAVAILABLE;
OBJC_EXPORT BOOL objc_atomicCompareAndSwapInstanceVariableBarrier(id predicate, id replacement, volatile id *objectLocation)
__OSX_DEPRECATED(10.6, 10.8, "use OSAtomicCompareAndSwapPtrBarrier instead") __IOS_UNAVAILABLE __TVOS_UNAVAILABLE __WATCHOS_UNAVAILABLE OBJC_ARC_UNAVAILABLE;
OBJC_EXPORT id objc_assign_strongCast(id val, id *dest)
__OSX_DEPRECATED(10.4, 10.8, "use a simple assignment instead") __IOS_UNAVAILABLE __TVOS_UNAVAILABLE __WATCHOS_UNAVAILABLE;
OBJC_EXPORT id objc_assign_global(id val, id *dest)
__OSX_DEPRECATED(10.4, 10.8, "use a simple assignment instead") __IOS_UNAVAILABLE __TVOS_UNAVAILABLE __WATCHOS_UNAVAILABLE;
OBJC_EXPORT id objc_assign_threadlocal(id val, id *dest)
__OSX_DEPRECATED(10.7, 10.8, "use a simple assignment instead") __IOS_UNAVAILABLE __TVOS_UNAVAILABLE __WATCHOS_UNAVAILABLE;
OBJC_EXPORT id objc_assign_ivar(id value, id dest, ptrdiff_t offset)
__OSX_DEPRECATED(10.4, 10.8, "use a simple assignment instead") __IOS_UNAVAILABLE __TVOS_UNAVAILABLE __WATCHOS_UNAVAILABLE;
OBJC_EXPORT void *objc_memmove_collectable(void *dst, const void *src, size_t size)
__OSX_DEPRECATED(10.4, 10.8, "use memmove instead") __IOS_UNAVAILABLE __TVOS_UNAVAILABLE __WATCHOS_UNAVAILABLE;
OBJC_EXPORT id objc_read_weak(id *location)
__OSX_DEPRECATED(10.5, 10.8, "use a simple read instead, or convert to zeroing __weak") __IOS_UNAVAILABLE __TVOS_UNAVAILABLE __WATCHOS_UNAVAILABLE;
OBJC_EXPORT id objc_assign_weak(id value, id *location)
__OSX_DEPRECATED(10.5, 10.8, "use a simple assignment instead, or convert to zeroing __weak") __IOS_UNAVAILABLE __TVOS_UNAVAILABLE __WATCHOS_UNAVAILABLE;
OBJC_EXPORT void objc_registerThreadWithCollector(void)
__OSX_DEPRECATED(10.6, 10.8, "it does nothing") __IOS_UNAVAILABLE __TVOS_UNAVAILABLE __WATCHOS_UNAVAILABLE;
OBJC_EXPORT void objc_unregisterThreadWithCollector(void)
__OSX_DEPRECATED(10.6, 10.8, "it does nothing") __IOS_UNAVAILABLE __TVOS_UNAVAILABLE __WATCHOS_UNAVAILABLE;
OBJC_EXPORT void objc_assertRegisteredThreadWithCollector(void)
__OSX_DEPRECATED(10.6, 10.8, "it does nothing") __IOS_UNAVAILABLE __TVOS_UNAVAILABLE __WATCHOS_UNAVAILABLE;
OBJC_EXPORT void objc_clear_stack(unsigned long options)
__OSX_DEPRECATED(10.5, 10.8, "it does nothing") __IOS_UNAVAILABLE __TVOS_UNAVAILABLE __WATCHOS_UNAVAILABLE;
OBJC_EXPORT BOOL objc_is_finalized(void *ptr)
__OSX_DEPRECATED(10.4, 10.8, "it always returns NO") __IOS_UNAVAILABLE __TVOS_UNAVAILABLE __WATCHOS_UNAVAILABLE;
OBJC_EXPORT void objc_finalizeOnMainThread(Class cls)
__OSX_DEPRECATED(10.5, 10.5, "it does nothing") __IOS_UNAVAILABLE __TVOS_UNAVAILABLE __WATCHOS_UNAVAILABLE;
OBJC_EXPORT BOOL objc_collecting_enabled(void)
__OSX_DEPRECATED(10.4, 10.5, "it always returns NO") __IOS_UNAVAILABLE __TVOS_UNAVAILABLE __WATCHOS_UNAVAILABLE;
OBJC_EXPORT void objc_set_collection_threshold(size_t threshold)
__OSX_DEPRECATED(10.4, 10.5, "it does nothing") __IOS_UNAVAILABLE __TVOS_UNAVAILABLE __WATCHOS_UNAVAILABLE;
OBJC_EXPORT void objc_set_collection_ratio(size_t ratio)
__OSX_DEPRECATED(10.4, 10.5, "it does nothing") __IOS_UNAVAILABLE __TVOS_UNAVAILABLE __WATCHOS_UNAVAILABLE;
OBJC_EXPORT void objc_start_collector_thread(void)
__OSX_DEPRECATED(10.4, 10.5, "it does nothing") __IOS_UNAVAILABLE __TVOS_UNAVAILABLE __WATCHOS_UNAVAILABLE;
OBJC_EXPORT void objc_startCollectorThread(void)
__OSX_DEPRECATED(10.5, 10.7, "it does nothing") __IOS_UNAVAILABLE __TVOS_UNAVAILABLE __WATCHOS_UNAVAILABLE;
OBJC_EXPORT id objc_allocate_object(Class cls, int extra)
__OSX_DEPRECATED(10.4, 10.4, "use class_createInstance instead") __IOS_UNAVAILABLE __TVOS_UNAVAILABLE __WATCHOS_UNAVAILABLE;
/* !defined(OBJC_NO_GC) */
#else
/* defined(OBJC_NO_GC) */
/* Inline declarations */
OBJC_GC_DEPRECATED("it does nothing")
static OBJC_INLINE void objc_collect(unsigned long options __unused) { }
OBJC_GC_DEPRECATED("it always returns NO")
static OBJC_INLINE BOOL objc_collectingEnabled(void) { return NO; }
#if TARGET_OS_OSX
OBJC_GC_DEPRECATED("it always returns nil")
static OBJC_INLINE malloc_zone_t *objc_collectableZone(void) { return nil; }
#endif
OBJC_GC_DEPRECATED("it does nothing")
static OBJC_INLINE void objc_setCollectionThreshold(size_t threshold __unused) { }
OBJC_GC_DEPRECATED("it does nothing")
static OBJC_INLINE void objc_setCollectionRatio(size_t ratio __unused) { }
OBJC_GC_DEPRECATED("it does nothing")
static OBJC_INLINE void objc_startCollectorThread(void) { }
#if __has_feature(objc_arc)
/* Covers for GC memory operations are unavailable in ARC */
#else
OBJC_GC_DEPRECATED("use OSAtomicCompareAndSwapPtr instead")
static OBJC_INLINE BOOL objc_atomicCompareAndSwapPtr(id predicate, id replacement, volatile id *objectLocation)
{ return OSAtomicCompareAndSwapPtr((void *)predicate, (void *)replacement, (void * volatile *)objectLocation); }
OBJC_GC_DEPRECATED("use OSAtomicCompareAndSwapPtrBarrier instead")
static OBJC_INLINE BOOL objc_atomicCompareAndSwapPtrBarrier(id predicate, id replacement, volatile id *objectLocation)
{ return OSAtomicCompareAndSwapPtrBarrier((void *)predicate, (void *)replacement, (void * volatile *)objectLocation); }
OBJC_GC_DEPRECATED("use OSAtomicCompareAndSwapPtr instead")
static OBJC_INLINE BOOL objc_atomicCompareAndSwapGlobal(id predicate, id replacement, volatile id *objectLocation)
{ return objc_atomicCompareAndSwapPtr(predicate, replacement, objectLocation); }
OBJC_GC_DEPRECATED("use OSAtomicCompareAndSwapPtrBarrier instead")
static OBJC_INLINE BOOL objc_atomicCompareAndSwapGlobalBarrier(id predicate, id replacement, volatile id *objectLocation)
{ return objc_atomicCompareAndSwapPtrBarrier(predicate, replacement, objectLocation); }
OBJC_GC_DEPRECATED("use OSAtomicCompareAndSwapPtr instead")
static OBJC_INLINE BOOL objc_atomicCompareAndSwapInstanceVariable(id predicate, id replacement, volatile id *objectLocation)
{ return objc_atomicCompareAndSwapPtr(predicate, replacement, objectLocation); }
OBJC_GC_DEPRECATED("use OSAtomicCompareAndSwapPtrBarrier instead")
static OBJC_INLINE BOOL objc_atomicCompareAndSwapInstanceVariableBarrier(id predicate, id replacement, volatile id *objectLocation)
{ return objc_atomicCompareAndSwapPtrBarrier(predicate, replacement, objectLocation); }
OBJC_GC_DEPRECATED("use a simple assignment instead")
static OBJC_INLINE id objc_assign_strongCast(id val, id *dest)
{ return (*dest = val); }
OBJC_GC_DEPRECATED("use a simple assignment instead")
static OBJC_INLINE id objc_assign_global(id val, id *dest)
{ return (*dest = val); }
OBJC_GC_DEPRECATED("use a simple assignment instead")
static OBJC_INLINE id objc_assign_threadlocal(id val, id *dest)
{ return (*dest = val); }
OBJC_GC_DEPRECATED("use a simple assignment instead")
static OBJC_INLINE id objc_assign_ivar(id val, id dest, ptrdiff_t offset)
{ return (*(id*)((char *)dest+offset) = val); }
OBJC_GC_DEPRECATED("use a simple read instead, or convert to zeroing __weak")
static OBJC_INLINE id objc_read_weak(id *location)
{ return *location; }
OBJC_GC_DEPRECATED("use a simple assignment instead, or convert to zeroing __weak")
static OBJC_INLINE id objc_assign_weak(id value, id *location)
{ return (*location = value); }
/* MRC */
#endif
OBJC_GC_DEPRECATED("use memmove instead")
static OBJC_INLINE void *objc_memmove_collectable(void *dst, const void *src, size_t size)
{ return memmove(dst, src, size); }
OBJC_GC_DEPRECATED("it does nothing")
static OBJC_INLINE void objc_finalizeOnMainThread(Class cls __unused) { }
OBJC_GC_DEPRECATED("it always returns NO")
static OBJC_INLINE BOOL objc_is_finalized(void *ptr __unused) { return NO; }
OBJC_GC_DEPRECATED("it does nothing")
static OBJC_INLINE void objc_clear_stack(unsigned long options __unused) { }
OBJC_GC_DEPRECATED("it always returns NO")
static OBJC_INLINE BOOL objc_collecting_enabled(void) { return NO; }
OBJC_GC_DEPRECATED("it does nothing")
static OBJC_INLINE void objc_set_collection_threshold(size_t threshold __unused) { }
OBJC_GC_DEPRECATED("it does nothing")
static OBJC_INLINE void objc_set_collection_ratio(size_t ratio __unused) { }
OBJC_GC_DEPRECATED("it does nothing")
static OBJC_INLINE void objc_start_collector_thread(void) { }
#if __has_feature(objc_arc)
extern id objc_allocate_object(Class cls, int extra) UNAVAILABLE_ATTRIBUTE;
#else
OBJC_EXPORT id class_createInstance(Class cls, size_t extraBytes)
OBJC_AVAILABLE(10.0, 2.0, 9.0, 1.0);
OBJC_GC_DEPRECATED("use class_createInstance instead")
static OBJC_INLINE id objc_allocate_object(Class cls, int extra)
{ return class_createInstance(cls, extra); }
#endif
OBJC_GC_DEPRECATED("it does nothing")
static OBJC_INLINE void objc_registerThreadWithCollector() { }
OBJC_GC_DEPRECATED("it does nothing")
static OBJC_INLINE void objc_unregisterThreadWithCollector() { }
OBJC_GC_DEPRECATED("it does nothing")
static OBJC_INLINE void objc_assertRegisteredThreadWithCollector() { }
/* defined(OBJC_NO_GC) */
#endif
#endif

121
runtime/objc-auto.mm Normal file
View File

@ -0,0 +1,121 @@
/*
* Copyright (c) 2004-2007 Apple Inc. All rights reserved.
*
* @APPLE_LICENSE_HEADER_START@
*
* 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 2.0 (the 'License'). You may not use this file except in
* compliance with the License. Please obtain a copy of the License at
* http://www.opensource.apple.com/apsl/ 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, QUIET ENJOYMENT OR NON-INFRINGEMENT.
* Please see the License for the specific language governing rights and
* limitations under the License.
*
* @APPLE_LICENSE_HEADER_END@
*/
#include "objc-private.h"
// GC is no longer supported.
#if OBJC_NO_GC_API
// No GC and no GC symbols needed. We're done here.
# if SUPPORT_GC_COMPAT
# error inconsistent config settings
# endif
#else
// No GC but we do need to export GC symbols.
// These are mostly the same as the OBJC_NO_GC inline versions in objc-auto.h.
# if !SUPPORT_GC_COMPAT
# error inconsistent config settings
# endif
OBJC_EXPORT void objc_collect(unsigned long options __unused) { }
OBJC_EXPORT BOOL objc_collectingEnabled(void) { return NO; }
OBJC_EXPORT void objc_setCollectionThreshold(size_t threshold __unused) { }
OBJC_EXPORT void objc_setCollectionRatio(size_t ratio __unused) { }
OBJC_EXPORT void objc_startCollectorThread(void) { }
#if TARGET_OS_WIN32
OBJC_EXPORT BOOL objc_atomicCompareAndSwapPtr(id predicate, id replacement, volatile id *objectLocation)
{ void *original = InterlockedCompareExchangePointer((void * volatile *)objectLocation, (void *)replacement, (void *)predicate); return (original == predicate); }
OBJC_EXPORT BOOL objc_atomicCompareAndSwapPtrBarrier(id predicate, id replacement, volatile id *objectLocation)
{ void *original = InterlockedCompareExchangePointer((void * volatile *)objectLocation, (void *)replacement, (void *)predicate); return (original == predicate); }
#else
OBJC_EXPORT BOOL objc_atomicCompareAndSwapPtr(id predicate, id replacement, volatile id *objectLocation)
{ return OSAtomicCompareAndSwapPtr((void *)predicate, (void *)replacement, (void * volatile *)objectLocation); }
OBJC_EXPORT BOOL objc_atomicCompareAndSwapPtrBarrier(id predicate, id replacement, volatile id *objectLocation)
{ return OSAtomicCompareAndSwapPtrBarrier((void *)predicate, (void *)replacement, (void * volatile *)objectLocation); }
#endif
OBJC_EXPORT BOOL objc_atomicCompareAndSwapGlobal(id predicate, id replacement, volatile id *objectLocation)
{ return objc_atomicCompareAndSwapPtr(predicate, replacement, objectLocation); }
OBJC_EXPORT BOOL objc_atomicCompareAndSwapGlobalBarrier(id predicate, id replacement, volatile id *objectLocation)
{ return objc_atomicCompareAndSwapPtrBarrier(predicate, replacement, objectLocation); }
OBJC_EXPORT BOOL objc_atomicCompareAndSwapInstanceVariable(id predicate, id replacement, volatile id *objectLocation)
{ return objc_atomicCompareAndSwapPtr(predicate, replacement, objectLocation); }
OBJC_EXPORT BOOL objc_atomicCompareAndSwapInstanceVariableBarrier(id predicate, id replacement, volatile id *objectLocation)
{ return objc_atomicCompareAndSwapPtrBarrier(predicate, replacement, objectLocation); }
OBJC_EXPORT id objc_assign_strongCast(id val, id *dest)
{ return (*dest = val); }
OBJC_EXPORT id objc_assign_global(id val, id *dest)
{ return (*dest = val); }
OBJC_EXPORT id objc_assign_threadlocal(id val, id *dest)
{ return (*dest = val); }
OBJC_EXPORT id objc_assign_ivar(id val, id dest, ptrdiff_t offset)
{ return (*(id*)((char *)dest+offset) = val); }
OBJC_EXPORT id objc_read_weak(id *location)
{ return *location; }
OBJC_EXPORT id objc_assign_weak(id value, id *location)
{ return (*location = value); }
OBJC_EXPORT void *objc_memmove_collectable(void *dst, const void *src, size_t size)
{ return memmove(dst, src, size); }
OBJC_EXPORT void objc_finalizeOnMainThread(Class cls __unused) { }
OBJC_EXPORT BOOL objc_is_finalized(void *ptr __unused) { return NO; }
OBJC_EXPORT void objc_clear_stack(unsigned long options __unused) { }
OBJC_EXPORT BOOL objc_collecting_enabled(void) { return NO; }
OBJC_EXPORT void objc_set_collection_threshold(size_t threshold __unused) { }
OBJC_EXPORT void objc_set_collection_ratio(size_t ratio __unused) { }
OBJC_EXPORT void objc_start_collector_thread(void) { }
OBJC_EXPORT id objc_allocate_object(Class cls, int extra)
{ return class_createInstance(cls, extra); }
OBJC_EXPORT void objc_registerThreadWithCollector() { }
OBJC_EXPORT void objc_unregisterThreadWithCollector() { }
OBJC_EXPORT void objc_assertRegisteredThreadWithCollector() { }
OBJC_EXPORT malloc_zone_t* objc_collect_init(int(*callback)() __unused) { return nil; }
OBJC_EXPORT void* objc_collectableZone() { return nil; }
OBJC_EXPORT BOOL objc_isAuto(id object __unused) { return NO; }
OBJC_EXPORT BOOL objc_dumpHeap(char *filename __unused, unsigned long length __unused)
{ return NO; }
// not OBJC_NO_GC_API
#endif

View File

@ -0,0 +1,477 @@
/*
* Copyright (c) 2010 Apple Inc. All Rights Reserved.
*
* @APPLE_LICENSE_HEADER_START@
*
* 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 2.0 (the 'License'). You may not use this file except in
* compliance with the License. Please obtain a copy of the License at
* http://www.opensource.apple.com/apsl/ 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, QUIET ENJOYMENT OR NON-INFRINGEMENT.
* Please see the License for the specific language governing rights and
* limitations under the License.
*
* @APPLE_LICENSE_HEADER_END@
*/
/***********************************************************************
* objc-block-trampolines.m
* Author: b.bum
*
**********************************************************************/
/***********************************************************************
* Imports.
**********************************************************************/
#include "objc-private.h"
#include "runtime.h"
#include <Block.h>
#include <Block_private.h>
#include <mach/mach.h>
// symbols defined in assembly files
// Don't use the symbols directly; they're thumb-biased on some ARM archs.
#define TRAMP(tramp) \
static inline __unused uintptr_t tramp(void) { \
extern void *_##tramp; \
return ((uintptr_t)&_##tramp) & ~1UL; \
}
// Scalar return
TRAMP(a1a2_tramphead); // trampoline header code
TRAMP(a1a2_firsttramp); // first trampoline
TRAMP(a1a2_trampend); // after the last trampoline
#if SUPPORT_STRET
// Struct return
TRAMP(a2a3_tramphead);
TRAMP(a2a3_firsttramp);
TRAMP(a2a3_trampend);
#endif
// argument mode identifier
typedef enum {
ReturnValueInRegisterArgumentMode,
#if SUPPORT_STRET
ReturnValueOnStackArgumentMode,
#endif
ArgumentModeCount
} ArgumentMode;
// We must take care with our data layout on architectures that support
// multiple page sizes.
//
// The trampoline template in __TEXT is sized and aligned with PAGE_MAX_SIZE.
// On some platforms this requires additional linker flags.
//
// When we allocate a page pair, we use PAGE_MAX_SIZE size.
// This allows trampoline code to find its data by subtracting PAGE_MAX_SIZE.
//
// When we allocate a page pair, we use the process's page alignment.
// This simplifies allocation because we don't need to force greater than
// default alignment when running with small pages, but it also means
// the trampoline code MUST NOT look for its data by masking with PAGE_MAX_MASK.
struct TrampolineBlockPagePair
{
TrampolineBlockPagePair *nextPagePair; // linked list of all pages
TrampolineBlockPagePair *nextAvailablePage; // linked list of pages with available slots
uintptr_t nextAvailable; // index of next available slot, endIndex() if no more available
// Payload data: block pointers and free list.
// Bytes parallel with trampoline header code are the fields above or unused
// uint8_t blocks[ PAGE_MAX_SIZE - sizeof(TrampolineBlockPagePair) ]
// Code: trampoline header followed by trampolines.
// uint8_t trampolines[PAGE_MAX_SIZE];
// Per-trampoline block data format:
// initial value is 0 while page data is filled sequentially
// when filled, value is reference to Block_copy()d block
// when empty, value is index of next available slot OR 0 if never used yet
union Payload {
id block;
uintptr_t nextAvailable; // free list
};
static uintptr_t headerSize() {
return (uintptr_t) (a1a2_firsttramp() - a1a2_tramphead());
}
static uintptr_t slotSize() {
return 8;
}
static uintptr_t startIndex() {
// headerSize is assumed to be slot-aligned
return headerSize() / slotSize();
}
static uintptr_t endIndex() {
return (uintptr_t)PAGE_MAX_SIZE / slotSize();
}
static bool validIndex(uintptr_t index) {
return (index >= startIndex() && index < endIndex());
}
Payload *payload(uintptr_t index) {
assert(validIndex(index));
return (Payload *)((char *)this + index*slotSize());
}
IMP trampoline(uintptr_t index) {
assert(validIndex(index));
char *imp = (char *)this + index*slotSize() + PAGE_MAX_SIZE;
#if __arm__
imp++; // trampoline is Thumb instructions
#endif
return (IMP)imp;
}
uintptr_t indexForTrampoline(IMP tramp) {
uintptr_t tramp0 = (uintptr_t)this + PAGE_MAX_SIZE;
uintptr_t start = tramp0 + headerSize();
uintptr_t end = tramp0 + PAGE_MAX_SIZE;
uintptr_t address = (uintptr_t)tramp;
if (address >= start && address < end) {
return (uintptr_t)(address - tramp0) / slotSize();
}
return 0;
}
static void check() {
assert(TrampolineBlockPagePair::slotSize() == 8);
assert(TrampolineBlockPagePair::headerSize() >= sizeof(TrampolineBlockPagePair));
assert(TrampolineBlockPagePair::headerSize() % TrampolineBlockPagePair::slotSize() == 0);
// _objc_inform("%p %p %p", a1a2_tramphead(), a1a2_firsttramp(),
// a1a2_trampend());
assert(a1a2_tramphead() % PAGE_SIZE == 0); // not PAGE_MAX_SIZE
assert(a1a2_tramphead() + PAGE_MAX_SIZE == a1a2_trampend());
#if SUPPORT_STRET
// _objc_inform("%p %p %p", a2a3_tramphead(), a2a3_firsttramp(),
// a2a3_trampend());
assert(a2a3_tramphead() % PAGE_SIZE == 0); // not PAGE_MAX_SIZE
assert(a2a3_tramphead() + PAGE_MAX_SIZE == a2a3_trampend());
#endif
#if __arm__
// make sure trampolines are Thumb
extern void *_a1a2_firsttramp;
extern void *_a2a3_firsttramp;
assert(((uintptr_t)&_a1a2_firsttramp) % 2 == 1);
assert(((uintptr_t)&_a2a3_firsttramp) % 2 == 1);
#endif
}
};
// two sets of trampoline pages; one for stack returns and one for register returns
static TrampolineBlockPagePair *headPagePairs[ArgumentModeCount];
#pragma mark Utility Functions
static inline void _lock() {
#if __OBJC2__
runtimeLock.write();
#else
classLock.lock();
#endif
}
static inline void _unlock() {
#if __OBJC2__
runtimeLock.unlockWrite();
#else
classLock.unlock();
#endif
}
static inline void _assert_locked() {
#if __OBJC2__
runtimeLock.assertWriting();
#else
classLock.assertLocked();
#endif
}
#pragma mark Trampoline Management Functions
static TrampolineBlockPagePair *_allocateTrampolinesAndData(ArgumentMode aMode)
{
_assert_locked();
vm_address_t dataAddress;
TrampolineBlockPagePair::check();
TrampolineBlockPagePair *headPagePair = headPagePairs[aMode];
if (headPagePair) {
assert(headPagePair->nextAvailablePage == nil);
}
kern_return_t result;
for (int i = 0; i < 5; i++) {
result = vm_allocate(mach_task_self(), &dataAddress,
PAGE_MAX_SIZE * 2,
TRUE | VM_MAKE_TAG(VM_MEMORY_FOUNDATION));
if (result != KERN_SUCCESS) {
mach_error("vm_allocate failed", result);
return nil;
}
vm_address_t codeAddress = dataAddress + PAGE_MAX_SIZE;
result = vm_deallocate(mach_task_self(), codeAddress, PAGE_MAX_SIZE);
if (result != KERN_SUCCESS) {
mach_error("vm_deallocate failed", result);
return nil;
}
uintptr_t codePage;
switch(aMode) {
case ReturnValueInRegisterArgumentMode:
codePage = a1a2_tramphead();
break;
#if SUPPORT_STRET
case ReturnValueOnStackArgumentMode:
codePage = a2a3_tramphead();
break;
#endif
default:
_objc_fatal("unknown return mode %d", (int)aMode);
break;
}
vm_prot_t currentProtection, maxProtection;
result = vm_remap(mach_task_self(), &codeAddress, PAGE_MAX_SIZE,
0, FALSE, mach_task_self(), codePage, TRUE,
&currentProtection, &maxProtection, VM_INHERIT_SHARE);
if (result != KERN_SUCCESS) {
result = vm_deallocate(mach_task_self(),
dataAddress, PAGE_MAX_SIZE);
if (result != KERN_SUCCESS) {
mach_error("vm_deallocate for retry failed.", result);
return nil;
}
} else {
break;
}
}
if (result != KERN_SUCCESS) {
return nil;
}
TrampolineBlockPagePair *pagePair = (TrampolineBlockPagePair *) dataAddress;
pagePair->nextAvailable = pagePair->startIndex();
pagePair->nextPagePair = nil;
pagePair->nextAvailablePage = nil;
if (headPagePair) {
TrampolineBlockPagePair *lastPagePair = headPagePair;
while(lastPagePair->nextPagePair)
lastPagePair = lastPagePair->nextPagePair;
lastPagePair->nextPagePair = pagePair;
headPagePairs[aMode]->nextAvailablePage = pagePair;
} else {
headPagePairs[aMode] = pagePair;
}
return pagePair;
}
static TrampolineBlockPagePair *
_getOrAllocatePagePairWithNextAvailable(ArgumentMode aMode)
{
_assert_locked();
TrampolineBlockPagePair *headPagePair = headPagePairs[aMode];
if (!headPagePair)
return _allocateTrampolinesAndData(aMode);
// make sure head page is filled first
if (headPagePair->nextAvailable != headPagePair->endIndex())
return headPagePair;
if (headPagePair->nextAvailablePage) // check if there is a page w/a hole
return headPagePair->nextAvailablePage;
return _allocateTrampolinesAndData(aMode); // tack on a new one
}
static TrampolineBlockPagePair *
_pageAndIndexContainingIMP(IMP anImp, uintptr_t *outIndex,
TrampolineBlockPagePair **outHeadPagePair)
{
_assert_locked();
for (int arg = 0; arg < ArgumentModeCount; arg++) {
for (TrampolineBlockPagePair *pagePair = headPagePairs[arg];
pagePair;
pagePair = pagePair->nextPagePair)
{
uintptr_t index = pagePair->indexForTrampoline(anImp);
if (index) {
if (outIndex) *outIndex = index;
if (outHeadPagePair) *outHeadPagePair = headPagePairs[arg];
return pagePair;
}
}
}
return nil;
}
static ArgumentMode
_argumentModeForBlock(id block)
{
ArgumentMode aMode = ReturnValueInRegisterArgumentMode;
#if SUPPORT_STRET
if (_Block_has_signature(block) && _Block_use_stret(block))
aMode = ReturnValueOnStackArgumentMode;
#else
assert(! (_Block_has_signature(block) && _Block_use_stret(block)));
#endif
return aMode;
}
// `block` must already have been copied
IMP
_imp_implementationWithBlockNoCopy(id block)
{
_assert_locked();
ArgumentMode aMode = _argumentModeForBlock(block);
TrampolineBlockPagePair *pagePair =
_getOrAllocatePagePairWithNextAvailable(aMode);
if (!headPagePairs[aMode])
headPagePairs[aMode] = pagePair;
uintptr_t index = pagePair->nextAvailable;
assert(index >= pagePair->startIndex() && index < pagePair->endIndex());
TrampolineBlockPagePair::Payload *payload = pagePair->payload(index);
uintptr_t nextAvailableIndex = payload->nextAvailable;
if (nextAvailableIndex == 0) {
// First time through (unused slots are zero). Fill sequentially.
// If the page is now full this will now be endIndex(), handled below.
nextAvailableIndex = index + 1;
}
pagePair->nextAvailable = nextAvailableIndex;
if (nextAvailableIndex == pagePair->endIndex()) {
// PagePair is now full (free list or wilderness exhausted)
// Remove from available page linked list
TrampolineBlockPagePair *iterator = headPagePairs[aMode];
while(iterator && (iterator->nextAvailablePage != pagePair)) {
iterator = iterator->nextAvailablePage;
}
if (iterator) {
iterator->nextAvailablePage = pagePair->nextAvailablePage;
pagePair->nextAvailablePage = nil;
}
}
payload->block = block;
return pagePair->trampoline(index);
}
#pragma mark Public API
IMP imp_implementationWithBlock(id block)
{
block = Block_copy(block);
_lock();
IMP returnIMP = _imp_implementationWithBlockNoCopy(block);
_unlock();
return returnIMP;
}
id imp_getBlock(IMP anImp) {
uintptr_t index;
TrampolineBlockPagePair *pagePair;
if (!anImp) return nil;
_lock();
pagePair = _pageAndIndexContainingIMP(anImp, &index, nil);
if (!pagePair) {
_unlock();
return nil;
}
TrampolineBlockPagePair::Payload *payload = pagePair->payload(index);
if (payload->nextAvailable <= TrampolineBlockPagePair::endIndex()) {
// unallocated
_unlock();
return nil;
}
_unlock();
return payload->block;
}
BOOL imp_removeBlock(IMP anImp) {
TrampolineBlockPagePair *pagePair;
TrampolineBlockPagePair *headPagePair;
uintptr_t index;
if (!anImp) return NO;
_lock();
pagePair = _pageAndIndexContainingIMP(anImp, &index, &headPagePair);
if (!pagePair) {
_unlock();
return NO;
}
TrampolineBlockPagePair::Payload *payload = pagePair->payload(index);
id block = payload->block;
// block is released below
payload->nextAvailable = pagePair->nextAvailable;
pagePair->nextAvailable = index;
// make sure this page is on available linked list
TrampolineBlockPagePair *pagePairIterator = headPagePair;
// see if page is the next available page for any existing pages
while (pagePairIterator->nextAvailablePage &&
pagePairIterator->nextAvailablePage != pagePair)
{
pagePairIterator = pagePairIterator->nextAvailablePage;
}
if (! pagePairIterator->nextAvailablePage) {
// if iteration stopped because nextAvail was nil
// add to end of list.
pagePairIterator->nextAvailablePage = pagePair;
pagePair->nextAvailablePage = nil;
}
_unlock();
Block_release(block);
return YES;
}

43
runtime/objc-cache-old.h Normal file
View File

@ -0,0 +1,43 @@
/*
* Copyright (c) 2012 Apple Inc. All Rights Reserved.
*
* @APPLE_LICENSE_HEADER_START@
*
* 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 2.0 (the 'License'). You may not use this file except in
* compliance with the License. Please obtain a copy of the License at
* http://www.opensource.apple.com/apsl/ 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, QUIET ENJOYMENT OR NON-INFRINGEMENT.
* Please see the License for the specific language governing rights and
* limitations under the License.
*
* @APPLE_LICENSE_HEADER_END@
*/
#ifndef _OBJC_CACHE_OLD_H
#define _OBJC_CACHE_OLD_H
#include "objc-private.h"
__BEGIN_DECLS
extern IMP _cache_getImp(Class cls, SEL sel);
extern Method _cache_getMethod(Class cls, SEL sel, IMP objc_msgForward_internal_imp);
extern void flush_cache(Class cls);
extern bool _cache_fill(Class cls, Method meth, SEL sel);
extern void _cache_addForwardEntry(Class cls, SEL sel);
extern IMP _cache_addIgnoredEntry(Class cls, SEL sel);
extern void _cache_free(Cache cache);
extern void _cache_collect(bool collectALot);
__END_DECLS
#endif

1793
runtime/objc-cache-old.mm Normal file

File diff suppressed because it is too large Load Diff

21
runtime/objc-cache.h Normal file
View File

@ -0,0 +1,21 @@
#ifndef _OBJC_CACHE_H
#define _OBJC_CACHE_H
#include "objc-private.h"
__BEGIN_DECLS
extern IMP cache_getImp(Class cls, SEL sel);
extern void cache_fill(Class cls, SEL sel, IMP imp, id receiver);
extern void cache_erase_nolock(Class cls);
extern void cache_delete(Class cls);
extern void cache_collect(bool collectALot);
__END_DECLS
#endif

1111
runtime/objc-cache.mm Normal file

File diff suppressed because it is too large Load Diff

2528
runtime/objc-class-old.mm Normal file

File diff suppressed because it is too large Load Diff

2
runtime/objc-class.h Normal file
View File

@ -0,0 +1,2 @@
#include <objc/runtime.h>
#include <objc/message.h>

1272
runtime/objc-class.mm Normal file

File diff suppressed because it is too large Load Diff

170
runtime/objc-config.h Normal file
View File

@ -0,0 +1,170 @@
/*
* Copyright (c) 1999-2002, 2005-2008 Apple Inc. All Rights Reserved.
*
* @APPLE_LICENSE_HEADER_START@
*
* 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 2.0 (the 'License'). You may not use this file except in
* compliance with the License. Please obtain a copy of the License at
* http://www.opensource.apple.com/apsl/ 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, QUIET ENJOYMENT OR NON-INFRINGEMENT.
* Please see the License for the specific language governing rights and
* limitations under the License.
*
* @APPLE_LICENSE_HEADER_END@
*/
#ifndef _OBJC_CONFIG_H_
#define _OBJC_CONFIG_H_
#include <TargetConditionals.h>
// Avoid the !NDEBUG double negative.
#if !NDEBUG
# define DEBUG 1
#else
# define DEBUG 0
#endif
// Define SUPPORT_GC_COMPAT=1 to enable compatibility where GC once was.
// OBJC_NO_GC and OBJC_NO_GC_API in objc-api.h mean something else.
#if !TARGET_OS_OSX
# define SUPPORT_GC_COMPAT 0
#else
# define SUPPORT_GC_COMPAT 1
#endif
// Define SUPPORT_ZONES=1 to enable malloc zone support in NXHashTable.
#if !TARGET_OS_OSX
# define SUPPORT_ZONES 0
#else
# define SUPPORT_ZONES 1
#endif
// Define SUPPORT_MOD=1 to use the mod operator in NXHashTable and objc-sel-set
#if defined(__arm__)
# define SUPPORT_MOD 0
#else
# define SUPPORT_MOD 1
#endif
// Define SUPPORT_PREOPT=1 to enable dyld shared cache optimizations
#if TARGET_OS_WIN32 || TARGET_OS_SIMULATOR
# define SUPPORT_PREOPT 0
#else
# define SUPPORT_PREOPT 1
#endif
// Define SUPPORT_TAGGED_POINTERS=1 to enable tagged pointer objects
// Be sure to edit tagged pointer SPI in objc-internal.h as well.
#if !(__OBJC2__ && __LP64__)
# define SUPPORT_TAGGED_POINTERS 0
#else
# define SUPPORT_TAGGED_POINTERS 1
#endif
// Define SUPPORT_MSB_TAGGED_POINTERS to use the MSB
// as the tagged pointer marker instead of the LSB.
// Be sure to edit tagged pointer SPI in objc-internal.h as well.
#if !SUPPORT_TAGGED_POINTERS || !TARGET_OS_IPHONE
# define SUPPORT_MSB_TAGGED_POINTERS 0
#else
# define SUPPORT_MSB_TAGGED_POINTERS 1
#endif
// Define SUPPORT_INDEXED_ISA=1 on platforms that store the class in the isa
// field as an index into a class table.
// Note, keep this in sync with any .s files which also define it.
// Be sure to edit objc-abi.h as well.
#if __ARM_ARCH_7K__ >= 2
# define SUPPORT_INDEXED_ISA 1
#else
# define SUPPORT_INDEXED_ISA 0
#endif
// Define SUPPORT_PACKED_ISA=1 on platforms that store the class in the isa
// field as a maskable pointer with other data around it.
#if (!__LP64__ || TARGET_OS_WIN32 || TARGET_OS_SIMULATOR)
# define SUPPORT_PACKED_ISA 0
#else
# define SUPPORT_PACKED_ISA 1
#endif
// Define SUPPORT_NONPOINTER_ISA=1 on any platform that may store something
// in the isa field that is not a raw pointer.
#if !SUPPORT_INDEXED_ISA && !SUPPORT_PACKED_ISA
# define SUPPORT_NONPOINTER_ISA 0
#else
# define SUPPORT_NONPOINTER_ISA 1
#endif
// Define SUPPORT_FIXUP=1 to repair calls sites for fixup dispatch.
// Fixup messaging itself is no longer supported.
// Be sure to edit objc-abi.h as well (objc_msgSend*_fixup)
#if !(defined(__x86_64__) && (TARGET_OS_OSX || TARGET_OS_SIMULATOR))
# define SUPPORT_FIXUP 0
#else
# define SUPPORT_FIXUP 1
#endif
// Define SUPPORT_ZEROCOST_EXCEPTIONS to use "zero-cost" exceptions for OBJC2.
// Be sure to edit objc-exception.h as well (objc_add/removeExceptionHandler)
#if !__OBJC2__ || (defined(__arm__) && __USING_SJLJ_EXCEPTIONS__)
# define SUPPORT_ZEROCOST_EXCEPTIONS 0
#else
# define SUPPORT_ZEROCOST_EXCEPTIONS 1
#endif
// Define SUPPORT_ALT_HANDLERS if you're using zero-cost exceptions
// but also need to support AppKit's alt-handler scheme
// Be sure to edit objc-exception.h as well (objc_add/removeExceptionHandler)
#if !SUPPORT_ZEROCOST_EXCEPTIONS || TARGET_OS_IPHONE || TARGET_OS_EMBEDDED
# define SUPPORT_ALT_HANDLERS 0
#else
# define SUPPORT_ALT_HANDLERS 1
#endif
// Define SUPPORT_RETURN_AUTORELEASE to optimize autoreleased return values
#if TARGET_OS_WIN32
# define SUPPORT_RETURN_AUTORELEASE 0
#else
# define SUPPORT_RETURN_AUTORELEASE 1
#endif
// Define SUPPORT_STRET on architectures that need separate struct-return ABI.
#if defined(__arm64__)
# define SUPPORT_STRET 0
#else
# define SUPPORT_STRET 1
#endif
// Define SUPPORT_MESSAGE_LOGGING to enable NSObjCMessageLoggingEnabled
#if TARGET_OS_WIN32 || TARGET_OS_EMBEDDED
# define SUPPORT_MESSAGE_LOGGING 0
#else
# define SUPPORT_MESSAGE_LOGGING 1
#endif
// Define SUPPORT_QOS_HACK to work around deadlocks due to QoS bugs.
#if !__OBJC2__ || TARGET_OS_WIN32
# define SUPPORT_QOS_HACK 0
#else
# define SUPPORT_QOS_HACK 1
#endif
// OBJC_INSTRUMENTED controls whether message dispatching is dynamically
// monitored. Monitoring introduces substantial overhead.
// NOTE: To define this condition, do so in the build command, NOT by
// uncommenting the line here. This is because objc-class.h heeds this
// condition, but objc-class.h can not #include this file (objc-config.h)
// because objc-class.h is public and objc-config.h is not.
//#define OBJC_INSTRUMENTED
#endif

42
runtime/objc-env.h Normal file
View File

@ -0,0 +1,42 @@
// -*- truncate-lines: t; -*-
// OPTION(var, env, help)
OPTION( PrintImages, OBJC_PRINT_IMAGES, "log image and library names as they are loaded")
OPTION( PrintImageTimes, OBJC_PRINT_IMAGE_TIMES, "measure duration of image loading steps")
OPTION( PrintLoading, OBJC_PRINT_LOAD_METHODS, "log calls to class and category +load methods")
OPTION( PrintInitializing, OBJC_PRINT_INITIALIZE_METHODS, "log calls to class +initialize methods")
OPTION( PrintResolving, OBJC_PRINT_RESOLVED_METHODS, "log methods created by +resolveClassMethod: and +resolveInstanceMethod:")
OPTION( PrintConnecting, OBJC_PRINT_CLASS_SETUP, "log progress of class and category setup")
OPTION( PrintProtocols, OBJC_PRINT_PROTOCOL_SETUP, "log progress of protocol setup")
OPTION( PrintIvars, OBJC_PRINT_IVAR_SETUP, "log processing of non-fragile ivars")
OPTION( PrintVtables, OBJC_PRINT_VTABLE_SETUP, "log processing of class vtables")
OPTION( PrintVtableImages, OBJC_PRINT_VTABLE_IMAGES, "print vtable images showing overridden methods")
OPTION( PrintCaches, OBJC_PRINT_CACHE_SETUP, "log processing of method caches")
OPTION( PrintFuture, OBJC_PRINT_FUTURE_CLASSES, "log use of future classes for toll-free bridging")
OPTION( PrintPreopt, OBJC_PRINT_PREOPTIMIZATION, "log preoptimization courtesy of dyld shared cache")
OPTION( PrintCxxCtors, OBJC_PRINT_CXX_CTORS, "log calls to C++ ctors and dtors for instance variables")
OPTION( PrintExceptions, OBJC_PRINT_EXCEPTIONS, "log exception handling")
OPTION( PrintExceptionThrow, OBJC_PRINT_EXCEPTION_THROW, "log backtrace of every objc_exception_throw()")
OPTION( PrintAltHandlers, OBJC_PRINT_ALT_HANDLERS, "log processing of exception alt handlers")
OPTION( PrintReplacedMethods, OBJC_PRINT_REPLACED_METHODS, "log methods replaced by category implementations")
OPTION( PrintDeprecation, OBJC_PRINT_DEPRECATION_WARNINGS, "warn about calls to deprecated runtime functions")
OPTION( PrintPoolHiwat, OBJC_PRINT_POOL_HIGHWATER, "log high-water marks for autorelease pools")
OPTION( PrintCustomRR, OBJC_PRINT_CUSTOM_RR, "log classes with un-optimized custom retain/release methods")
OPTION( PrintCustomAWZ, OBJC_PRINT_CUSTOM_AWZ, "log classes with un-optimized custom allocWithZone methods")
OPTION( PrintRawIsa, OBJC_PRINT_RAW_ISA, "log classes that require raw pointer isa fields")
OPTION( DebugUnload, OBJC_DEBUG_UNLOAD, "warn about poorly-behaving bundles when unloaded")
OPTION( DebugFragileSuperclasses, OBJC_DEBUG_FRAGILE_SUPERCLASSES, "warn about subclasses that may have been broken by subsequent changes to superclasses")
OPTION( DebugNilSync, OBJC_DEBUG_NIL_SYNC, "warn about @synchronized(nil), which does no synchronization")
OPTION( DebugNonFragileIvars, OBJC_DEBUG_NONFRAGILE_IVARS, "capriciously rearrange non-fragile ivars")
OPTION( DebugAltHandlers, OBJC_DEBUG_ALT_HANDLERS, "record more info about bad alt handler use")
OPTION( DebugMissingPools, OBJC_DEBUG_MISSING_POOLS, "warn about autorelease with no pool in place, which may be a leak")
OPTION( DebugPoolAllocation, OBJC_DEBUG_POOL_ALLOCATION, "halt when autorelease pools are popped out of order, and allow heap debuggers to track autorelease pools")
OPTION( DebugDuplicateClasses, OBJC_DEBUG_DUPLICATE_CLASSES, "halt when multiple classes with the same name are present")
OPTION( DebugDontCrash, OBJC_DEBUG_DONT_CRASH, "halt the process by exiting instead of crashing")
OPTION( DisableVtables, OBJC_DISABLE_VTABLES, "disable vtable dispatch")
OPTION( DisablePreopt, OBJC_DISABLE_PREOPTIMIZATION, "disable preoptimization courtesy of dyld shared cache")
OPTION( DisableTaggedPointers, OBJC_DISABLE_TAGGED_POINTERS, "disable tagged pointer optimization of NSNumber et al.")
OPTION( DisableNonpointerIsa, OBJC_DISABLE_NONPOINTER_ISA, "disable non-pointer isa fields")

306
runtime/objc-errors.mm Normal file
View File

@ -0,0 +1,306 @@
/*
* Copyright (c) 1999-2003, 2005-2007 Apple Inc. All Rights Reserved.
*
* @APPLE_LICENSE_HEADER_START@
*
* 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 2.0 (the 'License'). You may not use this file except in
* compliance with the License. Please obtain a copy of the License at
* http://www.opensource.apple.com/apsl/ 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, QUIET ENJOYMENT OR NON-INFRINGEMENT.
* Please see the License for the specific language governing rights and
* limitations under the License.
*
* @APPLE_LICENSE_HEADER_END@
*/
/*
* objc-errors.m
* Copyright 1988-2001, NeXT Software, Inc., Apple Computer, Inc.
*/
#include "objc-private.h"
#if TARGET_OS_WIN32
#include <conio.h>
void _objc_inform_on_crash(const char *fmt, ...)
{
}
void _objc_inform(const char *fmt, ...)
{
va_list args;
va_start(args, fmt);
_vcprintf(fmt, args);
va_end(args);
_cprintf("\n");
}
void _objc_fatal(const char *fmt, ...)
{
va_list args;
va_start(args, fmt);
_vcprintf(fmt, args);
va_end(args);
_cprintf("\n");
abort();
}
void __objc_error(id rcv, const char *fmt, ...)
{
va_list args;
va_start(args, fmt);
_vcprintf(fmt, args);
va_end(args);
abort();
}
void _objc_error(id rcv, const char *fmt, va_list args)
{
_vcprintf(fmt, args);
abort();
}
#else
#include <_simple.h>
OBJC_EXPORT void (*_error)(id, const char *, va_list);
// Return true if c is a UTF8 continuation byte
static bool isUTF8Continuation(char c)
{
return (c & 0xc0) == 0x80; // continuation byte is 0b10xxxxxx
}
// Add "message" to any forthcoming crash log.
static mutex_t crashlog_lock;
static void _objc_crashlog(const char *message)
{
char *newmsg;
#if 0
{
// for debugging at BOOT time.
extern char **_NSGetProgname(void);
FILE *crashlog = fopen("/_objc_crash.log", "a");
setbuf(crashlog, NULL);
fprintf(crashlog, "[%s] %s\n", *_NSGetProgname(), message);
fclose(crashlog);
sync();
}
#endif
mutex_locker_t lock(crashlog_lock);
char *oldmsg = (char *)CRGetCrashLogMessage();
size_t oldlen;
const size_t limit = 8000;
if (!oldmsg) {
newmsg = strdup(message);
} else if ((oldlen = strlen(oldmsg)) > limit) {
// limit total length by dropping old contents
char *truncmsg = oldmsg + oldlen - limit;
// advance past partial UTF-8 bytes
while (isUTF8Continuation(*truncmsg)) truncmsg++;
asprintf(&newmsg, "... %s\n%s", truncmsg, message);
} else {
asprintf(&newmsg, "%s\n%s", oldmsg, message);
}
if (newmsg) {
// Strip trailing newline
char *c = &newmsg[strlen(newmsg)-1];
if (*c == '\n') *c = '\0';
if (oldmsg) free(oldmsg);
CRSetCrashLogMessage(newmsg);
}
}
// Returns true if logs should be sent to stderr as well as syslog.
// Copied from CFUtilities.c
static bool also_do_stderr(void)
{
struct stat st;
int ret = fstat(STDERR_FILENO, &st);
if (ret < 0) return false;
mode_t m = st.st_mode & S_IFMT;
if (m == S_IFREG || m == S_IFSOCK || m == S_IFIFO || m == S_IFCHR) {
return true;
}
return false;
}
// Print "message" to the console.
static void _objc_syslog(const char *message)
{
_simple_asl_log(ASL_LEVEL_ERR, nil, message);
if (also_do_stderr()) {
write(STDERR_FILENO, message, strlen(message));
}
}
/*
* _objc_error is the default *_error handler.
*/
#if !__OBJC2__
// used by ExceptionHandling.framework
#endif
__attribute__((noreturn))
void _objc_error(id self, const char *fmt, va_list ap)
{
char *buf;
vasprintf(&buf, fmt, ap);
_objc_fatal("%s: %s", object_getClassName(self), buf);
}
/*
* this routine handles errors that involve an object (or class).
*/
void __objc_error(id rcv, const char *fmt, ...)
{
va_list vp;
va_start(vp,fmt);
#if !__OBJC2__
(*_error)(rcv, fmt, vp);
#endif
_objc_error (rcv, fmt, vp); /* In case (*_error)() returns. */
va_end(vp);
}
static __attribute__((noreturn))
void _objc_fatalv(uint64_t reason, uint64_t flags, const char *fmt, va_list ap)
{
char *buf1;
vasprintf(&buf1, fmt, ap);
char *buf2;
asprintf(&buf2, "objc[%d]: %s\n", getpid(), buf1);
_objc_syslog(buf2);
if (DebugDontCrash) {
char *buf3;
asprintf(&buf3, "objc[%d]: HALTED\n", getpid());
_objc_syslog(buf3);
_Exit(1);
}
else {
abort_with_reason(OS_REASON_OBJC, reason, buf1, flags);
}
}
void _objc_fatal_with_reason(uint64_t reason, uint64_t flags,
const char *fmt, ...)
{
va_list ap;
va_start(ap, fmt);
_objc_fatalv(reason, flags, fmt, ap);
}
void _objc_fatal(const char *fmt, ...)
{
va_list ap;
va_start(ap,fmt);
_objc_fatalv(OBJC_EXIT_REASON_UNSPECIFIED,
OS_REASON_FLAG_ONE_TIME_FAILURE,
fmt, ap);
}
/*
* this routine handles soft runtime errors...like not being able
* add a category to a class (because it wasn't linked in).
*/
void _objc_inform(const char *fmt, ...)
{
va_list ap;
char *buf1;
char *buf2;
va_start (ap,fmt);
vasprintf(&buf1, fmt, ap);
va_end (ap);
asprintf(&buf2, "objc[%d]: %s\n", getpid(), buf1);
_objc_syslog(buf2);
free(buf2);
free(buf1);
}
/*
* Like _objc_inform(), but prints the message only in any
* forthcoming crash log, not to the console.
*/
void _objc_inform_on_crash(const char *fmt, ...)
{
va_list ap;
char *buf1;
char *buf2;
va_start (ap,fmt);
vasprintf(&buf1, fmt, ap);
va_end (ap);
asprintf(&buf2, "objc[%d]: %s\n", getpid(), buf1);
_objc_crashlog(buf2);
free(buf2);
free(buf1);
}
/*
* Like calling both _objc_inform and _objc_inform_on_crash.
*/
void _objc_inform_now_and_on_crash(const char *fmt, ...)
{
va_list ap;
char *buf1;
char *buf2;
va_start (ap,fmt);
vasprintf(&buf1, fmt, ap);
va_end (ap);
asprintf(&buf2, "objc[%d]: %s\n", getpid(), buf1);
_objc_crashlog(buf2);
_objc_syslog(buf2);
free(buf2);
free(buf1);
}
#endif
BREAKPOINT_FUNCTION(
void _objc_warn_deprecated(void)
);
void _objc_inform_deprecated(const char *oldf, const char *newf)
{
if (PrintDeprecation) {
if (newf) {
_objc_inform("The function %s is obsolete. Use %s instead. Set a breakpoint on _objc_warn_deprecated to find the culprit.", oldf, newf);
} else {
_objc_inform("The function %s is obsolete. Do not use it. Set a breakpoint on _objc_warn_deprecated to find the culprit.", oldf);
}
}
_objc_warn_deprecated();
}

116
runtime/objc-exception.h Normal file
View File

@ -0,0 +1,116 @@
/*
* Copyright (c) 2002-2003, 2006-2007 Apple Inc. All Rights Reserved.
*
* @APPLE_LICENSE_HEADER_START@
*
* 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 2.0 (the 'License'). You may not use this file except in
* compliance with the License. Please obtain a copy of the License at
* http://www.opensource.apple.com/apsl/ 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, QUIET ENJOYMENT OR NON-INFRINGEMENT.
* Please see the License for the specific language governing rights and
* limitations under the License.
*
* @APPLE_LICENSE_HEADER_END@
*/
#ifndef __OBJC_EXCEPTION_H_
#define __OBJC_EXCEPTION_H_
#include <objc/objc.h>
#include <stdint.h>
#if !__OBJC2__
// compiler reserves a setjmp buffer + 4 words as localExceptionData
OBJC_EXPORT void objc_exception_throw(id exception)
__OSX_AVAILABLE(10.3)
__IOS_UNAVAILABLE __TVOS_UNAVAILABLE __WATCHOS_UNAVAILABLE;
OBJC_EXPORT void objc_exception_try_enter(void *localExceptionData)
__OSX_AVAILABLE(10.3)
__IOS_UNAVAILABLE __TVOS_UNAVAILABLE __WATCHOS_UNAVAILABLE;
OBJC_EXPORT void objc_exception_try_exit(void *localExceptionData)
__OSX_AVAILABLE(10.3)
__IOS_UNAVAILABLE __TVOS_UNAVAILABLE __WATCHOS_UNAVAILABLE;
OBJC_EXPORT id objc_exception_extract(void *localExceptionData)
__OSX_AVAILABLE(10.3)
__IOS_UNAVAILABLE __TVOS_UNAVAILABLE __WATCHOS_UNAVAILABLE;
OBJC_EXPORT int objc_exception_match(Class exceptionClass, id exception)
__OSX_AVAILABLE(10.3)
__IOS_UNAVAILABLE __TVOS_UNAVAILABLE __WATCHOS_UNAVAILABLE;
typedef struct {
int version;
void (*throw_exc)(id); // version 0
void (*try_enter)(void *); // version 0
void (*try_exit)(void *); // version 0
id (*extract)(void *); // version 0
int (*match)(Class, id); // version 0
} objc_exception_functions_t;
// get table; version tells how many
OBJC_EXPORT void objc_exception_get_functions(objc_exception_functions_t *table)
__OSX_AVAILABLE(10.3)
__IOS_UNAVAILABLE __TVOS_UNAVAILABLE __WATCHOS_UNAVAILABLE;
// set table
OBJC_EXPORT void objc_exception_set_functions(objc_exception_functions_t *table)
__OSX_AVAILABLE(10.3)
__IOS_UNAVAILABLE __TVOS_UNAVAILABLE __WATCHOS_UNAVAILABLE;
// !__OBJC2__
#else
// __OBJC2__
typedef id (*objc_exception_preprocessor)(id exception);
typedef int (*objc_exception_matcher)(Class catch_type, id exception);
typedef void (*objc_uncaught_exception_handler)(id exception);
typedef void (*objc_exception_handler)(id unused, void *context);
/**
* Throw a runtime exception. This function is inserted by the compiler
* where \c @throw would otherwise be.
*
* @param exception The exception to be thrown.
*/
OBJC_EXPORT void objc_exception_throw(id exception)
OBJC_AVAILABLE(10.5, 2.0, 9.0, 1.0);
OBJC_EXPORT void objc_exception_rethrow(void)
OBJC_AVAILABLE(10.5, 2.0, 9.0, 1.0);
OBJC_EXPORT id objc_begin_catch(void *exc_buf)
OBJC_AVAILABLE(10.5, 2.0, 9.0, 1.0);
OBJC_EXPORT void objc_end_catch(void)
OBJC_AVAILABLE(10.5, 2.0, 9.0, 1.0);
OBJC_EXPORT void objc_terminate(void)
OBJC_AVAILABLE(10.8, 6.0, 9.0, 1.0);
OBJC_EXPORT objc_exception_preprocessor objc_setExceptionPreprocessor(objc_exception_preprocessor fn)
OBJC_AVAILABLE(10.5, 2.0, 9.0, 1.0);
OBJC_EXPORT objc_exception_matcher objc_setExceptionMatcher(objc_exception_matcher fn)
OBJC_AVAILABLE(10.5, 2.0, 9.0, 1.0);
OBJC_EXPORT objc_uncaught_exception_handler objc_setUncaughtExceptionHandler(objc_uncaught_exception_handler fn)
OBJC_AVAILABLE(10.5, 2.0, 9.0, 1.0);
// Not for iOS.
OBJC_EXPORT uintptr_t objc_addExceptionHandler(objc_exception_handler fn, void *context)
__OSX_AVAILABLE(10.5)
__IOS_UNAVAILABLE __TVOS_UNAVAILABLE __WATCHOS_UNAVAILABLE;
OBJC_EXPORT void objc_removeExceptionHandler(uintptr_t token)
__OSX_AVAILABLE(10.5)
__IOS_UNAVAILABLE __TVOS_UNAVAILABLE __WATCHOS_UNAVAILABLE;
// __OBJC2__
#endif
#endif // __OBJC_EXCEPTION_H_

1396
runtime/objc-exception.mm Normal file

File diff suppressed because it is too large Load Diff

50
runtime/objc-file-old.h Normal file
View File

@ -0,0 +1,50 @@
/*
* Copyright (c) 2009 Apple Inc. All Rights Reserved.
*
* @APPLE_LICENSE_HEADER_START@
*
* 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 2.0 (the 'License'). You may not use this file except in
* compliance with the License. Please obtain a copy of the License at
* http://www.opensource.apple.com/apsl/ 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, QUIET ENJOYMENT OR NON-INFRINGEMENT.
* Please see the License for the specific language governing rights and
* limitations under the License.
*
* @APPLE_LICENSE_HEADER_END@
*/
#ifndef _OBJC_FILE_OLD_H
#define _OBJC_FILE_OLD_H
#if !__OBJC2__
#include "objc-os.h"
struct objc_module;
struct old_protocol;
struct old_class;
__BEGIN_DECLS
extern struct objc_module *_getObjcModules(const header_info *hi, size_t *nmodules);
extern SEL *_getObjcSelectorRefs(const header_info *hi, size_t *nmess);
extern struct old_protocol **_getObjcProtocols(const header_info *hi, size_t *nprotos);
extern Class *_getObjcClassRefs(const header_info *hi, size_t *nclasses);
extern const char *_getObjcClassNames(const header_info *hi, size_t *size);
using Initializer = void(*)(void);
extern Initializer* getLibobjcInitializers(const headerType *mhdr, size_t *count);
__END_DECLS
#endif
#endif

165
runtime/objc-file-old.mm Normal file
View File

@ -0,0 +1,165 @@
/*
* Copyright (c) 1999-2007 Apple Inc. All Rights Reserved.
*
* @APPLE_LICENSE_HEADER_START@
*
* 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 2.0 (the 'License'). You may not use this file except in
* compliance with the License. Please obtain a copy of the License at
* http://www.opensource.apple.com/apsl/ 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, QUIET ENJOYMENT OR NON-INFRINGEMENT.
* Please see the License for the specific language governing rights and
* limitations under the License.
*
* @APPLE_LICENSE_HEADER_END@
*/
// Copyright 1988-1996 NeXT Software, Inc.
#if !__OBJC2__
#include "objc-private.h"
#include "objc-runtime-old.h"
#include "objc-file-old.h"
#if TARGET_OS_WIN32
/*
Module
_getObjcModules(const header_info *hi, size_t *nmodules)
{
if (nmodules) *nmodules = hi->moduleCount;
return hi->modules;
}
*/
SEL *
_getObjcSelectorRefs(const header_info *hi, size_t *nmess)
{
if (nmess) *nmess = hi->selrefCount;
return hi->selrefs;
}
struct old_protocol **
_getObjcProtocols(const header_info *hi, size_t *nprotos)
{
if (nprotos) *nprotos = hi->protocolCount;
return hi->protocols;
}
Class*
_getObjcClassRefs(const header_info *hi, size_t *nclasses)
{
if (nclasses) *nclasses = hi->clsrefCount;
return (Class*)hi->clsrefs;
}
// __OBJC,__class_names section only emitted by CodeWarrior rdar://4951638
const char *
_getObjcClassNames(const header_info *hi, size_t *size)
{
if (size) *size = 0;
return NULL;
}
#else
#define GETSECT(name, type, segname, sectname) \
type *name(const headerType *mhdr, size_t *outCount) \
{ \
unsigned long byteCount = 0; \
type *data = (type *) \
getsectiondata(mhdr, segname, sectname, &byteCount); \
*outCount = byteCount / sizeof(type); \
return data; \
} \
type *name(const header_info *hi, size_t *outCount) \
{ \
return name(hi->mhdr(), outCount); \
}
GETSECT(_getObjcModules, objc_module, "__OBJC", "__module_info");
GETSECT(_getObjcSelectorRefs, SEL, "__OBJC", "__message_refs");
GETSECT(_getObjcClassRefs, Class, "__OBJC", "__cls_refs");
GETSECT(_getObjcClassNames, const char, "__OBJC", "__class_names");
// __OBJC,__class_names section only emitted by CodeWarrior rdar://4951638
GETSECT(getLibobjcInitializers, Initializer, "__DATA", "__objc_init_func");
objc_image_info *
_getObjcImageInfo(const headerType *mhdr, size_t *outBytes)
{
unsigned long byteCount = 0;
objc_image_info *info = (objc_image_info *)
getsectiondata(mhdr, SEG_OBJC, "__image_info", &byteCount);
*outBytes = byteCount;
return info;
}
struct old_protocol **
_getObjcProtocols(const header_info *hi, size_t *nprotos)
{
unsigned long size = 0;
struct old_protocol *protos = (struct old_protocol *)
getsectiondata(hi->mhdr(), SEG_OBJC, "__protocol", &size);
*nprotos = size / sizeof(struct old_protocol);
if (!hi->proto_refs && *nprotos) {
size_t i;
header_info *whi = (header_info *)hi;
whi->proto_refs = (struct old_protocol **)
malloc(*nprotos * sizeof(*hi->proto_refs));
for (i = 0; i < *nprotos; i++) {
hi->proto_refs[i] = protos+i;
}
}
return hi->proto_refs;
}
static const segmentType *
getsegbynamefromheader(const headerType *head, const char *segname)
{
const segmentType *sgp;
unsigned long i;
sgp = (const segmentType *) (head + 1);
for (i = 0; i < head->ncmds; i++){
if (sgp->cmd == SEGMENT_CMD) {
if (strncmp(sgp->segname, segname, sizeof(sgp->segname)) == 0) {
return sgp;
}
}
sgp = (const segmentType *)((char *)sgp + sgp->cmdsize);
}
return NULL;
}
bool
_hasObjcContents(const header_info *hi)
{
// Look for an __OBJC,* section other than __OBJC,__image_info
const segmentType *seg = getsegbynamefromheader(hi->mhdr(), "__OBJC");
const sectionType *sect;
uint32_t i;
for (i = 0; i < seg->nsects; i++) {
sect = ((const sectionType *)(seg+1))+i;
if (0 != strncmp(sect->sectname, "__image_info", 12)) {
return YES;
}
}
return NO;
}
#endif
#endif

52
runtime/objc-file.h Normal file
View File

@ -0,0 +1,52 @@
/*
* Copyright (c) 2009 Apple Inc. All Rights Reserved.
*
* @APPLE_LICENSE_HEADER_START@
*
* 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 2.0 (the 'License'). You may not use this file except in
* compliance with the License. Please obtain a copy of the License at
* http://www.opensource.apple.com/apsl/ 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, QUIET ENJOYMENT OR NON-INFRINGEMENT.
* Please see the License for the specific language governing rights and
* limitations under the License.
*
* @APPLE_LICENSE_HEADER_END@
*/
#ifndef _OBJC_FILE_NEW_H
#define _OBJC_FILE_NEW_H
#if __OBJC2__
#include "objc-runtime-new.h"
// classref_t is not fixed up at launch; use remapClass() to convert
extern SEL *_getObjc2SelectorRefs(const header_info *hi, size_t *count);
extern message_ref_t *_getObjc2MessageRefs(const header_info *hi, size_t *count);
extern Class*_getObjc2ClassRefs(const header_info *hi, size_t *count);
extern Class*_getObjc2SuperRefs(const header_info *hi, size_t *count);
extern classref_t *_getObjc2ClassList(const header_info *hi, size_t *count);
extern classref_t *_getObjc2NonlazyClassList(const header_info *hi, size_t *count);
extern category_t **_getObjc2CategoryList(const header_info *hi, size_t *count);
extern category_t **_getObjc2NonlazyCategoryList(const header_info *hi, size_t *count);
extern protocol_t **_getObjc2ProtocolList(const header_info *hi, size_t *count);
extern protocol_t **_getObjc2ProtocolRefs(const header_info *hi, size_t *count);
using Initializer = void(*)(void);
extern Initializer* getLibobjcInitializers(const header_info *hi, size_t *count);
extern classref_t *_getObjc2NonlazyClassList(const headerType *mhdr, size_t *count);
extern category_t **_getObjc2NonlazyCategoryList(const headerType *mhdr, size_t *count);
extern Initializer* getLibobjcInitializers(const headerType *mhdr, size_t *count);
#endif
#endif

127
runtime/objc-file.mm Normal file
View File

@ -0,0 +1,127 @@
/*
* Copyright (c) 1999-2007 Apple Inc. All Rights Reserved.
*
* @APPLE_LICENSE_HEADER_START@
*
* 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 2.0 (the 'License'). You may not use this file except in
* compliance with the License. Please obtain a copy of the License at
* http://www.opensource.apple.com/apsl/ 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, QUIET ENJOYMENT OR NON-INFRINGEMENT.
* Please see the License for the specific language governing rights and
* limitations under the License.
*
* @APPLE_LICENSE_HEADER_END@
*/
#if __OBJC2__
#include "objc-private.h"
#include "objc-file.h"
// Look for a __DATA or __DATA_CONST or __DATA_DIRTY section
// with the given name that stores an array of T.
template <typename T>
T* getDataSection(const headerType *mhdr, const char *sectname,
size_t *outBytes, size_t *outCount)
{
unsigned long byteCount = 0;
T* data = (T*)getsectiondata(mhdr, "__DATA", sectname, &byteCount);
if (!data) {
data = (T*)getsectiondata(mhdr, "__DATA_CONST", sectname, &byteCount);
}
if (!data) {
data = (T*)getsectiondata(mhdr, "__DATA_DIRTY", sectname, &byteCount);
}
if (outBytes) *outBytes = byteCount;
if (outCount) *outCount = byteCount / sizeof(T);
return data;
}
#define GETSECT(name, type, sectname) \
type *name(const headerType *mhdr, size_t *outCount) { \
return getDataSection<type>(mhdr, sectname, nil, outCount); \
} \
type *name(const header_info *hi, size_t *outCount) { \
return getDataSection<type>(hi->mhdr(), sectname, nil, outCount); \
}
// function name content type section name
GETSECT(_getObjc2SelectorRefs, SEL, "__objc_selrefs");
GETSECT(_getObjc2MessageRefs, message_ref_t, "__objc_msgrefs");
GETSECT(_getObjc2ClassRefs, Class, "__objc_classrefs");
GETSECT(_getObjc2SuperRefs, Class, "__objc_superrefs");
GETSECT(_getObjc2ClassList, classref_t, "__objc_classlist");
GETSECT(_getObjc2NonlazyClassList, classref_t, "__objc_nlclslist");
GETSECT(_getObjc2CategoryList, category_t *, "__objc_catlist");
GETSECT(_getObjc2NonlazyCategoryList, category_t *, "__objc_nlcatlist");
GETSECT(_getObjc2ProtocolList, protocol_t *, "__objc_protolist");
GETSECT(_getObjc2ProtocolRefs, protocol_t *, "__objc_protorefs");
GETSECT(getLibobjcInitializers, Initializer, "__objc_init_func");
objc_image_info *
_getObjcImageInfo(const headerType *mhdr, size_t *outBytes)
{
return getDataSection<objc_image_info>(mhdr, "__objc_imageinfo",
outBytes, nil);
}
static const segmentType *
getsegbynamefromheader(const headerType *mhdr, const char *segname)
{
const segmentType *seg = (const segmentType *) (mhdr + 1);
for (unsigned long i = 0; i < mhdr->ncmds; i++){
if (seg->cmd == SEGMENT_CMD && segnameEquals(seg->segname, segname)) {
return seg;
}
seg = (const segmentType *)((char *)seg + seg->cmdsize);
}
return nil;
}
// Look for an __objc* section other than __objc_imageinfo
static bool segmentHasObjcContents(const segmentType *seg)
{
if (seg) {
for (uint32_t i = 0; i < seg->nsects; i++) {
const sectionType *sect = ((const sectionType *)(seg+1))+i;
if (sectnameStartsWith(sect->sectname, "__objc_") &&
!sectnameEquals(sect->sectname, "__objc_imageinfo"))
{
return true;
}
}
}
return false;
}
// Look for an __objc* section other than __objc_imageinfo
bool
_hasObjcContents(const header_info *hi)
{
const segmentType *data =
getsegbynamefromheader(hi->mhdr(), "__DATA");
const segmentType *data_const =
getsegbynamefromheader(hi->mhdr(), "__DATA_CONST");
const segmentType *data_dirty =
getsegbynamefromheader(hi->mhdr(), "__DATA_DIRTY");
return segmentHasObjcContents(data)
|| segmentHasObjcContents(data_const)
|| segmentHasObjcContents(data_dirty);
}
// OBJC2
#endif

223
runtime/objc-gdb.h Normal file
View File

@ -0,0 +1,223 @@
/*
* Copyright (c) 2008 Apple Inc. All Rights Reserved.
*
* @APPLE_LICENSE_HEADER_START@
*
* 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 2.0 (the 'License'). You may not use this file except in
* compliance with the License. Please obtain a copy of the License at
* http://www.opensource.apple.com/apsl/ 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, QUIET ENJOYMENT OR NON-INFRINGEMENT.
* Please see the License for the specific language governing rights and
* limitations under the License.
*
* @APPLE_LICENSE_HEADER_END@
*/
#ifndef _OBJC_GDB_H
#define _OBJC_GDB_H
/*
* WARNING DANGER HAZARD BEWARE EEK
*
* Everything in this file is for debugger and developer tool use only.
* These will change in arbitrary OS updates and in unpredictable ways.
* When your program breaks, you get to keep both pieces.
*/
#ifdef __APPLE_API_PRIVATE
#define _OBJC_PRIVATE_H_
#include <stdint.h>
#include <objc/hashtable.h>
#include <objc/maptable.h>
__BEGIN_DECLS
/***********************************************************************
* Class pointer preflighting
**********************************************************************/
// Return cls if it's a valid class, or crash.
OBJC_EXPORT Class gdb_class_getClass(Class cls)
#if __OBJC2__
OBJC_AVAILABLE(10.6, 3.1, 9.0, 1.0);
#else
OBJC_AVAILABLE(10.7, 3.1, 9.0, 1.0);
#endif
// Same as gdb_class_getClass(object_getClass(cls)).
OBJC_EXPORT Class gdb_object_getClass(id obj)
OBJC_AVAILABLE(10.7, 4.3, 9.0, 1.0);
/***********************************************************************
* Class lists for heap.
**********************************************************************/
#if __OBJC2__
// Maps class name to Class, for in-use classes only. NXStrValueMapPrototype.
OBJC_EXPORT NXMapTable *gdb_objc_realized_classes
OBJC_AVAILABLE(10.6, 3.1, 9.0, 1.0);
#else
// Hashes Classes, for all known classes. Custom prototype.
OBJC_EXPORT NXHashTable *_objc_debug_class_hash
__OSX_AVAILABLE(10.2)
__IOS_UNAVAILABLE __TVOS_UNAVAILABLE __WATCHOS_UNAVAILABLE;
#endif
/***********************************************************************
* Non-pointer isa
**********************************************************************/
#if __OBJC2__
// Extract isa pointer from an isa field.
// (Class)(isa & mask) == class pointer
OBJC_EXPORT const uintptr_t objc_debug_isa_class_mask
OBJC_AVAILABLE(10.10, 7.0, 9.0, 1.0);
// Extract magic cookie from an isa field.
// (isa & magic_mask) == magic_value
OBJC_EXPORT const uintptr_t objc_debug_isa_magic_mask
OBJC_AVAILABLE(10.10, 7.0, 9.0, 1.0);
OBJC_EXPORT const uintptr_t objc_debug_isa_magic_value
OBJC_AVAILABLE(10.10, 7.0, 9.0, 1.0);
// Use indexed ISAs for targets which store index of the class in the ISA.
// This index can be used to index the array of classes.
OBJC_EXPORT const uintptr_t objc_debug_indexed_isa_magic_mask;
OBJC_EXPORT const uintptr_t objc_debug_indexed_isa_magic_value;
// Then these are used to extract the index from the ISA.
OBJC_EXPORT const uintptr_t objc_debug_indexed_isa_index_mask;
OBJC_EXPORT const uintptr_t objc_debug_indexed_isa_index_shift;
// And then we can use that index to get the class from this array. Note
// the size is provided so that clients can ensure the index they get is in
// bounds and not read off the end of the array.
OBJC_EXPORT Class objc_indexed_classes[];
// When we don't have enough bits to store a class*, we can instead store an
// index in to this array. Classes are added here when they are realized.
// Note, an index of 0 is illegal.
OBJC_EXPORT uintptr_t objc_indexed_classes_count;
// Absolute symbols for some of the above values are in objc-abi.h.
#endif
/***********************************************************************
* Tagged pointer decoding
**********************************************************************/
#if __OBJC2__
// Basic tagged pointers (7 classes, 60-bit payload).
// if (obj & mask) obj is a tagged pointer object
OBJC_EXPORT uintptr_t objc_debug_taggedpointer_mask
OBJC_AVAILABLE(10.9, 7.0, 9.0, 1.0);
// tag_slot = (obj >> slot_shift) & slot_mask
OBJC_EXPORT unsigned int objc_debug_taggedpointer_slot_shift
OBJC_AVAILABLE(10.9, 7.0, 9.0, 1.0);
OBJC_EXPORT uintptr_t objc_debug_taggedpointer_slot_mask
OBJC_AVAILABLE(10.9, 7.0, 9.0, 1.0);
// class = classes[tag_slot]
OBJC_EXPORT Class objc_debug_taggedpointer_classes[]
OBJC_AVAILABLE(10.9, 7.0, 9.0, 1.0);
// payload = (obj << payload_lshift) >> payload_rshift
// Payload signedness is determined by the signedness of the right-shift.
OBJC_EXPORT unsigned int objc_debug_taggedpointer_payload_lshift
OBJC_AVAILABLE(10.9, 7.0, 9.0, 1.0);
OBJC_EXPORT unsigned int objc_debug_taggedpointer_payload_rshift
OBJC_AVAILABLE(10.9, 7.0, 9.0, 1.0);
// Extended tagged pointers (255 classes, 52-bit payload).
// If you interrogate an extended tagged pointer using the basic
// tagged pointer scheme alone, it will appear to have an isa
// that is either nil or class __NSUnrecognizedTaggedPointer.
// if (ext_mask != 0 && (obj & ext_mask) == ext_mask)
// obj is a ext tagged pointer object
OBJC_EXPORT uintptr_t objc_debug_taggedpointer_ext_mask
OBJC_AVAILABLE(10.12, 10.0, 10.0, 3.0);
// ext_tag_slot = (obj >> ext_slot_shift) & ext_slot_mask
OBJC_EXPORT unsigned int objc_debug_taggedpointer_ext_slot_shift
OBJC_AVAILABLE(10.12, 10.0, 10.0, 3.0);
OBJC_EXPORT uintptr_t objc_debug_taggedpointer_ext_slot_mask
OBJC_AVAILABLE(10.12, 10.0, 10.0, 3.0);
// class = ext_classes[ext_tag_slot]
OBJC_EXPORT Class objc_debug_taggedpointer_ext_classes[]
OBJC_AVAILABLE(10.12, 10.0, 10.0, 3.0);
// payload = (obj << ext_payload_lshift) >> ext_payload_rshift
// Payload signedness is determined by the signedness of the right-shift.
OBJC_EXPORT unsigned int objc_debug_taggedpointer_ext_payload_lshift
OBJC_AVAILABLE(10.12, 10.0, 10.0, 3.0);
OBJC_EXPORT unsigned int objc_debug_taggedpointer_ext_payload_rshift
OBJC_AVAILABLE(10.12, 10.0, 10.0, 3.0);
#endif
/***********************************************************************
* Breakpoints in objc_msgSend for debugger stepping.
* The array is a {0,0} terminated list of addresses.
* Each address is one of the following:
* OBJC_MESSENGER_START: Address is the start of a messenger function.
* OBJC_MESSENGER_END_FAST: Address is a jump insn that calls an IMP.
* OBJC_MESSENGER_END_SLOW: Address is some insn in the slow lookup path.
* OBJC_MESSENGER_END_NIL: Address is a return insn for messages to nil.
*
* Every path from OBJC_MESSENGER_START should reach some OBJC_MESSENGER_END.
* At all ENDs, the stack and parameter register state is the same as START.
*
* In some cases, the END_FAST case jumps to something other than the
* method's implementation. In those cases the jump's destination will
* be another function that is marked OBJC_MESSENGER_START.
**********************************************************************/
#if __OBJC2__
#define OBJC_MESSENGER_START 1
#define OBJC_MESSENGER_END_FAST 2
#define OBJC_MESSENGER_END_SLOW 3
#define OBJC_MESSENGER_END_NIL 4
struct objc_messenger_breakpoint {
uintptr_t address;
uintptr_t kind;
};
OBJC_EXPORT struct objc_messenger_breakpoint
gdb_objc_messenger_breakpoints[]
OBJC_AVAILABLE(10.9, 7.0, 9.0, 1.0);
#endif
__END_DECLS
#endif
#endif

41
runtime/objc-initialize.h Normal file
View File

@ -0,0 +1,41 @@
/*
* Copyright (c) 2005-2006 Apple Inc. All Rights Reserved.
*
* @APPLE_LICENSE_HEADER_START@
*
* 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 2.0 (the 'License'). You may not use this file except in
* compliance with the License. Please obtain a copy of the License at
* http://www.opensource.apple.com/apsl/ 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, QUIET ENJOYMENT OR NON-INFRINGEMENT.
* Please see the License for the specific language governing rights and
* limitations under the License.
*
* @APPLE_LICENSE_HEADER_END@
*/
#ifndef _OBJC_INITIALIZE_H
#define _OBJC_INITIALIZE_H
#include "objc-private.h"
__BEGIN_DECLS
struct _objc_initializing_classes;
extern void _class_initialize(Class cls);
extern void _destroyInitializingClassList(struct _objc_initializing_classes *list);
extern bool _thisThreadIsInitializingClass(Class cls);
__END_DECLS
#endif

474
runtime/objc-initialize.mm Normal file
View File

@ -0,0 +1,474 @@
/*
* Copyright (c) 1999-2007 Apple Inc. All Rights Reserved.
*
* @APPLE_LICENSE_HEADER_START@
*
* 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 2.0 (the 'License'). You may not use this file except in
* compliance with the License. Please obtain a copy of the License at
* http://www.opensource.apple.com/apsl/ 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, QUIET ENJOYMENT OR NON-INFRINGEMENT.
* Please see the License for the specific language governing rights and
* limitations under the License.
*
* @APPLE_LICENSE_HEADER_END@
*/
/***********************************************************************
* objc-initialize.m
* +initialize support
**********************************************************************/
/***********************************************************************
* 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.
**********************************************************************/
#include "objc-private.h"
#include "message.h"
#include "objc-initialize.h"
/* classInitLock protects CLS_INITIALIZED and CLS_INITIALIZING, and
* is signalled when any class is done initializing.
* Threads that are waiting for a class to finish initializing wait on this. */
static monitor_t classInitLock;
/***********************************************************************
* 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;
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 nil when no classes are being initialized by this thread.
**********************************************************************/
static _objc_initializing_classes *_fetchInitializingClassList(bool create)
{
_objc_pthread_data *data;
_objc_initializing_classes *list;
Class *classes;
data = _objc_fetch_pthread_data(create);
if (data == nil) return nil;
list = data->initializingClasses;
if (list == nil) {
if (!create) {
return nil;
} else {
list = (_objc_initializing_classes *)
calloc(1, sizeof(_objc_initializing_classes));
data->initializingClasses = list;
}
}
classes = list->metaclasses;
if (classes == nil) {
// 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 = (Class *)
calloc(list->classesAllocated, sizeof(Class));
list->metaclasses = classes;
}
return list;
}
/***********************************************************************
* _destroyInitializingClassList
* Deallocate memory used by the given initialization list.
* Any part of the list may be nil.
* Called from _objc_pthread_destroyspecific().
**********************************************************************/
void _destroyInitializingClassList(struct _objc_initializing_classes *list)
{
if (list != nil) {
if (list->metaclasses != nil) {
free(list->metaclasses);
}
free(list);
}
}
/***********************************************************************
* _thisThreadIsInitializingClass
* Return TRUE if this thread is currently initializing the given class.
**********************************************************************/
bool _thisThreadIsInitializingClass(Class cls)
{
int i;
_objc_initializing_classes *list = _fetchInitializingClassList(NO);
if (list) {
cls = cls->getMeta();
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(Class cls)
{
int i;
_objc_initializing_classes *list = _fetchInitializingClassList(YES);
cls = cls->getMeta();
// 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 (! list->metaclasses[i]) {
list->metaclasses[i] = cls;
return;
}
}
// class list is full - reallocate
list->classesAllocated = list->classesAllocated * 2 + 1;
list->metaclasses = (Class *)
realloc(list->metaclasses,
list->classesAllocated * sizeof(Class));
// zero out the new entries
list->metaclasses[i++] = cls;
for ( ; i < list->classesAllocated; i++) {
list->metaclasses[i] = nil;
}
}
/***********************************************************************
* _setThisThreadIsNotInitializingClass
* Record that this thread is no longer initializing the given class.
**********************************************************************/
static void _setThisThreadIsNotInitializingClass(Class cls)
{
int i;
_objc_initializing_classes *list = _fetchInitializingClassList(NO);
if (list) {
cls = cls->getMeta();
for (i = 0; i < list->classesAllocated; i++) {
if (cls == list->metaclasses[i]) {
list->metaclasses[i] = nil;
return;
}
}
}
// no list or not found in list
_objc_fatal("thread is not initializing this class!");
}
typedef struct PendingInitialize {
Class subclass;
struct PendingInitialize *next;
} PendingInitialize;
static NXMapTable *pendingInitializeMap;
/***********************************************************************
* _finishInitializing
* cls has completed its +initialize method, and so has its superclass.
* Mark cls as initialized as well, then mark any of cls's subclasses
* that have already finished their own +initialize methods.
**********************************************************************/
static void _finishInitializing(Class cls, Class supercls)
{
PendingInitialize *pending;
classInitLock.assertLocked();
assert(!supercls || supercls->isInitialized());
if (PrintInitializing) {
_objc_inform("INITIALIZE: %s is fully +initialized",
cls->nameForLogging());
}
// mark this class as fully +initialized
cls->setInitialized();
classInitLock.notifyAll();
_setThisThreadIsNotInitializingClass(cls);
// mark any subclasses that were merely waiting for this class
if (!pendingInitializeMap) return;
pending = (PendingInitialize *)NXMapGet(pendingInitializeMap, cls);
if (!pending) return;
NXMapRemove(pendingInitializeMap, cls);
// Destroy the pending table if it's now empty, to save memory.
if (NXCountMapTable(pendingInitializeMap) == 0) {
NXFreeMapTable(pendingInitializeMap);
pendingInitializeMap = nil;
}
while (pending) {
PendingInitialize *next = pending->next;
if (pending->subclass) _finishInitializing(pending->subclass, cls);
free(pending);
pending = next;
}
}
/***********************************************************************
* _finishInitializingAfter
* cls has completed its +initialize method, but its superclass has not.
* Wait until supercls finishes before marking cls as initialized.
**********************************************************************/
static void _finishInitializingAfter(Class cls, Class supercls)
{
PendingInitialize *pending;
classInitLock.assertLocked();
if (PrintInitializing) {
_objc_inform("INITIALIZE: %s waiting for superclass +[%s initialize]",
cls->nameForLogging(), supercls->nameForLogging());
}
if (!pendingInitializeMap) {
pendingInitializeMap =
NXCreateMapTable(NXPtrValueMapPrototype, 10);
// fixme pre-size this table for CF/NSObject +initialize
}
pending = (PendingInitialize *)malloc(sizeof(*pending));
pending->subclass = cls;
pending->next = (PendingInitialize *)
NXMapGet(pendingInitializeMap, supercls);
NXMapInsert(pendingInitializeMap, supercls, pending);
}
// Provide helpful messages in stack traces.
OBJC_EXTERN __attribute__((noinline, used, visibility("hidden")))
void waitForInitializeToComplete(Class cls)
asm("_WAITING_FOR_ANOTHER_THREAD_TO_FINISH_CALLING_+initialize");
OBJC_EXTERN __attribute__((noinline, used, visibility("hidden")))
void callInitialize(Class cls)
asm("_CALLING_SOME_+initialize_METHOD");
void waitForInitializeToComplete(Class cls)
{
monitor_locker_t lock(classInitLock);
while (!cls->isInitialized()) {
classInitLock.wait();
}
asm("");
}
void callInitialize(Class cls)
{
((void(*)(Class, SEL))objc_msgSend)(cls, SEL_initialize);
asm("");
}
/***********************************************************************
* class_initialize. Send the '+initialize' message on demand to any
* uninitialized class. Force initialization of superclasses first.
**********************************************************************/
void _class_initialize(Class cls)
{
assert(!cls->isMetaClass());
Class supercls;
bool reallyInitialize = NO;
// Make sure super is done initializing BEFORE beginning to initialize cls.
// See note about deadlock above.
supercls = cls->superclass;
if (supercls && !supercls->isInitialized()) {
_class_initialize(supercls);
}
// Try to atomically set CLS_INITIALIZING.
{
monitor_locker_t lock(classInitLock);
if (!cls->isInitialized() && !cls->isInitializing()) {
cls->setInitializing();
reallyInitialize = YES;
}
}
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);
// Send the +initialize message.
// Note that +initialize is sent to the superclass (again) if
// this class doesn't implement +initialize. 2157218
if (PrintInitializing) {
_objc_inform("INITIALIZE: calling +[%s initialize]",
cls->nameForLogging());
}
// Exceptions: A +initialize call that throws an exception
// is deemed to be a complete and successful +initialize.
@try {
callInitialize(cls);
if (PrintInitializing) {
_objc_inform("INITIALIZE: finished +[%s initialize]",
cls->nameForLogging());
}
}
@catch (...) {
if (PrintInitializing) {
_objc_inform("INITIALIZE: +[%s initialize] threw an exception",
cls->nameForLogging());
}
@throw;
}
@finally {
// Done initializing.
// If the superclass is also done initializing, then update
// the info bits and notify waiting threads.
// If not, update them later. (This can happen if this +initialize
// was itself triggered from inside a superclass +initialize.)
monitor_locker_t lock(classInitLock);
if (!supercls || supercls->isInitialized()) {
_finishInitializing(cls, supercls);
} else {
_finishInitializingAfter(cls, supercls);
}
}
return;
}
else if (cls->isInitializing()) {
// 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 {
waitForInitializeToComplete(cls);
return;
}
}
else if (cls->isInitialized()) {
// 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!");
}
}

735
runtime/objc-internal.h Normal file
View File

@ -0,0 +1,735 @@
/*
* Copyright (c) 2009 Apple Inc. All Rights Reserved.
*
* @APPLE_LICENSE_HEADER_START@
*
* 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 2.0 (the 'License'). You may not use this file except in
* compliance with the License. Please obtain a copy of the License at
* http://www.opensource.apple.com/apsl/ 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, QUIET ENJOYMENT OR NON-INFRINGEMENT.
* Please see the License for the specific language governing rights and
* limitations under the License.
*
* @APPLE_LICENSE_HEADER_END@
*/
#ifndef _OBJC_INTERNAL_H
#define _OBJC_INTERNAL_H
/*
* WARNING DANGER HAZARD BEWARE EEK
*
* Everything in this file is for Apple Internal use only.
* These will change in arbitrary OS updates and in unpredictable ways.
* When your program breaks, you get to keep both pieces.
*/
/*
* objc-internal.h: Private SPI for use by other system frameworks.
*/
#include <objc/objc.h>
#include <objc/runtime.h>
#include <Availability.h>
#include <malloc/malloc.h>
#include <dispatch/dispatch.h>
__BEGIN_DECLS
// Termination reasons in the OS_REASON_OBJC namespace.
#define OBJC_EXIT_REASON_UNSPECIFIED 1
#define OBJC_EXIT_REASON_GC_NOT_SUPPORTED 2
// This is the allocation size required for each of the class and the metaclass
// with objc_initializeClassPair() and objc_readClassPair().
// The runtime's class structure will never grow beyond this.
#define OBJC_MAX_CLASS_SIZE (32*sizeof(void*))
// In-place construction of an Objective-C class.
// cls and metacls must each be OBJC_MAX_CLASS_SIZE bytes.
// Returns nil if a class with the same name already exists.
// Returns nil if the superclass is under construction.
// Call objc_registerClassPair() when you are done.
OBJC_EXPORT Class objc_initializeClassPair(Class superclass, const char *name, Class cls, Class metacls)
OBJC_AVAILABLE(10.6, 3.0, 9.0, 1.0);
// Class and metaclass construction from a compiler-generated memory image.
// cls and cls->isa must each be OBJC_MAX_CLASS_SIZE bytes.
// Extra bytes not used the the metadata must be zero.
// info is the same objc_image_info that would be emitted by a static compiler.
// Returns nil if a class with the same name already exists.
// Returns nil if the superclass is nil and the class is not marked as a root.
// Returns nil if the superclass is under construction.
// Do not call objc_registerClassPair().
#if __OBJC2__
struct objc_image_info;
OBJC_EXPORT Class objc_readClassPair(Class cls,
const struct objc_image_info *info)
OBJC_AVAILABLE(10.10, 8.0, 9.0, 1.0);
#endif
// Batch object allocation using malloc_zone_batch_malloc().
OBJC_EXPORT unsigned class_createInstances(Class cls, size_t extraBytes,
id *results, unsigned num_requested)
OBJC_AVAILABLE(10.7, 4.3, 9.0, 1.0)
OBJC_ARC_UNAVAILABLE;
// Get the isa pointer written into objects just before being freed.
OBJC_EXPORT Class _objc_getFreedObjectClass(void)
OBJC_AVAILABLE(10.0, 2.0, 9.0, 1.0);
// env NSObjCMessageLoggingEnabled
OBJC_EXPORT void instrumentObjcMessageSends(BOOL flag)
OBJC_AVAILABLE(10.0, 2.0, 9.0, 1.0);
// Initializer called by libSystem
OBJC_EXPORT void _objc_init(void)
#if __OBJC2__
OBJC_AVAILABLE(10.8, 6.0, 9.0, 1.0);
#else
OBJC_AVAILABLE(10.12, 10.0, 10.0, 3.0);
#endif
// Return YES if GC is on and `object` is a GC allocation.
OBJC_EXPORT BOOL objc_isAuto(id object)
__OSX_DEPRECATED(10.4, 10.8, "it always returns NO")
__IOS_UNAVAILABLE __TVOS_UNAVAILABLE __WATCHOS_UNAVAILABLE;
// GC startup callback from Foundation
OBJC_EXPORT malloc_zone_t *objc_collect_init(int (*callback)(void))
__OSX_DEPRECATED(10.4, 10.8, "it does nothing")
__IOS_UNAVAILABLE __TVOS_UNAVAILABLE __WATCHOS_UNAVAILABLE;
// Plainly-implemented GC barriers. Rosetta used to use these.
OBJC_EXPORT id objc_assign_strongCast_generic(id value, id *dest)
UNAVAILABLE_ATTRIBUTE;
OBJC_EXPORT id objc_assign_global_generic(id value, id *dest)
UNAVAILABLE_ATTRIBUTE;
OBJC_EXPORT id objc_assign_threadlocal_generic(id value, id *dest)
UNAVAILABLE_ATTRIBUTE;
OBJC_EXPORT id objc_assign_ivar_generic(id value, id dest, ptrdiff_t offset)
UNAVAILABLE_ATTRIBUTE;
// GC preflight for an app executable.
// 1: some slice requires GC
// 0: no slice requires GC
// -1: I/O or file format error
OBJC_EXPORT int objc_appRequiresGC(int fd)
__OSX_AVAILABLE(10.11)
__IOS_UNAVAILABLE __TVOS_UNAVAILABLE __WATCHOS_UNAVAILABLE;
// Install missing-class callback. Used by the late unlamented ZeroLink.
OBJC_EXPORT void _objc_setClassLoader(BOOL (*newClassLoader)(const char *)) OBJC2_UNAVAILABLE;
// Install handler for allocation failures.
// Handler may abort, or throw, or provide an object to return.
OBJC_EXPORT void _objc_setBadAllocHandler(id (*newHandler)(Class isa))
OBJC_AVAILABLE(10.8, 6.0, 9.0, 1.0);
// This can go away when AppKit stops calling it (rdar://7811851)
#if __OBJC2__
OBJC_EXPORT void objc_setMultithreaded (BOOL flag)
__OSX_DEPRECATED(10.0, 10.5, "multithreading is always available")
__IOS_UNAVAILABLE __TVOS_UNAVAILABLE __WATCHOS_UNAVAILABLE;
#endif
// Used by ExceptionHandling.framework
#if !__OBJC2__
OBJC_EXPORT void _objc_error(id rcv, const char *fmt, va_list args)
__attribute__((noreturn))
__OSX_DEPRECATED(10.0, 10.5, "use other logging facilities instead")
__IOS_UNAVAILABLE __TVOS_UNAVAILABLE __WATCHOS_UNAVAILABLE;
#endif
// Tagged pointer objects.
#if __LP64__
#define OBJC_HAVE_TAGGED_POINTERS 1
#endif
#if OBJC_HAVE_TAGGED_POINTERS
// Tagged pointer layout and usage is subject to change on different OS versions.
// Tag indexes 0..<7 have a 60-bit payload.
// Tag index 7 is reserved.
// Tag indexes 8..<264 have a 52-bit payload.
// Tag index 264 is reserved.
#if __has_feature(objc_fixed_enum) || __cplusplus >= 201103L
enum objc_tag_index_t : uint16_t
#else
typedef uint16_t objc_tag_index_t;
enum
#endif
{
OBJC_TAG_NSAtom = 0,
OBJC_TAG_1 = 1,
OBJC_TAG_NSString = 2,
OBJC_TAG_NSNumber = 3,
OBJC_TAG_NSIndexPath = 4,
OBJC_TAG_NSManagedObjectID = 5,
OBJC_TAG_NSDate = 6,
OBJC_TAG_RESERVED_7 = 7,
OBJC_TAG_First60BitPayload = 0,
OBJC_TAG_Last60BitPayload = 6,
OBJC_TAG_First52BitPayload = 8,
OBJC_TAG_Last52BitPayload = 263,
OBJC_TAG_RESERVED_264 = 264
};
#if __has_feature(objc_fixed_enum) && !defined(__cplusplus)
typedef enum objc_tag_index_t objc_tag_index_t;
#endif
// Returns true if tagged pointers are enabled.
// The other functions below must not be called if tagged pointers are disabled.
static inline bool
_objc_taggedPointersEnabled(void);
// Register a class for a tagged pointer tag.
// Aborts if the tag is invalid or already in use.
OBJC_EXPORT void _objc_registerTaggedPointerClass(objc_tag_index_t tag, Class cls)
OBJC_AVAILABLE(10.9, 7.0, 9.0, 1.0);
// Returns the registered class for the given tag.
// Returns nil if the tag is valid but has no registered class.
// Aborts if the tag is invalid.
OBJC_EXPORT Class _objc_getClassForTag(objc_tag_index_t tag)
OBJC_AVAILABLE(10.9, 7.0, 9.0, 1.0);
// Create a tagged pointer object with the given tag and payload.
// Assumes the tag is valid.
// Assumes tagged pointers are enabled.
// The payload will be silently truncated to fit.
static inline void *
_objc_makeTaggedPointer(objc_tag_index_t tag, uintptr_t payload);
// Return true if ptr is a tagged pointer object.
// Does not check the validity of ptr's class.
static inline bool
_objc_isTaggedPointer(const void *ptr);
// Extract the tag value from the given tagged pointer object.
// Assumes ptr is a valid tagged pointer object.
// Does not check the validity of ptr's tag.
static inline objc_tag_index_t
_objc_getTaggedPointerTag(const void *ptr);
// Extract the payload from the given tagged pointer object.
// Assumes ptr is a valid tagged pointer object.
// The payload value is zero-extended.
static inline uintptr_t
_objc_getTaggedPointerValue(const void *ptr);
// Extract the payload from the given tagged pointer object.
// Assumes ptr is a valid tagged pointer object.
// The payload value is sign-extended.
static inline intptr_t
_objc_getTaggedPointerSignedValue(const void *ptr);
// Don't use the values below. Use the declarations above.
#if TARGET_OS_OSX && __x86_64__
// 64-bit Mac - tag bit is LSB
# define OBJC_MSB_TAGGED_POINTERS 0
#else
// Everything else - tag bit is MSB
# define OBJC_MSB_TAGGED_POINTERS 1
#endif
#define _OBJC_TAG_INDEX_MASK 0x7
// array slot includes the tag bit itself
#define _OBJC_TAG_SLOT_COUNT 16
#define _OBJC_TAG_SLOT_MASK 0xf
#define _OBJC_TAG_EXT_INDEX_MASK 0xff
// array slot has no extra bits
#define _OBJC_TAG_EXT_SLOT_COUNT 256
#define _OBJC_TAG_EXT_SLOT_MASK 0xff
#if OBJC_MSB_TAGGED_POINTERS
# define _OBJC_TAG_MASK (1ULL<<63)
# define _OBJC_TAG_INDEX_SHIFT 60
# define _OBJC_TAG_SLOT_SHIFT 60
# define _OBJC_TAG_PAYLOAD_LSHIFT 4
# define _OBJC_TAG_PAYLOAD_RSHIFT 4
# define _OBJC_TAG_EXT_MASK (0xfULL<<60)
# define _OBJC_TAG_EXT_INDEX_SHIFT 52
# define _OBJC_TAG_EXT_SLOT_SHIFT 52
# define _OBJC_TAG_EXT_PAYLOAD_LSHIFT 12
# define _OBJC_TAG_EXT_PAYLOAD_RSHIFT 12
#else
# define _OBJC_TAG_MASK 1
# define _OBJC_TAG_INDEX_SHIFT 1
# define _OBJC_TAG_SLOT_SHIFT 0
# define _OBJC_TAG_PAYLOAD_LSHIFT 0
# define _OBJC_TAG_PAYLOAD_RSHIFT 4
# define _OBJC_TAG_EXT_MASK 0xfULL
# define _OBJC_TAG_EXT_INDEX_SHIFT 4
# define _OBJC_TAG_EXT_SLOT_SHIFT 4
# define _OBJC_TAG_EXT_PAYLOAD_LSHIFT 0
# define _OBJC_TAG_EXT_PAYLOAD_RSHIFT 12
#endif
static inline bool
_objc_taggedPointersEnabled(void)
{
extern uintptr_t objc_debug_taggedpointer_mask;
return (objc_debug_taggedpointer_mask != 0);
}
static inline void *
_objc_makeTaggedPointer(objc_tag_index_t tag, uintptr_t value)
{
// PAYLOAD_LSHIFT and PAYLOAD_RSHIFT are the payload extraction shifts.
// They are reversed here for payload insertion.
// assert(_objc_taggedPointersEnabled());
if (tag <= OBJC_TAG_Last60BitPayload) {
// assert(((value << _OBJC_TAG_PAYLOAD_RSHIFT) >> _OBJC_TAG_PAYLOAD_LSHIFT) == value);
return (void*)
(_OBJC_TAG_MASK |
((uintptr_t)tag << _OBJC_TAG_INDEX_SHIFT) |
((value << _OBJC_TAG_PAYLOAD_RSHIFT) >> _OBJC_TAG_PAYLOAD_LSHIFT));
} else {
// assert(tag >= OBJC_TAG_First52BitPayload);
// assert(tag <= OBJC_TAG_Last52BitPayload);
// assert(((value << _OBJC_TAG_EXT_PAYLOAD_RSHIFT) >> _OBJC_TAG_EXT_PAYLOAD_LSHIFT) == value);
return (void*)
(_OBJC_TAG_EXT_MASK |
((uintptr_t)(tag - OBJC_TAG_First52BitPayload) << _OBJC_TAG_EXT_INDEX_SHIFT) |
((value << _OBJC_TAG_EXT_PAYLOAD_RSHIFT) >> _OBJC_TAG_EXT_PAYLOAD_LSHIFT));
}
}
static inline bool
_objc_isTaggedPointer(const void *ptr)
{
return ((intptr_t)ptr & _OBJC_TAG_MASK) == _OBJC_TAG_MASK;
}
static inline objc_tag_index_t
_objc_getTaggedPointerTag(const void *ptr)
{
// assert(_objc_isTaggedPointer(ptr));
uintptr_t basicTag = ((uintptr_t)ptr >> _OBJC_TAG_INDEX_SHIFT) & _OBJC_TAG_INDEX_MASK;
uintptr_t extTag = ((uintptr_t)ptr >> _OBJC_TAG_EXT_INDEX_SHIFT) & _OBJC_TAG_EXT_INDEX_MASK;
if (basicTag == _OBJC_TAG_INDEX_MASK) {
return (objc_tag_index_t)(extTag + OBJC_TAG_First52BitPayload);
} else {
return (objc_tag_index_t)basicTag;
}
}
static inline uintptr_t
_objc_getTaggedPointerValue(const void *ptr)
{
// assert(_objc_isTaggedPointer(ptr));
uintptr_t basicTag = ((uintptr_t)ptr >> _OBJC_TAG_INDEX_SHIFT) & _OBJC_TAG_INDEX_MASK;
if (basicTag == _OBJC_TAG_INDEX_MASK) {
return ((uintptr_t)ptr << _OBJC_TAG_EXT_PAYLOAD_LSHIFT) >> _OBJC_TAG_EXT_PAYLOAD_RSHIFT;
} else {
return ((uintptr_t)ptr << _OBJC_TAG_PAYLOAD_LSHIFT) >> _OBJC_TAG_PAYLOAD_RSHIFT;
}
}
static inline intptr_t
_objc_getTaggedPointerSignedValue(const void *ptr)
{
// assert(_objc_isTaggedPointer(ptr));
uintptr_t basicTag = ((uintptr_t)ptr >> _OBJC_TAG_INDEX_SHIFT) & _OBJC_TAG_INDEX_MASK;
if (basicTag == _OBJC_TAG_INDEX_MASK) {
return ((intptr_t)ptr << _OBJC_TAG_EXT_PAYLOAD_LSHIFT) >> _OBJC_TAG_EXT_PAYLOAD_RSHIFT;
} else {
return ((intptr_t)ptr << _OBJC_TAG_PAYLOAD_LSHIFT) >> _OBJC_TAG_PAYLOAD_RSHIFT;
}
}
// OBJC_HAVE_TAGGED_POINTERS
#endif
/**
* Returns the method implementation of an object.
*
* @param obj An Objective-C object.
* @param name An Objective-C selector.
*
* @return The IMP corresponding to the instance method implemented by
* the class of \e obj.
*
* @note Equivalent to:
*
* class_getMethodImplementation(object_getClass(obj), name);
*/
OBJC_EXPORT IMP object_getMethodImplementation(id obj, SEL name)
OBJC_AVAILABLE(10.9, 7.0, 9.0, 1.0);
OBJC_EXPORT IMP object_getMethodImplementation_stret(id obj, SEL name)
OBJC_AVAILABLE(10.9, 7.0, 9.0, 1.0)
OBJC_ARM64_UNAVAILABLE;
// Instance-specific instance variable layout.
OBJC_EXPORT void _class_setIvarLayoutAccessor(Class cls_gen, const uint8_t* (*accessor) (id object))
__OSX_AVAILABLE(10.7)
__IOS_UNAVAILABLE __TVOS_UNAVAILABLE __WATCHOS_UNAVAILABLE;
OBJC_EXPORT const uint8_t *_object_getIvarLayout(Class cls_gen, id object)
__OSX_AVAILABLE(10.7)
__IOS_UNAVAILABLE __TVOS_UNAVAILABLE __WATCHOS_UNAVAILABLE;
/*
"Unknown" includes non-object ivars and non-ARC non-__weak ivars
"Strong" includes ARC __strong ivars
"Weak" includes ARC and new MRC __weak ivars
"Unretained" includes ARC __unsafe_unretained and old GC+MRC __weak ivars
*/
typedef enum {
objc_ivar_memoryUnknown, // unknown / unknown
objc_ivar_memoryStrong, // direct access / objc_storeStrong
objc_ivar_memoryWeak, // objc_loadWeak[Retained] / objc_storeWeak
objc_ivar_memoryUnretained // direct access / direct access
} objc_ivar_memory_management_t;
OBJC_EXPORT objc_ivar_memory_management_t _class_getIvarMemoryManagement(Class cls, Ivar ivar)
OBJC_AVAILABLE(10.12, 10.0, 10.0, 3.0);
OBJC_EXPORT BOOL _class_isFutureClass(Class cls)
OBJC_AVAILABLE(10.9, 7.0, 9.0, 1.0);
// API to only be called by root classes like NSObject or NSProxy
OBJC_EXPORT
id
_objc_rootRetain(id obj)
OBJC_AVAILABLE(10.7, 5.0, 9.0, 1.0);
OBJC_EXPORT
void
_objc_rootRelease(id obj)
OBJC_AVAILABLE(10.7, 5.0, 9.0, 1.0);
OBJC_EXPORT
bool
_objc_rootReleaseWasZero(id obj)
OBJC_AVAILABLE(10.7, 5.0, 9.0, 1.0);
OBJC_EXPORT
bool
_objc_rootTryRetain(id obj)
OBJC_AVAILABLE(10.7, 5.0, 9.0, 1.0);
OBJC_EXPORT
bool
_objc_rootIsDeallocating(id obj)
OBJC_AVAILABLE(10.7, 5.0, 9.0, 1.0);
OBJC_EXPORT
id
_objc_rootAutorelease(id obj)
OBJC_AVAILABLE(10.7, 5.0, 9.0, 1.0);
OBJC_EXPORT
uintptr_t
_objc_rootRetainCount(id obj)
OBJC_AVAILABLE(10.7, 5.0, 9.0, 1.0);
OBJC_EXPORT
id
_objc_rootInit(id obj)
OBJC_AVAILABLE(10.7, 5.0, 9.0, 1.0);
OBJC_EXPORT
id
_objc_rootAllocWithZone(Class cls, malloc_zone_t *zone)
OBJC_AVAILABLE(10.7, 5.0, 9.0, 1.0);
OBJC_EXPORT
id
_objc_rootAlloc(Class cls)
OBJC_AVAILABLE(10.7, 5.0, 9.0, 1.0);
OBJC_EXPORT
void
_objc_rootDealloc(id obj)
OBJC_AVAILABLE(10.7, 5.0, 9.0, 1.0);
OBJC_EXPORT
void
_objc_rootFinalize(id obj)
OBJC_AVAILABLE(10.7, 5.0, 9.0, 1.0);
OBJC_EXPORT
malloc_zone_t *
_objc_rootZone(id obj)
OBJC_AVAILABLE(10.7, 5.0, 9.0, 1.0);
OBJC_EXPORT
uintptr_t
_objc_rootHash(id obj)
OBJC_AVAILABLE(10.7, 5.0, 9.0, 1.0);
OBJC_EXPORT
void *
objc_autoreleasePoolPush(void)
OBJC_AVAILABLE(10.7, 5.0, 9.0, 1.0);
OBJC_EXPORT
void
objc_autoreleasePoolPop(void *context)
OBJC_AVAILABLE(10.7, 5.0, 9.0, 1.0);
OBJC_EXPORT id objc_alloc(Class cls)
OBJC_AVAILABLE(10.9, 7.0, 9.0, 1.0);
OBJC_EXPORT id objc_allocWithZone(Class cls)
OBJC_AVAILABLE(10.9, 7.0, 9.0, 1.0);
OBJC_EXPORT id objc_retain(id obj)
__asm__("_objc_retain")
OBJC_AVAILABLE(10.7, 5.0, 9.0, 1.0);
OBJC_EXPORT void objc_release(id obj)
__asm__("_objc_release")
OBJC_AVAILABLE(10.7, 5.0, 9.0, 1.0);
OBJC_EXPORT id objc_autorelease(id obj)
__asm__("_objc_autorelease")
OBJC_AVAILABLE(10.7, 5.0, 9.0, 1.0);
// Prepare a value at +1 for return through a +0 autoreleasing convention.
OBJC_EXPORT
id
objc_autoreleaseReturnValue(id obj)
OBJC_AVAILABLE(10.7, 5.0, 9.0, 1.0);
// Prepare a value at +0 for return through a +0 autoreleasing convention.
OBJC_EXPORT
id
objc_retainAutoreleaseReturnValue(id obj)
OBJC_AVAILABLE(10.7, 5.0, 9.0, 1.0);
// Accept a value returned through a +0 autoreleasing convention for use at +1.
OBJC_EXPORT
id
objc_retainAutoreleasedReturnValue(id obj)
OBJC_AVAILABLE(10.7, 5.0, 9.0, 1.0);
// Accept a value returned through a +0 autoreleasing convention for use at +0.
OBJC_EXPORT
id
objc_unsafeClaimAutoreleasedReturnValue(id obj)
OBJC_AVAILABLE(10.11, 9.0, 9.0, 1.0);
OBJC_EXPORT
void
objc_storeStrong(id *location, id obj)
OBJC_AVAILABLE(10.7, 5.0, 9.0, 1.0);
OBJC_EXPORT
id
objc_retainAutorelease(id obj)
OBJC_AVAILABLE(10.7, 5.0, 9.0, 1.0);
// obsolete.
OBJC_EXPORT id objc_retain_autorelease(id obj)
OBJC_AVAILABLE(10.7, 5.0, 9.0, 1.0);
OBJC_EXPORT
id
objc_loadWeakRetained(id *location)
OBJC_AVAILABLE(10.7, 5.0, 9.0, 1.0);
OBJC_EXPORT
id
objc_initWeak(id *location, id val)
OBJC_AVAILABLE(10.7, 5.0, 9.0, 1.0);
// Like objc_storeWeak, but stores nil if the new object is deallocating
// or the new object's class does not support weak references.
// Returns the value stored (either the new object or nil).
OBJC_EXPORT
id
objc_storeWeakOrNil(id *location, id obj)
OBJC_AVAILABLE(10.11, 9.0, 9.0, 1.0);
// Like objc_initWeak, but stores nil if the new object is deallocating
// or the new object's class does not support weak references.
// Returns the value stored (either the new object or nil).
OBJC_EXPORT
id
objc_initWeakOrNil(id *location, id val)
OBJC_AVAILABLE(10.11, 9.0, 9.0, 1.0);
OBJC_EXPORT
void
objc_destroyWeak(id *location)
OBJC_AVAILABLE(10.7, 5.0, 9.0, 1.0);
OBJC_EXPORT
void
objc_copyWeak(id *to, id *from)
OBJC_AVAILABLE(10.7, 5.0, 9.0, 1.0);
OBJC_EXPORT
void
objc_moveWeak(id *to, id *from)
OBJC_AVAILABLE(10.7, 5.0, 9.0, 1.0);
OBJC_EXPORT
void
_objc_autoreleasePoolPrint(void)
OBJC_AVAILABLE(10.7, 5.0, 9.0, 1.0);
OBJC_EXPORT BOOL objc_should_deallocate(id object)
OBJC_AVAILABLE(10.7, 5.0, 9.0, 1.0);
OBJC_EXPORT void objc_clear_deallocating(id object)
OBJC_AVAILABLE(10.7, 5.0, 9.0, 1.0);
// to make CF link for now
OBJC_EXPORT
void *
_objc_autoreleasePoolPush(void)
OBJC_AVAILABLE(10.7, 5.0, 9.0, 1.0);
OBJC_EXPORT
void
_objc_autoreleasePoolPop(void *context)
OBJC_AVAILABLE(10.7, 5.0, 9.0, 1.0);
// Extra @encode data for XPC, or NULL
OBJC_EXPORT const char *_protocol_getMethodTypeEncoding(Protocol *p, SEL sel, BOOL isRequiredMethod, BOOL isInstanceMethod)
OBJC_AVAILABLE(10.8, 6.0, 9.0, 1.0);
// API to only be called by classes that provide their own reference count storage
OBJC_EXPORT
void
_objc_deallocOnMainThreadHelper(void *context)
OBJC_AVAILABLE(10.7, 5.0, 9.0, 1.0);
// On async versus sync deallocation and the _dealloc2main flag
//
// Theory:
//
// If order matters, then code must always: [self dealloc].
// If order doesn't matter, then always async should be safe.
//
// Practice:
//
// The _dealloc2main bit is set for GUI objects that may be retained by other
// threads. Once deallocation begins on the main thread, doing more async
// deallocation will at best cause extra UI latency and at worst cause
// use-after-free bugs in unretained delegate style patterns. Yes, this is
// extremely fragile. Yes, in the long run, developers should switch to weak
// references.
//
// Note is NOT safe to do any equality check against the result of
// dispatch_get_current_queue(). The main thread can and does drain more than
// one dispatch queue. That is why we call pthread_main_np().
//
typedef enum {
_OBJC_RESURRECT_OBJECT = -1, /* _logicBlock has called -retain, and scheduled a -release for later. */
_OBJC_DEALLOC_OBJECT_NOW = 1, /* call [self dealloc] immediately. */
_OBJC_DEALLOC_OBJECT_LATER = 2 /* call [self dealloc] on the main queue. */
} _objc_object_disposition_t;
#define _OBJC_SUPPORTED_INLINE_REFCNT_LOGIC_BLOCK(_rc_ivar, _logicBlock) \
-(id)retain { \
/* this will fail to compile if _rc_ivar is an unsigned type */ \
int _retain_count_ivar_must_not_be_unsigned[0L - (__typeof__(_rc_ivar))-1] __attribute__((unused)); \
__typeof__(_rc_ivar) _prev = __sync_fetch_and_add(&_rc_ivar, 2); \
if (_prev < -2) { /* specifically allow resurrection from logical 0. */ \
__builtin_trap(); /* BUG: retain of over-released ref */ \
} \
return self; \
} \
-(oneway void)release { \
__typeof__(_rc_ivar) _prev = __sync_fetch_and_sub(&_rc_ivar, 2); \
if (_prev > 0) { \
return; \
} else if (_prev < 0) { \
__builtin_trap(); /* BUG: over-release */ \
} \
_objc_object_disposition_t fate = _logicBlock(self); \
if (fate == _OBJC_RESURRECT_OBJECT) { \
return; \
} \
/* mark the object as deallocating. */ \
if (!__sync_bool_compare_and_swap(&_rc_ivar, -2, 1)) { \
__builtin_trap(); /* BUG: dangling ref did a retain */ \
} \
if (fate == _OBJC_DEALLOC_OBJECT_NOW) { \
[self dealloc]; \
} else if (fate == _OBJC_DEALLOC_OBJECT_LATER) { \
dispatch_barrier_async_f(dispatch_get_main_queue(), self, \
_objc_deallocOnMainThreadHelper); \
} else { \
__builtin_trap(); /* BUG: bogus fate value */ \
} \
} \
-(NSUInteger)retainCount { \
return (_rc_ivar + 2) >> 1; \
} \
-(BOOL)_tryRetain { \
__typeof__(_rc_ivar) _prev; \
do { \
_prev = _rc_ivar; \
if (_prev & 1) { \
return 0; \
} else if (_prev == -2) { \
return 0; \
} else if (_prev < -2) { \
__builtin_trap(); /* BUG: over-release elsewhere */ \
} \
} while ( ! __sync_bool_compare_and_swap(&_rc_ivar, _prev, _prev + 2)); \
return 1; \
} \
-(BOOL)_isDeallocating { \
if (_rc_ivar == -2) { \
return 1; \
} else if (_rc_ivar < -2) { \
__builtin_trap(); /* BUG: over-release elsewhere */ \
} \
return _rc_ivar & 1; \
}
#define _OBJC_SUPPORTED_INLINE_REFCNT_LOGIC(_rc_ivar, _dealloc2main) \
_OBJC_SUPPORTED_INLINE_REFCNT_LOGIC_BLOCK(_rc_ivar, (^(id _self_ __attribute__((unused))) { \
if (_dealloc2main && !pthread_main_np()) { \
return _OBJC_DEALLOC_OBJECT_LATER; \
} else { \
return _OBJC_DEALLOC_OBJECT_NOW; \
} \
}))
#define _OBJC_SUPPORTED_INLINE_REFCNT(_rc_ivar) _OBJC_SUPPORTED_INLINE_REFCNT_LOGIC(_rc_ivar, 0)
#define _OBJC_SUPPORTED_INLINE_REFCNT_WITH_DEALLOC2MAIN(_rc_ivar) _OBJC_SUPPORTED_INLINE_REFCNT_LOGIC(_rc_ivar, 1)
__END_DECLS
#endif

928
runtime/objc-layout.mm Normal file
View File

@ -0,0 +1,928 @@
/*
* Copyright (c) 2004-2008 Apple Inc. All rights reserved.
*
* @APPLE_LICENSE_HEADER_START@
*
* 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 2.0 (the 'License'). You may not use this file except in
* compliance with the License. Please obtain a copy of the License at
* http://www.opensource.apple.com/apsl/ 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, QUIET ENJOYMENT OR NON-INFRINGEMENT.
* Please see the License for the specific language governing rights and
* limitations under the License.
*
* @APPLE_LICENSE_HEADER_END@
*/
#include <stdlib.h>
#include <assert.h>
#include "objc-private.h"
/**********************************************************************
* Object Layouts.
*
* Layouts are used by the garbage collector to identify references from
* the object to other objects.
*
* Layout information is in the form of a '\0' terminated byte string.
* Each byte contains a word skip count in the high nibble and a
* consecutive references count in the low nibble. Counts that exceed 15 are
* continued in the succeeding byte with a zero in the opposite nibble.
* Objects that should be scanned conservatively will have a NULL layout.
* Objects that have no references have a empty byte string.
*
* Example;
*
* For a class with pointers at offsets 4,12, 16, 32-128
* the layout is { 0x11, 0x12, 0x3f, 0x0a, 0x00 } or
* skip 1 - 1 reference (4)
* skip 1 - 2 references (12, 16)
* skip 3 - 15 references (32-88)
* no skip - 10 references (92-128)
* end
*
**********************************************************************/
/**********************************************************************
* compress_layout
* Allocates and returns a compressed string matching the given layout bitmap.
**********************************************************************/
static unsigned char *
compress_layout(const uint8_t *bits, size_t bitmap_bits, bool weak)
{
bool all_set = YES;
bool none_set = YES;
unsigned char *result;
// overallocate a lot; reallocate at correct size later
unsigned char * const layout = (unsigned char *)
calloc(bitmap_bits + 1, 1);
unsigned char *l = layout;
size_t i = 0;
while (i < bitmap_bits) {
size_t skip = 0;
size_t scan = 0;
// Count one range each of skip and scan.
while (i < bitmap_bits) {
uint8_t bit = (uint8_t)((bits[i/8] >> (i % 8)) & 1);
if (bit) break;
i++;
skip++;
}
while (i < bitmap_bits) {
uint8_t bit = (uint8_t)((bits[i/8] >> (i % 8)) & 1);
if (!bit) break;
i++;
scan++;
none_set = NO;
}
// Record skip and scan
if (skip) all_set = NO;
if (scan) none_set = NO;
while (skip > 0xf) {
*l++ = 0xf0;
skip -= 0xf;
}
if (skip || scan) {
*l = (uint8_t)(skip << 4); // NOT incremented - merges with scan
while (scan > 0xf) {
*l++ |= 0x0f; // May merge with short skip; must calloc
scan -= 0xf;
}
*l++ |= scan; // NOT checked for zero - always increments
// May merge with short skip; must calloc
}
}
// insert terminating byte
*l++ = '\0';
// return result
if (none_set && weak) {
result = NULL; // NULL weak layout means none-weak
} else if (all_set && !weak) {
result = NULL; // NULL ivar layout means all-scanned
} else {
result = (unsigned char *)strdup((char *)layout);
}
free(layout);
return result;
}
static void set_bits(layout_bitmap bits, size_t which, size_t count)
{
// fixme optimize for byte/word at a time
size_t bit;
for (bit = which; bit < which + count && bit < bits.bitCount; bit++) {
bits.bits[bit/8] |= 1 << (bit % 8);
}
if (bit == bits.bitCount && bit < which + count) {
// couldn't fit full type in bitmap
_objc_fatal("layout bitmap too short");
}
}
static void clear_bits(layout_bitmap bits, size_t which, size_t count)
{
// fixme optimize for byte/word at a time
size_t bit;
for (bit = which; bit < which + count && bit < bits.bitCount; bit++) {
bits.bits[bit/8] &= ~(1 << (bit % 8));
}
if (bit == bits.bitCount && bit < which + count) {
// couldn't fit full type in bitmap
_objc_fatal("layout bitmap too short");
}
}
static void move_bits(layout_bitmap bits, size_t src, size_t dst,
size_t count)
{
// fixme optimize for byte/word at a time
if (dst == src) {
return;
}
else if (dst > src) {
// Copy backwards in case of overlap
size_t pos = count;
while (pos--) {
size_t srcbit = src + pos;
size_t dstbit = dst + pos;
if (bits.bits[srcbit/8] & (1 << (srcbit % 8))) {
bits.bits[dstbit/8] |= 1 << (dstbit % 8);
} else {
bits.bits[dstbit/8] &= ~(1 << (dstbit % 8));
}
}
}
else {
// Copy forwards in case of overlap
size_t pos;
for (pos = 0; pos < count; pos++) {
size_t srcbit = src + pos;
size_t dstbit = dst + pos;
if (bits.bits[srcbit/8] & (1 << (srcbit % 8))) {
bits.bits[dstbit/8] |= 1 << (dstbit % 8);
} else {
bits.bits[dstbit/8] &= ~(1 << (dstbit % 8));
}
}
}
}
// emacs autoindent hack - it doesn't like the loop in set_bits/clear_bits
#if 0
} }
#endif
static void decompress_layout(const unsigned char *layout_string, layout_bitmap bits)
{
unsigned char c;
size_t bit = 0;
while ((c = *layout_string++)) {
unsigned char skip = (c & 0xf0) >> 4;
unsigned char scan = (c & 0x0f);
bit += skip;
set_bits(bits, bit, scan);
bit += scan;
}
}
/***********************************************************************
* layout_bitmap_create
* Allocate a layout bitmap.
* The new bitmap spans the given instance size bytes.
* The start of the bitmap is filled from the given layout string (which
* spans an instance size of layoutStringSize); the rest is zero-filled.
* The returned bitmap must be freed with layout_bitmap_free().
**********************************************************************/
layout_bitmap
layout_bitmap_create(const unsigned char *layout_string,
size_t layoutStringInstanceSize,
size_t instanceSize, bool weak)
{
layout_bitmap result;
size_t words = instanceSize / sizeof(id);
result.weak = weak;
result.bitCount = words;
result.bitsAllocated = words;
result.bits = (uint8_t *)calloc((words+7)/8, 1);
if (!layout_string) {
if (!weak) {
// NULL ivar layout means all-scanned
// (but only up to layoutStringSize instance size)
set_bits(result, 0, layoutStringInstanceSize/sizeof(id));
} else {
// NULL weak layout means none-weak.
}
} else {
decompress_layout(layout_string, result);
}
return result;
}
/***********************************************************************
* layout_bitmap_create_empty
* Allocate a layout bitmap.
* The new bitmap spans the given instance size bytes.
* The bitmap is empty, to represent an object whose ivars are completely unscanned.
* The returned bitmap must be freed with layout_bitmap_free().
**********************************************************************/
layout_bitmap
layout_bitmap_create_empty(size_t instanceSize, bool weak)
{
layout_bitmap result;
size_t words = instanceSize / sizeof(id);
result.weak = weak;
result.bitCount = words;
result.bitsAllocated = words;
result.bits = (uint8_t *)calloc((words+7)/8, 1);
return result;
}
void
layout_bitmap_free(layout_bitmap bits)
{
if (bits.bits) free(bits.bits);
}
const unsigned char *
layout_string_create(layout_bitmap bits)
{
const unsigned char *result =
compress_layout(bits.bits, bits.bitCount, bits.weak);
#if DEBUG
// paranoia: cycle to bitmap and back to string again, and compare
layout_bitmap check = layout_bitmap_create(result, bits.bitCount*sizeof(id),
bits.bitCount*sizeof(id), bits.weak);
unsigned char *result2 =
compress_layout(check.bits, check.bitCount, check.weak);
if (result != result2 && 0 != strcmp((char*)result, (char *)result2)) {
layout_bitmap_print(bits);
layout_bitmap_print(check);
_objc_fatal("libobjc bug: mishandled layout bitmap");
}
free(result2);
layout_bitmap_free(check);
#endif
return result;
}
void
layout_bitmap_set_ivar(layout_bitmap bits, const char *type, size_t offset)
{
// fixme only handles some types
size_t bit = offset / sizeof(id);
if (!type) return;
if (type[0] == '@' || 0 == strcmp(type, "^@")) {
// id
// id *
// Block ("@?")
set_bits(bits, bit, 1);
}
else if (type[0] == '[') {
// id[]
char *t;
unsigned long count = strtoul(type+1, &t, 10);
if (t && t[0] == '@') {
set_bits(bits, bit, count);
}
}
else if (strchr(type, '@')) {
_objc_inform("warning: failing to set GC layout for '%s'\n", type);
}
}
/***********************************************************************
* layout_bitmap_grow
* Expand a layout bitmap to span newCount bits.
* The new bits are undefined.
**********************************************************************/
void
layout_bitmap_grow(layout_bitmap *bits, size_t newCount)
{
if (bits->bitCount >= newCount) return;
bits->bitCount = newCount;
if (bits->bitsAllocated < newCount) {
size_t newAllocated = bits->bitsAllocated * 2;
if (newAllocated < newCount) newAllocated = newCount;
bits->bits = (uint8_t *)
realloc(bits->bits, (newAllocated+7) / 8);
bits->bitsAllocated = newAllocated;
}
assert(bits->bitsAllocated >= bits->bitCount);
assert(bits->bitsAllocated >= newCount);
}
/***********************************************************************
* layout_bitmap_slide
* Slide the end of a layout bitmap farther from the start.
* Slides bits [oldPos, bits.bitCount) to [newPos, bits.bitCount+newPos-oldPos)
* Bits [oldPos, newPos) are zero-filled.
* The bitmap is expanded and bitCount updated if necessary.
* newPos >= oldPos.
**********************************************************************/
void
layout_bitmap_slide(layout_bitmap *bits, size_t oldPos, size_t newPos)
{
size_t shift;
size_t count;
if (oldPos == newPos) return;
if (oldPos > newPos) _objc_fatal("layout bitmap sliding backwards");
shift = newPos - oldPos;
count = bits->bitCount - oldPos;
layout_bitmap_grow(bits, bits->bitCount + shift);
move_bits(*bits, oldPos, newPos, count); // slide
clear_bits(*bits, oldPos, shift); // zero-fill
}
/***********************************************************************
* layout_bitmap_slide_anywhere
* Slide the end of a layout bitmap relative to the start.
* Like layout_bitmap_slide, but can slide backwards too.
* The end of the bitmap is truncated.
**********************************************************************/
void
layout_bitmap_slide_anywhere(layout_bitmap *bits, size_t oldPos, size_t newPos)
{
size_t shift;
size_t count;
if (oldPos == newPos) return;
if (oldPos < newPos) {
layout_bitmap_slide(bits, oldPos, newPos);
return;
}
shift = oldPos - newPos;
count = bits->bitCount - oldPos;
move_bits(*bits, oldPos, newPos, count); // slide
bits->bitCount -= shift;
}
/***********************************************************************
* layout_bitmap_splat
* Pastes the contents of bitmap src to the start of bitmap dst.
* dst bits between the end of src and oldSrcInstanceSize are zeroed.
* dst must be at least as long as src.
* Returns YES if any of dst's bits were changed.
**********************************************************************/
bool
layout_bitmap_splat(layout_bitmap dst, layout_bitmap src,
size_t oldSrcInstanceSize)
{
bool changed;
size_t oldSrcBitCount;
size_t bit;
if (dst.bitCount < src.bitCount) _objc_fatal("layout bitmap too short");
changed = NO;
oldSrcBitCount = oldSrcInstanceSize / sizeof(id);
// fixme optimize for byte/word at a time
for (bit = 0; bit < oldSrcBitCount; bit++) {
int dstset = dst.bits[bit/8] & (1 << (bit % 8));
int srcset = (bit < src.bitCount)
? src.bits[bit/8] & (1 << (bit % 8))
: 0;
if (dstset != srcset) {
changed = YES;
if (srcset) {
dst.bits[bit/8] |= 1 << (bit % 8);
} else {
dst.bits[bit/8] &= ~(1 << (bit % 8));
}
}
}
return changed;
}
/***********************************************************************
* layout_bitmap_or
* Set dst=dst|src.
* dst must be at least as long as src.
* Returns YES if any of dst's bits were changed.
**********************************************************************/
bool
layout_bitmap_or(layout_bitmap dst, layout_bitmap src, const char *msg)
{
bool changed = NO;
size_t bit;
if (dst.bitCount < src.bitCount) {
_objc_fatal("layout_bitmap_or: layout bitmap too short%s%s",
msg ? ": " : "", msg ? msg : "");
}
// fixme optimize for byte/word at a time
for (bit = 0; bit < src.bitCount; bit++) {
int dstset = dst.bits[bit/8] & (1 << (bit % 8));
int srcset = src.bits[bit/8] & (1 << (bit % 8));
if (srcset && !dstset) {
changed = YES;
dst.bits[bit/8] |= 1 << (bit % 8);
}
}
return changed;
}
/***********************************************************************
* layout_bitmap_clear
* Set dst=dst&~src.
* dst must be at least as long as src.
* Returns YES if any of dst's bits were changed.
**********************************************************************/
bool
layout_bitmap_clear(layout_bitmap dst, layout_bitmap src, const char *msg)
{
bool changed = NO;
size_t bit;
if (dst.bitCount < src.bitCount) {
_objc_fatal("layout_bitmap_clear: layout bitmap too short%s%s",
msg ? ": " : "", msg ? msg : "");
}
// fixme optimize for byte/word at a time
for (bit = 0; bit < src.bitCount; bit++) {
int dstset = dst.bits[bit/8] & (1 << (bit % 8));
int srcset = src.bits[bit/8] & (1 << (bit % 8));
if (srcset && dstset) {
changed = YES;
dst.bits[bit/8] &= ~(1 << (bit % 8));
}
}
return changed;
}
void
layout_bitmap_print(layout_bitmap bits)
{
size_t i;
printf("%zu: ", bits.bitCount);
for (i = 0; i < bits.bitCount; i++) {
int set = bits.bits[i/8] & (1 << (i % 8));
printf("%c", set ? '#' : '.');
}
printf("\n");
}
#if 0
// The code below may be useful when interpreting ivar types more precisely.
/**********************************************************************
* mark_offset_for_layout
*
* Marks the appropriate bit in the bits array cooresponding to a the
* offset of a reference. If we are scanning a nested pointer structure
* then the bits array will be NULL then this function does nothing.
*
**********************************************************************/
static void mark_offset_for_layout(long offset, long bits_size, unsigned char *bits) {
// references are ignored if bits is NULL
if (bits) {
long slot = offset / sizeof(long);
// determine byte index using (offset / 8 bits per byte)
long i_byte = slot >> 3;
// if the byte index is valid
if (i_byte < bits_size) {
// set the (offset / 8 bits per byte)th bit
bits[i_byte] |= 1 << (slot & 7);
} else {
// offset not within instance size
_objc_inform ("layout - offset exceeds instance size");
}
}
}
/**********************************************************************
* skip_ivar_type_name
*
* Skip over the name of a field/class in an ivar type string. Names
* are in the form of a double-quoted string. Returns the remaining
* string.
*
**********************************************************************/
static char *skip_ivar_type_name(char *type) {
// current character
char ch;
// if there is an open quote
if (*type == '\"') {
// skip quote
type++;
// while no closing quote
while ((ch = *type) != '\"') {
// if end of string return end of string
if (!ch) return type;
// skip character
type++;
}
// skip closing quote
type++;
}
// return remaining string
return type;
}
/**********************************************************************
* skip_ivar_struct_name
*
* Skip over the name of a struct in an ivar type string. Names
* may be followed by an equals sign. Returns the remaining string.
*
**********************************************************************/
static char *skip_ivar_struct_name(char *type) {
// get first character
char ch = *type;
if (ch == _C_UNDEF) {
// skip undefined name
type++;
} else if ((ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z') || ch == '_') {
// if alphabetic
// scan alphanumerics
do {
// next character
ch = *++type;
} while ((ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z') || ch == '_' || (ch >= '0' && ch <= '9'));
} else {
// no struct name present
return type;
}
// skip equals sign
if (*type == '=') type++;
return type;
}
/**********************************************************************
* scan_basic_ivar_type
*
* Determines the size and alignment of a basic ivar type. If the basic
* type is a possible reference to another garbage collected type the
* is_reference is set to true (false otherwise.) Returns the remaining
* string.
*
**********************************************************************/
static char *scan_ivar_type_for_layout(char *type, long offset, long bits_size, unsigned char *bits, long *next_offset);
static char *scan_basic_ivar_type(char *type, long *size, long *alignment, bool *is_reference) {
// assume it is a non-reference type
*is_reference = NO;
// get the first character (advancing string)
const char *full_type = type;
char ch = *type++;
// GCC 4 uses for const type*.
if (ch == _C_CONST) ch = *type++;
// act on first character
switch (ch) {
case _C_ID: {
// ID type
// skip over optional class name
type = skip_ivar_type_name(type);
// size and alignment of an id type
*size = sizeof(id);
*alignment = __alignof(id);
// is a reference type
*is_reference = YES;
break;
}
case _C_PTR: {
// C pointer type
// skip underlying type
long ignored_offset;
type = scan_ivar_type_for_layout(type, 0, 0, NULL, &ignored_offset);
// size and alignment of a generic pointer type
*size = sizeof(void *);
*alignment = __alignof(void *);
// is a reference type
*is_reference = YES;
break;
}
case _C_CHARPTR: {
// C string
// size and alignment of a char pointer type
*size = sizeof(char *);
*alignment = __alignof(char *);
// is a reference type
*is_reference = YES;
break;
}
case _C_CLASS:
case _C_SEL: {
// classes and selectors are ignored for now
*size = sizeof(void *);
*alignment = __alignof(void *);
break;
}
case _C_CHR:
case _C_UCHR: {
// char and unsigned char
*size = sizeof(char);
*alignment = __alignof(char);
break;
}
case _C_SHT:
case _C_USHT: {
// short and unsigned short
*size = sizeof(short);
*alignment = __alignof(short);
break;
}
case _C_ATOM:
case _C_INT:
case _C_UINT: {
// int and unsigned int
*size = sizeof(int);
*alignment = __alignof(int);
break;
}
case _C_LNG:
case _C_ULNG: {
// long and unsigned long
*size = sizeof(long);
*alignment = __alignof(long);
break;
}
case _C_LNG_LNG:
case _C_ULNG_LNG: {
// long long and unsigned long long
*size = sizeof(long long);
*alignment = __alignof(long long);
break;
}
case _C_VECTOR: {
// vector
*size = 16;
*alignment = 16;
break;
}
case _C_FLT: {
// float
*size = sizeof(float);
*alignment = __alignof(float);
break;
}
case _C_DBL: {
// double
*size = sizeof(double);
*alignment = __alignof(double);
break;
}
case _C_BFLD: {
// bit field
// get number of bits in bit field (advance type string)
long lng = strtol(type, &type, 10);
// while next type is a bit field
while (*type == _C_BFLD) {
// skip over _C_BFLD
type++;
// get next bit field length
long next_lng = strtol(type, &type, 10);
// if spans next word then align to next word
if ((lng & ~31) != ((lng + next_lng) & ~31)) lng = (lng + 31) & ~31;
// increment running length
lng += next_lng;
// skip over potential field name
type = skip_ivar_type_name(type);
}
// determine number of bytes bits represent
*size = (lng + 7) / 8;
// byte alignment
*alignment = __alignof(char);
break;
}
case _C_BOOL: {
// double
*size = sizeof(BOOL);
*alignment = __alignof(BOOL);
break;
}
case _C_VOID: {
// skip void types
*size = 0;
*alignment = __alignof(char);
break;
}
case _C_UNDEF: {
*size = 0;
*alignment = __alignof(char);
break;
}
default: {
// unhandled type
_objc_fatal("unrecognized character \'%c\' in ivar type: \"%s\"", ch, full_type);
}
}
return type;
}
/**********************************************************************
* scan_ivar_type_for_layout
*
* Scan an ivar type string looking for references. The offset indicates
* where the ivar begins. bits is a byte array of size bits_size used to
* contain the references bit map. next_offset is the offset beyond the
* ivar. Returns the remaining string.
*
**********************************************************************/
static char *scan_ivar_type_for_layout(char *type, long offset, long bits_size, unsigned char *bits, long *next_offset) {
long size; // size of a basic type
long alignment; // alignment of the basic type
bool is_reference; // true if the type indicates a reference to a garbage collected object
// get the first character
char ch = *type;
// GCC 4 uses for const type*.
if (ch == _C_CONST) ch = *++type;
// act on first character
switch (ch) {
case _C_ARY_B: {
// array type
// get the array length
long lng = strtol(type + 1, &type, 10);
// next type will be where to advance the type string once the array is processed
char *next_type = type;
// repeat the next type x lng
if (!lng) {
next_type = scan_ivar_type_for_layout(type, 0, 0, NULL, &offset);
} else {
while (lng--) {
// repeatedly scan the same type
next_type = scan_ivar_type_for_layout(type, offset, bits_size, bits, &offset);
}
}
// advance the type now
type = next_type;
// after the end of the array
*next_offset = offset;
// advance over closing bracket
if (*type == _C_ARY_E) type++;
else _objc_inform("missing \'%c\' in ivar type.", _C_ARY_E);
break;
}
case _C_UNION_B: {
// union type
// skip over possible union name
type = skip_ivar_struct_name(type + 1);
// need to accumulate the maximum element offset
long max_offset = 0;
// while not closing paren
while ((ch = *type) && ch != _C_UNION_E) {
// skip over potential field name
type = skip_ivar_type_name(type);
// scan type
long union_offset;
type = scan_ivar_type_for_layout(type, offset, bits_size, bits, &union_offset);
// adjust the maximum element offset
if (max_offset < union_offset) max_offset = union_offset;
}
// after the largest element
*next_offset = max_offset;
// advance over closing paren
if (ch == _C_UNION_E) {
type++;
} else {
_objc_inform("missing \'%c\' in ivar type", _C_UNION_E);
}
break;
}
case _C_STRUCT_B: {
// struct type
// skip over possible struct name
type = skip_ivar_struct_name(type + 1);
// while not closing brace
while ((ch = *type) && ch != _C_STRUCT_E) {
// skip over potential field name
type = skip_ivar_type_name(type);
// scan type
type = scan_ivar_type_for_layout(type, offset, bits_size, bits, &offset);
}
// after the end of the struct
*next_offset = offset;
// advance over closing brace
if (ch == _C_STRUCT_E) type++;
else _objc_inform("missing \'%c\' in ivar type", _C_STRUCT_E);
break;
}
default: {
// basic type
// scan type
type = scan_basic_ivar_type(type, &size, &alignment, &is_reference);
// create alignment mask
alignment--;
// align offset
offset = (offset + alignment) & ~alignment;
// if is a reference then mark in the bit map
if (is_reference) mark_offset_for_layout(offset, bits_size, bits);
// after the basic type
*next_offset = offset + size;
break;
}
}
// return remainder of type string
return type;
}
#endif

54
runtime/objc-load.h Normal file
View File

@ -0,0 +1,54 @@
/*
* Copyright (c) 1999-2001, 2005-2006 Apple Inc. All Rights Reserved.
*
* @APPLE_LICENSE_HEADER_START@
*
* 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 2.0 (the 'License'). You may not use this file except in
* compliance with the License. Please obtain a copy of the License at
* http://www.opensource.apple.com/apsl/ 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, QUIET ENJOYMENT OR NON-INFRINGEMENT.
* Please see the License for the specific language governing rights and
* limitations under the License.
*
* @APPLE_LICENSE_HEADER_END@
*/
/*
* objc-load.h
* Copyright 1988-1996, NeXT Software, Inc.
*/
#ifndef _OBJC_LOAD_H_
#define _OBJC_LOAD_H_
#include <objc/objc-class.h>
#include <mach-o/loader.h>
/* dynamically loading Mach-O object files that contain Objective-C code */
OBJC_EXPORT long objc_loadModules (
char *modlist[],
void *errStream,
void (*class_callback) (Class, Category),
/*headerType*/ struct mach_header **hdr_addr,
char *debug_file
) OBJC2_UNAVAILABLE;
OBJC_EXPORT int objc_loadModule (
char * moduleName,
void (*class_callback) (Class, Category),
int * errorCode
) OBJC2_UNAVAILABLE;
OBJC_EXPORT long objc_unloadModules(
void *errorStream, /* input (optional) */
void (*unloadCallback)(Class, Category) /* input (optional) */
) OBJC2_UNAVAILABLE;
#endif /* _OBJC_LOAD_H_ */

167
runtime/objc-load.mm Normal file
View File

@ -0,0 +1,167 @@
/*
* Copyright (c) 1999-2001, 2004-2007 Apple Inc. All Rights Reserved.
*
* @APPLE_LICENSE_HEADER_START@
*
* 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 2.0 (the 'License'). You may not use this file except in
* compliance with the License. Please obtain a copy of the License at
* http://www.opensource.apple.com/apsl/ 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, QUIET ENJOYMENT OR NON-INFRINGEMENT.
* Please see the License for the specific language governing rights and
* limitations under the License.
*
* @APPLE_LICENSE_HEADER_END@
*/
/*
* objc-load.m
* Copyright 1988-1996, NeXT Software, Inc.
* Author: s. naroff
*
*/
#include "objc-private.h"
#include "objc-load.h"
#if !__OBJC2__ && !TARGET_OS_WIN32
extern void (*callbackFunction)( Class, Category );
/**********************************************************************************
* objc_loadModule.
*
* NOTE: Loading isn't really thread safe. If a load message recursively calls
* objc_loadModules() both sets will be loaded correctly, but if the original
* caller calls objc_unloadModules() it will probably unload the wrong modules.
* If a load message calls objc_unloadModules(), then it will unload
* the modules currently being loaded, which will probably cause a crash.
*
* Error handling is still somewhat crude. If we encounter errors while
* linking up classes or categories, we will not recover correctly.
*
* I removed attempts to lock the class hashtable, since this introduced
* deadlock which was hard to remove. The only way you can get into trouble
* is if one thread loads a module while another thread tries to access the
* loaded classes (using objc_lookUpClass) before the load is complete.
**********************************************************************************/
int objc_loadModule(char *moduleName, void (*class_callback) (Class, Category), int *errorCode)
{
int successFlag = 1;
int locErrorCode;
NSObjectFileImage objectFileImage;
NSObjectFileImageReturnCode code;
// So we don't have to check this everywhere
if (errorCode == NULL)
errorCode = &locErrorCode;
if (moduleName == NULL)
{
*errorCode = NSObjectFileImageInappropriateFile;
return 0;
}
if (_dyld_present () == 0)
{
*errorCode = NSObjectFileImageFailure;
return 0;
}
callbackFunction = class_callback;
code = NSCreateObjectFileImageFromFile (moduleName, &objectFileImage);
if (code != NSObjectFileImageSuccess)
{
*errorCode = code;
return 0;
}
if (NSLinkModule(objectFileImage, moduleName, NSLINKMODULE_OPTION_RETURN_ON_ERROR) == NULL) {
NSLinkEditErrors error;
int errorNum;
const char *fileName, *errorString;
NSLinkEditError(&error, &errorNum, &fileName, &errorString);
// These errors may overlap with other errors that objc_loadModule returns in other failure cases.
*errorCode = error;
return 0;
}
callbackFunction = NULL;
return successFlag;
}
/**********************************************************************************
* objc_loadModules.
**********************************************************************************/
/* Lock for dynamic loading and unloading. */
// static OBJC_DECLARE_LOCK (loadLock);
long objc_loadModules (char * modlist[],
void * errStream,
void (*class_callback) (Class, Category),
headerType ** hdr_addr,
char * debug_file)
{
char ** modules;
int code;
int itWorked;
if (modlist == 0)
return 0;
for (modules = &modlist[0]; *modules != 0; modules++)
{
itWorked = objc_loadModule (*modules, class_callback, &code);
if (itWorked == 0)
{
//if (errStream)
// NXPrintf ((NXStream *) errStream, "objc_loadModules(%s) code = %d\n", *modules, code);
return 1;
}
if (hdr_addr)
*(hdr_addr++) = 0;
}
return 0;
}
/**********************************************************************************
* objc_unloadModules.
*
* NOTE: Unloading isn't really thread safe. If an unload message calls
* objc_loadModules() or objc_unloadModules(), then the current call
* to objc_unloadModules() will probably unload the wrong stuff.
**********************************************************************************/
long objc_unloadModules (void * errStream,
void (*unload_callback) (Class, Category))
{
headerType * header_addr = 0;
int errflag = 0;
// TODO: to make unloading work, should get the current header
if (header_addr)
{
; // TODO: unload the current header
}
else
{
errflag = 1;
}
return errflag;
}
#endif

45
runtime/objc-loadmethod.h Normal file
View File

@ -0,0 +1,45 @@
/*
* Copyright (c) 2004-2006 Apple Inc. All Rights Reserved.
*
* @APPLE_LICENSE_HEADER_START@
*
* 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 2.0 (the 'License'). You may not use this file except in
* compliance with the License. Please obtain a copy of the License at
* http://www.opensource.apple.com/apsl/ 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, QUIET ENJOYMENT OR NON-INFRINGEMENT.
* Please see the License for the specific language governing rights and
* limitations under the License.
*
* @APPLE_LICENSE_HEADER_END@
*/
/***********************************************************************
* objc-loadmethod.h
* Support for +load methods.
**********************************************************************/
#ifndef _OBJC_LOADMETHOD_H
#define _OBJC_LOADMETHOD_H
#include "objc-private.h"
__BEGIN_DECLS
extern void add_class_to_loadable_list(Class cls);
extern void add_category_to_loadable_list(Category cat);
extern void remove_class_from_loadable_list(Class cls);
extern void remove_category_from_loadable_list(Category cat);
extern void call_load_methods(void);
__END_DECLS
#endif

367
runtime/objc-loadmethod.mm Normal file
View File

@ -0,0 +1,367 @@
/*
* Copyright (c) 2004-2006 Apple Inc. All Rights Reserved.
*
* @APPLE_LICENSE_HEADER_START@
*
* 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 2.0 (the 'License'). You may not use this file except in
* compliance with the License. Please obtain a copy of the License at
* http://www.opensource.apple.com/apsl/ 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, QUIET ENJOYMENT OR NON-INFRINGEMENT.
* Please see the License for the specific language governing rights and
* limitations under the License.
*
* @APPLE_LICENSE_HEADER_END@
*/
/***********************************************************************
* objc-loadmethod.m
* Support for +load methods.
**********************************************************************/
#include "objc-loadmethod.h"
#include "objc-private.h"
typedef void(*load_method_t)(id, SEL);
struct loadable_class {
Class cls; // may be nil
IMP method;
};
struct loadable_category {
Category cat; // may be nil
IMP method;
};
// List of classes that need +load called (pending superclass +load)
// This list always has superclasses first because of the way it is constructed
static struct loadable_class *loadable_classes = nil;
static int loadable_classes_used = 0;
static int loadable_classes_allocated = 0;
// List of categories that need +load called (pending parent class +load)
static struct loadable_category *loadable_categories = nil;
static int loadable_categories_used = 0;
static int loadable_categories_allocated = 0;
/***********************************************************************
* add_class_to_loadable_list
* Class cls has just become connected. Schedule it for +load if
* it implements a +load method.
**********************************************************************/
void add_class_to_loadable_list(Class cls)
{
IMP method;
loadMethodLock.assertLocked();
method = cls->getLoadMethod();
if (!method) return; // Don't bother if cls has no +load method
if (PrintLoading) {
_objc_inform("LOAD: class '%s' scheduled for +load",
cls->nameForLogging());
}
if (loadable_classes_used == loadable_classes_allocated) {
loadable_classes_allocated = loadable_classes_allocated*2 + 16;
loadable_classes = (struct loadable_class *)
realloc(loadable_classes,
loadable_classes_allocated *
sizeof(struct loadable_class));
}
loadable_classes[loadable_classes_used].cls = cls;
loadable_classes[loadable_classes_used].method = method;
loadable_classes_used++;
}
/***********************************************************************
* add_category_to_loadable_list
* Category cat's parent class exists and the category has been attached
* to its class. Schedule this category for +load after its parent class
* becomes connected and has its own +load method called.
**********************************************************************/
void add_category_to_loadable_list(Category cat)
{
IMP method;
loadMethodLock.assertLocked();
method = _category_getLoadMethod(cat);
// Don't bother if cat has no +load method
if (!method) return;
if (PrintLoading) {
_objc_inform("LOAD: category '%s(%s)' scheduled for +load",
_category_getClassName(cat), _category_getName(cat));
}
if (loadable_categories_used == loadable_categories_allocated) {
loadable_categories_allocated = loadable_categories_allocated*2 + 16;
loadable_categories = (struct loadable_category *)
realloc(loadable_categories,
loadable_categories_allocated *
sizeof(struct loadable_category));
}
loadable_categories[loadable_categories_used].cat = cat;
loadable_categories[loadable_categories_used].method = method;
loadable_categories_used++;
}
/***********************************************************************
* remove_class_from_loadable_list
* Class cls may have been loadable before, but it is now no longer
* loadable (because its image is being unmapped).
**********************************************************************/
void remove_class_from_loadable_list(Class cls)
{
loadMethodLock.assertLocked();
if (loadable_classes) {
int i;
for (i = 0; i < loadable_classes_used; i++) {
if (loadable_classes[i].cls == cls) {
loadable_classes[i].cls = nil;
if (PrintLoading) {
_objc_inform("LOAD: class '%s' unscheduled for +load",
cls->nameForLogging());
}
return;
}
}
}
}
/***********************************************************************
* remove_category_from_loadable_list
* Category cat may have been loadable before, but it is now no longer
* loadable (because its image is being unmapped).
**********************************************************************/
void remove_category_from_loadable_list(Category cat)
{
loadMethodLock.assertLocked();
if (loadable_categories) {
int i;
for (i = 0; i < loadable_categories_used; i++) {
if (loadable_categories[i].cat == cat) {
loadable_categories[i].cat = nil;
if (PrintLoading) {
_objc_inform("LOAD: category '%s(%s)' unscheduled for +load",
_category_getClassName(cat),
_category_getName(cat));
}
return;
}
}
}
}
/***********************************************************************
* call_class_loads
* Call all pending class +load methods.
* If new classes become loadable, +load is NOT called for them.
*
* Called only by call_load_methods().
**********************************************************************/
static void call_class_loads(void)
{
int i;
// Detach current loadable list.
struct loadable_class *classes = loadable_classes;
int used = loadable_classes_used;
loadable_classes = nil;
loadable_classes_allocated = 0;
loadable_classes_used = 0;
// Call all +loads for the detached list.
for (i = 0; i < used; i++) {
Class cls = classes[i].cls;
load_method_t load_method = (load_method_t)classes[i].method;
if (!cls) continue;
if (PrintLoading) {
_objc_inform("LOAD: +[%s load]\n", cls->nameForLogging());
}
(*load_method)(cls, SEL_load);
}
// Destroy the detached list.
if (classes) free(classes);
}
/***********************************************************************
* call_category_loads
* Call some pending category +load methods.
* The parent class of the +load-implementing categories has all of
* its categories attached, in case some are lazily waiting for +initalize.
* Don't call +load unless the parent class is connected.
* If new categories become loadable, +load is NOT called, and they
* are added to the end of the loadable list, and we return TRUE.
* Return FALSE if no new categories became loadable.
*
* Called only by call_load_methods().
**********************************************************************/
static bool call_category_loads(void)
{
int i, shift;
bool new_categories_added = NO;
// Detach current loadable list.
struct loadable_category *cats = loadable_categories;
int used = loadable_categories_used;
int allocated = loadable_categories_allocated;
loadable_categories = nil;
loadable_categories_allocated = 0;
loadable_categories_used = 0;
// Call all +loads for the detached list.
for (i = 0; i < used; i++) {
Category cat = cats[i].cat;
load_method_t load_method = (load_method_t)cats[i].method;
Class cls;
if (!cat) continue;
cls = _category_getClass(cat);
if (cls && cls->isLoadable()) {
if (PrintLoading) {
_objc_inform("LOAD: +[%s(%s) load]\n",
cls->nameForLogging(),
_category_getName(cat));
}
(*load_method)(cls, SEL_load);
cats[i].cat = nil;
}
}
// Compact detached list (order-preserving)
shift = 0;
for (i = 0; i < used; i++) {
if (cats[i].cat) {
cats[i-shift] = cats[i];
} else {
shift++;
}
}
used -= shift;
// Copy any new +load candidates from the new list to the detached list.
new_categories_added = (loadable_categories_used > 0);
for (i = 0; i < loadable_categories_used; i++) {
if (used == allocated) {
allocated = allocated*2 + 16;
cats = (struct loadable_category *)
realloc(cats, allocated *
sizeof(struct loadable_category));
}
cats[used++] = loadable_categories[i];
}
// Destroy the new list.
if (loadable_categories) free(loadable_categories);
// Reattach the (now augmented) detached list.
// But if there's nothing left to load, destroy the list.
if (used) {
loadable_categories = cats;
loadable_categories_used = used;
loadable_categories_allocated = allocated;
} else {
if (cats) free(cats);
loadable_categories = nil;
loadable_categories_used = 0;
loadable_categories_allocated = 0;
}
if (PrintLoading) {
if (loadable_categories_used != 0) {
_objc_inform("LOAD: %d categories still waiting for +load\n",
loadable_categories_used);
}
}
return new_categories_added;
}
/***********************************************************************
* call_load_methods
* Call all pending class and category +load methods.
* Class +load methods are called superclass-first.
* Category +load methods are not called until after the parent class's +load.
*
* This method must be RE-ENTRANT, because a +load could trigger
* more image mapping. In addition, the superclass-first ordering
* must be preserved in the face of re-entrant calls. Therefore,
* only the OUTERMOST call of this function will do anything, and
* that call will handle all loadable classes, even those generated
* while it was running.
*
* The sequence below preserves +load ordering in the face of
* image loading during a +load, and make sure that no
* +load method is forgotten because it was added during
* a +load call.
* Sequence:
* 1. Repeatedly call class +loads until there aren't any more
* 2. Call category +loads ONCE.
* 3. Run more +loads if:
* (a) there are more classes to load, OR
* (b) there are some potential category +loads that have
* still never been attempted.
* Category +loads are only run once to ensure "parent class first"
* ordering, even if a category +load triggers a new loadable class
* and a new loadable category attached to that class.
*
* Locking: loadMethodLock must be held by the caller
* All other locks must not be held.
**********************************************************************/
void call_load_methods(void)
{
static bool loading = NO;
bool more_categories;
loadMethodLock.assertLocked();
// Re-entrant calls do nothing; the outermost call will finish the job.
if (loading) return;
loading = YES;
void *pool = objc_autoreleasePoolPush();
do {
// 1. Repeatedly call class +loads until there aren't any more
while (loadable_classes_used > 0) {
call_class_loads();
}
// 2. Call category +loads ONCE
more_categories = call_category_loads();
// 3. Run more +loads if there are classes OR more untried categories
} while (loadable_classes_used > 0 || more_categories);
objc_autoreleasePoolPop(pool);
loading = NO;
}

89
runtime/objc-lockdebug.h Normal file
View File

@ -0,0 +1,89 @@
/*
* Copyright (c) 2015 Apple Inc. All Rights Reserved.
*
* @APPLE_LICENSE_HEADER_START@
*
* 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 2.0 (the 'License'). You may not use this file except in
* compliance with the License. Please obtain a copy of the License at
* http://www.opensource.apple.com/apsl/ 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, QUIET ENJOYMENT OR NON-INFRINGEMENT.
* Please see the License for the specific language governing rights and
* limitations under the License.
*
* @APPLE_LICENSE_HEADER_END@
*/
extern void lockdebug_mutex_lock(mutex_tt<true> *lock);
extern void lockdebug_mutex_try_lock(mutex_tt<true> *lock);
extern void lockdebug_mutex_unlock(mutex_tt<true> *lock);
extern void lockdebug_mutex_assert_locked(mutex_tt<true> *lock);
extern void lockdebug_mutex_assert_unlocked(mutex_tt<true> *lock);
static inline void lockdebug_mutex_lock(mutex_tt<false> *lock) { }
static inline void lockdebug_mutex_try_lock(mutex_tt<false> *lock) { }
static inline void lockdebug_mutex_unlock(mutex_tt<false> *lock) { }
static inline void lockdebug_mutex_assert_locked(mutex_tt<false> *lock) { }
static inline void lockdebug_mutex_assert_unlocked(mutex_tt<false> *lock) { }
extern void lockdebug_monitor_enter(monitor_tt<true> *lock);
extern void lockdebug_monitor_leave(monitor_tt<true> *lock);
extern void lockdebug_monitor_wait(monitor_tt<true> *lock);
extern void lockdebug_monitor_assert_locked(monitor_tt<true> *lock);
extern void lockdebug_monitor_assert_unlocked(monitor_tt<true> *lock);
static inline void lockdebug_monitor_enter(monitor_tt<false> *lock) { }
static inline void lockdebug_monitor_leave(monitor_tt<false> *lock) { }
static inline void lockdebug_monitor_wait(monitor_tt<false> *lock) { }
static inline void lockdebug_monitor_assert_locked(monitor_tt<false> *lock) { }
static inline void lockdebug_monitor_assert_unlocked(monitor_tt<false> *lock) {}
extern void
lockdebug_recursive_mutex_lock(recursive_mutex_tt<true> *lock);
extern void
lockdebug_recursive_mutex_unlock(recursive_mutex_tt<true> *lock);
extern void
lockdebug_recursive_mutex_assert_locked(recursive_mutex_tt<true> *lock);
extern void
lockdebug_recursive_mutex_assert_unlocked(recursive_mutex_tt<true> *lock);
static inline void
lockdebug_recursive_mutex_lock(recursive_mutex_tt<false> *lock) { }
static inline void
lockdebug_recursive_mutex_unlock(recursive_mutex_tt<false> *lock) { }
static inline void
lockdebug_recursive_mutex_assert_locked(recursive_mutex_tt<false> *lock) { }
static inline void
lockdebug_recursive_mutex_assert_unlocked(recursive_mutex_tt<false> *lock) { }
extern void lockdebug_rwlock_read(rwlock_tt<true> *lock);
extern void lockdebug_rwlock_try_read_success(rwlock_tt<true> *lock);
extern void lockdebug_rwlock_unlock_read(rwlock_tt<true> *lock);
extern void lockdebug_rwlock_write(rwlock_tt<true> *lock);
extern void lockdebug_rwlock_try_write_success(rwlock_tt<true> *lock);
extern void lockdebug_rwlock_unlock_write(rwlock_tt<true> *lock);
extern void lockdebug_rwlock_assert_reading(rwlock_tt<true> *lock);
extern void lockdebug_rwlock_assert_writing(rwlock_tt<true> *lock);
extern void lockdebug_rwlock_assert_locked(rwlock_tt<true> *lock);
extern void lockdebug_rwlock_assert_unlocked(rwlock_tt<true> *lock);
static inline void lockdebug_rwlock_read(rwlock_tt<false> *) { }
static inline void lockdebug_rwlock_try_read_success(rwlock_tt<false> *) { }
static inline void lockdebug_rwlock_unlock_read(rwlock_tt<false> *) { }
static inline void lockdebug_rwlock_write(rwlock_tt<false> *) { }
static inline void lockdebug_rwlock_try_write_success(rwlock_tt<false> *) { }
static inline void lockdebug_rwlock_unlock_write(rwlock_tt<false> *) { }
static inline void lockdebug_rwlock_assert_reading(rwlock_tt<false> *) { }
static inline void lockdebug_rwlock_assert_writing(rwlock_tt<false> *) { }
static inline void lockdebug_rwlock_assert_locked(rwlock_tt<false> *) { }
static inline void lockdebug_rwlock_assert_unlocked(rwlock_tt<false> *) { }

471
runtime/objc-lockdebug.mm Normal file
View File

@ -0,0 +1,471 @@
/*
* Copyright (c) 2007 Apple Inc. All Rights Reserved.
*
* @APPLE_LICENSE_HEADER_START@
*
* 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 2.0 (the 'License'). You may not use this file except in
* compliance with the License. Please obtain a copy of the License at
* http://www.opensource.apple.com/apsl/ 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, QUIET ENJOYMENT OR NON-INFRINGEMENT.
* Please see the License for the specific language governing rights and
* limitations under the License.
*
* @APPLE_LICENSE_HEADER_END@
*/
/***********************************************************************
* objc-lock.m
* Error-checking locks for debugging.
**********************************************************************/
#include "objc-private.h"
#if DEBUG && !TARGET_OS_WIN32
/***********************************************************************
* Recording - per-thread list of mutexes and monitors held
**********************************************************************/
typedef struct {
void *l; // the lock itself
int k; // the kind of lock it is (MUTEX, MONITOR, etc)
int i; // the lock's nest count
} lockcount;
#define MUTEX 1
#define MONITOR 2
#define RDLOCK 3
#define WRLOCK 4
#define RECURSIVE 5
typedef struct _objc_lock_list {
int allocated;
int used;
lockcount list[0];
} _objc_lock_list;
static tls_key_t lock_tls;
static void
destroyLocks(void *value)
{
_objc_lock_list *locks = (_objc_lock_list *)value;
// fixme complain about any still-held locks?
if (locks) free(locks);
}
static struct _objc_lock_list *
getLocks(BOOL create)
{
_objc_lock_list *locks;
// Use a dedicated tls key to prevent differences vs non-debug in
// usage of objc's other tls keys (required for some unit tests).
INIT_ONCE_PTR(lock_tls, tls_create(&destroyLocks), (void)0);
locks = (_objc_lock_list *)tls_get(lock_tls);
if (!locks) {
if (!create) {
return NULL;
} else {
locks = (_objc_lock_list *)calloc(1, sizeof(_objc_lock_list) + sizeof(lockcount) * 16);
locks->allocated = 16;
locks->used = 0;
tls_set(lock_tls, locks);
}
}
if (locks->allocated == locks->used) {
if (!create) {
return locks;
} else {
_objc_lock_list *oldlocks = locks;
locks = (_objc_lock_list *)calloc(1, sizeof(_objc_lock_list) + 2 * oldlocks->used * sizeof(lockcount));
locks->used = oldlocks->used;
locks->allocated = oldlocks->used * 2;
memcpy(locks->list, oldlocks->list, locks->used * sizeof(lockcount));
tls_set(lock_tls, locks);
free(oldlocks);
}
}
return locks;
}
static BOOL
hasLock(_objc_lock_list *locks, void *lock, int kind)
{
int i;
if (!locks) return NO;
for (i = 0; i < locks->used; i++) {
if (locks->list[i].l == lock && locks->list[i].k == kind) return YES;
}
return NO;
}
static void
setLock(_objc_lock_list *locks, void *lock, int kind)
{
int i;
for (i = 0; i < locks->used; i++) {
if (locks->list[i].l == lock && locks->list[i].k == kind) {
locks->list[i].i++;
return;
}
}
locks->list[locks->used].l = lock;
locks->list[locks->used].i = 1;
locks->list[locks->used].k = kind;
locks->used++;
}
static void
clearLock(_objc_lock_list *locks, void *lock, int kind)
{
int i;
for (i = 0; i < locks->used; i++) {
if (locks->list[i].l == lock && locks->list[i].k == kind) {
if (--locks->list[i].i == 0) {
locks->list[i].l = NULL;
locks->list[i] = locks->list[--locks->used];
}
return;
}
}
_objc_fatal("lock not found!");
}
/***********************************************************************
* Mutex checking
**********************************************************************/
#if !TARGET_OS_SIMULATOR
// Non-simulator platforms have lock debugging built into os_unfair_lock.
void
lockdebug_mutex_lock(mutex_t *lock)
{
// empty
}
void
lockdebug_mutex_unlock(mutex_t *lock)
{
// empty
}
void
lockdebug_mutex_assert_locked(mutex_t *lock)
{
os_unfair_lock_assert_owner((os_unfair_lock *)lock);
}
void
lockdebug_mutex_assert_unlocked(mutex_t *lock)
{
os_unfair_lock_assert_not_owner((os_unfair_lock *)lock);
}
// !TARGET_OS_SIMULATOR
#else
// TARGET_OS_SIMULATOR
// Simulator platforms have no built-in lock debugging in os_unfair_lock.
void
lockdebug_mutex_lock(mutex_t *lock)
{
_objc_lock_list *locks = getLocks(YES);
if (hasLock(locks, lock, MUTEX)) {
_objc_fatal("deadlock: relocking mutex");
}
setLock(locks, lock, MUTEX);
}
// try-lock success is the only case with lockdebug effects.
// try-lock when already locked is OK (will fail)
// try-lock failure does nothing.
void
lockdebug_mutex_try_lock_success(mutex_t *lock)
{
_objc_lock_list *locks = getLocks(YES);
setLock(locks, lock, MUTEX);
}
void
lockdebug_mutex_unlock(mutex_t *lock)
{
_objc_lock_list *locks = getLocks(NO);
if (!hasLock(locks, lock, MUTEX)) {
_objc_fatal("unlocking unowned mutex");
}
clearLock(locks, lock, MUTEX);
}
void
lockdebug_mutex_assert_locked(mutex_t *lock)
{
_objc_lock_list *locks = getLocks(NO);
if (!hasLock(locks, lock, MUTEX)) {
_objc_fatal("mutex incorrectly not locked");
}
}
void
lockdebug_mutex_assert_unlocked(mutex_t *lock)
{
_objc_lock_list *locks = getLocks(NO);
if (hasLock(locks, lock, MUTEX)) {
_objc_fatal("mutex incorrectly locked");
}
}
// TARGET_OS_SIMULATOR
#endif
/***********************************************************************
* Recursive mutex checking
**********************************************************************/
void
lockdebug_recursive_mutex_lock(recursive_mutex_tt<true> *lock)
{
_objc_lock_list *locks = getLocks(YES);
setLock(locks, lock, RECURSIVE);
}
void
lockdebug_recursive_mutex_unlock(recursive_mutex_tt<true> *lock)
{
_objc_lock_list *locks = getLocks(NO);
if (!hasLock(locks, lock, RECURSIVE)) {
_objc_fatal("unlocking unowned recursive mutex");
}
clearLock(locks, lock, RECURSIVE);
}
void
lockdebug_recursive_mutex_assert_locked(recursive_mutex_tt<true> *lock)
{
_objc_lock_list *locks = getLocks(NO);
if (!hasLock(locks, lock, RECURSIVE)) {
_objc_fatal("recursive mutex incorrectly not locked");
}
}
void
lockdebug_recursive_mutex_assert_unlocked(recursive_mutex_tt<true> *lock)
{
_objc_lock_list *locks = getLocks(NO);
if (hasLock(locks, lock, RECURSIVE)) {
_objc_fatal("recursive mutex incorrectly locked");
}
}
/***********************************************************************
* Monitor checking
**********************************************************************/
void
lockdebug_monitor_enter(monitor_t *lock)
{
_objc_lock_list *locks = getLocks(YES);
if (hasLock(locks, lock, MONITOR)) {
_objc_fatal("deadlock: relocking monitor");
}
setLock(locks, lock, MONITOR);
}
void
lockdebug_monitor_leave(monitor_t *lock)
{
_objc_lock_list *locks = getLocks(NO);
if (!hasLock(locks, lock, MONITOR)) {
_objc_fatal("unlocking unowned monitor");
}
clearLock(locks, lock, MONITOR);
}
void
lockdebug_monitor_wait(monitor_t *lock)
{
_objc_lock_list *locks = getLocks(NO);
if (!hasLock(locks, lock, MONITOR)) {
_objc_fatal("waiting in unowned monitor");
}
}
void
lockdebug_monitor_assert_locked(monitor_t *lock)
{
_objc_lock_list *locks = getLocks(NO);
if (!hasLock(locks, lock, MONITOR)) {
_objc_fatal("monitor incorrectly not locked");
}
}
void
lockdebug_monitor_assert_unlocked(monitor_t *lock)
{
_objc_lock_list *locks = getLocks(NO);
if (hasLock(locks, lock, MONITOR)) {
_objc_fatal("monitor incorrectly held");
}
}
/***********************************************************************
* rwlock checking
**********************************************************************/
void
lockdebug_rwlock_read(rwlock_tt<true> *lock)
{
_objc_lock_list *locks = getLocks(YES);
if (hasLock(locks, lock, RDLOCK)) {
// Recursive rwlock read is bad (may deadlock vs pending writer)
_objc_fatal("recursive rwlock read");
}
if (hasLock(locks, lock, WRLOCK)) {
_objc_fatal("deadlock: read after write for rwlock");
}
setLock(locks, lock, RDLOCK);
}
// try-read success is the only case with lockdebug effects.
// try-read when already reading is OK (won't deadlock)
// try-read when already writing is OK (will fail)
// try-read failure does nothing.
void
lockdebug_rwlock_try_read_success(rwlock_tt<true> *lock)
{
_objc_lock_list *locks = getLocks(YES);
setLock(locks, lock, RDLOCK);
}
void
lockdebug_rwlock_unlock_read(rwlock_tt<true> *lock)
{
_objc_lock_list *locks = getLocks(NO);
if (!hasLock(locks, lock, RDLOCK)) {
_objc_fatal("un-reading unowned rwlock");
}
clearLock(locks, lock, RDLOCK);
}
void
lockdebug_rwlock_write(rwlock_tt<true> *lock)
{
_objc_lock_list *locks = getLocks(YES);
if (hasLock(locks, lock, RDLOCK)) {
// Lock promotion not allowed (may deadlock)
_objc_fatal("deadlock: write after read for rwlock");
}
if (hasLock(locks, lock, WRLOCK)) {
_objc_fatal("recursive rwlock write");
}
setLock(locks, lock, WRLOCK);
}
// try-write success is the only case with lockdebug effects.
// try-write when already reading is OK (will fail)
// try-write when already writing is OK (will fail)
// try-write failure does nothing.
void
lockdebug_rwlock_try_write_success(rwlock_tt<true> *lock)
{
_objc_lock_list *locks = getLocks(YES);
setLock(locks, lock, WRLOCK);
}
void
lockdebug_rwlock_unlock_write(rwlock_tt<true> *lock)
{
_objc_lock_list *locks = getLocks(NO);
if (!hasLock(locks, lock, WRLOCK)) {
_objc_fatal("un-writing unowned rwlock");
}
clearLock(locks, lock, WRLOCK);
}
void
lockdebug_rwlock_assert_reading(rwlock_tt<true> *lock)
{
_objc_lock_list *locks = getLocks(NO);
if (!hasLock(locks, lock, RDLOCK)) {
_objc_fatal("rwlock incorrectly not reading");
}
}
void
lockdebug_rwlock_assert_writing(rwlock_tt<true> *lock)
{
_objc_lock_list *locks = getLocks(NO);
if (!hasLock(locks, lock, WRLOCK)) {
_objc_fatal("rwlock incorrectly not writing");
}
}
void
lockdebug_rwlock_assert_locked(rwlock_tt<true> *lock)
{
_objc_lock_list *locks = getLocks(NO);
if (!hasLock(locks, lock, RDLOCK) && !hasLock(locks, lock, WRLOCK)) {
_objc_fatal("rwlock incorrectly neither reading nor writing");
}
}
void
lockdebug_rwlock_assert_unlocked(rwlock_tt<true> *lock)
{
_objc_lock_list *locks = getLocks(NO);
if (hasLock(locks, lock, RDLOCK) || hasLock(locks, lock, WRLOCK)) {
_objc_fatal("rwlock incorrectly not unlocked");
}
}
#endif

1217
runtime/objc-object.h Normal file

File diff suppressed because it is too large Load Diff

360
runtime/objc-opt.mm Normal file
View File

@ -0,0 +1,360 @@
/*
* Copyright (c) 2012 Apple Inc. All Rights Reserved.
*
* @APPLE_LICENSE_HEADER_START@
*
* 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 2.0 (the 'License'). You may not use this file except in
* compliance with the License. Please obtain a copy of the License at
* http://www.opensource.apple.com/apsl/ 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, QUIET ENJOYMENT OR NON-INFRINGEMENT.
* Please see the License for the specific language governing rights and
* limitations under the License.
*
* @APPLE_LICENSE_HEADER_END@
*/
/*
objc-opt.mm
Management of optimizations in the dyld shared cache
*/
#include "objc-private.h"
#if !SUPPORT_PREOPT
// Preoptimization not supported on this platform.
struct objc_selopt_t;
bool isPreoptimized(void)
{
return false;
}
bool noMissingWeakSuperclasses(void)
{
return false;
}
bool header_info::isPreoptimized() const
{
return false;
}
objc_selopt_t *preoptimizedSelectors(void)
{
return nil;
}
Protocol *getPreoptimizedProtocol(const char *name)
{
return nil;
}
Class getPreoptimizedClass(const char *name)
{
return nil;
}
Class* copyPreoptimizedClasses(const char *name, int *outCount)
{
*outCount = 0;
return nil;
}
header_info *preoptimizedHinfoForHeader(const headerType *mhdr)
{
return nil;
}
header_info_rw *getPreoptimizedHeaderRW(const struct header_info *const hdr)
{
return nil;
}
void preopt_init(void)
{
disableSharedCacheOptimizations();
if (PrintPreopt) {
_objc_inform("PREOPTIMIZATION: is DISABLED "
"(not supported on ths platform)");
}
}
// !SUPPORT_PREOPT
#else
// SUPPORT_PREOPT
#include <objc-shared-cache.h>
using objc_opt::objc_stringhash_offset_t;
using objc_opt::objc_protocolopt_t;
using objc_opt::objc_clsopt_t;
using objc_opt::objc_headeropt_ro_t;
using objc_opt::objc_headeropt_rw_t;
using objc_opt::objc_opt_t;
__BEGIN_DECLS
// preopt: the actual opt used at runtime (nil or &_objc_opt_data)
// _objc_opt_data: opt data possibly written by dyld
// opt is initialized to ~0 to detect incorrect use before preopt_init()
static const objc_opt_t *opt = (objc_opt_t *)~0;
static bool preoptimized;
extern const objc_opt_t _objc_opt_data; // in __TEXT, __objc_opt_ro
/***********************************************************************
* Return YES if we have a valid optimized shared cache.
**********************************************************************/
bool isPreoptimized(void)
{
return preoptimized;
}
/***********************************************************************
* Return YES if the shared cache does not have any classes with
* missing weak superclasses.
**********************************************************************/
bool noMissingWeakSuperclasses(void)
{
if (!preoptimized) return NO; // might have missing weak superclasses
return opt->flags & objc_opt::NoMissingWeakSuperclasses;
}
/***********************************************************************
* Return YES if this image's dyld shared cache optimizations are valid.
**********************************************************************/
bool header_info::isPreoptimized() const
{
// preoptimization disabled for some reason
if (!preoptimized) return NO;
// image not from shared cache, or not fixed inside shared cache
if (!info()->optimizedByDyld()) return NO;
return YES;
}
objc_selopt_t *preoptimizedSelectors(void)
{
return opt ? opt->selopt() : nil;
}
Protocol *getPreoptimizedProtocol(const char *name)
{
objc_protocolopt_t *protocols = opt ? opt->protocolopt() : nil;
if (!protocols) return nil;
return (Protocol *)protocols->getProtocol(name);
}
Class getPreoptimizedClass(const char *name)
{
objc_clsopt_t *classes = opt ? opt->clsopt() : nil;
if (!classes) return nil;
void *cls;
void *hi;
uint32_t count = classes->getClassAndHeader(name, cls, hi);
if (count == 1 && ((header_info *)hi)->isLoaded()) {
// exactly one matching class, and its image is loaded
return (Class)cls;
}
else if (count > 1) {
// more than one matching class - find one that is loaded
void *clslist[count];
void *hilist[count];
classes->getClassesAndHeaders(name, clslist, hilist);
for (uint32_t i = 0; i < count; i++) {
if (((header_info *)hilist[i])->isLoaded()) {
return (Class)clslist[i];
}
}
}
// no match that is loaded
return nil;
}
Class* copyPreoptimizedClasses(const char *name, int *outCount)
{
*outCount = 0;
objc_clsopt_t *classes = opt ? opt->clsopt() : nil;
if (!classes) return nil;
void *cls;
void *hi;
uint32_t count = classes->getClassAndHeader(name, cls, hi);
if (count == 0) return nil;
Class *result = (Class *)calloc(count, sizeof(Class));
if (count == 1 && ((header_info *)hi)->isLoaded()) {
// exactly one matching class, and its image is loaded
result[(*outCount)++] = (Class)cls;
return result;
}
else if (count > 1) {
// more than one matching class - find those that are loaded
void *clslist[count];
void *hilist[count];
classes->getClassesAndHeaders(name, clslist, hilist);
for (uint32_t i = 0; i < count; i++) {
if (((header_info *)hilist[i])->isLoaded()) {
result[(*outCount)++] = (Class)clslist[i];
}
}
if (*outCount == 0) {
// found multiple classes with that name, but none are loaded
free(result);
result = nil;
}
return result;
}
// no match that is loaded
return nil;
}
namespace objc_opt {
struct objc_headeropt_ro_t {
uint32_t count;
uint32_t entsize;
header_info headers[0]; // sorted by mhdr address
header_info *get(const headerType *mhdr)
{
assert(entsize == sizeof(header_info));
int32_t start = 0;
int32_t end = count;
while (start <= end) {
int32_t i = (start+end)/2;
header_info *hi = headers+i;
if (mhdr == hi->mhdr()) return hi;
else if (mhdr < hi->mhdr()) end = i-1;
else start = i+1;
}
#if DEBUG
for (uint32_t i = 0; i < count; i++) {
header_info *hi = headers+i;
if (mhdr == hi->mhdr()) {
_objc_fatal("failed to find header %p (%d/%d)",
mhdr, i, count);
}
}
#endif
return nil;
}
};
struct objc_headeropt_rw_t {
uint32_t count;
uint32_t entsize;
header_info_rw headers[0]; // sorted by mhdr address
};
};
header_info *preoptimizedHinfoForHeader(const headerType *mhdr)
{
#if !__OBJC2__
// fixme old ABI shared cache doesn't prepare these properly
return nil;
#endif
objc_headeropt_ro_t *hinfos = opt ? opt->headeropt_ro() : nil;
if (hinfos) return hinfos->get(mhdr);
else return nil;
}
header_info_rw *getPreoptimizedHeaderRW(const struct header_info *const hdr)
{
#if !__OBJC2__
// fixme old ABI shared cache doesn't prepare these properly
return nil;
#endif
objc_headeropt_ro_t *hinfoRO = opt ? opt->headeropt_ro() : nil;
objc_headeropt_rw_t *hinfoRW = opt ? opt->headeropt_rw() : nil;
if (!hinfoRO || !hinfoRW) {
_objc_fatal("preoptimized header_info missing for %s (%p %p %p)",
hdr->fname(), hdr, hinfoRO, hinfoRW);
}
int32_t index = (int32_t)(hdr - hinfoRO->headers);
assert(hinfoRW->entsize == sizeof(header_info_rw));
return &hinfoRW->headers[index];
}
void preopt_init(void)
{
// `opt` not set at compile time in order to detect too-early usage
const char *failure = nil;
opt = &_objc_opt_data;
if (DisablePreopt) {
// OBJC_DISABLE_PREOPTIMIZATION is set
// If opt->version != VERSION then you continue at your own risk.
failure = "(by OBJC_DISABLE_PREOPTIMIZATION)";
}
else if (opt->version != objc_opt::VERSION) {
// This shouldn't happen. You probably forgot to edit objc-sel-table.s.
// If dyld really did write the wrong optimization version,
// then we must halt because we don't know what bits dyld twiddled.
_objc_fatal("bad objc preopt version (want %d, got %d)",
objc_opt::VERSION, opt->version);
}
else if (!opt->selopt() || !opt->headeropt_ro()) {
// One of the tables is missing.
failure = "(dyld shared cache is absent or out of date)";
}
if (failure) {
// All preoptimized selector references are invalid.
preoptimized = NO;
opt = nil;
disableSharedCacheOptimizations();
if (PrintPreopt) {
_objc_inform("PREOPTIMIZATION: is DISABLED %s", failure);
}
}
else {
// Valid optimization data written by dyld shared cache
preoptimized = YES;
if (PrintPreopt) {
_objc_inform("PREOPTIMIZATION: is ENABLED "
"(version %d)", opt->version);
}
}
}
__END_DECLS
// SUPPORT_PREOPT
#endif

1225
runtime/objc-os.h Normal file

File diff suppressed because it is too large Load Diff

778
runtime/objc-os.mm Normal file
View File

@ -0,0 +1,778 @@
/*
* Copyright (c) 2007 Apple Inc. All Rights Reserved.
*
* @APPLE_LICENSE_HEADER_START@
*
* 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 2.0 (the 'License'). You may not use this file except in
* compliance with the License. Please obtain a copy of the License at
* http://www.opensource.apple.com/apsl/ 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, QUIET ENJOYMENT OR NON-INFRINGEMENT.
* Please see the License for the specific language governing rights and
* limitations under the License.
*
* @APPLE_LICENSE_HEADER_END@
*/
/***********************************************************************
* objc-os.m
* OS portability layer.
**********************************************************************/
#include "objc-private.h"
#include "objc-loadmethod.h"
#if TARGET_OS_WIN32
#include "objc-runtime-old.h"
#include "objcrt.h"
int monitor_init(monitor_t *c)
{
// fixme error checking
HANDLE mutex = CreateMutex(NULL, TRUE, NULL);
while (!c->mutex) {
// fixme memory barrier here?
if (0 == InterlockedCompareExchangePointer(&c->mutex, mutex, 0)) {
// we win - finish construction
c->waiters = CreateSemaphore(NULL, 0, 0x7fffffff, NULL);
c->waitersDone = CreateEvent(NULL, FALSE, FALSE, NULL);
InitializeCriticalSection(&c->waitCountLock);
c->waitCount = 0;
c->didBroadcast = 0;
ReleaseMutex(c->mutex);
return 0;
}
}
// someone else allocated the mutex and constructed the monitor
ReleaseMutex(mutex);
CloseHandle(mutex);
return 0;
}
void mutex_init(mutex_t *m)
{
while (!m->lock) {
CRITICAL_SECTION *newlock = malloc(sizeof(CRITICAL_SECTION));
InitializeCriticalSection(newlock);
// fixme memory barrier here?
if (0 == InterlockedCompareExchangePointer(&m->lock, newlock, 0)) {
return;
}
// someone else installed their lock first
DeleteCriticalSection(newlock);
free(newlock);
}
}
void recursive_mutex_init(recursive_mutex_t *m)
{
// fixme error checking
HANDLE newmutex = CreateMutex(NULL, FALSE, NULL);
while (!m->mutex) {
// fixme memory barrier here?
if (0 == InterlockedCompareExchangePointer(&m->mutex, newmutex, 0)) {
// we win
return;
}
}
// someone else installed their lock first
CloseHandle(newmutex);
}
WINBOOL APIENTRY DllMain( HMODULE hModule,
DWORD ul_reason_for_call,
LPVOID lpReserved
)
{
switch (ul_reason_for_call) {
case DLL_PROCESS_ATTACH:
environ_init();
tls_init();
lock_init();
sel_init(3500); // old selector heuristic
exception_init();
break;
case DLL_THREAD_ATTACH:
break;
case DLL_THREAD_DETACH:
case DLL_PROCESS_DETACH:
break;
}
return TRUE;
}
OBJC_EXPORT void *_objc_init_image(HMODULE image, const objc_sections *sects)
{
header_info *hi = malloc(sizeof(header_info));
size_t count, i;
hi->mhdr = (const headerType *)image;
hi->info = sects->iiStart;
hi->allClassesRealized = NO;
hi->modules = sects->modStart ? (Module *)((void **)sects->modStart+1) : 0;
hi->moduleCount = (Module *)sects->modEnd - hi->modules;
hi->protocols = sects->protoStart ? (struct old_protocol **)((void **)sects->protoStart+1) : 0;
hi->protocolCount = (struct old_protocol **)sects->protoEnd - hi->protocols;
hi->imageinfo = NULL;
hi->imageinfoBytes = 0;
// hi->imageinfo = sects->iiStart ? (uint8_t *)((void **)sects->iiStart+1) : 0;;
// hi->imageinfoBytes = (uint8_t *)sects->iiEnd - hi->imageinfo;
hi->selrefs = sects->selrefsStart ? (SEL *)((void **)sects->selrefsStart+1) : 0;
hi->selrefCount = (SEL *)sects->selrefsEnd - hi->selrefs;
hi->clsrefs = sects->clsrefsStart ? (Class *)((void **)sects->clsrefsStart+1) : 0;
hi->clsrefCount = (Class *)sects->clsrefsEnd - hi->clsrefs;
count = 0;
for (i = 0; i < hi->moduleCount; i++) {
if (hi->modules[i]) count++;
}
hi->mod_count = 0;
hi->mod_ptr = 0;
if (count > 0) {
hi->mod_ptr = malloc(count * sizeof(struct objc_module));
for (i = 0; i < hi->moduleCount; i++) {
if (hi->modules[i]) memcpy(&hi->mod_ptr[hi->mod_count++], hi->modules[i], sizeof(struct objc_module));
}
}
hi->moduleName = malloc(MAX_PATH * sizeof(TCHAR));
GetModuleFileName((HMODULE)(hi->mhdr), hi->moduleName, MAX_PATH * sizeof(TCHAR));
appendHeader(hi);
if (PrintImages) {
_objc_inform("IMAGES: loading image for %s%s%s%s\n",
hi->fname,
headerIsBundle(hi) ? " (bundle)" : "",
hi->info->isReplacement() ? " (replacement)":"",
hi->info->hasCategoryClassProperties() ? " (has class properties)":"");
}
// Count classes. Size various table based on the total.
int total = 0;
int unoptimizedTotal = 0;
{
if (_getObjc2ClassList(hi, &count)) {
total += (int)count;
if (!hi->getInSharedCache()) unoptimizedTotal += count;
}
}
_read_images(&hi, 1, total, unoptimizedTotal);
return hi;
}
OBJC_EXPORT void _objc_load_image(HMODULE image, header_info *hinfo)
{
prepare_load_methods(hinfo);
call_load_methods();
}
OBJC_EXPORT void _objc_unload_image(HMODULE image, header_info *hinfo)
{
_objc_fatal("image unload not supported");
}
// TARGET_OS_WIN32
#elif TARGET_OS_MAC
#include "objc-file-old.h"
#include "objc-file.h"
/***********************************************************************
* libobjc must never run static destructors.
* Cover libc's __cxa_atexit with our own definition that runs nothing.
* rdar://21734598 ER: Compiler option to suppress C++ static destructors
**********************************************************************/
extern "C" int __cxa_atexit();
extern "C" int __cxa_atexit() { return 0; }
/***********************************************************************
* bad_magic.
* Return YES if the header has invalid Mach-o magic.
**********************************************************************/
bool bad_magic(const headerType *mhdr)
{
return (mhdr->magic != MH_MAGIC && mhdr->magic != MH_MAGIC_64 &&
mhdr->magic != MH_CIGAM && mhdr->magic != MH_CIGAM_64);
}
static header_info * addHeader(const headerType *mhdr, const char *path, int &totalClasses, int &unoptimizedTotalClasses)
{
header_info *hi;
if (bad_magic(mhdr)) return NULL;
bool inSharedCache = false;
// Look for hinfo from the dyld shared cache.
hi = preoptimizedHinfoForHeader(mhdr);
if (hi) {
// Found an hinfo in the dyld shared cache.
// Weed out duplicates.
if (hi->isLoaded()) {
return NULL;
}
inSharedCache = true;
// Initialize fields not set by the shared cache
// hi->next is set by appendHeader
hi->setLoaded(true);
if (PrintPreopt) {
_objc_inform("PREOPTIMIZATION: honoring preoptimized header info at %p for %s", hi, hi->fname());
}
#if !__OBJC2__
_objc_fatal("shouldn't be here");
#endif
#if DEBUG
// Verify image_info
size_t info_size = 0;
const objc_image_info *image_info = _getObjcImageInfo(mhdr,&info_size);
assert(image_info == hi->info());
#endif
}
else
{
// Didn't find an hinfo in the dyld shared cache.
// Weed out duplicates
for (hi = FirstHeader; hi; hi = hi->getNext()) {
if (mhdr == hi->mhdr()) return NULL;
}
// Locate the __OBJC segment
size_t info_size = 0;
unsigned long seg_size;
const objc_image_info *image_info = _getObjcImageInfo(mhdr,&info_size);
const uint8_t *objc_segment = getsegmentdata(mhdr,SEG_OBJC,&seg_size);
if (!objc_segment && !image_info) return NULL;
// Allocate a header_info entry.
// Note we also allocate space for a single header_info_rw in the
// rw_data[] inside header_info.
hi = (header_info *)calloc(sizeof(header_info) + sizeof(header_info_rw), 1);
// Set up the new header_info entry.
hi->setmhdr(mhdr);
#if !__OBJC2__
// mhdr must already be set
hi->mod_count = 0;
hi->mod_ptr = _getObjcModules(hi, &hi->mod_count);
#endif
// Install a placeholder image_info if absent to simplify code elsewhere
static const objc_image_info emptyInfo = {0, 0};
hi->setinfo(image_info ?: &emptyInfo);
hi->setLoaded(true);
hi->setAllClassesRealized(NO);
}
#if __OBJC2__
{
size_t count = 0;
if (_getObjc2ClassList(hi, &count)) {
totalClasses += (int)count;
if (!inSharedCache) unoptimizedTotalClasses += count;
}
}
#endif
appendHeader(hi);
return hi;
}
/***********************************************************************
* linksToLibrary
* Returns true if the image links directly to a dylib whose install name
* is exactly the given name.
**********************************************************************/
bool
linksToLibrary(const header_info *hi, const char *name)
{
const struct dylib_command *cmd;
unsigned long i;
cmd = (const struct dylib_command *) (hi->mhdr() + 1);
for (i = 0; i < hi->mhdr()->ncmds; i++) {
if (cmd->cmd == LC_LOAD_DYLIB || cmd->cmd == LC_LOAD_UPWARD_DYLIB ||
cmd->cmd == LC_LOAD_WEAK_DYLIB || cmd->cmd == LC_REEXPORT_DYLIB)
{
const char *dylib = cmd->dylib.name.offset + (const char *)cmd;
if (0 == strcmp(dylib, name)) return true;
}
cmd = (const struct dylib_command *)((char *)cmd + cmd->cmdsize);
}
return false;
}
#if SUPPORT_GC_COMPAT
/***********************************************************************
* shouldRejectGCApp
* Return YES if the executable requires GC.
**********************************************************************/
static bool shouldRejectGCApp(const header_info *hi)
{
assert(hi->mhdr()->filetype == MH_EXECUTE);
if (!hi->info()->supportsGC()) {
// App does not use GC. Don't reject it.
return NO;
}
// Exception: Trivial AppleScriptObjC apps can run without GC.
// 1. executable defines no classes
// 2. executable references NSBundle only
// 3. executable links to AppleScriptObjC.framework
// Note that objc_appRequiresGC() also knows about this.
size_t classcount = 0;
size_t refcount = 0;
#if __OBJC2__
_getObjc2ClassList(hi, &classcount);
_getObjc2ClassRefs(hi, &refcount);
#else
if (hi->mod_count == 0 || (hi->mod_count == 1 && !hi->mod_ptr[0].symtab)) classcount = 0;
else classcount = 1;
_getObjcClassRefs(hi, &refcount);
#endif
if (classcount == 0 && refcount == 1 &&
linksToLibrary(hi, "/System/Library/Frameworks"
"/AppleScriptObjC.framework/Versions/A"
"/AppleScriptObjC"))
{
// It's AppleScriptObjC. Don't reject it.
return NO;
}
else {
// GC and not trivial AppleScriptObjC. Reject it.
return YES;
}
}
/***********************************************************************
* rejectGCImage
* Halt if an image requires GC.
* Testing of the main executable should use rejectGCApp() instead.
**********************************************************************/
static bool shouldRejectGCImage(const headerType *mhdr)
{
assert(mhdr->filetype != MH_EXECUTE);
objc_image_info *image_info;
size_t size;
#if !__OBJC2__
unsigned long seg_size;
// 32-bit: __OBJC seg but no image_info means no GC support
if (!getsegmentdata(mhdr, "__OBJC", &seg_size)) {
// Not objc, therefore not GC. Don't reject it.
return NO;
}
image_info = _getObjcImageInfo(mhdr, &size);
if (!image_info) {
// No image_info, therefore not GC. Don't reject it.
return NO;
}
#else
// 64-bit: no image_info means no objc at all
image_info = _getObjcImageInfo(mhdr, &size);
if (!image_info) {
// Not objc, therefore not GC. Don't reject it.
return NO;
}
#endif
return image_info->requiresGC();
}
// SUPPORT_GC_COMPAT
#endif
/***********************************************************************
* map_images_nolock
* Process the given images which are being mapped in by dyld.
* All class registration and fixups are performed (or deferred pending
* discovery of missing superclasses etc), and +load methods are called.
*
* info[] is in bottom-up order i.e. libobjc will be earlier in the
* array than any library that links to libobjc.
*
* Locking: loadMethodLock(old) or runtimeLock(new) acquired by map_images.
**********************************************************************/
#if __OBJC2__
#include "objc-file.h"
#else
#include "objc-file-old.h"
#endif
void
map_images_nolock(unsigned mhCount, const char * const mhPaths[],
const struct mach_header * const mhdrs[])
{
static bool firstTime = YES;
header_info *hList[mhCount];
uint32_t hCount;
size_t selrefCount = 0;
// Perform first-time initialization if necessary.
// This function is called before ordinary library initializers.
// fixme defer initialization until an objc-using image is found?
if (firstTime) {
preopt_init();
}
if (PrintImages) {
_objc_inform("IMAGES: processing %u newly-mapped images...\n", mhCount);
}
// Find all images with Objective-C metadata.
hCount = 0;
// Count classes. Size various table based on the total.
int totalClasses = 0;
int unoptimizedTotalClasses = 0;
{
uint32_t i = mhCount;
while (i--) {
const headerType *mhdr = (const headerType *)mhdrs[i];
auto hi = addHeader(mhdr, mhPaths[i], totalClasses, unoptimizedTotalClasses);
if (!hi) {
// no objc data in this entry
continue;
}
if (mhdr->filetype == MH_EXECUTE) {
// Size some data structures based on main executable's size
#if __OBJC2__
size_t count;
_getObjc2SelectorRefs(hi, &count);
selrefCount += count;
_getObjc2MessageRefs(hi, &count);
selrefCount += count;
#else
_getObjcSelectorRefs(hi, &selrefCount);
#endif
#if SUPPORT_GC_COMPAT
// Halt if this is a GC app.
if (shouldRejectGCApp(hi)) {
_objc_fatal_with_reason
(OBJC_EXIT_REASON_GC_NOT_SUPPORTED,
OS_REASON_FLAG_CONSISTENT_FAILURE,
"Objective-C garbage collection "
"is no longer supported.");
}
#endif
}
hList[hCount++] = hi;
if (PrintImages) {
_objc_inform("IMAGES: loading image for %s%s%s%s%s\n",
hi->fname(),
mhdr->filetype == MH_BUNDLE ? " (bundle)" : "",
hi->info()->isReplacement() ? " (replacement)" : "",
hi->info()->hasCategoryClassProperties() ? " (has class properties)" : "",
hi->info()->optimizedByDyld()?" (preoptimized)":"");
}
}
}
// Perform one-time runtime initialization that must be deferred until
// the executable itself is found. This needs to be done before
// further initialization.
// (The executable may not be present in this infoList if the
// executable does not contain Objective-C code but Objective-C
// is dynamically loaded later.
if (firstTime) {
sel_init(selrefCount);
arr_init();
#if SUPPORT_GC_COMPAT
// Reject any GC images linked to the main executable.
// We already rejected the app itself above.
// Images loaded after launch will be rejected by dyld.
for (uint32_t i = 0; i < hCount; i++) {
auto hi = hList[i];
auto mh = hi->mhdr();
if (mh->filetype != MH_EXECUTE && shouldRejectGCImage(mh)) {
_objc_fatal_with_reason
(OBJC_EXIT_REASON_GC_NOT_SUPPORTED,
OS_REASON_FLAG_CONSISTENT_FAILURE,
"%s requires Objective-C garbage collection "
"which is no longer supported.", hi->fname());
}
}
#endif
}
if (hCount > 0) {
_read_images(hList, hCount, totalClasses, unoptimizedTotalClasses);
}
firstTime = NO;
}
/***********************************************************************
* unmap_image_nolock
* Process the given image which is about to be unmapped by dyld.
* mh is mach_header instead of headerType because that's what
* dyld_priv.h says even for 64-bit.
*
* Locking: loadMethodLock(both) and runtimeLock(new) acquired by unmap_image.
**********************************************************************/
void
unmap_image_nolock(const struct mach_header *mh)
{
if (PrintImages) {
_objc_inform("IMAGES: processing 1 newly-unmapped image...\n");
}
header_info *hi;
// Find the runtime's header_info struct for the image
for (hi = FirstHeader; hi != NULL; hi = hi->getNext()) {
if (hi->mhdr() == (const headerType *)mh) {
break;
}
}
if (!hi) return;
if (PrintImages) {
_objc_inform("IMAGES: unloading image for %s%s%s\n",
hi->fname(),
hi->mhdr()->filetype == MH_BUNDLE ? " (bundle)" : "",
hi->info()->isReplacement() ? " (replacement)" : "");
}
_unload_image(hi);
// Remove header_info from header list
removeHeader(hi);
free(hi);
}
/***********************************************************************
* static_init
* Run C++ static constructor functions.
* libc calls _objc_init() before dyld would call our static constructors,
* so we have to do it ourselves.
**********************************************************************/
static void static_init()
{
size_t count;
Initializer *inits = getLibobjcInitializers(&_mh_dylib_header, &count);
for (size_t i = 0; i < count; i++) {
inits[i]();
}
}
/***********************************************************************
* _objc_init
* Bootstrap initialization. Registers our image notifier with dyld.
* Called by libSystem BEFORE library initialization time
**********************************************************************/
void _objc_init(void)
{
static bool initialized = false;
if (initialized) return;
initialized = true;
// fixme defer initialization until an objc-using image is found?
environ_init();
tls_init();
static_init();
lock_init();
exception_init();
_dyld_objc_notify_register(&map_2_images, load_images, unmap_image);
}
/***********************************************************************
* _headerForAddress.
* addr can be a class or a category
**********************************************************************/
static const header_info *_headerForAddress(void *addr)
{
#if __OBJC2__
const char *segnames[] = { "__DATA", "__DATA_CONST", "__DATA_DIRTY" };
#else
const char *segnames[] = { "__OBJC" };
#endif
header_info *hi;
for (hi = FirstHeader; hi != NULL; hi = hi->getNext()) {
for (size_t i = 0; i < sizeof(segnames)/sizeof(segnames[0]); i++) {
unsigned long seg_size;
uint8_t *seg = getsegmentdata(hi->mhdr(), segnames[i], &seg_size);
if (!seg) continue;
// Is the class in this header?
if ((uint8_t *)addr >= seg && (uint8_t *)addr < seg + seg_size) {
return hi;
}
}
}
// Not found
return 0;
}
/***********************************************************************
* _headerForClass
* Return the image header containing this class, or NULL.
* Returns NULL on runtime-constructed classes, and the NSCF classes.
**********************************************************************/
const header_info *_headerForClass(Class cls)
{
return _headerForAddress(cls);
}
/**********************************************************************
* secure_open
* Securely open a file from a world-writable directory (like /tmp)
* If the file does not exist, it will be atomically created with mode 0600
* If the file exists, it must be, and remain after opening:
* 1. a regular file (in particular, not a symlink)
* 2. owned by euid
* 3. permissions 0600
* 4. link count == 1
* Returns a file descriptor or -1. Errno may or may not be set on error.
**********************************************************************/
int secure_open(const char *filename, int flags, uid_t euid)
{
struct stat fs, ls;
int fd = -1;
bool truncate = NO;
bool create = NO;
if (flags & O_TRUNC) {
// Don't truncate the file until after it is open and verified.
truncate = YES;
flags &= ~O_TRUNC;
}
if (flags & O_CREAT) {
// Don't create except when we're ready for it
create = YES;
flags &= ~O_CREAT;
flags &= ~O_EXCL;
}
if (lstat(filename, &ls) < 0) {
if (errno == ENOENT && create) {
// No such file - create it
fd = open(filename, flags | O_CREAT | O_EXCL, 0600);
if (fd >= 0) {
// File was created successfully.
// New file does not need to be truncated.
return fd;
} else {
// File creation failed.
return -1;
}
} else {
// lstat failed, or user doesn't want to create the file
return -1;
}
} else {
// lstat succeeded - verify attributes and open
if (S_ISREG(ls.st_mode) && // regular file?
ls.st_nlink == 1 && // link count == 1?
ls.st_uid == euid && // owned by euid?
(ls.st_mode & ALLPERMS) == (S_IRUSR | S_IWUSR)) // mode 0600?
{
// Attributes look ok - open it and check attributes again
fd = open(filename, flags, 0000);
if (fd >= 0) {
// File is open - double-check attributes
if (0 == fstat(fd, &fs) &&
fs.st_nlink == ls.st_nlink && // link count == 1?
fs.st_uid == ls.st_uid && // owned by euid?
fs.st_mode == ls.st_mode && // regular file, 0600?
fs.st_ino == ls.st_ino && // same inode as before?
fs.st_dev == ls.st_dev) // same device as before?
{
// File is open and OK
if (truncate) ftruncate(fd, 0);
return fd;
} else {
// Opened file looks funny - close it
close(fd);
return -1;
}
} else {
// File didn't open
return -1;
}
} else {
// Unopened file looks funny - don't open it
return -1;
}
}
}
#if TARGET_OS_IPHONE
const char *__crashreporter_info__ = NULL;
const char *CRSetCrashLogMessage(const char *msg)
{
__crashreporter_info__ = msg;
return msg;
}
const char *CRGetCrashLogMessage(void)
{
return __crashreporter_info__;
}
#endif
// TARGET_OS_MAC
#else
#error unknown OS
#endif

1022
runtime/objc-private.h Normal file

File diff suppressed because it is too large Load Diff

5
runtime/objc-probes.d Normal file
View File

@ -0,0 +1,5 @@
provider objc_runtime
{
probe objc_exception_throw(void *id);
probe objc_exception_rethrow();
};

41
runtime/objc-references.h Normal file
View File

@ -0,0 +1,41 @@
/*
* Copyright (c) 2008 Apple Inc. All Rights Reserved.
*
* @APPLE_LICENSE_HEADER_START@
*
* 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 2.0 (the 'License'). You may not use this file except in
* compliance with the License. Please obtain a copy of the License at
* http://www.opensource.apple.com/apsl/ 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, QUIET ENJOYMENT OR NON-INFRINGEMENT.
* Please see the License for the specific language governing rights and
* limitations under the License.
*
* @APPLE_LICENSE_HEADER_END@
*/
/*
* objc-references.h
*/
#ifndef _OBJC_REFERENCES_H_
#define _OBJC_REFERENCES_H_
#include "objc-api.h"
#include "objc-config.h"
__BEGIN_DECLS
extern void _object_set_associative_reference(id object, void *key, id value, uintptr_t policy);
extern id _object_get_associative_reference(id object, void *key);
extern void _object_remove_assocations(id object);
__END_DECLS
#endif

334
runtime/objc-references.mm Normal file
View File

@ -0,0 +1,334 @@
/*
* Copyright (c) 2004-2007 Apple Inc. All rights reserved.
*
* @APPLE_LICENSE_HEADER_START@
*
* 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 2.0 (the 'License'). You may not use this file except in
* compliance with the License. Please obtain a copy of the License at
* http://www.opensource.apple.com/apsl/ 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, QUIET ENJOYMENT OR NON-INFRINGEMENT.
* Please see the License for the specific language governing rights and
* limitations under the License.
*
* @APPLE_LICENSE_HEADER_END@
*/
/*
Implementation of the weak / associative references for non-GC mode.
*/
#include "objc-private.h"
#include <objc/message.h>
#include <map>
#if _LIBCPP_VERSION
# include <unordered_map>
#else
# include <tr1/unordered_map>
using namespace tr1;
#endif
// wrap all the murky C++ details in a namespace to get them out of the way.
namespace objc_references_support {
struct DisguisedPointerEqual {
bool operator()(uintptr_t p1, uintptr_t p2) const {
return p1 == p2;
}
};
struct DisguisedPointerHash {
uintptr_t operator()(uintptr_t k) const {
// borrowed from CFSet.c
#if __LP64__
uintptr_t a = 0x4368726973746F70ULL;
uintptr_t b = 0x686572204B616E65ULL;
#else
uintptr_t a = 0x4B616E65UL;
uintptr_t b = 0x4B616E65UL;
#endif
uintptr_t c = 1;
a += k;
#if __LP64__
a -= b; a -= c; a ^= (c >> 43);
b -= c; b -= a; b ^= (a << 9);
c -= a; c -= b; c ^= (b >> 8);
a -= b; a -= c; a ^= (c >> 38);
b -= c; b -= a; b ^= (a << 23);
c -= a; c -= b; c ^= (b >> 5);
a -= b; a -= c; a ^= (c >> 35);
b -= c; b -= a; b ^= (a << 49);
c -= a; c -= b; c ^= (b >> 11);
a -= b; a -= c; a ^= (c >> 12);
b -= c; b -= a; b ^= (a << 18);
c -= a; c -= b; c ^= (b >> 22);
#else
a -= b; a -= c; a ^= (c >> 13);
b -= c; b -= a; b ^= (a << 8);
c -= a; c -= b; c ^= (b >> 13);
a -= b; a -= c; a ^= (c >> 12);
b -= c; b -= a; b ^= (a << 16);
c -= a; c -= b; c ^= (b >> 5);
a -= b; a -= c; a ^= (c >> 3);
b -= c; b -= a; b ^= (a << 10);
c -= a; c -= b; c ^= (b >> 15);
#endif
return c;
}
};
struct ObjectPointerLess {
bool operator()(const void *p1, const void *p2) const {
return p1 < p2;
}
};
struct ObjcPointerHash {
uintptr_t operator()(void *p) const {
return DisguisedPointerHash()(uintptr_t(p));
}
};
// STL allocator that uses the runtime's internal allocator.
template <typename T> struct ObjcAllocator {
typedef T value_type;
typedef value_type* pointer;
typedef const value_type *const_pointer;
typedef value_type& reference;
typedef const value_type& const_reference;
typedef size_t size_type;
typedef ptrdiff_t difference_type;
template <typename U> struct rebind { typedef ObjcAllocator<U> other; };
template <typename U> ObjcAllocator(const ObjcAllocator<U>&) {}
ObjcAllocator() {}
ObjcAllocator(const ObjcAllocator&) {}
~ObjcAllocator() {}
pointer address(reference x) const { return &x; }
const_pointer address(const_reference x) const {
return x;
}
pointer allocate(size_type n, const_pointer = 0) {
return static_cast<pointer>(::malloc(n * sizeof(T)));
}
void deallocate(pointer p, size_type) { ::free(p); }
size_type max_size() const {
return static_cast<size_type>(-1) / sizeof(T);
}
void construct(pointer p, const value_type& x) {
new(p) value_type(x);
}
void destroy(pointer p) { p->~value_type(); }
void operator=(const ObjcAllocator&);
};
template<> struct ObjcAllocator<void> {
typedef void value_type;
typedef void* pointer;
typedef const void *const_pointer;
template <typename U> struct rebind { typedef ObjcAllocator<U> other; };
};
typedef uintptr_t disguised_ptr_t;
inline disguised_ptr_t DISGUISE(id value) { return ~uintptr_t(value); }
inline id UNDISGUISE(disguised_ptr_t dptr) { return id(~dptr); }
class ObjcAssociation {
uintptr_t _policy;
id _value;
public:
ObjcAssociation(uintptr_t policy, id value) : _policy(policy), _value(value) {}
ObjcAssociation() : _policy(0), _value(nil) {}
uintptr_t policy() const { return _policy; }
id value() const { return _value; }
bool hasValue() { return _value != nil; }
};
#if TARGET_OS_WIN32
typedef hash_map<void *, ObjcAssociation> ObjectAssociationMap;
typedef hash_map<disguised_ptr_t, ObjectAssociationMap *> AssociationsHashMap;
#else
typedef ObjcAllocator<std::pair<void * const, ObjcAssociation> > ObjectAssociationMapAllocator;
class ObjectAssociationMap : public std::map<void *, ObjcAssociation, ObjectPointerLess, ObjectAssociationMapAllocator> {
public:
void *operator new(size_t n) { return ::malloc(n); }
void operator delete(void *ptr) { ::free(ptr); }
};
typedef ObjcAllocator<std::pair<const disguised_ptr_t, ObjectAssociationMap*> > AssociationsHashMapAllocator;
class AssociationsHashMap : public unordered_map<disguised_ptr_t, ObjectAssociationMap *, DisguisedPointerHash, DisguisedPointerEqual, AssociationsHashMapAllocator> {
public:
void *operator new(size_t n) { return ::malloc(n); }
void operator delete(void *ptr) { ::free(ptr); }
};
#endif
}
using namespace objc_references_support;
// class AssociationsManager manages a lock / hash table singleton pair.
// Allocating an instance acquires the lock, and calling its assocations() method
// lazily allocates it.
class AssociationsManager {
static spinlock_t _lock;
static AssociationsHashMap *_map; // associative references: object pointer -> PtrPtrHashMap.
public:
AssociationsManager() { _lock.lock(); }
~AssociationsManager() { _lock.unlock(); }
AssociationsHashMap &associations() {
if (_map == NULL)
_map = new AssociationsHashMap();
return *_map;
}
};
spinlock_t AssociationsManager::_lock;
AssociationsHashMap *AssociationsManager::_map = NULL;
// expanded policy bits.
enum {
OBJC_ASSOCIATION_SETTER_ASSIGN = 0,
OBJC_ASSOCIATION_SETTER_RETAIN = 1,
OBJC_ASSOCIATION_SETTER_COPY = 3, // NOTE: both bits are set, so we can simply test 1 bit in releaseValue below.
OBJC_ASSOCIATION_GETTER_READ = (0 << 8),
OBJC_ASSOCIATION_GETTER_RETAIN = (1 << 8),
OBJC_ASSOCIATION_GETTER_AUTORELEASE = (2 << 8)
};
id _object_get_associative_reference(id object, void *key) {
id value = nil;
uintptr_t policy = OBJC_ASSOCIATION_ASSIGN;
{
AssociationsManager manager;
AssociationsHashMap &associations(manager.associations());
disguised_ptr_t disguised_object = DISGUISE(object);
AssociationsHashMap::iterator i = associations.find(disguised_object);
if (i != associations.end()) {
ObjectAssociationMap *refs = i->second;
ObjectAssociationMap::iterator j = refs->find(key);
if (j != refs->end()) {
ObjcAssociation &entry = j->second;
value = entry.value();
policy = entry.policy();
if (policy & OBJC_ASSOCIATION_GETTER_RETAIN) ((id(*)(id, SEL))objc_msgSend)(value, SEL_retain);
}
}
}
if (value && (policy & OBJC_ASSOCIATION_GETTER_AUTORELEASE)) {
((id(*)(id, SEL))objc_msgSend)(value, SEL_autorelease);
}
return value;
}
static id acquireValue(id value, uintptr_t policy) {
switch (policy & 0xFF) {
case OBJC_ASSOCIATION_SETTER_RETAIN:
return ((id(*)(id, SEL))objc_msgSend)(value, SEL_retain);
case OBJC_ASSOCIATION_SETTER_COPY:
return ((id(*)(id, SEL))objc_msgSend)(value, SEL_copy);
}
return value;
}
static void releaseValue(id value, uintptr_t policy) {
if (policy & OBJC_ASSOCIATION_SETTER_RETAIN) {
((id(*)(id, SEL))objc_msgSend)(value, SEL_release);
}
}
struct ReleaseValue {
void operator() (ObjcAssociation &association) {
releaseValue(association.value(), association.policy());
}
};
void _object_set_associative_reference(id object, void *key, id value, uintptr_t policy) {
// retain the new value (if any) outside the lock.
ObjcAssociation old_association(0, nil);
id new_value = value ? acquireValue(value, policy) : nil;
{
AssociationsManager manager;
AssociationsHashMap &associations(manager.associations());
disguised_ptr_t disguised_object = DISGUISE(object);
if (new_value) {
// break any existing association.
AssociationsHashMap::iterator i = associations.find(disguised_object);
if (i != associations.end()) {
// secondary table exists
ObjectAssociationMap *refs = i->second;
ObjectAssociationMap::iterator j = refs->find(key);
if (j != refs->end()) {
old_association = j->second;
j->second = ObjcAssociation(policy, new_value);
} else {
(*refs)[key] = ObjcAssociation(policy, new_value);
}
} else {
// create the new association (first time).
ObjectAssociationMap *refs = new ObjectAssociationMap;
associations[disguised_object] = refs;
(*refs)[key] = ObjcAssociation(policy, new_value);
object->setHasAssociatedObjects();
}
} else {
// setting the association to nil breaks the association.
AssociationsHashMap::iterator i = associations.find(disguised_object);
if (i != associations.end()) {
ObjectAssociationMap *refs = i->second;
ObjectAssociationMap::iterator j = refs->find(key);
if (j != refs->end()) {
old_association = j->second;
refs->erase(j);
}
}
}
}
// release the old value (outside of the lock).
if (old_association.hasValue()) ReleaseValue()(old_association);
}
void _object_remove_assocations(id object) {
vector< ObjcAssociation,ObjcAllocator<ObjcAssociation> > elements;
{
AssociationsManager manager;
AssociationsHashMap &associations(manager.associations());
if (associations.size() == 0) return;
disguised_ptr_t disguised_object = DISGUISE(object);
AssociationsHashMap::iterator i = associations.find(disguised_object);
if (i != associations.end()) {
// copy all of the associations that need to be removed.
ObjectAssociationMap *refs = i->second;
for (ObjectAssociationMap::iterator j = refs->begin(), end = refs->end(); j != end; ++j) {
elements.push_back(j->second);
}
// remove the secondary table.
delete refs;
associations.erase(i);
}
}
// the calls to releaseValue() happen outside of the lock.
for_each(elements.begin(), elements.end(), ReleaseValue());
}

1399
runtime/objc-runtime-new.h Normal file

File diff suppressed because it is too large Load Diff

6573
runtime/objc-runtime-new.mm Normal file

File diff suppressed because it is too large Load Diff

399
runtime/objc-runtime-old.h Normal file
View File

@ -0,0 +1,399 @@
/*
* Copyright (c) 1999-2007 Apple Inc. All Rights Reserved.
*
* @APPLE_LICENSE_HEADER_START@
*
* 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 2.0 (the 'License'). You may not use this file except in
* compliance with the License. Please obtain a copy of the License at
* http://www.opensource.apple.com/apsl/ 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, QUIET ENJOYMENT OR NON-INFRINGEMENT.
* Please see the License for the specific language governing rights and
* limitations under the License.
*
* @APPLE_LICENSE_HEADER_END@
*/
#ifndef _OBJC_RUNTIME_OLD_H
#define _OBJC_RUNTIME_OLD_H
#include "objc-private.h"
#define CLS_CLASS 0x1
#define CLS_META 0x2
#define CLS_INITIALIZED 0x4
#define CLS_POSING 0x8
#define CLS_MAPPED 0x10
#define CLS_FLUSH_CACHE 0x20
#define CLS_GROW_CACHE 0x40
#define CLS_NEED_BIND 0x80
#define CLS_METHOD_ARRAY 0x100
// the JavaBridge constructs classes with these markers
#define CLS_JAVA_HYBRID 0x200
#define CLS_JAVA_CLASS 0x400
// thread-safe +initialize
#define CLS_INITIALIZING 0x800
// bundle unloading
#define CLS_FROM_BUNDLE 0x1000
// C++ ivar support
#define CLS_HAS_CXX_STRUCTORS 0x2000
// Lazy method list arrays
#define CLS_NO_METHOD_ARRAY 0x4000
// +load implementation
#define CLS_HAS_LOAD_METHOD 0x8000
// objc_allocateClassPair API
#define CLS_CONSTRUCTING 0x10000
// visibility=hidden
#define CLS_HIDDEN 0x20000
// available for use; was CLS_FINALIZE_ON_MAIN_THREAD
#define CLS_40000 0x40000
// Lazy property list arrays
#define CLS_NO_PROPERTY_ARRAY 0x80000
// +load implementation
#define CLS_CONNECTED 0x100000
#define CLS_LOADED 0x200000
// objc_allocateClassPair API
#define CLS_CONSTRUCTED 0x400000
// class is leaf for cache flushing
#define CLS_LEAF 0x800000
// class instances may have associative references
#define CLS_INSTANCES_HAVE_ASSOCIATED_OBJECTS 0x1000000
// class has instance-specific GC layout
#define CLS_HAS_INSTANCE_SPECIFIC_LAYOUT 0x2000000
// class compiled with ARC
#define CLS_IS_ARC 0x4000000
// class is not ARC but has ARC-style weak ivar layout
#define CLS_HAS_WEAK_WITHOUT_ARC 0x8000000
// Terminator for array of method lists
#define END_OF_METHODS_LIST ((struct old_method_list*)-1)
#define ISCLASS(cls) (((cls)->info & CLS_CLASS) != 0)
#define ISMETA(cls) (((cls)->info & CLS_META) != 0)
#define GETMETA(cls) (ISMETA(cls) ? (cls) : (cls)->ISA())
struct old_class_ext {
uint32_t size;
const uint8_t *weak_ivar_layout;
struct old_property_list **propertyLists;
};
struct old_category {
char *category_name;
char *class_name;
struct old_method_list *instance_methods;
struct old_method_list *class_methods;
struct old_protocol_list *protocols;
// Fields below this point are in version 7 or later only.
uint32_t size;
struct old_property_list *instance_properties;
// Check size for fields below this point.
struct old_property_list *class_properties;
bool hasClassPropertiesField() const {
return size >= offsetof(old_category, class_properties) + sizeof(class_properties);
}
};
struct old_ivar {
char *ivar_name;
char *ivar_type;
int ivar_offset;
#ifdef __LP64__
int space;
#endif
};
struct old_ivar_list {
int ivar_count;
#ifdef __LP64__
int space;
#endif
/* variable length structure */
struct old_ivar ivar_list[1];
};
struct old_method {
SEL method_name;
char *method_types;
IMP method_imp;
};
struct old_method_list {
void *obsolete;
int method_count;
#ifdef __LP64__
int space;
#endif
/* variable length structure */
struct old_method method_list[1];
};
struct old_protocol {
Class isa;
const char *protocol_name;
struct old_protocol_list *protocol_list;
struct objc_method_description_list *instance_methods;
struct objc_method_description_list *class_methods;
};
struct old_protocol_list {
struct old_protocol_list *next;
long count;
struct old_protocol *list[1];
};
struct old_protocol_ext {
uint32_t size;
struct objc_method_description_list *optional_instance_methods;
struct objc_method_description_list *optional_class_methods;
struct old_property_list *instance_properties;
const char **extendedMethodTypes;
struct old_property_list *class_properties;
bool hasClassPropertiesField() const {
return size >= offsetof(old_protocol_ext, class_properties) + sizeof(class_properties);
}
};
struct old_property {
const char *name;
const char *attributes;
};
struct old_property_list {
uint32_t entsize;
uint32_t count;
struct old_property first;
};
struct objc_class : objc_object {
Class superclass;
const char *name;
uint32_t version;
uint32_t info;
uint32_t instance_size;
struct old_ivar_list *ivars;
struct old_method_list **methodLists;
Cache cache;
struct old_protocol_list *protocols;
// CLS_EXT only
const uint8_t *ivar_layout;
struct old_class_ext *ext;
void setInfo(uint32_t set) {
OSAtomicOr32Barrier(set, (volatile uint32_t *)&info);
}
void clearInfo(uint32_t clear) {
OSAtomicXor32Barrier(clear, (volatile uint32_t *)&info);
}
// set and clear must not overlap
void changeInfo(uint32_t set, uint32_t clear) {
assert((set & clear) == 0);
uint32_t oldf, newf;
do {
oldf = this->info;
newf = (oldf | set) & ~clear;
} while (!OSAtomicCompareAndSwap32Barrier(oldf, newf, (volatile int32_t *)&info));
}
bool hasCxxCtor() {
// set_superclass propagates the flag from the superclass.
return info & CLS_HAS_CXX_STRUCTORS;
}
bool hasCxxDtor() {
return hasCxxCtor(); // one bit for both ctor and dtor
}
// Return YES if the class's ivars are managed by ARC,
// or the class is MRC but has ARC-style weak ivars.
bool hasAutomaticIvars() {
return info & (CLS_IS_ARC | CLS_HAS_WEAK_WITHOUT_ARC);
}
// Return YES if the class's ivars are managed by ARC.
bool isARC() {
return info & CLS_IS_ARC;
}
bool hasCustomRR() {
return true;
}
void setHasCustomRR(bool = false) { }
void setHasDefaultRR() { }
void printCustomRR(bool) { }
bool hasCustomAWZ() {
return true;
}
void setHasCustomAWZ(bool = false) { }
void setHasDefaultAWZ() { }
void printCustomAWZ(bool) { }
bool instancesHaveAssociatedObjects() {
return info & CLS_INSTANCES_HAVE_ASSOCIATED_OBJECTS;
}
void setInstancesHaveAssociatedObjects() {
setInfo(CLS_INSTANCES_HAVE_ASSOCIATED_OBJECTS);
}
bool shouldGrowCache() {
return info & CLS_GROW_CACHE;
}
void setShouldGrowCache(bool grow) {
if (grow) setInfo(CLS_GROW_CACHE);
else clearInfo(CLS_GROW_CACHE);
}
// +initialize bits are stored on the metaclass only
bool isInitializing() {
return getMeta()->info & CLS_INITIALIZING;
}
// +initialize bits are stored on the metaclass only
void setInitializing() {
getMeta()->setInfo(CLS_INITIALIZING);
}
// +initialize bits are stored on the metaclass only
bool isInitialized() {
return getMeta()->info & CLS_INITIALIZED;
}
// +initialize bits are stored on the metaclass only
void setInitialized() {
getMeta()->changeInfo(CLS_INITIALIZED, CLS_INITIALIZING);
}
bool isLoadable() {
// A class registered for +load is ready for +load to be called
// if it is connected.
return isConnected();
}
IMP getLoadMethod();
bool isFuture();
bool isConnected();
const char *mangledName() { return name; }
const char *demangledName() { return name; }
const char *nameForLogging() { return name; }
bool isMetaClass() {
return info & CLS_META;
}
// NOT identical to this->ISA() when this is a metaclass
Class getMeta() {
if (isMetaClass()) return (Class)this;
else return this->ISA();
}
// May be unaligned depending on class's ivars.
uint32_t unalignedInstanceStart() {
// This is not simply superclass->instance_size.
// superclass->instance_size is padded to its sizeof() boundary,
// which may envelop one of this class's ivars.
// That in turn would break ARC-style ivar layouts.
// Instead, we use the address of this class's first ivar when possible.
if (!superclass) return 0;
if (!ivars || ivars->ivar_count == 0) return superclass->instance_size;
return ivars->ivar_list[0].ivar_offset;
}
// Class's instance start rounded up to a pointer-size boundary.
// This is used for ARC layout bitmaps.
uint32_t alignedInstanceStart() {
return word_align(unalignedInstanceStart());
}
// May be unaligned depending on class's ivars.
uint32_t unalignedInstanceSize() {
return instance_size;
}
// Class's ivar size rounded up to a pointer-size boundary.
uint32_t alignedInstanceSize() {
return word_align(unalignedInstanceSize());
}
size_t instanceSize(size_t extraBytes) {
size_t size = alignedInstanceSize() + extraBytes;
// CF requires all objects be at least 16 bytes.
if (size < 16) size = 16;
return size;
}
};
#include "hashtable2.h"
__BEGIN_DECLS
#define oldprotocol(proto) ((struct old_protocol *)proto)
#define oldmethod(meth) ((struct old_method *)meth)
#define oldcategory(cat) ((struct old_category *)cat)
#define oldivar(ivar) ((struct old_ivar *)ivar)
#define oldproperty(prop) ((struct old_property *)prop)
extern NXHashTable *class_hash;
extern void unload_class(Class cls);
extern IMP lookupNamedMethodInMethodList(struct old_method_list *mlist, const char *meth_name);
extern void _objc_insertMethods(Class cls, struct old_method_list *mlist, struct old_category *cat);
extern void _objc_removeMethods(Class cls, struct old_method_list *mlist);
extern void _objc_flush_caches (Class cls);
extern bool _class_addProperties(Class cls, struct old_property_list *additions);
extern bool _class_hasLoadMethod(Class cls);
extern void change_class_references(Class imposter, Class original, Class copy, bool changeSuperRefs);
extern void flush_marked_caches(void);
extern void set_superclass(Class cls, Class supercls, bool cls_is_new);
extern void try_free(const void *p);
extern struct old_property *property_list_nth(const struct old_property_list *plist, uint32_t i);
extern struct old_property **copyPropertyList(struct old_property_list *plist, unsigned int *outCount);
extern struct objc_method_description * lookup_protocol_method(struct old_protocol *proto, SEL aSel, bool isRequiredMethod, bool isInstanceMethod, bool recursive);
// used by flush_caches outside objc-cache.m
extern void _cache_flush(Class cls);
#ifdef OBJC_INSTRUMENTED
extern unsigned int LinearFlushCachesCount;
extern unsigned int LinearFlushCachesVisitedCount;
extern unsigned int MaxLinearFlushCachesVisitedCount;
extern unsigned int NonlinearFlushCachesCount;
extern unsigned int NonlinearFlushCachesClassCount;
extern unsigned int NonlinearFlushCachesVisitedCount;
extern unsigned int MaxNonlinearFlushCachesVisitedCount;
extern unsigned int IdealFlushCachesCount;
extern unsigned int MaxIdealFlushCachesCount;
#endif
__END_DECLS
#endif

3233
runtime/objc-runtime-old.mm Normal file

File diff suppressed because it is too large Load Diff

2
runtime/objc-runtime.h Normal file
View File

@ -0,0 +1,2 @@
#include <objc/runtime.h>
#include <objc/message.h>

1033
runtime/objc-runtime.mm Normal file

File diff suppressed because it is too large Load Diff

215
runtime/objc-sel-old.mm Normal file
View File

@ -0,0 +1,215 @@
/*
* Copyright (c) 1999-2007 Apple Inc. All Rights Reserved.
*
* @APPLE_LICENSE_HEADER_START@
*
* 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 2.0 (the 'License'). You may not use this file except in
* compliance with the License. Please obtain a copy of the License at
* http://www.opensource.apple.com/apsl/ 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, QUIET ENJOYMENT OR NON-INFRINGEMENT.
* Please see the License for the specific language governing rights and
* limitations under the License.
*
* @APPLE_LICENSE_HEADER_END@
*/
/*
* Utilities for registering and looking up selectors. The sole
* purpose of the selector tables is a registry whereby there is
* exactly one address (selector) associated with a given string
* (method name).
*/
#if !__OBJC2__
#include "objc-private.h"
#include "objc-sel-set.h"
#if SUPPORT_PREOPT
#include <objc-shared-cache.h>
static const objc_selopt_t *builtins = NULL;
#endif
__BEGIN_DECLS
static size_t SelrefCount = 0;
static const char *_objc_empty_selector = "";
static struct __objc_sel_set *_objc_selectors = NULL;
static SEL _objc_search_builtins(const char *key)
{
#if defined(DUMP_SELECTORS)
if (NULL != key) printf("\t\"%s\",\n", key);
#endif
if (!key) return (SEL)0;
if ('\0' == *key) return (SEL)_objc_empty_selector;
#if SUPPORT_PREOPT
if (builtins) return (SEL)builtins->get(key);
#endif
return (SEL)0;
}
const char *sel_getName(SEL sel) {
return sel ? (const char *)sel : "<null selector>";
}
BOOL sel_isMapped(SEL name)
{
SEL sel;
if (!name) return NO;
sel = _objc_search_builtins((const char *)name);
if (sel) return YES;
rwlock_reader_t lock(selLock);
if (_objc_selectors) {
sel = __objc_sel_set_get(_objc_selectors, name);
}
return bool(sel);
}
static SEL __sel_registerName(const char *name, int lock, int copy)
{
SEL result = 0;
if (lock) selLock.assertUnlocked();
else selLock.assertWriting();
if (!name) return (SEL)0;
result = _objc_search_builtins(name);
if (result) return result;
if (lock) selLock.read();
if (_objc_selectors) {
result = __objc_sel_set_get(_objc_selectors, (SEL)name);
}
if (lock) selLock.unlockRead();
if (result) return result;
// No match. Insert.
if (lock) selLock.write();
if (!_objc_selectors) {
_objc_selectors = __objc_sel_set_create(SelrefCount);
}
if (lock) {
// Rescan in case it was added while we dropped the lock
result = __objc_sel_set_get(_objc_selectors, (SEL)name);
}
if (!result) {
result = (SEL)(copy ? strdup(name) : name);
__objc_sel_set_add(_objc_selectors, result);
#if defined(DUMP_UNKNOWN_SELECTORS)
printf("\t\"%s\",\n", name);
#endif
}
if (lock) selLock.unlockWrite();
return result;
}
SEL sel_registerName(const char *name) {
return __sel_registerName(name, 1, 1); // YES lock, YES copy
}
SEL sel_registerNameNoLock(const char *name, bool copy) {
return __sel_registerName(name, 0, copy); // NO lock, maybe copy
}
void sel_lock(void)
{
selLock.write();
}
void sel_unlock(void)
{
selLock.unlockWrite();
}
// 2001/1/24
// the majority of uses of this function (which used to return NULL if not found)
// did not check for NULL, so, in fact, never return NULL
//
SEL sel_getUid(const char *name) {
return __sel_registerName(name, 2, 1); // YES lock, YES copy
}
BOOL sel_isEqual(SEL lhs, SEL rhs)
{
return bool(lhs == rhs);
}
/***********************************************************************
* sel_init
* Initialize selector tables and register selectors used internally.
**********************************************************************/
void sel_init(size_t selrefCount)
{
// save this value for later
SelrefCount = selrefCount;
#if SUPPORT_PREOPT
builtins = preoptimizedSelectors();
#endif
// Register selectors used by libobjc
#define s(x) SEL_##x = sel_registerNameNoLock(#x, NO)
#define t(x,y) SEL_##y = sel_registerNameNoLock(#x, NO)
sel_lock();
s(load);
s(initialize);
t(resolveInstanceMethod:, resolveInstanceMethod);
t(resolveClassMethod:, resolveClassMethod);
t(.cxx_construct, cxx_construct);
t(.cxx_destruct, cxx_destruct);
s(retain);
s(release);
s(autorelease);
s(retainCount);
s(alloc);
t(allocWithZone:, allocWithZone);
s(dealloc);
s(copy);
s(new);
t(forwardInvocation:, forwardInvocation);
t(_tryRetain, tryRetain);
t(_isDeallocating, isDeallocating);
s(retainWeakReference);
s(allowsWeakReference);
extern SEL FwdSel;
FwdSel = sel_registerNameNoLock("forward::", NO);
sel_unlock();
#undef s
#undef t
}
__END_DECLS
#endif

49
runtime/objc-sel-set.h Normal file
View File

@ -0,0 +1,49 @@
/*
* Copyright (c) 2004 Apple Inc. All rights reserved.
*
* @APPLE_LICENSE_HEADER_START@
*
* 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 2.0 (the 'License'). You may not use this file except in
* compliance with the License. Please obtain a copy of the License at
* http://www.opensource.apple.com/apsl/ 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, QUIET ENJOYMENT OR NON-INFRINGEMENT.
* Please see the License for the specific language governing rights and
* limitations under the License.
*
* @APPLE_LICENSE_HEADER_END@
*/
/*
* objc-sel-set.h
* A set of SELs used for SEL uniquing.
*/
#ifndef _OBJC_SEL_SET_H_
#define _OBJC_SEL_SET_H_
#if !__OBJC2__
#include <stdint.h>
#include "objc-os.h"
__BEGIN_DECLS
struct __objc_sel_set;
extern struct __objc_sel_set *__objc_sel_set_create(size_t selrefCount);
extern SEL __objc_sel_set_get(struct __objc_sel_set *sset, SEL candidate);
extern void __objc_sel_set_add(struct __objc_sel_set *sset, SEL value);
__END_DECLS
#endif
#endif

176
runtime/objc-sel-set.mm Normal file
View File

@ -0,0 +1,176 @@
/*
* Copyright (c) 1999-2004,2008 Apple Inc. All rights reserved.
*
* @APPLE_LICENSE_HEADER_START@
*
* 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 2.0 (the 'License'). You may not use this file except in
* compliance with the License. Please obtain a copy of the License at
* http://www.opensource.apple.com/apsl/ 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, QUIET ENJOYMENT OR NON-INFRINGEMENT.
* Please see the License for the specific language governing rights and
* limitations under the License.
*
* @APPLE_LICENSE_HEADER_END@
*/
/*
* objc-sel-set.h
* A cut-down copy of CFSet used for SEL uniquing.
*/
// NOTE: even on a 64-bit system, the implementation is still limited
// to 32-bit integers (like, the count), but SEL can be any size.
#include <stdint.h>
#include "objc-private.h"
#include "objc-sel-set.h"
#if !__OBJC2__
#if !SUPPORT_MOD
// mod-free power of 2 version
#define CONSTRAIN(val, range) ((val) & ((range)-1))
#define SIZE 27
static const uint32_t __objc_sel_set_capacities[SIZE+1] = {
3, 6, 12, 24, 48, 96, 192, 384, 768, 1536, 3072, 6144, 12288, 24576,
49152, 98304, 196608, 393216, 786432, 1572864, 3145728, 6291456,
12582912, 25165824, 50331648, 100663296, 201326592, UINT32_MAX
};
static const uint32_t __objc_sel_set_buckets[SIZE] = { // powers of 2
4, 8, 16, 32, 64, 128, 256, 512, 1024, 2048, 4096, 8192, 16384, 32768,
65536, 131072, 262144, 524288, 1048576, 2097152, 4194304, 8388608,
16777216, 33554432, 67108864, 134217728, 268435456
};
#else
// prime version
#define CONSTRAIN(val, range) ((val) % (range))
#define SIZE 42
static const uint32_t __objc_sel_set_capacities[SIZE+1] = {
4, 8, 17, 29, 47, 76, 123, 199, 322, 521, 843, 1364, 2207, 3571,
5778, 9349, 15127, 24476, 39603, 64079, 103682, 167761, 271443,
439204, 710647, 1149851, 1860498, 3010349, 4870847, 7881196, 12752043,
20633239, 33385282, 54018521, 87403803, 141422324, 228826127, 370248451,
599074578, 969323029, 1568397607, 2537720636U, UINT32_MAX
};
static const uint32_t __objc_sel_set_buckets[SIZE] = { // primes
5, 11, 23, 41, 67, 113, 199, 317, 521, 839, 1361, 2207, 3571, 5779,
9349, 15121, 24473, 39607, 64081, 103681, 167759, 271429, 439199,
710641, 1149857, 1860503, 3010349, 4870843, 7881193, 12752029, 20633237,
33385273, 54018521, 87403763, 141422317, 228826121, 370248451, 599074561,
969323023, 1568397599, 2537720629U, 4106118251U
};
#endif
struct __objc_sel_set {
uint32_t _count; /* number of slots used */
uint32_t _capacity; /* maximum number of used slots */
uint32_t _bucketsNum; /* number of slots */
SEL *_buckets; /* can be NULL if not allocated yet */
};
struct __objc_sel_set_finds {
SEL match;
uint32_t nomatch;
};
// candidate may not be 0; match is 0 if not present
static struct __objc_sel_set_finds __objc_sel_set_findBuckets(struct __objc_sel_set *sset, SEL candidate) {
struct __objc_sel_set_finds ret = {0, 0xffffffff};
uint32_t probe = CONSTRAIN((uint32_t)_objc_strhash((const char *)candidate), sset->_bucketsNum);
for (;;) {
SEL currentSel = sset->_buckets[probe];
if (!currentSel) {
ret.nomatch = probe;
return ret;
} else if (!ret.match && 0 == strcmp((const char *)currentSel, (const char *)candidate)) {
ret.match = currentSel;
}
probe++;
if (sset->_bucketsNum <= probe) {
probe -= sset->_bucketsNum;
}
}
}
// create a set with given starting capacity, will resize as needed
struct __objc_sel_set *__objc_sel_set_create(size_t selrefs) {
uint32_t idx;
struct __objc_sel_set *sset = (struct __objc_sel_set *)
malloc(sizeof(struct __objc_sel_set));
if (!sset) _objc_fatal("objc_sel_set failure");
sset->_count = 0;
// heuristic to convert executable's selrefs count to table size
#if TARGET_OS_IPHONE
for (idx = 0; __objc_sel_set_capacities[idx] < selrefs; idx++);
if (idx > 0 && selrefs < 1536) idx--;
#else
if (selrefs < 1024) selrefs = 1024;
for (idx = 0; __objc_sel_set_capacities[idx] < selrefs; idx++);
idx++;
#endif
if (SIZE <= idx) _objc_fatal("objc_sel_set failure");
sset->_capacity = __objc_sel_set_capacities[idx];
sset->_bucketsNum = __objc_sel_set_buckets[idx];
sset->_buckets = (SEL *)calloc(sset->_bucketsNum, sizeof(SEL));
if (!sset->_buckets) _objc_fatal("objc_sel_set failure");
return sset;
}
// returns 0 on failure; candidate may not be 0
SEL __objc_sel_set_get(struct __objc_sel_set *sset, SEL candidate) {
return __objc_sel_set_findBuckets(sset, candidate).match;
}
// value may not be 0; should not be called unless it is known the value is not in the set
void __objc_sel_set_add(struct __objc_sel_set *sset, SEL value) {
if (sset->_count == sset->_capacity) {
SEL *oldbuckets = sset->_buckets;
uint32_t oldnbuckets = sset->_bucketsNum;
uint32_t idx, capacity = sset->_count + 1;
for (idx = 0; __objc_sel_set_capacities[idx] < capacity; idx++);
if (SIZE <= idx) _objc_fatal("objc_sel_set failure");
sset->_capacity = __objc_sel_set_capacities[idx];
sset->_bucketsNum = __objc_sel_set_buckets[idx];
sset->_buckets = (SEL *)
calloc(sset->_bucketsNum, sizeof(SEL));
if (!sset->_buckets) _objc_fatal("objc_sel_set failure");
for (idx = 0; idx < oldnbuckets; idx++) {
SEL currentSel = oldbuckets[idx];
if (currentSel) {
uint32_t nomatch = __objc_sel_set_findBuckets(sset, currentSel).nomatch;
sset->_buckets[nomatch] = currentSel;
}
}
free(oldbuckets);
}
{
uint32_t nomatch = __objc_sel_set_findBuckets(sset, value).nomatch;
sset->_buckets[nomatch] = value;
sset->_count++;
}
}
// !__OBJC2__
#endif

69
runtime/objc-sel-table.s Normal file
View File

@ -0,0 +1,69 @@
#include <TargetConditionals.h>
#include <mach/vm_param.h>
#if __LP64__
# define PTR(x) .quad x
#else
# define PTR(x) .long x
#endif
.section __TEXT,__objc_opt_ro
.align 3
.private_extern __objc_opt_data
__objc_opt_data:
.long 15 /* table.version */
.long 0 /* table.flags */
.long 0 /* table.selopt_offset */
.long 0 /* table.headeropt_ro_offset */
.long 0 /* table.clsopt_offset */
.long 0 /* table.protocolopt_offset */
.long 0 /* table.headeropt_rw_offset */
.space PAGE_MAX_SIZE-28
/* space for selopt, smax/capacity=524288, blen/mask=262143+1 */
.space 262144 /* mask tab */
.space 524288 /* checkbytes */
.space 524288*4 /* offsets */
/* space for clsopt, smax/capacity=65536, blen/mask=16383+1 */
.space 16384 /* mask tab */
.space 65536 /* checkbytes */
.space 65536*12 /* offsets to name and class and header_info */
.space PAGE_MAX_SIZE /* some duplicate classes */
/* space for protocolopt, smax/capacity=8192, blen/mask=4095+1 */
.space 4096 /* mask tab */
.space 8192 /* checkbytes */
.space 8192*4 /* offsets */
/* space for header_info (RO) structures */
.space 16384
.section __DATA,__objc_opt_rw
.align 3
.private_extern __objc_opt_rw_data
__objc_opt_rw_data:
/* space for header_info (RW) structures */
.space 16384
/* space for 8192 protocols */
#if __LP64__
.space 8192 * 11 * 8
#else
.space 8192 * 11 * 4
#endif
/* section of pointers that the shared cache optimizer wants to know about */
.section __DATA,__objc_opt_ptrs
.align 3
#if TARGET_OS_OSX && __i386__
// old ABI
.globl .objc_class_name_Protocol
PTR(.objc_class_name_Protocol)
#else
// new ABI
.globl _OBJC_CLASS_$_Protocol
PTR(_OBJC_CLASS_$_Protocol)
#endif

215
runtime/objc-sel.mm Normal file
View File

@ -0,0 +1,215 @@
/*
* Copyright (c) 2012 Apple Inc. All Rights Reserved.
*
* @APPLE_LICENSE_HEADER_START@
*
* 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 2.0 (the 'License'). You may not use this file except in
* compliance with the License. Please obtain a copy of the License at
* http://www.opensource.apple.com/apsl/ 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, QUIET ENJOYMENT OR NON-INFRINGEMENT.
* Please see the License for the specific language governing rights and
* limitations under the License.
*
* @APPLE_LICENSE_HEADER_END@
*/
#if __OBJC2__
#include "objc-private.h"
#include "objc-cache.h"
#if SUPPORT_PREOPT
static const objc_selopt_t *builtins = NULL;
#endif
static size_t SelrefCount = 0;
static NXMapTable *namedSelectors;
static SEL search_builtins(const char *key);
/***********************************************************************
* sel_init
* Initialize selector tables and register selectors used internally.
**********************************************************************/
void sel_init(size_t selrefCount)
{
// save this value for later
SelrefCount = selrefCount;
#if SUPPORT_PREOPT
builtins = preoptimizedSelectors();
if (PrintPreopt && builtins) {
uint32_t occupied = builtins->occupied;
uint32_t capacity = builtins->capacity;
_objc_inform("PREOPTIMIZATION: using selopt at %p", builtins);
_objc_inform("PREOPTIMIZATION: %u selectors", occupied);
_objc_inform("PREOPTIMIZATION: %u/%u (%u%%) hash table occupancy",
occupied, capacity,
(unsigned)(occupied/(double)capacity*100));
}
#endif
// Register selectors used by libobjc
#define s(x) SEL_##x = sel_registerNameNoLock(#x, NO)
#define t(x,y) SEL_##y = sel_registerNameNoLock(#x, NO)
sel_lock();
s(load);
s(initialize);
t(resolveInstanceMethod:, resolveInstanceMethod);
t(resolveClassMethod:, resolveClassMethod);
t(.cxx_construct, cxx_construct);
t(.cxx_destruct, cxx_destruct);
s(retain);
s(release);
s(autorelease);
s(retainCount);
s(alloc);
t(allocWithZone:, allocWithZone);
s(dealloc);
s(copy);
s(new);
t(forwardInvocation:, forwardInvocation);
t(_tryRetain, tryRetain);
t(_isDeallocating, isDeallocating);
s(retainWeakReference);
s(allowsWeakReference);
sel_unlock();
#undef s
#undef t
}
static SEL sel_alloc(const char *name, bool copy)
{
selLock.assertWriting();
return (SEL)(copy ? strdupIfMutable(name) : name);
}
const char *sel_getName(SEL sel)
{
if (!sel) return "<null selector>";
return (const char *)(const void*)sel;
}
BOOL sel_isMapped(SEL sel)
{
if (!sel) return NO;
const char *name = (const char *)(void *)sel;
if (sel == search_builtins(name)) return YES;
rwlock_reader_t lock(selLock);
if (namedSelectors) {
return (sel == (SEL)NXMapGet(namedSelectors, name));
}
return false;
}
static SEL search_builtins(const char *name)
{
#if SUPPORT_PREOPT
if (builtins) return (SEL)builtins->get(name);
#endif
return nil;
}
static SEL __sel_registerName(const char *name, int lock, int copy)
{
SEL result = 0;
if (lock) selLock.assertUnlocked();
else selLock.assertWriting();
if (!name) return (SEL)0;
result = search_builtins(name);
if (result) return result;
if (lock) selLock.read();
if (namedSelectors) {
result = (SEL)NXMapGet(namedSelectors, name);
}
if (lock) selLock.unlockRead();
if (result) return result;
// No match. Insert.
if (lock) selLock.write();
if (!namedSelectors) {
namedSelectors = NXCreateMapTable(NXStrValueMapPrototype,
(unsigned)SelrefCount);
}
if (lock) {
// Rescan in case it was added while we dropped the lock
result = (SEL)NXMapGet(namedSelectors, name);
}
if (!result) {
result = sel_alloc(name, copy);
// fixme choose a better container (hash not map for starters)
NXMapInsert(namedSelectors, sel_getName(result), result);
}
if (lock) selLock.unlockWrite();
return result;
}
SEL sel_registerName(const char *name) {
return __sel_registerName(name, 1, 1); // YES lock, YES copy
}
SEL sel_registerNameNoLock(const char *name, bool copy) {
return __sel_registerName(name, 0, copy); // NO lock, maybe copy
}
void sel_lock(void)
{
selLock.write();
}
void sel_unlock(void)
{
selLock.unlockWrite();
}
// 2001/1/24
// the majority of uses of this function (which used to return NULL if not found)
// did not check for NULL, so, in fact, never return NULL
//
SEL sel_getUid(const char *name) {
return __sel_registerName(name, 2, 1); // YES lock, YES copy
}
BOOL sel_isEqual(SEL lhs, SEL rhs)
{
return bool(lhs == rhs);
}
#endif

67
runtime/objc-sync.h Normal file
View File

@ -0,0 +1,67 @@
/*
* Copyright (c) 2002, 2006 Apple Inc. All Rights Reserved.
*
* @APPLE_LICENSE_HEADER_START@
*
* 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 2.0 (the 'License'). You may not use this file except in
* compliance with the License. Please obtain a copy of the License at
* http://www.opensource.apple.com/apsl/ 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, QUIET ENJOYMENT OR NON-INFRINGEMENT.
* Please see the License for the specific language governing rights and
* limitations under the License.
*
* @APPLE_LICENSE_HEADER_END@
*/
#ifndef __OBJC_SNYC_H_
#define __OBJC_SNYC_H_
#include <objc/objc.h>
/**
* Begin synchronizing on 'obj'.
* Allocates recursive pthread_mutex associated with 'obj' if needed.
*
* @param obj The object to begin synchronizing on.
*
* @return OBJC_SYNC_SUCCESS once lock is acquired.
*/
OBJC_EXPORT int objc_sync_enter(id obj)
OBJC_AVAILABLE(10.3, 2.0, 9.0, 1.0);
/**
* End synchronizing on 'obj'.
*
* @param obj The objet to end synchronizing on.
*
* @return OBJC_SYNC_SUCCESS or OBJC_SYNC_NOT_OWNING_THREAD_ERROR
*/
OBJC_EXPORT int objc_sync_exit(id obj)
OBJC_AVAILABLE(10.3, 2.0, 9.0, 1.0);
// The wait/notify functions have never worked correctly and no longer exist.
OBJC_EXPORT int objc_sync_wait(id obj, long long milliSecondsMaxWait)
UNAVAILABLE_ATTRIBUTE;
OBJC_EXPORT int objc_sync_notify(id obj)
UNAVAILABLE_ATTRIBUTE;
OBJC_EXPORT int objc_sync_notifyAll(id obj)
UNAVAILABLE_ATTRIBUTE;
enum {
OBJC_SYNC_SUCCESS = 0,
OBJC_SYNC_NOT_OWNING_THREAD_ERROR = -1,
OBJC_SYNC_TIMED_OUT = -2,
OBJC_SYNC_NOT_INITIALIZED = -3
};
#endif // __OBJC_SNYC_H_

327
runtime/objc-sync.mm Normal file
View File

@ -0,0 +1,327 @@
/*
* Copyright (c) 1999-2007 Apple Inc. All Rights Reserved.
*
* @APPLE_LICENSE_HEADER_START@
*
* 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 2.0 (the 'License'). You may not use this file except in
* compliance with the License. Please obtain a copy of the License at
* http://www.opensource.apple.com/apsl/ 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, QUIET ENJOYMENT OR NON-INFRINGEMENT.
* Please see the License for the specific language governing rights and
* limitations under the License.
*
* @APPLE_LICENSE_HEADER_END@
*/
#include "objc-private.h"
#include "objc-sync.h"
//
// Allocate a lock only when needed. Since few locks are needed at any point
// in time, keep them on a single list.
//
typedef struct SyncData {
struct SyncData* nextData;
DisguisedPtr<objc_object> object;
int32_t threadCount; // number of THREADS using this block
recursive_mutex_t mutex;
} SyncData;
typedef struct {
SyncData *data;
unsigned int lockCount; // number of times THIS THREAD locked this block
} SyncCacheItem;
typedef struct SyncCache {
unsigned int allocated;
unsigned int used;
SyncCacheItem list[0];
} SyncCache;
/*
Fast cache: two fixed pthread keys store a single SyncCacheItem.
This avoids malloc of the SyncCache for threads that only synchronize
a single object at a time.
SYNC_DATA_DIRECT_KEY == SyncCacheItem.data
SYNC_COUNT_DIRECT_KEY == SyncCacheItem.lockCount
*/
struct SyncList {
SyncData *data;
spinlock_t lock;
SyncList() : data(nil) { }
};
// Use multiple parallel lists to decrease contention among unrelated objects.
#define LOCK_FOR_OBJ(obj) sDataLists[obj].lock
#define LIST_FOR_OBJ(obj) sDataLists[obj].data
static StripedMap<SyncList> sDataLists;
enum usage { ACQUIRE, RELEASE, CHECK };
static SyncCache *fetch_cache(bool create)
{
_objc_pthread_data *data;
data = _objc_fetch_pthread_data(create);
if (!data) return NULL;
if (!data->syncCache) {
if (!create) {
return NULL;
} else {
int count = 4;
data->syncCache = (SyncCache *)
calloc(1, sizeof(SyncCache) + count*sizeof(SyncCacheItem));
data->syncCache->allocated = count;
}
}
// Make sure there's at least one open slot in the list.
if (data->syncCache->allocated == data->syncCache->used) {
data->syncCache->allocated *= 2;
data->syncCache = (SyncCache *)
realloc(data->syncCache, sizeof(SyncCache)
+ data->syncCache->allocated * sizeof(SyncCacheItem));
}
return data->syncCache;
}
void _destroySyncCache(struct SyncCache *cache)
{
if (cache) free(cache);
}
static SyncData* id2data(id object, enum usage why)
{
spinlock_t *lockp = &LOCK_FOR_OBJ(object);
SyncData **listp = &LIST_FOR_OBJ(object);
SyncData* result = NULL;
#if SUPPORT_DIRECT_THREAD_KEYS
// Check per-thread single-entry fast cache for matching object
bool fastCacheOccupied = NO;
SyncData *data = (SyncData *)tls_get_direct(SYNC_DATA_DIRECT_KEY);
if (data) {
fastCacheOccupied = YES;
if (data->object == object) {
// Found a match in fast cache.
uintptr_t lockCount;
result = data;
lockCount = (uintptr_t)tls_get_direct(SYNC_COUNT_DIRECT_KEY);
if (result->threadCount <= 0 || lockCount <= 0) {
_objc_fatal("id2data fastcache is buggy");
}
switch(why) {
case ACQUIRE: {
lockCount++;
tls_set_direct(SYNC_COUNT_DIRECT_KEY, (void*)lockCount);
break;
}
case RELEASE:
lockCount--;
tls_set_direct(SYNC_COUNT_DIRECT_KEY, (void*)lockCount);
if (lockCount == 0) {
// remove from fast cache
tls_set_direct(SYNC_DATA_DIRECT_KEY, NULL);
// atomic because may collide with concurrent ACQUIRE
OSAtomicDecrement32Barrier(&result->threadCount);
}
break;
case CHECK:
// do nothing
break;
}
return result;
}
}
#endif
// Check per-thread cache of already-owned locks for matching object
SyncCache *cache = fetch_cache(NO);
if (cache) {
unsigned int i;
for (i = 0; i < cache->used; i++) {
SyncCacheItem *item = &cache->list[i];
if (item->data->object != object) continue;
// Found a match.
result = item->data;
if (result->threadCount <= 0 || item->lockCount <= 0) {
_objc_fatal("id2data cache is buggy");
}
switch(why) {
case ACQUIRE:
item->lockCount++;
break;
case RELEASE:
item->lockCount--;
if (item->lockCount == 0) {
// remove from per-thread cache
cache->list[i] = cache->list[--cache->used];
// atomic because may collide with concurrent ACQUIRE
OSAtomicDecrement32Barrier(&result->threadCount);
}
break;
case CHECK:
// do nothing
break;
}
return result;
}
}
// Thread cache didn't find anything.
// Walk in-use list looking for matching object
// Spinlock prevents multiple threads from creating multiple
// locks for the same new object.
// We could keep the nodes in some hash table if we find that there are
// more than 20 or so distinct locks active, but we don't do that now.
lockp->lock();
{
SyncData* p;
SyncData* firstUnused = NULL;
for (p = *listp; p != NULL; p = p->nextData) {
if ( p->object == object ) {
result = p;
// atomic because may collide with concurrent RELEASE
OSAtomicIncrement32Barrier(&result->threadCount);
goto done;
}
if ( (firstUnused == NULL) && (p->threadCount == 0) )
firstUnused = p;
}
// no SyncData currently associated with object
if ( (why == RELEASE) || (why == CHECK) )
goto done;
// an unused one was found, use it
if ( firstUnused != NULL ) {
result = firstUnused;
result->object = (objc_object *)object;
result->threadCount = 1;
goto done;
}
}
// malloc a new SyncData and add to list.
// XXX calling malloc with a global lock held is bad practice,
// might be worth releasing the lock, mallocing, and searching again.
// But since we never free these guys we won't be stuck in malloc very often.
result = (SyncData*)calloc(sizeof(SyncData), 1);
result->object = (objc_object *)object;
result->threadCount = 1;
new (&result->mutex) recursive_mutex_t();
result->nextData = *listp;
*listp = result;
done:
lockp->unlock();
if (result) {
// Only new ACQUIRE should get here.
// All RELEASE and CHECK and recursive ACQUIRE are
// handled by the per-thread caches above.
if (why == RELEASE) {
// Probably some thread is incorrectly exiting
// while the object is held by another thread.
return nil;
}
if (why != ACQUIRE) _objc_fatal("id2data is buggy");
if (result->object != object) _objc_fatal("id2data is buggy");
#if SUPPORT_DIRECT_THREAD_KEYS
if (!fastCacheOccupied) {
// Save in fast thread cache
tls_set_direct(SYNC_DATA_DIRECT_KEY, result);
tls_set_direct(SYNC_COUNT_DIRECT_KEY, (void*)1);
} else
#endif
{
// Save in thread cache
if (!cache) cache = fetch_cache(YES);
cache->list[cache->used].data = result;
cache->list[cache->used].lockCount = 1;
cache->used++;
}
}
return result;
}
BREAKPOINT_FUNCTION(
void objc_sync_nil(void)
);
// Begin synchronizing on 'obj'.
// Allocates recursive mutex associated with 'obj' if needed.
// Returns OBJC_SYNC_SUCCESS once lock is acquired.
int objc_sync_enter(id obj)
{
int result = OBJC_SYNC_SUCCESS;
if (obj) {
SyncData* data = id2data(obj, ACQUIRE);
assert(data);
data->mutex.lock();
} else {
// @synchronized(nil) does nothing
if (DebugNilSync) {
_objc_inform("NIL SYNC DEBUG: @synchronized(nil); set a breakpoint on objc_sync_nil to debug");
}
objc_sync_nil();
}
return result;
}
// End synchronizing on 'obj'.
// Returns OBJC_SYNC_SUCCESS or OBJC_SYNC_NOT_OWNING_THREAD_ERROR
int objc_sync_exit(id obj)
{
int result = OBJC_SYNC_SUCCESS;
if (obj) {
SyncData* data = id2data(obj, RELEASE);
if (!data) {
result = OBJC_SYNC_NOT_OWNING_THREAD_ERROR;
} else {
bool okay = data->mutex.tryUnlock();
if (!okay) {
result = OBJC_SYNC_NOT_OWNING_THREAD_ERROR;
}
}
} else {
// @synchronized(nil) does nothing
}
return result;
}

View File

@ -0,0 +1,365 @@
/*
* Copyright (c) 1999-2007 Apple Inc. All Rights Reserved.
*
* @APPLE_LICENSE_HEADER_START@
*
* 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 2.0 (the 'License'). You may not use this file except in
* compliance with the License. Please obtain a copy of the License at
* http://www.opensource.apple.com/apsl/ 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, QUIET ENJOYMENT OR NON-INFRINGEMENT.
* Please see the License for the specific language governing rights and
* limitations under the License.
*
* @APPLE_LICENSE_HEADER_END@
*/
/***********************************************************************
* objc-typeencoding.m
* Parsing of old-style type strings.
**********************************************************************/
#include "objc-private.h"
/***********************************************************************
* SubtypeUntil.
*
* Delegation.
**********************************************************************/
static int SubtypeUntil (const char * type,
char end)
{
int level = 0;
const char * head = type;
//
while (*type)
{
if (!*type || (!level && (*type == end)))
return (int)(type - head);
switch (*type)
{
case ']': case '}': case ')': level--; break;
case '[': case '{': case '(': level += 1; break;
}
type += 1;
}
_objc_fatal ("Object: SubtypeUntil: end of type encountered prematurely\n");
return 0;
}
/***********************************************************************
* SkipFirstType.
**********************************************************************/
static const char * SkipFirstType (const char * type)
{
while (1)
{
switch (*type++)
{
case 'O': /* bycopy */
case 'n': /* in */
case 'o': /* out */
case 'N': /* inout */
case 'r': /* const */
case 'V': /* oneway */
case '^': /* pointers */
break;
case '@': /* objects */
if (type[0] == '?') type++; /* Blocks */
return type;
/* arrays */
case '[':
while ((*type >= '0') && (*type <= '9'))
type += 1;
return type + SubtypeUntil (type, ']') + 1;
/* structures */
case '{':
return type + SubtypeUntil (type, '}') + 1;
/* unions */
case '(':
return type + SubtypeUntil (type, ')') + 1;
/* basic types */
default:
return type;
}
}
}
/***********************************************************************
* encoding_getNumberOfArguments.
**********************************************************************/
unsigned int
encoding_getNumberOfArguments(const char *typedesc)
{
unsigned nargs;
// First, skip the return type
typedesc = SkipFirstType (typedesc);
// Next, skip stack size
while ((*typedesc >= '0') && (*typedesc <= '9'))
typedesc += 1;
// Now, we have the arguments - count how many
nargs = 0;
while (*typedesc)
{
// Traverse argument type
typedesc = SkipFirstType (typedesc);
// Skip GNU runtime's register parameter hint
if (*typedesc == '+') typedesc++;
// Traverse (possibly negative) argument offset
if (*typedesc == '-')
typedesc += 1;
while ((*typedesc >= '0') && (*typedesc <= '9'))
typedesc += 1;
// Made it past an argument
nargs += 1;
}
return nargs;
}
/***********************************************************************
* encoding_getSizeOfArguments.
**********************************************************************/
unsigned
encoding_getSizeOfArguments(const char *typedesc)
{
unsigned stack_size;
// Get our starting points
stack_size = 0;
// Skip the return type
typedesc = SkipFirstType (typedesc);
// Convert ASCII number string to integer
while ((*typedesc >= '0') && (*typedesc <= '9'))
stack_size = (stack_size * 10) + (*typedesc++ - '0');
return stack_size;
}
/***********************************************************************
* encoding_getArgumentInfo.
**********************************************************************/
unsigned int
encoding_getArgumentInfo(const char *typedesc, unsigned int arg,
const char **type, int *offset)
{
unsigned nargs = 0;
int self_offset = 0;
bool offset_is_negative = NO;
// First, skip the return type
typedesc = SkipFirstType (typedesc);
// Next, skip stack size
while ((*typedesc >= '0') && (*typedesc <= '9'))
typedesc += 1;
// Now, we have the arguments - position typedesc to the appropriate argument
while (*typedesc && nargs != arg)
{
// Skip argument type
typedesc = SkipFirstType (typedesc);
if (nargs == 0)
{
// Skip GNU runtime's register parameter hint
if (*typedesc == '+') typedesc++;
// Skip negative sign in offset
if (*typedesc == '-')
{
offset_is_negative = YES;
typedesc += 1;
}
else
offset_is_negative = NO;
while ((*typedesc >= '0') && (*typedesc <= '9'))
self_offset = self_offset * 10 + (*typedesc++ - '0');
if (offset_is_negative)
self_offset = -(self_offset);
}
else
{
// Skip GNU runtime's register parameter hint
if (*typedesc == '+') typedesc++;
// Skip (possibly negative) argument offset
if (*typedesc == '-')
typedesc += 1;
while ((*typedesc >= '0') && (*typedesc <= '9'))
typedesc += 1;
}
nargs += 1;
}
if (*typedesc)
{
int arg_offset = 0;
*type = typedesc;
typedesc = SkipFirstType (typedesc);
if (arg == 0)
{
*offset = 0;
}
else
{
// Skip GNU register parameter hint
if (*typedesc == '+') typedesc++;
// Pick up (possibly negative) argument offset
if (*typedesc == '-')
{
offset_is_negative = YES;
typedesc += 1;
}
else
offset_is_negative = NO;
while ((*typedesc >= '0') && (*typedesc <= '9'))
arg_offset = arg_offset * 10 + (*typedesc++ - '0');
if (offset_is_negative)
arg_offset = - arg_offset;
*offset = arg_offset - self_offset;
}
}
else
{
*type = 0;
*offset = 0;
}
return nargs;
}
void
encoding_getReturnType(const char *t, char *dst, size_t dst_len)
{
size_t len;
const char *end;
if (!dst) return;
if (!t) {
strncpy(dst, "", dst_len);
return;
}
end = SkipFirstType(t);
len = end - t;
strncpy(dst, t, MIN(len, dst_len));
if (len < dst_len) memset(dst+len, 0, dst_len - len);
}
/***********************************************************************
* encoding_copyReturnType. Returns the method's return type string
* on the heap.
**********************************************************************/
char *
encoding_copyReturnType(const char *t)
{
size_t len;
const char *end;
char *result;
if (!t) return NULL;
end = SkipFirstType(t);
len = end - t;
result = (char *)malloc(len + 1);
strncpy(result, t, len);
result[len] = '\0';
return result;
}
void
encoding_getArgumentType(const char *t, unsigned int index,
char *dst, size_t dst_len)
{
size_t len;
const char *end;
int offset;
if (!dst) return;
if (!t) {
strncpy(dst, "", dst_len);
return;
}
encoding_getArgumentInfo(t, index, &t, &offset);
if (!t) {
strncpy(dst, "", dst_len);
return;
}
end = SkipFirstType(t);
len = end - t;
strncpy(dst, t, MIN(len, dst_len));
if (len < dst_len) memset(dst+len, 0, dst_len - len);
}
/***********************************************************************
* encoding_copyArgumentType. Returns a single argument's type string
* on the heap. Argument 0 is `self`; argument 1 is `_cmd`.
**********************************************************************/
char *
encoding_copyArgumentType(const char *t, unsigned int index)
{
size_t len;
const char *end;
char *result;
int offset;
if (!t) return NULL;
encoding_getArgumentInfo(t, index, &t, &offset);
if (!t) return NULL;
end = SkipFirstType(t);
len = end - t;
result = (char *)malloc(len + 1);
strncpy(result, t, len);
result[len] = '\0';
return result;
}

143
runtime/objc-weak.h Normal file
View File

@ -0,0 +1,143 @@
/*
* Copyright (c) 2010-2011 Apple Inc. All rights reserved.
*
* @APPLE_LICENSE_HEADER_START@
*
* 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 2.0 (the 'License'). You may not use this file except in
* compliance with the License. Please obtain a copy of the License at
* http://www.opensource.apple.com/apsl/ 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, QUIET ENJOYMENT OR NON-INFRINGEMENT.
* Please see the License for the specific language governing rights and
* limitations under the License.
*
* @APPLE_LICENSE_HEADER_END@
*/
#ifndef _OBJC_WEAK_H_
#define _OBJC_WEAK_H_
#include <objc/objc.h>
#include "objc-config.h"
__BEGIN_DECLS
/*
The weak table is a hash table governed by a single spin lock.
An allocated blob of memory, most often an object, but under GC any such
allocation, may have its address stored in a __weak marked storage location
through use of compiler generated write-barriers or hand coded uses of the
register weak primitive. Associated with the registration can be a callback
block for the case when one of the allocated chunks of memory is reclaimed.
The table is hashed on the address of the allocated memory. When __weak
marked memory changes its reference, we count on the fact that we can still
see its previous reference.
So, in the hash table, indexed by the weakly referenced item, is a list of
all locations where this address is currently being stored.
For ARC, we also keep track of whether an arbitrary object is being
deallocated by briefly placing it in the table just prior to invoking
dealloc, and removing it via objc_clear_deallocating just prior to memory
reclamation.
*/
// The address of a __weak variable.
// These pointers are stored disguised so memory analysis tools
// don't see lots of interior pointers from the weak table into objects.
typedef DisguisedPtr<objc_object *> weak_referrer_t;
#if __LP64__
#define PTR_MINUS_2 62
#else
#define PTR_MINUS_2 30
#endif
/**
* The internal structure stored in the weak references table.
* It maintains and stores
* a hash set of weak references pointing to an object.
* If out_of_line_ness != REFERRERS_OUT_OF_LINE then the set
* is instead a small inline array.
*/
#define WEAK_INLINE_COUNT 4
// out_of_line_ness field overlaps with the low two bits of inline_referrers[1].
// inline_referrers[1] is a DisguisedPtr of a pointer-aligned address.
// The low two bits of a pointer-aligned DisguisedPtr will always be 0b00
// (disguised nil or 0x80..00) or 0b11 (any other address).
// Therefore out_of_line_ness == 0b10 is used to mark the out-of-line state.
#define REFERRERS_OUT_OF_LINE 2
struct weak_entry_t {
DisguisedPtr<objc_object> referent;
union {
struct {
weak_referrer_t *referrers;
uintptr_t out_of_line_ness : 2;
uintptr_t num_refs : PTR_MINUS_2;
uintptr_t mask;
uintptr_t max_hash_displacement;
};
struct {
// out_of_line_ness field is low bits of inline_referrers[1]
weak_referrer_t inline_referrers[WEAK_INLINE_COUNT];
};
};
bool out_of_line() {
return (out_of_line_ness == REFERRERS_OUT_OF_LINE);
}
weak_entry_t& operator=(const weak_entry_t& other) {
memcpy(this, &other, sizeof(other));
return *this;
}
weak_entry_t(objc_object *newReferent, objc_object **newReferrer)
: referent(newReferent)
{
inline_referrers[0] = newReferrer;
for (int i = 1; i < WEAK_INLINE_COUNT; i++) {
inline_referrers[i] = nil;
}
}
};
/**
* The global weak references table. Stores object ids as keys,
* and weak_entry_t structs as their values.
*/
struct weak_table_t {
weak_entry_t *weak_entries;
size_t num_entries;
uintptr_t mask;
uintptr_t max_hash_displacement;
};
/// Adds an (object, weak pointer) pair to the weak table.
id weak_register_no_lock(weak_table_t *weak_table, id referent,
id *referrer, bool crashIfDeallocating);
/// Removes an (object, weak pointer) pair from the weak table.
void weak_unregister_no_lock(weak_table_t *weak_table, id referent, id *referrer);
#if DEBUG
/// Returns true if an object is weakly referenced somewhere.
bool weak_is_registered_no_lock(weak_table_t *weak_table, id referent);
#endif
/// Called on object destruction. Sets all remaining weak pointers to nil.
void weak_clear_no_lock(weak_table_t *weak_table, id referent);
__END_DECLS
#endif /* _OBJC_WEAK_H_ */

Some files were not shown because too many files have changed in this diff Show More