From: helge Date: Fri, 3 Jun 2005 14:22:37 +0000 (+0000) Subject: bringing gnustep-objc r114 into the main branch X-Git-Url: https://err.no/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=efc80a92924c633fa0212ee7df79e8bdc6895bab;p=sope bringing gnustep-objc r114 into the main branch git-svn-id: http://svn.opengroupware.org/SOPE/trunk@833 e4a50df8-12e2-0310-a44c-efbce7f8a7e3 --- diff --git a/gnustep-objc/COPYING b/gnustep-objc/COPYING new file mode 100644 index 00000000..60549be5 --- /dev/null +++ b/gnustep-objc/COPYING @@ -0,0 +1,340 @@ + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc. + 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Library General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) 19yy + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) 19yy name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + , 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Library General +Public License instead of this License. diff --git a/gnustep-objc/COPYING.LIB b/gnustep-objc/COPYING.LIB new file mode 100644 index 00000000..161a3d1d --- /dev/null +++ b/gnustep-objc/COPYING.LIB @@ -0,0 +1,482 @@ + GNU LIBRARY GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1991 Free Software Foundation, Inc. + 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + +[This is the first released version of the library GPL. It is + numbered 2 because it goes with version 2 of the ordinary GPL.] + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +Licenses are intended to guarantee your freedom to share and change +free software--to make sure the software is free for all its users. + + This license, the Library General Public License, applies to some +specially designated Free Software Foundation software, and to any +other libraries whose authors decide to use it. You can use it for +your libraries, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if +you distribute copies of the library, or if you modify it. + + For example, if you distribute copies of the library, whether gratis +or for a fee, you must give the recipients all the rights that we gave +you. You must make sure that they, too, receive or can get the source +code. If you link a program with the library, you must provide +complete object files to the recipients so that they can relink them +with the library, after making changes to the library and recompiling +it. And you must show them these terms so they know their rights. + + Our method of protecting your rights has two steps: (1) copyright +the library, and (2) offer you this license which gives you legal +permission to copy, distribute and/or modify the library. + + Also, for each distributor's protection, we want to make certain +that everyone understands that there is no warranty for this free +library. If the library is modified by someone else and passed on, we +want its recipients to know that what they have is not the original +version, so that any problems introduced by others will not reflect on +the original authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that companies distributing free +software will individually obtain patent licenses, thus in effect +transforming the program into proprietary software. To prevent this, +we have made it clear that any patent must be licensed for everyone's +free use or not licensed at all. + + Most GNU software, including some libraries, is covered by the ordinary +GNU General Public License, which was designed for utility programs. This +license, the GNU Library General Public License, applies to certain +designated libraries. This license is quite different from the ordinary +one; be sure to read it in full, and don't assume that anything in it is +the same as in the ordinary license. + + The reason we have a separate public license for some libraries is that +they blur the distinction we usually make between modifying or adding to a +program and simply using it. Linking a program with a library, without +changing the library, is in some sense simply using the library, and is +analogous to running a utility program or application program. However, in +a textual and legal sense, the linked executable is a combined work, a +derivative of the original library, and the ordinary General Public License +treats it as such. + + Because of this blurred distinction, using the ordinary General +Public License for libraries did not effectively promote software +sharing, because most developers did not use the libraries. We +concluded that weaker conditions might promote sharing better. + + However, unrestricted linking of non-free programs would deprive the +users of those programs of all benefit from the free status of the +libraries themselves. This Library General Public License is intended to +permit developers of non-free programs to use free libraries, while +preserving your freedom as a user of such programs to change the free +libraries that are incorporated in them. (We have not seen how to achieve +this as regards changes in header files, but we have achieved it as regards +changes in the actual functions of the Library.) The hope is that this +will lead to faster development of free libraries. + + The precise terms and conditions for copying, distribution and +modification follow. Pay close attention to the difference between a +"work based on the library" and a "work that uses the library". The +former contains code derived from the library, while the latter only +works together with the library. + + Note that it is possible for a library to be covered by the ordinary +General Public License rather than by this special one. + + GNU LIBRARY GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License Agreement applies to any software library which +contains a notice placed by the copyright holder or other authorized +party saying it may be distributed under the terms of this Library +General Public License (also called "this License"). Each licensee is +addressed as "you". + + A "library" means a collection of software functions and/or data +prepared so as to be conveniently linked with application programs +(which use some of those functions and data) to form executables. + + The "Library", below, refers to any such software library or work +which has been distributed under these terms. A "work based on the +Library" means either the Library or any derivative work under +copyright law: that is to say, a work containing the Library or a +portion of it, either verbatim or with modifications and/or translated +straightforwardly into another language. (Hereinafter, translation is +included without limitation in the term "modification".) + + "Source code" for a work means the preferred form of the work for +making modifications to it. For a library, complete source code means +all the source code for all modules it contains, plus any associated +interface definition files, plus the scripts used to control compilation +and installation of the library. + + Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running a program using the Library is not restricted, and output from +such a program is covered only if its contents constitute a work based +on the Library (independent of the use of the Library in a tool for +writing it). Whether that is true depends on what the Library does +and what the program that uses the Library does. + + 1. You may copy and distribute verbatim copies of the Library's +complete source code as you receive it, in any medium, provided that +you conspicuously and appropriately publish on each copy an +appropriate copyright notice and disclaimer of warranty; keep intact +all the notices that refer to this License and to the absence of any +warranty; and distribute a copy of this License along with the +Library. + + You may charge a fee for the physical act of transferring a copy, +and you may at your option offer warranty protection in exchange for a +fee. + + 2. You may modify your copy or copies of the Library or any portion +of it, thus forming a work based on the Library, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) The modified work must itself be a software library. + + b) You must cause the files modified to carry prominent notices + stating that you changed the files and the date of any change. + + c) You must cause the whole of the work to be licensed at no + charge to all third parties under the terms of this License. + + d) If a facility in the modified Library refers to a function or a + table of data to be supplied by an application program that uses + the facility, other than as an argument passed when the facility + is invoked, then you must make a good faith effort to ensure that, + in the event an application does not supply such function or + table, the facility still operates, and performs whatever part of + its purpose remains meaningful. + + (For example, a function in a library to compute square roots has + a purpose that is entirely well-defined independent of the + application. Therefore, Subsection 2d requires that any + application-supplied function or table used by this function must + be optional: if the application does not supply it, the square + root function must still compute square roots.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Library, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Library, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote +it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Library. + +In addition, mere aggregation of another work not based on the Library +with the Library (or with a work based on the Library) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may opt to apply the terms of the ordinary GNU General Public +License instead of this License to a given copy of the Library. To do +this, you must alter all the notices that refer to this License, so +that they refer to the ordinary GNU General Public License, version 2, +instead of to this License. (If a newer version than version 2 of the +ordinary GNU General Public License has appeared, then you can specify +that version instead if you wish.) Do not make any other change in +these notices. + + Once this change is made in a given copy, it is irreversible for +that copy, so the ordinary GNU General Public License applies to all +subsequent copies and derivative works made from that copy. + + This option is useful when you wish to copy part of the code of +the Library into a program that is not a library. + + 4. You may copy and distribute the Library (or a portion or +derivative of it, under Section 2) in object code or executable form +under the terms of Sections 1 and 2 above provided that you accompany +it with the complete corresponding machine-readable source code, which +must be distributed under the terms of Sections 1 and 2 above on a +medium customarily used for software interchange. + + If distribution of object code is made by offering access to copy +from a designated place, then offering equivalent access to copy the +source code from the same place satisfies the requirement to +distribute the source code, even though third parties are not +compelled to copy the source along with the object code. + + 5. A program that contains no derivative of any portion of the +Library, but is designed to work with the Library by being compiled or +linked with it, is called a "work that uses the Library". Such a +work, in isolation, is not a derivative work of the Library, and +therefore falls outside the scope of this License. + + However, linking a "work that uses the Library" with the Library +creates an executable that is a derivative of the Library (because it +contains portions of the Library), rather than a "work that uses the +library". The executable is therefore covered by this License. +Section 6 states terms for distribution of such executables. + + When a "work that uses the Library" uses material from a header file +that is part of the Library, the object code for the work may be a +derivative work of the Library even though the source code is not. +Whether this is true is especially significant if the work can be +linked without the Library, or if the work is itself a library. The +threshold for this to be true is not precisely defined by law. + + If such an object file uses only numerical parameters, data +structure layouts and accessors, and small macros and small inline +functions (ten lines or less in length), then the use of the object +file is unrestricted, regardless of whether it is legally a derivative +work. (Executables containing this object code plus portions of the +Library will still fall under Section 6.) + + Otherwise, if the work is a derivative of the Library, you may +distribute the object code for the work under the terms of Section 6. +Any executables containing that work also fall under Section 6, +whether or not they are linked directly with the Library itself. + + 6. As an exception to the Sections above, you may also compile or +link a "work that uses the Library" with the Library to produce a +work containing portions of the Library, and distribute that work +under terms of your choice, provided that the terms permit +modification of the work for the customer's own use and reverse +engineering for debugging such modifications. + + You must give prominent notice with each copy of the work that the +Library is used in it and that the Library and its use are covered by +this License. You must supply a copy of this License. If the work +during execution displays copyright notices, you must include the +copyright notice for the Library among them, as well as a reference +directing the user to the copy of this License. Also, you must do one +of these things: + + a) Accompany the work with the complete corresponding + machine-readable source code for the Library including whatever + changes were used in the work (which must be distributed under + Sections 1 and 2 above); and, if the work is an executable linked + with the Library, with the complete machine-readable "work that + uses the Library", as object code and/or source code, so that the + user can modify the Library and then relink to produce a modified + executable containing the modified Library. (It is understood + that the user who changes the contents of definitions files in the + Library will not necessarily be able to recompile the application + to use the modified definitions.) + + b) Accompany the work with a written offer, valid for at + least three years, to give the same user the materials + specified in Subsection 6a, above, for a charge no more + than the cost of performing this distribution. + + c) If distribution of the work is made by offering access to copy + from a designated place, offer equivalent access to copy the above + specified materials from the same place. + + d) Verify that the user has already received a copy of these + materials or that you have already sent this user a copy. + + For an executable, the required form of the "work that uses the +Library" must include any data and utility programs needed for +reproducing the executable from it. However, as a special exception, +the source code distributed need not include anything that is normally +distributed (in either source or binary form) with the major +components (compiler, kernel, and so on) of the operating system on +which the executable runs, unless that component itself accompanies +the executable. + + It may happen that this requirement contradicts the license +restrictions of other proprietary libraries that do not normally +accompany the operating system. Such a contradiction means you cannot +use both them and the Library together in an executable that you +distribute. + + 7. You may place library facilities that are a work based on the +Library side-by-side in a single library together with other library +facilities not covered by this License, and distribute such a combined +library, provided that the separate distribution of the work based on +the Library and of the other library facilities is otherwise +permitted, and provided that you do these two things: + + a) Accompany the combined library with a copy of the same work + based on the Library, uncombined with any other library + facilities. This must be distributed under the terms of the + Sections above. + + b) Give prominent notice with the combined library of the fact + that part of it is a work based on the Library, and explaining + where to find the accompanying uncombined form of the same work. + + 8. You may not copy, modify, sublicense, link with, or distribute +the Library except as expressly provided under this License. Any +attempt otherwise to copy, modify, sublicense, link with, or +distribute the Library is void, and will automatically terminate your +rights under this License. However, parties who have received copies, +or rights, from you under this License will not have their licenses +terminated so long as such parties remain in full compliance. + + 9. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Library or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Library (or any work based on the +Library), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Library or works based on it. + + 10. Each time you redistribute the Library (or any work based on the +Library), the recipient automatically receives a license from the +original licensor to copy, distribute, link with or modify the Library +subject to these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 11. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Library at all. For example, if a patent +license would not permit royalty-free redistribution of the Library by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Library. + +If any portion of this section is held invalid or unenforceable under any +particular circumstance, the balance of the section is intended to apply, +and the section as a whole is intended to apply in other circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 12. If the distribution and/or use of the Library is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Library under this License may add +an explicit geographical distribution limitation excluding those countries, +so that distribution is permitted only in or among countries not thus +excluded. In such case, this License incorporates the limitation as if +written in the body of this License. + + 13. The Free Software Foundation may publish revised and/or new +versions of the Library General Public License from time to time. +Such new versions will be similar in spirit to the present version, +but may differ in detail to address new problems or concerns. + +Each version is given a distinguishing version number. If the Library +specifies a version number of this License which applies to it and +"any later version", you have the option of following the terms and +conditions either of that version or of any later version published by +the Free Software Foundation. If the Library does not specify a +license version number, you may choose any version ever published by +the Free Software Foundation. + + 14. If you wish to incorporate parts of the Library into other free +programs whose distribution conditions are incompatible with these, +write to the author to ask for permission. For software which is +copyrighted by the Free Software Foundation, write to the Free +Software Foundation; we sometimes make exceptions for this. Our +decision will be guided by the two goals of preserving the free status +of all derivatives of our free software and of promoting the sharing +and reuse of software generally. + + NO WARRANTY + + 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO +WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. +EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR +OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY +KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE +LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME +THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN +WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY +AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU +FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR +CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE +LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING +RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A +FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF +SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH +DAMAGES. + + END OF TERMS AND CONDITIONS + + Appendix: How to Apply These Terms to Your New Libraries + + If you develop a new library, and you want it to be of the greatest +possible use to the public, we recommend making it free software that +everyone can redistribute and change. You can do so by permitting +redistribution under these terms (or, alternatively, under the terms of the +ordinary General Public License). + + To apply these terms, attach the following notices to the library. It is +safest to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least the +"copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, + MA 02111-1307, USA + +Also add information on how to contact you by electronic and paper mail. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the library, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the + library `Frob' (a library for tweaking knobs) written by James Random Hacker. + + , 1 April 1990 + Ty Coon, President of Vice + +That's all there is to it! diff --git a/gnustep-objc/ChangeLog b/gnustep-objc/ChangeLog new file mode 100644 index 00000000..5af45f11 --- /dev/null +++ b/gnustep-objc/ChangeLog @@ -0,0 +1,105 @@ +2005-05-22 Sebastian Ley + + * added config.h for generic/amd64 (#1392) + +2005-05-17 Frank Reppin + + * added config.h for openbsd3.7 (#1383) + +2005-03-09 Helge Hess + + * GNUmakefile: added support for a gstep-make configure script + + * selector.c: include string.h to avoid some warnings + +2004-12-22 Helge Hess + + * added compiler-info.h for m68k/linux-gnu (as a copy of + powerpc/linux-gnu) + + * added compiler-info.h for sparc/linux-gnu (as a copy of solaris 2.9) + + * added compiler-info.h for arm/linux-gnu (as a copy of + powerpc/linux-gnu) + + * added compiler-info.h for mipsel/linux-gnu (as a copy of + mips/linux-gnu) + + * added compiler-info.h for hppa/linux-gnu (as a copy of hppa/hpux) + +2004-10-28 Helge Hess + + * added compiler-info.h for mips/gnu-linux, should fix OGo bug #992 + +2004-09-09 Helge Hess + + * GNUmakefile: include makefiles from GNUSTEP_MAKEFILES (for newer + gstep-make versions) + + * GNUmakefile: changed soname from ogo2.95.3 to lf2.95.3 + +2004-08-29 Helge Hess + + * added hack to install libobjc in FHS locations using, the library and + its headers will be installed in FHS_INSTALL_ROOT if specified + (eg make FHS_INSTALL_ROOT=/usr/local) + + * GNUmakefile: changed soname from 2.95.3 to ogo2.95.3 + +2004-06-10 Helge Hess + + * added config/powerpc/linux-gnu/compiler-info.h with some values which + sound reasonable, should be checked (but probably doesn't affect + operation of OGo) + +2004-03-09 Helge Hess + + * copied sparc/solaris2.6 configuration to sparc/solaris2.9 + +2003-11-14 Helge Hess + + * copied ix86/openbsd3.2 compiler-info.h to ix86/solaris2.9/, don't + know whether this is correct, but it should at least help with the + compilation ;-) + +2003-08-31 Helge Hess + + * config/ix86/freebsd/compiler-info.h, + config/ix86/openbsd3.2/compiler-info.h: removed define + STRUCTURE_SIZE_BOUNDARY for BSD platforms, seems to break basic + forwarding on OpenBSD (and probably FreeBSD) (thanks to Max Berger) + +2003-07-27 Helge Hess + + * added config/openbsd3.2 (thanks to Max Berger) + +2003-07-18 Helge Hess + + * added config/freebsd (thanks to znek) + +2002-11-01 Helge Hess + + * GNUmakefile (VERSION): corrected version from 1.0.0 to 2.95.3 + +2002-05-31 Helge Hess + + * archive.c: fixed for gcc 3.1 + + * hash.h: include stdlib.h for abort() + +Fri May 25 11:19:44 2001 Helge Hess + + * init.c (__objc_send_message_in_list): added bugfix as mentioned in + the gcc mailing list + +Fri Jan 5 11:08:32 2001 Helge Hess + + * encoding.c: added logging of current function in objc_error + +Thu Apr 20 10:38:24 2000 Helge Hess + + * objc.h (objc_selector ): removed precomputed selectors + +Tue Feb 29 16:57:14 2000 Helge Hess + + * MOF3 import diff --git a/gnustep-objc/GNUmakefile b/gnustep-objc/GNUmakefile new file mode 100644 index 00000000..6438c620 --- /dev/null +++ b/gnustep-objc/GNUmakefile @@ -0,0 +1,138 @@ +# +# GNUmakefile +# +# Copyright (C) 1998 MDlink online service center, Helge Hess +# +# +# Author: Helge Hess (helge@mdlink.de) +# +# This file is part of the MDlink Object Framework 2 (MOF2) +# +# Permission to use, copy, modify, and distribute this software and its +# documentation for any purpose and without fee is hereby granted, provided +# that the above copyright notice appear in all copies and that both that +# copyright notice and this permission notice appear in supporting +# documentation. +# +# We disclaim all warranties with regard to this software, including all +# implied warranties of merchantability and fitness, in no event shall +# we be liable for any special, indirect or consequential damages or any +# damages whatsoever resulting from loss of use, data or profits, whether in +# an action of contract, negligence or other tortious action, arising out of +# or in connection with the use or performance of this software. +# + +-include config.make +include $(GNUSTEP_MAKEFILES)/common.make + +PACKAGE_NAME=skyrix-objc +VERSION=lf2.95.3 + +GNUSTEP_INSTALLATION_DIR = $(GNUSTEP_SYSTEM_ROOT) + +LIBRARY_NAME = libobjc + +# dce, decosf1, irix, mach, os2, posix, pthreads, single, solaris, vxworks +THREADING = single + +GC_HEADER_FILES_DIR = ./gc/include +GC_HEADER_FILES = \ + cord.h \ + ec.h \ + gc.h \ + gc_alloc.h \ + gc_cpp.h \ + gc_inl.h \ + gc_inline.h \ + gc_typed.h \ + weakpointer.h \ + +libobjc_HEADER_FILES = \ + objc-decls.h \ + Object.h \ + Protocol.h \ + encoding.h \ + hash.h \ + objc-api.h \ + objc-list.h \ + objc-mem.h \ + objc.h \ + sarray.h \ + thr.h \ + typedstream.h \ +# NXConstStr.h \ + +libobjc_OBJC_FILES = \ + Object.m \ + Protocol.m \ + linking.m \ +# NXConstStr.m \ + +libobjc_C_FILES = \ + globals.c \ + archive.c \ + class.c \ + encoding.c \ + gc.c \ + hash.c \ + init.c \ + misc.c \ + nil_method.c \ + objects.c \ + sarray.c \ + selector.c \ + sendmsg.c \ + thr-backends/$(THREADING).c\ + thr.c \ + libobjc_entry.c \ + +ADDITIONAL_CPPFLAGS += \ + -pipe \ + -DSTDC_HEADERS=1\ + -DHAVE_STDLIB_H \ + -DOBJC_THREAD_BACKEND='"thr-backends/$(THREADING).h"'\ + +# -DOBJC_DEBUG=1 \ +# -DEBUG_DTABLE=1 \ + +ADDITIONAL_CFLAGS += -O2 -Wall + +libobjc_HEADER_FILES_DIR = . +libobjc_HEADER_FILES_INSTALL_DIR = /objc + +libobjc_DLL_DEF = libobjc.def + +ifeq ($(THREADING), single) +ADDITIONAL_CPPFLAGS += -DOBJC_WITHOUT_THREADING +endif + +ifeq ($(gc), yes) +ADDITIONAL_CPPFLAGS += -DOBJC_WITH_GC=1 -DGC_DEBUG=1 +ADDITIONAL_CPPFLAGS += -DDEBUG_OBJC_GC=0 +libobjc_LIBRARIES_DEPEND_UPON += -lgc + +ifeq ($(THREADING), solaris) +ADDITIONAL_CPPFLAGS += -DSOLARIS_THREADS +endif + +else # gc +ADDITIONAL_CPPFLAGS += -DOBJC_WITH_GC=0 -DDEBUG_OBJC_GC=0 +endif + +ifeq ($(gc), xyes) +GC_OFILES = \ + alloc.o reclaim.o allchblk.o misc.o mach_dep.o os_dep.o mark_rts.o \ + headers.o mark.o obj_map.o blacklst.o finalize.o new_hblk.o dbg_mlc.o \ + malloc.o stubborn.o checksums.o solaris_threads.o irix_threads.o \ + typd_mlc.o ptr_chck.o mallocx.o solaris_pthreads.o \ + dyn_load.o \ + +ADDITIONAL_LIBRARY_OBJ_FILES = $(addprefix gc/, $(GC_OFILES)) +endif + +-include config/$(GNUSTEP_TARGET_CPU)/config.make +-include config/$(GNUSTEP_TARGET_CPU)/$(GNUSTEP_TARGET_OS)/config.make + +-include GNUmakefile.preamble +include $(GNUSTEP_MAKEFILES)/library.make +-include GNUmakefile.postamble diff --git a/gnustep-objc/GNUmakefile.postamble b/gnustep-objc/GNUmakefile.postamble new file mode 100644 index 00000000..bb287cc0 --- /dev/null +++ b/gnustep-objc/GNUmakefile.postamble @@ -0,0 +1,34 @@ +# postprocessing + +ADDITIONAL_INCLUDE_DIRS += \ + -Iconfig/$(GNUSTEP_TARGET_CPU)/$(GNUSTEP_TARGET_OS) \ + -Iconfig/$(GNUSTEP_TARGET_CPU)/generic \ + -I.. -I. + +before-all:: $(GNUSTEP_OBJ_DIR)/thr-backends + @(if ! test -L ./objc; then\ + ln -sf . ./objc;\ + fi) + +after-clean :: + rm -f ./objc + +distclean :: + rm -f config.make + +ifeq ($(gc),xyes) + +after-install:: + for file in $(GC_HEADER_FILES) __done; do \ + if [ $$file != __done ]; then \ + $(INSTALL_DATA) $(GC_HEADER_FILES_DIR)/$$file \ + $(GNUSTEP_HEADERS)$(libobjc_HEADER_FILES_INSTALL_DIR)/$$file ; \ + fi; \ + done; + +endif + +$(GNUSTEP_OBJ_DIR)/thr-backends: $(GNUSTEP_OBJ_DIR) + @if [ ! -d $@ ]; then echo mkdir $@; mkdir $@; fi + +include fhs.make diff --git a/gnustep-objc/NXConstStr.h b/gnustep-objc/NXConstStr.h new file mode 100644 index 00000000..c9799544 --- /dev/null +++ b/gnustep-objc/NXConstStr.h @@ -0,0 +1,44 @@ +/* Interface for the NXConstantString class for Objective-C. + Copyright (C) 1995 Free Software Foundation, Inc. + Contributed by Pieter J. Schoenmakers + +This file is part of GNU CC. + +GNU CC is free software; you can redistribute it and/or modify it +under the terms of the GNU General Public License as published by the +Free Software Foundation; either version 2, or (at your option) any +later version. + +GNU CC is distributed in the hope that it will be useful, but WITHOUT +ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public +License for more details. + +You should have received a copy of the GNU General Public License +along with GNU CC; see the file COPYING. If not, write to +the Free Software Foundation, 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + +/* As a special exception, if you link this library with files + compiled with GCC to produce an executable, this does not cause + the resulting executable to be covered by the GNU General Public License. + This exception does not however invalidate any other reasons why + the executable file might be covered by the GNU General Public License. */ + +#ifndef __nxconstantstring_INCLUDE_GNU +#define __nxconstantstring_INCLUDE_GNU + +#include "objc/Object.h" + +@interface NXConstantString: Object +{ + char *c_string; + unsigned int len; +} + +-(const char *) cString; +-(unsigned int) length; + +@end + +#endif diff --git a/gnustep-objc/NXConstStr.m b/gnustep-objc/NXConstStr.m new file mode 100644 index 00000000..4d2f3e1d --- /dev/null +++ b/gnustep-objc/NXConstStr.m @@ -0,0 +1,42 @@ +/* Implementation of the NXConstantString class for Objective-C. + Copyright (C) 1995 Free Software Foundation, Inc. + Contributed by Pieter J. Schoenmakers + +This file is part of GNU CC. + +GNU CC is free software; you can redistribute it and/or modify it +under the terms of the GNU General Public License as published by the +Free Software Foundation; either version 2, or (at your option) any +later version. + +GNU CC is distributed in the hope that it will be useful, but WITHOUT +ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public +License for more details. + +You should have received a copy of the GNU General Public License +along with GNU CC; see the file COPYING. If not, write to +the Free Software Foundation, 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + +/* As a special exception, if you link this library with files + compiled with GCC to produce an executable, this does not cause + the resulting executable to be covered by the GNU General Public License. + This exception does not however invalidate any other reasons why + the executable file might be covered by the GNU General Public License. */ + +#include "objc/NXConstStr.h" + +@implementation NXConstantString + +-(const char *) cString +{ + return (c_string); +} /* -cString */ + +-(unsigned int) length +{ + return (len); +} /* -length */ + +@end diff --git a/gnustep-objc/Object.h b/gnustep-objc/Object.h new file mode 100644 index 00000000..a762acc3 --- /dev/null +++ b/gnustep-objc/Object.h @@ -0,0 +1,124 @@ +/* Interface for the Object class for Objective-C. + Copyright (C) 1993, 1994, 1995 Free Software Foundation, Inc. + +This file is part of GNU CC. + +GNU CC is free software; you can redistribute it and/or modify it +under the terms of the GNU General Public License as published by the +Free Software Foundation; either version 2, or (at your option) any +later version. + +GNU CC is distributed in the hope that it will be useful, but WITHOUT +ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public +License for more details. + +You should have received a copy of the GNU General Public License +along with GNU CC; see the file COPYING. If not, write to +the Free Software Foundation, 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + +/* As a special exception, if you link this library with files compiled + with GCC to produce an executable, this does not cause the resulting + executable to be covered by the GNU General Public License. This + exception does not however invalidate any other reasons why the + executable file might be covered by the GNU General Public License. */ + +#ifndef __object_INCLUDE_GNU +#define __object_INCLUDE_GNU + +#include +#include + +/* + * All classes are derived from Object. As such, + * this is the overhead tacked onto those objects. + */ +@interface Object +{ + Class isa; /* A pointer to the instance's class structure */ +} + + /* Initializing classes and instances */ ++ initialize; +- init; + + /* Creating, freeing, and copying instances */ ++ new; ++ alloc; +- free; +- copy; +- shallowCopy; +- deepen; +- deepCopy; + + /* Identifying classes */ +- (Class)class; +- (Class)superClass; +- (MetaClass)metaClass; +- (const char *)name; + + /* Identifying and comparing objects */ +- self; +- (unsigned int)hash; +- (BOOL)isEqual:anObject; +- (int)compare:anotherObject; + + /* Testing object type */ +- (BOOL)isMetaClass; +- (BOOL)isClass; +- (BOOL)isInstance; + + /* Testing inheritance relationships */ +- (BOOL)isKindOf:(Class)aClassObject; +- (BOOL)isMemberOf:(Class)aClassObject; +- (BOOL)isKindOfClassNamed:(const char *)aClassName; +- (BOOL)isMemberOfClassNamed:(const char *)aClassName; + + /* Testing class functionality */ ++ (BOOL)instancesRespondTo:(SEL)aSel; +- (BOOL)respondsTo:(SEL)aSel; + + /* Testing protocol conformance */ +- (BOOL)conformsTo:(Protocol*)aProtocol; + + /* Introspection */ ++ (IMP)instanceMethodFor:(SEL)aSel; +- (IMP)methodFor:(SEL)aSel; ++ (struct objc_method_description *)descriptionForInstanceMethod:(SEL)aSel; +- (struct objc_method_description *)descriptionForMethod:(SEL)aSel; + + /* Sending messages determined at run time */ +- perform:(SEL)aSel; +- perform:(SEL)aSel with:anObject; +- perform:(SEL)aSel with:anObject1 with:anObject2; + + /* Forwarding */ +- (retval_t)forward:(SEL)aSel :(arglist_t)argFrame; +- (retval_t)performv:(SEL)aSel :(arglist_t)argFrame; + + /* Posing */ ++ poseAs:(Class)aClassObject; +- (Class)transmuteClassTo:(Class)aClassObject; + + /* Enforcing intentions */ +- subclassResponsibility:(SEL)aSel; +- notImplemented:(SEL)aSel; +- shouldNotImplement:(SEL)aSel; + + /* Error handling */ +- doesNotRecognize:(SEL)aSel; +- error:(const char *)aString, ...; + + /* Archiving */ ++ (int)version; ++ setVersion:(int)aVersion; ++ (int)streamVersion: (TypedStream*)aStream; + +- read: (TypedStream*)aStream; +- write: (TypedStream*)aStream; +- awake; + +@end + +#endif diff --git a/gnustep-objc/Object.m b/gnustep-objc/Object.m new file mode 100644 index 00000000..ef91029e --- /dev/null +++ b/gnustep-objc/Object.m @@ -0,0 +1,388 @@ +/* The implementation of class Object for Objective-C. + Copyright (C) 1993, 1994, 1995, 1997 Free Software Foundation, Inc. + +This file is part of GNU CC. + +GNU CC is free software; you can redistribute it and/or modify it +under the terms of the GNU General Public License as published by the +Free Software Foundation; either version 2, or (at your option) any +later version. + +GNU CC is distributed in the hope that it will be useful, but WITHOUT +ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public +License for more details. + +You should have received a copy of the GNU General Public License +along with GNU CC; see the file COPYING. If not, write to +the Free Software Foundation, 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + +/* As a special exception, if you link this library with files compiled + with GCC to produce an executable, this does not cause the resulting + executable to be covered by the GNU General Public License. This + exception does not however invalidate any other reasons why the + executable file might be covered by the GNU General Public License. */ + +#include +#include +#include "objc/Object.h" +#include "objc/Protocol.h" +#include "objc/objc-api.h" + +extern int errno; + +#define MAX_CLASS_NAME_LEN 256 + +@implementation Object + ++ initialize +{ + return self; +} + +- init +{ + return self; +} + ++ new +{ + return [[self alloc] init]; +} + ++ alloc +{ + return class_create_instance(self); +} + +- free +{ + return object_dispose(self); +} + +- copy +{ + return [[self shallowCopy] deepen]; +} + +- shallowCopy +{ + return object_copy(self); +} + +- deepen +{ + return self; +} + +- deepCopy +{ + return [self copy]; +} + +- (Class)class +{ + return object_get_class(self); +} + +- (Class)superClass +{ + return object_get_super_class(self); +} + +- (MetaClass)metaClass +{ + return object_get_meta_class(self); +} + +- (const char *)name +{ + return object_get_class_name(self); +} + +- self +{ + return self; +} + +- (unsigned int)hash +{ + return (size_t)self; +} + +- (BOOL)isEqual:anObject +{ + return self==anObject; +} + +- (int)compare:anotherObject; +{ + if ([self isEqual:anotherObject]) + return 0; + // Ordering objects by their address is pretty useless, + // so subclasses should override this is some useful way. + else if (self > anotherObject) + return 1; + else + return -1; +} + +- (BOOL)isMetaClass +{ + return NO; +} + +- (BOOL)isClass +{ + return object_is_class(self); +} + +- (BOOL)isInstance +{ + return object_is_instance(self); +} + +- (BOOL)isKindOf:(Class)aClassObject +{ + Class class; + + for (class = self->isa; class!=Nil; class = class_get_super_class(class)) + if (class==aClassObject) + return YES; + return NO; +} + +- (BOOL)isMemberOf:(Class)aClassObject +{ + return self->isa==aClassObject; +} + +- (BOOL)isKindOfClassNamed:(const char *)aClassName +{ + Class class; + + if (aClassName!=NULL) + for (class = self->isa; class!=Nil; class = class_get_super_class(class)) + if (!strcmp(class_get_class_name(class), aClassName)) + return YES; + return NO; +} + +- (BOOL)isMemberOfClassNamed:(const char *)aClassName +{ + return ((aClassName!=NULL) + &&!strcmp(class_get_class_name(self->isa), aClassName)); +} + ++ (BOOL)instancesRespondTo:(SEL)aSel +{ + return class_get_instance_method(self, aSel)!=METHOD_NULL; +} + +- (BOOL)respondsTo:(SEL)aSel +{ + return ((object_is_instance(self) + ?class_get_instance_method(self->isa, aSel) + :class_get_class_method(self->isa, aSel))!=METHOD_NULL); +} + ++ (IMP)instanceMethodFor:(SEL)aSel +{ + return method_get_imp(class_get_instance_method(self, aSel)); +} + +// Indicates if the receiving class or instance conforms to the given protocol +// not usually overridden by subclasses +// +// Modified 9/5/94 to always search the class object's protocol list, rather +// than the meta class. + ++ (BOOL) conformsTo: (Protocol*)aProtocol +{ + int i; + struct objc_protocol_list* proto_list; + id parent; + + for (proto_list = ((Class)self)->protocols; + proto_list; proto_list = proto_list->next) + { + for (i=0; i < proto_list->count; i++) + { + if ([proto_list->list[i] conformsTo: aProtocol]) + return YES; + } + } + + if ((parent = [self superClass])) + return [parent conformsTo: aProtocol]; + else + return NO; +} + +- (BOOL) conformsTo: (Protocol*)aProtocol +{ + return [[self class] conformsTo:aProtocol]; +} + +- (IMP)methodFor:(SEL)aSel +{ + return (method_get_imp(object_is_instance(self) + ?class_get_instance_method(self->isa, aSel) + :class_get_class_method(self->isa, aSel))); +} + ++ (struct objc_method_description *)descriptionForInstanceMethod:(SEL)aSel +{ + return ((struct objc_method_description *) + class_get_instance_method(self, aSel)); +} + +- (struct objc_method_description *)descriptionForMethod:(SEL)aSel +{ + return ((struct objc_method_description *) + (object_is_instance(self) + ?class_get_instance_method(self->isa, aSel) + :class_get_class_method(self->isa, aSel))); +} + +- perform:(SEL)aSel +{ + IMP msg = objc_msg_lookup(self, aSel); + if (!msg) + return [self error:"invalid selector passed to %s", sel_get_name(_cmd)]; + return (*msg)(self, aSel); +} + +- perform:(SEL)aSel with:anObject +{ + IMP msg = objc_msg_lookup(self, aSel); + if (!msg) + return [self error:"invalid selector passed to %s", sel_get_name(_cmd)]; + return (*msg)(self, aSel, anObject); +} + +- perform:(SEL)aSel with:anObject1 with:anObject2 +{ + IMP msg = objc_msg_lookup(self, aSel); + if (!msg) + return [self error:"invalid selector passed to %s", sel_get_name(_cmd)]; + return (*msg)(self, aSel, anObject1, anObject2); +} + +- (retval_t)forward:(SEL)aSel :(arglist_t)argFrame +{ + return (retval_t)[self doesNotRecognize: aSel]; +} + +- (retval_t)performv:(SEL)aSel :(arglist_t)argFrame +{ + return objc_msg_sendv(self, aSel, argFrame); +} + ++ poseAs:(Class)aClassObject +{ + return class_pose_as(self, aClassObject); +} + +- (Class)transmuteClassTo:(Class)aClassObject +{ + if (object_is_instance(self)) + if (class_is_class(aClassObject)) + if (class_get_instance_size(aClassObject)==class_get_instance_size(isa)) + if ([self isKindOf:aClassObject]) + { + Class old_isa = isa; + isa = aClassObject; + return old_isa; + } + return nil; +} + +- subclassResponsibility:(SEL)aSel +{ + return [self error:"subclass should override %s", sel_get_name(aSel)]; +} + +- notImplemented:(SEL)aSel +{ + return [self error:"method %s not implemented", sel_get_name(aSel)]; +} + +- shouldNotImplement:(SEL)aSel +{ + return [self error:"%s should not implement %s", + object_get_class_name(self), sel_get_name(aSel)]; +} + +- doesNotRecognize:(SEL)aSel +{ + return [self error:"%s does not recognize %s", + object_get_class_name(self), sel_get_name(aSel)]; +} + +#ifdef __alpha__ +extern size_t strlen(const char*); +#endif + +- error:(const char *)aString, ... +{ +#define FMT "error: %s (%s)\n%s\n" + char fmt[(strlen((char*)FMT)+strlen((char*)object_get_class_name(self)) + +((aString!=NULL)?strlen((char*)aString):0)+8)]; + va_list ap; + + sprintf(fmt, FMT, object_get_class_name(self), + object_is_instance(self) ? "instance" : "class", + (aString!=NULL)?aString:""); + va_start(ap, aString); + objc_verror(self, OBJC_ERR_UNKNOWN, fmt, ap); + va_end(ap); + return nil; +#undef FMT +} + ++ (int)version +{ + return class_get_version(self); +} + ++ setVersion:(int)aVersion +{ + class_set_version(self, aVersion); + return self; +} + ++ (int)streamVersion: (TypedStream*)aStream +{ + if (aStream->mode == OBJC_READONLY) + return objc_get_stream_class_version (aStream, self); + else + return class_get_version (self); +} + +// These are used to write or read the instance variables +// declared in this particular part of the object. Subclasses +// should extend these, by calling [super read/write: aStream] +// before doing their own archiving. These methods are private, in +// the sense that they should only be called from subclasses. + +- read: (TypedStream*)aStream +{ + // [super read: aStream]; + return self; +} + +- write: (TypedStream*)aStream +{ + // [super write: aStream]; + return self; +} + +- awake +{ + // [super awake]; + return self; +} + +@end diff --git a/gnustep-objc/Protocol.h b/gnustep-objc/Protocol.h new file mode 100644 index 00000000..9d9b3217 --- /dev/null +++ b/gnustep-objc/Protocol.h @@ -0,0 +1,55 @@ +/* Declare the class Protocol for Objective C programs. + Copyright (C) 1993 Free Software Foundation, Inc. + +This file is part of GNU CC. + +GNU CC is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU CC is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU CC; see the file COPYING. If not, write to +the Free Software Foundation, 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + +/* As a special exception, if you link this library with files + compiled with GCC to produce an executable, this does not cause + the resulting executable to be covered by the GNU General Public License. + This exception does not however invalidate any other reasons why + the executable file might be covered by the GNU General Public License. */ + +#ifndef __Protocol_INCLUDE_GNU +#define __Protocol_INCLUDE_GNU + +#include "objc/Object.h" + +@interface Protocol : Object +{ +@private + char *protocol_name; + struct objc_protocol_list *protocol_list; + struct objc_method_description_list *instance_methods, *class_methods; +} + +/* Obtaining attributes intrinsic to the protocol */ + +- (const char *)name; + +/* Testing protocol conformance */ + +- (BOOL) conformsTo: (Protocol *)aProtocolObject; + +/* Looking up information specific to a protocol */ + +- (struct objc_method_description *) descriptionForInstanceMethod:(SEL)aSel; +- (struct objc_method_description *) descriptionForClassMethod:(SEL)aSel; + +@end + +#endif /* __Protocol_INCLUDE_GNU */ diff --git a/gnustep-objc/Protocol.m b/gnustep-objc/Protocol.m new file mode 100644 index 00000000..206da3d3 --- /dev/null +++ b/gnustep-objc/Protocol.m @@ -0,0 +1,129 @@ +/* This file contains the implementation of class Protocol. + Copyright (C) 1993 Free Software Foundation, Inc. + +This file is part of GNU CC. + +GNU CC is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU CC is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU CC; see the file COPYING. If not, write to +the Free Software Foundation, 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + +/* As a special exception, if you link this library with files + compiled with GCC to produce an executable, this does not cause + the resulting executable to be covered by the GNU General Public License. + This exception does not however invalidate any other reasons why + the executable file might be covered by the GNU General Public License. */ + +#include +#include "objc/Protocol.h" +#include "objc/objc-api.h" + +/* Method description list */ +struct objc_method_description_list { + int count; + struct objc_method_description list[1]; +}; + + +@implementation Protocol +{ +@private + char *protocol_name; + struct objc_protocol_list *protocol_list; + struct objc_method_description_list *instance_methods, *class_methods; +} + +/* Obtaining attributes intrinsic to the protocol */ + +- (const char *)name +{ + return protocol_name; +} + +/* Testing protocol conformance */ + +- (BOOL) conformsTo: (Protocol *)aProtocolObject +{ + int i; + struct objc_protocol_list* proto_list; + + if (!strcmp(aProtocolObject->protocol_name, self->protocol_name)) + return YES; + + for (proto_list = protocol_list; proto_list; proto_list = proto_list->next) + { + for (i=0; i < proto_list->count; i++) + { + if ([proto_list->list[i] conformsTo: aProtocolObject]) + return YES; + } + } + + return NO; +} + +/* Looking up information specific to a protocol */ + +- (struct objc_method_description *) descriptionForInstanceMethod:(SEL)aSel +{ + int i; + struct objc_protocol_list* proto_list; + const char* name = sel_get_name (aSel); + struct objc_method_description *result; + + for (i = 0; i < instance_methods->count; i++) + { + if (!strcmp ((char*)instance_methods->list[i].name, name)) + return &(instance_methods->list[i]); + } + + for (proto_list = protocol_list; proto_list; proto_list = proto_list->next) + { + for (i=0; i < proto_list->count; i++) + { + if ((result = [proto_list->list[i] + descriptionForInstanceMethod: aSel])) + return result; + } + } + + return NULL; +} + +- (struct objc_method_description *) descriptionForClassMethod:(SEL)aSel; +{ + int i; + struct objc_protocol_list* proto_list; + const char* name = sel_get_name (aSel); + struct objc_method_description *result; + + for (i = 0; i < class_methods->count; i++) + { + if (!strcmp ((char*)class_methods->list[i].name, name)) + return &(class_methods->list[i]); + } + + for (proto_list = protocol_list; proto_list; proto_list = proto_list->next) + { + for (i=0; i < proto_list->count; i++) + { + if ((result = [proto_list->list[i] + descriptionForClassMethod: aSel])) + return result; + } + } + + return NULL; +} + +@end diff --git a/gnustep-objc/README b/gnustep-objc/README new file mode 100644 index 00000000..f478d67d --- /dev/null +++ b/gnustep-objc/README @@ -0,0 +1,97 @@ + +GNU Objective C notes +********************* + +This document is to explain what has been done, and a little about how +specific features differ from other implementations. The runtime has +been completely rewritten in gcc 2.4. The earlier runtime had several +severe bugs and was rather incomplete. The compiler has had several +new features added as well. + +This is not documentation for Objective C, it is usable to someone +who knows Objective C from somewhere else. + + +Runtime API functions +===================== + +The runtime is modeled after the NeXT Objective C runtime. That is, +most functions have semantics as it is known from the NeXT. The +names, however, have changed. All runtime API functions have names +of lowercase letters and underscores as opposed to the +`traditional' mixed case names. + The runtime api functions are not documented as of now. +Someone offered to write it, and did it, but we were not allowed to +use it by his university (Very sad story). We have started writing +the documentation over again. This will be announced in appropriate +places when it becomes available. + + +Protocols +========= + +Protocols are now fully supported. The semantics is exactly as on the +NeXT. There is a flag to specify how protocols should be typechecked +when adopted to classes. The normal typechecker requires that all +methods in a given protocol must be implemented in the class that +adopts it -- it is not enough to inherit them. The flag +`-Wno-protocol' causes it to allow inherited methods, while +`-Wprotocols' is the default which requires them defined. + + ++initialize +=========== + +This method, if defined, is called before any other instance or class +methods of that particular class. This method is not inherited, and +is thus not called as initializer for a subclass that doesn't define +it itself. Thus, each +initialize method is called exactly once (or +never if no methods of that particular class is never called). +Besides this, it is allowed to have several +initialize methods, one +for each category. The order in which these (multiple methods) are +called is not well defined. I am not completely certain what the +semantics of this method is for other implementations, but this is +how it works for GNU Objective C. + + +Passivation/Activation/Typedstreams +=================================== + +This is supported in the style of NeXT TypedStream's. Consult the +headerfile Typedstreams.h for api functions. I (Kresten) have +rewritten it in Objective C, but this implementation is not part of +2.4, it is available from the GNU Objective C prerelease archive. + There is one difference worth noting concerning objects stored with +objc_write_object_reference (aka NXWriteObjectReference). When these +are read back in, their object is not guaranteed to be available until +the `-awake' method is called in the object that requests that object. +To objc_read_object you must pass a pointer to an id, which is valid +after exit from the function calling it (like e.g. an instance +variable). In general, you should not use objects read in until the +-awake method is called. + + +Acknowledgements +================ + +The GNU Objective C team: Geoffrey Knauth (manager), +Tom Wood (compiler) and Kresten Krab Thorup + (runtime) would like to thank a some people for +participating in the development of the present GNU Objective C. + +Paul Burchard and Andrew McCallum + has been very helpful debugging the +runtime. Eric Herring has been very helpful +cleaning up after the documentation-copyright disaster and is now +helping with the new documentation. + +Steve Naroff and Richard Stallman + has been very helpful with implementation details +in the compiler. + + +Bug Reports +=========== + +Please read the section `Submitting Bugreports' of the gcc manual +before you submit any bugs. diff --git a/gnustep-objc/README.threads b/gnustep-objc/README.threads new file mode 100644 index 00000000..5f15bd9c --- /dev/null +++ b/gnustep-objc/README.threads @@ -0,0 +1,50 @@ +============================================================================== +README.threads - Wed Nov 29 15:16:24 EST 1995 +------------------------------------------------------------------------------ + +Limited documentation is available in the THREADS file. + +This version has been tested on Sun Solaris, SGI Irix, and Windows NT. +It should also work on any single threaded system. + +Thanks go to the following people for help test and debug the library: + + Scott Christley, scottc@ocbi.com + Andrew McCallum, mccallum@cs.rochester.edu + +galen +gchunt@cs.rochester.edu + +Any questions, bug reports, etc should be directed to: + +Scott Christley, scottc@ocbi.com + +Please do not bug Galen with email as he no longer supports the code. + +============================================================================== +Changes from prior releases (in revered chronological order): +------------------------------------------------------------------------------ + +* Fixed bug in copy part of sarray_realloc. I had an < which should + have been <=. (Bug report from Scott). + +------------------------------------------------------------------------------ + +* Support for DEC OSF/1 is definitely broken. My programs always + seg-fault when I link with libpthreads.a. + +* Thread id's are no longer int's, but are instead of type + _objc_thread_t which is typedef'ed from a void *. An invalid thread + id is denoted by NULL and not -1 as before. + +------------------------------------------------------------------------------ + +* Renamed thread-winnt.c to thread-win32.c to better reflect support + for the API on both Windows NT and Windows 95 platforms. + (Who knows, maybe even Win32s :-). + +* Fixed bugs in Win32 support as per report from Scott Christley. + +* Fixed bug in sarray_get as per report from Scott Christley. + + diff --git a/gnustep-objc/THREADS b/gnustep-objc/THREADS new file mode 100644 index 00000000..9dfbbed9 --- /dev/null +++ b/gnustep-objc/THREADS @@ -0,0 +1,374 @@ +This file describes in little detail the modifications to the +Objective-C runtime needed to make it thread safe. + +First off, kudos to Galen Hunt who is the author of this great work. + +If you have an comments or just want to know where to +send me money to express your undying gratitude for threading the +Objective-C runtime you can reach Galen at: + + gchunt@cs.rochester.edu + +Any questions, comments, bug reports, etc. should send email either to the +GCC bug account or to: + + Scott Christley + +* Sarray Threading: + +The most critical component of the Objective-C runtime is the sparse array +structure (sarray). Sarrays store object selectors and implementations. +Following in the tradition of the Objective-C runtime, my threading +support assumes that fast message dispatching is far more important +than *ANY* and *ALL* other operations. The message dispatching thus +uses *NO* locks on any kind. In fact, if you look in sarray.h, you +will notice that the message dispatching has not been modified. +Instead, I have modified the sarray management functions so that all +updates to the sarray data structure can be made in parallel will +message dispatching. + +To support concurrent message dispatching, no dynamically allocated +sarray data structures are freed while more than one thread is +operational. Sarray data structures that are no longer in use are +kept in a linked list of garbage and are released whenever the program +is operating with a single thread. The programmer can also flush the +garbage list by calling sarray_remove_garbage when the programmer can +ensure that no message dispatching is taking place concurrently. The +amount of un-reclaimed sarray garbage should normally be extremely +small in a real program as sarray structures are freed only when using +the "poseAs" functionality and early in program initialization, which +normally occurs while the program is single threaded. + +****************************************************************************** +* Static Variables: + +The following variables are either statically or globally defined. This list +does not include variables which are internal to implementation dependent +versions of thread-*.c. + +The following threading designations are used: + SAFE : Implicitly thread safe. + SINGLE : Must only be used in single thread mode. + MUTEX : Protected by single global mutex objc_runtime_mutex. + UNUSED : Not used in the runtime. + +Variable Name: Usage: Defined: Also used in: +=========================== ====== ============ ===================== +__objc_class_hash MUTEX class.c +__objc_class_links_resolved UNUSED class.c runtime.h +__objc_class_number MUTEX class.c +__objc_dangling_categories UNUSED init.c +__objc_module_list MUTEX init.c +__objc_selector_array MUTEX selector.c +__objc_selector_hash MUTEX selector.c +__objc_selector_max_index MUTEX selector.c sendmsg.c runtime.h +__objc_selector_names MUTEX selector.c +__objc_thread_exit_status SAFE thread.c +__objc_uninstalled_dtable MUTEX sendmsg.c selector.c +_objc_load_callback SAFE init.c objc-api.h +_objc_lookup_class SAFE class.c objc-api.h +_objc_object_alloc SINGLE objects.c objc-api.h +_objc_object_copy SINGLE objects.c objc-api.h +_objc_object_dispose SINGLE objects.c objc-api.h +frwd_sel SAFE2 sendmsg.c +idxsize MUTEX sarray.c sendmsg.c sarray.h +initialize_sel SAFE2 sendmsg.c +narrays MUTEX sarray.c sendmsg.c sarray.h +nbuckets MUTEX sarray.c sendmsg.c sarray.h +nindices MUTEX sarray.c sarray.h +previous_constructors SAFE1 init.c +proto_class SAFE1 init.c +unclaimed_categories MUTEX init.c +unclaimed_proto_list MUTEX init.c +uninitialized_statics MUTEX init.c + +Notes: +1) Initialized once in unithread mode. +2) Initialized value will always be same, guaranteed by lock on selector + hash table. + + +****************************************************************************** +* Frontend/Backend design: + +The design of the Objective-C runtime thread and mutex functions utilizes a +frontend/backend implementation. + +The frontend, as characterized by the files thr.h and thr.c, is a set +of platform independent structures and functions which represent the +user interface. Objective-C programs should use these structures and +functions for their thread and mutex work if they wish to maintain a +high degree of portability across platforms. + +The backend is composed of a file with the necessary code to map the ObjC +thread and mutex to a platform specific implementation. For example, the +file thr-solaris.c contains the implementation for Solaris. When you +configure GCC, it attempts to pick an appropriate backend file for the +target platform; however, you can override this choice by assign the +OBJC_THREAD_FILE make variable to the basename of the backend file. This +is especially useful on platforms which have multiple thread libraries. +For example: + + make OBJC_THREAD_FILE=thr-posix + +would indicate that the generic posix backend file, thr-posix.c, should be +compiled with the ObjC runtime library. If your platform does not support +threads then you should specify the OBJC_THREAD_FILE=thr-single backend file +to compile the ObjC runtime library without thread or mutex support; note +that programs which rely upon the ObjC thread and mutex functions will +compile and link correctly but attempting to create a thread or mutex will +result in an error. + +It is questionable whether it is really necessary to have both a +frontend and backend function for all available functionality. On the +one hand, it provides a clear, consistent differentiation between what +is public and what is private with the downside of having the overhead +of multiple functions calls. For example, the function to have a thread +yield the processor is objc_thread_yield; in the current implementation +this produces a function call set: + +objc_thread_yield() -> __objc_thread_yield() -> system yield function + +This has two extra function calls over calling the platform specific function +explicitly, but the issue is whether only the overhead of a single function +is necessary. + +objc_thread_yield() -> system yield function + +This breaks the public/private dichotomy between the frontend/backend +for the sake of efficiency. It is possible to just use a preprocessor +define so as to eliminate the extra function call: + +#define objc_thread_yield() __objc_thread_yield() + +This has the undesirable effect that if objc_thread_yield is actually +turned into a function based upon future need; then ObjC programs which +access the thread functions would need to be recompiled versus just +being relinked. + +****************************************************************************** +* Threads: + +The thread system attempts to create multiple threads using whatever +operating system or library thread support is available. It does +assume that all system functions are thread safe. Notably this means +that the system implementation of malloc and free must be thread safe. +If a system has multiple processors, the threads are configured for +full parallel processing. + +* Backend initialization functions + +__objc_init_thread_system(void), int + Initialize the thread subsystem. Called once by __objc_exec_class. + Return -1 if error otherwise return 0. + +__objc_close_thread_system(void), int + Closes the thread subsystem, not currently guaranteed to be called. + Return -1 if error otherwise return 0. + +***** +* Frontend thread functions +* User programs should use these functions. + +objc_thread_detach(SEL selector, id object, id argument), objc_thread_t + Creates and detaches a new thread. The new thread starts by + sending the given selector with a single argument to the + given object. + +objc_thread_set_priority(int priority), int + Sets a thread's relative priority within the program. Valid + options are: + + OBJC_THREAD_INTERACTIVE_PRIORITY + OBJC_THREAD_BACKGROUND_PRIORITY + OBJC_THREAD_LOW_PRIORITY + +objc_thread_get_priority(void), int + Query a thread's priority. + +objc_thread_yield(void), void + Yields processor to another thread with equal or higher + priority. It is up to the system scheduler to determine if + the processor is taken or not. + +objc_thread_exit(void), int + Terminates a thread. If this is the last thread executing + then the program will terminate. + +objc_thread_id(void), int + Returns the current thread's id. + +objc_thread_set_data(void *value), int + Set a pointer to the thread's local storage. Local storage is + thread specific. + +objc_thread_get_data(void), void * + Returns the pointer to the thread's local storage. + +***** +* Backend thread functions +* User programs should *NOT* directly call these functions. + +__objc_thread_detach(void (*func)(void *arg), void *arg), objc_thread_t + Spawns a new thread executing func, called by objc_thread_detach. + Return NULL if error otherwise return thread id. + +__objc_thread_set_priority(int priority), int + Set the thread's priority, called by objc_thread_set_priority. + Return -1 if error otherwise return 0. + +__objc_thread_get_priority(void), int + Query a thread's priority, called by objc_thread_get_priority. + Return -1 if error otherwise return the priority. + +__objc_thread_yield(void), void + Yields the processor, called by objc_thread_yield. + +__objc_thread_exit(void), int + Terminates the thread, called by objc_thread_exit. + Return -1 if error otherwise function does not return. + +__objc_thread_id(void), objc_thread_t + Returns the current thread's id, called by objc_thread_id. + Return -1 if error otherwise return thread id. + +__objc_thread_set_data(void *value), int + Set pointer for thread local storage, called by objc_thread_set_data. + Returns -1 if error otherwise return 0. + +__objc_thread_get_data(void), void * + Returns the pointer to the thread's local storage. + Returns NULL if error, called by objc_thread_get_data. + + +****************************************************************************** +* Mutexes: + +Mutexes can be locked recursively. Each locked mutex remembers +its owner (by thread id) and how many times it has been locked. The +last unlock on a mutex removes the system lock and allows other +threads to access the mutex. + +***** +* Frontend mutex functions +* User programs should use these functions. + +objc_mutex_allocate(void), objc_mutex_t + Allocates a new mutex. Mutex is initially unlocked. + Return NULL if error otherwise return mutex pointer. + +objc_mutex_deallocate(objc_mutex_t mutex), int + Free a mutex. Before freeing the mutex, makes sure that no + one else is using it. + Return -1 if error otherwise return 0. + +objc_mutex_lock(objc_mutex_t mutex), int + Locks a mutex. As mentioned earlier, the same thread may call + this routine repeatedly. + Return -1 if error otherwise return 0. + +objc_mutex_trylock(objc_mutex_t mutex), int + Attempts to lock a mutex. If lock on mutex can be acquired + then function operates exactly as objc_mutex_lock. + Return -1 if failed to acquire lock otherwise return 0. + +objc_mutex_unlock(objc_mutex_t mutex), int + Unlocks the mutex by one level. Other threads may not acquire + the mutex until this thread has released all locks on it. + Return -1 if error otherwise return 0. + +***** +* Backend mutex functions +* User programs should *NOT* directly call these functions. + +__objc_mutex_allocate(objc_mutex_t mutex), int + Allocates a new mutex, called by objc_mutex_allocate. + Return -1 if error otherwise return 0. + +__objc_mutex_deallocate(objc_mutex_t mutex), int + Free a mutex, called by objc_mutex_deallocate. + Return -1 if error otherwise return 0. + +__objc_mutex_lock(objc_mutex_t mutex), int + Locks a mutex, called by objc_mutex_lock. + Return -1 if error otherwise return 0. + +__objc_mutex_trylock(objc_mutex_t mutex), int + Attempts to lock a mutex, called by objc_mutex_trylock. + Return -1 if failed to acquire lock or error otherwise return 0. + +__objc_mutex_unlock(objc_mutex_t mutex), int + Unlocks the mutex, called by objc_mutex_unlock. + Return -1 if error otherwise return 0. + +****************************************************************************** +* Condition Mutexes: + +Mutexes can be locked recursively. Each locked mutex remembers +its owner (by thread id) and how many times it has been locked. The +last unlock on a mutex removes the system lock and allows other +threads to access the mutex. + +* +* Frontend condition mutex functions +* User programs should use these functions. +* + +objc_condition_allocate(void), objc_condition_t + Allocate a condition mutex. + Return NULL if error otherwise return condition pointer. + +objc_condition_deallocate(objc_condition_t condition), int + Deallocate a condition. Note that this includes an implicit + condition_broadcast to insure that waiting threads have the + opportunity to wake. It is legal to dealloc a condition only + if no other thread is/will be using it. Does NOT check for + other threads waiting but just wakes them up. + Return -1 if error otherwise return 0. + +objc_condition_wait(objc_condition_t condition, objc_mutex_t mutex), int + Wait on the condition unlocking the mutex until objc_condition_signal() + or objc_condition_broadcast() are called for the same condition. The + given mutex *must* have the depth 1 so that it can be unlocked + here, for someone else can lock it and signal/broadcast the condition. + The mutex is used to lock access to the shared data that make up the + "condition" predicate. + Return -1 if error otherwise return 0. + +objc_condition_broadcast(objc_condition_t condition), int + Wake up all threads waiting on this condition. It is recommended that + the called would lock the same mutex as the threads in + objc_condition_wait before changing the "condition predicate" + and make this call and unlock it right away after this call. + Return -1 if error otherwise return 0. + +objc_condition_signal(objc_condition_t condition), int + Wake up one thread waiting on this condition. + Return -1 if error otherwise return 0. + +* +* Backend condition mutex functions +* User programs should *NOT* directly call these functions. +* + +__objc_condition_allocate(objc_condition_t condition), int + Allocate a condition mutex, called by objc_condition_allocate. + Return -1 if error otherwise return 0. + +__objc_condition_deallocate(objc_condition_t condition), int + Deallocate a condition, called by objc_condition_deallocate. + Return -1 if error otherwise return 0. + +__objc_condition_wait(objc_condition_t condition, objc_mutex_t mutex), int + Wait on the condition, called by objc_condition_wait. + Return -1 if error otherwise return 0 when condition is met. + +__objc_condition_broadcast(objc_condition_t condition), int + Wake up all threads waiting on this condition. + Called by objc_condition_broadcast. + Return -1 if error otherwise return 0. + +__objc_condition_signal(objc_condition_t condition), int + Wake up one thread waiting on this condition. + Called by objc_condition_signal. + Return -1 if error otherwise return 0. diff --git a/gnustep-objc/archive.c b/gnustep-objc/archive.c new file mode 100644 index 00000000..59e3303b --- /dev/null +++ b/gnustep-objc/archive.c @@ -0,0 +1,1642 @@ +// $Id$ + +/* GNU Objective C Runtime archiving + Copyright (C) 1993, 1995, 1996, 1997 Free Software Foundation, Inc. + Contributed by Kresten Krab Thorup + +This file is part of GNU CC. + +GNU CC is free software; you can redistribute it and/or modify it under the +terms of the GNU General Public License as published by the Free Software +Foundation; either version 2, or (at your option) any later version. + +GNU CC is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +FOR A PARTICULAR PURPOSE. See the GNU General Public License for more +details. + +You should have received a copy of the GNU General Public License along with +GNU CC; see the file COPYING. If not, write to the Free Software +Foundation, 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + +/* As a special exception, if you link this library with files compiled with + GCC to produce an executable, this does not cause the resulting executable + to be covered by the GNU General Public License. This exception does not + however invalidate any other reasons why the executable file might be + covered by the GNU General Public License. */ + +#include "runtime.h" +#include "typedstream.h" +#include "encoding.h" +#include "hash.h" +#include "objc-api.h" +#include + +#ifdef HAVE_STDLIB_H +#include +#endif + +extern int fflush(FILE*); + +#define ROUND(V, A) \ + ({ typeof(V) __v=(V); typeof(A) __a=(A); \ + __a*((__v+__a-1)/__a); }) + +#define PTR2LONG(P) (((char*)(P))-(char*)0) +#define LONG2PTR(L) (((char*)0)+(L)) + +/* Declare some functions... */ + +static int +objc_read_class (struct objc_typed_stream* stream, Class* class); + +int objc_sizeof_type(const char* type); + +static int +objc_write_use_common (struct objc_typed_stream* stream, unsigned long key); + +static int +objc_write_register_common (struct objc_typed_stream* stream, + unsigned long key); + +static int +objc_write_class (struct objc_typed_stream* stream, + struct objc_class* class); + +const char* objc_skip_type (const char* type); + +static void __objc_finish_write_root_object(struct objc_typed_stream*); +static void __objc_finish_read_root_object(struct objc_typed_stream*); + +static __inline__ int +__objc_code_unsigned_char (unsigned char* buf, unsigned char val) +{ + if ((val&_B_VALUE) == val) + { + buf[0] = val|_B_SINT; + return 1; + } + else + { + buf[0] = _B_NINT|0x01; + buf[1] = val; + return 2; + } +} + +int +objc_write_unsigned_char (struct objc_typed_stream* stream, + unsigned char value) +{ + unsigned char buf[sizeof (unsigned char)+1]; + int len = __objc_code_unsigned_char (buf, value); + return (*stream->write)(stream->physical, buf, len); +} + +static __inline__ int +__objc_code_char (unsigned char* buf, char val) +{ + if (val >= 0) + return __objc_code_unsigned_char (buf, val); + else + { + buf[0] = _B_NINT|_B_SIGN|0x01; + buf[1] = -val; + return 2; + } +} + +int +objc_write_char (struct objc_typed_stream* stream, char value) +{ + unsigned char buf[sizeof (char)+1]; + int len = __objc_code_char (buf, value); + return (*stream->write)(stream->physical, buf, len); +} + +static __inline__ int +__objc_code_unsigned_short (unsigned char* buf, unsigned short val) +{ + if ((val&_B_VALUE) == val) + { + buf[0] = val|_B_SINT; + return 1; + } + else + { + int c, b; + + buf[0] = _B_NINT; + + for (c= sizeof(short); c != 0; c -= 1) + if (((val>>(8*(c-1)))%0x100) != 0) + break; + + buf[0] |= c; + + for (b = 1; c != 0; c--, b++) + { + buf[b] = (val >> (8*(c-1)))%0x100; + } + + return b; + } +} + +int +objc_write_unsigned_short (struct objc_typed_stream* stream, + unsigned short value) +{ + unsigned char buf[sizeof (unsigned short)+1]; + int len = __objc_code_unsigned_short (buf, value); + return (*stream->write)(stream->physical, buf, len); +} + +static __inline__ int +__objc_code_short (unsigned char* buf, short val) +{ + int sign = (val < 0); + int size = __objc_code_unsigned_short (buf, sign ? -val : val); + if (sign) + buf[0] |= _B_SIGN; + return size; +} + +int +objc_write_short (struct objc_typed_stream* stream, short value) +{ + unsigned char buf[sizeof (short)+1]; + int len = __objc_code_short (buf, value); + return (*stream->write)(stream->physical, buf, len); +} + + +static __inline__ int +__objc_code_unsigned_int (unsigned char* buf, unsigned int val) +{ + if ((val&_B_VALUE) == val) + { + buf[0] = val|_B_SINT; + return 1; + } + else + { + int c, b; + + buf[0] = _B_NINT; + + for (c= sizeof(int); c != 0; c -= 1) + if (((val>>(8*(c-1)))%0x100) != 0) + break; + + buf[0] |= c; + + for (b = 1; c != 0; c--, b++) + { + buf[b] = (val >> (8*(c-1)))%0x100; + } + + return b; + } +} + +int +objc_write_unsigned_int (struct objc_typed_stream* stream, unsigned int value) +{ + unsigned char buf[sizeof(unsigned int)+1]; + int len = __objc_code_unsigned_int (buf, value); + return (*stream->write)(stream->physical, buf, len); +} + +static __inline__ int +__objc_code_int (unsigned char* buf, int val) +{ + int sign = (val < 0); + int size = __objc_code_unsigned_int (buf, sign ? -val : val); + if (sign) + buf[0] |= _B_SIGN; + return size; +} + +int +objc_write_int (struct objc_typed_stream* stream, int value) +{ + unsigned char buf[sizeof(int)+1]; + int len = __objc_code_int (buf, value); + return (*stream->write)(stream->physical, buf, len); +} + +static __inline__ int +__objc_code_unsigned_long (unsigned char* buf, unsigned long val) +{ + if ((val&_B_VALUE) == val) + { + buf[0] = val|_B_SINT; + return 1; + } + else + { + int c, b; + + buf[0] = _B_NINT; + + for (c= sizeof(long); c != 0; c -= 1) + if (((val>>(8*(c-1)))%0x100) != 0) + break; + + buf[0] |= c; + + for (b = 1; c != 0; c--, b++) + { + buf[b] = (val >> (8*(c-1)))%0x100; + } + + return b; + } +} + +int +objc_write_unsigned_long (struct objc_typed_stream* stream, + unsigned long value) +{ + unsigned char buf[sizeof(unsigned long)+1]; + int len = __objc_code_unsigned_long (buf, value); + return (*stream->write)(stream->physical, buf, len); +} + +static __inline__ int +__objc_code_long (unsigned char* buf, long val) +{ + int sign = (val < 0); + int size = __objc_code_unsigned_long (buf, sign ? -val : val); + if (sign) + buf[0] |= _B_SIGN; + return size; +} + +int +objc_write_long (struct objc_typed_stream* stream, long value) +{ + unsigned char buf[sizeof(long)+1]; + int len = __objc_code_long (buf, value); + return (*stream->write)(stream->physical, buf, len); +} + + +int +objc_write_string (struct objc_typed_stream* stream, + const unsigned char* string, unsigned int nbytes) +{ + unsigned char buf[sizeof(unsigned int)+1]; + int len = __objc_code_unsigned_int (buf, nbytes); + + if ((buf[0]&_B_CODE) == _B_SINT) + buf[0] = (buf[0]&_B_VALUE)|_B_SSTR; + + else /* _B_NINT */ + buf[0] = (buf[0]&_B_VALUE)|_B_NSTR; + + if ((*stream->write)(stream->physical, buf, len) != 0) + return (*stream->write)(stream->physical, string, nbytes); + else + return 0; +} + +int +objc_write_string_atomic (struct objc_typed_stream* stream, + unsigned char* string, unsigned int nbytes) +{ + unsigned long key; + if ((key = PTR2LONG(hash_value_for_key (stream->stream_table, string)))) + return objc_write_use_common (stream, key); + else + { + int length; + hash_add (&stream->stream_table, LONG2PTR(key=PTR2LONG(string)), string); + if ((length = objc_write_register_common (stream, key))) + return objc_write_string (stream, string, nbytes); + return length; + } +} + +static int +objc_write_register_common (struct objc_typed_stream* stream, + unsigned long key) +{ + unsigned char buf[sizeof (unsigned long)+2]; + int len = __objc_code_unsigned_long (buf+1, key); + if (len == 1) + { + buf[0] = _B_RCOMM|0x01; + buf[1] &= _B_VALUE; + return (*stream->write)(stream->physical, buf, len+1); + } + else + { + buf[1] = (buf[1]&_B_VALUE)|_B_RCOMM; + return (*stream->write)(stream->physical, buf+1, len); + } +} + +static int +objc_write_use_common (struct objc_typed_stream* stream, unsigned long key) +{ + unsigned char buf[sizeof (unsigned long)+2]; + int len = __objc_code_unsigned_long (buf+1, key); + if (len == 1) + { + buf[0] = _B_UCOMM|0x01; + buf[1] &= _B_VALUE; + return (*stream->write)(stream->physical, buf, 2); + } + else + { + buf[1] = (buf[1]&_B_VALUE)|_B_UCOMM; + return (*stream->write)(stream->physical, buf+1, len); + } +} + +static __inline__ int +__objc_write_extension (struct objc_typed_stream* stream, unsigned char code) +{ + if (code <= _B_VALUE) + { + unsigned char buf = code|_B_EXT; + return (*stream->write)(stream->physical, &buf, 1); + } + else + { + objc_error(nil, OBJC_ERR_BAD_OPCODE, + "__objc_write_extension: bad opcode %c\n", code); + return -1; + } +} + +__inline__ int +__objc_write_object (struct objc_typed_stream* stream, id object) +{ + unsigned char buf = '\0'; + SEL write_sel = sel_get_any_uid ("write:"); + if (object) + { + __objc_write_extension (stream, _BX_OBJECT); + objc_write_class (stream, object->class_pointer); + (*objc_msg_lookup(object, write_sel))(object, write_sel, stream); + return (*stream->write)(stream->physical, &buf, 1); + } + else + return objc_write_use_common(stream, 0); +} + +int +objc_write_object_reference (struct objc_typed_stream* stream, id object) +{ + unsigned long key; + if ((key = PTR2LONG(hash_value_for_key (stream->object_table, object)))) + return objc_write_use_common (stream, key); + + __objc_write_extension (stream, _BX_OBJREF); + return objc_write_unsigned_long (stream, PTR2LONG (object)); +} + +int +objc_write_root_object (struct objc_typed_stream* stream, id object) +{ + int len = 0; + if (stream->writing_root_p) + objc_error (nil, OBJC_ERR_RECURSE_ROOT, + "objc_write_root_object called recursively"); + else + { + stream->writing_root_p = 1; + __objc_write_extension (stream, _BX_OBJROOT); + if((len = objc_write_object (stream, object))) + __objc_finish_write_root_object(stream); + stream->writing_root_p = 0; + } + return len; +} + +int +objc_write_object (struct objc_typed_stream* stream, id object) +{ + unsigned long key; + if ((key = PTR2LONG(hash_value_for_key (stream->object_table, object)))) + return objc_write_use_common (stream, key); + + else if (object == nil) + return objc_write_use_common(stream, 0); + + else + { + int length; + hash_add (&stream->object_table, LONG2PTR(key=PTR2LONG(object)), object); + if ((length = objc_write_register_common (stream, key))) + return __objc_write_object (stream, object); + return length; + } +} + +__inline__ int +__objc_write_class (struct objc_typed_stream* stream, struct objc_class* class) +{ + __objc_write_extension (stream, _BX_CLASS); + objc_write_string_atomic(stream, (char*)class->name, + strlen((char*)class->name)); + return objc_write_unsigned_long (stream, class->version); +} + + +static int +objc_write_class (struct objc_typed_stream* stream, + struct objc_class* class) +{ + unsigned long key; + if ((key = PTR2LONG(hash_value_for_key (stream->stream_table, class)))) + return objc_write_use_common (stream, key); + else + { + int length; + hash_add (&stream->stream_table, LONG2PTR(key=PTR2LONG(class)), class); + if ((length = objc_write_register_common (stream, key))) + return __objc_write_class (stream, class); + return length; + } +} + + +__inline__ int +__objc_write_selector (struct objc_typed_stream* stream, SEL selector) +{ + const char* sel_name; + __objc_write_extension (stream, _BX_SEL); + /* to handle NULL selectors */ + if ((SEL)0 == selector) + return objc_write_string (stream, "", 0); + sel_name = sel_get_name (selector); + return objc_write_string (stream, sel_name, strlen ((char*)sel_name)); +} + +int +objc_write_selector (struct objc_typed_stream* stream, SEL selector) +{ + const char* sel_name; + unsigned long key; + + /* to handle NULL selectors */ + if ((SEL)0 == selector) + return __objc_write_selector (stream, selector); + + sel_name = sel_get_name (selector); + if ((key = PTR2LONG(hash_value_for_key (stream->stream_table, sel_name)))) + return objc_write_use_common (stream, key); + else + { + int length; + hash_add (&stream->stream_table, + LONG2PTR(key=PTR2LONG(sel_name)), (char*)sel_name); + if ((length = objc_write_register_common (stream, key))) + return __objc_write_selector (stream, selector); + return length; + } +} + + + +/* +** Read operations +*/ + +__inline__ int +objc_read_char (struct objc_typed_stream* stream, char* val) +{ + unsigned char buf; + int len; + len = (*stream->read)(stream->physical, &buf, 1); + if (len != 0) + { + if ((buf & _B_CODE) == _B_SINT) + (*val) = (buf & _B_VALUE); + + else if ((buf & _B_NUMBER) == 1) + { + len = (*stream->read)(stream->physical, val, 1); + if (buf&_B_SIGN) + (*val) = -1*(*val); + } + + else + objc_error(nil, OBJC_ERR_BAD_DATA, + "expected 8bit signed int, got %dbit int", + (int)(buf&_B_NUMBER)*8); + } + return len; +} + + +__inline__ int +objc_read_unsigned_char (struct objc_typed_stream* stream, unsigned char* val) +{ + unsigned char buf; + int len; + if ((len = (*stream->read)(stream->physical, &buf, 1))) + { + if ((buf & _B_CODE) == _B_SINT) + (*val) = (buf & _B_VALUE); + + else if ((buf & _B_NUMBER) == 1) + len = (*stream->read)(stream->physical, val, 1); + + else + objc_error(nil, OBJC_ERR_BAD_DATA, + "expected 8bit unsigned int, got %dbit int", + (int)(buf&_B_NUMBER)*8); + } + return len; +} + +__inline__ int +objc_read_short (struct objc_typed_stream* stream, short* value) +{ + unsigned char buf[sizeof(short)+1]; + int len; + if ((len = (*stream->read)(stream->physical, buf, 1))) + { + if ((buf[0] & _B_CODE) == _B_SINT) + (*value) = (buf[0] & _B_VALUE); + + else + { + int pos = 1; + int nbytes = buf[0] & _B_NUMBER; + if (nbytes > sizeof (short)) + objc_error(nil, OBJC_ERR_BAD_DATA, + "expected short, got bigger (%dbits)", nbytes*8); + len = (*stream->read)(stream->physical, buf+1, nbytes); + (*value) = 0; + while (pos <= nbytes) + (*value) = ((*value)*0x100) + buf[pos++]; + if (buf[0] & _B_SIGN) + (*value) = -(*value); + } + } + return len; +} + +__inline__ int +objc_read_unsigned_short (struct objc_typed_stream* stream, + unsigned short* value) +{ + unsigned char buf[sizeof(unsigned short)+1]; + int len; + if ((len = (*stream->read)(stream->physical, buf, 1))) + { + if ((buf[0] & _B_CODE) == _B_SINT) + (*value) = (buf[0] & _B_VALUE); + + else + { + int pos = 1; + int nbytes = buf[0] & _B_NUMBER; + if (nbytes > sizeof (short)) + objc_error(nil, OBJC_ERR_BAD_DATA, + "expected short, got int or bigger"); + len = (*stream->read)(stream->physical, buf+1, nbytes); + (*value) = 0; + while (pos <= nbytes) + (*value) = ((*value)*0x100) + buf[pos++]; + } + } + return len; +} + + +__inline__ int +objc_read_int (struct objc_typed_stream* stream, int* value) +{ + unsigned char buf[sizeof(int)+1]; + int len; + if ((len = (*stream->read)(stream->physical, buf, 1))) + { + if ((buf[0] & _B_CODE) == _B_SINT) + (*value) = (buf[0] & _B_VALUE); + + else + { + int pos = 1; + int nbytes = buf[0] & _B_NUMBER; + if (nbytes > sizeof (int)) + objc_error(nil, OBJC_ERR_BAD_DATA, "expected int, got bigger"); + len = (*stream->read)(stream->physical, buf+1, nbytes); + (*value) = 0; + while (pos <= nbytes) + (*value) = ((*value)*0x100) + buf[pos++]; + if (buf[0] & _B_SIGN) + (*value) = -(*value); + } + } + return len; +} + +__inline__ int +objc_read_long (struct objc_typed_stream* stream, long* value) +{ + unsigned char buf[sizeof(long)+1]; + int len; + if ((len = (*stream->read)(stream->physical, buf, 1))) + { + if ((buf[0] & _B_CODE) == _B_SINT) + (*value) = (buf[0] & _B_VALUE); + + else + { + int pos = 1; + int nbytes = buf[0] & _B_NUMBER; + if (nbytes > sizeof (long)) + objc_error(nil, OBJC_ERR_BAD_DATA, "expected long, got bigger"); + len = (*stream->read)(stream->physical, buf+1, nbytes); + (*value) = 0; + while (pos <= nbytes) + (*value) = ((*value)*0x100) + buf[pos++]; + if (buf[0] & _B_SIGN) + (*value) = -(*value); + } + } + return len; +} + +__inline__ int +__objc_read_nbyte_uint (struct objc_typed_stream* stream, + unsigned int nbytes, unsigned int* val) +{ + int len, pos = 0; + unsigned char buf[sizeof(unsigned int)+1]; + + if (nbytes > sizeof (int)) + objc_error(nil, OBJC_ERR_BAD_DATA, "expected int, got bigger"); + + len = (*stream->read)(stream->physical, buf, nbytes); + (*val) = 0; + while (pos < nbytes) + (*val) = ((*val)*0x100) + buf[pos++]; + return len; +} + + +__inline__ int +objc_read_unsigned_int (struct objc_typed_stream* stream, + unsigned int* value) +{ + unsigned char buf[sizeof(unsigned int)+1]; + int len; + if ((len = (*stream->read)(stream->physical, buf, 1))) + { + if ((buf[0] & _B_CODE) == _B_SINT) + (*value) = (buf[0] & _B_VALUE); + + else + len = __objc_read_nbyte_uint (stream, (buf[0] & _B_VALUE), value); + + } + return len; +} + +int +__objc_read_nbyte_ulong (struct objc_typed_stream* stream, + unsigned int nbytes, unsigned long* val) +{ + int len, pos = 0; + unsigned char buf[sizeof(unsigned long)+1]; + + if (nbytes > sizeof (long)) + objc_error(nil, OBJC_ERR_BAD_DATA, "expected long, got bigger"); + + len = (*stream->read)(stream->physical, buf, nbytes); + (*val) = 0; + while (pos < nbytes) + (*val) = ((*val)*0x100) + buf[pos++]; + return len; +} + + +__inline__ int +objc_read_unsigned_long (struct objc_typed_stream* stream, + unsigned long* value) +{ + unsigned char buf[sizeof(unsigned long)+1]; + int len; + if ((len = (*stream->read)(stream->physical, buf, 1))) + { + if ((buf[0] & _B_CODE) == _B_SINT) + (*value) = (buf[0] & _B_VALUE); + + else + len = __objc_read_nbyte_ulong (stream, (buf[0] & _B_VALUE), value); + + } + return len; +} + +__inline__ int +objc_read_string (struct objc_typed_stream* stream, + char** string) +{ + unsigned char buf[sizeof(unsigned int)+1]; + int len; + if ((len = (*stream->read)(stream->physical, buf, 1))) + { + unsigned long key = 0; + + if ((buf[0]&_B_CODE) == _B_RCOMM) /* register following */ + { + len = __objc_read_nbyte_ulong(stream, (buf[0] & _B_VALUE), &key); + len = (*stream->read)(stream->physical, buf, 1); + } + + switch (buf[0]&_B_CODE) { + case _B_SSTR: + { + int length = buf[0]&_B_VALUE; + (*string) = (char*)objc_malloc(length+1); + if (key) + hash_add (&stream->stream_table, LONG2PTR(key), *string); + len = (*stream->read)(stream->physical, *string, length); + (*string)[length] = '\0'; + } + break; + + case _B_UCOMM: + { + char *tmp; + len = __objc_read_nbyte_ulong(stream, (buf[0] & _B_VALUE), &key); + tmp = hash_value_for_key (stream->stream_table, LONG2PTR (key)); + *string = objc_malloc (strlen(tmp) + 1); + strcpy (*string, tmp); + } + break; + + case _B_NSTR: + { + unsigned int nbytes = buf[0]&_B_VALUE; + len = __objc_read_nbyte_uint(stream, nbytes, &nbytes); + if (len) { + (*string) = (char*)objc_malloc(nbytes+1); + if (key) + hash_add (&stream->stream_table, LONG2PTR(key), *string); + len = (*stream->read)(stream->physical, *string, nbytes); + (*string)[nbytes] = '\0'; + } + } + break; + + default: + objc_error(nil, OBJC_ERR_BAD_DATA, + "expected string, got opcode %c\n", (buf[0]&_B_CODE)); + } + } + + return len; +} + + +int +objc_read_object (struct objc_typed_stream* stream, id* object) +{ + unsigned char buf[sizeof (unsigned int)]; + int len; + if ((len = (*stream->read)(stream->physical, buf, 1))) + { + SEL read_sel = sel_get_any_uid ("read:"); + unsigned long key = 0; + + if ((buf[0]&_B_CODE) == _B_RCOMM) /* register common */ + { + len = __objc_read_nbyte_ulong(stream, (buf[0] & _B_VALUE), &key); + len = (*stream->read)(stream->physical, buf, 1); + } + + if (buf[0] == (_B_EXT | _BX_OBJECT)) + { + Class class; + + /* get class */ + len = objc_read_class (stream, &class); + + /* create instance */ + (*object) = class_create_instance(class); + + /* register? */ + if (key) + hash_add (&stream->object_table, LONG2PTR(key), *object); + + /* send -read: */ + if (__objc_responds_to (*object, read_sel)) + (*get_imp(class, read_sel))(*object, read_sel, stream); + + /* check null-byte */ + len = (*stream->read)(stream->physical, buf, 1); + if (buf[0] != '\0') + objc_error(nil, OBJC_ERR_BAD_DATA, + "expected null-byte, got opcode %c", buf[0]); + } + + else if ((buf[0]&_B_CODE) == _B_UCOMM) + { + if (key) + objc_error(nil, OBJC_ERR_BAD_KEY, "cannot register use upcode..."); + len = __objc_read_nbyte_ulong(stream, (buf[0] & _B_VALUE), &key); + (*object) = hash_value_for_key (stream->object_table, LONG2PTR(key)); + } + + else if (buf[0] == (_B_EXT | _BX_OBJREF)) /* a forward reference */ + { + struct objc_list* other; + len = objc_read_unsigned_long (stream, &key); + other = (struct objc_list*)hash_value_for_key (stream->object_refs, + LONG2PTR(key)); + hash_add (&stream->object_refs, LONG2PTR(key), + (void*)list_cons(object, other)); + } + + else if (buf[0] == (_B_EXT | _BX_OBJROOT)) /* a root object */ + { + if (key) + objc_error(nil, OBJC_ERR_BAD_KEY, + "cannot register root object..."); + len = objc_read_object (stream, object); + __objc_finish_read_root_object (stream); + } + + else + objc_error(nil, OBJC_ERR_BAD_DATA, + "expected object, got opcode %c", buf[0]); + } + return len; +} + +static int +objc_read_class (struct objc_typed_stream* stream, Class* class) +{ + unsigned char buf[sizeof (unsigned int)]; + int len; + if ((len = (*stream->read)(stream->physical, buf, 1))) + { + unsigned long key = 0; + + if ((buf[0]&_B_CODE) == _B_RCOMM) /* register following */ + { + len = __objc_read_nbyte_ulong(stream, (buf[0] & _B_VALUE), &key); + len = (*stream->read)(stream->physical, buf, 1); + } + + if (buf[0] == (_B_EXT | _BX_CLASS)) + { + char* class_name; + unsigned long version; + + /* get class */ + len = objc_read_string (stream, &class_name); + (*class) = objc_get_class(class_name); + objc_free(class_name); + + /* register */ + if (key) + hash_add (&stream->stream_table, LONG2PTR(key), *class); + + objc_read_unsigned_long(stream, &version); + hash_add (&stream->class_table, (*class)->name, (void*)version); + } + + else if ((buf[0]&_B_CODE) == _B_UCOMM) + { + if (key) + objc_error(nil, OBJC_ERR_BAD_KEY, "cannot register use upcode..."); + len = __objc_read_nbyte_ulong(stream, (buf[0] & _B_VALUE), &key); + (*class) = hash_value_for_key (stream->stream_table, LONG2PTR(key)); + if (!*class) + objc_error(nil, OBJC_ERR_BAD_CLASS, + "cannot find class for key %lu", key); + } + + else + objc_error(nil, OBJC_ERR_BAD_DATA, + "expected class, got opcode %c", buf[0]); + } + return len; +} + +int +objc_read_selector (struct objc_typed_stream* stream, SEL* selector) +{ + unsigned char buf[sizeof (unsigned int)]; + int len; + if ((len = (*stream->read)(stream->physical, buf, 1))) + { + unsigned long key = 0; + + if ((buf[0]&_B_CODE) == _B_RCOMM) /* register following */ + { + len = __objc_read_nbyte_ulong(stream, (buf[0] & _B_VALUE), &key); + len = (*stream->read)(stream->physical, buf, 1); + } + + if (buf[0] == (_B_EXT|_BX_SEL)) /* selector! */ + { + char* selector_name; + + /* get selector */ + len = objc_read_string (stream, &selector_name); + /* To handle NULL selectors */ + if (0 == strlen(selector_name)) + { + (*selector) = (SEL)0; + return 0; + } + else + (*selector) = sel_get_any_uid(selector_name); + objc_free(selector_name); + + /* register */ + if (key) + hash_add (&stream->stream_table, LONG2PTR(key), (void*)*selector); + } + + else if ((buf[0]&_B_CODE) == _B_UCOMM) + { + if (key) + objc_error(nil, OBJC_ERR_BAD_KEY, "cannot register use upcode..."); + len = __objc_read_nbyte_ulong(stream, (buf[0] & _B_VALUE), &key); + (*selector) = hash_value_for_key (stream->stream_table, + LONG2PTR(key)); + } + + else + objc_error(nil, OBJC_ERR_BAD_DATA, + "expected selector, got opcode %c", buf[0]); + } + return len; +} + +/* +** USER LEVEL FUNCTIONS +*/ + +/* +** Write one object, encoded in TYPE and pointed to by DATA to the +** typed stream STREAM. +*/ + +int +objc_write_type(TypedStream* stream, const char* type, const void* data) +{ + switch(*type) { + case _C_ID: + return objc_write_object (stream, *(id*)data); + break; + + case _C_CLASS: + return objc_write_class (stream, *(Class*)data); + break; + + case _C_SEL: + return objc_write_selector (stream, *(SEL*)data); + break; + + case _C_CHR: + return objc_write_char(stream, *(char*)data); + break; + + case _C_UCHR: + return objc_write_unsigned_char(stream, *(unsigned char*)data); + break; + + case _C_SHT: + return objc_write_short(stream, *(short*)data); + break; + + case _C_USHT: + return objc_write_unsigned_short(stream, *(unsigned short*)data); + break; + + case _C_INT: + return objc_write_int(stream, *(int*)data); + break; + + case _C_UINT: + return objc_write_unsigned_int(stream, *(unsigned int*)data); + break; + + case _C_LNG: + return objc_write_long(stream, *(long*)data); + break; + + case _C_ULNG: + return objc_write_unsigned_long(stream, *(unsigned long*)data); + break; + + case _C_CHARPTR: + return objc_write_string (stream, *(char**)data, strlen(*(char**)data)); + break; + + case _C_ATOM: + return objc_write_string_atomic (stream, *(char**)data, + strlen(*(char**)data)); + break; + + case _C_ARY_B: + { + int len = atoi(type+1); + while (isdigit((int)*++type)) + ; + return objc_write_array (stream, type, len, data); + } + break; + + case _C_STRUCT_B: + { + int acc_size = 0; + int align; + while (*type != _C_STRUCT_E && *type++ != '=') + ; /* skip "=" */ + while (*type != _C_STRUCT_E) + { + align = objc_alignof_type (type); /* padd to alignment */ + acc_size += ROUND (acc_size, align); + objc_write_type (stream, type, ((char*)data)+acc_size); + acc_size += objc_sizeof_type (type); /* add component size */ + type = objc_skip_typespec (type); /* skip component */ + } + return 1; + } + + default: + { + objc_error(nil, OBJC_ERR_BAD_TYPE, + "objc_write_type: cannot parse typespec: %s\n", type); + return 0; + } + } +} + +/* +** Read one object, encoded in TYPE and pointed to by DATA to the +** typed stream STREAM. DATA specifies the address of the types to +** read. Expected type is checked against the type actually present +** on the stream. +*/ + +int +objc_read_type(TypedStream* stream, const char* type, void* data) +{ + char c; + switch(c = *type) { + case _C_ID: + return objc_read_object (stream, (id*)data); + break; + + case _C_CLASS: + return objc_read_class (stream, (Class*)data); + break; + + case _C_SEL: + return objc_read_selector (stream, (SEL*)data); + break; + + case _C_CHR: + return objc_read_char (stream, (char*)data); + break; + + case _C_UCHR: + return objc_read_unsigned_char (stream, (unsigned char*)data); + break; + + case _C_SHT: + return objc_read_short (stream, (short*)data); + break; + + case _C_USHT: + return objc_read_unsigned_short (stream, (unsigned short*)data); + break; + + case _C_INT: + return objc_read_int (stream, (int*)data); + break; + + case _C_UINT: + return objc_read_unsigned_int (stream, (unsigned int*)data); + break; + + case _C_LNG: + return objc_read_long (stream, (long*)data); + break; + + case _C_ULNG: + return objc_read_unsigned_long (stream, (unsigned long*)data); + break; + + case _C_CHARPTR: + case _C_ATOM: + return objc_read_string (stream, (char**)data); + break; + + case _C_ARY_B: + { + int len = atoi(type+1); + while (isdigit((int)*++type)) + ; + return objc_read_array (stream, type, len, data); + } + break; + + case _C_STRUCT_B: + { + int acc_size = 0; + int align; + while (*type != _C_STRUCT_E && *type++ != '=') + ; /* skip "=" */ + while (*type != _C_STRUCT_E) + { + align = objc_alignof_type (type); /* padd to alignment */ + acc_size += ROUND (acc_size, align); + objc_read_type (stream, type, ((char*)data)+acc_size); + acc_size += objc_sizeof_type (type); /* add component size */ + type = objc_skip_typespec (type); /* skip component */ + } + return 1; + } + + default: + { + objc_error(nil, OBJC_ERR_BAD_TYPE, + "objc_read_type: cannot parse typespec: %s\n", type); + return 0; + } + } +} + +/* +** Write the object specified by the template TYPE to STREAM. Last +** arguments specify addresses of values to be written. It might +** seem surprising to specify values by address, but this is extremely +** convenient for copy-paste with objc_read_types calls. A more +** down-to-the-earth cause for this passing of addresses is that values +** of arbitrary size is not well supported in ANSI C for functions with +** variable number of arguments. +*/ + +int +objc_write_types (TypedStream* stream, const char* type, ...) +{ + va_list args; + const char *c; + int res = 0; + + va_start(args, type); + + for (c = type; *c; c = objc_skip_typespec (c)) + { + switch(*c) { + case _C_ID: + res = objc_write_object (stream, *va_arg (args, id*)); + break; + + case _C_CLASS: + res = objc_write_class (stream, *va_arg(args, Class*)); + break; + + case _C_SEL: + res = objc_write_selector (stream, *va_arg(args, SEL*)); + break; + + case _C_CHR: + res = objc_write_char (stream, *va_arg (args, char*)); + break; + + case _C_UCHR: + res = objc_write_unsigned_char (stream, + *va_arg (args, unsigned char*)); + break; + + case _C_SHT: + res = objc_write_short (stream, *va_arg(args, short*)); + break; + + case _C_USHT: + res = objc_write_unsigned_short (stream, + *va_arg(args, unsigned short*)); + break; + + case _C_INT: + res = objc_write_int(stream, *va_arg(args, int*)); + break; + + case _C_UINT: + res = objc_write_unsigned_int(stream, *va_arg(args, unsigned int*)); + break; + + case _C_LNG: + res = objc_write_long(stream, *va_arg(args, long*)); + break; + + case _C_ULNG: + res = objc_write_unsigned_long(stream, *va_arg(args, unsigned long*)); + break; + + case _C_CHARPTR: + { + char** str = va_arg(args, char**); + res = objc_write_string (stream, *str, strlen(*str)); + } + break; + + case _C_ATOM: + { + char** str = va_arg(args, char**); + res = objc_write_string_atomic (stream, *str, strlen(*str)); + } + break; + + case _C_ARY_B: + { + int len = atoi(c+1); + const char* t = c; + while (isdigit((int)*++t)) + ; + res = objc_write_array (stream, t, len, va_arg(args, void*)); + t = objc_skip_typespec (t); + if (*t != _C_ARY_E) + objc_error(nil, OBJC_ERR_BAD_TYPE, "expected `]', got: %s", t); + } + break; + + default: + objc_error(nil, OBJC_ERR_BAD_TYPE, + "objc_write_types: cannot parse typespec: %s\n", type); + } + } + va_end(args); + return res; +} + + +/* +** Last arguments specify addresses of values to be read. Expected +** type is checked against the type actually present on the stream. +*/ + +int +objc_read_types(TypedStream* stream, const char* type, ...) +{ + va_list args; + const char *c; + int res = 0; + + va_start(args, type); + + for (c = type; *c; c = objc_skip_typespec(c)) + { + switch(*c) { + case _C_ID: + res = objc_read_object(stream, va_arg(args, id*)); + break; + + case _C_CLASS: + res = objc_read_class(stream, va_arg(args, Class*)); + break; + + case _C_SEL: + res = objc_read_selector(stream, va_arg(args, SEL*)); + break; + + case _C_CHR: + res = objc_read_char(stream, va_arg(args, char*)); + break; + + case _C_UCHR: + res = objc_read_unsigned_char(stream, va_arg(args, unsigned char*)); + break; + + case _C_SHT: + res = objc_read_short(stream, va_arg(args, short*)); + break; + + case _C_USHT: + res = objc_read_unsigned_short(stream, va_arg(args, unsigned short*)); + break; + + case _C_INT: + res = objc_read_int(stream, va_arg(args, int*)); + break; + + case _C_UINT: + res = objc_read_unsigned_int(stream, va_arg(args, unsigned int*)); + break; + + case _C_LNG: + res = objc_read_long(stream, va_arg(args, long*)); + break; + + case _C_ULNG: + res = objc_read_unsigned_long(stream, va_arg(args, unsigned long*)); + break; + + case _C_CHARPTR: + case _C_ATOM: + { + char** str = va_arg(args, char**); + res = objc_read_string (stream, str); + } + break; + + case _C_ARY_B: + { + int len = atoi(c+1); + const char* t = c; + while (isdigit((int)*++t)) + ; + res = objc_read_array (stream, t, len, va_arg(args, void*)); + t = objc_skip_typespec (t); + if (*t != _C_ARY_E) + objc_error(nil, OBJC_ERR_BAD_TYPE, "expected `]', got: %s", t); + } + break; + + default: + objc_error(nil, OBJC_ERR_BAD_TYPE, + "objc_read_types: cannot parse typespec: %s\n", type); + } + } + va_end(args); + return res; +} + +/* +** Write an array of COUNT elements of TYPE from the memory address DATA. +** This is equivalent of objc_write_type (stream, "[N]", data) +*/ + +int +objc_write_array (TypedStream* stream, const char* type, + int count, const void* data) +{ + int off = objc_sizeof_type(type); + const char* where = data; + + while (count-- > 0) + { + objc_write_type(stream, type, where); + where += off; + } + return 1; +} + +/* +** Read an array of COUNT elements of TYPE into the memory address +** DATA. The memory pointed to by data is supposed to be allocated +** by the callee. This is equivalent of +** objc_read_type (stream, "[N]", data) +*/ + +int +objc_read_array (TypedStream* stream, const char* type, + int count, void* data) +{ + int off = objc_sizeof_type(type); + char* where = (char*)data; + + while (count-- > 0) + { + objc_read_type(stream, type, where); + where += off; + } + return 1; +} + +static int +__objc_fread(FILE* file, char* data, int len) +{ + return fread(data, len, 1, file); +} + +static int +__objc_fwrite(FILE* file, char* data, int len) +{ + return fwrite(data, len, 1, file); +} + +static int +__objc_feof(FILE* file) +{ + return feof(file); +} + +static int +__objc_no_write(FILE* file, char* data, int len) +{ + objc_error (nil, OBJC_ERR_NO_WRITE, "TypedStream not open for writing"); + return 0; +} + +static int +__objc_no_read(FILE* file, char* data, int len) +{ + objc_error (nil, OBJC_ERR_NO_READ, "TypedStream not open for reading"); + return 0; +} + +static int +__objc_read_typed_stream_signature (TypedStream* stream) +{ + char buffer[80]; + int pos = 0; + do + (*stream->read)(stream->physical, buffer+pos, 1); + while (buffer[pos++] != '\0') + ; + sscanf (buffer, "GNU TypedStream %d", &stream->version); + if (stream->version != OBJC_TYPED_STREAM_VERSION) + objc_error (nil, OBJC_ERR_STREAM_VERSION, + "cannot handle TypedStream version %d", stream->version); + return 1; +} + +static int +__objc_write_typed_stream_signature (TypedStream* stream) +{ + char buffer[80]; + sprintf(buffer, "GNU TypedStream %d", OBJC_TYPED_STREAM_VERSION); + stream->version = OBJC_TYPED_STREAM_VERSION; + (*stream->write)(stream->physical, buffer, strlen(buffer)+1); + return 1; +} + +static void __objc_finish_write_root_object(struct objc_typed_stream* stream) +{ + hash_delete (stream->object_table); + stream->object_table = ptrhash_new(64); +} + +static void __objc_finish_read_root_object(struct objc_typed_stream* stream) +{ + node_ptr node; + SEL awake_sel = sel_get_any_uid ("awake"); + cache_ptr free_list = ptrhash_new(64); + + /* resolve object forward references */ + for (node = hash_next (stream->object_refs, NULL); node; + node = hash_next (stream->object_refs, node)) + { + struct objc_list* reflist = node->value; + const void* key = node->key; + id object = hash_value_for_key (stream->object_table, key); + while(reflist) + { + *((id*)reflist->head) = object; + if (hash_value_for_key (free_list,reflist) == NULL) + hash_add (&free_list,reflist,reflist); + + reflist = reflist->tail; + } + } + + /* apply __objc_free to all objects stored in free_list */ + for (node = hash_next (free_list, NULL); node; + node = hash_next (free_list, node)) + objc_free ((void *) node->key); + + hash_delete (free_list); + + /* empty object reference table */ + hash_delete (stream->object_refs); + stream->object_refs = ptrhash_new(8); + + /* call -awake for all objects read */ + if (awake_sel) + { + for (node = hash_next (stream->object_table, NULL); node; + node = hash_next (stream->object_table, node)) + { + id object = node->value; + if (__objc_responds_to (object, awake_sel)) + (*objc_msg_lookup(object, awake_sel))(object, awake_sel); + } + } + + /* empty object table */ + hash_delete (stream->object_table); + stream->object_table = ptrhash_new(64); +} + +/* +** Open the stream PHYSICAL in MODE +*/ + +TypedStream* +objc_open_typed_stream (FILE* physical, int mode) +{ + TypedStream* s = (TypedStream*)objc_malloc(sizeof(TypedStream)); + + s->mode = mode; + s->physical = physical; + s->stream_table = ptrhash_new(64); + s->object_table = ptrhash_new(64); + s->eof = (objc_typed_eof_func)__objc_feof; + s->flush = (objc_typed_flush_func)fflush; + s->writing_root_p = 0; + if (mode == OBJC_READONLY) + { + s->class_table = strhash_new(8); + s->object_refs = ptrhash_new(8); + s->read = (objc_typed_read_func)__objc_fread; + s->write = (objc_typed_write_func)__objc_no_write; + __objc_read_typed_stream_signature (s); + } + else if (mode == OBJC_WRITEONLY) + { + s->class_table = 0; + s->object_refs = 0; + s->read = (objc_typed_read_func)__objc_no_read; + s->write = (objc_typed_write_func)__objc_fwrite; + __objc_write_typed_stream_signature (s); + } + else + { + objc_close_typed_stream (s); + return NULL; + } + s->type = OBJC_FILE_STREAM; + return s; +} + +/* +** Open the file named by FILE_NAME in MODE +*/ + +TypedStream* +objc_open_typed_stream_for_file (const char* file_name, int mode) +{ + FILE* file = NULL; + TypedStream* s; + + if (mode == OBJC_READONLY) + file = fopen (file_name, "r"); + else + file = fopen (file_name, "w"); + + if (file) + { + s = objc_open_typed_stream (file, mode); + if (s) + s->type |= OBJC_MANAGED_STREAM; + return s; + } + else + return NULL; +} + +/* +** Close STREAM freeing the structure it self. If it was opened with +** objc_open_typed_stream_for_file, the file will also be closed. +*/ + +void +objc_close_typed_stream (TypedStream* stream) +{ + if (stream->mode == OBJC_READONLY) + { + __objc_finish_read_root_object (stream); /* Just in case... */ + hash_delete (stream->class_table); + hash_delete (stream->object_refs); + } + + hash_delete (stream->stream_table); + hash_delete (stream->object_table); + + if (stream->type == (OBJC_MANAGED_STREAM | OBJC_FILE_STREAM)) + fclose ((FILE*)stream->physical); + + objc_free(stream); +} + +BOOL +objc_end_of_typed_stream (TypedStream* stream) +{ + return (*stream->eof)(stream->physical); +} + +void +objc_flush_typed_stream (TypedStream* stream) +{ + (*stream->flush)(stream->physical); +} + +long +objc_get_stream_class_version (TypedStream* stream, Class class) +{ + if (stream->class_table) + return PTR2LONG(hash_value_for_key (stream->class_table, class->name)); + else + return class_get_version (class); +} + diff --git a/gnustep-objc/class.c b/gnustep-objc/class.c new file mode 100644 index 00000000..ce1c60af --- /dev/null +++ b/gnustep-objc/class.c @@ -0,0 +1,342 @@ +/* GNU Objective C Runtime class related functions + Copyright (C) 1993, 1995, 1996, 1997 Free Software Foundation, Inc. + Contributed by Kresten Krab Thorup and Dennis Glatting. + +This file is part of GNU CC. + +GNU CC is free software; you can redistribute it and/or modify it under the +terms of the GNU General Public License as published by the Free Software +Foundation; either version 2, or (at your option) any later version. + +GNU CC is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +FOR A PARTICULAR PURPOSE. See the GNU General Public License for more +details. + +You should have received a copy of the GNU General Public License along with +GNU CC; see the file COPYING. If not, write to the Free Software +Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +/* As a special exception, if you link this library with files compiled with + GCC to produce an executable, this does not cause the resulting executable + to be covered by the GNU General Public License. This exception does not + however invalidate any other reasons why the executable file might be + covered by the GNU General Public License. */ + +#include "runtime.h" /* the kitchen sink */ + +/* Initial number of buckets size of class hash table. */ +#define CLASS_HASH_SIZE 32 + +void __objc_init_class_tables() +{ + /* Allocate the class hash table */ + + if(__objc_class_hash) + return; + + RUNTIME_LOCK; + __objc_class_hash = strhash_new(CLASS_HASH_SIZE); + RUNTIME_UNLOCK; +} + +/* This function adds a class to the class hash table, and assigns the + class a number, unless it's already known */ +void __objc_add_class_to_hash(Class class) { + Class h_class; + + RUNTIME_LOCK; + + /* make sure the table is there */ + assert(__objc_class_hash); + + /* make sure it's not a meta class */ + assert(CLS_ISCLASS(class)); + + /* Check to see if the class is already in the hash table. */ + h_class = hash_value_for_key (__objc_class_hash, class->name); + if (!h_class) + { + /* The class isn't in the hash table. Add the class and assign a class + number. */ + static unsigned int class_number = 1; + + CLS_SETNUMBER(class, class_number); + CLS_SETNUMBER(class->class_pointer, class_number); + + ++class_number; + hash_add (&__objc_class_hash, class->name, class); + } + + RUNTIME_UNLOCK; +} + +/* Get the class object for the class named NAME. If NAME does not + identify a known class, the hook _objc_lookup_class is called. If + this fails, nil is returned */ +Class objc_lookup_class (const char* name) +{ + Class class; + + if (name == NULL) { + abort(); + fprintf(stderr, "WARNING: %s was called with NULL class name !\n", + __PRETTY_FUNCTION__); + fflush(stderr); + return Nil; + } + + RUNTIME_LOCK; + + /* Make sure the class hash table exists. */ + assert (__objc_class_hash); + + class = hash_value_for_key (__objc_class_hash, name); + + RUNTIME_UNLOCK; + + if (class) + return class; + + if (_objc_lookup_class) + return (*_objc_lookup_class)(name); + else + return 0; +} + +/* Get the class object for the class named NAME. If NAME does not + identify a known class, the hook _objc_lookup_class is called. If + this fails, an error message is issued and the system aborts */ +Class +objc_get_class (const char *name) +{ + Class class; + + RUNTIME_LOCK; + + /* Make sure the class hash table exists. */ + assert (__objc_class_hash); + + class = hash_value_for_key (__objc_class_hash, name); + + RUNTIME_UNLOCK; + + if (class) + return class; + + if (_objc_lookup_class) + class = (*_objc_lookup_class)(name); + + if(class) + return class; + + objc_error(nil, OBJC_ERR_BAD_CLASS, + "objc runtime: cannot find class %s\n", name); + return 0; +} + +MetaClass +objc_get_meta_class(const char *name) +{ + return objc_get_class(name)->class_pointer; +} + +/* This function provides a way to enumerate all the classes in the + executable. Pass *ENUM_STATE == NULL to start the enumeration. The + function will return 0 when there are no more classes. + For example: + id class; + void *es = NULL; + while ((class = objc_next_class(&es))) + ... do something with class; +*/ +Class +objc_next_class(void **enum_state) +{ + RUNTIME_LOCK; + + /* make sure the table is there */ + assert(__objc_class_hash); + + *(node_ptr*)enum_state = + hash_next(__objc_class_hash, *(node_ptr*)enum_state); + + RUNTIME_UNLOCK; + + if (*(node_ptr*)enum_state) + return (*(node_ptr*)enum_state)->value; + return (Class)0; +} + +/* Resolve super/subclass links for all classes. The only thing we + can be sure of is that the class_pointer for class objects point + to the right meta class objects */ +void __objc_resolve_class_links() +{ + node_ptr node; + Class object_class = objc_get_class ("Object"); + + assert(object_class); + + RUNTIME_LOCK; + + /* Assign subclass links */ + for (node = hash_next (__objc_class_hash, NULL); node; + node = hash_next (__objc_class_hash, node)) + { + Class class1 = node->value; + + /* Make sure we have what we think we have. */ + assert (CLS_ISCLASS(class1)); + assert (CLS_ISMETA(class1->class_pointer)); + + /* The class_pointer of all meta classes point to Object's meta class. */ + class1->class_pointer->class_pointer = object_class->class_pointer; + + if (!(CLS_ISRESOLV(class1))) + { + CLS_SETRESOLV(class1); + CLS_SETRESOLV(class1->class_pointer); + + if(class1->super_class) + { + Class a_super_class + = objc_get_class ((char *) class1->super_class); + + assert (a_super_class); + + DEBUG_PRINTF ("making class connections for: %s\n", + class1->name ? class1->name : ""); + + /* assign subclass links for superclass */ + class1->sibling_class = a_super_class->subclass_list; + a_super_class->subclass_list = class1; + + /* Assign subclass links for meta class of superclass */ + if (a_super_class->class_pointer) + { + class1->class_pointer->sibling_class + = a_super_class->class_pointer->subclass_list; + a_super_class->class_pointer->subclass_list + = class1->class_pointer; + } + } + else /* a root class, make its meta object */ + /* be a subclass of Object */ + { + class1->class_pointer->sibling_class + = object_class->subclass_list; + object_class->subclass_list = class1->class_pointer; + } + } + } + + /* Assign superclass links */ + for (node = hash_next (__objc_class_hash, NULL); node; + node = hash_next (__objc_class_hash, node)) + { + Class class1 = node->value; + Class sub_class; + for (sub_class = class1->subclass_list; sub_class; + sub_class = sub_class->sibling_class) + { + sub_class->super_class = class1; + if(CLS_ISCLASS(sub_class)) + sub_class->class_pointer->super_class = class1->class_pointer; + } + } + + RUNTIME_UNLOCK; +} + + + +#define CLASSOF(c) ((c)->class_pointer) + +Class class_pose_as (Class impostor, Class super_class) +{ + node_ptr node; + Class class1; + + if (!CLS_ISRESOLV (impostor)) + __objc_resolve_class_links (); + + /* preconditions */ + assert (impostor); + assert (super_class); + assert (impostor->super_class == super_class); + assert (CLS_ISCLASS (impostor)); + assert (CLS_ISCLASS (super_class)); + assert (impostor->instance_size == super_class->instance_size); + + { + Class *subclass = &(super_class->subclass_list); + + /* move subclasses of super_class to impostor */ + while (*subclass) + { + Class nextSub = (*subclass)->sibling_class; + + if (*subclass != impostor) + { + Class sub = *subclass; + + /* classes */ + sub->sibling_class = impostor->subclass_list; + sub->super_class = impostor; + impostor->subclass_list = sub; + + /* It will happen that SUB is not a class object if it is + the top of the meta class hierarchy chain. (root + meta-class objects inherit their class object) If that is + the case... don't mess with the meta-meta class. */ + if (CLS_ISCLASS (sub)) + { + /* meta classes */ + CLASSOF (sub)->sibling_class = + CLASSOF (impostor)->subclass_list; + CLASSOF (sub)->super_class = CLASSOF (impostor); + CLASSOF (impostor)->subclass_list = CLASSOF (sub); + } + } + + *subclass = nextSub; + } + + /* set subclasses of superclass to be impostor only */ + super_class->subclass_list = impostor; + CLASSOF (super_class)->subclass_list = CLASSOF (impostor); + + /* set impostor to have no sibling classes */ + impostor->sibling_class = 0; + CLASSOF (impostor)->sibling_class = 0; + } + + /* check relationship of impostor and super_class is kept. */ + assert (impostor->super_class == super_class); + assert (CLASSOF (impostor)->super_class == CLASSOF (super_class)); + + /* This is how to update the lookup table. Regardless of + what the keys of the hashtable is, change all values that are + superclass into impostor. */ + + RUNTIME_LOCK; + + for (node = hash_next (__objc_class_hash, NULL); node; + node = hash_next (__objc_class_hash, node)) + { + class1 = (Class)node->value; + if (class1 == super_class) + { + node->value = impostor; /* change hash table value */ + } + } + + RUNTIME_UNLOCK; + + /* next, we update the dispatch tables... */ + __objc_update_dispatch_table_for_class (CLASSOF (impostor)); + __objc_update_dispatch_table_for_class (impostor); + + return impostor; +} diff --git a/gnustep-objc/config/alpha/generic/compiler-info.h b/gnustep-objc/config/alpha/generic/compiler-info.h new file mode 100644 index 00000000..0ee90d71 --- /dev/null +++ b/gnustep-objc/config/alpha/generic/compiler-info.h @@ -0,0 +1,4 @@ +#define BITS_PER_UNIT 8 +#define BITS_PER_WORD 64 +#define PCC_BITFIELD_TYPE_MATTERS 1 +#define STRUCTURE_SIZE_BOUNDARY 8 diff --git a/gnustep-objc/config/arm/linux-gnu/compiler-info.h b/gnustep-objc/config/arm/linux-gnu/compiler-info.h new file mode 100644 index 00000000..13a367a7 --- /dev/null +++ b/gnustep-objc/config/arm/linux-gnu/compiler-info.h @@ -0,0 +1,5 @@ +/* what I think makes sense, should be checked ... */ +#define STRUCTURE_SIZE_BOUNDARY 8 +#define PCC_BITFIELD_TYPE_MATTERS 1 +#define BITS_PER_UNIT 8 +#define BITS_PER_WORD 32 diff --git a/gnustep-objc/config/hppa/hpux/compiler-info.h b/gnustep-objc/config/hppa/hpux/compiler-info.h new file mode 100644 index 00000000..400aaaea --- /dev/null +++ b/gnustep-objc/config/hppa/hpux/compiler-info.h @@ -0,0 +1,4 @@ +#define STRUCTURE_SIZE_BOUNDARY 8 +#define PCC_BITFIELD_TYPE_MATTERS 1 +#define BITS_PER_UNIT 8 +#define BITS_PER_WORD 32 diff --git a/gnustep-objc/config/hppa/linux-gnu/compiler-info.h b/gnustep-objc/config/hppa/linux-gnu/compiler-info.h new file mode 100644 index 00000000..400aaaea --- /dev/null +++ b/gnustep-objc/config/hppa/linux-gnu/compiler-info.h @@ -0,0 +1,4 @@ +#define STRUCTURE_SIZE_BOUNDARY 8 +#define PCC_BITFIELD_TYPE_MATTERS 1 +#define BITS_PER_UNIT 8 +#define BITS_PER_WORD 32 diff --git a/gnustep-objc/config/i386/linux-gnu/compiler-info.h b/gnustep-objc/config/i386/linux-gnu/compiler-info.h new file mode 100644 index 00000000..400aaaea --- /dev/null +++ b/gnustep-objc/config/i386/linux-gnu/compiler-info.h @@ -0,0 +1,4 @@ +#define STRUCTURE_SIZE_BOUNDARY 8 +#define PCC_BITFIELD_TYPE_MATTERS 1 +#define BITS_PER_UNIT 8 +#define BITS_PER_WORD 32 diff --git a/gnustep-objc/config/ix86/freebsd/compiler-info.h b/gnustep-objc/config/ix86/freebsd/compiler-info.h new file mode 100644 index 00000000..6df49bce --- /dev/null +++ b/gnustep-objc/config/ix86/freebsd/compiler-info.h @@ -0,0 +1,4 @@ +//#define STRUCTURE_SIZE_BOUNDARY 8 +#define PCC_BITFIELD_TYPE_MATTERS 1 +#define BITS_PER_UNIT 8 +#define BITS_PER_WORD 32 diff --git a/gnustep-objc/config/ix86/linux-gnu/compiler-info.h b/gnustep-objc/config/ix86/linux-gnu/compiler-info.h new file mode 100644 index 00000000..400aaaea --- /dev/null +++ b/gnustep-objc/config/ix86/linux-gnu/compiler-info.h @@ -0,0 +1,4 @@ +#define STRUCTURE_SIZE_BOUNDARY 8 +#define PCC_BITFIELD_TYPE_MATTERS 1 +#define BITS_PER_UNIT 8 +#define BITS_PER_WORD 32 diff --git a/gnustep-objc/config/ix86/openbsd3.2/compiler-info.h b/gnustep-objc/config/ix86/openbsd3.2/compiler-info.h new file mode 100644 index 00000000..6df49bce --- /dev/null +++ b/gnustep-objc/config/ix86/openbsd3.2/compiler-info.h @@ -0,0 +1,4 @@ +//#define STRUCTURE_SIZE_BOUNDARY 8 +#define PCC_BITFIELD_TYPE_MATTERS 1 +#define BITS_PER_UNIT 8 +#define BITS_PER_WORD 32 diff --git a/gnustep-objc/config/ix86/openbsd3.7/compiler-info.h b/gnustep-objc/config/ix86/openbsd3.7/compiler-info.h new file mode 100644 index 00000000..6df49bce --- /dev/null +++ b/gnustep-objc/config/ix86/openbsd3.7/compiler-info.h @@ -0,0 +1,4 @@ +//#define STRUCTURE_SIZE_BOUNDARY 8 +#define PCC_BITFIELD_TYPE_MATTERS 1 +#define BITS_PER_UNIT 8 +#define BITS_PER_WORD 32 diff --git a/gnustep-objc/config/ix86/solaris2.9/compiler-info.h b/gnustep-objc/config/ix86/solaris2.9/compiler-info.h new file mode 100644 index 00000000..6df49bce --- /dev/null +++ b/gnustep-objc/config/ix86/solaris2.9/compiler-info.h @@ -0,0 +1,4 @@ +//#define STRUCTURE_SIZE_BOUNDARY 8 +#define PCC_BITFIELD_TYPE_MATTERS 1 +#define BITS_PER_UNIT 8 +#define BITS_PER_WORD 32 diff --git a/gnustep-objc/config/m68k/linux-gnu/compiler-info.h b/gnustep-objc/config/m68k/linux-gnu/compiler-info.h new file mode 100644 index 00000000..13a367a7 --- /dev/null +++ b/gnustep-objc/config/m68k/linux-gnu/compiler-info.h @@ -0,0 +1,5 @@ +/* what I think makes sense, should be checked ... */ +#define STRUCTURE_SIZE_BOUNDARY 8 +#define PCC_BITFIELD_TYPE_MATTERS 1 +#define BITS_PER_UNIT 8 +#define BITS_PER_WORD 32 diff --git a/gnustep-objc/config/mips/irix6/compiler-info.h b/gnustep-objc/config/mips/irix6/compiler-info.h new file mode 100644 index 00000000..74a611f7 --- /dev/null +++ b/gnustep-objc/config/mips/irix6/compiler-info.h @@ -0,0 +1,4 @@ +#define STRUCTURE_SIZE_BOUNDARY 8 +#define PCC_BITFIELD_TYPE_MATTERS 1 +#define BITS_PER_UNIT 8 +#define BITS_PER_WORD 64 diff --git a/gnustep-objc/config/mips/linux-gnu/compiler-info.h b/gnustep-objc/config/mips/linux-gnu/compiler-info.h new file mode 100644 index 00000000..74a611f7 --- /dev/null +++ b/gnustep-objc/config/mips/linux-gnu/compiler-info.h @@ -0,0 +1,4 @@ +#define STRUCTURE_SIZE_BOUNDARY 8 +#define PCC_BITFIELD_TYPE_MATTERS 1 +#define BITS_PER_UNIT 8 +#define BITS_PER_WORD 64 diff --git a/gnustep-objc/config/mipsel/linux-gnu/compiler-info.h b/gnustep-objc/config/mipsel/linux-gnu/compiler-info.h new file mode 100644 index 00000000..74a611f7 --- /dev/null +++ b/gnustep-objc/config/mipsel/linux-gnu/compiler-info.h @@ -0,0 +1,4 @@ +#define STRUCTURE_SIZE_BOUNDARY 8 +#define PCC_BITFIELD_TYPE_MATTERS 1 +#define BITS_PER_UNIT 8 +#define BITS_PER_WORD 64 diff --git a/gnustep-objc/config/powerpc/linux-gnu/compiler-info.h b/gnustep-objc/config/powerpc/linux-gnu/compiler-info.h new file mode 100644 index 00000000..13a367a7 --- /dev/null +++ b/gnustep-objc/config/powerpc/linux-gnu/compiler-info.h @@ -0,0 +1,5 @@ +/* what I think makes sense, should be checked ... */ +#define STRUCTURE_SIZE_BOUNDARY 8 +#define PCC_BITFIELD_TYPE_MATTERS 1 +#define BITS_PER_UNIT 8 +#define BITS_PER_WORD 32 diff --git a/gnustep-objc/config/powerpc64/linux-gnu/compiler-info.h b/gnustep-objc/config/powerpc64/linux-gnu/compiler-info.h new file mode 100644 index 00000000..400aaaea --- /dev/null +++ b/gnustep-objc/config/powerpc64/linux-gnu/compiler-info.h @@ -0,0 +1,4 @@ +#define STRUCTURE_SIZE_BOUNDARY 8 +#define PCC_BITFIELD_TYPE_MATTERS 1 +#define BITS_PER_UNIT 8 +#define BITS_PER_WORD 32 diff --git a/gnustep-objc/config/s390/linux-gnu/compiler-info.h b/gnustep-objc/config/s390/linux-gnu/compiler-info.h new file mode 100644 index 00000000..400aaaea --- /dev/null +++ b/gnustep-objc/config/s390/linux-gnu/compiler-info.h @@ -0,0 +1,4 @@ +#define STRUCTURE_SIZE_BOUNDARY 8 +#define PCC_BITFIELD_TYPE_MATTERS 1 +#define BITS_PER_UNIT 8 +#define BITS_PER_WORD 32 diff --git a/gnustep-objc/config/sparc/config.make b/gnustep-objc/config/sparc/config.make new file mode 100644 index 00000000..45536aa4 --- /dev/null +++ b/gnustep-objc/config/sparc/config.make @@ -0,0 +1,5 @@ +# $Id$ + +ADDITIONAL_CPPFLAGS += \ + -DPRECOMPUTE_SELECTORS=1\ + diff --git a/gnustep-objc/config/sparc/linux-gnu/compiler-info.h b/gnustep-objc/config/sparc/linux-gnu/compiler-info.h new file mode 100644 index 00000000..400aaaea --- /dev/null +++ b/gnustep-objc/config/sparc/linux-gnu/compiler-info.h @@ -0,0 +1,4 @@ +#define STRUCTURE_SIZE_BOUNDARY 8 +#define PCC_BITFIELD_TYPE_MATTERS 1 +#define BITS_PER_UNIT 8 +#define BITS_PER_WORD 32 diff --git a/gnustep-objc/config/sparc/solaris2.6/compiler-info.h b/gnustep-objc/config/sparc/solaris2.6/compiler-info.h new file mode 100644 index 00000000..400aaaea --- /dev/null +++ b/gnustep-objc/config/sparc/solaris2.6/compiler-info.h @@ -0,0 +1,4 @@ +#define STRUCTURE_SIZE_BOUNDARY 8 +#define PCC_BITFIELD_TYPE_MATTERS 1 +#define BITS_PER_UNIT 8 +#define BITS_PER_WORD 32 diff --git a/gnustep-objc/config/sparc/solaris2.9/compiler-info.h b/gnustep-objc/config/sparc/solaris2.9/compiler-info.h new file mode 100644 index 00000000..400aaaea --- /dev/null +++ b/gnustep-objc/config/sparc/solaris2.9/compiler-info.h @@ -0,0 +1,4 @@ +#define STRUCTURE_SIZE_BOUNDARY 8 +#define PCC_BITFIELD_TYPE_MATTERS 1 +#define BITS_PER_UNIT 8 +#define BITS_PER_WORD 32 diff --git a/gnustep-objc/config/unknown/generic/compiler-info.h b/gnustep-objc/config/unknown/generic/compiler-info.h new file mode 100644 index 00000000..400aaaea --- /dev/null +++ b/gnustep-objc/config/unknown/generic/compiler-info.h @@ -0,0 +1,4 @@ +#define STRUCTURE_SIZE_BOUNDARY 8 +#define PCC_BITFIELD_TYPE_MATTERS 1 +#define BITS_PER_UNIT 8 +#define BITS_PER_WORD 32 diff --git a/gnustep-objc/config/x86_64/generic/compiler-info.h b/gnustep-objc/config/x86_64/generic/compiler-info.h new file mode 100644 index 00000000..0ee90d71 --- /dev/null +++ b/gnustep-objc/config/x86_64/generic/compiler-info.h @@ -0,0 +1,4 @@ +#define BITS_PER_UNIT 8 +#define BITS_PER_WORD 64 +#define PCC_BITFIELD_TYPE_MATTERS 1 +#define STRUCTURE_SIZE_BOUNDARY 8 diff --git a/gnustep-objc/configure b/gnustep-objc/configure new file mode 100755 index 00000000..abe881a2 --- /dev/null +++ b/gnustep-objc/configure @@ -0,0 +1,329 @@ +#!/bin/bash + +# +# Note: When adding make options to this script, ensure that the source still +# compiles without those options! (and just with GNUstep.sh being +# sourced) +# We do not want to force people to run configure. +# + +# ******************** variables **************** + +CFG_ARGS="$0 $1 $2 $3 $4 $5 $6 $7 $8 $9" + +ARG_BEQUIET=0 +ARG_NOCREATE=0 +ARG_PREFIX="" +ARG_GSMAKE="$GNUSTEP_MAKEFILES" +ARG_CFGMAKE="$PWD/config.make" +ARG_WITH_GNUSTEP=0 +ARG_WITH_DEBUG=0 + +DARG_GNUSTEP_SH="$ARG_GSMAKE/GNUstep.sh" +DARG_IS_FHS=1 + +NGSTREAMS_DIR="./sope-core/NGStreams" + +# ******************** usage ******************** + +function usage() { + cat <<_ACEOF +\`configure' configures a GNUstep-make based sourcetree for installation. + +Usage: $0 [OPTION]... + +Note: You do not need to configure this source tree, as another option + just ensure that the GNUstep.sh of your GNUstep make installation + is properly sourced prior running make. + +Configuration: + -h, --help display this help and exit + -q, --quiet, --silent do not print \`checking...' messages + -n, --no-create do not create output files + +Installation directories: + --prefix=PREFIX install files in PREFIX [/usr/local] + --gsmake=PATH path to gnustep-make tree + --configmake=PATH path to the config file being created + --with-gnustep install in GNUstep tree + --enable-debug turn on debugging and compile time warnings + +_ACEOF + + exit 0; +} + +# ******************** running ******************** + +function printParas() { + echo "Configuration:" + if test $ARG_BEQUIET = 1; then echo " will be quite."; fi + if test $ARG_NOCREATE = 1; then echo " won't create files"; fi + if test $DARG_IS_FHS = 1; then + echo " FHS: install in FHS root"; + else + echo " FHS: install in GNUstep tree"; + fi + + if test $ARG_WITH_DEBUG = 1; then + echo " debug: yes"; + else + echo " debug: no"; + fi + + echo " prefix: $ARG_PREFIX" + echo " gstep: $ARG_GSMAKE" + echo " config: $ARG_CFGMAKE" + echo " script: $DARG_GNUSTEP_SH" + echo "" +} + +function warnOnFHSPrefix() { + cat <<_ACEOFWARN +Warning: you are configuring for a non standard FHS style prefix. + prefix: $ARG_PREFIX + +Some code in SOPE only looks in /usr and /usr/local for resources and is +therefore incompatible with arbitary install pathes. + +If you want to have the flexibility of installation in arbitary pathes just +configure GNUstep-make and source the GNUstep.sh script prior executing tools +to ensure a proper environment. +All SOPE based code is completely relocatable when being used in a GNUstep +environment. + +_ACEOFWARN +} + +function validateGNUstepArgs() { + # GNUstep make + if test "x$ARG_GSMAKE" = "x"; then + if test -f $HOME/OGoRoot/Library/Makefiles/GNUstep.sh; then + ARG_GSMAKE="$HOME/OGoRoot/Library/Makefiles/" + elif test -f $HOME/GNUstep/Library/Makefiles/GNUstep.sh; then + ARG_GSMAKE="$HOME/GNUstep/Library/Makefiles/" + elif test -f /usr/GNUstep/System/Library/Makefiles/GNUstep.sh; then + ARG_GSMAKE="/usr/GNUstep/System/Library/Makefiles/" + else + echo "error: please specify a GNUstep make tree!" + exit 1 + fi + DARG_GNUSTEP_SH="$ARG_GSMAKE/GNUstep.sh" + elif test -d $ARG_GSMAKE; then + if test -f $ARG_GSMAKE/GNUstep.sh; then + DARG_GNUSTEP_SH="$ARG_GSMAKE/GNUstep.sh" + elif test -f $ARG_GSMAKE/Library/Makefiles/GNUstep.sh; then + ARG_GSMAKE="$ARG_GSMAKE/Library/Makefiles" + DARG_GNUSTEP_SH="$ARG_GSMAKE/GNUstep.sh" + else + echo "error: specified directory contains no GNUstep.sh: $ARG_GSMAKE" + exit 1 + fi + else + echo "error: specified GNUstep make tree does not exist: $ARG_GSMAKE" + exit 1 + fi +} + +function validateArgs() { + # validate prefix (could be better?) + case "x$ARG_PREFIX" in + "x/usr/local"|"x/usr/local/") + DARG_IS_FHS=1; + ;; + "x/usr"|"x/usr/") + DARG_IS_FHS=1; + ;; + "x$GNUSTEP_USER_ROOT"|"x$GNUSTEP_LOCAL_ROOT"|"x$GNUSTEP_SYSTEM_ROOT") + DARG_IS_FHS=0; + ARG_WITH_GNUSTEP=1; + ;; + "x") + if test $ARG_WITH_GNUSTEP = 1; then + DARG_IS_FHS=0; + ARG_PREFIX="$GNUSTEP_LOCAL_ROOT" + if test $ARG_BEQUIET != 1; then + echo "Note: will install in GNUSTEP_LOCAL_ROOT: $ARG_PREFIX" + echo "" + fi + else + DARG_IS_FHS=1; + ARG_PREFIX="/usr/local/" + echo "Note: will install in default location: $ARG_PREFIX" + echo "" + fi + ;; + *) + if test $ARG_WITH_GNUSTEP = 1; then + echo "error: specified --with-gnustep, but specified prefix is not" + echo " a GNUstep root: '$ARG_PREFIX'" + exit 1 + else + if test $ARG_BEQUIET != 1; then + warnOnFHSPrefix; + fi + DARG_IS_FHS=1; + fi + ;; + esac + + if test $ARG_WITH_GNUSTEP = 1; then + if test $DARG_IS_FHS = 1; then + echo "error: configured for FHS root _and_ GNUstep tree. Choose one!" + exit 1 + fi + fi +} + +function printGNUstepSetup() { + echo "GNUstep environment:" + echo " system: ${GNUSTEP_SYSTEM_ROOT}" + echo " local: ${GNUSTEP_LOCAL_ROOT}" + echo " user: ${GNUSTEP_USER_ROOT}" + echo " path: ${GNUSTEP_PATHLIST}" + echo " flat: ${GNUSTEP_FLATTENED}" + echo " arch: ${GNUSTEP_HOST}" + echo " combo: ${LIBRARY_COMBO}" + echo "" +} + +function cfgwrite() { + echo "$1" >> $ARG_CFGMAKE +} + +function genConfigMake() { + # we ignore the following vars also patches by gstep-make: + # PATH + # DYLD_LIBRARY_PATH + # GUILE_LOAD_PATH + # CLASSPATH + + if test $ARG_BEQUIET != 1; then + echo "creating: $ARG_CFGMAKE" + fi + + echo "# GNUstep environment configuration" > $ARG_CFGMAKE + cfgwrite "# created by: '$CFG_ARGS'" + cfgwrite "" + + cfgwrite "# Note: you can override any option as a 'make' parameter, eg:" + cfgwrite "# make debug=yes" + cfgwrite "" + + cfgwrite "# print on the cmdline that this file is being used" + cfgwrite "all :: " + cfgwrite " @echo Local GNUstep config.make is active" + cfgwrite "" + + # TODO: should be also write a GNUSTEP_INSTALLATION_DIR / BUNDLE_INSTALL_DIR? + + if test $DARG_IS_FHS = 1; then + cfgwrite "# configured for FHS install" + cfgwrite "FHS_INSTALL_ROOT:=$ARG_PREFIX" + cfgwrite "" + fi + + if test $ARG_WITH_DEBUG = 1; then + cfgwrite "# configured to produce debugging code"; + cfgwrite "debug:=yes" + else + cfgwrite "# configured to produce non-debugging code"; + cfgwrite "debug:=no" + fi + cfgwrite "" + + cfgwrite "# enforce shared libraries"; + cfgwrite "shared:=yes" + cfgwrite "" + + cfgwrite "# GNUstep environment variables:"; + for i in `env | grep GNUSTEP_ | sort`; do + MAKE_ASSI="`echo $i | sed s/=/:=/`" + cfgwrite "${MAKE_ASSI}"; + done + cfgwrite "LIBRARY_COMBO=$LIBRARY_COMBO" + cfgwrite "" + + cfgwrite "# avoid a gstep-make warning" + cfgwrite "PATH:=\$(GNUSTEP_SYSTEM_ROOT)/Tools:\$(PATH)" +} + +function runIt() { + if test $ARG_BEQUIET != 1; then + printParas; + fi + + if test $ARG_NOCREATE = 1; then + if test $ARG_BEQUIET != 1; then + echo "not creating the config file ..."; + fi + else + genConfigMake; + + if test -x $NGSTREAMS_DIR/configure; then + if test $ARG_BEQUIET != 1; then + echo -n "configuring NGStreams library .." + old="$PWD" + cd $NGSTREAMS_DIR + ./configure >$old/config-NGStreams.log + cd $old + echo ".. done (log in config-NGStreams.log)." + fi + fi + fi +} + +# ******************** options ******************** + +function extractFuncValue() { + VALUE="`echo "$1" | sed "s/[^=]*=//g"`" +} + +function processOption() { + case "x$1" in + "x--help"|"x-h") + usage; + ;; + "x--quiet"|"x--silent"|"x-q") ARG_BEQUIET=1; ;; + "x--no-create"|"x-n") ARG_NOCREATE=1; ;; + x--prefix=*) + extractFuncValue $1; + ARG_PREFIX="$VALUE"; + ;; + x--gsmake=*) + extractFuncValue $1; + ARG_GSMAKE="$VALUE"; + ;; + x--configmake=*) + extractFuncValue $1; + ARG_CFGMAKE="$VALUE"; + ;; + "x--with-gnustep") + ARG_WITH_GNUSTEP=1 + DARG_IS_FHS=0 + ;; + "x--enable-debug") + ARG_WITH_DEBUG=1 + ;; + + *) echo "error: cannot process argument: $1"; exit 1; ;; + esac +} + +for i in $@; do + processOption $i; +done + +# load GNUstep environment +validateGNUstepArgs +# first we load the GNUstep.sh environment +source $DARG_GNUSTEP_SH +if test $ARG_BEQUIET != 1; then + printGNUstepSetup; +fi + +# ensure the parameters make sense +validateArgs + +# start it +runIt diff --git a/gnustep-objc/debian/changelog b/gnustep-objc/debian/changelog new file mode 100644 index 00000000..febc6e71 --- /dev/null +++ b/gnustep-objc/debian/changelog @@ -0,0 +1,27 @@ +libobjc-lf2 (2.95.3r24-0) experimental; urgency=low + + * Change source package name to match upstreams SONAME. + * Change versioning scheme to match upstream new scheme. + * Install to FHS compliant paths. + + -- Sebastian Ley Mon, 13 Sep 2004 13:56:12 +0200 + +libobjc-ogo1 (2.95.3cvs20040611-1pre1) experimental; urgency=low + + * Depend explicitly on gobjc. + + -- Sebastian Ley Tue, 10 Aug 2004 22:29:09 +0200 + +libobjc-ogo1 (2.95.3cvs20040611-1pre0) experimental; urgency=low + + * New upstream version. + - Contains compiler-info.h for powerpc (Closes: #249640) + + -- Sebastian Ley Fri, 11 Jun 2004 01:02:27 +0200 + +libobjc-ogo1 (2.95.3cvs20040312-1pre0) experimental; urgency=low + + * Initial Release. + + -- Sebastian Ley Sat, 1 May 2004 17:23:37 +0200 + diff --git a/gnustep-objc/debian/compat b/gnustep-objc/debian/compat new file mode 100644 index 00000000..b8626c4c --- /dev/null +++ b/gnustep-objc/debian/compat @@ -0,0 +1 @@ +4 diff --git a/gnustep-objc/debian/control b/gnustep-objc/debian/control new file mode 100644 index 00000000..9edbf177 --- /dev/null +++ b/gnustep-objc/debian/control @@ -0,0 +1,22 @@ +Source: libobjc-lf2 +Priority: extra +Maintainer: Sebastian Ley +Build-Depends: debhelper (>= 4.0.0), dpatch, gnustep-make-ogo, gobjc | objc-compiler +Standards-Version: 3.6.1 + +Package: libobjc-lf2-dev +Section: libdevel +Architecture: any +Provides: libobjc-lf-dev +Conflicts: libobjc-lf-dev +Depends: libobjc-lf2 (= ${Source-Version}) +Description: Header files for the libFoundation fork of the Objective-C library + This package contains the header files to build Objective-C applications + that use libFoundation. + +Package: libobjc-lf2 +Section: libs +Architecture: any +Depends: ${shlibs:Depends}, ${misc:Depends} +Description: libFoundation fork of the Objective-C runtime library + Library needed to run Objective-C applications which use libFoundation. diff --git a/gnustep-objc/debian/copyright b/gnustep-objc/debian/copyright new file mode 100644 index 00000000..149ad3ff --- /dev/null +++ b/gnustep-objc/debian/copyright @@ -0,0 +1,29 @@ +This package was debianized by Sebastian Ley on +Wed, 26 Nov 2003 16:49:10 +0100. + +It was downloaded from http://www.opengroupware.org + +Upstream Authors: + Geoffrey Knauth + Tom Wood + Kresten Krab Thorup + +Copyright: + + This package is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This package is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this package; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +On Debian systems, the complete text of the GNU Lesser General +Public License can be found in `/usr/share/common-licenses/LGPL'. + diff --git a/gnustep-objc/debian/docs b/gnustep-objc/debian/docs new file mode 100644 index 00000000..e7e3ce2f --- /dev/null +++ b/gnustep-objc/debian/docs @@ -0,0 +1,2 @@ +README +README.threads diff --git a/gnustep-objc/debian/libobjc-lf2-dev.install b/gnustep-objc/debian/libobjc-lf2-dev.install new file mode 100644 index 00000000..1512d671 --- /dev/null +++ b/gnustep-objc/debian/libobjc-lf2-dev.install @@ -0,0 +1,2 @@ +usr/lib/*.so +usr/include/* usr/lib/opengroupware.org/System/Library/Headers diff --git a/gnustep-objc/debian/libobjc-lf2.install b/gnustep-objc/debian/libobjc-lf2.install new file mode 100644 index 00000000..093956b1 --- /dev/null +++ b/gnustep-objc/debian/libobjc-lf2.install @@ -0,0 +1 @@ +usr/lib/*.so.* diff --git a/gnustep-objc/debian/patches/00list b/gnustep-objc/debian/patches/00list new file mode 100644 index 00000000..e69de29b diff --git a/gnustep-objc/debian/rules b/gnustep-objc/debian/rules new file mode 100755 index 00000000..1111d244 --- /dev/null +++ b/gnustep-objc/debian/rules @@ -0,0 +1,92 @@ +#!/usr/bin/make -f +# -*- makefile -*- +# Sample debian/rules that uses debhelper. +# GNU copyright 1997 to 1999 by Joey Hess. + +# Uncomment this to turn on verbose mode. +#export DH_VERBOSE=1 + +# Include dpatch stuff. +include /usr/share/dpatch/dpatch.make + +CFLAGS = -Wall -g +MAKE_FLAGS = messages=yes OPTFLAG=-O0 + +GNUSTEP_SETUP=/usr/lib/opengroupware.org/System/Library/Makefiles/GNUstep.sh + +ifneq (,$(findstring noopt,$(DEB_BUILD_OPTIONS))) + CFLAGS += -O0 +else + CFLAGS += -O2 +endif +ifeq (,$(findstring nostrip,$(DEB_BUILD_OPTIONS))) + INSTALL_PROGRAM += -s +endif + +build: build-stamp +build-stamp: patch-stamp + dh_testdir + + CFLAGS="$(CFLAGS)" . $(GNUSTEP_SETUP); \ + $(MAKE) $(MAKE_FLAGS) all + + touch build-stamp + +clean: unpatch + dh_testdir + dh_testroot + rm -f build-stamp + + -. $(GNUSTEP_SETUP); $(MAKE) clean + -. $(GNUSTEP_SETUP); $(MAKE) distclean + + dh_clean + +install: build + dh_testdir + dh_testroot + dh_clean -k + dh_installdirs + + CFLAGS="$(CFLAGS)" . $(GNUSTEP_SETUP); \ + $(MAKE) $(MAKE_FLAGS) install \ + GNUSTEP_INSTALLATION_DIR=$(CURDIR)/debian/tmp/$$GNUSTEP_SYSTEM_ROOT \ + FHS_INSTALL_ROOT=$(CURDIR)/debian/tmp/usr + +# Build architecture-independent files here. +binary-indep: build install +# We have nothing to do by default. + +# Build architecture-dependent files here. +binary-arch: build install + dh_testdir + dh_testroot + dh_installchangelogs ChangeLog + dh_installdocs + dh_installexamples + dh_install --sourcedir=debian/tmp +# dh_installmenu +# dh_installdebconf +# dh_installlogrotate +# dh_installemacsen +# dh_installpam +# dh_installmime +# dh_installinit +# dh_installcron +# dh_installinfo + dh_installman + dh_link + dh_strip + dh_compress + dh_fixperms +# dh_perl +# dh_python + dh_makeshlibs -V + dh_installdeb + dh_shlibdeps + dh_gencontrol + dh_md5sums + dh_builddeb + +binary: binary-indep binary-arch +.PHONY: build clean binary-indep binary-arch binary install configure diff --git a/gnustep-objc/encoding.c b/gnustep-objc/encoding.c new file mode 100644 index 00000000..61d977a5 --- /dev/null +++ b/gnustep-objc/encoding.c @@ -0,0 +1,917 @@ +/* Encoding of types for Objective C. + Copyright (C) 1993, 1995, 1996, 1997, 1998 Free Software Foundation, Inc. + Contributed by Kresten Krab Thorup + Bitfield support by Ovidiu Predescu + +This file is part of GNU CC. + +GNU CC is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU CC is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU CC; see the file COPYING. If not, write to +the Free Software Foundation, 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + +/* As a special exception, if you link this library with files + compiled with GCC to produce an executable, this does not cause + the resulting executable to be covered by the GNU General Public License. + This exception does not however invalidate any other reasons why + the executable file might be covered by the GNU General Public License. */ + +#include "compiler-info.h" +#include "objc-api.h" +#include "encoding.h" + +#define MAX(X, Y) \ + ({ typeof(X) __x = (X), __y = (Y); \ + (__x > __y ? __x : __y); }) + +#define MIN(X, Y) \ + ({ typeof(X) __x = (X), __y = (Y); \ + (__x < __y ? __x : __y); }) + +#define ROUND(V, A) \ + ({ typeof(V) __v=(V); typeof(A) __a=(A); \ + __a*((__v+__a-1)/__a); }) + + +/* Various hacks for objc_layout_record. These are used by the target + macros. */ + +#define TREE_CODE(TYPE) *TYPE +#define TREE_TYPE(TREE) TREE + +#define RECORD_TYPE _C_STRUCT_B +#define UNION_TYPE _C_UNION_B +#define QUAL_UNION_TYPE _C_UNION_B +#define ARRAY_TYPE _C_ARY_B + +#define TYPE_FIELDS(TYPE) objc_skip_typespec (TYPE) + +#define DECL_MODE(TYPE) *(TYPE) + +#define DFmode _C_DBL + +#define get_inner_array_type(TYPE) ((TYPE) + 1) + + +static __inline__ int objc_atoi(register const char* str) { + register int res = 0; + + while (isdigit ((int)*str)) + res *= 10, res += (*str++ - '0'); + + return res; +} + +/* + return the size of an object specified by type +*/ + +int objc_sizeof_type (const char* type) { + /* Skip the variable name if any */ + if (*type == '"') + { + for (type++; *type++ != '"';) + /* do nothing */; + } + + switch(*type) { + case _C_ID: + return sizeof(id); + break; + + case _C_CLASS: + return sizeof(Class); + break; + + case _C_SEL: + return sizeof(SEL); + break; + + case _C_CHR: + return sizeof(char); + break; + + case _C_UCHR: + return sizeof(unsigned char); + break; + + case _C_SHT: + return sizeof(short); + break; + + case _C_USHT: + return sizeof(unsigned short); + break; + + case _C_INT: + return sizeof(int); + break; + + case _C_UINT: + return sizeof(unsigned int); + break; + + case _C_LNG: + return sizeof(long); + break; + + case _C_ULNG: + return sizeof(unsigned long); + break; + + case _C_LNG_LNG: + return sizeof(long long); + break; + + case _C_ULNG_LNG: + return sizeof(unsigned long long); + break; + + case _C_FLT: + return sizeof(float); + break; + + case _C_DBL: + return sizeof(double); + break; + + case _C_VOID: + return sizeof(void); + break; + case _C_PTR: + case _C_ATOM: + case _C_CHARPTR: + return sizeof(char*); + break; + + case _C_ARY_B: + { + int len = objc_atoi(type+1); + while (isdigit((int)*++type)); + return len*objc_aligned_size (type); + } + break; + + case _C_BFLD: + { + /* The new encoding of bitfields is: b 'position' 'type' 'size' */ + int position, size; + int startByte, endByte; + + position = objc_atoi (type + 1); + while (isdigit ((int)*++type)); + size = objc_atoi (type + 1); + + startByte = position / BITS_PER_UNIT; + endByte = (position + size) / BITS_PER_UNIT; + return endByte - startByte; + } + + case _C_STRUCT_B: + { + struct objc_struct_layout layout; + unsigned int size; + + objc_layout_structure (type, &layout); + while (objc_layout_structure_next_member (&layout)) + /* do nothing */ ; + objc_layout_finish_structure (&layout, &size, NULL); + + return size; + } + + case _C_UNION_B: + { + int max_size = 0; + while (*type != _C_UNION_E && *type++ != '=') /* do nothing */; + while (*type != _C_UNION_E) + { + /* Skip the variable name if any */ + if (*type == '"') + { + for (type++; *type++ != '"';) + /* do nothing */; + } + max_size = MAX (max_size, objc_sizeof_type (type)); + type = objc_skip_typespec (type); + } + return max_size; + } + + default: + { + objc_error(nil, OBJC_ERR_BAD_TYPE, "%s: unknown type %s\n", + __PRETTY_FUNCTION__, type); + return 0; + } + } +} + + +/* + Return the alignment of an object specified by type +*/ + +int +objc_alignof_type(const char* type) +{ + /* Skip the variable name if any */ + if (*type == '"') + { + for (type++; *type++ != '"';) + /* do nothing */; + } + switch(*type) { + case _C_ID: + return __alignof__(id); + break; + + case _C_CLASS: + return __alignof__(Class); + break; + + case _C_SEL: + return __alignof__(SEL); + break; + + case _C_CHR: + return __alignof__(char); + break; + + case _C_UCHR: + return __alignof__(unsigned char); + break; + + case _C_SHT: + return __alignof__(short); + break; + + case _C_USHT: + return __alignof__(unsigned short); + break; + + case _C_INT: + return __alignof__(int); + break; + + case _C_UINT: + return __alignof__(unsigned int); + break; + + case _C_LNG: + return __alignof__(long); + break; + + case _C_ULNG: + return __alignof__(unsigned long); + break; + + case _C_LNG_LNG: + return __alignof__(long long); + break; + + case _C_ULNG_LNG: + return __alignof__(unsigned long long); + break; + + case _C_FLT: + return __alignof__(float); + break; + + case _C_DBL: + return __alignof__(double); + break; + + case _C_PTR: + case _C_ATOM: + case _C_CHARPTR: + return __alignof__(char*); + break; + + case _C_ARY_B: + while (isdigit((int)*++type)) /* do nothing */; + return objc_alignof_type (type); + + case _C_STRUCT_B: + { + struct objc_struct_layout layout; + unsigned int align; + + objc_layout_structure (type, &layout); + while (objc_layout_structure_next_member (&layout)) + /* do nothing */; + objc_layout_finish_structure (&layout, NULL, &align); + + return align; + } + + case _C_UNION_B: + { + int maxalign = 0; + while (*type != _C_UNION_E && *type++ != '=') /* do nothing */; + while (*type != _C_UNION_E) + { + /* Skip the variable name if any */ + if (*type == '"') + { + for (type++; *type++ != '"';) + /* do nothing */; + } + maxalign = MAX (maxalign, objc_alignof_type (type)); + type = objc_skip_typespec (type); + } + return maxalign; + } + + default: + { + objc_error(nil, OBJC_ERR_BAD_TYPE, "%s: unknown type %s\n", + __PRETTY_FUNCTION__, type); + return 0; + } + } +} + +/* + The aligned size if the size rounded up to the nearest alignment. +*/ + +int +objc_aligned_size (const char* type) +{ + int size, align; + + /* Skip the variable name */ + if (*type == '"') + { + for (type++; *type++ != '"';) + /* do nothing */; + } + + size = objc_sizeof_type (type); + align = objc_alignof_type (type); + + return ROUND (size, align); +} + +/* + The size rounded up to the nearest integral of the wordsize, taken + to be the size of a void*. +*/ + +int +objc_promoted_size (const char* type) +{ + int size, wordsize; + + /* Skip the variable name */ + if (*type == '"') + { + for (type++; *type++ != '"';) + /* do nothing */; + } + + size = objc_sizeof_type (type); + wordsize = sizeof (void*); + + return ROUND (size, wordsize); +} + +/* + Skip type qualifiers. These may eventually precede typespecs + occurring in method prototype encodings. +*/ + +__inline__ const char* +objc_skip_type_qualifiers (const char* type) +{ + while (*type == _C_CONST + || *type == _C_IN + || *type == _C_INOUT + || *type == _C_OUT + || *type == _C_BYCOPY + || *type == _C_BYREF + || *type == _C_ONEWAY + || *type == _C_GCINVISIBLE) + { + type += 1; + } + return type; +} + + +/* + Skip one typespec element. If the typespec is prepended by type + qualifiers, these are skipped as well. +*/ + +const char* +objc_skip_typespec (const char* type) +{ + /* Skip the variable name if any */ + if (*type == '"') + { + for (type++; *type++ != '"';) + /* do nothing */; + } + + type = objc_skip_type_qualifiers (type); + + switch (*type) { + + case _C_ID: + /* An id may be annotated by the actual type if it is known + with the @"ClassName" syntax */ + + if (*++type != '"') + return type; + else + { + while (*++type != '"') /* do nothing */; + return type + 1; + } + + /* The following are one character type codes */ + case _C_CLASS: + case _C_SEL: + case _C_CHR: + case _C_UCHR: + case _C_CHARPTR: + case _C_ATOM: + case _C_SHT: + case _C_USHT: + case _C_INT: + case _C_UINT: + case _C_LNG: + case _C_ULNG: + case _C_LNG_LNG: + case _C_ULNG_LNG: + case _C_FLT: + case _C_DBL: + case _C_VOID: + case _C_UNDEF: + return ++type; + break; + + case _C_ARY_B: + /* skip digits, typespec and closing ']' */ + + while(isdigit((int)*++type)); + type = objc_skip_typespec(type); + if (*type == _C_ARY_E) + return ++type; + else + { + objc_error(nil, OBJC_ERR_BAD_TYPE, "bad array type %s\n", type); + return 0; + } + + case _C_BFLD: + /* The new encoding of bitfields is: b 'position' 'type' 'size' */ + while (isdigit ((int)*++type)); /* skip position */ + while (isdigit ((int)*++type)); /* skip type and size */ + return type; + + case _C_STRUCT_B: + /* skip name, and elements until closing '}' */ + + while (*type != _C_STRUCT_E && *type++ != '='); + while (*type != _C_STRUCT_E) { type = objc_skip_typespec (type); } + return ++type; + + case _C_UNION_B: + /* skip name, and elements until closing ')' */ + + while (*type != _C_UNION_E && *type++ != '='); + while (*type != _C_UNION_E) { type = objc_skip_typespec (type); } + return ++type; + + case _C_PTR: + /* Just skip the following typespec */ + + return objc_skip_typespec (++type); + + default: + { + objc_error(nil, OBJC_ERR_BAD_TYPE, "%s: unknown type %s\n", + __PRETTY_FUNCTION__, type); + return 0; + } + } +} + +/* + Skip an offset as part of a method encoding. This is prepended by a + '+' if the argument is passed in registers. +*/ +__inline__ const char* +objc_skip_offset (const char* type) +{ + if (*type == '+') type++; + while(isdigit((int)*++type)); + return type; +} + +/* + Skip an argument specification of a method encoding. +*/ +const char* +objc_skip_argspec (const char* type) +{ + type = objc_skip_typespec (type); + type = objc_skip_offset (type); + return type; +} + +/* + Return the number of arguments that the method MTH expects. + Note that all methods need two implicit arguments `self' and + `_cmd'. +*/ +int +method_get_number_of_arguments (struct objc_method* mth) +{ + int i = 0; + const char* type = mth->method_types; + while (*type) + { + type = objc_skip_argspec (type); + i += 1; + } + return i - 1; +} + +/* + Return the size of the argument block needed on the stack to invoke + the method MTH. This may be zero, if all arguments are passed in + registers. +*/ + +int +method_get_sizeof_arguments (struct objc_method* mth) +{ + const char* type = objc_skip_typespec (mth->method_types); + return objc_atoi (type); +} + +/* + Return a pointer to the next argument of ARGFRAME. type points to + the last argument. Typical use of this look like: + + { + char *datum, *type; + for (datum = method_get_first_argument (method, argframe, &type); + datum; datum = method_get_next_argument (argframe, &type)) + { + unsigned flags = objc_get_type_qualifiers (type); + type = objc_skip_type_qualifiers (type); + if (*type != _C_PTR) + [portal encodeData: datum ofType: type]; + else + { + if ((flags & _F_IN) == _F_IN) + [portal encodeData: *(char**)datum ofType: ++type]; + } + } + } +*/ + +char* +method_get_next_argument (arglist_t argframe, + const char **type) +{ + const char *t = objc_skip_argspec (*type); + + if (*t == '\0') + return 0; + + *type = t; + t = objc_skip_typespec (t); + + if (*t == '+') + return argframe->arg_regs + objc_atoi (++t); + else + return argframe->arg_ptr + objc_atoi (t); +} + +/* + Return a pointer to the value of the first argument of the method + described in M with the given argumentframe ARGFRAME. The type + is returned in TYPE. type must be passed to successive calls of + method_get_next_argument. +*/ +char* +method_get_first_argument (struct objc_method* m, + arglist_t argframe, + const char** type) +{ + *type = m->method_types; + return method_get_next_argument (argframe, type); +} + +/* + Return a pointer to the ARGth argument of the method + M from the frame ARGFRAME. The type of the argument + is returned in the value-result argument TYPE +*/ + +char* +method_get_nth_argument (struct objc_method* m, + arglist_t argframe, int arg, + const char **type) +{ + const char* t = objc_skip_argspec (m->method_types); + + if (arg > method_get_number_of_arguments (m)) + return 0; + + while (arg--) + t = objc_skip_argspec (t); + + *type = t; + t = objc_skip_typespec (t); + + if (*t == '+') + return argframe->arg_regs + objc_atoi (++t); + else + return argframe->arg_ptr + objc_atoi (t); +} + +unsigned objc_get_type_qualifiers (const char* type) { + unsigned res = 0; + BOOL flag = YES; + + while (flag) + switch (*type++) + { + case _C_CONST: res |= _F_CONST; break; + case _C_IN: res |= _F_IN; break; + case _C_INOUT: res |= _F_INOUT; break; + case _C_OUT: res |= _F_OUT; break; + case _C_BYCOPY: res |= _F_BYCOPY; break; + case _C_BYREF: res |= _F_BYREF; break; + case _C_ONEWAY: res |= _F_ONEWAY; break; + case _C_GCINVISIBLE: res |= _F_GCINVISIBLE; break; + default: flag = NO; + } + + return res; +} + + +/* The following three functions can be used to determine how a + structure is laid out by the compiler. For example: + + struct objc_struct_layout layout; + int i; + + objc_layout_structure (type, &layout); + while (objc_layout_structure_next_member (&layout)) + { + int position, align; + const char *type; + + objc_layout_structure_get_info (&layout, &position, &align, &type); + printf ("element %d has offset %d, alignment %d\n", + i++, position, align); + } + + These functions are used by objc_sizeof_type and objc_alignof_type + functions to compute the size and alignment of structures. The + previous method of computing the size and alignment of a structure + was not working on some architectures, particulary on AIX, and in + the presence of bitfields inside the structure. */ +void +objc_layout_structure (const char *type, + struct objc_struct_layout *layout) +{ + const char *ntype; + + if (*type++ != _C_STRUCT_B) + { + objc_error(nil, OBJC_ERR_BAD_TYPE, + "record type expected in objc_layout_structure, got %s\n", + type); + } + + layout->original_type = type; + + /* Skip "=" if any. Avoid embedded structures and unions. */ + ntype = type; + while (*ntype != _C_STRUCT_E && *ntype != _C_STRUCT_B && *ntype != _C_UNION_B + && *ntype++ != '=') + /* do nothing */; + + /* If there's a "=", ntype - 1 points to '='; skip the the name */ + if (*(ntype - 1) == '=') + type = ntype; + + layout->type = type; + layout->prev_type = NULL; + layout->record_size = 0; + layout->record_align = BITS_PER_UNIT; + +#ifdef STRUCTURE_SIZE_BOUNDARY + layout->record_align = MAX (layout->record_align, STRUCTURE_SIZE_BOUNDARY); +#endif +} + + +BOOL +objc_layout_structure_next_member (struct objc_struct_layout *layout) +{ + /* unused: register int known_align = layout->record_size; */ + register int desired_align = 0; + + /* The following are used only if the field is a bitfield */ + register const char *bfld_type = NULL; + register int bfld_type_size = 0; + register int bfld_type_align = 0; + register int bfld_field_size = 0; + + /* The current type without the type qualifiers */ + const char *type; + +#if 1 + if (layout->prev_type == NULL) + { + layout->prev_type = layout->type; + layout->type = objc_skip_typespec (layout->prev_type); + return YES; + } +#endif + + /* Add the size of the previous field to the size of the record. */ + if (layout->prev_type) + { + type = objc_skip_type_qualifiers (layout->prev_type); + + if (*type != _C_BFLD) + layout->record_size += objc_sizeof_type (type) * BITS_PER_UNIT; + else { + desired_align = 1; + /* Get the bitfield's type */ + for (bfld_type = type + 1; + isdigit((int)*bfld_type); + bfld_type++) + /* do nothing */; + + bfld_type_size = objc_sizeof_type (bfld_type) * BITS_PER_UNIT; + bfld_type_align = objc_alignof_type (bfld_type) * BITS_PER_UNIT; + bfld_field_size = objc_atoi (objc_skip_typespec (bfld_type)); + layout->record_size += bfld_field_size; + } + } + + if (*layout->type == _C_STRUCT_E) + return NO; + + /* Skip the variable name if any */ + if (*layout->type == '"') + { + for (layout->type++; *layout->type++ != '"';) + /* do nothing */; + } + + type = objc_skip_type_qualifiers (layout->type); + + if (*type != _C_BFLD) + desired_align = objc_alignof_type(type) * BITS_PER_UNIT; + else + { + desired_align = 1; + /* Skip the bitfield's offset */ + for (bfld_type = type + 1; isdigit((int)*bfld_type); bfld_type++) + /* do nothing */; + + bfld_type_size = objc_sizeof_type (bfld_type) * BITS_PER_UNIT; + bfld_type_align = objc_alignof_type (bfld_type) * BITS_PER_UNIT; + bfld_field_size = objc_atoi (objc_skip_typespec (bfld_type)); + } + +#ifdef BIGGEST_FIELD_ALIGNMENT + desired_align = MIN (desired_align, BIGGEST_FIELD_ALIGNMENT); +#endif +#ifdef ADJUST_FIELD_ALIGN + desired_align = ADJUST_FIELD_ALIGN (type, desired_align); +#endif + + /* Record must have at least as much alignment as any field. + Otherwise, the alignment of the field within the record + is meaningless. */ +#ifndef PCC_BITFIELD_TYPE_MATTERS + layout->record_align = MAX (layout->record_align, desired_align); +#else + if (*type == _C_BFLD) + { + /* For these machines, a zero-length field does not + affect the alignment of the structure as a whole. + It does, however, affect the alignment of the next field + within the structure. */ + if (bfld_field_size) + layout->record_align = MAX (layout->record_align, desired_align); + else + desired_align = objc_alignof_type (bfld_type) * BITS_PER_UNIT; + + /* A named bit field of declared type `int' + forces the entire structure to have `int' alignment. + Q1: How is encoded this thing and how to check for it? + Q2: How to determine maximum_field_alignment at runtime? */ + +/* if (DECL_NAME (field) != 0) */ + { + int type_align = bfld_type_align; +#if 0 + if (maximum_field_alignment != 0) + type_align = MIN (type_align, maximum_field_alignment); + else if (DECL_PACKED (field)) + type_align = MIN (type_align, BITS_PER_UNIT); +#endif + + layout->record_align = MAX (layout->record_align, type_align); + } + } + else + layout->record_align = MAX (layout->record_align, desired_align); +#endif + + /* Does this field automatically have alignment it needs + by virtue of the fields that precede it and the record's + own alignment? */ + + if (*type == _C_BFLD) + layout->record_size = objc_atoi (type + 1); + else if (layout->record_size % desired_align != 0) + { + /* No, we need to skip space before this field. + Bump the cumulative size to multiple of field alignment. */ + layout->record_size = ROUND (layout->record_size, desired_align); + } + + /* Jump to the next field in record. */ + + layout->prev_type = layout->type; + layout->type = objc_skip_typespec (layout->type); /* skip component */ + + return YES; +} + + +void objc_layout_finish_structure (struct objc_struct_layout *layout, + unsigned int *size, + unsigned int *align) +{ + if (layout->type && *layout->type == _C_STRUCT_E) + { + /* Work out the alignment of the record as one expression and store + in the record type. Round it up to a multiple of the record's + alignment. */ + +#ifdef ROUND_TYPE_ALIGN + layout->record_align = ROUND_TYPE_ALIGN (layout->original_type, + 1, + layout->record_align); +#else + layout->record_align = MAX (1, layout->record_align); +#endif + +#ifdef ROUND_TYPE_SIZE + layout->record_size = ROUND_TYPE_SIZE (layout->original_type, + layout->record_size, + layout->record_align); +#else + /* Round the size up to be a multiple of the required alignment */ + layout->record_size = ROUND (layout->record_size, layout->record_align); +#endif + + layout->type = NULL; + } + if (size) + *size = layout->record_size / BITS_PER_UNIT; + if (align) + *align = layout->record_align / BITS_PER_UNIT; +} + + +void objc_layout_structure_get_info (struct objc_struct_layout *layout, + unsigned int *offset, + unsigned int *align, + const char **type) +{ + if (offset) + *offset = layout->record_size / BITS_PER_UNIT; + if (align) + *align = layout->record_align / BITS_PER_UNIT; + if (type) + *type = layout->prev_type; +} diff --git a/gnustep-objc/encoding.h b/gnustep-objc/encoding.h new file mode 100644 index 00000000..b4def430 --- /dev/null +++ b/gnustep-objc/encoding.h @@ -0,0 +1,99 @@ +/* Encoding of types for Objective C. + Copyright (C) 1993, 1997 Free Software Foundation, Inc. + +Author: Kresten Krab Thorup + +This file is part of GNU CC. + +GNU CC is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU CC is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU CC; see the file COPYING. If not, write to +the Free Software Foundation, 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + +/* As a special exception, if you link this library with files + compiled with GCC to produce an executable, this does not cause + the resulting executable to be covered by the GNU General Public License. + This exception does not however invalidate any other reasons why + the executable file might be covered by the GNU General Public License. */ + +#ifndef __encoding_INCLUDE_GNU +#define __encoding_INCLUDE_GNU + +#include +#include "objc/objc-api.h" + +#define _C_CONST 'r' +#define _C_IN 'n' +#define _C_INOUT 'N' +#define _C_OUT 'o' +#define _C_BYCOPY 'O' +#define _C_BYREF 'R' +#define _C_ONEWAY 'V' +#define _C_GCINVISIBLE '!' + +#define _F_CONST 0x01 +#define _F_IN 0x01 +#define _F_OUT 0x02 +#define _F_INOUT 0x03 +#define _F_BYCOPY 0x04 +#define _F_BYREF 0x08 +#define _F_ONEWAY 0x10 +#define _F_GCINVISIBLE 0x20 + +int objc_aligned_size (const char* type); +int objc_sizeof_type (const char* type); +int objc_alignof_type (const char* type); +int objc_aligned_size (const char* type); +int objc_promoted_size (const char* type); + +const char* objc_skip_type_qualifiers (const char* type); +const char* objc_skip_typespec (const char* type); +const char* objc_skip_offset (const char* type); +const char* objc_skip_argspec (const char* type); +int method_get_number_of_arguments (struct objc_method*); +int method_get_sizeof_arguments (struct objc_method*); + +char* method_get_first_argument (struct objc_method*, + arglist_t argframe, + const char** type); +char* method_get_next_argument (arglist_t argframe, + const char **type); +char* method_get_nth_argument (struct objc_method* m, + arglist_t argframe, + int arg, + const char **type); + +unsigned objc_get_type_qualifiers (const char* type); + + +struct objc_struct_layout +{ + const char *original_type; + const char *type; + const char *prev_type; + unsigned int record_size; + unsigned int record_align; +}; + +void objc_layout_structure (const char *type, + struct objc_struct_layout *layout); +BOOL objc_layout_structure_next_member (struct objc_struct_layout *layout); +void objc_layout_finish_structure (struct objc_struct_layout *layout, + unsigned int *size, + unsigned int *align); +void objc_layout_structure_get_info (struct objc_struct_layout *layout, + unsigned int *offset, + unsigned int *align, + const char **type); + +#endif /* __encoding_INCLUDE_GNU */ diff --git a/gnustep-objc/fhs.make b/gnustep-objc/fhs.make new file mode 100644 index 00000000..8f856c4c --- /dev/null +++ b/gnustep-objc/fhs.make @@ -0,0 +1,51 @@ +# fhs.make +# +# Copyright (C) 2004 Helge Hess. +# All rights reserved. +# +# Author: Helge Hess +# Date: Ausgust 2004 +# +# This file is part of libFoundation. +# +# Permission to use, copy, modify, and distribute this software and its +# documentation for any purpose and without fee is hereby granted, provided +# that the above copyright notice appear in all copies and that both that +# copyright notice and this permission notice appear in supporting +# documentation. +# +# We disclaim all warranties with regard to this software, including all +# implied warranties of merchantability and fitness, in no event shall +# we be liable for any special, indirect or consequential damages or any +# damages whatsoever resulting from loss of use, data or profits, whether in +# an action of contract, negligence or other tortious action, arising out of +# or in connection with the use or performance of this software. +# + +# FHS support (this is a hack and is going to be done by gstep-make!) + +ifneq ($(FHS_INSTALL_ROOT),) + +FHS_INCLUDE_DIR=$(FHS_INSTALL_ROOT)/include/ +FHS_LIB_DIR=$(FHS_INSTALL_ROOT)/lib/ + +fhs-header-dirs :: + $(MKDIRS) $(FHS_INCLUDE_DIR) + $(MKDIRS) $(FHS_INCLUDE_DIR)/objc + +move-headers-to-fhs :: fhs-header-dirs + @echo "moving headers to $(FHS_INCLUDE_DIR) .." + mv $(GNUSTEP_HEADERS)/objc/*.h $(FHS_INCLUDE_DIR)/objc/ + +NONFHS_LIBDIR="$(GNUSTEP_LIBRARIES)/$(GNUSTEP_TARGET_LDIR)/" +NONFHS_LIBNAME="$(LIBRARY_NAME)$(LIBRARY_NAME_SUFFIX)$(SHARED_LIBEXT)" + +move-libs-to-fhs :: + @echo "moving libs to $(FHS_LIB_DIR) .." + mv $(NONFHS_LIBDIR)/$(NONFHS_LIBNAME)* $(FHS_LIB_DIR)/ + +move-to-fhs :: move-headers-to-fhs move-libs-to-fhs + +after-install :: move-to-fhs + +endif diff --git a/gnustep-objc/gc.c b/gnustep-objc/gc.c new file mode 100644 index 00000000..3526a33c --- /dev/null +++ b/gnustep-objc/gc.c @@ -0,0 +1,592 @@ +/* Basic data types for Objective C. + Copyright (C) 1998 Free Software Foundation, Inc. + Contributed by Ovidiu Predescu. + +This file is part of GNU CC. + +GNU CC is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU CC is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU CC; see the file COPYING. If not, write to +the Free Software Foundation, 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + +/* As a special exception, if you link this library with files + compiled with GCC to produce an executable, this does not cause + the resulting executable to be covered by the GNU General Public License. + This exception does not however invalidate any other reasons why + the executable file might be covered by the GNU General Public License. */ + +#include "compiler-info.h" +#include "objc.h" +#include "encoding.h" +#include "objc-api.h" + +#include +#include + +#if OBJC_WITH_GC + +#include "gc/gc.h" + +/* gc_typed.h uses the following but doesn't declare them */ +typedef GC_word word; +typedef GC_signed_word signed_word; + +#if BITS_PER_WORD == 32 +# define LOGWL 5 +# define modWORDSZ(n) ((n) & 0x1f) /* n mod size of word */ +#endif + +#if BITS_PER_WORD == 64 +# define LOGWL 6 +# define modWORDSZ(n) ((n) & 0x3f) /* n mod size of word */ +#endif + +#define divWORDSZ(n) ((n) >> LOGWL) /* divide n by size of word */ + +#include "gc/gc_typed.h" + +/* The following functions set up in `mask` the corresponding pointers. + The offset is incremented with the size of the type. */ + +#define ROUND(V, A) \ + ({ typeof(V) __v=(V); typeof(A) __a=(A); \ + __a*((__v+__a-1)/__a); }) + +#define SET_BIT_FOR_OFFSET(mask, offset) \ + GC_set_bit(mask, offset / sizeof (void*)) + +/* Some prototypes */ +static void +__objc_gc_setup_struct (GC_bitmap mask, const char *type, int offset); +static void +__objc_gc_setup_union (GC_bitmap mask, const char *type, int offset); + + +static void +__objc_gc_setup_array (GC_bitmap mask, const char *type, int offset) +{ + register int i, len; + + if (type == NULL) { + printf("WARNING: %s got NULL type.\n", __PRETTY_FUNCTION__); + return; + } + + len = atoi(type + 1); + + while (isdigit(*++type)) + /* do nothing */; /* skip the size of the array */ + + switch (*type) { + case _C_ARY_B: + for (i = 0; i < len; i++) + __objc_gc_setup_array (mask, type, offset); + break; + + case _C_STRUCT_B: + for (i = 0; i < len; i++) + __objc_gc_setup_struct (mask, type, offset); + break; + + case _C_UNION_B: + for (i = 0; i < len; i++) + __objc_gc_setup_union (mask, type, offset); + break; + + default: + break; + } +} + +static void +__objc_gc_setup_struct (GC_bitmap mask, const char *type, int offset) +{ + struct objc_struct_layout layout; + unsigned int position; + const char *mtype; + + if (type == NULL) { + printf("WARNING: %s got NULL type.\n", __PRETTY_FUNCTION__); + return; + } + + objc_layout_structure (type, &layout); + + while (objc_layout_structure_next_member (&layout)) + { + BOOL gc_invisible = NO; + + objc_layout_structure_get_info (&layout, &position, NULL, &mtype); + + /* Skip the variable name */ + if (*mtype == '"') + { + for (mtype++; *mtype++ != '"';) + /* do nothing */; + } + + if (*mtype == _C_GCINVISIBLE) + { + gc_invisible = YES; + mtype++; + } + + /* Add to position the offset of this structure */ + position += offset; + + switch (*mtype) { + case _C_ID: + case _C_CLASS: + case _C_SEL: + case _C_PTR: + case _C_CHARPTR: + case _C_ATOM: + if (!gc_invisible) + SET_BIT_FOR_OFFSET(mask, position); + break; + + case _C_ARY_B: + __objc_gc_setup_array (mask, mtype, position); + break; + + case _C_STRUCT_B: + __objc_gc_setup_struct (mask, mtype, position); + break; + + case _C_UNION_B: + __objc_gc_setup_union (mask, mtype, position); + break; + + default: + break; + } + } +} + +static void +__objc_gc_setup_union (GC_bitmap mask, const char *type, int offset) +{ + /* Sub-optimal, quick implementation: assume the union is made of + pointers, set up the mask accordingly. */ + + int i, size, align; + + if (type == NULL) { + printf("WARNING: %s got NULL type.\n", __PRETTY_FUNCTION__); + return; + } + + /* Skip the variable name */ + if (*type == '"') + { + for (type++; *type++ != '"';) + /* do nothing */; + } + + size = objc_sizeof_type (type); + align = objc_alignof_type (type); + + offset = ROUND(offset, align); + for (i = 0; i < size; i += sizeof (void*)) + { + SET_BIT_FOR_OFFSET(mask, offset); + offset += sizeof (void*); + } +} + + +/* Iterates over the types in the structure that represents the class + encoding and sets the bits in mask according to each ivar type. */ +static void +__objc_gc_type_description_from_type (GC_bitmap mask, const char *type) +{ + struct objc_struct_layout layout; + unsigned int offset, align; + const char *ivar_type; + + if (type == NULL) { + printf("WARNING: %s got NULL type.\n", __PRETTY_FUNCTION__); + return; + } + + objc_layout_structure (type, &layout); + + while (objc_layout_structure_next_member (&layout)) { + BOOL gc_invisible = NO; + + objc_layout_structure_get_info (&layout, &offset, &align, &ivar_type); + + /* Skip the variable name */ + if (*ivar_type == '"') { + for (ivar_type++; *ivar_type++ != '"';) + /* do nothing */; + } + + if (*ivar_type == _C_GCINVISIBLE) { + gc_invisible = YES; + ivar_type++; + } + + switch (*ivar_type) { + case _C_ID: + case _C_CLASS: + case _C_SEL: + case _C_PTR: + case _C_CHARPTR: + if (!gc_invisible) + SET_BIT_FOR_OFFSET(mask, offset); + break; + + case _C_ARY_B: + __objc_gc_setup_array (mask, ivar_type, offset); + break; + + case _C_STRUCT_B: + __objc_gc_setup_struct (mask, ivar_type, offset); + break; + + case _C_UNION_B: + __objc_gc_setup_union (mask, ivar_type, offset); + break; + + default: + break; + } + } +} + +/* Computes in *type the full type encoding of this class including + its super classes. '*size' gives the total number of bytes allocated + into *type, '*current' the number of bytes used so far by the + encoding. */ +static void +__objc_class_structure_encoding (Class class, char **type, int *size, + int *current) +{ + int i, ivar_count; + struct objc_ivar_list* ivars; + + if (class == Nil) { + // Root class, add '{' + strcat (*type, "{"); + *current++; + return; + } + + /* Add the type encodings of the super classes */ + __objc_class_structure_encoding (class->super_class, type, size, current); + + ivars = class->ivars; + if (!ivars) + return; + + ivar_count = ivars->ivar_count; + + for (i = 0; i < ivar_count; i++) { + struct objc_ivar *ivar = &(ivars->ivar_list[i]); + const char *ivar_type = ivar->ivar_type; + int len = strlen (ivar_type); + + if (*current + len + 1 >= *size) + { + /* Increase the size of the encoding string so that it + contains this ivar's type. */ + *size = ROUND(*current + len + 1, 10); + *type = objc_realloc (*type, *size); + } + strcat (*type + *current, ivar_type); + *current += len; + } +} + + +/* Allocates the memory that will hold the type description for class + and calls the __objc_class_structure_encoding that generates this + value. */ +void __objc_generate_gc_type_description (Class class) +{ + GC_bitmap mask = NULL; + int bits_no, size; + int type_size = 800; + int current = 0; + char *class_structure_type = NULL; + + if (!CLS_ISCLASS(class)) + return; + + /* We have to create a mask in which each bit counts for a pointer member. + We take into consideration all the non-pointer instance variables and we + round them up to the alignment. */ + + //class_structure_type = objc_atomic_malloc (type_size); + class_structure_type = GC_MALLOC_ATOMIC(1024); + class_structure_type[0] = '\0'; + __objc_class_structure_encoding (class, + &class_structure_type, + &type_size, + ¤t); + //if (current + 1 == type_size) + // class_structure_type = objc_realloc (class_structure_type, ++type_size); + // add root class suffix + strcat (class_structure_type + current, "}"); + + if (class_structure_type[0] != '{') { + printf("ERROR: invalid class type '%s'", + class_structure_type ? class_structure_type : ""); + abort(); + } + if (class_structure_type[strlen(class_structure_type) - 1] != '}') { + printf("ERROR: invalid class type '%s'", + class_structure_type ? class_structure_type : ""); + abort(); + } + +#if DEBUG_OBJC_GC + printf ("type description for '%s' is %s\n", + class->name ? class->name : "", + class_structure_type ? class_structure_type : ""); +#endif + + if (class_structure_type == NULL) { + printf("WARNING: %s got NULL type for class %s.\n", + __PRETTY_FUNCTION__, class->name ? class->name : ""); + abort(); + } + + /* The number of bits in the mask is the size of an instance in bytes divided + by the size of a pointer. */ + bits_no = (ROUND(class_get_instance_size (class), sizeof(void*)) + / sizeof (void*)); + size = ROUND(bits_no, BITS_PER_WORD) / BITS_PER_WORD; + mask = GC_MALLOC_ATOMIC(size * sizeof (int)); + memset(mask, 0, size * sizeof (int)); + + __objc_gc_type_description_from_type (mask, class_structure_type); + class_structure_type = NULL; + +#if DEBUG_OBJC_GC + printf (" mask for '%s', type '%s' (bits %d, mask size %d) is:", + class_structure_type ? class_structure_type : "", + class->name ? class->name : "", + bits_no, size); + { + int i; + for (i = 0; i < size; i++) + printf (" %lx", mask[i]); + } + puts (""); +#endif + + class->gc_object_type = (void*)GC_make_descriptor (mask, bits_no); +} + + +/* Returns YES if type denotes a pointer type, NO otherwise */ +static __inline__ BOOL __objc_ivar_pointer (register const char *type) +{ + type = objc_skip_type_qualifiers (type); + + return (*type == _C_ID + || *type == _C_CLASS + || *type == _C_SEL + || *type == _C_PTR + || *type == _C_CHARPTR + || *type == _C_ATOM); +} + + +/* Mark the instance variable whose name is given by ivarname as a + weak pointer (a pointer hidden to the garbage collector) if + gc_invisible is true. If gc_invisible is false it unmarks the + instance variable and makes it a normal pointer, visible to the + garbage collector. + + This operation only makes sense on instance variables that are + pointers. */ +void +class_ivar_set_gcinvisible (Class class, const char* ivarname, + BOOL gc_invisible) +{ + int i, ivar_count; + struct objc_ivar_list* ivars; + + if (!class || !ivarname) + return; + + ivars = class->ivars; + if (!ivars) + return; + + ivar_count = ivars->ivar_count; + + for (i = 0; i < ivar_count; i++) + { + struct objc_ivar *ivar = &(ivars->ivar_list[i]); + const char *type; + + if (!ivar->ivar_name || strcmp (ivar->ivar_name, ivarname)) + continue; + + assert (ivar->ivar_type); + type = ivar->ivar_type; + + /* Skip the variable name */ + if (*type == '"') + { + for (type++; *type++ != '"';) + /* do nothing */; + } + + if (*type == _C_GCINVISIBLE) + { + char *new_type; + + if (gc_invisible || !__objc_ivar_pointer (type)) + return; /* The type of the variable already matches the + requested gc_invisible type */ + + /* The variable is gc_invisible and we have to reverse it */ + new_type = objc_atomic_malloc (strlen (ivar->ivar_type)); + strncpy (new_type, ivar->ivar_type, + (size_t)(type - ivar->ivar_type)); + strcat (new_type, type + 1); + ivar->ivar_type = new_type; + } + else + { + char *new_type; + + if (!gc_invisible || !__objc_ivar_pointer (type)) + return; /* The type of the variable already matches the + requested gc_invisible type */ + + /* The variable is gc visible and we have to make it gc_invisible */ + new_type = objc_malloc (strlen (ivar->ivar_type) + 2); + strncpy (new_type, ivar->ivar_type, + (size_t)(type - ivar->ivar_type)); + strcat (new_type, "!"); + strcat (new_type, type); + ivar->ivar_type = new_type; + } + + __objc_generate_gc_type_description (class); + return; + } + + /* Search the instance variable in the superclasses */ + class_ivar_set_gcinvisible (class->super_class, ivarname, gc_invisible); +} + +BOOL objc_ignore_leaks = YES; +void (*objc_report_atomic_leak_func)(void *ptr, unsigned size) = NULL; +void (*objc_report_composite_leak_func)(void *ptr, unsigned size) = NULL; + +void objc_report_atomic_leak(void *ptr, unsigned size) { + const unsigned char *t; + unsigned char buffer[128]; + + if (objc_ignore_leaks) return; + if (objc_report_atomic_leak_func) { + objc_report_atomic_leak_func(ptr, size); + return; + } + + /* + if (object_is_class(ptr)) + t = "class"; + else if (object_is_instance(ptr)) + t = "object"; + else + */ + t = "unknown"; + + buffer[0] = 0; + if (size < 120) { + int i; + unsigned char c; + + for (i = 0; i < size; i++) { + c = ((unsigned char *)ptr)[i]; + if (c == '\0') break; + if (!((c > 31) && (c < 128))) + break; + } + + if (i < size) { + if (c == '\0') + strcpy(buffer, ptr); + } + } + + fprintf(stderr, "LEAK(atomic): %s 0x%08X %d bytes(%s)\n", + t ? t : "", + (unsigned)ptr, size, + buffer ? buffer : ""); +} +void objc_report_composite_leak(void *ptr, unsigned size) { + const char *t; + unsigned char buffer[128]; + + if (objc_ignore_leaks) return; + if (objc_report_composite_leak_func) { + objc_report_composite_leak_func(ptr, size); + return; + } + + /* + if (object_is_class(ptr)) + t = "class"; + else if (object_is_instance(ptr)) + t = "object"; + else + */ + t = "unknown"; + + buffer[0] = 0; + if (size < 120) { + int i; + unsigned char c; + + for (i = 0; i < size; i++) { + c = ((unsigned char *)ptr)[i]; + if (c == '\0') break; + if (!((c > 31) && (c < 128))) + break; + } + + if (i < size) { + if (c == '\0') + strcpy(buffer, ptr); + } + } + + fprintf(stderr, "LEAK(composite): %s 0x%08X %d bytes(%s)\n", + t ? t : "", + (unsigned)ptr, size, + buffer ? buffer : ""); +} + +#else /* !OBJC_WITH_GC */ + +void +__objc_generate_gc_type_description (Class class) +{ +} + +void class_ivar_set_gcinvisible (Class class, + const char* ivarname, + BOOL gc_invisible) +{ +} + +#endif /* OBJC_WITH_GC */ diff --git a/gnustep-objc/globals.c b/gnustep-objc/globals.c new file mode 100644 index 00000000..7123d844 --- /dev/null +++ b/gnustep-objc/globals.c @@ -0,0 +1,99 @@ +/* GNU Objective C Runtime class related functions + Copyright (C) 1993, 1995, 1996, 1997 Free Software Foundation, Inc. + Contributed by Kresten Krab Thorup and Dennis Glatting. + +This file is part of GNU CC. + +GNU CC is free software; you can redistribute it and/or modify it under the +terms of the GNU General Public License as published by the Free Software +Foundation; either version 2, or (at your option) any later version. + +GNU CC is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +FOR A PARTICULAR PURPOSE. See the GNU General Public License for more +details. + +You should have received a copy of the GNU General Public License along with +GNU CC; see the file COPYING. If not, write to the Free Software +Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +/* As a special exception, if you link this library with files compiled with + GCC to produce an executable, this does not cause the resulting executable + to be covered by the GNU General Public License. This exception does not + however invalidate any other reasons why the executable file might be + covered by the GNU General Public License. */ + +#include "objc-decls.h" +#include "runtime.h" /* the kitchen sink */ + +/* + Global variables used in the Objective-C runtime. +*/ + +/* deprecated: */ + +objc_DECLARE void *__objc_uninstalled_dtable = NULL; + +/* ******************** from class.c: ******************** */ + +/* The table of classname->class. Used for objc_lookup_class and friends */ +objc_DECLARE cache_ptr __objc_class_hash = 0; /* !T:MUTEX */ + +/* This is a hook which is called by objc_get_class and + objc_lookup_class if the runtime is not able to find the class. + This may e.g. try to load in the class using dynamic loading */ +objc_DECLARE Class (*_objc_lookup_class)(const char* name) = 0; /* !T:SAFE */ + + +/* True when class links has been resolved */ +objc_DECLARE BOOL __objc_class_links_resolved = NO; /* !T:UNUSED */ + + +/* ******************** from init.c: ********************* */ + +/* This list contains all modules currently loaded into the runtime */ +objc_DECLARE struct objc_list* __objc_module_list = 0; /* !T:MUTEX */ + +/* This list contains all proto_list's not yet assigned class links */ +objc_DECLARE struct objc_list* __objc_unclaimed_proto_list = 0; /* !T:MUTEX */ + +/* List of unresolved static instances. */ +objc_DECLARE struct objc_list *__objc_uninitialized_statics = 0; /* !T:MUTEX */ + +/* Global runtime "write" mutex. */ +objc_DECLARE objc_mutex_t __objc_runtime_mutex = 0; + +/* Number of threads that are alive. */ +objc_DECLARE int __objc_runtime_threads_alive = 1; /* !T:MUTEX */ + +/* This is a hook which is called by __objc_exec_class every time a class + or a category is loaded into the runtime. This may e.g. help a + dynamic loader determine the classes that have been loaded when + an object file is dynamically linked in */ +objc_DECLARE void (*_objc_load_callback)(Class class, Category* category); /* !T:SAFE */ + +/* Is all categories/classes resolved? */ +objc_DECLARE BOOL __objc_dangling_categories = NO; /* !T:UNUSED */ + +/* This is a linked list of objc_class_tree trees. The head of these trees + are root classes (their super class is Nil). These different trees + represent different class hierarchies. */ +objc_DECLARE struct objc_list *__objc_class_tree_list = NULL; + +/* Keeps the +load methods who have been already executed. This hash should + not be destroyed during the execution of the program. */ +objc_DECLARE cache_ptr __objc_load_methods = NULL; + + +/* ******************** from selector.c: ********************* */ + +/* Tables mapping selector names to uid and opposite */ +objc_DECLARE struct sarray* __objc_selector_array = 0; /* uid -> sel-list !T:MUTEX */ +objc_DECLARE struct sarray* __objc_selector_names = 0; /* uid -> name !T:MUTEX */ +objc_DECLARE cache_ptr __objc_selector_hash = 0; /* name -> uid !T:MUTEX */ + +/* Number of selectors stored in each of the above tables */ +objc_DECLARE int __objc_selector_max_index = 0; /* !T:MUTEX */ + +objc_DECLARE IMP (*__objc_msg_lookup)(id, SEL) = NULL; +objc_DECLARE IMP (*__objc_class_get_method)(Class, SEL) = NULL; diff --git a/gnustep-objc/globals.h b/gnustep-objc/globals.h new file mode 100644 index 00000000..1bf5dfff --- /dev/null +++ b/gnustep-objc/globals.h @@ -0,0 +1,96 @@ +/* GNU Objective C Runtime class related functions + Copyright (C) 1993, 1995, 1996, 1997 Free Software Foundation, Inc. + Contributed by Kresten Krab Thorup and Dennis Glatting. + +This file is part of GNU CC. + +GNU CC is free software; you can redistribute it and/or modify it under the +terms of the GNU General Public License as published by the Free Software +Foundation; either version 2, or (at your option) any later version. + +GNU CC is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +FOR A PARTICULAR PURPOSE. See the GNU General Public License for more +details. + +You should have received a copy of the GNU General Public License along with +GNU CC; see the file COPYING. If not, write to the Free Software +Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +/* As a special exception, if you link this library with files compiled with + GCC to produce an executable, this does not cause the resulting executable + to be covered by the GNU General Public License. This exception does not + however invalidate any other reasons why the executable file might be + covered by the GNU General Public License. */ + +#ifndef __objc_globals_H__ +#define __objc_globals_H__ + +#include "objc-decls.h" +#include "objc-api.h" + +/* + Global variables used in the Objective-C runtime. +*/ + +/* ******************** from class.c: ******************** */ + +/* The table of classname->class. Used for objc_lookup_class and friends */ +objc_EXPORT cache_ptr __objc_class_hash; /* !T:MUTEX */ + +/* This is a hook which is called by objc_get_class and + objc_lookup_class if the runtime is not able to find the class. + This may e.g. try to load in the class using dynamic loading */ +objc_EXPORT Class (*_objc_lookup_class)(const char* name); /* !T:SAFE */ + + +/* True when class links has been resolved */ +objc_EXPORT BOOL __objc_class_links_resolved; /* !T:UNUSED */ + +/* ******************** from init.c: ********************* */ + +/* This list contains all modules currently loaded into the runtime */ +objc_EXPORT struct objc_list* __objc_module_list; /* !T:MUTEX */ + +/* This list contains all proto_list's not yet assigned class links */ +objc_EXPORT struct objc_list* __objc_unclaimed_proto_list; /* !T:MUTEX */ + +/* List of unresolved static instances. */ +objc_EXPORT struct objc_list *__objc_uninitialized_statics; /* !T:MUTEX */ + +/* Global runtime "write" mutex. */ +objc_EXPORT objc_mutex_t __objc_runtime_mutex; + +/* Number of threads that are alive. */ +objc_EXPORT int __objc_runtime_threads_alive; /* !T:MUTEX */ + +/* This is a hook which is called by __objc_exec_class every time a class + or a category is loaded into the runtime. This may e.g. help a + dynamic loader determine the classes that have been loaded when + an object file is dynamically linked in */ +objc_EXPORT void (*_objc_load_callback)(Class class, Category *category); /* !T:SAFE*/ + +/* Is all categories/classes resolved? */ +objc_EXPORT BOOL __objc_dangling_categories; /* !T:UNUSED */ + +/* This is a linked list of objc_class_tree trees. The head of these trees + are root classes (their super class is Nil). These different trees + represent different class hierarchies. */ +objc_EXPORT struct objc_list *__objc_class_tree_list; + +/* Keeps the +load methods who have been already executed. This hash should + not be destroyed during the execution of the program. */ +objc_EXPORT cache_ptr __objc_load_methods; + + +/* ******************** from selector.c: ********************* */ + +/* Tables mapping selector names to uid and opposite */ +objc_EXPORT struct sarray* __objc_selector_array; /* uid -> sel-list !T:MUTEX */ +objc_EXPORT struct sarray* __objc_selector_names; /* uid -> name !T:MUTEX */ +objc_EXPORT cache_ptr __objc_selector_hash; /* name -> uid !T:MUTEX */ + +/* Number of selectors stored in each of the above tables */ +objc_EXPORT int __objc_selector_max_index; /* !T:MUTEX */ + +#endif /* __objc_globals_H__ */ diff --git a/gnustep-objc/hash.c b/gnustep-objc/hash.c new file mode 100644 index 00000000..c4e0758d --- /dev/null +++ b/gnustep-objc/hash.c @@ -0,0 +1,130 @@ +/* Hash tables for Objective C internal structures + Copyright (C) 1993, 1996, 1997 Free Software Foundation, Inc. + +This file is part of GNU CC. + +GNU CC is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU CC is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU CC; see the file COPYING. If not, write to +the Free Software Foundation, 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + +/* As a special exception, if you link this library with files + compiled with GCC to produce an executable, this does not cause + the resulting executable to be covered by the GNU General Public License. + This exception does not however invalidate any other reasons why + the executable file might be covered by the GNU General Public License. */ + +#include "assert.h" +#include "hash.h" +#include "runtime.h" /* for DEBUG_PRINTF */ +#include "objc-api.h" + +/* These two macros determine when a hash table is full and + by how much it should be expanded respectively. + + These equations are percentages. */ +#define FULLNESS(cache) ((((cache)->size * 75) / 100) <= (cache)->used) +#define EXPANSION(cache) ((cache)->size * 2) + +cache_ptr hash_new (unsigned int size, char hashType) +{ + cache_ptr cache; + + /* Pass me a value greater than 0 and a power of 2. */ + assert (size); + assert (!(size & (size - 1))); + + /* Allocate the cache structure. calloc insures + its initialization for default values. */ + cache = (cache_ptr)OBJC_CALLOC_UNCOLLECTABLE(sizeof (struct cache)); + assert (cache); + + /* Allocate the array of buckets for the cache. + calloc initializes all of the pointers to NULL. */ + cache->node_table = + (node_ptr *)OBJC_CALLOC_UNCOLLECTABLE(size * sizeof (node_ptr)); + + assert (cache->node_table); + + cache->size = size; + + /* This should work for all processor architectures? */ + cache->mask = (size - 1); + + cache->hashType = hashType; + + return cache; +} + + +void +hash_add (cache_ptr *cachep, const void *key, void *value) +{ + size_t indx = objc_call_hash(*cachep, key); + //hh: size_t indx = (*(*cachep)->hash_func)(*cachep, key); + node_ptr node; + + node = (node_ptr)OBJC_CALLOC_UNCOLLECTABLE(sizeof (struct cache_node)); + assert (node); + + /* Initialize the new node. */ + node->key = key; + node->value = value; + node->next = (*cachep)->node_table[indx]; + + /* Debugging. + Check the list for another key. */ +#if DEBUG_OBJC + { node_ptr node1 = (*cachep)->node_table[indx]; + + while (node1) { + + assert (node1->key != key); + node1 = node1->next; + } + } +#endif + + /* Install the node as the first element on the list. */ + (*cachep)->node_table[indx] = node; + + /* Bump the number of entries in the cache. */ + ++(*cachep)->used; + + /* Check the hash table's fullness. We're going + to expand if it is above the fullness level. */ + if (FULLNESS (*cachep)) { + + /* The hash table has reached its fullness level. Time to + expand it. + + I'm using a slow method here but is built on other + primitive functions thereby increasing its + correctness. */ + node_ptr node1 = NULL; + cache_ptr new = hash_new (EXPANSION (*cachep), (*cachep)->hashType); + + DEBUG_PRINTF ("Expanding cache 0x%08X from %d to %d\n", + (size_t)*cachep, (*cachep)->size, new->size); + + /* Copy the nodes from the first hash table to the new one. */ + while ((node1 = hash_next (*cachep, node1))) + hash_add (&new, node1->key, node1->value); + + /* Trash the old cache. */ + hash_delete (*cachep); + + /* Return a pointer to the new hash table. */ + *cachep = new; + } +} diff --git a/gnustep-objc/hash.h b/gnustep-objc/hash.h new file mode 100644 index 00000000..f13379a4 --- /dev/null +++ b/gnustep-objc/hash.h @@ -0,0 +1,382 @@ +/* Hash tables for Objective C method dispatch. + Copyright (C) 1993, 1995, 1996 Free Software Foundation, Inc. + +This file is part of GNU CC. + +GNU CC is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU CC is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU CC; see the file COPYING. If not, write to +the Free Software Foundation, 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + +/* As a special exception, if you link this library with files + compiled with GCC to produce an executable, this does not cause + the resulting executable to be covered by the GNU General Public License. + This exception does not however invalidate any other reasons why + the executable file might be covered by the GNU General Public License. */ + + +#ifndef __hash_INCLUDE_GNU +#define __hash_INCLUDE_GNU + +#include +#include +#include +#include + +/* + * This data structure is used to hold items + * stored in a hash table. Each node holds + * a key/value pair. + * + * Items in the cache are really of type void *. + */ +typedef struct cache_node +{ + struct cache_node *next; /* Pointer to next entry on the list. + NULL indicates end of list. */ + const void *key; /* Key used to locate the value. Used + to locate value when more than one + key computes the same hash + value. */ + void *value; /* Value stored for the key. */ +} *node_ptr; + +/* + * This data structure is the cache. + * + * It must be passed to all of the hashing routines + * (except for new). + */ +typedef struct cache +{ + /* Variables used to implement the hash itself. */ + node_ptr *node_table; /* Pointer to an array of hash nodes. */ + /* Variables used to track the size of the hash table so to determine + when to resize it. */ + unsigned int size; /* Number of buckets allocated for the hash table + (number of array entries allocated for + "node_table"). Must be a power of two. */ + unsigned int used; /* Current number of entries in the hash table. */ + unsigned int mask; /* Precomputed mask. */ + + /* Variables used to implement indexing through the hash table. */ + + unsigned int last_bucket; /* Tracks which entry in the array where + the last value was returned. */ + + char hashType; // 1 = string-hash, 0 = ptr-hash +} *cache_ptr; + +static __inline__ unsigned int objc_call_hash(cache_ptr cache, const void *key) +{ + if (cache->hashType == 1) { // string hash + register unsigned int ret = 0; + register unsigned int ctr = 0; + + while (*(char*)key) { + ret ^= *(char*)key++ << ctr; + ctr = (ctr + 1) % sizeof (void *); + } + + return (ret & cache->mask); + } + else if (cache->hashType == 0) // ptr hash + return ((size_t)key / sizeof (void *)) & cache->mask; + else + abort(); +} +static __inline__ int objc_call_compare(cache_ptr cache, + const void *k1, const void *k2) +{ + if (cache->hashType == 1) { // string compare + if (k1 == k2) + return 1; + else if (k1 == 0 || k2 == 0) + return 0; + else { + while ((*(char*)k1 == *(char*)k2) && (*(char*)k1 != '\0')) + k1++, k2++; + + return (*(char*)k1 == *(char*)k2) ? 1 : 0; + } + } + else if (cache->hashType == 0) // ptr compare + return !(k1 - k2); + else + abort(); +} + +/* Two important hash tables. */ +objc_EXPORT cache_ptr module_hash_table, class_hash_table; + +#include + +static __inline__ void hash_delete(cache_ptr cache); +static __inline__ void hash_remove(cache_ptr cache, const void *key); +static __inline__ unsigned int hash_ptr(cache_ptr cache, const void *key); +static __inline__ int compare_ptrs(register const void *k1, register const void *k2); +static __inline__ unsigned int hash_string(cache_ptr cache,register const void *key); + +static __inline__ int +compare_strings(register const char *k1,register const char *k2); + +/* Allocate and initialize a hash table. */ + +static __inline__ cache_ptr ptrhash_new(unsigned int size) { + cache_ptr hash_new (unsigned int size, + char hashType); + return hash_new(size, 0); +} +static __inline__ cache_ptr strhash_new(unsigned int size) { + cache_ptr hash_new (unsigned int size, + char hashType); + return hash_new(size, 1); +} + +/* Deallocate all of the hash nodes and the cache itself. */ + +static __inline__ void hash_delete (cache_ptr cache) { + node_ptr node; + node_ptr next_node; + unsigned int i; + + /* Purge all key/value pairs from the table. */ + /* Step through the nodes one by one and remove every node WITHOUT + using hash_next. this makes hash_delete much more efficient. */ + for (i = 0;i < cache->size;i++) { + if ((node = cache->node_table[i])) { + /* an entry in the hash table has been found, now step through the + nodes next in the list and free them. */ + while ((next_node = node->next)) { + hash_remove (cache,node->key); + node = next_node; + } + + hash_remove (cache,node->key); + } + } + + /* Release the array of nodes and the cache itself. */ +#if OBJC_WITH_GC + GC_FREE(cache->node_table); cache->node_table = NULL; + GC_FREE(cache); cache = NULL; +#else + objc_free(cache->node_table); + objc_free(cache); +#endif +} + +/* Add the key/value pair to the hash table. If the + hash table reaches a level of fullness then it will be resized. + + assert if the key is already in the hash. */ + +void hash_add (cache_ptr *cachep, const void *key, void *value); + +/* Remove the key/value pair from the hash table. + assert if the key isn't in the table. */ + +static __inline__ void hash_remove (cache_ptr cache, const void *key) { + size_t indx = objc_call_hash(cache, key); + //size_t indx = (*cache->hash_func)(cache, key); + node_ptr node = cache->node_table[indx]; + + + /* We assume there is an entry in the table. Error if it is not. */ + if (node == NULL) abort(); + + /* Special case. First element is the key/value pair to be removed. */ + //if ((*cache->compare_func)(node->key, key)) { + if (objc_call_compare(cache, node->key, key)) { + cache->node_table[indx] = node->next; +#if OBJC_WITH_GC + GC_FREE(node); node = NULL; +#else + objc_free(node); +#endif + } + else { + /* Otherwise, find the hash entry. */ + node_ptr prev = node; + BOOL removed = NO; + + do { + //if ((*cache->compare_func)(node->key, key)) { + if (objc_call_compare(cache, node->key, key)) { + prev->next = node->next, removed = YES; +#if OBJC_WITH_GC + GC_FREE(node); node = NULL; +#else + objc_free(node); +#endif + } else { + prev = node, node = node->next; + } + } while (!removed && node); + if(removed==0) abort(); + } + + /* Decrement the number of entries in the hash table. */ + --cache->used; +} + +/* Used to index through the hash table. Start with NULL + to get the first entry. + + Successive calls pass the value returned previously. + ** Don't modify the hash during this operation *** + + Cache nodes are returned such that key or value can + be extracted. */ + +static __inline__ node_ptr hash_next (cache_ptr cache, node_ptr node) { + /* If the scan is being started then reset the last node + visitied pointer and bucket index. */ + if (!node) + cache->last_bucket = 0; + + /* If there is a node visited last then check for another + entry in the same bucket; Otherwise step to the next bucket. */ + if (node) { + if (node->next) + /* There is a node which follows the last node + returned. Step to that node and retun it. */ + return node->next; + else + ++cache->last_bucket; + } + + /* If the list isn't exhausted then search the buckets for + other nodes. */ + if (cache->last_bucket < cache->size) { + /* Scan the remainder of the buckets looking for an entry + at the head of the list. Return the first item found. */ + while (cache->last_bucket < cache->size) + if (cache->node_table[cache->last_bucket]) + return cache->node_table[cache->last_bucket]; + else + ++cache->last_bucket; + + /* No further nodes were found in the hash table. */ + return NULL; + } else + return NULL; +} + +/* Used to return a value from a hash table using a given key. */ + +static __inline__ void *hash_value_for_key (cache_ptr cache, const void *key) { + /* Given KEY, return corresponding value for it in CACHE. + Return NULL if the KEY is not recorded. */ + + node_ptr node = cache->node_table[objc_call_hash(cache, key)]; + //node_ptr node = cache->node_table[(*cache->hash_func)(cache, key)]; + void *retval = NULL; + + if (node) + do { + //if ((*cache->compare_func)(node->key, key)) { + if (objc_call_compare(cache, node->key, key)) { + retval = node->value; + break; + } else + node = node->next; + } while (!retval && node); + + return retval; +} + +/* Used to determine if the given key exists in the hash table */ + +static __inline__ BOOL hash_is_key_in_hash (cache_ptr cache, const void *key) { + /* Given KEY, return YES if it exists in the CACHE. + Return NO if it does not */ + + //node_ptr node = cache->node_table[(*cache->hash_func)(cache, key)]; + register node_ptr node = cache->node_table[objc_call_hash(cache, key)]; + + if (node) { + do { + //if ((*cache->compare_func)(node->key, key)) + if (objc_call_compare(cache, node->key, key)) + return YES; + + node = node->next; + } while (node); + } + return NO; +} + +/************************************************ + + Useful hashing functions. + + Declared inline for your pleasure. + +************************************************/ + +/* Calculate a hash code by performing some + manipulation of the key pointer. (Use the lowest bits + except for those likely to be 0 due to alignment.) */ + +static __inline__ unsigned int hash_ptr (cache_ptr cache, const void *key) +{ + return ((size_t)key / sizeof (void *)) & cache->mask; +} + + +/* Calculate a hash code by iterating over a NULL + terminate string. */ +static __inline__ unsigned int +hash_string (cache_ptr cache,register const void *key) +{ + register unsigned int ret = 0; + register unsigned int ctr = 0; + + while (*(char*)key) { + ret ^= *(char*)key++ << ctr; + ctr = (ctr + 1) % sizeof (void *); + } + + return (ret & cache->mask); +} + + +/* Compare two pointers for equality. */ +static __inline__ int +compare_ptrs (register const void *k1, register const void *k2) +{ + return !(k1 - k2); +} + + +/* Compare two strings. */ +static __inline__ int +compare_strings(register const char *k1,register const char *k2) +{ + if (k1 == k2) + return 1; + else if (k1 == 0 || k2 == 0) + return 0; + else { + while ((*k1 == *k2) && (*k1 != '\0')) { + k1++; + k2++; + } + return (*k1 == *k2) ? 1 : 0; + + //return !strcmp (k1, k2); + } +} + +#endif /* not __hash_INCLUDE_GNU */ diff --git a/gnustep-objc/init.c b/gnustep-objc/init.c new file mode 100644 index 00000000..60e28fc4 --- /dev/null +++ b/gnustep-objc/init.c @@ -0,0 +1,852 @@ +/* GNU Objective C Runtime initialization + Copyright (C) 1993, 1995, 1996, 1997 Free Software Foundation, Inc. + Contributed by Kresten Krab Thorup + +load support contributed by Ovidiu Predescu + +This file is part of GNU CC. + +GNU CC is free software; you can redistribute it and/or modify it under the +terms of the GNU General Public License as published by the Free Software +Foundation; either version 2, or (at your option) any later version. + +GNU CC is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +FOR A PARTICULAR PURPOSE. See the GNU General Public License for more +details. + +You should have received a copy of the GNU General Public License along with +GNU CC; see the file COPYING. If not, write to the Free Software +Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +/* As a special exception, if you link this library with files compiled with + GCC to produce an executable, this does not cause the resulting executable + to be covered by the GNU General Public License. This exception does not + however invalidate any other reasons why the executable file might be + covered by the GNU General Public License. */ + +#include "runtime.h" +#include "objc-api.h" + +/* The version number of this runtime. This must match the number + defined in gcc (objc-act.c) */ +#define OBJC_VERSION 8 /* HH version 8 */ +#define PROTOCOL_VERSION 2 + +/* Check compiler vs runtime version */ +static void init_check_module_version (Module_t); + +/* Assign isa links to protos */ +static void __objc_init_protocols (struct objc_protocol_list* protos); + +/* Add protocol to class */ +static void __objc_class_add_protocols (Class, struct objc_protocol_list*); + +extern SEL +__sel_register_typed_name (const char *name, const char *types, + struct objc_selector *orig, BOOL is_const); + +/* Sends +load to all classes and categories in certain situations. */ +static void objc_send_load (void); + +/* Inserts all the classes defined in module in a tree of classes that + resembles the class hierarchy. This tree is traversed in preorder and the + classes in its nodes receive the +load message if these methods were not + executed before. The algorithm ensures that when the +load method of a class + is executed all the superclasses have been already received the +load + message. */ +static void __objc_create_classes_tree (Module_t module); + +static void __objc_call_callback (Module_t module); + +/* A special version that works only before the classes are completely + installed in the runtime. */ +static BOOL class_is_subclass_of_class (Class class, Class superclass); + +typedef struct objc_class_tree { + Class class; + struct objc_list *subclasses; /* `head' is pointer to an objc_class_tree */ +} objc_class_tree; + +/* Creates a tree of classes whose topmost class is directly inherited from + `upper' and the bottom class in this tree is `bottom_class'. The classes + in this tree are super classes of `bottom_class'. `subclasses' member + of each tree node point to the next subclass tree node. */ +static objc_class_tree * +create_tree_of_subclasses_inherited_from (Class bottom_class, Class upper) +{ + Class superclass = bottom_class->super_class ? + objc_lookup_class ((char*)bottom_class->super_class) + : Nil; + + objc_class_tree *tree, *prev; + + DEBUG_PRINTF ("create_tree_of_subclasses_inherited_from:"); + DEBUG_PRINTF ("bottom_class = %s, upper = %s\n", + (bottom_class ? bottom_class->name : ""), + (upper ? upper->name : "")); + + tree = prev = objc_calloc (1, sizeof (objc_class_tree)); + prev->class = bottom_class; + + while (superclass != upper) + { + tree = objc_calloc (1, sizeof (objc_class_tree)); + tree->class = superclass; + tree->subclasses = list_cons (prev, tree->subclasses); + superclass = (superclass->super_class ? + objc_lookup_class ((char*)superclass->super_class) + : Nil); + prev = tree; + } + + return tree; +} + +/* Insert the `class' into the proper place in the `tree' class hierarchy. This + function returns a new tree if the class has been successfully inserted into + the tree or NULL if the class is not part of the classes hierarchy described + by `tree'. This function is private to objc_tree_insert_class(), you should + not call it directly. */ +static objc_class_tree * +__objc_tree_insert_class (objc_class_tree *tree, Class class) +{ + DEBUG_PRINTF ("__objc_tree_insert_class: tree = 0x%08X, class = %s\n", + (unsigned int)tree, class->name ? class->name : ""); + + if (tree == NULL) + return create_tree_of_subclasses_inherited_from (class, NULL); + else if (class == tree->class) + { + /* `class' has been already inserted */ + DEBUG_PRINTF ("1. class %s was previously inserted\n", + class->name ? class->name : ""); + return tree; + } + else if ((class->super_class ? + objc_lookup_class ((char*)class->super_class) + : Nil) + == tree->class) + { + /* If class is a direct subclass of tree->class then add class to the + list of subclasses. First check to see if it wasn't already + inserted. */ + struct objc_list *list = tree->subclasses; + objc_class_tree *node; + + while (list) + { + /* Class has been already inserted; do nothing just return + the tree. */ + if (((objc_class_tree*)list->head)->class == class) + { + DEBUG_PRINTF ("2. class %s was previously inserted\n", + class->name ? class->name : ""); + return tree; + } + list = list->tail; + } + + /* Create a new node class and insert it into the list of subclasses */ + node = objc_calloc (1, sizeof (objc_class_tree)); + node->class = class; + tree->subclasses = list_cons (node, tree->subclasses); + DEBUG_PRINTF ("3. class %s inserted\n", + class->name ? class->name : ""); + return tree; + } + else + { + /* The class is not a direct subclass of tree->class. Search for class's + superclasses in the list of subclasses. */ + struct objc_list *subclasses = tree->subclasses; + + /* Precondition: the class must be a subclass of tree->class; otherwise + return NULL to indicate our caller that it must take the next tree. */ + if (!class_is_subclass_of_class (class, tree->class)) + return NULL; + + for (; subclasses != NULL; subclasses = subclasses->tail) + { + Class aClass = ((objc_class_tree*)(subclasses->head))->class; + + if (class_is_subclass_of_class (class, aClass)) + { + /* If we found one of class's superclasses we insert the class + into its subtree and return the original tree since nothing + has been changed. */ + subclasses->head + = __objc_tree_insert_class (subclasses->head, class); + DEBUG_PRINTF ("4. class %s inserted\n", + class->name ? class->name : ""); + return tree; + } + } + + /* We haven't found a subclass of `class' in the `subclasses' list. + Create a new tree of classes whose topmost class is a direct subclass + of tree->class. */ + { + objc_class_tree *new_tree + = create_tree_of_subclasses_inherited_from (class, tree->class); + tree->subclasses = list_cons (new_tree, tree->subclasses); + DEBUG_PRINTF ("5. class %s inserted\n", + class->name ? class->name : ""); + return tree; + } + } +} + +/* This function inserts `class' in the right tree hierarchy classes. */ +static void +objc_tree_insert_class (Class class) +{ + struct objc_list *list_node; + objc_class_tree *tree; + + list_node = __objc_class_tree_list; + while (list_node) + { + tree = __objc_tree_insert_class (list_node->head, class); + if (tree) + { + list_node->head = tree; + break; + } + else + list_node = list_node->tail; + } + + /* If the list was finished but the class hasn't been inserted, insert it + here. */ + if (!list_node) + { + __objc_class_tree_list = list_cons (NULL, __objc_class_tree_list); + __objc_class_tree_list->head = __objc_tree_insert_class (NULL, class); + } +} + +/* Traverse tree in preorder. Used to send +load. */ +static void +objc_preorder_traverse (objc_class_tree *tree, + int level, + void (*function)(objc_class_tree*, int)) +{ + struct objc_list *node; + + (*function) (tree, level); + for (node = tree->subclasses; node; node = node->tail) + objc_preorder_traverse (node->head, level + 1, function); +} + +/* Traverse tree in postorder. Used to destroy a tree. */ +static void +objc_postorder_traverse (objc_class_tree *tree, + int level, + void (*function)(objc_class_tree*, int)) +{ + struct objc_list *node; + + for (node = tree->subclasses; node; node = node->tail) + objc_postorder_traverse (node->head, level + 1, function); + (*function) (tree, level); +} + +/* Used to print a tree class hierarchy. */ +#if DEBUG_OBJC +static void __objc_tree_print (objc_class_tree *tree, int level) { + int i; + + for (i = 0; i < level; i++) + printf (" "); + printf ("%s\n", + tree + ? (tree->class + ? (tree->class->name ? tree->class->name : "") + : "") + : ""); +} +#endif + +/* Walks on a linked list of methods in the reverse order and executes all + the methods corresponding to `op' selector. Walking in the reverse order + assures the +load of class is executed first and then +load of categories + because of the way in which categories are added to the class methods. */ +static void +__objc_send_message_in_list (MethodList_t method_list, Class class, SEL op) +{ + int i; + + if (!method_list) + return; + + /* First execute the `op' message in the following method lists */ + __objc_send_message_in_list (method_list->method_next, class, op); + + /* Search the method list. */ + for (i = 0; i < method_list->method_count; i++) { + Method_t mth = &method_list->method_list[i]; + + if (mth->method_name && sel_eq (mth->method_name, op) + && !hash_is_key_in_hash (__objc_load_methods, mth->method_name)) + { + /* The method was found and wasn't previously executed. */ + (*mth->method_imp) ((id)class, mth->method_name); + + /* Add this method into the +load hash table */ + hash_add (&__objc_load_methods, mth->method_name, mth->method_imp); + + DEBUG_PRINTF ("sending +load in class: %s\n", + class->name ? class->name : ""); + + break; + } + } +} + +static void +__objc_send_load (objc_class_tree *tree, int level) +{ + static SEL load_sel = 0; + Class class = tree->class; + MethodList_t method_list = class->class_pointer->methods; + + if (!load_sel) + load_sel = sel_register_name ("load"); + + __objc_send_message_in_list (method_list, class, load_sel); +} + +static void +__objc_destroy_class_tree_node (objc_class_tree *tree, int level) +{ + objc_free (tree); +} + +/* This is used to check if the relationship between two classes before the + runtime completely installs the classes. */ +static BOOL +class_is_subclass_of_class (Class class, Class superclass) +{ + for (; class != Nil;) + { + if (class == superclass) + return YES; + class = (class->super_class ? + objc_lookup_class ((char*)class->super_class) + : Nil); + } + + return NO; +} + +/* This list contains all the classes in the runtime system for whom their + superclasses are not yet know to the runtime. */ +static struct objc_list* unresolved_classes = 0; + +/* Static function used to reference the Object and NXConstantString classes. + */ +static void +__objc_force_linking (void) +{ + extern void __objc_linking (void); + __objc_linking (); + + /* Call the function to avoid compiler warning */ + __objc_force_linking (); +} + +/* Run through the statics list, removing modules as soon as all its statics + have been initialized. */ +static void +objc_init_statics (void) +{ + struct objc_list **cell = &__objc_uninitialized_statics; + struct objc_static_instances **statics_in_module; + + RUNTIME_LOCK; + + while (*cell) + { + int module_initialized = 1; + + for (statics_in_module = (*cell)->head; + *statics_in_module; statics_in_module++) + { + struct objc_static_instances *statics = *statics_in_module; + Class class = objc_lookup_class (statics->class_name); + + if (!class) + module_initialized = 0; + /* Actually, the static's class_pointer will be NULL when we + haven't been here before. However, the comparison is to be + reminded of taking into account class posing and to think about + possible semantics... */ + else if (class != statics->instances[0]->class_pointer) + { + id *inst; + + for (inst = &statics->instances[0]; *inst; inst++) + { + (*inst)->class_pointer = class; + + /* ??? Make sure the object will not be freed. With + refcounting, invoke `-retain'. Without refcounting, do + nothing and hope that `-free' will never be invoked. */ + + /* ??? Send the object an `-initStatic' or something to + that effect now or later on? What are the semantics of + statically allocated instances, besides the trivial + NXConstantString, anyway? */ + } + } + } + if (module_initialized) + { + /* Remove this module from the uninitialized list. */ + struct objc_list *this = *cell; + *cell = this->tail; + objc_free(this); + } + else + cell = &(*cell)->tail; + } + + RUNTIME_UNLOCK; +} /* objc_init_statics */ + +/* This function is called by constructor functions generated for each + module compiled. (_GLOBAL_$I$...) The purpose of this function is to + gather the module pointers so that they may be processed by the + initialization routines as soon as possible */ + +int objc_moduleCount = 0; +int objc_classCount = 0; +int objc_categoryCount = 0; + +objc_DECLARE void __objc_exec_module(Module_t module) +{ + /* Have we processed any constructors previously? This flag is used to + indicate that some global data structures need to be built. */ + static BOOL previous_constructors = 0; + + static struct objc_list* unclaimed_categories = 0; + + /* The symbol table (defined in objc-api.h) generated by gcc */ + Symtab_t symtab = module->symtab; + + /* The statics in this module */ + struct objc_static_instances **statics + = symtab->defs[symtab->cls_def_cnt + symtab->cat_def_cnt]; + + /* Entry used to traverse hash lists */ + struct objc_list** cell; + + /* The table of selector references for this module */ + SEL selectors = symtab->refs; + + /* dummy counter */ + int i; + + DEBUG_PRINTF ("received module: %s\n", + module->name ? module->name : ""); + + /* check gcc version */ + init_check_module_version(module); + + /* On the first call of this routine, initialize some data structures. */ + if (!previous_constructors) + { + /* Initialize thread-safe system */ + __objc_init_thread_system(); + __objc_runtime_threads_alive = 1; + __objc_runtime_mutex = objc_mutex_allocate(); + if (__objc_runtime_mutex == NULL) + fprintf(stderr, "Could not allocate Objective-C runtime mutex.\n"); + + __objc_init_selector_tables(); + __objc_init_class_tables(); + __objc_init_dispatch_tables(); + __objc_class_tree_list = list_cons (NULL, __objc_class_tree_list); + __objc_load_methods = ptrhash_new(128); + previous_constructors = 1; + } + + RUNTIME_LOCK; + + /* Take a look whether module is already loaded. If a module is contained + in a shared library it can happen that the module constructor is executed + multiple times. Multiple execution of modules won't work since the runtime + replaces static information in the module (like selector names) with + dynamic one (eg dynamic selector ids ). */ + { + register struct objc_list *l; + + for (l = __objc_module_list; l; l = l->tail) { + if (l->head == module) + break; + } + + if (l) { + /* l is defined if module is already loaded */ + fprintf(stderr, "module %s is already loaded !\n", + module->name ? module->name : ""); + fflush(stderr); + RUNTIME_UNLOCK; + return; + } + } + __objc_module_list = list_cons(module, __objc_module_list); + objc_moduleCount++; + + /* Replace referenced selectors from names to SEL's. */ + if (selectors) { + for (i = 0; selectors[i].sel_id; ++i) { + register const char *name, *type; + + name = (char*)selectors[i].sel_id; + type = (char*)selectors[i].sel_types; + + /* Constructors are constant static data so we can safely store + pointers to them in the runtime structures. is_const == YES */ + __sel_register_typed_name(name, type, + (struct objc_selector*)&(selectors[i]), + YES); + } + } + + /* Parse the classes in the load module and gather selector information. */ + + DEBUG_PRINTF ("gathering selectors from module: %s (#-of modules=%i)\n", + module->name ? module->name : "", objc_moduleCount); + + for (i = 0; i < symtab->cls_def_cnt; ++i) { + Class class = (Class) symtab->defs[i]; + const char *superclass = (char *)class->super_class; + + /* Make sure we have what we think. */ + assert (CLS_ISCLASS(class)); + assert (CLS_ISMETA(class->class_pointer)); + DEBUG_PRINTF ("phase 1, processing class: %s (super=%s)\n", + class->name ? class->name : "", + superclass ? superclass : ""); + + /* Initialize the subclass list to be NULL. + In some cases it isn't and this crashes the program. */ + class->subclass_list = NULL; + + /* Store the class in the class table and assign class numbers. */ + __objc_add_class_to_hash (class); + objc_classCount++; + + /* Register all of the selectors in the class and meta class. */ + __objc_register_selectors_from_class (class); + __objc_register_selectors_from_class ((Class) class->class_pointer); + + /* Install the fake dispatch tables */ + class->dtable = NULL; + class->class_pointer->dtable = NULL; + + /* Register the instance methods as class methods, this is + only done for root classes. */ + __objc_register_instance_methods_to_class(class); + + if (class->protocols) + __objc_init_protocols (class->protocols); + + /* Check to see if the superclass is known in this point. If it's not + add the class to the unresolved_classes list. */ + if ((superclass != NULL) && !objc_lookup_class (superclass)) { + assert(superclass != NULL); + + DEBUG_PRINTF("inserting unresolved class %s (super=%s) ..\n", + class->name ? class->name : "", + superclass ? superclass : ""); + + unresolved_classes = list_cons (class, unresolved_classes); + } + } + + /* Process category information from the module. */ + for (i = 0; i < symtab->cat_def_cnt; ++i) { + Category_t category = symtab->defs[i + symtab->cls_def_cnt]; + Class class = objc_lookup_class (category->class_name); + + objc_categoryCount++; + + /* If the class for the category exists then append its methods. */ + if (class) { + DEBUG_PRINTF ("processing categories from (module %s, object %s)\n", + module->name ? module->name : "", + class->name ? class->name : ""); + + /* Do instance methods. */ + if (category->instance_methods) + class_add_method_list (class, category->instance_methods); + + /* Do class methods. */ + if (category->class_methods) + class_add_method_list ((Class) class->class_pointer, + category->class_methods); + + if (category->protocols) { + __objc_init_protocols (category->protocols); + __objc_class_add_protocols (class, category->protocols); + } + + /* Register the instance methods as class methods, this is + only done for root classes. */ + __objc_register_instance_methods_to_class(class); + } + else { + /* The object to which the category methods belong can't be found. + Save the information. */ + unclaimed_categories = list_cons(category, unclaimed_categories); + } + } + + if (statics) { + __objc_uninitialized_statics = + list_cons (statics, __objc_uninitialized_statics); + } + if (__objc_uninitialized_statics) + objc_init_statics (); + + /* Scan the unclaimed category hash. Attempt to attach any unclaimed + categories to objects. */ + cell = &unclaimed_categories; + while (*cell) { + Category_t category; + Class class; + + category = (*cell)->head; + class = objc_lookup_class (category->class_name); + + if (class) { + DEBUG_PRINTF ("attaching stored categories to object: %s\n", + class->name ? class->name : ""); + + list_remove_head (cell); + + if (category->instance_methods) + class_add_method_list (class, category->instance_methods); + + if (category->class_methods) + class_add_method_list ((Class) class->class_pointer, + category->class_methods); + + if (category->protocols) { + __objc_init_protocols (category->protocols); + __objc_class_add_protocols (class, category->protocols); + } + + /* Register the instance methods as class methods, this is + only done for root classes. */ + __objc_register_instance_methods_to_class(class); + } + if (*cell) cell = &(*cell)->tail; + } + + if (__objc_unclaimed_proto_list && objc_lookup_class ("Protocol")) { + list_mapcar (__objc_unclaimed_proto_list, + (void(*)(void*))__objc_init_protocols); + list_free (__objc_unclaimed_proto_list); + __objc_unclaimed_proto_list = 0; + } + + objc_send_load (); + + RUNTIME_UNLOCK; +} + +objc_DECLARE void __objc_exec_class (Module_t module) +{ + __objc_exec_module(module); +} + +static void objc_send_load (void) +{ + if (!__objc_module_list) + return; + + /* Try to find out if all the classes loaded so far also have their + superclasses known to the runtime. We suppose that the objects that are + allocated in the +load method are in general of a class declared in the + same module. */ + if (unresolved_classes) { + Class class = unresolved_classes->head; + + assert(class != Nil); + + DEBUG_PRINTF("check unresolved class %s, super is %s\n", + class->name ? class->name : "", + class->super_class ? (char*)class->super_class : ""); + + while (objc_lookup_class ((char*)class->super_class)) { + list_remove_head (&unresolved_classes); + + if (unresolved_classes) + class = unresolved_classes->head; + else + break; + } + + /* + * If we still have classes for whom we don't have yet their super + * classes known to the runtime we don't send the +load messages. + */ + if (unresolved_classes) + return; + } + + /* Special check to allow creating and sending messages to constant strings + in +load methods. If these classes are not yet known, even if all the + other classes are known, delay sending of +load. */ + if (!objc_lookup_class ("NXConstantString") || + !objc_lookup_class ("Object")) + return; + + /* Iterate over all modules in the __objc_module_list and call on them the + __objc_create_classes_tree function. This function creates a tree of + classes that resembles the class hierarchy. */ + list_mapcar (__objc_module_list, (void(*)(void*))__objc_create_classes_tree); + + while (__objc_class_tree_list) { +#if DEBUG_OBJC + objc_preorder_traverse (__objc_class_tree_list->head, + 0, __objc_tree_print); +#endif + objc_preorder_traverse (__objc_class_tree_list->head, + 0, __objc_send_load); + objc_postorder_traverse (__objc_class_tree_list->head, + 0, __objc_destroy_class_tree_node); + list_remove_head (&__objc_class_tree_list); + } + + list_mapcar (__objc_module_list, (void(*)(void*))__objc_call_callback); + + list_free (__objc_module_list); + __objc_module_list = NULL; +} + +static void __objc_create_classes_tree (Module_t module) +{ + /* The runtime mutex is locked in this point */ + + Symtab_t symtab = module->symtab; + int i; + + /* Iterate thru classes defined in this module and insert them in the classes + tree hierarchy. */ + for (i = 0; i < symtab->cls_def_cnt; i++) { + Class class = (Class) symtab->defs[i]; + + objc_tree_insert_class (class); + } +} + +static void __objc_call_callback (Module_t module) +{ + /* The runtime mutex is locked in this point */ + Symtab_t symtab = module->symtab; + int i; + + /* Iterate thru classes defined in this module and call the callback for + each one. */ + for (i = 0; i < symtab->cls_def_cnt; i++) { + Class class = (Class) symtab->defs[i]; + + /* Call the _objc_load_callback for this class. */ + if (_objc_load_callback) + _objc_load_callback(class, 0); + } + + /* Call the _objc_load_callback for categories. Don't register the instance + methods as class methods for categories to root classes since they were + already added in the class. */ + for (i = 0; i < symtab->cat_def_cnt; i++) { + register Category_t category; + register Class class; + + category = symtab->defs[i + symtab->cls_def_cnt]; + class = objc_lookup_class (category->class_name); + + if (_objc_load_callback) + _objc_load_callback(class, category); + } +} + +/* Sanity check the version of gcc used to compile `module'*/ +static void init_check_module_version(Module_t module) +{ + if ((module->version != OBJC_VERSION) || (module->size != sizeof (Module))) { + int code; + + if(module->version > OBJC_VERSION) + code = OBJC_ERR_OBJC_VERSION; + else if (module->version < OBJC_VERSION) + code = OBJC_ERR_GCC_VERSION; + else + code = OBJC_ERR_MODULE_SIZE; + + objc_error(nil, code, "Module %s version %d doesn't match runtime %d\n", + module->name, (int)module->version, OBJC_VERSION); + } +} + +static void +__objc_init_protocols (struct objc_protocol_list* protos) +{ + int i; + static Class proto_class = 0; + + if (! protos) + return; + + RUNTIME_LOCK; + + if (proto_class == Nil) + proto_class = objc_lookup_class("Protocol"); + + if (proto_class == Nil) { + __objc_unclaimed_proto_list = + list_cons (protos, __objc_unclaimed_proto_list); + RUNTIME_UNLOCK; + return; + } + +#if 0 + assert (protos->next == 0); /* only single ones allowed */ +#endif + + for(i = 0; i < protos->count; i++) { + struct objc_protocol* aProto = protos->list[i]; + + if (((size_t)aProto->class_pointer) == PROTOCOL_VERSION) { + /* assign class pointer */ + aProto->class_pointer = proto_class; + + /* init super protocols */ + __objc_init_protocols (aProto->protocol_list); + } + else if (protos->list[i]->class_pointer != proto_class) { + objc_error(nil, OBJC_ERR_PROTOCOL_VERSION, + "Version %d doesn't match runtime protocol version %d\n", + (int)((char*)protos->list[i]->class_pointer-(char*)0), + PROTOCOL_VERSION); + } + } + + RUNTIME_UNLOCK; +} + +static void __objc_class_add_protocols (Class class, + struct objc_protocol_list* protos) +{ + /* Well... */ + if (protos == NULL) + return; + + /* Add it... */ + protos->next = class->protocols; + class->protocols = protos; +} diff --git a/gnustep-objc/libobjc-lf2.spec b/gnustep-objc/libobjc-lf2.spec new file mode 100755 index 00000000..b5ac7a2a --- /dev/null +++ b/gnustep-objc/libobjc-lf2.spec @@ -0,0 +1,123 @@ +Summary: libFoundation fork of the Objective-C runtime library. +Name: libobjc-lf2 +Version: %{libf_objc_version} +Release: %{libf_objc_release}.%{libf_objc_buildcount}%{dist_suffix} +Vendor: http://www.gnustep.org +Packager: Frank Reppin +License: GPL +URL: http://www.opengroupware.org +Group: Development/Libraries +AutoReqProv: off +Source: %{libf_objc_source} +Prefix: %{libf_objc_prefix} +BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-root +BuildPreReq: ogo-gnustep_make + +%description +Library needed to run Objective-C applications which use libFoundation. + +%package devel +Summary: Header files for the libFoundation fork of the Objective-C library +Group: Development/Libraries +Requires: libobjc-lf2 ogo-gnustep_make +AutoReqProv: off + +%description devel +This package contains the header files to build Objective-C applications +that use libFoundation. + +%prep +rm -fr ${RPM_BUILD_ROOT} +%setup -q -n libobjc-lf2 + +# ****************************** build ******************************** +%build +source %{prefix}/OGo-GNUstep/Library/Makefiles/GNUstep.sh +make %{libf_objc_makeflags} all + +# ****************************** install ****************************** +%install +source %{prefix}/OGo-GNUstep/Library/Makefiles/GNUstep.sh +make %{libf_objc_makeflags} GNUSTEP_INSTALLATION_DIR=${RPM_BUILD_ROOT}%{prefix}/OGo-GNUstep install + +mkdir -p ${RPM_BUILD_ROOT}%{prefix}/lib +mv ${RPM_BUILD_ROOT}%{prefix}/OGo-GNUstep/Library/Libraries/libobjc*.so.lf2* \ + ${RPM_BUILD_ROOT}%{prefix}/lib/ + +if [ -h "${RPM_BUILD_ROOT}%{prefix}/OGo-GNUstep/Library/Libraries/libobjc_d.so" ]; then + rm -f "${RPM_BUILD_ROOT}%{prefix}/OGo-GNUstep/Library/Libraries/libobjc_d.so" +fi + +if [ -h "${RPM_BUILD_ROOT}%{prefix}/OGo-GNUstep/Library/Libraries/libobjc.so" ]; then + rm -f "${RPM_BUILD_ROOT}%{prefix}/OGo-GNUstep/Library/Libraries/libobjc.so" +fi + +# ****************************** post ********************************* +%post +if [ $1 = 1 ]; then + if [ -e %{prefix}/lib/libobjc_d.so.lf2 ]; then + mkdir -p %{prefix}/OGo-GNUstep/Library/Libraries + cd %{prefix}/OGo-GNUstep/Library/Libraries + ln -s %{prefix}/lib/libobjc_d.so.lf2 + ln -s %{prefix}/lib/libobjc_d.so.lf2 \ + %{prefix}/OGo-GNUstep/Library/Libraries/libobjc_d.so + fi + if [ -e %{prefix}/lib/libobjc.so.lf2 ]; then + mkdir -p %{prefix}/OGo-GNUstep/Library/Libraries + cd %{prefix}/OGo-GNUstep/Library/Libraries + ln -s %{prefix}/lib/libobjc.so.lf2 + ln -s %{prefix}/lib/libobjc.so.lf2 \ + %{prefix}/OGo-GNUstep/Library/Libraries/libobjc.so + fi + if [ -d %{_sysconfdir}/ld.so.conf.d ]; then + echo "%{prefix}/lib" > %{_sysconfdir}/ld.so.conf.d/libobjc-lf2.conf + elif [ ! "`grep '%{prefix}/lib' %{_sysconfdir}/ld.so.conf`" ]; then + echo "%{prefix}/lib" >> %{_sysconfdir}/ld.so.conf + fi + /sbin/ldconfig +fi + +# ****************************** postun ********************************* +%postun +if [ $1 = 0 ]; then + if [ -h %{prefix}/OGo-GNUstep/Library/Libraries/libobjc_d.so.lf2 ]; then + rm -f %{prefix}/OGo-GNUstep/Library/Libraries/libobjc_d.so.lf2 + fi + if [ -h %{prefix}/OGo-GNUstep/Library/Libraries/libobjc_d.so ]; then + rm -f %{prefix}/OGo-GNUstep/Library/Libraries/libobjc_d.so + fi + if [ -h %{prefix}/OGo-GNUstep/Library/Libraries/libobjc.so.lf2 ]; then + rm -f %{prefix}/OGo-GNUstep/Library/Libraries/libobjc.so.lf2 + fi + if [ -h %{prefix}/OGo-GNUstep/Library/Libraries/libobjc.so ]; then + rm -f %{prefix}/OGo-GNUstep/Library/Libraries/libobjc.so + fi + if [ -e %{_sysconfdir}/ld.so.conf.d/libobjc-lf2.conf ]; then + rm -f %{_sysconfdir}/ld.so.conf.d/libobjc-lf2.conf + fi + /sbin/ldconfig +fi + +# ****************************** clean ******************************** +%clean +rm -fr ${RPM_BUILD_ROOT} + +# ****************************** files ******************************** +%files +%defattr(-,root,root,-) +%{prefix}/lib/libobjc*.so.lf2* +%files devel +%defattr(-,root,root,-) +%{prefix}/OGo-GNUstep/Library/Headers/objc + +# ********************************* changelog ************************* +%changelog +* Thu Apr 14 2005 Frank Reppin +- fix linking issue (make sure things are linked against the lf2 libobjc) +* Tue Mar 22 2005 Frank Reppin +- remove leftover symlink pointing to nowhere from buildroot + during install (after mv) +* Mon Jan 17 2005 Frank Reppin +- mkdir "%{prefix}/OGo-GNUstep/Library/Libraries" prior symlinking, +* Wed Sep 09 2004 Frank Reppin +- initial build diff --git a/gnustep-objc/libobjc.def b/gnustep-objc/libobjc.def new file mode 100644 index 00000000..ceb7f0bb --- /dev/null +++ b/gnustep-objc/libobjc.def @@ -0,0 +1,154 @@ +; GNU Objective C Runtime DLL Export Definitions +; Copyright (C) 1997 Free Software Foundation, Inc. +; Contributed by Scott Christley +; +; This file is part of GNU CC. +; +; GNU CC is free software; you can redistribute it and/or modify it under the +; terms of the GNU General Public License as published by the Free Software +; Foundation; either version 2, or (at your option) any later version. +; +; GNU CC is distributed in the hope that it will be useful, but WITHOUT ANY +; WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +; FOR A PARTICULAR PURPOSE. See the GNU General Public License for more +; details. +; +; You should have received a copy of the GNU General Public License along with +; GNU CC; see the file COPYING. If not, write to the Free Software +; Foundation, 59 Temple Place - Suite 330, +; Boston, MA 02111-1307, USA. + +LIBRARY libobjc +EXPORTS + search_for_method_in_list + objc_verror + _objc_load_callback + __objc_init_thread_system + objc_mutex_allocate + objc_mutex_deallocate + objc_mutex_lock + objc_mutex_trylock + objc_mutex_unlock + objc_thread_detach + objc_thread_exit + objc_thread_get_data + objc_thread_get_priority + objc_thread_id + objc_thread_set_data + objc_thread_set_priority + objc_thread_yield + __objc_class_name_Object + __objc_class_name_Protocol + ;__objc_class_name_NXConstantString + objc_error + __objc_object_alloc + __objc_object_copy + __objc_object_dispose + class_create_instance + object_copy + object_dispose + __objc_init_selector_tables + __objc_register_selectors_from_class + __sel_register_typed_name + sel_get_any_typed_uid + sel_get_any_uid + sel_get_name + sel_get_type + sel_get_typed_uid + sel_get_uid + sel_is_mapped + sel_register_name + sel_register_typed_name + sel_types_match + method_get_first_argument + method_get_next_argument + method_get_nth_argument + method_get_number_of_arguments + method_get_sizeof_arguments + objc_aligned_size + objc_alignof_type + objc_get_type_qualifiers + objc_promoted_size + objc_sizeof_type + objc_skip_argspec + objc_skip_offset + objc_skip_type_qualifiers + objc_skip_typespec + __objc_read_nbyte_uint + __objc_read_nbyte_ulong + __objc_write_class + __objc_write_object + __objc_write_selector + objc_close_typed_stream + objc_end_of_typed_stream + objc_flush_typed_stream + objc_get_stream_class_version + objc_open_typed_stream + objc_open_typed_stream_for_file + objc_read_array + objc_read_char + objc_read_int + objc_read_long + objc_read_object + objc_read_selector + objc_read_short + objc_read_string + objc_read_type + objc_read_types + objc_read_unsigned_char + objc_read_unsigned_int + objc_read_unsigned_long + objc_read_unsigned_short + objc_write_array + objc_write_char + objc_write_int + objc_write_long + objc_write_object + objc_write_object_reference + objc_write_root_object + objc_write_selector + objc_write_short + objc_write_string + objc_write_string_atomic + objc_write_type + objc_write_types + objc_write_unsigned_char + objc_write_unsigned_int + objc_write_unsigned_long + objc_write_unsigned_short + __objc_exec_class + __objc_init_dispatch_tables + __objc_print_dtable_stats + __objc_responds_to + __objc_update_dispatch_table_for_class + class_add_method_list + class_get_class_method + class_get_instance_method + get_imp + nil_method + objc_msg_lookup + objc_msg_lookup_super + objc_msg_sendv + __objc_add_class_to_hash + __objc_init_class_tables + __objc_resolve_class_links + class_pose_as + objc_get_class + objc_get_meta_class + objc_lookup_class + objc_next_class + sarray_at_put_safe + sarray_free + sarray_lazy_copy + sarray_new + sarray_realloc + sarray_remove_garbage + hash_add + hash_new + objc_set_error_handler + _objc_lookup_class + objc_condition_allocate + objc_condition_deallocate + objc_condition_wait + objc_condition_broadcast + __objc_uninstalled_dtable diff --git a/gnustep-objc/libobjc_entry.c b/gnustep-objc/libobjc_entry.c new file mode 100644 index 00000000..62f17964 --- /dev/null +++ b/gnustep-objc/libobjc_entry.c @@ -0,0 +1,59 @@ +/* GNU Objective C Runtime DLL Entry + Copyright (C) 1997 Free Software Foundation, Inc. + Contributed by Scott Christley + +This file is part of GNU CC. + +GNU CC is free software; you can redistribute it and/or modify it +under the terms of the GNU General Public License as published by the +Free Software Foundation; either version 2, or (at your option) any +later version. + +GNU CC is distributed in the hope that it will be useful, but WITHOUT +ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License +along with GNU CC; see the file COPYING. If not, write to the Free +Software Foundation, 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + +/* As a special exception, if you link this library with files compiled with + GCC to produce an executable, this does not cause the resulting executable + to be covered by the GNU General Public License. This exception does not + however invalidate any other reasons why the executable file might be + covered by the GNU General Public License. */ + +#if defined(WIN32) + +#include + +/* + DLL entry function for Objective-C Runtime library + This function gets called everytime a process/thread attaches to DLL + */ +WINBOOL WINAPI DllMain(HANDLE hInst, ULONG ul_reason_for_call, + LPVOID lpReserved) +{ + switch(ul_reason_for_call) + { + case DLL_PROCESS_ATTACH: + break; + case DLL_PROCESS_DETACH: + break; + case DLL_THREAD_ATTACH: + break; + case DLL_THREAD_DETACH: + break; + } + return TRUE; +} + +/* + This section terminates the list of imports under GCC. If you do not + include this then you will have problems when linking with DLLs. + */ +asm (".section .idata$3\n" ".long 0,0,0,0,0,0,0,0"); + +#endif diff --git a/gnustep-objc/linking.m b/gnustep-objc/linking.m new file mode 100644 index 00000000..d80859ef --- /dev/null +++ b/gnustep-objc/linking.m @@ -0,0 +1,40 @@ +/* Force linking of classes required by Objective C runtime. + Copyright (C) 1997 Free Software Foundation, Inc. + Contributed by Ovidiu Predescu (ovidiu@net-community.com). + +This file is part of GNU CC. + +GNU CC is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU CC is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU CC; see the file COPYING. If not, write to +the Free Software Foundation, 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + +/* As a special exception, if you link this library with files compiled with + GCC to produce an executable, this does not cause the resulting executable + to be covered by the GNU General Public License. This exception does not + however invalidate any other reasons why the executable file might be + covered by the GNU General Public License. */ + +#include +//#include + +/* Generate references to Object and NXConstanstString classes since they are + needed by the runtime system to run correctly. */ + + +void __objc_linking (void) +{ + [Object name]; + // [NXConstantString name]; +} + diff --git a/gnustep-objc/misc.c b/gnustep-objc/misc.c new file mode 100644 index 00000000..c3c8d2c3 --- /dev/null +++ b/gnustep-objc/misc.c @@ -0,0 +1,123 @@ +/* GNU Objective C Runtime Miscellaneous + Copyright (C) 1993, 1994, 1995, 1996, 1997 Free Software Foundation, Inc. + Contributed by Kresten Krab Thorup + +This file is part of GNU CC. + +GNU CC is free software; you can redistribute it and/or modify it +under the terms of the GNU General Public License as published by the +Free Software Foundation; either version 2, or (at your option) any +later version. + +GNU CC is distributed in the hope that it will be useful, but WITHOUT +ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License +along with GNU CC; see the file COPYING. If not, write to the Free +Software Foundation, 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + +/* As a special exception, if you link this library with files compiled with + GCC to produce an executable, this does not cause the resulting executable + to be covered by the GNU General Public License. This exception does not + however invalidate any other reasons why the executable file might be + covered by the GNU General Public License. */ + +#define __USE_FIXED_PROTOTYPES__ +#include +#include "runtime.h" +#include "objc-api.h" + +/* +** Error handler function +** NULL so that default is to just print to stderr +*/ +static objc_error_handler _objc_error_handler = NULL; + +/* Trigger an objc error */ +void +objc_error(id object, int code, const char* fmt, ...) +{ + va_list ap; + + va_start(ap, fmt); + objc_verror(object, code, fmt, ap); + va_end(ap); +} + +/* Trigger an objc error */ +void +objc_verror(id object, int code, const char* fmt, va_list ap) +{ + BOOL result = NO; + + /* Call the error handler if its there + Otherwise print to stderr */ + if (_objc_error_handler) + result = (*_objc_error_handler)(object, code, fmt, ap); + else + vfprintf (stderr, fmt, ap); + + /* Continue if the error handler says its ok + Otherwise abort the program */ + if (result) + return; + else + abort(); +} + +/* Set the error handler */ +objc_error_handler +objc_set_error_handler(objc_error_handler func) +{ + objc_error_handler temp = _objc_error_handler; + _objc_error_handler = func; + return temp; +} + +/* +** Hook functions for memory allocation and disposal. +** This makes it easy to substitute garbage collection systems +** such as Boehm's GC by assigning these function pointers +** to the GC's allocation routines. By default these point +** to the ANSI standard malloc, realloc, free, etc. +** +** Users should call the normal objc routines above for +** memory allocation and disposal within their programs. +*/ + +#if OBJC_WITH_GC +#include "gc/gc.h" + +static void *GC_calloc (size_t nelem, size_t size) +{ + void* p = GC_malloc (nelem * size); + if (!p) + objc_error (nil, OBJC_ERR_MEMORY, "Virtual memory exhausted!\n"); + + memset (p, 0, nelem * size); + return p; +} + +static void noFree (void* p) {} + +void *(*_objc_malloc)(size_t) = GC_malloc; +void *(*_objc_atomic_malloc)(size_t) = GC_malloc_atomic; +void *(*_objc_valloc)(size_t) = GC_malloc; +void *(*_objc_realloc)(void *, size_t) = GC_realloc; +void *(*_objc_calloc)(size_t, size_t) = GC_calloc; +void (*_objc_free)(void *) = noFree; + +#else + +void *(*_objc_malloc)(size_t) = malloc; +void *(*_objc_atomic_malloc)(size_t) = malloc; +void *(*_objc_valloc)(size_t) = malloc; +void *(*_objc_realloc)(void *, size_t) = realloc; +void *(*_objc_calloc)(size_t, size_t) = calloc; +void (*_objc_free)(void *) = free; + + +#endif diff --git a/gnustep-objc/nil_method.c b/gnustep-objc/nil_method.c new file mode 100644 index 00000000..1b621282 --- /dev/null +++ b/gnustep-objc/nil_method.c @@ -0,0 +1,40 @@ +/* GNU Objective C Runtime nil receiver function + Copyright (C) 1993, 1995, 1996 Free Software Foundation, Inc. + Contributed by Kresten Krab Thorup + +This file is part of GNU CC. + +GNU CC is free software; you can redistribute it and/or modify it under the +terms of the GNU General Public License as published by the Free Software +Foundation; either version 2, or (at your option) any later version. + +GNU CC is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +FOR A PARTICULAR PURPOSE. See the GNU General Public License for more +details. + +You should have received a copy of the GNU General Public License along with +GNU CC; see the file COPYING. If not, write to the Free Software +Foundation, 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + +/* As a special exception, if you link this library with files compiled with + GCC to produce an executable, this does not cause the resulting executable + to be covered by the GNU General Public License. This exception does not + however invalidate any other reasons why the executable file might be + covered by the GNU General Public License. */ + +/* This is the nil method, the function that is called when the receiver + of a method is nil */ + +#include "runtime.h" + +id +nil_method(id receiver, SEL op, ...) +{ + return receiver; +} + + + + diff --git a/gnustep-objc/objc-api.h b/gnustep-objc/objc-api.h new file mode 100644 index 00000000..d817c332 --- /dev/null +++ b/gnustep-objc/objc-api.h @@ -0,0 +1,595 @@ +/* GNU Objective-C Runtime API. + Copyright (C) 1993, 1995, 1996, 1997 Free Software Foundation, Inc. + +This file is part of GNU CC. + +GNU CC is free software; you can redistribute it and/or modify it +under the terms of the GNU General Public License as published by the +Free Software Foundation; either version 2, or (at your option) any +later version. + +GNU CC is distributed in the hope that it will be useful, but WITHOUT +ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public +License for more details. + +You should have received a copy of the GNU General Public License +along with GNU CC; see the file COPYING. If not, write to +the Free Software Foundation, 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + +/* As a special exception, if you link this library with files compiled + with GCC to produce an executable, this does not cause the resulting + executable to be covered by the GNU General Public License. This + exception does not however invalidate any other reasons why the + executable file might be covered by the GNU General Public License. */ + +#ifndef __objc_api_INCLUDE_GNU +#define __objc_api_INCLUDE_GNU + +#include "objc/objc-decls.h" +#include "objc/objc.h" +#include "objc/hash.h" +#include "objc/thr.h" +#include +#include + +/* For functions which return Method_t */ +#define METHOD_NULL (Method_t)0 + /* Boolean typedefs */ +/* +** Method descriptor returned by introspective Object methods. +** This is really just the first part of the more complete objc_method +** structure defined below and used internally by the runtime. +*/ +struct objc_method_description +{ + SEL name; /* this is a selector, not a string */ + char *types; /* type encoding */ +}; + +/* Filer types used to describe Ivars and Methods. */ +#define _C_ID '@' +#define _C_CLASS '#' +#define _C_SEL ':' +#define _C_CHR 'c' +#define _C_UCHR 'C' +#define _C_SHT 's' +#define _C_USHT 'S' +#define _C_INT 'i' +#define _C_UINT 'I' +#define _C_LNG 'l' +#define _C_ULNG 'L' +#define _C_LNG_LNG 'q' +#define _C_ULNG_LNG 'Q' +#define _C_FLT 'f' +#define _C_DBL 'd' +#define _C_BFLD 'b' +#define _C_VOID 'v' +#define _C_UNDEF '?' +#define _C_PTR '^' +#define _C_CHARPTR '*' +#define _C_ATOM '%' +#define _C_ARY_B '[' +#define _C_ARY_E ']' +#define _C_UNION_B '(' +#define _C_UNION_E ')' +#define _C_STRUCT_B '{' +#define _C_STRUCT_E '}' + + +/* +** Error handling +** +** Call objc_error() or objc_verror() to record an error; this error +** routine will generally exit the program but not necessarily if the +** user has installed his own error handler. +** +** Call objc_set_error_handler to assign your own function for +** handling errors. The function should return YES if it is ok +** to continue execution, or return NO or just abort if the +** program should be stopped. The default error handler is just to +** print a message on stderr. +** +** The error handler function should be of type objc_error_handler +** The first parameter is an object instance of relevance. +** The second parameter is an error code. +** The third parameter is a format string in the printf style. +** The fourth parameter is a variable list of arguments. +*/ +objc_EXPORT void objc_error(id object, int code, const char* fmt, ...); +objc_EXPORT void objc_verror(id object, int code, const char* fmt, va_list ap); +typedef BOOL (*objc_error_handler)(id, int code, const char *fmt, va_list ap); +objc_error_handler objc_set_error_handler(objc_error_handler func); + +/* +** Error codes +** These are used by the runtime library, and your +** error handling may use them to determine if the error is +** hard or soft thus whether execution can continue or abort. +*/ +#define OBJC_ERR_UNKNOWN 0 /* Generic error */ + +#define OBJC_ERR_OBJC_VERSION 1 /* Incorrect runtime version */ +#define OBJC_ERR_GCC_VERSION 2 /* Incorrect compiler version */ +#define OBJC_ERR_MODULE_SIZE 3 /* Bad module size */ +#define OBJC_ERR_PROTOCOL_VERSION 4 /* Incorrect protocol version */ + +#define OBJC_ERR_MEMORY 10 /* Out of memory */ + +#define OBJC_ERR_RECURSE_ROOT 20 /* Attempt to archive the root + object more than once. */ +#define OBJC_ERR_BAD_DATA 21 /* Didn't read expected data */ +#define OBJC_ERR_BAD_KEY 22 /* Bad key for object */ +#define OBJC_ERR_BAD_CLASS 23 /* Unknown class */ +#define OBJC_ERR_BAD_TYPE 24 /* Bad type specification */ +#define OBJC_ERR_NO_READ 25 /* Cannot read stream */ +#define OBJC_ERR_NO_WRITE 26 /* Cannot write stream */ +#define OBJC_ERR_STREAM_VERSION 27 /* Incorrect stream version */ +#define OBJC_ERR_BAD_OPCODE 28 /* Bad opcode */ + +#define OBJC_ERR_UNIMPLEMENTED 30 /* Method is not implemented */ + +#define OBJC_ERR_BAD_STATE 40 /* Bad thread state */ + +/* +** Set this variable nonzero to print a line describing each +** message that is sent. (this is currently disabled) +*/ +objc_EXPORT BOOL objc_trace; + + +/* For every class which happens to have statically allocated instances in + this module, one OBJC_STATIC_INSTANCES is allocated by the compiler. + INSTANCES is NULL terminated and points to all statically allocated + instances of this class. */ +struct objc_static_instances +{ + char *class_name; + id instances[0]; +}; + +/* +** Whereas a Module (defined further down) is the root (typically) of a file, +** a Symtab is the root of the class and category definitions within the +** module. +** +** A Symtab contains a variable length array of pointers to classes and +** categories defined in the module. +*/ +typedef struct objc_symtab { + unsigned long sel_ref_cnt; /* Unknown. */ + SEL refs; /* Unknown. */ + unsigned short cls_def_cnt; /* Number of classes compiled + (defined) in the module. */ + unsigned short cat_def_cnt; /* Number of categories + compiled (defined) in the + module. */ + + void *defs[1]; /* Variable array of pointers. + cls_def_cnt of type Class + followed by cat_def_cnt of + type Category_t, followed + by a NULL terminated array + of objc_static_instances. */ +} Symtab, *Symtab_t; + + +/* +** The compiler generates one of these structures for each module that +** composes the executable (eg main.m). +** +** This data structure is the root of the definition tree for the module. +** +** A collect program runs between ld stages and creates a ObjC ctor array. +** That array holds a pointer to each module structure of the executable. +*/ +typedef struct objc_module { + unsigned long version; /* Compiler revision. */ + unsigned long size; /* sizeof(Module). */ + const char* name; /* Name of the file where the + module was generated. The + name includes the path. */ + + Symtab_t symtab; /* Pointer to the Symtab of + the module. The Symtab + holds an array of + pointers to + the classes and categories + defined in the module. */ +} Module, *Module_t; + + +/* +** The compiler generates one of these structures for a class that has +** instance variables defined in its specification. +*/ +typedef struct objc_ivar* Ivar_t; +typedef struct objc_ivar_list { + int ivar_count; /* Number of structures (Ivar) + contained in the list. One + structure per instance + variable defined in the + class. */ + struct objc_ivar { + const char* ivar_name; /* Name of the instance + variable as entered in the + class definition. */ + const char* ivar_type; /* Description of the Ivar's + type. Useful for + debuggers. */ + int ivar_offset; /* Byte offset from the base + address of the instance + structure to the variable. */ + + } ivar_list[1]; /* Variable length + structure. */ +} IvarList, *IvarList_t; + + +/* +** The compiler generates one (or more) of these structures for a class that +** has methods defined in its specification. +** +** The implementation of a class can be broken into separate pieces in a file +** and categories can break them across modules. To handle this problem is a +** singly linked list of methods. +*/ +typedef struct objc_method Method; +typedef Method* Method_t; +typedef struct objc_method_list { + struct objc_method_list* method_next; /* This variable is used to link + a method list to another. It + is a singly linked list. */ + int method_count; /* Number of methods defined in + this structure. */ + struct objc_method { + SEL method_name; /* This variable is the method's + name. It is a char*. + The unique integer passed to + objc_msg_send is a char* too. + It is compared against + method_name using strcmp. */ + const char* method_types; /* Description of the method's + parameter list. Useful for + debuggers. */ + IMP method_imp; /* Address of the method in the + executable. */ + } method_list[1]; /* Variable length + structure. */ +} MethodList, *MethodList_t; + +struct objc_protocol_list { + struct objc_protocol_list *next; + int count; + Protocol *list[1]; +}; + +/* +** This is used to assure consistent access to the info field of +** classes +*/ +#ifndef HOST_BITS_PER_LONG +#define HOST_BITS_PER_LONG (sizeof(long)*8) +#endif + +#define __CLS_INFO(cls) ((cls)->info) +#define __CLS_ISINFO(cls, mask) ((__CLS_INFO(cls)&mask)==mask) +#define __CLS_SETINFO(cls, mask) (__CLS_INFO(cls) |= mask) + +/* The structure is of type MetaClass */ +#define _CLS_META 0x2L +#define CLS_ISMETA(cls) ((cls)&&__CLS_ISINFO(cls, _CLS_META)) + + +/* The structure is of type Class */ +#define _CLS_CLASS 0x1L +#define CLS_ISCLASS(cls) ((cls)&&__CLS_ISINFO(cls, _CLS_CLASS)) + +/* +** The class is initialized within the runtime. This means that +** it has had correct super and sublinks assigned +*/ +#define _CLS_RESOLV 0x8L +#define CLS_ISRESOLV(cls) __CLS_ISINFO(cls, _CLS_RESOLV) +#define CLS_SETRESOLV(cls) __CLS_SETINFO(cls, _CLS_RESOLV) + +/* +** The class has been send a +initialize message or a such is not +** defined for this class +*/ +#define _CLS_INITIALIZED 0x04L +#define CLS_ISINITIALIZED(cls) __CLS_ISINFO(cls, _CLS_INITIALIZED) +#define CLS_SETINITIALIZED(cls) __CLS_SETINFO(cls, _CLS_INITIALIZED) + +/* +** The class number of this class. This must be the same for both the +** class and its meta class object +*/ +#define CLS_GETNUMBER(cls) (__CLS_INFO(cls) >> (HOST_BITS_PER_LONG/2)) +#define CLS_SETNUMBER(cls, num) \ + ({ (cls)->info <<= (HOST_BITS_PER_LONG/2); \ + (cls)->info >>= (HOST_BITS_PER_LONG/2); \ + __CLS_SETINFO(cls, (((unsigned long)num) << (HOST_BITS_PER_LONG/2))); }) + +/* +** The compiler generates one of these structures for each category. A class +** may have many categories and contain both instance and factory methods. +*/ +typedef struct objc_category { + const char* category_name; /* Name of the category. Name + contained in the () of the + category definition. */ + const char* class_name; /* Name of the class to which + the category belongs. */ + MethodList_t instance_methods; /* Linked list of instance + methods defined in the + category. NULL indicates no + instance methods defined. */ + MethodList_t class_methods; /* Linked list of factory + methods defined in the + category. NULL indicates no + class methods defined. */ + struct objc_protocol_list *protocols; /* List of Protocols + conformed to */ +} Category, *Category_t; + +/* +** Structure used when a message is send to a class's super class. The +** compiler generates one of these structures and passes it to +** objc_msg_super. +*/ +typedef struct objc_super { + id self; /* Id of the object sending + the message. */ + Class class; /* Object's super class. */ +} Super, *Super_t; + +objc_EXPORT IMP objc_msg_lookup_super(Super_t super, SEL sel); + +objc_EXPORT retval_t objc_msg_sendv(id, SEL, arglist_t); + + + +/* +** This is a hook which is called by objc_lookup_class and +** objc_get_class if the runtime is not able to find the class. +** This may e.g. try to load in the class using dynamic loading. +** The function is guaranteed to be passed a non-NULL name string. +*/ +objc_EXPORT Class (*_objc_lookup_class)(const char *name); + +/* +** This is a hook which is called by __objc_exec_class every time a class +** or a category is loaded into the runtime. This may e.g. help a +** dynamic loader determine the classes that have been loaded when +** an object file is dynamically linked in. +*/ +objc_EXPORT void (*_objc_load_callback)(Class class, Category* category); + +/* +** Hook functions for allocating, copying and disposing of instances +*/ +objc_EXPORT id (*_objc_object_alloc)(Class class); +objc_EXPORT id (*_objc_object_copy)(id object); +objc_EXPORT id (*_objc_object_dispose)(id object); + +#if OBJC_WITH_GC +objc_EXPORT BOOL objc_ignore_leaks; +objc_EXPORT void (*objc_report_atomic_leak_func)(void *ptr, unsigned size); +objc_EXPORT void (*objc_report_composite_leak_func)(void *ptr, unsigned size); +#endif + +#if 1 +#include +#else +objc_EXPORT void *objc_malloc(size_t size); +objc_EXPORT void *objc_atomic_malloc(size_t size); +objc_EXPORT void *objc_valloc(size_t size); +objc_EXPORT void *objc_realloc(void *mem, size_t size); +objc_EXPORT void *objc_calloc(size_t nelem, size_t size); +objc_EXPORT void objc_free(void *mem); +#endif + +/* +** Hook functions for memory allocation and disposal. +** This makes it easy to substitute garbage collection systems +** such as Boehm's GC by assigning these function pointers +** to the GC's allocation routines. By default these point +** to the ANSI standard malloc, realloc, free, etc. +** +** Users should call the normal objc routines above for +** memory allocation and disposal within their programs. +*/ +#if WITH_ALLOC_CALLBACKS +objc_EXPORT void *(*_objc_malloc)(size_t); +objc_EXPORT void *(*_objc_atomic_malloc)(size_t); +objc_EXPORT void *(*_objc_valloc)(size_t); +objc_EXPORT void *(*_objc_realloc)(void *, size_t); +objc_EXPORT void *(*_objc_calloc)(size_t, size_t); +objc_EXPORT void (*_objc_free)(void *); +#endif + +/* + hook functions for method lookup. +*/ +#define OBJC_METHOD_LOOKUP_HOOKS 1 +objc_EXPORT IMP (*__objc_msg_lookup)(id, SEL); +objc_EXPORT IMP (*__objc_class_get_method)(Class, SEL); + + +objc_EXPORT Method_t class_get_class_method(MetaClass class, SEL aSel); + +objc_EXPORT Method_t class_get_instance_method(Class class, SEL aSel); + +objc_EXPORT Class class_pose_as(Class impostor, Class superclass); + +objc_EXPORT Class objc_get_class(const char *name); + +objc_EXPORT Class objc_lookup_class(const char *name); + +objc_EXPORT Class objc_next_class(void **enum_state); + +objc_EXPORT const char *sel_get_name(SEL selector); + +objc_EXPORT const char *sel_get_type(SEL selector); + +objc_EXPORT SEL sel_get_uid(const char *name); + +objc_EXPORT SEL sel_get_any_uid(const char *name); + +objc_EXPORT SEL sel_get_any_typed_uid(const char *name); + +objc_EXPORT SEL sel_get_typed_uid(const char *name, const char*); + +objc_EXPORT SEL sel_register_name(const char *name); + +objc_EXPORT SEL sel_register_typed_name(const char *name, const char*type); + + +objc_EXPORT BOOL sel_is_mapped (SEL aSel); + +objc_EXPORT id class_create_instance(Class class); + +static __inline__ const char * +class_get_class_name(Class class) +{ + return CLS_ISCLASS(class)?class->name:((class==Nil)?"Nil":0); +} + +static __inline__ long +class_get_instance_size(Class class) +{ + return CLS_ISCLASS(class)?class->instance_size:0; +} + +static __inline__ MetaClass +class_get_meta_class(Class class) +{ + return CLS_ISCLASS(class)?class->class_pointer:Nil; +} + +static __inline__ Class +class_get_super_class(Class class) +{ + return CLS_ISCLASS(class)?class->super_class:Nil; +} + +static __inline__ int +class_get_version(Class class) +{ + return CLS_ISCLASS(class)?class->version:-1; +} + +static __inline__ BOOL +class_is_class(Class class) +{ + return CLS_ISCLASS(class); +} + +static __inline__ BOOL +class_is_meta_class(Class class) +{ + return CLS_ISMETA(class); +} + + +static __inline__ void +class_set_version(Class class, long version) +{ + if (CLS_ISCLASS(class)) + class->version = version; +} + +static __inline__ void * +class_get_gc_object_type (Class class) +{ + return CLS_ISCLASS(class) ? class->gc_object_type : NULL; +} + +/* Mark the instance variable as innaccessible to the garbage collector */ +objc_EXPORT void class_ivar_set_gcinvisible (Class class, + const char* ivarname, + BOOL gcInvisible); + +static __inline__ IMP +method_get_imp(Method_t method) +{ + return (method!=METHOD_NULL)?method->method_imp:(IMP)0; +} + +objc_EXPORT IMP get_imp (Class class, SEL sel); + +/* Redefine on NeXTSTEP so as not to conflict with system function */ +#ifdef __NeXT__ +#define object_copy gnu_object_copy +#define object_dispose gnu_object_dispose +#endif + +objc_EXPORT id object_copy(id object); + +objc_EXPORT id object_dispose(id object); + +static __inline__ Class +object_get_class(id object) +{ + return ((object!=nil) + ? (CLS_ISCLASS(object->class_pointer) + ? object->class_pointer + : (CLS_ISMETA(object->class_pointer) + ? (Class)object + : Nil)) + : Nil); +} + +static __inline__ const char * +object_get_class_name(id object) +{ + return ((object!=nil)?(CLS_ISCLASS(object->class_pointer) + ?object->class_pointer->name + :((Class)object)->name) + :"Nil"); +} + +static __inline__ MetaClass +object_get_meta_class(id object) +{ + return ((object!=nil)?(CLS_ISCLASS(object->class_pointer) + ?object->class_pointer->class_pointer + :(CLS_ISMETA(object->class_pointer) + ?object->class_pointer + :Nil)) + :Nil); +} + +static __inline__ Class +object_get_super_class +(id object) +{ + return ((object!=nil)?(CLS_ISCLASS(object->class_pointer) + ?object->class_pointer->super_class + :(CLS_ISMETA(object->class_pointer) + ?((Class)object)->super_class + :Nil)) + :Nil); +} + +static __inline__ BOOL +object_is_class(id object) +{ + return CLS_ISCLASS((Class)object); +} + +static __inline__ BOOL +object_is_instance(id object) +{ + return (object!=nil)&&CLS_ISCLASS(object->class_pointer); +} + +static __inline__ BOOL +object_is_meta_class(id object) +{ + return CLS_ISMETA((Class)object); +} + +#endif /* not __objc_api_INCLUDE_GNU */ diff --git a/gnustep-objc/objc-decls.h b/gnustep-objc/objc-decls.h new file mode 100644 index 00000000..0167782c --- /dev/null +++ b/gnustep-objc/objc-decls.h @@ -0,0 +1,17 @@ +// $Id$ + +#ifndef __objc_decls_H__ +#define __objc_decls_H__ + +#if BUILD_libobjc_DLL +# define objc_EXPORT __declspec(dllexport) +# define objc_DECLARE __declspec(dllexport) +#elif libobjc_ISDLL +# define objc_EXPORT extern __declspec(dllimport) +# define objc_DECLARE extern __declspec(dllimport) +#else +# define objc_EXPORT extern +# define objc_DECLARE +#endif + +#endif /* __objc_decls_H__ */ diff --git a/gnustep-objc/objc-features.texi b/gnustep-objc/objc-features.texi new file mode 100644 index 00000000..f1a33ae4 --- /dev/null +++ b/gnustep-objc/objc-features.texi @@ -0,0 +1,392 @@ +\input texinfo @c -*-texinfo-*- +@c %**start of header +@setfilename objc-features.info +@settitle GNU Objective-C runtime features +@setchapternewpage odd +@c %**end of header + +@node Top, Executing code before main, , (dir), (dir) +@comment node-name, next, previous, up + +@chapter GNU Objective-C runtime features + +This document is meant to describe some of the GNU Objective-C runtime +features. It is not intended to teach you Objective-C, there are several +resources on the Internet that present the language. Questions and +comments about this document to Ovidiu Predescu +@code{}. + +@menu +* Executing code before main:: +* Type encoding:: +* Garbage Collection:: +@end menu + + +@node Executing code before main, What you can and what you cannot do in +load, Top, Top +@section @code{+load}: Executing code before main + + +The GNU Objective-C runtime provides a way that allows you to execute +code before the execution of the program enters the @code{main} +function. The code is executed on a per-class and a per-category basis, +through a special class method @code{+load}. + +This facility is very useful if you want to initialize global variables +which can be accessed by the program directly, without sending a message +to the class first. The usual way to initialize global variables, in the +@code{+initialize} method, might not be useful because +@code{+initialize} is only called when the first message is sent to a +class object, which in some cases could be too late. + +Suppose for example you have a @code{FileStream} class that declares +@code{Stdin}, @code{Stdout} and @code{Stderr} as global variables, like +below: + +@example + +FileStream *Stdin = nil; +FileStream *Stdout = nil; +FileStream *Stderr = nil; + +@@implementation FileStream + ++ (void)initialize +@{ + Stdin = [[FileStream new] initWithFd:0]; + Stdout = [[FileStream new] initWithFd:1]; + Stderr = [[FileStream new] initWithFd:2]; +@} + +/* Other methods here */ +@@end + +@end example + +In this example, the initialization of @code{Stdin}, @code{Stdout} and +@code{Stderr} in @code{+initialize} occurs too late. The programmer can +send a message to one of these objects before the variables are actually +initialized, thus sending messages to the @code{nil} object. The +@code{+initialize} method which actually initializes the global +variables is not invoked until the first message is sent to the class +object. The solution would require these variables to be initialized +just before entering @code{main}. + +The correct solution of the above problem is to use the @code{+load} +method instead of @code{+initialize}: + +@example + +@@implementation FileStream + ++ (void)load +@{ + Stdin = [[FileStream new] initWithFd:0]; + Stdout = [[FileStream new] initWithFd:1]; + Stderr = [[FileStream new] initWithFd:2]; +@} + +/* Other methods here */ +@@end + +@end example + +The @code{+load} is a method that is not overridden by categories. If a +class and a category of it both implement @code{+load}, both methods are +invoked. This allows some additional initializations to be performed in +a category. + +This mechanism is not intended to be a replacement for @code{+initialize}. +You should be aware of its limitations when you decide to use it +instead of @code{+initialize}. + +@menu +* What you can and what you cannot do in +load:: +@end menu + + +@node What you can and what you cannot do in +load, Type encoding, Executing code before main, Executing code before main +@subsection What you can and what you cannot do in @code{+load} + +The +load implementation in the GNU runtime guarantees you the following +things: + +@itemize @bullet + +@item +you can write whatever C code you like; + +@item +you can send messages to Objective-C constant strings (@@"this is a +constant string"); + +@item +you can allocate and send messages to objects whose class is implemented +in the same file; + +@item +the @code{+load} implementation of all super classes of a class are executed before the @code{+load} of that class is executed; + +@item +the @code{+load} implementation of a class is executed before the +@code{+load} implementation of any category. + +@end itemize + +In particular, the following things, even if they can work in a +particular case, are not guaranteed: + +@itemize @bullet + +@item +allocation of or sending messages to arbitrary objects; + +@item +allocation of or sending messages to objects whose classes have a +category implemented in the same file; + +@end itemize + +You should make no assumptions about receiving @code{+load} in sibling +classes when you write @code{+load} of a class. The order in which +sibling classes receive @code{+load} is not guaranteed. + +The order in which @code{+load} and @code{+initialize} are called could +be problematic if this matters. If you don't allocate objects inside +@code{+load}, it is guaranteed that @code{+load} is called before +@code{+initialize}. If you create an object inside @code{+load} the +@code{+initialize} method of object's class is invoked even if +@code{+load} was not invoked. Note if you explicitly call @code{+load} +on a class, @code{+initialize} will be called first. To avoid possible +problems try to implement only one of these methods. + +The @code{+load} method is also invoked when a bundle is dynamically +loaded into your running program. This happens automatically without any +intervening operation from you. When you write bundles and you need to +write @code{+load} you can safely create and send messages to objects whose +classes already exist in the running program. The same restrictions as +above apply to classes defined in bundle. + + + +@node Type encoding, Garbage Collection, What you can and what you cannot do in +load, Top +@section Type encoding + +The Objective-C compiler generates type encodings for all the +types. These type encodings are used at runtime to find out information +about selectors and methods and about objects and classes. + +The types are encoded in the following way: + +@c @sp 1 + +@multitable @columnfractions .25 .75 +@item @code{char} +@tab @code{c} +@item @code{unsigned char} +@tab @code{C} +@item @code{short} +@tab @code{s} +@item @code{unsigned short} +@tab @code{S} +@item @code{int} +@tab @code{i} +@item @code{unsigned int} +@tab @code{I} +@item @code{long} +@tab @code{l} +@item @code{unsigned long} +@tab @code{L} +@item @code{long long} +@tab @code{q} +@item @code{unsigned long long} +@tab @code{Q} +@item @code{float} +@tab @code{f} +@item @code{double} +@tab @code{d} +@item @code{void} +@tab @code{v} +@item @code{id} +@tab @code{@@} +@item @code{Class} +@tab @code{#} +@item @code{SEL} +@tab @code{:} +@item @code{char*} +@tab @code{*} +@item unknown type +@tab @code{?} +@item bitfields +@tab @code{b} followed by the starting position of the bitfield, the type of the bitfield and the size of the bitfield (the bitfields encoding was changed from the NeXT's compiler encoding, see below) +@end multitable + +@c @sp 1 + +The encoding of bitfields has changed to allow bitfields to be properly +handled by the runtime functions that compute sizes and alignments of +types that contain bitfields. The previous encoding contained only the +size of the bitfield. Using only this information it is not possible to +reliably compute the size occupied by the bitfield. This is very +important in the presence of the Boehm's garbage collector because the +objects are allocated using the typed memory facility available in this +collector. The typed memory allocation requires information about where +the pointers are located inside the object. + +The position in the bitfield is the position, counting in bits, of the +bit closest to the beginning of the structure. + +The non-atomic types are encoded as follows: + +@c @sp 1 + +@multitable @columnfractions .2 .8 +@item pointers +@tab @code{'^'} followed by the pointed type. +@item arrays +@tab @code{'['} followed by the number of elements in the array followed by the type of the elements followed by @code{']'} +@item structures +@tab @code{'@{'} followed by the name of the structure (or '?' if the structure is unnamed), the '=' sign, the type of the members and by @code{'@}'} +@item unions +@tab @code{'('} followed by the name of the structure (or '?' if the union is unnamed), the '=' sign, the type of the members followed by @code{')'} +@end multitable + +Here are some types and their encodings, as they are generated by the +compiler on a i386 machine: + +@sp 1 + +@multitable @columnfractions .25 .75 +@item Objective-C type +@tab Compiler encoding +@item +@example +int a[10]; +@end example +@tab @code{[10i]} +@item +@example +struct @{ + int i; + float f[3]; + int a:3; + int b:2; + char c; +@} +@end example +@tab @code{@{?=i[3f]b128i3b131i2c@}} +@end multitable + +@sp 1 + +In addition to the types the compiler also encodes the type +specifiers. The table below describes the encoding of the current +Objective-C type specifiers: + +@sp 1 + +@multitable @columnfractions .25 .75 +@item Specifier +@tab Encoding +@item @code{const} +@tab @code{r} +@item @code{in} +@tab @code{n} +@item @code{inout} +@tab @code{N} +@item @code{out} +@tab @code{o} +@item @code{bycopy} +@tab @code{O} +@item @code{oneway} +@tab @code{V} +@end multitable + +@sp 1 + +The type specifiers are encoded just before the type. Unlike types +however, the type specifiers are only encoded when they appear in method +argument types. + + +@node Garbage Collection, , Type encoding, Top + +@page +@section Garbage Collection + +Support for a new memory management policy has been added by using a +powerful conservative garbage collector, known as the +Boehm-Demers-Weiser conservative garbage collector. It is available from +@w{@uref{http://reality.sgi.com/employees/boehm_mti/gc.html}}. + +To enable the support for it you have to configure the compiler using an +additional argument, @w{@kbd{--enable-objc-gc}}. You need to have +garbage collector installed before building the compiler. This will +build an additional runtime library which has several enhancements to +support the garbage collector. The new library has a new name, +@kbd{libobjc_gc.a} to not conflict with the non-garbage-collected +library. + +When the garbage collector is used, the objects are allocated using the +so-called typed memory allocation mechanism available in the +Boehm-Demers-Weiser collector. This mode requires precise information on +where pointers are located inside objects. This information is computed +once per class, immediately after the class has been initialized. + +There is a new runtime function @code{class_ivar_set_gcinvisible()} +which can be used to declare a so-called @strong{weak pointer} +reference. Such a pointer is basically hidden for the garbage collector; +this can be useful in certain situations, especially when you want to +keep track of the allocated objects, yet allow them to be +collected. This kind of pointers can only be members of objects, you +cannot declare a global pointer as a weak reference. Every type which is +a pointer type can be declared a weak pointer, including @code{id}, +@code{Class} and @code{SEL}. + +Here is an example of how to use this feature. Suppose you want to +implement a class whose instances hold a weak pointer reference; the +following class does this: + +@example + +@@interface WeakPointer : Object +@{ + const void* weakPointer; +@} + +- initWithPointer:(const void*)p; +- (const void*)weakPointer; +@@end + + +@@implementation WeakPointer + ++ (void)initialize +@{ + class_ivar_set_gcinvisible (self, "weakPointer", YES); +@} + +- initWithPointer:(const void*)p +@{ + weakPointer = p; + return self; +@} + +- (const void*)weakPointer +@{ + return weakPointer; +@} + +@@end + +@end example + +Weak pointers are supported through a new type character specifier +represented by the @code{'!'} character. The +@code{class_ivar_set_gcinvisible()} function adds or removes this +specifier to the string type description of the instance variable named +as argument. + + +@bye + diff --git a/gnustep-objc/objc-list.h b/gnustep-objc/objc-list.h new file mode 100644 index 00000000..9fc5ad61 --- /dev/null +++ b/gnustep-objc/objc-list.h @@ -0,0 +1,146 @@ +/* Generic single linked list to keep various information + Copyright (C) 1993, 1994, 1996 Free Software Foundation, Inc. + Contributed by Kresten Krab Thorup. + +This file is part of GNU CC. + +GNU CC is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU CC is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU CC; see the file COPYING. If not, write to +the Free Software Foundation, 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + +/* As a special exception, if you link this library with files compiled with + GCC to produce an executable, this does not cause the resulting executable + to be covered by the GNU General Public License. This exception does not + however invalidate any other reasons why the executable file might be + covered by the GNU General Public License. */ + +#ifndef __GNU_OBJC_LIST_H +#define __GNU_OBJC_LIST_H + +#include + +struct objc_list { + void *head; + struct objc_list *tail; +}; + +/* Return a cons cell produced from (head . tail) */ + +static __inline__ struct objc_list* +list_cons(void* head, struct objc_list* tail) +{ + struct objc_list* cell; + +#if OBJC_WITH_GC + cell = GC_MALLOC_UNCOLLECTABLE(sizeof(struct objc_list)); +#else + cell = malloc(sizeof(struct objc_list)); +#endif + cell->head = head; + cell->tail = tail; + return cell; +} + +/* Return the length of a list, list_length(NULL) returns zero */ + +static __inline__ int +list_length(struct objc_list* list) +{ + int i = 0; + while(list) + { + i += 1; + list = list->tail; + } + return i; +} + +/* Return the Nth element of LIST, where N count from zero. If N + larger than the list length, NULL is returned */ + +static __inline__ void* +list_nth(int index, struct objc_list* list) +{ + while(index-- != 0) { + if(list->tail) + list = list->tail; + else + return 0; + } + return list->head; +} + +/* Remove the element at the head by replacing it by its successor */ + +static __inline__ void +list_remove_head(struct objc_list** list) +{ + if ((*list)->tail) { + struct objc_list* tail = (*list)->tail; /* fetch next */ + *(*list) = *tail; /* copy next to list head */ + objc_free(tail); /* free next */ + } + else { /* only one element in list */ + objc_free(*list); + (*list) = 0; + } +} + + +/* Remove the element with `car' set to ELEMENT */ + +static __inline__ void +list_remove_elem(struct objc_list** list, void* elem) +{ + while (*list) { + if ((*list)->head == elem) + list_remove_head(list); + list = &((*list)->tail); + } +} + +/* Map FUNCTION over all elements in LIST */ + +static __inline__ void +list_mapcar(struct objc_list* list, void(*function)(void*)) +{ + while (list) { + (*function)(list->head); + list = list->tail; + } +} + +/* Return element that has ELEM as car */ + +static __inline__ struct objc_list** +list_find(struct objc_list** list, void* elem) +{ + while (*list) { + if ((*list)->head == elem) + return list; + list = &((*list)->tail); + } + return NULL; +} + +/* Free list (backwards recursive) */ + +static void list_free(struct objc_list *list) +{ + if (list) { + list_free(list->tail); + objc_free(list); + } +} +#endif /* __GNU_OBJC_LIST_H */ diff --git a/gnustep-objc/objc-mem.h b/gnustep-objc/objc-mem.h new file mode 100644 index 00000000..0c14373a --- /dev/null +++ b/gnustep-objc/objc-mem.h @@ -0,0 +1,129 @@ +// $Id$ + +//#define WITH_ALLOC_CALLBACKS 0 +#define GC_DEBUG 1 + +static __inline__ void *objc_malloc(size_t size); +static __inline__ void *objc_atomic_malloc(size_t size); +static __inline__ void *objc_valloc(size_t size); +static __inline__ void *objc_realloc(void *mem, size_t size); +static __inline__ void *objc_calloc(size_t nelem, size_t size); +static __inline__ void objc_free(void *mem); + +#if !defined(OBJC_MEMORY) +#define OBJC_MEMORY + +#ifndef OBJC_ERR_MEMORY +# define OBJC_ERR_MEMORY 10 /* Out of memory */ +#endif + +objc_EXPORT void objc_error(id object, int code, const char* fmt, ...); + +#if !WITH_ALLOC_CALLBACKS +# if OBJC_WITH_GC +# include "objc/gc.h" +# else +# include +# endif +#endif + +/* +** Standard functions for memory allocation and disposal. +** Users should use these functions in their ObjC programs so +** that they work properly with garbage collectors as well as +** can take advantage of the exception/error handling available. +*/ +static __inline__ void *objc_malloc(size_t size) { +#if WITH_ALLOC_CALLBACKS + void* res = (void*) (*_objc_malloc)(size); +#else +#if OBJC_WITH_GC + void *res = GC_MALLOC(size); +#else + void *res = malloc(size); +#endif +#endif + + if(!res) + objc_error(nil, OBJC_ERR_MEMORY, "Virtual memory exhausted\n"); + return res; +} + +#include + +static __inline__ void *objc_atomic_malloc(size_t size) { +#if WITH_ALLOC_CALLBACKS + void* res = (void*) (*_objc_atomic_malloc)(size); +#else +#if OBJC_WITH_GC + void *res = GC_MALLOC_ATOMIC(size); +#else + void *res = malloc(size); +#endif +#endif + if(!res) + objc_error(nil, OBJC_ERR_MEMORY, "Virtual memory exhausted\n"); + return res; +} + +static __inline__ void *objc_valloc(size_t size) { +#if WITH_ALLOC_CALLBACKS + void* res = (void*) (*_objc_valloc)(size); +#else +#if OBJC_WITH_GC + void *res = GC_MALLOC(size); + if (res) memset(res, 0, size); +#else + void *res = malloc(size); +#endif +#endif + if(!res) + objc_error(nil, OBJC_ERR_MEMORY, "Virtual memory exhausted\n"); + return res; +} + +static __inline__ void *objc_realloc(void *mem, size_t size) { +#if WITH_ALLOC_CALLBACKS + void* res = (void*) (*_objc_realloc)(mem, size); +#else +#if OBJC_WITH_GC + void *res = GC_REALLOC(mem, size); +#else + void *res = realloc(mem, size); +#endif +#endif + if(!res) + objc_error(nil, OBJC_ERR_MEMORY, "Virtual memory exhausted\n"); + return res; +} + +static __inline__ void *objc_calloc(size_t nelem, size_t size) { +#if WITH_ALLOC_CALLBACKS + void* res = (void*) (*_objc_calloc)(nelem, size); +#else +#if OBJC_WITH_GC + register size_t s = nelem * size; + void *res = GC_MALLOC(s); + if (res) memset(res, 0, s); +#else + void *res = calloc(nelem, size); +#endif +#endif + if(!res) + objc_error(nil, OBJC_ERR_MEMORY, "Virtual memory exhausted\n"); + return res; +} + +static __inline__ void objc_free(void *mem) { +#if WITH_ALLOC_CALLBACKS + (*_objc_free)(mem); +#else +#if OBJC_WITH_GC + GC_FREE(mem); mem = NULL; +#else + free(mem); +#endif +#endif +} + +#endif diff --git a/gnustep-objc/objc.h b/gnustep-objc/objc.h new file mode 100644 index 00000000..b2adb637 --- /dev/null +++ b/gnustep-objc/objc.h @@ -0,0 +1,159 @@ +/* Basic data types for Objective C. + Copyright (C) 1993, 1995, 1996 Free Software Foundation, Inc. + +This file is part of GNU CC. + +GNU CC is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU CC is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU CC; see the file COPYING. If not, write to +the Free Software Foundation, 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + +/* As a special exception, if you link this library with files + compiled with GCC to produce an executable, this does not cause + the resulting executable to be covered by the GNU General Public License. + This exception does not however invalidate any other reasons why + the executable file might be covered by the GNU General Public License. */ + +#ifndef __objc_INCLUDE_GNU +#define __objc_INCLUDE_GNU + +#ifdef __cplusplus +extern "C" { +#endif + +#include + +/* +** Definition of the boolean type. +*/ +#ifdef __vxworks +typedef int BOOL; +#else +typedef unsigned char BOOL; +#endif +#define YES (BOOL)1 +#define NO (BOOL)0 + +/* +** Definition of a selector. Selectors themselves are not unique, but +** the sel_id is a unique identifier. +*/ +typedef const struct objc_selector +{ + void *sel_id; + const char *sel_types; +} *SEL; + +inline static BOOL +sel_eq (SEL s1, SEL s2) +{ + if (s1 == 0 || s2 == 0) + return s1 == s2; + else + return s1->sel_id == s2->sel_id; +} + + +/* +** ObjC uses this typedef for untyped instances. +*/ +typedef struct objc_object { + struct objc_class* class_pointer; +} *id; + +/* +** Definition of method type. When retrieving the implementation of a +** method, this is type of the pointer returned +*/ +typedef id (*IMP)(id, SEL, ...); + +/* +** More simple types... +*/ +#define nil (id)0 /* id of Nil instance */ +#define Nil (Class)0 /* id of Nil class */ +typedef char *STR; /* String alias */ + +/* +** The compiler generates one of these structures for each class. +** +** This structure is the definition for classes. +** +** This structure is generated by the compiler in the executable and used by +** the run-time during normal messaging operations. Therefore some members +** change type. The compiler generates "char* const" and places a string in +** the following member variables: super_class. +*/ +typedef struct objc_class *MetaClass; +typedef struct objc_class *Class; +struct objc_class { + MetaClass class_pointer; /* Pointer to the class's + meta class. */ + struct objc_class* super_class; /* Pointer to the super + class. NULL for class + Object. */ + const char* name; /* Name of the class. */ + long version; /* Unknown. */ + unsigned long info; /* Bit mask. See class masks + defined above. */ + long instance_size; /* Size in bytes of the class. + The sum of the class + definition and all super + class definitions. */ + struct objc_ivar_list* ivars; /* Pointer to a structure that + describes the instance + variables in the class + definition. NULL indicates + no instance variables. Does + not include super class + variables. */ + struct objc_method_list* methods; /* Linked list of instance + methods defined for the + class. */ + /* the idx in the sarray is the SEL sel_id, the value is the method-IMP */ + struct sarray * dtable; /* Pointer to instance + method dispatch table. */ + struct objc_class* subclass_list; /* Subclasses */ + struct objc_class* sibling_class; + + struct objc_protocol_list *protocols; /* Protocols conformed to */ + void* gc_object_type; +}; + +#ifndef __OBJC__ +typedef struct objc_protocol { + struct objc_class* class_pointer; + char *protocol_name; + struct objc_protocol_list *protocol_list; + struct objc_method_description_list *instance_methods, *class_methods; +} Protocol; + +#else /* __OBJC__ */ +@class Protocol; +#endif + +typedef void* retval_t; /* return value */ +typedef void(*apply_t)(void); /* function pointer */ +typedef union { + char *arg_ptr; + char arg_regs[sizeof (char*)]; +} *arglist_t; /* argument frame */ + + +IMP objc_msg_lookup(id receiver, SEL op); + +#ifdef __cplusplus +} +#endif + +#endif /* not __objc_INCLUDE_GNU */ diff --git a/gnustep-objc/objects.c b/gnustep-objc/objects.c new file mode 100644 index 00000000..e70a9797 --- /dev/null +++ b/gnustep-objc/objects.c @@ -0,0 +1,108 @@ +/* GNU Objective C Runtime class related functions + Copyright (C) 1993, 1995, 1996 Free Software Foundation, Inc. + Contributed by Kresten Krab Thorup + +This file is part of GNU CC. + +GNU CC is free software; you can redistribute it and/or modify it under the +terms of the GNU General Public License as published by the Free Software +Foundation; either version 2, or (at your option) any later version. + +GNU CC is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +FOR A PARTICULAR PURPOSE. See the GNU General Public License for more +details. + +You should have received a copy of the GNU General Public License along with +GNU CC; see the file COPYING. If not, write to the Free Software +Foundation, 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + +/* As a special exception, if you link this library with files compiled with + GCC to produce an executable, this does not cause the resulting executable + to be covered by the GNU General Public License. This exception does not + however invalidate any other reasons why the executable file might be + covered by the GNU General Public License. */ + +#include "objc.h" +#include "runtime.h" /* the kitchen sink */ +#include "objc-api.h" +#include + +#if OBJC_WITH_GC +# include "gc/gc.h" +# include "gc/gc_typed.h" +#endif + +id __objc_object_alloc(Class); +id __objc_object_dispose(id); +id __objc_object_copy(id); + +id (*_objc_object_alloc)(Class) = __objc_object_alloc; /* !T:SINGLE */ +id (*_objc_object_dispose)(id) = __objc_object_dispose; /* !T:SINGLE */ +id (*_objc_object_copy)(id) = __objc_object_copy; /* !T:SINGLE */ + +id +class_create_instance(Class class) +{ + id new = nil; + +#if OBJC_WITH_GC + if (CLS_ISCLASS(class)) { + new = (id)GC_malloc_explicitly_typed (class->instance_size, + class->gc_object_type); + } +#else + if (CLS_ISCLASS(class)) + new = (*_objc_object_alloc)(class); +#endif + + if (new!=nil) + { + memset (new, 0, class->instance_size); + new->class_pointer = class; + } + return new; +} + +id +object_copy(id object) +{ + if ((object!=nil)&&CLS_ISCLASS(object->class_pointer)) + return (*_objc_object_copy)(object); + else + return nil; +} + +id +object_dispose(id object) +{ + if ((object!=nil)&&CLS_ISCLASS(object->class_pointer)) + { + if (_objc_object_dispose) + (*_objc_object_dispose)(object); + else + objc_free(object); + } + return nil; +} + +id __objc_object_alloc(Class class) +{ + return (id)objc_malloc(class->instance_size); +} + +id __objc_object_dispose(id object) +{ + objc_free(object); + return 0; +} + +id __objc_object_copy(id object) +{ + id copy = class_create_instance(object->class_pointer); + memcpy(copy, object, object->class_pointer->instance_size); + return copy; +} + + diff --git a/gnustep-objc/runtime.h b/gnustep-objc/runtime.h new file mode 100644 index 00000000..e56ddc06 --- /dev/null +++ b/gnustep-objc/runtime.h @@ -0,0 +1,123 @@ +/* GNU Objective C Runtime internal declarations + Copyright (C) 1993, 1995, 1996, 1997 Free Software Foundation, Inc. + Contributed by Kresten Krab Thorup + +This file is part of GNU CC. + +GNU CC is free software; you can redistribute it and/or modify it under the +terms of the GNU General Public License as published by the Free Software +Foundation; either version 2, or (at your option) any later version. + +GNU CC is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +FOR A PARTICULAR PURPOSE. See the GNU General Public License for more +details. + +You should have received a copy of the GNU General Public License along with +GNU CC; see the file COPYING. If not, write to the Free Software +Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +/* As a special exception, if you link this library with files compiled with + GCC to produce an executable, this does not cause the resulting executable + to be covered by the GNU General Public License. This exception does not + however invalidate any other reasons why the executable file might be + covered by the GNU General Public License. */ + +#ifndef __objc_runtime_INCLUDE_GNU +#define __objc_runtime_INCLUDE_GNU + +/* + runtime.h is private header file +*/ + +#include /* for varargs and va_list's */ + +#include +#include + +#include /* so noone else will get system versions */ + +#if OBJC_WITH_GC +# include "gc.h" +#endif + +#include "assert.h" + +#include "objc.h" /* core data types */ +#include "objc-api.h" /* runtime api functions */ +#include "thr.h" /* thread and mutex support */ +#include "hash.h" /* hash structures */ +#include "objc-list.h" /* linear lists */ +#include "globals.h" + +objc_EXPORT void __objc_add_class_to_hash(Class); /* (objc-class.c) */ +objc_EXPORT void __objc_init_selector_tables(void); /* (objc-sel.c) */ +objc_EXPORT void __objc_init_class_tables(void); /* (objc-class.c) */ +objc_EXPORT void __objc_init_dispatch_tables(void); /* (objc-dispatch.c) */ +objc_EXPORT void __objc_resolve_class_links(void); /* (objc-class.c) */ +objc_EXPORT void __objc_register_selectors_from_class(Class); /* (objc-sel.c) */ +objc_EXPORT void __objc_update_dispatch_table_for_class (Class);/* (objc-msg.c) */ + +objc_EXPORT int __objc_init_thread_system(void); /* thread.c */ +objc_EXPORT int __objc_fini_thread_system(void); /* thread.c */ +objc_EXPORT void __objc_print_dtable_stats(void); /* sendmsg.c */ + +objc_EXPORT void class_add_method_list(Class, MethodList_t); + +/* Registering instance methods as class methods for root classes */ +objc_EXPORT void __objc_register_instance_methods_to_class(Class); +objc_EXPORT Method_t search_for_method_in_list(MethodList_t list, SEL op); + +/* True when class links has been resolved */ +objc_EXPORT BOOL __objc_class_links_resolved; + +/* Number of selectors stored in each of the selector tables */ +objc_EXPORT int __objc_selector_max_index; + +/* Mutex locking __objc_selector_max_index and its arrays. */ +objc_EXPORT objc_mutex_t __objc_runtime_mutex; + +/* Number of threads which are alive. */ +objc_EXPORT int __objc_runtime_threads_alive; + +#ifdef OBJC_DEBUG +# define DEBUG_PRINTF(format, args...) printf (format, ## args) +#else +# define DEBUG_PRINTF(format, args...) +#endif + +BOOL __objc_responds_to (id object, SEL sel); /* for internal use only! */ +SEL __sel_register_typed_name (const char*, const char*, + struct objc_selector*, BOOL is_const); + +/* runtime locking */ + +#if !defined(OBJC_WITHOUT_THREADING) +# define RUNTIME_LOCK objc_mutex_lock(__objc_runtime_mutex) +# define RUNTIME_UNLOCK objc_mutex_unlock(__objc_runtime_mutex) +#else +# define RUNTIME_LOCK +# define RUNTIME_UNLOCK +#endif + +/* memory stuff */ + +static inline void *OBJC_MALLOC_UNCOLLECTABLE(unsigned int size) { +#if OBJC_WITH_GC + return GC_MALLOC_UNCOLLECTABLE(size); +#else + return malloc(size); +#endif +} + +static inline void *OBJC_CALLOC_UNCOLLECTABLE(unsigned int size) { +#if OBJC_WITH_GC + register void *result = GC_MALLOC_UNCOLLECTABLE(size); + memset(result, 0, size); + return result; +#else + return calloc(1, size); +#endif +} + +#endif /* not __objc_runtime_INCLUDE_GNU */ diff --git a/gnustep-objc/sarray.c b/gnustep-objc/sarray.c new file mode 100644 index 00000000..ce6c5bbe --- /dev/null +++ b/gnustep-objc/sarray.c @@ -0,0 +1,404 @@ +/* Sparse Arrays for Objective C dispatch tables + Copyright (C) 1993, 1995, 1996 Free Software Foundation, Inc. + +This file is part of GNU CC. + +GNU CC is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU CC is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU CC; see the file COPYING. If not, write to +the Free Software Foundation, 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + +/* As a special exception, if you link this library with files + compiled with GCC to produce an executable, this does not cause + the resulting executable to be covered by the GNU General Public License. + This exception does not however invalidate any other reasons why + the executable file might be covered by the GNU General Public License. */ + +#include "sarray.h" +#include "runtime.h" +#include +#include +#include "assert.h" +#include "objc-api.h" + +int nbuckets = 0; /* !T:MUTEX */ +int nindices = 0; /* !T:MUTEX */ +int narrays = 0; /* !T:MUTEX */ +int idxsize = 0; /* !T:MUTEX */ + +static void *first_free_data = NULL; /* !T:MUTEX */ + +const char* __objc_sparse2_id = "2 level sparse indices"; + +#ifdef __alpha__ +const void *memcpy (void*, const void*, size_t); +#endif + +static void sarray_free_garbage(void *vp); + +/* sparse array 2 */ + +#if BUCKET_SIZE == 32 +static struct sbucket empty_bucket_32 = { + { NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL }, /* elements */ + { -1 } +}; +#elif BUCKET_SIZE == 64 +static struct sbucket empty_bucket_64 = { + { NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL }, /* elements */ + { -1 } +}; +#elif BUCKET_SIZE == 256 +static struct sbucket empty_bucket_256 = { + { NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL }, /* elements */ + { -1 } +}; +#endif + +struct sarray *sarray_new (int size) +{ + struct sarray *arr; + size_t num_indices = ((size - 1) / BUCKET_SIZE) + 1; + struct sbucket **new_buckets; + int counter; + + assert(size > 0); + + /* Allocate core array */ + arr = (struct sarray*)OBJC_MALLOC_UNCOLLECTABLE(sizeof(struct sarray)); + arr->version.version = 0; + + /* Initialize members */ + arr->capacity = num_indices * BUCKET_SIZE; + new_buckets = (struct sbucket **) + OBJC_MALLOC_UNCOLLECTABLE(sizeof(struct sbucket *) * num_indices); + + narrays += 1; + idxsize += num_indices; + +#if BUCKET_SIZE == 32 || BUCKET_SIZE == 64 ||BUCKET_SIZE == 256 +# if BUCKET_SIZE == 32 + arr->empty_bucket = &empty_bucket_32; +# elif BUCKET_SIZE == 64 + arr->empty_bucket = &empty_bucket_64; +# elif BUCKET_SIZE == 256 + arr->empty_bucket = &empty_bucket_256; +# endif +#else + arr->empty_bucket = + (struct sbucket *)OBJC_MALLOC_UNCOLLECTABLE(sizeof(struct sbucket)); + arr->empty_bucket->version.version = 0; +#endif + + nbuckets += 1; + + arr->ref_count = 1; + arr->is_copy_of = (struct sarray*)0; + + for (counter = 0; counter < num_indices; counter++) + new_buckets[counter] = arr->empty_bucket; + + arr->buckets = new_buckets; + + return arr; +} + +/* Reallocate the sparse array to hold `newsize' entries + Note: We really allocate and then free. We have to do this to ensure that + any concurrent readers notice the update. */ +void sarray_realloc(struct sarray* array, int newsize) +{ + size_t old_max_index = (array->capacity-1)/BUCKET_SIZE; + size_t new_max_index = ((newsize-1)/BUCKET_SIZE); + size_t rounded_size = (new_max_index+1)*BUCKET_SIZE; + + struct sbucket ** new_buckets; + struct sbucket ** old_buckets; + + int counter; + + assert(newsize > 0); + + /* The size is the same, just ignore the request */ + if(rounded_size <= array->capacity) + return; + + assert(array->ref_count == 1); /* stop if lazy copied... */ + + /* We are asked to extend the array -- allocate new bucket table, */ + /* and insert empty_bucket in newly allocated places. */ + if(rounded_size > array->capacity) { + new_max_index += 4; + rounded_size = (new_max_index+1)*BUCKET_SIZE; + + /* update capacity */ + array->capacity = rounded_size; + + old_buckets = array->buckets; + new_buckets = (struct sbucket**) + OBJC_MALLOC_UNCOLLECTABLE((new_max_index + 1) * sizeof(struct sbucket*)); + + /* copy buckets below old_max_index (they are still valid) */ + for(counter = 0; counter <= old_max_index; counter++ ) + new_buckets[counter] = old_buckets[counter]; + + /* reset entries above old_max_index to empty_bucket */ + for(counter = old_max_index+1; counter <= new_max_index; counter++) + new_buckets[counter] = array->empty_bucket; + + array->buckets = new_buckets; + sarray_free_garbage(old_buckets); + + idxsize += (new_max_index-old_max_index); + return; + } +} + +/* Free a sparse array allocated with sarray_new */ +void sarray_free(struct sarray *array) +{ + size_t old_max_bucket_index; + struct sbucket **old_buckets; + register int counter; + + if (array == NULL) + return; + + old_max_bucket_index = (array->capacity - 1) / BUCKET_SIZE; + + assert(array->ref_count != 0); /* Freed multiple times!!! */ + + (array->ref_count)--; + if(array->ref_count > 0) /* There exists copies of me */ + return; + + old_buckets = array->buckets; + + /* Free all entries that do not point to empty_bucket */ + for(counter = 0; counter <= old_max_bucket_index; counter++ ) { + register struct sbucket *bkt = array->buckets[counter]; + + if ((bkt == NULL) || (bkt == array->empty_bucket)) + continue; + + if (bkt->version.version == array->version.version) { + /* + only if bucket belongs to this array + (only written records in lazy copies) + */ + sarray_free_garbage(bkt); bkt = NULL; + nbuckets -= 1; + } + } + + /* free empty_bucket */ + if(array->empty_bucket->version.version == array->version.version) { + sarray_free_garbage(array->empty_bucket); + nbuckets -= 1; + } + idxsize -= (old_max_bucket_index + 1); + narrays -= 1; + + /* free bucket table */ + sarray_free_garbage(array->buckets); + + /* release lazy copy */ + if (array->is_copy_of) { + assert(array->is_copy_of != array); + assert(array->is_copy_of->version.version < array->version.version); + + sarray_free(array->is_copy_of); + array->is_copy_of = NULL; + } + + /* free array */ + sarray_free_garbage(array); +} + +/* This is a lazy copy. Only the core of the structure is actually */ +/* copied. */ + +struct sarray *sarray_lazy_copy(struct sarray* oarr) +{ + struct sarray* arr; + size_t num_indices = ((oarr->capacity-1)/BUCKET_SIZE)+1; + struct sbucket ** new_buckets; + + /* Allocate core array */ + arr = (struct sarray *)OBJC_MALLOC_UNCOLLECTABLE(sizeof(struct sarray)); + assert(arr != oarr); + arr->version.version = oarr->version.version + 1; + arr->empty_bucket = oarr->empty_bucket; + arr->ref_count = 1; + oarr->ref_count += 1; + arr->is_copy_of = oarr; + arr->capacity = oarr->capacity; + + /* Copy bucket table */ + new_buckets = (struct sbucket**) + OBJC_MALLOC_UNCOLLECTABLE(sizeof(struct sbucket *) * num_indices); + memcpy(new_buckets, oarr->buckets, sizeof(struct sbucket*)*num_indices); + arr->buckets = new_buckets; + idxsize += num_indices; + narrays += 1; + + return arr; +} + +void sarray_at_put(struct sarray *array, sidx index, void *element) { + return sarray_at_put_safe(array, index, element); +} + +void +sarray_at_put_safe(struct sarray *array, sidx index, void *element) +{ + register unsigned int idx; + struct sbucket** the_bucket; + struct sbucket* new_bucket; + size_t boffset; + size_t eoffset; + boffset = index / BUCKET_SIZE; + eoffset = index % BUCKET_SIZE; + + idx = index; + +#ifdef __WIN32__ + if (array == NULL) + abort(); +#endif + + if (idx >= array->capacity) + sarray_realloc(array, (idx + 1)); + + assert(idx < array->capacity); /* Range check */ + + the_bucket = &(array->buckets[boffset]); + + if ((*the_bucket)->elems[eoffset] == element) + return; /* great! we just avoided a lazy copy */ + + /* next, perform lazy allocation/copy of the bucket if needed */ + + if ((*the_bucket) == array->empty_bucket) { + + /* The bucket was previously empty (or something like that), */ + /* allocate a new. This is the effect of `lazy' allocation */ + new_bucket = + (struct sbucket*)OBJC_MALLOC_UNCOLLECTABLE(sizeof(struct sbucket)); + + memcpy((void *) new_bucket, (const void*)array->empty_bucket, + sizeof(struct sbucket)); + new_bucket->version.version = array->version.version; + *the_bucket = new_bucket; /* Prepared for install. */ + + nbuckets += 1; + + } else if ((*the_bucket)->version.version != array->version.version) { + + /* Perform lazy copy. */ + struct sbucket* old_bucket = *the_bucket; + + new_bucket = + (struct sbucket*)OBJC_MALLOC_UNCOLLECTABLE(sizeof(struct sbucket)); + + memcpy( new_bucket, old_bucket, sizeof(struct sbucket)); + new_bucket->version.version = array->version.version; + *the_bucket = new_bucket; /* Prepared for install. */ + + nbuckets += 1; + + } + (*the_bucket)->elems[eoffset] = element; +} + +/* This function removes any structures left over from free operations + that were not safe in a multi-threaded environment. */ +void sarray_remove_garbage(void) { + void **vp; + void *np; + + RUNTIME_LOCK; + + vp = first_free_data; + first_free_data = NULL; + + while (vp) { + np = *vp; +#if OBJC_WITH_GC + GC_FREE(vp); +#else + free(vp); +#endif + vp = np; + } + + RUNTIME_UNLOCK; +} + +/* Free a block of dynamically allocated memory. If we are in multi-threaded + mode, it is ok to free it. If not, we add it to the garbage heap to be + freed later. */ + +static void sarray_free_garbage(void *vp) { + RUNTIME_LOCK; + + if (__objc_runtime_threads_alive == 1) { +#if OBJC_WITH_GC + GC_FREE(vp); +#else + free(vp); +#endif + if (first_free_data) + sarray_remove_garbage(); + } + else { + *(void **)vp = first_free_data; + first_free_data = vp; + } + + RUNTIME_UNLOCK; +} diff --git a/gnustep-objc/sarray.h b/gnustep-objc/sarray.h new file mode 100644 index 00000000..ca7caab5 --- /dev/null +++ b/gnustep-objc/sarray.h @@ -0,0 +1,88 @@ +/* Sparse Arrays for Objective C dispatch tables + Copyright (C) 1993, 1995, 1996 Free Software Foundation, Inc. + Contributed by Kresten Krab Thorup. + +This file is part of GNU CC. + +GNU CC is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU CC is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU CC; see the file COPYING. If not, write to +the Free Software Foundation, 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + +/* As a special exception, if you link this library with files + compiled with GCC to produce an executable, this does not cause + the resulting executable to be covered by the GNU General Public License. + This exception does not however invalidate any other reasons why + the executable file might be covered by the GNU General Public License. */ + +#ifndef __sarray_INCLUDE_GNU +#define __sarray_INCLUDE_GNU + +#include "objc/objc-decls.h" + +objc_EXPORT const char* __objc_sparse2_id; + +#include +#include "objc/thr.h" + +objc_EXPORT int nbuckets; /* for stats */ +objc_EXPORT int nindices; +objc_EXPORT int narrays; +objc_EXPORT int idxsize; + +#include + +/* Buckets are 32 words each */ +#define BUCKET_SIZE (1 << 6) + +typedef size_t sidx; + +union sversion { + int version; + void *next_free; +}; + +struct sbucket { + void* elems[BUCKET_SIZE]; /* elements stored in array */ + union sversion version; /* used for copy-on-write */ +}; + +struct sarray { + struct sbucket** buckets; + struct sbucket* empty_bucket; + union sversion version; /* used for copy-on-write */ + short ref_count; + struct sarray *is_copy_of; + size_t capacity; +}; + +struct sarray* sarray_new (int size); +void sarray_free (struct sarray *array); +struct sarray* sarray_lazy_copy (struct sarray *array); +void sarray_realloc (struct sarray *array, int new_size); +void sarray_at_put_safe(struct sarray *array, sidx index, void* elem); + +void sarray_remove_garbage(void); + +/* implementation */ + +/* Get element from the Sparse array `array' at offset `index' */ + +static inline void* sarray_get_safe(struct sarray* array, sidx index) +{ + return (index < array->capacity) + ? array->buckets[index / BUCKET_SIZE]->elems[index % BUCKET_SIZE] + : array->empty_bucket->elems[0]; +} + +#endif /* __sarray_INCLUDE_GNU */ diff --git a/gnustep-objc/selector.c b/gnustep-objc/selector.c new file mode 100644 index 00000000..ed8f3458 --- /dev/null +++ b/gnustep-objc/selector.c @@ -0,0 +1,426 @@ +/* GNU Objective C Runtime selector related functions + Copyright (C) 1993, 1995, 1996, 1997 Free Software Foundation, Inc. + Contributed by Kresten Krab Thorup + +This file is part of GNU CC. + +GNU CC is free software; you can redistribute it and/or modify it under the +terms of the GNU General Public License as published by the Free Software +Foundation; either version 2, or (at your option) any later version. + +GNU CC is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +FOR A PARTICULAR PURPOSE. See the GNU General Public License for more +details. + +You should have received a copy of the GNU General Public License along with +GNU CC; see the file COPYING. If not, write to the Free Software +Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +/* As a special exception, if you link this library with files compiled with + GCC to produce an executable, this does not cause the resulting executable + to be covered by the GNU General Public License. This exception does not + however invalidate any other reasons why the executable file might be + covered by the GNU General Public License. */ + +#include "runtime.h" +#include "sarray.h" +#include "encoding.h" +#include "hash.h" +#include + +/* Initial selector hash table size. Value doesn't matter much */ +#define SELECTOR_HASH_SIZE 128 + +static void register_selectors_from_list(MethodList_t); + +void __objc_init_selector_tables() +{ + __objc_selector_array = sarray_new (SELECTOR_HASH_SIZE); + __objc_selector_names = sarray_new (SELECTOR_HASH_SIZE); + __objc_selector_hash = strhash_new(SELECTOR_HASH_SIZE); +} + +/* This routine is given a class and records all of the methods in its class + structure in the record table. */ +void __objc_register_selectors_from_class (Class class) +{ + register MethodList_t method_list; + + method_list = class->methods; + while (method_list) { + register_selectors_from_list (method_list); + method_list = method_list->method_next; + } +} + + +/* This routine is given a list of methods and records each of the methods in + the record table. This is the routine that does the actual recording + work. + + This one is only called for Class objects. For categories, + class_add_method_list is called. + */ +static void register_selectors_from_list (MethodList_t method_list) +{ + register int i = 0; + while (i < method_list->method_count) + { + Method_t method = &method_list->method_list[i]; + method->method_name + = sel_register_typed_name ((const char*)method->method_name, + method->method_types); + i += 1; + } +} + + +/* Register instance methods as class methods for root classes */ +void __objc_register_instance_methods_to_class(Class class) +{ + MethodList_t method_list; + MethodList_t class_method_list; + int max_methods_no = 16; + MethodList_t new_list; + Method_t curr_method; + + /* Only if a root class. */ + if(class->super_class) + return; + + /* Allocate a method list to hold the new class methods */ + new_list = + OBJC_CALLOC_UNCOLLECTABLE(sizeof(struct objc_method_list) + + sizeof(struct objc_method[max_methods_no])); + + method_list = class->methods; + class_method_list = class->class_pointer->methods; + curr_method = &new_list->method_list[0]; + + /* Iterate through the method lists for the class */ + while (method_list) + { + int i; + + /* Iterate through the methods from this method list */ + for (i = 0; i < method_list->method_count; i++) + { + Method_t mth = &method_list->method_list[i]; + if (mth->method_name + && !search_for_method_in_list (class_method_list, + mth->method_name)) + { + /* This instance method isn't a class method. + Add it into the new_list. */ + *curr_method = *mth; + + /* Reallocate the method list if necessary */ + if(++new_list->method_count == max_methods_no) + new_list = + objc_realloc(new_list, sizeof(struct objc_method_list) + + sizeof(struct + objc_method[max_methods_no += 16])); + curr_method = &new_list->method_list[new_list->method_count]; + } + } + + method_list = method_list->method_next; + } + + /* If we created any new class methods + then attach the method list to the class */ + if (new_list->method_count) + { + new_list = + objc_realloc(new_list, sizeof(struct objc_method_list) + + sizeof(struct objc_method[new_list->method_count])); + new_list->method_next = class->class_pointer->methods; + class->class_pointer->methods = new_list; + } + + __objc_update_dispatch_table_for_class (class->class_pointer); +} + + +/* Returns YES iff t1 and t2 have same method types, but we ignore + the argframe layout */ +BOOL sel_types_match (const char* t1, const char* t2) +{ + if (!t1 || !t2) + return NO; + while (*t1 && *t2) + { + if (*t1 == '+') t1++; + if (*t2 == '+') t2++; + while (isdigit((int)*t1)) t1++; + while (isdigit((int)*t2)) t2++; + /* xxx Remove these next two lines when qualifiers are put in + all selectors, not just Protocol selectors. */ + t1 = objc_skip_type_qualifiers(t1); + t2 = objc_skip_type_qualifiers(t2); + if (!*t1 && !*t2) + return YES; + if (*t1 != *t2) + return NO; + t1++; + t2++; + } + return NO; +} + +/* return selector representing name */ +SEL sel_get_typed_uid (const char *name, const char *types) +{ + struct objc_list *l; + sidx i; + + RUNTIME_LOCK; + + i = (sidx) hash_value_for_key (__objc_selector_hash, name); + if (i == 0) + { + RUNTIME_UNLOCK; + return 0; + } + + for (l = (struct objc_list*)sarray_get_safe (__objc_selector_array, i); + l; l = l->tail) + { + SEL s = (SEL)l->head; + if (types == 0 || s->sel_types == 0) + { + if (s->sel_types == types) + { + RUNTIME_UNLOCK; + return s; + } + } + else if (sel_types_match (s->sel_types, types)) + { + RUNTIME_UNLOCK; + return s; + } + } + + RUNTIME_UNLOCK; + return 0; +} + +/* Return selector representing name; prefer a selector with non-NULL type */ +SEL sel_get_any_typed_uid (const char *name) +{ + struct objc_list *l; + sidx i; + SEL s = NULL; + + RUNTIME_LOCK; + + i = (sidx) hash_value_for_key (__objc_selector_hash, name); + if (i == 0) + { + RUNTIME_UNLOCK; + return 0; + } + + for (l = (struct objc_list*)sarray_get_safe (__objc_selector_array, i); + l; l = l->tail) + { + s = (SEL) l->head; + if (s->sel_types) + { + RUNTIME_UNLOCK; + return s; + } + } + + RUNTIME_UNLOCK; + return s; +} + +/* return selector representing name */ +SEL sel_get_any_uid (const char *name) +{ + struct objc_list *l; + sidx i; + + RUNTIME_LOCK; + + i = (sidx) hash_value_for_key (__objc_selector_hash, name); + if (i == 0) { + RUNTIME_UNLOCK; + return 0; + } + + l = (struct objc_list*)sarray_get_safe (__objc_selector_array, i); + RUNTIME_UNLOCK; + + if (l == 0) + return 0; + + return (SEL)l->head; +} + +/* return selector representing name */ +SEL sel_get_uid (const char *name) +{ + return sel_register_typed_name (name, 0); +} + +/* Get name of selector. If selector is unknown, the empty string "" + is returned */ +const char* sel_get_name (SEL selector) +{ + const char *ret; + + RUNTIME_LOCK; + ret = ((selector->sel_id > 0) + && ((unsigned int)selector->sel_id <= __objc_selector_max_index)) + ? sarray_get_safe (__objc_selector_names, (sidx) selector->sel_id) + : 0; + RUNTIME_UNLOCK; + return ret; +} + +BOOL sel_is_mapped (SEL selector) +{ + register unsigned int idx = (unsigned int)selector->sel_id; + return ((idx > 0) && (idx <= __objc_selector_max_index)); +} + + +const char* sel_get_type (SEL selector) +{ + return selector ? selector->sel_types : 0; +} + +/* Store the passed selector name in the selector record and return its + selector value (value returned by sel_get_uid). + Assumes that the calling function has locked down __objc_runtime_mutex. */ +/* is_const parameter tells us if the name and types parameters + are really constant or not. If YES then they are constant and + we can just store the pointers. If NO then we need to copy + name and types because the pointers may disappear later on. */ +SEL +__sel_register_typed_name (const char *name, const char *types, + struct objc_selector *orig, BOOL is_const) +{ + struct objc_selector* j; + sidx i; + struct objc_list *l; + + i = (sidx) hash_value_for_key (__objc_selector_hash, name); + if (i != 0) { + for (l = (struct objc_list*)sarray_get_safe (__objc_selector_array, i); + l; l = l->tail) { + SEL s = (SEL)l->head; + if (types == 0 || s->sel_types == 0) { + if (s->sel_types == types) { + if (orig) { + orig->sel_id = (void*)i; + return orig; + } + else + return s; + } + } + else if (!strcmp (s->sel_types, types)) { + if (orig) { + orig->sel_id = (void*)i; + return orig; + } + else + return s; + } + } + if (orig) + j = orig; + else + j = OBJC_MALLOC_UNCOLLECTABLE(sizeof(struct objc_selector)); + + j->sel_id = (void*)i; + /* Can we use the pointer or must copy types? Don't copy if NULL */ + if ((is_const) || (types == 0)) { + j->sel_types = (const char*)types; + } + else { + j->sel_types = (char *)OBJC_MALLOC_UNCOLLECTABLE(strlen(types) + 1); + strcpy((char *)j->sel_types, types); + } + l = (struct objc_list*)sarray_get_safe (__objc_selector_array, i); + } + else { + __objc_selector_max_index += 1; + i = __objc_selector_max_index; + + if (orig) + j = orig; + else + j = OBJC_MALLOC_UNCOLLECTABLE (sizeof (struct objc_selector)); + + j->sel_id = (void*)i; + /* Can we use the pointer or must copy types? Don't copy if NULL */ + if ((is_const) || (types == 0)) + j->sel_types = (const char*)types; + else { + j->sel_types = (char *)OBJC_MALLOC_UNCOLLECTABLE(strlen(types)+1); + + strcpy((char *)j->sel_types, types); + } + l = 0; + } + + DEBUG_PRINTF ("Record selector %s[%s] as: %ld\n", + name ? name : "", types ? types : "", + (long int)i); + + { + int is_new = (l == 0); + const char *new_name; + + /* Can we use the pointer or must copy name? Don't copy if NULL */ + if ((is_const) || (name == 0)) { + new_name = name; + } + else { + new_name = (char *)OBJC_MALLOC_UNCOLLECTABLE(strlen(name) + 1); + strcpy((char *)new_name, name); + } + + l = list_cons ((void*)j, l); + sarray_at_put_safe (__objc_selector_names, i, (void *) new_name); + sarray_at_put_safe (__objc_selector_array, i, (void *) l); + if (is_new) + hash_add (&__objc_selector_hash, (void *) new_name, (void *) i); + } + + //hh:sarray_realloc(__objc_uninstalled_dtable, __objc_selector_max_index + 1); + + return (SEL) j; +} + +SEL sel_register_name (const char *name) +{ + SEL ret; + + RUNTIME_LOCK; + /* Assume that name is not constant static memory and needs to be + copied before put into a runtime structure. is_const == NO */ + ret = __sel_register_typed_name (name, 0, 0, NO); + RUNTIME_UNLOCK; + + return ret; +} + +SEL sel_register_typed_name (const char *name, const char *type) +{ + SEL ret; + + RUNTIME_LOCK; + /* Assume that name and type are not constant static memory and need to + be copied before put into a runtime structure. is_const == NO */ + ret = __sel_register_typed_name (name, type, 0, NO); + RUNTIME_UNLOCK; + + return ret; +} diff --git a/gnustep-objc/sendmsg.c b/gnustep-objc/sendmsg.c new file mode 100644 index 00000000..fc96433b --- /dev/null +++ b/gnustep-objc/sendmsg.c @@ -0,0 +1,661 @@ +/* GNU Objective C Runtime message lookup + Copyright (C) 1993, 1995, 1996, 1997, 1998 Free Software Foundation, Inc. + Contributed by Kresten Krab Thorup + +This file is part of GNU CC. + +GNU CC is free software; you can redistribute it and/or modify it under the +terms of the GNU General Public License as published by the Free Software +Foundation; either version 2, or (at your option) any later version. + +GNU CC is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +FOR A PARTICULAR PURPOSE. See the GNU General Public License for more +details. + +You should have received a copy of the GNU General Public License along with +GNU CC; see the file COPYING. If not, write to the Free Software +Foundation, 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + +/* As a special exception, if you link this library with files compiled with + GCC to produce an executable, this does not cause the resulting executable + to be covered by the GNU General Public License. This exception does not + however invalidate any other reasons why the executable file might be + covered by the GNU General Public License. */ + +#include "runtime.h" +#include "sarray.h" +#include "encoding.h" + +/* this is how we hack STRUCT_VALUE to be 1 or 0 */ +#define gen_rtx(args...) 1 +#define gen_rtx_MEM(args...) 1 +#define rtx int + +#if !defined(STRUCT_VALUE) || STRUCT_VALUE == 0 +# define INVISIBLE_STRUCT_RETURN 1 +#else +# define INVISIBLE_STRUCT_RETURN 0 +#endif + +/* Send +initialize to class */ +static void __objc_send_initialize(Class); + +static void __objc_install_dispatch_table_for_class (Class); + +/* Forward declare some functions */ +static void __objc_init_install_dtable(id, SEL); + +/* Various forwarding functions that are used based upon the + return type for the selector. + __objc_block_forward for structures. + __objc_double_forward for floats/doubles. + __objc_word_forward for pointers or types that fit in registers. + */ +static double __objc_double_forward(id, SEL, ...); +static id __objc_word_forward(id, SEL, ...); +typedef struct { id many[8]; } __big; +#if INVISIBLE_STRUCT_RETURN +static __big +#else +static id +#endif +__objc_block_forward(id, SEL, ...); +static Method_t search_for_method_in_hierarchy (Class class, SEL sel); +Method_t search_for_method_in_list(MethodList_t list, SEL op); +id nil_method(id, SEL, ...); + +/* Given a selector, return the proper forwarding implementation. */ +__inline__ IMP __objc_get_forward_imp (SEL sel) +{ + const char *t = sel->sel_types; + + if (t && (*t == '[' || *t == '(' || *t == '{') +#ifdef OBJC_MAX_STRUCT_BY_VALUE + && objc_sizeof_type(t) > OBJC_MAX_STRUCT_BY_VALUE +#endif + ) + return (IMP)__objc_block_forward; + else if (t && (*t == 'f' || *t == 'd')) + return (IMP)__objc_double_forward; + else + return (IMP)__objc_word_forward; +} + +/* Given a class and selector, return the selector's implementation. */ +objc_DECLARE __inline__ IMP get_imp (Class class, SEL sel) +{ + register void *res; + + if (class->dtable == NULL) { + /* The dispatch table needs to be installed. */ + RUNTIME_LOCK; + __objc_install_dispatch_table_for_class (class); + RUNTIME_UNLOCK; + } + + if ((res = sarray_get_safe (class->dtable, (size_t)sel->sel_id))) + return res; + + if (__objc_class_get_method) { + if ((res = __objc_class_get_method(class, sel))) + return res; + } + + /* if 0: The dispatch table has been installed so the + method just doesn't exist for the class. + Return the forwarding implementation. */ + + return __objc_get_forward_imp(sel); +} + +/* Query if an object can respond to a selector, returns YES if the +object implements the selector otherwise NO. Does not check if the +method can be forwarded. */ +objc_DECLARE __inline__ BOOL __objc_responds_to (id object, SEL sel) +{ + /* Install dispatch table if need be */ + if (object->class_pointer->dtable == NULL) { + RUNTIME_LOCK; + __objc_install_dispatch_table_for_class (object->class_pointer); + RUNTIME_UNLOCK; + } + + /* Get the method from the dispatch table */ + return sarray_get_safe (object->class_pointer->dtable, (size_t) sel->sel_id) + ? YES : NO; +} + +/* This is the lookup function. All entries in the table are either a + valid method *or* zero. If zero then either the dispatch table + needs to be installed or it doesn't exist and forwarding is attempted. */ +objc_DECLARE __inline__ IMP objc_msg_lookup(id receiver, SEL op) +{ + register IMP result; + + if (receiver == nil) + return nil_method; + + if (receiver->class_pointer->dtable == NULL) { + /* The dispatch table needs to be installed. + This happens on the very first method call to the class. */ + __objc_init_install_dtable(receiver, op); + } + +#if DEBUG && 0 + assert(receiver->class_pointer->dtable != NULL); +#endif + + if ((result = sarray_get_safe (receiver->class_pointer->dtable, + (sidx)op->sel_id))) + return result; + + if (__objc_msg_lookup) { + if ((result = __objc_msg_lookup(receiver, op))) + return result; + } + + return __objc_get_forward_imp(op); +} + +objc_DECLARE __inline__ IMP +objc_msg_lookup_super (Super_t super, SEL sel) +{ + return (super->self) + ? get_imp (super->class, sel) + : nil_method; +} + +int method_get_sizeof_arguments (Method*); + +objc_DECLARE retval_t +objc_msg_sendv(id object, SEL op, arglist_t arg_frame) +{ + Method* m = class_get_instance_method(object->class_pointer, op); + const char *type; + *((id*)method_get_first_argument (m, arg_frame, &type)) = object; + *((SEL*)method_get_next_argument (arg_frame, &type)) = op; + return __builtin_apply((apply_t)m->method_imp, + arg_frame, + method_get_sizeof_arguments (m)); +} + +objc_DECLARE void +__objc_init_dispatch_tables() +{ +#if 0 + extern void *__objc_uninstalled_dtable; + __objc_uninstalled_dtable = sarray_new(200); + printf("init dispatch tables, __objc_uninstalled_dtable=0x%08X\n", + __objc_uninstalled_dtable); +#endif +} + +/* This function is called by objc_msg_lookup when the + dispatch table needs to be installed; thus it is called once + for each class, namely when the very first message is sent to it. */ +static void __objc_init_install_dtable(id receiver, SEL op) +{ + /* This may happen, if the programmer has taken the address of a + method before the dtable was initialized... too bad for him! */ + if(receiver->class_pointer->dtable != NULL) + return; + + RUNTIME_LOCK; + + if(CLS_ISCLASS(receiver->class_pointer)) + { + /* receiver is an ordinary object */ + assert(CLS_ISCLASS(receiver->class_pointer)); + + /* install instance methods table */ + __objc_install_dispatch_table_for_class (receiver->class_pointer); + + /* call +initialize -- this will in turn install the factory + dispatch table if not already done :-) */ + __objc_send_initialize(receiver->class_pointer); + } + else + { + /* receiver is a class object */ + assert(CLS_ISCLASS((Class)receiver)); + assert(CLS_ISMETA(receiver->class_pointer)); + + /* Install real dtable for factory methods */ + __objc_install_dispatch_table_for_class(receiver->class_pointer); + + __objc_send_initialize((Class)receiver); + } + + RUNTIME_UNLOCK; +} + +/* Install dummy table for class which causes the first message to + that class (or instances hereof) to be initialized properly */ +objc_DECLARE void __objc_install_premature_dtable(Class class) +{ + // DEPRECATED + /* hh:assert(__objc_uninstalled_dtable); + class->dtable = __objc_uninstalled_dtable; + */ + class->dtable = NULL; +} + +/* Send +initialize to class if not already done */ +static void __objc_send_initialize(Class class) +{ + extern void __objc_generate_gc_type_description (Class class); + + /* This *must* be a class object */ + assert(CLS_ISCLASS(class)); + assert(!CLS_ISMETA(class)); + + if (!CLS_ISINITIALIZED(class)) + { + CLS_SETINITIALIZED(class); + CLS_SETINITIALIZED(class->class_pointer); + + /* Create the garbage collector type memory description */ + __objc_generate_gc_type_description (class); + + if(class->super_class) + __objc_send_initialize(class->super_class); + + { + SEL op = sel_register_name ("initialize"); + IMP imp = 0; + MethodList_t method_list = class->class_pointer->methods; + + while (method_list) { + int i; + Method_t method; + + for (i = 0; i< method_list->method_count; i++) { + method = &(method_list->method_list[i]); + if (method->method_name + && method->method_name->sel_id == op->sel_id) { + imp = method->method_imp; + break; + } + } + + if (imp) + break; + + method_list = method_list->method_next; + + } + if (imp) + (*imp)((id)class, op); + + } + } +} + +/* Walk on the methods list of class and install the methods in the reverse + order of the lists. Since methods added by categories are before the methods + of class in the methods list, this allows categories to substitute methods + declared in class. However if more than one category replaces the same + method nothing is guaranteed about what method will be used. + Assumes that __objc_runtime_mutex is locked down. */ +static void +__objc_install_methods_in_dtable (Class class, MethodList_t method_list) +{ + register int i; + + if (method_list == NULL) + return; + + if (method_list->method_next) + __objc_install_methods_in_dtable (class, method_list->method_next); + + for (i = 0; i < method_list->method_count; i++) { + Method_t method = &(method_list->method_list[i]); + + sarray_at_put_safe (class->dtable, + (sidx) method->method_name->sel_id, + method->method_imp); + } +} + +/* Assumes that __objc_runtime_mutex is locked down. */ +static int depth = 0; + +static void +__objc_install_dispatch_table_for_class (Class class) +{ + Class super; + + /* If the class has not yet had its class links resolved, we must + re-compute all class links */ + if(!CLS_ISRESOLV(class)) + __objc_resolve_class_links(); + + super = class->super_class; + +#if DEBUG_DTABLE + { int i; for (i = 0; i < depth; i++) putc(' ', stdout); } + printf("installing dispatch table for %sclass %s (super is %sclass %s)\n", + CLS_ISMETA(class) ? "meta-" : "", class->name ? class->name : "", + CLS_ISMETA(super) ? "meta-" : "", super ? super->name : ""); + fflush(stdout); +#endif + + /* Allocate dtable if necessary */ + if (super == 0) { + // root-class + RUNTIME_LOCK; + class->dtable = sarray_new (__objc_selector_max_index); + RUNTIME_UNLOCK; + } + else { // non-root class + if (super->dtable == NULL) + __objc_install_dispatch_table_for_class (super); + + assert(super->dtable); + class->dtable = sarray_lazy_copy (super->dtable); + } + + __objc_install_methods_in_dtable (class, class->methods); +} + +objc_DECLARE void +__objc_update_dispatch_table_for_class (Class class) +{ + /* not yet installed -- skip it */ + if (class->dtable == NULL) + return; + + depth++; + +#if DEBUG_DTABLE + { int i; for (i = 0; i < depth; i++) putc(' ', stdout); } + printf("! %sclass %s updating dispatch table (super is %sclass %s)\n", + CLS_ISMETA(class) ? "meta-" : "", class->name ? class->name : "", + CLS_ISMETA(class->super_class) ? "meta-" : "", + class->super_class ? class->super_class->name : ""); + fflush(stdout); +#endif + + RUNTIME_LOCK; + + sarray_free(class->dtable); class->dtable = NULL; + + /* could have been lazy... */ + __objc_install_dispatch_table_for_class (class); + + if (class->subclass_list) { /* Traverse subclasses */ + register Class next; + +#if DEBUG_DTABLE + depth++; + for (next = class->subclass_list; next; next = next->sibling_class) { + int i; + for (i = 0; i < depth; i++) putc(' ', stdout); + printf("%% child(of=%sclass %s): %sclass %s\n", + CLS_ISMETA(class) ? "meta-" : "", + class->name ? class->name : "", + CLS_ISMETA(next) ? "meta-" : "", + next->name ? next->name : ""); + fflush(stdout); + + assert(next->super_class == class); + } +#endif + for (next = class->subclass_list; next; next = next->sibling_class) { + assert(next->super_class == class); + __objc_update_dispatch_table_for_class (next); + } + depth--; + } + + RUNTIME_UNLOCK; + + depth--; +} + + +/* This function adds a method list to a class. This function is + typically called by another function specific to the run-time. As + such this function does not worry about thread safe issues. + + This one is only called for categories. Class objects have their + methods installed right away, and their selectors are made into + SEL's by the function __objc_register_selectors_from_class. */ +objc_DECLARE void +class_add_method_list (Class class, MethodList_t list) +{ + int i; + + /* Passing of a linked list is not allowed. Do multiple calls. */ + assert(list->method_next == NULL); + + /* Check for duplicates. */ + for (i = 0; i < list->method_count; ++i) { + Method_t method = &list->method_list[i]; + + if (method->method_name) { /* Sometimes these are NULL */ + /* This is where selector names are transmogrified to SEL's */ + method->method_name = + sel_register_typed_name ((const char*)method->method_name, + method->method_types); + } + } + + /* Add the methods to the class's method list. */ + list->method_next = class->methods; + class->methods = list; + + /* Update the dispatch table of class */ + __objc_update_dispatch_table_for_class (class); +} + +objc_DECLARE Method_t class_get_instance_method(Class class, SEL op) +{ + return search_for_method_in_hierarchy(class, op); +} + +objc_DECLARE Method_t class_get_class_method(MetaClass class, SEL op) +{ + return search_for_method_in_hierarchy(class, op); +} + + +/* Search for a method starting from the current class up its hierarchy. + Return a pointer to the method's method structure if found. NULL + otherwise. */ + +static Method_t search_for_method_in_hierarchy (Class cls, SEL sel) +{ + Method_t method = NULL; + Class class; + + if (! sel_is_mapped (sel)) + return NULL; + + /* Scan the method list of the class. If the method isn't found in the + list then step to its super class. */ + for (class = cls; ((! method) && class); class = class->super_class) + method = search_for_method_in_list (class->methods, sel); + + return method; +} + + + +/* Given a linked list of method and a method's name. Search for the named + method's method structure. Return a pointer to the method's method + structure if found. NULL otherwise. */ +objc_DECLARE Method_t search_for_method_in_list (MethodList_t list, SEL op) +{ + MethodList_t method_list = list; + + if (! sel_is_mapped (op)) + return NULL; + + /* If not found then we'll search the list. */ + while (method_list) + { + int i; + + /* Search the method list. */ + for (i = 0; i < method_list->method_count; ++i) + { + Method_t method = &method_list->method_list[i]; + + if (method->method_name) + if (method->method_name->sel_id == op->sel_id) + return method; + } + + /* The method wasn't found. Follow the link to the next list of + methods. */ + method_list = method_list->method_next; + } + + return NULL; +} + +static retval_t __objc_forward (id object, SEL sel, arglist_t args); + +/* Forwarding pointers/integers through the normal registers */ +static id +__objc_word_forward (id rcv, SEL op, ...) +{ + void *args, *res; + + args = __builtin_apply_args (); + res = __objc_forward (rcv, op, args); + if (res) + __builtin_return (res); + else + return res; +} + +/* Specific routine for forwarding floats/double because of + architectural differences on some processors. i386s for + example which uses a floating point stack versus general + registers for floating point numbers. This forward routine + makes sure that GCC restores the proper return values */ +static double +__objc_double_forward (id rcv, SEL op, ...) +{ + void *args, *res; + + args = __builtin_apply_args (); + res = __objc_forward (rcv, op, args); + __builtin_return (res); +} + +#if INVISIBLE_STRUCT_RETURN +static __big +#else +static id +#endif +__objc_block_forward (id rcv, SEL op, ...) +{ + void *args, *res; + + args = __builtin_apply_args (); + res = __objc_forward (rcv, op, args); + if (res) + __builtin_return (res); + else +#if INVISIBLE_STRUCT_RETURN + return (__big) {{0, 0, 0, 0, 0, 0, 0, 0}}; +#else + return nil; +#endif +} + + +/* This function is installed in the dispatch table for all methods which are + not implemented. Thus, it is called when a selector is not recognized. */ +static retval_t +__objc_forward (id object, SEL sel, arglist_t args) +{ + IMP imp; + static SEL frwd_sel = 0; /* !T:SAFE2 */ + SEL err_sel; + + /* first try if the object understands forward:: */ + if (!frwd_sel) + frwd_sel = sel_get_any_uid("forward::"); + + if (__objc_responds_to (object, frwd_sel)) + { + imp = get_imp(object->class_pointer, frwd_sel); + return (*imp)(object, frwd_sel, sel, args); + } + + /* If the object recognizes the doesNotRecognize: method then we're going + to send it. */ + err_sel = sel_get_any_uid ("doesNotRecognize:"); + if (__objc_responds_to (object, err_sel)) { + imp = get_imp (object->class_pointer, err_sel); + return (*imp) (object, err_sel, sel); + } + + /* The object doesn't recognize the method. Check for responding to + error:. If it does then sent it. */ + { + size_t strlen (const char*); + char msg[256 + strlen ((const char*)sel_get_name (sel)) + + strlen ((const char*)object->class_pointer->name)]; + + sprintf (msg, "(%s) %s does not recognize %s", + (CLS_ISMETA(object->class_pointer) + ? "class" + : "instance" ), + object->class_pointer->name, + sel_get_name (sel)); + + err_sel = sel_get_any_uid ("error:"); + if (__objc_responds_to (object, err_sel)) { + imp = get_imp (object->class_pointer, err_sel); + return (*imp) (object, sel_get_any_uid ("error:"), msg); + } + + /* The object doesn't respond to doesNotRecognize: or error:; Therefore, + a default action is taken. */ + objc_error (object, OBJC_ERR_UNIMPLEMENTED, "%s\n", msg); + + return 0; + } +} + +objc_DECLARE void __objc_print_dtable_stats() +{ + extern int objc_moduleCount; + extern int objc_classCount; + extern int objc_categoryCount; + //extern int __objc_selector_max_index; + int total = 0; + + RUNTIME_LOCK; + + printf("memory usage:\n" + " sparse: 2-level sparse arrays\n" + " modules: %i\n" + " classes: %i\n" + " categories: %i\n" + " selectors: %i\n", + objc_moduleCount, objc_classCount, objc_categoryCount, + __objc_selector_max_index); + + printf("arrays: %d = %ld bytes\n", narrays, + (long)narrays*sizeof(struct sarray)); + total += narrays*sizeof(struct sarray); + printf("buckets: %d = %ld bytes\n", nbuckets, + (long)nbuckets*sizeof(struct sbucket)); + total += nbuckets*sizeof(struct sbucket); + + printf("idxtables: %d = %ld bytes\n", idxsize, (long)idxsize*sizeof(void*)); + total += idxsize*sizeof(void*); + printf("-----------------------------------\n"); + printf("total: %d bytes\n", total); + printf("===================================\n"); + + RUNTIME_UNLOCK; +} diff --git a/gnustep-objc/thr-backends/mach.c b/gnustep-objc/thr-backends/mach.c new file mode 100644 index 00000000..8b4776ff --- /dev/null +++ b/gnustep-objc/thr-backends/mach.c @@ -0,0 +1,337 @@ +/* GNU Objective C Runtime Thread Implementation + Copyright (C) 1996, 1997 Free Software Foundation, Inc. + Contributed by Galen C. Hunt (gchunt@cs.rochester.edu) + Modified for Mach threads by Bill Bumgarner + Condition functions added by Mircea Oancea + +This file is part of GNU CC. + +GNU CC is free software; you can redistribute it and/or modify it under the +terms of the GNU General Public License as published by the Free Software +Foundation; either version 2, or (at your option) any later version. + +GNU CC is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +FOR A PARTICULAR PURPOSE. See the GNU General Public License for more +details. + +You should have received a copy of the GNU General Public License +along with GNU CC; see the file COPYING. If not, write to +the Free Software Foundation, 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + +/* As a special exception, if you link this library with files compiled with + GCC to produce an executable, this does not cause the resulting executable + to be covered by the GNU General Public License. This exception does not + however invalidate any other reasons why the executable file might be + covered by the GNU General Public License. */ + +/* + This readme refers to the file thr-mach.c. + + Under mach, thread priorities are kinda strange-- any given thread has + a MAXIMUM priority and a BASE priority. The BASE priority is the + current priority of the thread and the MAXIMUM is the maximum possible + priority the thread can assume. The developer can lower, but never + raise the maximum priority. + + The gcc concept of thread priorities is that they run at one of three + levels; interactive, background, and low. + + Under mach, this is translated to: + + interactive -- set priority to maximum + background -- set priority to 2/3 of maximum + low -- set priority to 1/3 of maximum + + This means that it is possible for a thread with the priority of + interactive to actually run at a lower priority than another thread + with a background, or even low, priority if the developer has modified + the maximum priority. +*/ + +#include +#include +#include +#include "runtime.h" +#include "objc-api.h" + +/* + Obtain the maximum thread priority that can set for t. Under the + mach threading model, it is possible for the developer to adjust the + maximum priority downward only-- cannot be raised without superuser + privileges. Once lowered, it cannot be raised. + */ +static int __mach_get_max_thread_priority(cthread_t t, int *base) +{ + thread_t threadP; + kern_return_t error; + struct thread_sched_info info; + unsigned int info_count=THREAD_SCHED_INFO_COUNT; + + if (t == NULL) + return -1; + + threadP = cthread_thread(t); /* get thread underlying */ + + error=thread_info(threadP, THREAD_SCHED_INFO, + (thread_info_t)&info, &info_count); + + if (error != KERN_SUCCESS) + return -1; + + if (base != NULL) + *base = info.base_priority; + + return info.max_priority; +} + +/* Backend initialization functions */ + +/* Initialize the threads subsystem. */ +int +__objc_init_thread_system(void) +{ + return 0; +} + +/* Close the threads subsystem. */ +int +__objc_close_thread_system(void) +{ + return 0; +} + +/* Backend thread functions */ + +/* Create a new thread of execution. */ +objc_thread_t +__objc_thread_detach(void (*func)(void *arg), void *arg) +{ + objc_thread_t thread_id; + cthread_t new_thread_handle; + + /* create thread */ + new_thread_handle = cthread_fork((cthread_fn_t)func, arg); + + if(new_thread_handle) + { + /* this is not terribly portable */ + thread_id = *(objc_thread_t *)&new_thread_handle; + cthread_detach(new_thread_handle); + } + else + thread_id = NULL; + + return thread_id; +} + +/* Set the current thread's priority. */ +int +__objc_thread_set_priority(int priority) +{ + objc_thread_t *t = objc_thread_id(); + cthread_t cT = (cthread_t) t; + int maxPriority = __mach_get_max_thread_priority(cT, NULL); + int sys_priority = 0; + + if (maxPriority == -1) + return -1; + + switch (priority) + { + case OBJC_THREAD_INTERACTIVE_PRIORITY: + sys_priority = maxPriority; + break; + case OBJC_THREAD_BACKGROUND_PRIORITY: + sys_priority = (maxPriority * 2) / 3; + break; + case OBJC_THREAD_LOW_PRIORITY: + sys_priority = maxPriority / 3; + break; + default: + return -1; + } + + if (sys_priority == 0) + return -1; + + /* Change the priority */ + if (cthread_priority(cT, sys_priority, 0) == KERN_SUCCESS) + return 0; + else + return -1; +} + +/* Return the current thread's priority. */ +int +__objc_thread_get_priority(void) +{ + objc_thread_t *t = objc_thread_id(); + cthread_t cT = (cthread_t) t; /* see objc_thread_id() */ + int basePriority; + int maxPriority; + int sys_priority = 0; + + int interactiveT, backgroundT, lowT; /* thresholds */ + + maxPriority = __mach_get_max_thread_priority(cT, &basePriority); + + if(maxPriority == -1) + return -1; + + if (basePriority > ( (maxPriority * 2) / 3)) + return OBJC_THREAD_INTERACTIVE_PRIORITY; + + if (basePriority > ( maxPriority / 3)) + return OBJC_THREAD_BACKGROUND_PRIORITY; + + return OBJC_THREAD_LOW_PRIORITY; +} + +/* Yield our process time to another thread. */ +void +__objc_thread_yield(void) +{ + cthread_yield(); +} + +/* Terminate the current thread. */ +int +__objc_thread_exit(void) +{ + /* exit the thread */ + cthread_exit(&__objc_thread_exit_status); + + /* Failed if we reached here */ + return -1; +} + +/* Returns an integer value which uniquely describes a thread. */ +objc_thread_t +__objc_thread_id(void) +{ + cthread_t self = cthread_self(); + + return *(objc_thread_t *)&self; +} + +/* Sets the thread's local storage pointer. */ +int +__objc_thread_set_data(void *value) +{ + cthread_set_data(cthread_self(), (any_t) value); + return 0; +} + +/* Returns the thread's local storage pointer. */ +void * +__objc_thread_get_data(void) +{ + return (void *) cthread_data(cthread_self()); +} + +/* Backend mutex functions */ + +/* Allocate a mutex. */ +int +__objc_mutex_allocate(objc_mutex_t mutex) +{ + int err = 0; + mutex->backend = objc_malloc(sizeof(struct mutex)); + + err = mutex_init((mutex_t)(mutex->backend)); + + if (err != 0) + { + objc_free(mutex->backend); + return -1; + } + else + return 0; +} + +/* Deallocate a mutex. */ +int +__objc_mutex_deallocate(objc_mutex_t mutex) +{ + mutex_clear((mutex_t)(mutex->backend)); + + objc_free(mutex->backend); + mutex->backend = NULL; + return 0; +} + +/* Grab a lock on a mutex. */ +int +__objc_mutex_lock(objc_mutex_t mutex) +{ + mutex_lock((mutex_t)(mutex->backend)); + return 0; +} + +/* Try to grab a lock on a mutex. */ +int +__objc_mutex_trylock(objc_mutex_t mutex) +{ + if (mutex_try_lock((mutex_t)(mutex->backend)) == 0) + return -1; + else + return 0; +} + +/* Unlock the mutex */ +int +__objc_mutex_unlock(objc_mutex_t mutex) +{ + mutex_unlock((mutex_t)(mutex->backend)); + return 0; +} + +/* Backend condition mutex functions */ + +/* Allocate a condition. */ +int +__objc_condition_allocate(objc_condition_t condition) +{ + condition->backend = objc_malloc(sizeof(struct condition)); + condition_init((condition_t)(condition->backend)); + return 0; +} + +/* Deallocate a condition. */ +int +__objc_condition_deallocate(objc_condition_t condition) +{ + condition_clear((condition_t)(condition->backend)); + objc_free(condition->backend); + condition->backend = NULL; + return 0; +} + +/* Wait on the condition */ +int +__objc_condition_wait(objc_condition_t condition, objc_mutex_t mutex) +{ + condition_wait((condition_t)(condition->backend), + (mutex_t)(mutex->backend)); + return 0; +} + +/* Wake up all threads waiting on this condition. */ +int +__objc_condition_broadcast(objc_condition_t condition) +{ + condition_broadcast((condition_t)(condition->backend)); + return 0; +} + +/* Wake up one thread waiting on this condition. */ +int +__objc_condition_signal(objc_condition_t condition) +{ + condition_signal((condition_t)(condition->backend)); + return 0; +} + +/* End of File */ diff --git a/gnustep-objc/thr-backends/mach.h b/gnustep-objc/thr-backends/mach.h new file mode 100644 index 00000000..641ea271 --- /dev/null +++ b/gnustep-objc/thr-backends/mach.h @@ -0,0 +1,25 @@ +/* GNU Objective C Runtime Thread Interface + Copyright (C) 1996, 1997 Free Software Foundation, Inc. + Contributed by Galen C. Hunt (gchunt@cs.rochester.edu) + +This file is part of GNU CC. + +GNU CC is free software; you can redistribute it and/or modify it under the +terms of the GNU General Public License as published by the Free Software +Foundation; either version 2, or (at your option) any later version. + +GNU CC is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +FOR A PARTICULAR PURPOSE. See the GNU General Public License for more +details. + +You should have received a copy of the GNU General Public License along with +GNU CC; see the file COPYING. If not, write to the Free Software +Foundation, 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + +/* As a special exception, if you link this library with files compiled with + GCC to produce an executable, this does not cause the resulting executable + to be covered by the GNU General Public License. This exception does not + however invalidate any other reasons why the executable file might be + covered by the GNU General Public License. */ diff --git a/gnustep-objc/thr-backends/posix.c b/gnustep-objc/thr-backends/posix.c new file mode 100644 index 00000000..2000b5fd --- /dev/null +++ b/gnustep-objc/thr-backends/posix.c @@ -0,0 +1,230 @@ +/* GNU Objective C Runtime Thread Interface for POSIX compliant threads + Copyright (C) 1996, 1997 Free Software Foundation, Inc. + Contributed by Galen C. Hunt (gchunt@cs.rochester.edu) + Modified for Linux/Pthreads by Kai-Uwe Sattler (kus@iti.cs.uni-magdeburg.de) + +This file is part of GNU CC. + +GNU CC is free software; you can redistribute it and/or modify it under the +terms of the GNU General Public License as published by the Free Software +Foundation; either version 2, or (at your option) any later version. + +GNU CC is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +FOR A PARTICULAR PURPOSE. See the GNU General Public License for more +details. + +You should have received a copy of the GNU General Public License +along with GNU CC; see the file COPYING. If not, write to +the Free Software Foundation, 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + +/* As a special exception, if you link this library with files compiled with + GCC to produce an executable, this does not cause the resulting executable + to be covered by the GNU General Public License. This exception does not + however invalidate any other reasons why the executable file might be + covered by the GNU General Public License. */ + +#include +#include "runtime.h" +#include +#include "objc-api.h" + +/* Key structure for maintaining thread specific storage */ +static pthread_key_t _objc_thread_storage; + +/* Backend initialization functions */ + +/* Initialize the threads subsystem. */ +int +__objc_init_thread_system(void) +{ + /* Initialize the thread storage key */ + return pthread_key_create(&_objc_thread_storage, NULL); +} + +/* Close the threads subsystem. */ +int +__objc_close_thread_system(void) +{ + return 0; +} + +/* Backend thread functions */ + +/* Create a new thread of execution. */ +objc_thread_t +__objc_thread_detach(void (*func)(void *arg), void *arg) +{ + objc_thread_t thread_id; + pthread_t new_thread_handle; + + if ( !(pthread_create(&new_thread_handle, NULL, (void *)func, arg)) ) + thread_id = *(objc_thread_t *)&new_thread_handle; + else + thread_id = NULL; + + return thread_id; +} + +/* Set the current thread's priority. */ +int +__objc_thread_set_priority(int priority) +{ + /* Not implemented yet */ + return -1; +} + +/* Return the current thread's priority. */ +int +__objc_thread_get_priority(void) +{ + /* Not implemented yet */ + return -1; +} + +/* Yield our process time to another thread. */ +void +__objc_thread_yield(void) +{ + sched_yield(); +} + +/* Terminate the current thread. */ +int +__objc_thread_exit(void) +{ + /* exit the thread */ + pthread_exit(&__objc_thread_exit_status); + + /* Failed if we reached here */ + return -1; +} + +/* Returns an integer value which uniquely describes a thread. */ +objc_thread_t +__objc_thread_id(void) +{ + pthread_t self = pthread_self(); + + return *(objc_thread_t *)&self; +} + +/* Sets the thread's local storage pointer. */ +int +__objc_thread_set_data(void *value) +{ + return pthread_setspecific(_objc_thread_storage, value); +} + +/* Returns the thread's local storage pointer. */ +void * +__objc_thread_get_data(void) +{ + return pthread_getspecific(_objc_thread_storage); +} + +/* Backend mutex functions */ + +/* Allocate a mutex. */ +int +__objc_mutex_allocate(objc_mutex_t mutex) +{ + mutex->backend = objc_malloc(sizeof(pthread_mutex_t)); + + if (pthread_mutex_init((pthread_mutex_t *)mutex->backend, NULL)) + { + objc_free(mutex->backend); + mutex->backend = NULL; + return -1; + } + + return 0; +} + +/* Deallocate a mutex. */ +int +__objc_mutex_deallocate(objc_mutex_t mutex) +{ + if (pthread_mutex_destroy((pthread_mutex_t *)mutex->backend)) + return -1; + + objc_free(mutex->backend); + mutex->backend = NULL; + return 0; +} + +/* Grab a lock on a mutex. */ +int +__objc_mutex_lock(objc_mutex_t mutex) +{ + return pthread_mutex_lock((pthread_mutex_t *)mutex->backend); +} + +/* Try to grab a lock on a mutex. */ +int +__objc_mutex_trylock(objc_mutex_t mutex) +{ + return pthread_mutex_trylock((pthread_mutex_t *)mutex->backend); +} + +/* Unlock the mutex */ +int +__objc_mutex_unlock(objc_mutex_t mutex) +{ + return pthread_mutex_unlock((pthread_mutex_t *)mutex->backend); +} + +/* Backend condition mutex functions */ + +/* Allocate a condition. */ +int +__objc_condition_allocate(objc_condition_t condition) +{ + condition->backend = objc_malloc(sizeof(pthread_cond_t)); + + if (pthread_cond_init((pthread_cond_t *)condition->backend, NULL)) + { + objc_free(condition->backend); + condition->backend = NULL; + return -1; + } + + return 0; +} + +/* Deallocate a condition. */ +int +__objc_condition_deallocate(objc_condition_t condition) +{ + if (pthread_cond_destroy((pthread_cond_t *)condition->backend)) + return -1; + + objc_free(condition->backend); + condition->backend = NULL; + return 0; +} + +/* Wait on the condition */ +int +__objc_condition_wait(objc_condition_t condition, objc_mutex_t mutex) +{ + return pthread_cond_wait((pthread_cond_t *)condition->backend, + (pthread_mutex_t *)mutex->backend); +} + +/* Wake up all threads waiting on this condition. */ +int +__objc_condition_broadcast(objc_condition_t condition) +{ + return pthread_cond_broadcast((pthread_cond_t *)condition->backend); +} + +/* Wake up one thread waiting on this condition. */ +int +__objc_condition_signal(objc_condition_t condition) +{ + return pthread_cond_signal((pthread_cond_t *)condition->backend); +} + +/* End of File */ diff --git a/gnustep-objc/thr-backends/posix.h b/gnustep-objc/thr-backends/posix.h new file mode 100644 index 00000000..641ea271 --- /dev/null +++ b/gnustep-objc/thr-backends/posix.h @@ -0,0 +1,25 @@ +/* GNU Objective C Runtime Thread Interface + Copyright (C) 1996, 1997 Free Software Foundation, Inc. + Contributed by Galen C. Hunt (gchunt@cs.rochester.edu) + +This file is part of GNU CC. + +GNU CC is free software; you can redistribute it and/or modify it under the +terms of the GNU General Public License as published by the Free Software +Foundation; either version 2, or (at your option) any later version. + +GNU CC is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +FOR A PARTICULAR PURPOSE. See the GNU General Public License for more +details. + +You should have received a copy of the GNU General Public License along with +GNU CC; see the file COPYING. If not, write to the Free Software +Foundation, 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + +/* As a special exception, if you link this library with files compiled with + GCC to produce an executable, this does not cause the resulting executable + to be covered by the GNU General Public License. This exception does not + however invalidate any other reasons why the executable file might be + covered by the GNU General Public License. */ diff --git a/gnustep-objc/thr-backends/pthreads.c b/gnustep-objc/thr-backends/pthreads.c new file mode 100644 index 00000000..2efdd15b --- /dev/null +++ b/gnustep-objc/thr-backends/pthreads.c @@ -0,0 +1,218 @@ +/* GNU Objective C Runtime Thread Implementation for PCThreads under GNU/Linux. + Copyright (C) 1996, 1997 Free Software Foundation, Inc. + Contributed by Scott Christley + Condition functions added by: Mircea Oancea + +This file is part of GNU CC. + +GNU CC is free software; you can redistribute it and/or modify it under the +terms of the GNU General Public License as published by the Free Software +Foundation; either version 2, or (at your option) any later version. + +GNU CC is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +FOR A PARTICULAR PURPOSE. See the GNU General Public License for more +details. + +You should have received a copy of the GNU General Public License +along with GNU CC; see the file COPYING. If not, write to +the Free Software Foundation, 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + +/* As a special exception, if you link this library with files compiled with + GCC to produce an executable, this does not cause the resulting executable + to be covered by the GNU General Public License. This exception does not + however invalidate any other reasons why the executable file might be + covered by the GNU General Public License. */ + +#include +#include +#include "runtime.h" + +/* Key structure for maintaining thread specific storage */ +static pthread_key_t _objc_thread_storage; + +/* Backend initialization functions */ + +/* Initialize the threads subsystem. */ +int +__objc_init_thread_system(void) +{ + /* Initialize the thread storage key */ + return pthread_key_create(&_objc_thread_storage, NULL); +} + +/* Close the threads subsystem. */ +int +__objc_close_thread_system(void) +{ + /* Destroy the thread storage key */ + /* Not implemented yet */ + /* return pthread_key_delete(&_objc_thread_storage); */ + return 0; +} + +/* Backend thread functions */ + +/* Create a new thread of execution. */ +objc_thread_t +__objc_thread_detach(void (*func)(void *arg), void *arg) +{ + objc_thread_t thread_id; + pthread_t new_thread_handle; + + if ( !(pthread_create(&new_thread_handle, NULL, (void *)func, arg)) ) + thread_id = *(objc_thread_t *)&new_thread_handle; + else + thread_id = NULL; + + return thread_id; +} + +/* Set the current thread's priority. */ +int +__objc_thread_set_priority(int priority) +{ + /* Not implemented yet */ + return -1; +} + +/* Return the current thread's priority. */ +int +__objc_thread_get_priority(void) +{ + /* Not implemented yet */ + return OBJC_THREAD_INTERACTIVE_PRIORITY; +} + +/* Yield our process time to another thread. */ +void +__objc_thread_yield(void) +{ + pthread_yield(NULL); +} + +/* Terminate the current thread. */ +int +__objc_thread_exit(void) +{ + /* exit the thread */ + pthread_exit(&__objc_thread_exit_status); + + /* Failed if we reached here */ + return -1; +} + +/* Returns an integer value which uniquely describes a thread. */ +objc_thread_t +__objc_thread_id(void) +{ + pthread_t self = pthread_self(); + + return *(objc_thread_t *)&self; +} + +/* Sets the thread's local storage pointer. */ +int +__objc_thread_set_data(void *value) +{ + return pthread_setspecific(_objc_thread_storage, value); +} + +/* Returns the thread's local storage pointer. */ +void * +__objc_thread_get_data(void) +{ + void *value = NULL; + + if ( !(pthread_getspecific(_objc_thread_storage, &value)) ) + return value; + + return NULL; +} + +/* Backend mutex functions */ + +/* Allocate a mutex. */ +int +__objc_mutex_allocate(objc_mutex_t mutex) +{ + if (pthread_mutex_init((pthread_mutex_t *)(&(mutex->backend)), NULL)) + return -1; + else + return 0; +} + +/* Deallocate a mutex. */ +int +__objc_mutex_deallocate(objc_mutex_t mutex) +{ + if (pthread_mutex_destroy((pthread_mutex_t *)(&(mutex->backend)))) + return -1; + else + return 0; +} + +/* Grab a lock on a mutex. */ +int +__objc_mutex_lock(objc_mutex_t mutex) +{ + return pthread_mutex_lock((pthread_mutex_t *)(&(mutex->backend))); +} + +/* Try to grab a lock on a mutex. */ +int +__objc_mutex_trylock(objc_mutex_t mutex) +{ + return pthread_mutex_trylock((pthread_mutex_t *)(&(mutex->backend))); +} + +/* Unlock the mutex */ +int +__objc_mutex_unlock(objc_mutex_t mutex) +{ + return pthread_mutex_unlock((pthread_mutex_t *)(&(mutex->backend))); +} + +/* Backend condition mutex functions */ + +/* Allocate a condition. */ +int +__objc_condition_allocate(objc_condition_t condition) +{ + if (pthread_cond_init((pthread_cond_t *)(&(condition->backend)), NULL)) + return -1; + else + return 0; +} + +/* Deallocate a condition. */ +int +__objc_condition_deallocate(objc_condition_t condition) +{ + return pthread_cond_destroy((pthread_cond_t *)(&(condition->backend))); +} + +/* Wait on the condition */ +int +__objc_condition_wait(objc_condition_t condition, objc_mutex_t mutex) +{ + return pthread_cond_wait((pthread_cond_t *)(&(condition->backend)), + (pthread_mutex_t *)(&(mutex->backend))); +} + +/* Wake up all threads waiting on this condition. */ +int +__objc_condition_broadcast(objc_condition_t condition) +{ + return pthread_cond_broadcast((pthread_cond_t *)(&(condition->backend))); +} + +/* Wake up one thread waiting on this condition. */ +int +__objc_condition_signal(objc_condition_t condition) +{ + return pthread_cond_signal((pthread_cond_t *)(&(condition->backend))); +} + +/* End of File */ diff --git a/gnustep-objc/thr-backends/pthreads.h b/gnustep-objc/thr-backends/pthreads.h new file mode 100644 index 00000000..641ea271 --- /dev/null +++ b/gnustep-objc/thr-backends/pthreads.h @@ -0,0 +1,25 @@ +/* GNU Objective C Runtime Thread Interface + Copyright (C) 1996, 1997 Free Software Foundation, Inc. + Contributed by Galen C. Hunt (gchunt@cs.rochester.edu) + +This file is part of GNU CC. + +GNU CC is free software; you can redistribute it and/or modify it under the +terms of the GNU General Public License as published by the Free Software +Foundation; either version 2, or (at your option) any later version. + +GNU CC is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +FOR A PARTICULAR PURPOSE. See the GNU General Public License for more +details. + +You should have received a copy of the GNU General Public License along with +GNU CC; see the file COPYING. If not, write to the Free Software +Foundation, 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + +/* As a special exception, if you link this library with files compiled with + GCC to produce an executable, this does not cause the resulting executable + to be covered by the GNU General Public License. This exception does not + however invalidate any other reasons why the executable file might be + covered by the GNU General Public License. */ diff --git a/gnustep-objc/thr-backends/single.c b/gnustep-objc/thr-backends/single.c new file mode 100644 index 00000000..dbf83ea5 --- /dev/null +++ b/gnustep-objc/thr-backends/single.c @@ -0,0 +1,49 @@ +/* GNU Objective C Runtime Thread Implementation + Copyright (C) 1996, 1997 Free Software Foundation, Inc. + Contributed by Galen C. Hunt (gchunt@cs.rochester.edu) + +This file is part of GNU CC. + +GNU CC is free software; you can redistribute it and/or modify it under the +terms of the GNU General Public License as published by the Free Software +Foundation; either version 2, or (at your option) any later version. + +GNU CC is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +FOR A PARTICULAR PURPOSE. See the GNU General Public License for more +details. + +You should have received a copy of the GNU General Public License along with +GNU CC; see the file COPYING. If not, write to the Free Software +Foundation, 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + +/* As a special exception, if you link this library with files compiled with + GCC to produce an executable, this does not cause the resulting executable + to be covered by the GNU General Public License. This exception does not + however invalidate any other reasons why the executable file might be + covered by the GNU General Public License. */ + +#include +#include "runtime.h" + +/* Thread local storage for a single thread */ +void *__objc_backend_thread_local_storage = NULL; + +/* Backend initialization functions */ + +/* Initialize the threads subsystem. */ +int +__objc_init_thread_system(void) +{ + /* No thread support available */ + return -1; +} + +/* Close the threads subsystem. */ +int +__objc_close_thread_system(void) +{ + /* No thread support available */ + return -1; +} diff --git a/gnustep-objc/thr-backends/single.h b/gnustep-objc/thr-backends/single.h new file mode 100644 index 00000000..0e346c49 --- /dev/null +++ b/gnustep-objc/thr-backends/single.h @@ -0,0 +1,173 @@ +/* GNU Objective C Runtime Thread Implementation + Copyright (C) 1996, 1997 Free Software Foundation, Inc. + Contributed by Galen C. Hunt (gchunt@cs.rochester.edu) + +This file is part of GNU CC. + +GNU CC is free software; you can redistribute it and/or modify it under the +terms of the GNU General Public License as published by the Free Software +Foundation; either version 2, or (at your option) any later version. + +GNU CC is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +FOR A PARTICULAR PURPOSE. See the GNU General Public License for more +details. + +You should have received a copy of the GNU General Public License along with +GNU CC; see the file COPYING. If not, write to the Free Software +Foundation, 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + +/* As a special exception, if you link this library with files compiled with + GCC to produce an executable, this does not cause the resulting executable + to be covered by the GNU General Public License. This exception does not + however invalidate any other reasons why the executable file might be + covered by the GNU General Public License. */ + +#include +#include "runtime.h" + +/* Backend thread functions */ + +/* Create a new thread of execution. */ +static inline objc_thread_t +__objc_thread_detach(void (*func)(void *arg), void *arg) +{ + /* No thread support available */ + return NULL; +} + +/* Set the current thread's priority. */ +static inline int +__objc_thread_set_priority(int priority) +{ + /* No thread support available */ + return -1; +} + +/* Return the current thread's priority. */ +static inline int +__objc_thread_get_priority(void) +{ + return OBJC_THREAD_INTERACTIVE_PRIORITY; +} + +/* Yield our process time to another thread. */ +static inline void +__objc_thread_yield(void) +{ + return; +} + +/* Terminate the current thread. */ +static inline int +__objc_thread_exit(void) +{ + /* No thread support available */ + /* Should we really exit the program */ + /* exit(&__objc_thread_exit_status); */ + return -1; +} + +/* Returns an integer value which uniquely describes a thread. */ +static inline objc_thread_t +__objc_thread_id(void) +{ + /* No thread support, use 1. */ + return (objc_thread_t)1; +} + +extern void *__objc_backend_thread_local_storage; + +/* Sets the thread's local storage pointer. */ +static inline int +__objc_thread_set_data(void *value) +{ + __objc_backend_thread_local_storage = value; + return 0; +} + +/* Returns the thread's local storage pointer. */ +static inline void * +__objc_thread_get_data(void) +{ + return __objc_backend_thread_local_storage; +} + +/* Backend mutex functions */ + +/* Allocate a mutex. */ +static inline int +__objc_mutex_allocate(objc_mutex_t mutex) +{ + return 0; +} + +/* Deallocate a mutex. */ +static inline int +__objc_mutex_deallocate(objc_mutex_t mutex) +{ + return 0; +} + +/* Grab a lock on a mutex. */ +static inline int +__objc_mutex_lock(objc_mutex_t mutex) +{ + /* There can only be one thread, so we always get the lock */ + return 0; +} + +/* Try to grab a lock on a mutex. */ +static inline int +__objc_mutex_trylock(objc_mutex_t mutex) +{ + /* There can only be one thread, so we always get the lock */ + return 0; +} + +/* Unlock the mutex */ +static inline int +__objc_mutex_unlock(objc_mutex_t mutex) +{ + return 0; +} + +/* Backend condition mutex functions */ + +/* Allocate a condition. */ +static inline int +__objc_condition_allocate(objc_condition_t condition) +{ + return 0; +} + +/* Deallocate a condition. */ +static inline int +__objc_condition_deallocate(objc_condition_t condition) +{ + return 0; +} + +/* Wait on the condition */ +static inline int +__objc_condition_wait(objc_condition_t condition, objc_mutex_t mutex) +{ + return 0; +} + +/* Wake up all threads waiting on this condition. */ +static inline int +__objc_condition_broadcast(objc_condition_t condition) +{ + return 0; +} + +/* Wake up one thread waiting on this condition. */ +static inline int +__objc_condition_signal(objc_condition_t condition) +{ + return 0; +} + +/* End of File */ diff --git a/gnustep-objc/thr-backends/solaris.c b/gnustep-objc/thr-backends/solaris.c new file mode 100644 index 00000000..19100f9b --- /dev/null +++ b/gnustep-objc/thr-backends/solaris.c @@ -0,0 +1,242 @@ +/* GNU Objective C Runtime Thread Interface + Copyright (C) 1996, 1997 Free Software Foundation, Inc. + Contributed by Galen C. Hunt (gchunt@cs.rochester.edu) + Conditions added by Mircea Oancea (mircea@first.elcom.pub.ro) + +This file is part of GNU CC. + +GNU CC is free software; you can redistribute it and/or modify it under the +terms of the GNU General Public License as published by the Free Software +Foundation; either version 2, or (at your option) any later version. + +GNU CC is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +FOR A PARTICULAR PURPOSE. See the GNU General Public License for more +details. + +You should have received a copy of the GNU General Public License along with +GNU CC; see the file COPYING. If not, write to the Free Software +Foundation, 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + +/* As a special exception, if you link this library with files compiled with + GCC to produce an executable, this does not cause the resulting executable + to be covered by the GNU General Public License. This exception does not + however invalidate any other reasons why the executable file might be + covered by the GNU General Public License. */ + +#include +#include "runtime.h" + +#include +#include +#include +#include + +#if OBJC_WITH_GC +# include +#endif +#if OBJC_WITH_SGC +# include +#endif + +/* Key structure for maintaining thread specific storage */ +static thread_key_t __objc_thread_data_key = 0; + +/* Backend initialization functions */ + +/* Initialize the threads subsystem. */ +int __objc_init_thread_system(void) { + /* Initialize the thread storage key */ + + printf("Launching Objective-C threading backend: %s ..\n", __FILE__); + fflush(stdout); + + return (thr_keycreate(&__objc_thread_data_key, NULL) == 0) ? 0 : -1; +} + +/* Close the threads subsystem. */ +int __objc_close_thread_system(void) { + return 0; +} + +/* Backend thread functions */ + +/* Create a new thread of execution. */ +objc_thread_t __objc_thread_detach(void (*func)(void *arg), void *arg) { + thread_t new_thread_id = 0; + + if ( +#if OBJC_WITH_SGC + SGC_thr_create +#elif OBJC_WITH_GC + GC_thr_create +#else + thr_create +#endif + (NULL, 0, (void *)func, arg, + THR_DETACHED | THR_NEW_LWP, + &new_thread_id) == 0) { + + if (sizeof(objc_thread_t) != sizeof(new_thread_id)) + abort(); + + return (objc_thread_t)new_thread_id; + } + else + return NULL; +} + +/* Set the current thread's priority. */ +int __objc_thread_set_priority(int priority) { + int sys_priority = 0; + + switch (priority) { + case OBJC_THREAD_INTERACTIVE_PRIORITY: + sys_priority = 300; + break; + default: + case OBJC_THREAD_BACKGROUND_PRIORITY: + sys_priority = 200; + break; + case OBJC_THREAD_LOW_PRIORITY: + sys_priority = 1000; + break; + } + + /* Change priority */ + return (thr_setprio(thr_self(), sys_priority) == 0) ? 0 : -1; +} + +/* Return the current thread's priority. */ +int __objc_thread_get_priority(void) { + int sys_priority; + + if (thr_getprio(thr_self(), &sys_priority) == 0){ + if (sys_priority >= 250) + return OBJC_THREAD_INTERACTIVE_PRIORITY; + else if (sys_priority >= 150) + return OBJC_THREAD_BACKGROUND_PRIORITY; + return OBJC_THREAD_LOW_PRIORITY; + } + + /* Couldn't get priority. */ + return -1; +} + +/* Yield our process time to another thread. */ +void __objc_thread_yield(void) { + thr_yield(); +} + +/* Terminate the current thread. */ +int __objc_thread_exit(void) { + /* exit the thread */ + thr_exit(&__objc_thread_exit_status); + + /* Failed if we reached here */ + return -1; +} + +/* Returns an integer value which uniquely describes a thread. */ +objc_thread_t __objc_thread_id(void) { + if (sizeof(objc_thread_t) != sizeof(thread_t)) + abort(); + + return (objc_thread_t)thr_self(); +} + +/* Sets the thread's local storage pointer. */ +int __objc_thread_set_data(void *value) { + return (thr_setspecific(__objc_thread_data_key, value) == 0) ? 0 : -1; +} + +/* Returns the thread's local storage pointer. */ +void *__objc_thread_get_data(void) { + void *value = NULL; + + if (thr_getspecific(__objc_thread_data_key, &value) == 0) + return value; + + return NULL; +} + +/* Backend mutex functions */ + +int __objc_mutex_allocate(objc_mutex_t mutex) { + mutex->backend = calloc(1, sizeof(mutex_t)); + if (mutex->backend == NULL) { + fprintf(stderr, "%s: could not allocate memory for Solaris mutex !\n" + __PRETTY_FUNCTION__); + return -1; + } + + if (mutex_init(mutex->backend, USYNC_THREAD, 0) != 0) { + free(mutex->backend); mutex->backend = NULL; + return -1; + } + return 0; +} + +int __objc_mutex_deallocate(objc_mutex_t mutex) { + if (mutex->backend) { + mutex_destroy(mutex->backend); + free(mutex->backend); mutex->backend = NULL; + return 0; + } + else + return -1; +} + +int __objc_mutex_lock(objc_mutex_t mutex) { + return (mutex_lock(mutex->backend) != 0) ? -1 : 0; +} + +int __objc_mutex_trylock(objc_mutex_t mutex) { + return (mutex_trylock(mutex->backend) != 0) ? -1 : 0; +} + +int __objc_mutex_unlock(objc_mutex_t mutex) { + return (mutex_unlock(mutex->backend) != 0) ? -1 : 0; +} + +/* Backend condition mutex functions */ + +int __objc_condition_allocate(objc_condition_t condition) { + condition->backend = calloc(1, sizeof(cond_t)); + if (condition->backend == NULL) { + fprintf(stderr, "%s: could not allocate memory for Solaris mutex !\n" + __PRETTY_FUNCTION__); + return -1; + } + + if (cond_init(condition->backend, USYNC_THREAD, 0) != 0) { + free(condition->backend); condition->backend = NULL; + return -1; + } + return 0; +} + +int __objc_condition_deallocate(objc_condition_t condition) { + if (condition->backend) { + cond_destroy(condition->backend); + free(condition->backend); condition->backend = NULL; + return 0; + } + else + return -1; +} + +int __objc_condition_wait(objc_condition_t condition, objc_mutex_t mutex) { + return cond_wait(condition->backend, mutex->backend); +} + +/* Wake up all threads waiting on this condition. */ +int __objc_condition_broadcast(objc_condition_t condition) { + return cond_broadcast(condition->backend); +} + +/* Wake up one thread waiting on this condition. */ +int __objc_condition_signal(objc_condition_t condition) { + return cond_signal(condition->backend); +} diff --git a/gnustep-objc/thr-backends/solaris.h b/gnustep-objc/thr-backends/solaris.h new file mode 100644 index 00000000..641ea271 --- /dev/null +++ b/gnustep-objc/thr-backends/solaris.h @@ -0,0 +1,25 @@ +/* GNU Objective C Runtime Thread Interface + Copyright (C) 1996, 1997 Free Software Foundation, Inc. + Contributed by Galen C. Hunt (gchunt@cs.rochester.edu) + +This file is part of GNU CC. + +GNU CC is free software; you can redistribute it and/or modify it under the +terms of the GNU General Public License as published by the Free Software +Foundation; either version 2, or (at your option) any later version. + +GNU CC is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +FOR A PARTICULAR PURPOSE. See the GNU General Public License for more +details. + +You should have received a copy of the GNU General Public License along with +GNU CC; see the file COPYING. If not, write to the Free Software +Foundation, 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + +/* As a special exception, if you link this library with files compiled with + GCC to produce an executable, this does not cause the resulting executable + to be covered by the GNU General Public License. This exception does not + however invalidate any other reasons why the executable file might be + covered by the GNU General Public License. */ diff --git a/gnustep-objc/thr-backends/win32.c b/gnustep-objc/thr-backends/win32.c new file mode 100644 index 00000000..8570ffd9 --- /dev/null +++ b/gnustep-objc/thr-backends/win32.c @@ -0,0 +1,272 @@ +/* GNU Objective C Runtime Thread Interface - Win32 Implementation + Copyright (C) 1996, 1997 Free Software Foundation, Inc. + Contributed by Galen C. Hunt (gchunt@cs.rochester.edu) + +This file is part of GNU CC. + +GNU CC is free software; you can redistribute it and/or modify it under the +terms of the GNU General Public License as published by the Free Software +Foundation; either version 2, or (at your option) any later version. + +GNU CC is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +FOR A PARTICULAR PURPOSE. See the GNU General Public License for more +details. + +You should have received a copy of the GNU General Public License along with +GNU CC; see the file COPYING. If not, write to the Free Software +Foundation, 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + +/* As a special exception, if you link this library with files compiled with + GCC to produce an executable, this does not cause the resulting executable + to be covered by the GNU General Public License. This exception does not + however invalidate any other reasons why the executable file might be + covered by the GNU General Public License. */ + +#include +#include "runtime.h" + +#ifndef __OBJC__ +#define __OBJC__ +#endif +#include + +/* Key structure for maintaining thread specific storage */ +static DWORD __objc_data_tls = (DWORD)-1; + +/* Backend initialization functions */ + +/* Initialize the threads subsystem. */ +int +__objc_init_thread_system(void) +{ + /* Initialize the thread storage key */ + if ((__objc_data_tls = TlsAlloc()) != (DWORD)-1) + return 0; + else + return -1; +} + +/* Close the threads subsystem. */ +int +__objc_close_thread_system(void) +{ + if (__objc_data_tls != (DWORD)-1) + TlsFree(__objc_data_tls); + return 0; +} + +/* Backend thread functions */ + +/* Create a new thread of execution. */ +objc_thread_t +__objc_thread_detach(void (*func)(void *arg), void *arg) +{ + DWORD thread_id = 0; + HANDLE win32_handle; + + if (!(win32_handle = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)func, + arg, 0, &thread_id))) + thread_id = 0; + + return (objc_thread_t)thread_id; +} + +/* Set the current thread's priority. */ +int +__objc_thread_set_priority(int priority) +{ + int sys_priority = 0; + + switch (priority) + { + case OBJC_THREAD_INTERACTIVE_PRIORITY: + sys_priority = THREAD_PRIORITY_NORMAL; + break; + default: + case OBJC_THREAD_BACKGROUND_PRIORITY: + sys_priority = THREAD_PRIORITY_BELOW_NORMAL; + break; + case OBJC_THREAD_LOW_PRIORITY: + sys_priority = THREAD_PRIORITY_LOWEST; + break; + } + + /* Change priority */ + if (SetThreadPriority(GetCurrentThread(), sys_priority)) + return 0; + else + return -1; +} + +/* Return the current thread's priority. */ +int +__objc_thread_get_priority(void) +{ + int sys_priority; + + sys_priority = GetThreadPriority(GetCurrentThread()); + + switch (sys_priority) + { + case THREAD_PRIORITY_HIGHEST: + case THREAD_PRIORITY_TIME_CRITICAL: + case THREAD_PRIORITY_ABOVE_NORMAL: + case THREAD_PRIORITY_NORMAL: + return OBJC_THREAD_INTERACTIVE_PRIORITY; + + default: + case THREAD_PRIORITY_BELOW_NORMAL: + return OBJC_THREAD_BACKGROUND_PRIORITY; + + case THREAD_PRIORITY_IDLE: + case THREAD_PRIORITY_LOWEST: + return OBJC_THREAD_LOW_PRIORITY; + } + + /* Couldn't get priority. */ + return -1; +} + +/* Yield our process time to another thread. */ +void +__objc_thread_yield(void) +{ + Sleep(0); +} + +/* Terminate the current thread. */ +int +__objc_thread_exit(void) +{ + /* exit the thread */ + ExitThread(__objc_thread_exit_status); + + /* Failed if we reached here */ + return -1; +} + +/* Returns an integer value which uniquely describes a thread. */ +objc_thread_t +__objc_thread_id(void) +{ + return (objc_thread_t)GetCurrentThreadId(); +} + +/* Sets the thread's local storage pointer. */ +int +__objc_thread_set_data(void *value) +{ + if (TlsSetValue(__objc_data_tls, value)) + return 0; + else + return -1; +} + +/* Returns the thread's local storage pointer. */ +void * +__objc_thread_get_data(void) +{ + return TlsGetValue(__objc_data_tls); /* Return thread data. */ +} + +/* Backend mutex functions */ + +/* Allocate a mutex. */ +int +__objc_mutex_allocate(objc_mutex_t mutex) +{ + if ((mutex->backend = (void *)CreateMutex(NULL, 0, NULL)) == NULL) + return -1; + else + return 0; +} + +/* Deallocate a mutex. */ +int +__objc_mutex_deallocate(objc_mutex_t mutex) +{ + CloseHandle((HANDLE)(mutex->backend)); + return 0; +} + +/* Grab a lock on a mutex. */ +int +__objc_mutex_lock(objc_mutex_t mutex) +{ + int status; + + status = WaitForSingleObject((HANDLE)(mutex->backend), INFINITE); + if (status != WAIT_OBJECT_0 && status != WAIT_ABANDONED) + return -1; + else + return 0; +} + +/* Try to grab a lock on a mutex. */ +int +__objc_mutex_trylock(objc_mutex_t mutex) +{ + int status; + + status = WaitForSingleObject((HANDLE)(mutex->backend), 0); + if (status != WAIT_OBJECT_0 && status != WAIT_ABANDONED) + return -1; + else + return 0; +} + +/* Unlock the mutex */ +int +__objc_mutex_unlock(objc_mutex_t mutex) +{ + if (ReleaseMutex((HANDLE)(mutex->backend)) == 0) + return -1; + else + return 0; +} + +/* Backend condition mutex functions */ + +/* Allocate a condition. */ +int +__objc_condition_allocate(objc_condition_t condition) +{ + /* Unimplemented. */ + return -1; +} + +/* Deallocate a condition. */ +int +__objc_condition_deallocate(objc_condition_t condition) +{ + /* Unimplemented. */ + return -1; +} + +/* Wait on the condition */ +int +__objc_condition_wait(objc_condition_t condition, objc_mutex_t mutex) +{ + /* Unimplemented. */ + return -1; +} + +/* Wake up all threads waiting on this condition. */ +int +__objc_condition_broadcast(objc_condition_t condition) +{ + /* Unimplemented. */ + return -1; +} + +/* Wake up one thread waiting on this condition. */ +int +__objc_condition_signal(objc_condition_t condition) +{ + /* Unimplemented. */ + return -1; +} + +/* End of File */ diff --git a/gnustep-objc/thr-backends/win32.h b/gnustep-objc/thr-backends/win32.h new file mode 100644 index 00000000..641ea271 --- /dev/null +++ b/gnustep-objc/thr-backends/win32.h @@ -0,0 +1,25 @@ +/* GNU Objective C Runtime Thread Interface + Copyright (C) 1996, 1997 Free Software Foundation, Inc. + Contributed by Galen C. Hunt (gchunt@cs.rochester.edu) + +This file is part of GNU CC. + +GNU CC is free software; you can redistribute it and/or modify it under the +terms of the GNU General Public License as published by the Free Software +Foundation; either version 2, or (at your option) any later version. + +GNU CC is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +FOR A PARTICULAR PURPOSE. See the GNU General Public License for more +details. + +You should have received a copy of the GNU General Public License along with +GNU CC; see the file COPYING. If not, write to the Free Software +Foundation, 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + +/* As a special exception, if you link this library with files compiled with + GCC to produce an executable, this does not cause the resulting executable + to be covered by the GNU General Public License. This exception does not + however invalidate any other reasons why the executable file might be + covered by the GNU General Public License. */ diff --git a/gnustep-objc/thr.c b/gnustep-objc/thr.c new file mode 100644 index 00000000..02aa7613 --- /dev/null +++ b/gnustep-objc/thr.c @@ -0,0 +1,548 @@ +/* GNU Objective C Runtime Thread Interface + Copyright (C) 1996, 1997 Free Software Foundation, Inc. + Contributed by Galen C. Hunt (gchunt@cs.rochester.edu) + +This file is part of GNU CC. + +GNU CC is free software; you can redistribute it and/or modify it under the +terms of the GNU General Public License as published by the Free Software +Foundation; either version 2, or (at your option) any later version. + +GNU CC is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +FOR A PARTICULAR PURPOSE. See the GNU General Public License for more +details. + +You should have received a copy of the GNU General Public License along with +GNU CC; see the file COPYING. If not, write to the Free Software +Foundation, 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + +/* As a special exception, if you link this library with files compiled with + GCC to produce an executable, this does not cause the resulting executable + to be covered by the GNU General Public License. This exception does not + however invalidate any other reasons why the executable file might be + covered by the GNU General Public License. */ + +#include +#include "runtime.h" +#include "objc-api.h" +#include "thr.h" +//#include "thr-backend.h" +//#include OBJC_THREAD_BACKEND +#include "thr-backends/single.h" + +#if OBJC_WITH_GC +# include "gc/gc.h" +#endif + +/* Global exit status. */ +int __objc_thread_exit_status = 0; + +/* Flag which lets us know if we ever became multi threaded */ +int __objc_is_multi_threaded = 0; + +/* The hook function called when the runtime becomes multi threaded */ +objc_thread_callback _objc_became_multi_threaded = NULL; + +/* + Use this to set the hook function that will be called when the + runtime initially becomes multi threaded. + The hook function is only called once, meaning only when the + 2nd thread is spawned, not for each and every thread. + + It returns the previous hook function or NULL if there is none. + + A program outside of the runtime could set this to some function so + it can be informed; for example, the GNUstep Base Library sets it + so it can implement the NSBecomingMultiThreaded notification. + */ +objc_thread_callback objc_set_thread_callback(objc_thread_callback func) +{ + objc_thread_callback temp = _objc_became_multi_threaded; + _objc_became_multi_threaded = func; + return temp; +} + +/* + Private functions + + These functions are utilized by the frontend, but they are not + considered part of the public interface. + */ + +/* + First function called in a thread, starts everything else. + + This function is passed to the backend by objc_thread_detach + as the starting function for a new thread. + */ +struct __objc_thread_start_state +{ + SEL selector; + id object; + id argument; +}; + +static volatile void +__objc_thread_detach_function(struct __objc_thread_start_state *istate) +{ + /* Valid state? */ + if (istate) { + id (*imp)(id,SEL,id); + SEL selector = istate->selector; + id object = istate->object; + id argument = istate->argument; + + /* Don't need anymore so free it */ + objc_free(istate); + + /* Clear out the thread local storage */ + objc_thread_set_data(NULL); + + /* Check to see if we just became multi threaded */ + if (!__objc_is_multi_threaded) + { + __objc_is_multi_threaded = 1; + + /* Call the hook function */ + if (_objc_became_multi_threaded != NULL) + (*_objc_became_multi_threaded)(); + } + + /* Call the method */ + if ((imp = (id(*)(id, SEL, id))objc_msg_lookup(object, selector))) + (*imp)(object, selector, argument); + else + objc_error(object, OBJC_ERR_UNIMPLEMENTED, + "objc_thread_detach called with bad selector.\n"); + } + else + objc_error(nil, OBJC_ERR_BAD_STATE, + "objc_thread_detach called with NULL state.\n"); + + /* Exit the thread */ + objc_thread_exit(); +} + +/* + Frontend functions + + These functions constitute the public interface to the Objective-C thread + and mutex functionality. + */ + +/* Frontend thread functions */ + +/* + Detach a new thread of execution and return its id. Returns NULL if fails. + Thread is started by sending message with selector to object. Message + takes a single argument. + */ +objc_thread_t +objc_thread_detach(SEL selector, id object, id argument) +{ + struct __objc_thread_start_state *istate; + objc_thread_t thread_id = NULL; + + /* Allocate the state structure */ + if (!(istate = (struct __objc_thread_start_state *) + objc_malloc(sizeof(*istate)))) + return NULL; + + /* Initialize the state structure */ + istate->selector = selector; + istate->object = object; + istate->argument = argument; + + /* lock access */ + objc_mutex_lock(__objc_runtime_mutex); + + /* Call the backend to spawn the thread */ + if ((thread_id = __objc_thread_detach((void *)__objc_thread_detach_function, + istate)) == NULL) + { + /* failed! */ + objc_mutex_unlock(__objc_runtime_mutex); + objc_free(istate); + return NULL; + } + + /* Increment our thread counter */ + __objc_runtime_threads_alive++; + objc_mutex_unlock(__objc_runtime_mutex); + + return thread_id; +} + +/* Set the current thread's priority. */ +int +objc_thread_set_priority(int priority) +{ + /* Call the backend */ + return __objc_thread_set_priority(priority); +} + +/* Return the current thread's priority. */ +int +objc_thread_get_priority(void) +{ + /* Call the backend */ + return __objc_thread_get_priority(); +} + +/* + Yield our process time to another thread. Any BUSY waiting that is done + by a thread should use this function to make sure that other threads can + make progress even on a lazy uniprocessor system. + */ +void +objc_thread_yield(void) +{ + /* Call the backend */ + __objc_thread_yield(); +} + +/* + Terminate the current tread. Doesn't return. + Actually, if it failed returns -1. + */ +int +objc_thread_exit(void) +{ + /* Decrement our counter of the number of threads alive */ + objc_mutex_lock(__objc_runtime_mutex); + __objc_runtime_threads_alive--; + objc_mutex_unlock(__objc_runtime_mutex); + + /* Call the backend to terminate the thread */ + return __objc_thread_exit(); +} + +/* + Returns an integer value which uniquely describes a thread. Must not be + NULL which is reserved as a marker for "no thread". + */ +objc_thread_t objc_thread_id(void) { + /* Call the backend */ + return __objc_thread_id(); +} + +/* + Sets the thread's local storage pointer. + Returns 0 if successful or -1 if failed. + */ +int +objc_thread_set_data(void *value) +{ + /* Call the backend */ + return __objc_thread_set_data(value); +} + +/* + Returns the thread's local storage pointer. Returns NULL on failure. + */ +void * +objc_thread_get_data(void) +{ + /* Call the backend */ + return __objc_thread_get_data(); +} + +/* Frontend mutex functions */ + +/* + Allocate a mutex. Return the mutex pointer if successful or NULL if the + allocation failed for any reason. + */ +objc_mutex_t objc_mutex_allocate(void) { + objc_mutex_t mutex; + + /* Allocate the mutex structure */ + if (!(mutex = (objc_mutex_t)objc_malloc(sizeof(struct objc_mutex)))) { + fprintf(stderr, "%s: could not allocate memory for mutex !\n", + __PRETTY_FUNCTION__); + return NULL; + } + + /* Call backend to create the mutex */ + if (__objc_mutex_allocate(mutex)) { + fprintf(stderr, "%s: backend could not create mutex !\n", + __PRETTY_FUNCTION__); + + /* failed! */ + objc_free(mutex); mutex = NULL; + return NULL; + } + + /* Initialize mutex */ + mutex->owner = NULL; + mutex->depth = 0; + return mutex; +} + +/* + Deallocate a mutex. Note that this includes an implicit mutex_lock to + insure that no one else is using the lock. It is legal to deallocate + a lock if we have a lock on it, but illegal to deallocate a lock held + by anyone else. + Returns the number of locks on the thread. (1 for deallocate). + */ +int objc_mutex_deallocate(objc_mutex_t mutex) { + int depth; + + /* Valid mutex? */ + if (mutex == NULL) { + fprintf(stderr, "%s: tried to deallocate invalid mutex !\n", + __PRETTY_FUNCTION__); + return -1; + } + + /* Acquire lock on mutex */ + depth = objc_mutex_lock(mutex); + + /* Call backend to destroy mutex */ + if (__objc_mutex_deallocate(mutex)) { + fprintf(stderr, "%s: deallocate of mutex failed !\n", __PRETTY_FUNCTION__); + return -1; + } + + /* Free the mutex structure */ + objc_free(mutex); + + /* Return last depth */ + return depth; +} + +/* + Grab a lock on a mutex. If this thread already has a lock on this mutex + then we increment the lock count. If another thread has a lock on the + mutex we block and wait for the thread to release the lock. + Returns the lock count on the mutex held by this thread. + */ +int objc_mutex_lock(objc_mutex_t mutex) { + objc_thread_t thread_id; + int status; + + /* Valid mutex? */ + if (mutex == NULL) { + fprintf(stderr, "%s: tried to lock invalid mutex !\n", __PRETTY_FUNCTION__); + abort(); + return -1; + } + + /* If we already own the lock then increment depth */ + thread_id = objc_thread_id(); + if (mutex->owner == thread_id) + return (++mutex->depth); + + /* Call the backend to lock the mutex */ + status = __objc_mutex_lock(mutex); + + /* Failed? */ + if (status != 0) { + fprintf(stderr, "%s: lock mutex failed !\n", __PRETTY_FUNCTION__); + return status; + } + + /* Successfully locked the thread */ + mutex->owner = thread_id; + return mutex->depth = 1; +} + +/* + Try to grab a lock on a mutex. If this thread already has a lock on + this mutex then we increment the lock count and return it. If another + thread has a lock on the mutex returns -1. + */ +int +objc_mutex_trylock(objc_mutex_t mutex) +{ + objc_thread_t thread_id; + int status; + + /* Valid mutex? */ + if (!mutex) + return -1; + + /* If we already own the lock then increment depth */ + thread_id = objc_thread_id(); + if (mutex->owner == thread_id) + return ++mutex->depth; + + /* Call the backend to try to lock the mutex */ + status = __objc_mutex_trylock(mutex); + + /* Failed? */ + if (status) + return status; + + /* Successfully locked the thread */ + mutex->owner = thread_id; + return mutex->depth = 1; +} + +/* + Unlocks the mutex by one level. + Decrements the lock count on this mutex by one. + If the lock count reaches zero, release the lock on the mutex. + Returns the lock count on the mutex. + It is an error to attempt to unlock a mutex which this thread + doesn't hold in which case return -1 and the mutex is unaffected. + */ +int +objc_mutex_unlock(objc_mutex_t mutex) +{ + objc_thread_t thread_id; + int status; + + /* Valid mutex? */ + if (!mutex) + return -1; + + /* If another thread owns the lock then abort */ + thread_id = objc_thread_id(); + if (mutex->owner != thread_id) + return -1; + + /* Decrement depth and return */ + if (mutex->depth > 1) + return --mutex->depth; + + /* Depth down to zero so we are no longer the owner */ + mutex->depth = 0; + mutex->owner = NULL; + + /* Have the backend unlock the mutex */ + status = __objc_mutex_unlock(mutex); + + /* Failed? */ + if (status) + return status; + + return 0; +} + +/* Frontend condition mutex functions */ + +/* + Allocate a condition. Return the condition pointer if successful or NULL + if the allocation failed for any reason. + */ +objc_condition_t objc_condition_allocate(void) { + objc_condition_t condition; + + /* Allocate the condition mutex structure */ + if (!(condition = + (objc_condition_t)objc_malloc(sizeof(struct objc_condition)))) + return NULL; + + /* Call the backend to create the condition mutex */ + if (__objc_condition_allocate(condition)) + { + /* failed! */ + objc_free(condition); + return NULL; + } + + /* Success! */ + return condition; +} + +/* + Deallocate a condition. Note that this includes an implicit + condition_broadcast to insure that waiting threads have the opportunity + to wake. It is legal to dealloc a condition only if no other + thread is/will be using it. Here we do NOT check for other threads + waiting but just wake them up. + */ +int +objc_condition_deallocate(objc_condition_t condition) +{ + /* Broadcast the condition */ + if (objc_condition_broadcast(condition)) + return -1; + + /* Call the backend to destroy */ + if (__objc_condition_deallocate(condition)) + return -1; + + /* Free the condition mutex structure */ + objc_free(condition); + + return 0; +} + +/* + Wait on the condition unlocking the mutex until objc_condition_signal() + or objc_condition_broadcast() are called for the same condition. The + given mutex *must* have the depth set to 1 so that it can be unlocked + here, so that someone else can lock it and signal/broadcast the condition. + The mutex is used to lock access to the shared data that make up the + "condition" predicate. + */ +int +objc_condition_wait(objc_condition_t condition, objc_mutex_t mutex) +{ + objc_thread_t thread_id; + + /* Valid arguments? */ + if (!mutex || !condition) + return -1; + + /* Make sure we are owner of mutex */ + thread_id = objc_thread_id(); + if (mutex->owner != thread_id) + return -1; + + /* Cannot be locked more than once */ + if (mutex->depth > 1) + return -1; + + /* Virtually unlock the mutex */ + mutex->depth = 0; + mutex->owner = (objc_thread_t)NULL; + + /* Call the backend to wait */ + __objc_condition_wait(condition, mutex); + + /* Make ourselves owner of the mutex */ + mutex->owner = thread_id; + mutex->depth = 1; + + return 0; +} + +/* + Wake up all threads waiting on this condition. It is recommended that + the called would lock the same mutex as the threads in objc_condition_wait + before changing the "condition predicate" and make this call and unlock it + right away after this call. + */ +int +objc_condition_broadcast(objc_condition_t condition) +{ + /* Valid condition mutex? */ + if (!condition) + return -1; + + return __objc_condition_broadcast(condition); +} + +/* + Wake up one thread waiting on this condition. It is recommended that + the called would lock the same mutex as the threads in objc_condition_wait + before changing the "condition predicate" and make this call and unlock it + right away after this call. + */ +int +objc_condition_signal(objc_condition_t condition) +{ + /* Valid condition mutex? */ + if (!condition) + return -1; + + return __objc_condition_signal(condition); +} + +/* End of File */ diff --git a/gnustep-objc/thr.h b/gnustep-objc/thr.h new file mode 100644 index 00000000..cef52732 --- /dev/null +++ b/gnustep-objc/thr.h @@ -0,0 +1,115 @@ +/* Thread and mutex controls for Objective C. + Copyright (C) 1996, 1997 Free Software Foundation, Inc. + Contributed by Galen C. Hunt (gchunt@cs.rochester.edu) + +This file is part of GNU CC. + +GNU CC is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU CC is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +GNU CC is free software; you can redistribute it and/or modify it under the +terms of the GNU General Public License as published by the Free Software +Foundation; either version 2, or (at your option) any later version. + +GNU CC is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +FOR A PARTICULAR PURPOSE. See the GNU General Public License for more +details. + +You should have received a copy of the GNU General Public License along with +GNU CC; see the file COPYING. If not, write to the Free Software +Foundation, 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + +/* As a special exception, if you link this library with files + compiled with GCC to produce an executable, this does not cause + the resulting executable to be covered by the GNU General Public License. + This exception does not however invalidate any other reasons why + the executable file might be covered by the GNU General Public License. */ + + +#ifndef __thread_INCLUDE_GNU +#define __thread_INCLUDE_GNU + +#include "objc/objc.h" + +/************************************************************************* + * Universal static variables: + */ +extern int __objc_thread_exit_status; /* Global exit status. */ + +/******** + * Thread safe implementation types and functions. + */ + +/* Thread priorities */ +#define OBJC_THREAD_INTERACTIVE_PRIORITY 2 +#define OBJC_THREAD_BACKGROUND_PRIORITY 1 +#define OBJC_THREAD_LOW_PRIORITY 0 + +/* A thread */ +typedef void * objc_thread_t; + +/* This structure represents a single mutual exclusion lock. */ +struct objc_mutex +{ + volatile objc_thread_t owner; /* Id of thread that owns. */ + volatile int depth; /* # of acquires. */ + void *backend; /* Specific to backend */ +}; +typedef struct objc_mutex *objc_mutex_t; + +/* This structure represents a single condition mutex */ +struct objc_condition +{ + void * backend; /* Specific to backend */ +}; +typedef struct objc_condition *objc_condition_t; + +/* Frontend mutex functions */ +objc_mutex_t objc_mutex_allocate(void); +int objc_mutex_deallocate(objc_mutex_t mutex); +int objc_mutex_lock(objc_mutex_t mutex); +int objc_mutex_unlock(objc_mutex_t mutex); +int objc_mutex_trylock(objc_mutex_t mutex); + +/* Frontend condition mutex functions */ +objc_condition_t objc_condition_allocate(void); +int objc_condition_deallocate(objc_condition_t condition); +int objc_condition_wait(objc_condition_t condition, objc_mutex_t mutex); +int objc_condition_signal(objc_condition_t condition); +int objc_condition_broadcast(objc_condition_t condition); + +/* Frontend thread functions */ +objc_thread_t objc_thread_detach(SEL selector, id object, id argument); +void objc_thread_yield(void); +int objc_thread_exit(void); +int objc_thread_set_priority(int priority); +int objc_thread_get_priority(void); +void * objc_thread_get_data(void); +int objc_thread_set_data(void *value); +objc_thread_t objc_thread_id(void); + +/* + Use this to set the hook function that will be called when the + runtime initially becomes multi threaded. + The hook function is only called once, meaning only when the + 2nd thread is spawned, not for each and every thread. + + It returns the previous hook function or NULL if there is none. + + A program outside of the runtime could set this to some function so + it can be informed; for example, the GNUstep Base Library sets it + so it can implement the NSBecomingMultiThreaded notification. + */ +typedef void (*objc_thread_callback)(); +objc_thread_callback objc_set_thread_callback(objc_thread_callback func); + +#endif /* not __thread_INCLUDE_GNU */ diff --git a/gnustep-objc/typedstream.h b/gnustep-objc/typedstream.h new file mode 100644 index 00000000..18114444 --- /dev/null +++ b/gnustep-objc/typedstream.h @@ -0,0 +1,132 @@ +/* GNU Objective-C Typed Streams interface. + Copyright (C) 1993, 1995 Free Software Foundation, Inc. + +This file is part of GNU CC. + +GNU CC is free software; you can redistribute it and/or modify it +under the terms of the GNU General Public License as published by the +Free Software Foundation; either version 2, or (at your option) any +later version. + +GNU CC is distributed in the hope that it will be useful, but WITHOUT +ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public +License for more details. + +You should have received a copy of the GNU General Public License +along with GNU CC; see the file COPYING. If not, write to +the Free Software Foundation, 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + +/* As a special exception, if you link this library with files compiled + with GCC to produce an executable, this does not cause the resulting + executable to be covered by the GNU General Public License. This + exception does not however invalidate any other reasons why the + executable file might be covered by the GNU General Public License. */ + +#ifndef __typedstream_INCLUDE_GNU +#define __typedstream_INCLUDE_GNU + +#include "objc.h" +#include "hash.h" +#include + +typedef int (*objc_typed_read_func)(void*, char*, int); +typedef int (*objc_typed_write_func)(void*, const char*, int); +typedef int (*objc_typed_flush_func)(void*); +typedef int (*objc_typed_eof_func)(void*); + +#define OBJC_READONLY 0x01 +#define OBJC_WRITEONLY 0x02 + +#define OBJC_MANAGED_STREAM 0x01 +#define OBJC_FILE_STREAM 0x02 +#define OBJC_MEMORY_STREAM 0x04 + +#define OBJC_TYPED_STREAM_VERSION 0x01 + +typedef struct objc_typed_stream { + void* physical; + cache_ptr object_table; /* read/written objects */ + cache_ptr stream_table; /* other read/written but shared things.. */ + cache_ptr class_table; /* class version mapping */ + cache_ptr object_refs; /* forward references */ + int mode; /* OBJC_READONLY or OBJC_WRITEONLY */ + int type; /* MANAGED, FILE, MEMORY etc bit string */ + int version; /* version used when writing */ + int writing_root_p; + objc_typed_read_func read; + objc_typed_write_func write; + objc_typed_eof_func eof; + objc_typed_flush_func flush; +} TypedStream; + +/* opcode masks */ +#define _B_VALUE 0x1fU +#define _B_CODE 0xe0U +#define _B_SIGN 0x10U +#define _B_NUMBER 0x0fU + +/* standard opcodes */ +#define _B_INVALID 0x00U +#define _B_SINT 0x20U +#define _B_NINT 0x40U +#define _B_SSTR 0x60U +#define _B_NSTR 0x80U +#define _B_RCOMM 0xa0U +#define _B_UCOMM 0xc0U +#define _B_EXT 0xe0U + +/* eXtension opcodes */ +#define _BX_OBJECT 0x00U +#define _BX_CLASS 0x01U +#define _BX_SEL 0x02U +#define _BX_OBJREF 0x03U +#define _BX_OBJROOT 0x04U +#define _BX_EXT 0x1fU + +/* +** Read and write objects as specified by TYPE. All the `last' +** arguments are pointers to the objects to read/write. +*/ + +int objc_write_type (TypedStream* stream, const char* type, const void* data); +int objc_read_type (TypedStream* stream, const char* type, void* data); + +int objc_write_types (TypedStream* stream, const char* type, ...); +int objc_read_types (TypedStream* stream, const char* type, ...); + +int objc_write_object_reference (TypedStream* stream, id object); +int objc_write_root_object (TypedStream* stream, id object); + +long objc_get_stream_class_version (TypedStream* stream, Class class); + + +/* +** Convenience functions +*/ + +int objc_write_array (TypedStream* stream, const char* type, + int count, const void* data); +int objc_read_array (TypedStream* stream, const char* type, + int count, void* data); + +int objc_write_object (TypedStream* stream, id object); +int objc_read_object (TypedStream* stream, id* object); + + + +/* +** Open a typed stream for reading or writing. MODE may be either of +** OBJC_READONLY or OBJC_WRITEONLY. +*/ + +TypedStream* objc_open_typed_stream (FILE* physical, int mode); +TypedStream* objc_open_typed_stream_for_file (const char* file_name, int mode); + +void objc_close_typed_stream (TypedStream* stream); + +BOOL objc_end_of_typed_stream (TypedStream* stream); +void objc_flush_typed_stream (TypedStream* stream); + +#endif /* not __typedstream_INCLUDE_GNU */