mirror of
https://github.com/darlinghq/darling-objc4.git
synced 2024-11-23 04:09:46 +00:00
objc4-706
This commit is contained in:
commit
adfc003729
367
APPLE_LICENSE
Normal file
367
APPLE_LICENSE
Normal 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
358
ReleaseNotes.rtf
Normal 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
358
libobjc.order
Normal 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
562
markgc.cpp
Normal 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, §[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
34
objc.sln
Executable 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
|
1088
objc.vcproj
Normal file
1088
objc.vcproj
Normal file
File diff suppressed because it is too large
Load Diff
823
objc.xcodeproj/project.pbxproj
Normal file
823
objc.xcodeproj/project.pbxproj
Normal 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
95
objcrt/objcrt.vcproj
Executable 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"%DSTROOT%\AppleInternal\include" /I"%SRCROOT%\AppleInternal\include" /I"$(ProjectDir)\runtime" /D"_WINDOWS" /Dnil=0 ..\runtime\objcrt.c /Fo"$(OutDir)\objcrt_debug.obj"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCCustomBuildTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCMIDLTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCPostBuildEventTool"
|
||||
CommandLine="xcopy /Y "$(OutDir)\objcrt_debug.obj" "%DSTROOT%\AppleInternal\lib""
|
||||
/>
|
||||
</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"%DSTROOT%\AppleInternal\include" /I"%SRCROOT%\AppleInternal\include" /I"$(ProjectDir)\..\runtime" /D"_WINDOWS" /Dnil=0 ..\runtime\objcrt.c /Fo"$(OutDir)\objcrt.obj"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCCustomBuildTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCMIDLTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCPostBuildEventTool"
|
||||
CommandLine="xcopy /Y "$(OutDir)\objcrt.obj" "%DSTROOT%\AppleInternal\lib""
|
||||
/>
|
||||
</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
15
prebuild.bat
Executable 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
|
911
runtime/Messengers.subproj/objc-msg-arm.s
Normal file
911
runtime/Messengers.subproj/objc-msg-arm.s
Normal 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
|
561
runtime/Messengers.subproj/objc-msg-arm64.s
Executable file
561
runtime/Messengers.subproj/objc-msg-arm64.s
Executable 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
|
1164
runtime/Messengers.subproj/objc-msg-i386.s
Normal file
1164
runtime/Messengers.subproj/objc-msg-i386.s
Normal file
File diff suppressed because it is too large
Load Diff
1045
runtime/Messengers.subproj/objc-msg-simulator-i386.s
Normal file
1045
runtime/Messengers.subproj/objc-msg-simulator-i386.s
Normal file
File diff suppressed because it is too large
Load Diff
1215
runtime/Messengers.subproj/objc-msg-simulator-x86_64.s
Normal file
1215
runtime/Messengers.subproj/objc-msg-simulator-x86_64.s
Normal file
File diff suppressed because it is too large
Load Diff
520
runtime/Messengers.subproj/objc-msg-win32.m
Normal file
520
runtime/Messengers.subproj/objc-msg-win32.m
Normal 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
|
||||
}
|
||||
}
|
1329
runtime/Messengers.subproj/objc-msg-x86_64.s
Normal file
1329
runtime/Messengers.subproj/objc-msg-x86_64.s
Normal file
File diff suppressed because it is too large
Load Diff
33
runtime/NSObjCRuntime.h
Normal file
33
runtime/NSObjCRuntime.h
Normal 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
109
runtime/NSObject.h
Normal 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
2352
runtime/NSObject.mm
Normal file
File diff suppressed because it is too large
Load Diff
167
runtime/Object.h
Normal file
167
runtime/Object.h
Normal 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
558
runtime/Object.mm
Normal 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
|
118
runtime/OldClasses.subproj/List.h
Normal file
118
runtime/OldClasses.subproj/List.h
Normal 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_ */
|
294
runtime/OldClasses.subproj/List.m
Normal file
294
runtime/OldClasses.subproj/List.m
Normal 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
88
runtime/Protocol.h
Normal 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
128
runtime/Protocol.mm
Normal 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
|
148
runtime/a1a2-blocktramps-arm.s
Normal file
148
runtime/a1a2-blocktramps-arm.s
Normal 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
|
134
runtime/a1a2-blocktramps-arm64.s
Normal file
134
runtime/a1a2-blocktramps-arm64.s
Normal 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
566
runtime/a1a2-blocktramps-i386.s
Executable 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
564
runtime/a1a2-blocktramps-x86_64.s
Executable 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
|
148
runtime/a2a3-blocktramps-arm.s
Normal file
148
runtime/a2a3-blocktramps-arm.s
Normal 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
566
runtime/a2a3-blocktramps-i386.s
Executable 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
565
runtime/a2a3-blocktramps-x86_64.s
Executable 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
2
runtime/hashtable.h
Normal file
@ -0,0 +1,2 @@
|
||||
#include <objc/hashtable2.h>
|
||||
|
229
runtime/hashtable2.h
Normal file
229
runtime/hashtable2.h
Normal 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
646
runtime/hashtable2.mm
Normal 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
171
runtime/llvm-AlignOf.h
Normal 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
1097
runtime/llvm-DenseMap.h
Normal file
File diff suppressed because it is too large
Load Diff
200
runtime/llvm-DenseMapInfo.h
Normal file
200
runtime/llvm-DenseMapInfo.h
Normal 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
480
runtime/llvm-MathExtras.h
Normal 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
221
runtime/llvm-type_traits.h
Normal 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
138
runtime/maptable.h
Normal 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
453
runtime/maptable.mm
Normal 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
333
runtime/message.h
Normal 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 object’s 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
346
runtime/objc-abi.h
Normal 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
161
runtime/objc-accessors.mm
Normal 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
232
runtime/objc-api.h
Normal 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
255
runtime/objc-auto.h
Normal 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
121
runtime/objc-auto.mm
Normal 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
|
477
runtime/objc-block-trampolines.mm
Normal file
477
runtime/objc-block-trampolines.mm
Normal 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,
|
||||
¤tProtection, &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
43
runtime/objc-cache-old.h
Normal 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
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
21
runtime/objc-cache.h
Normal 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
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
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
2
runtime/objc-class.h
Normal file
@ -0,0 +1,2 @@
|
||||
#include <objc/runtime.h>
|
||||
#include <objc/message.h>
|
1272
runtime/objc-class.mm
Normal file
1272
runtime/objc-class.mm
Normal file
File diff suppressed because it is too large
Load Diff
170
runtime/objc-config.h
Normal file
170
runtime/objc-config.h
Normal 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
42
runtime/objc-env.h
Normal 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
306
runtime/objc-errors.mm
Normal 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
116
runtime/objc-exception.h
Normal 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
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
50
runtime/objc-file-old.h
Normal 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
165
runtime/objc-file-old.mm
Normal 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
52
runtime/objc-file.h
Normal 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
127
runtime/objc-file.mm
Normal 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
223
runtime/objc-gdb.h
Normal 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
41
runtime/objc-initialize.h
Normal 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
474
runtime/objc-initialize.mm
Normal 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
735
runtime/objc-internal.h
Normal 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
928
runtime/objc-layout.mm
Normal 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
54
runtime/objc-load.h
Normal 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
167
runtime/objc-load.mm
Normal 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
45
runtime/objc-loadmethod.h
Normal 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
367
runtime/objc-loadmethod.mm
Normal 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
89
runtime/objc-lockdebug.h
Normal 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
471
runtime/objc-lockdebug.mm
Normal 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
1217
runtime/objc-object.h
Normal file
File diff suppressed because it is too large
Load Diff
360
runtime/objc-opt.mm
Normal file
360
runtime/objc-opt.mm
Normal 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
1225
runtime/objc-os.h
Normal file
File diff suppressed because it is too large
Load Diff
778
runtime/objc-os.mm
Normal file
778
runtime/objc-os.mm
Normal 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
1022
runtime/objc-private.h
Normal file
File diff suppressed because it is too large
Load Diff
5
runtime/objc-probes.d
Normal file
5
runtime/objc-probes.d
Normal 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
41
runtime/objc-references.h
Normal 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
334
runtime/objc-references.mm
Normal 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
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
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
399
runtime/objc-runtime-old.h
Normal 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
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
2
runtime/objc-runtime.h
Normal file
@ -0,0 +1,2 @@
|
||||
#include <objc/runtime.h>
|
||||
#include <objc/message.h>
|
1033
runtime/objc-runtime.mm
Normal file
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
215
runtime/objc-sel-old.mm
Normal 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
49
runtime/objc-sel-set.h
Normal 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
176
runtime/objc-sel-set.mm
Normal 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
69
runtime/objc-sel-table.s
Normal 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
215
runtime/objc-sel.mm
Normal 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
67
runtime/objc-sync.h
Normal 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
327
runtime/objc-sync.mm
Normal 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;
|
||||
}
|
||||
|
365
runtime/objc-typeencoding.mm
Normal file
365
runtime/objc-typeencoding.mm
Normal 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
143
runtime/objc-weak.h
Normal 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
Loading…
Reference in New Issue
Block a user