diff --git a/build-mingw.sh b/build-mingw.sh index 2882bc4..78b2b28 100755 --- a/build-mingw.sh +++ b/build-mingw.sh @@ -3,10 +3,11 @@ java -jar ./JCGO/jcgo.jar mudclient -src ./mudclient204-headless \ patch -p0 -i sdl.diff -x86_64-w64-mingw32-gcc -g -I ./JCGO/include -I ./JCGO/native \ - -I ./JCGO/include/boehmgc -I ./SDL2-2.0.14/x86_64-w64-mingw32/include \ - -DJCGO_NOGC -DJCGO_USEGCJ -DJCGO_FPFAST -DJCGO_FASTMATH -DJCGO_INET \ +x86_64-w64-mingw32-gcc -O2 -I ./JCGO/include -I ./JCGO/native \ + -I ./JCGO/include/tinygc -I ./SDL2-2.0.14/x86_64-w64-mingw32/include \ + -fno-strict-aliasing \ + -DGC_THREADS -DJCGO_USEGCJ -DJCGO_FPFAST -DJCGO_FASTMATH -DJCGO_INET \ -DJCGO_INTFIT -DJCGO_THREADS -D_IEEEFP_H -DJCGO_WIN32 \ -o mudclient.exe jcgo_Out/Main.c -lm \ -L ./SDL2-2.0.14/x86_64-w64-mingw32/lib -lSDL2 -lwsock32 \ - ./JCGO/libs/amd64/mingw64/libgcmt.a -no-pie + ./tinygc-tinygc-2_6/tinygcmt.o -no-pie diff --git a/build.sh b/build.sh index fd78b25..eaa8180 100755 --- a/build.sh +++ b/build.sh @@ -5,7 +5,8 @@ patch -p0 -i sdl.diff #-DJCGO_PARALLEL #-DJCGO_NOGJ -gcc -g -I ./JCGO/include -I ./JCGO/native -I ./JCGO/include/boehmgc \ +gcc -O2 -I ./JCGO/include -I ./JCGO/native -I ./JCGO/include/boehmgc \ + -fno-strict-aliasing \ -DJCGO_USEGCJ -DJCGO_FPFAST -DJCGO_FASTMATH -DJCGO_INET \ -DJCGO_INTFIT -DJCGO_THREADS -DJCGO_UNIX -D_IEEEFP_H -DJCGO_UNIFSYS \ -o mudclient jcgo_Out/Main.c -lm -lpthread -lSDL2 \ diff --git a/tinygc-tinygc-2_6/ChangeLog b/tinygc-tinygc-2_6/ChangeLog new file mode 100755 index 0000000..79bff2e --- /dev/null +++ b/tinygc-tinygc-2_6/ChangeLog @@ -0,0 +1,40 @@ +[2.6 release] + +2010-12-04 Ivan Maidanski + + * htdocs/index.html: Update (according to the changes in README). + * README.txt: Update "Tuning macros" section (add GC_THREADS + macro description); update "Files list" section (for gc_mark.h). + * gc.h (GC_TINYGC_VER): Update the value. + * gc.h (GC_NO_THREAD_REDIRECTS, GC_allow_register_threads, + GC_register_my_thread, GC_unregister_my_thread): Declare only if + GC_THREADS. + * gc_mark.h (GC_start_callback_proc, GC_set_start_callback, + GC_get_start_callback): New API prototype. + * tinygc.c (GC_start_call_back): New static global variable. + * tinygc.c (GC_collect_unreachable): Call GC_start_call_back if + non-zero. + * tinygc.c (GC_set_start_callback, GC_get_start_callback): New API + function. + +[2.5 release] + +2009-12-20 Ivan Maidanski + + * htdocs/index.html: New file (also put to sftp:web.sf.net/htdocs). + +2009-12-20 Ivan Maidanski + + * ChangeLog: New file. + * GNU_GPL.txt: New file (GNU GPLv2 license). + * tinygc.c: Set version to 2.5. + * README.txt: Ditto. + * gc.h (GC_TINYGC_VER): Ditto. + * gc_gcj.h: Initial SVN import. + * gc_mark.h: Ditto. + * javaxfc.h: Ditto. + * README.txt: Update. + +Local Variables: +version-control: never +End: \ No newline at end of file diff --git a/tinygc-tinygc-2_6/GNU_GPL.txt b/tinygc-tinygc-2_6/GNU_GPL.txt new file mode 100755 index 0000000..5bb0601 --- /dev/null +++ b/tinygc-tinygc-2_6/GNU_GPL.txt @@ -0,0 +1,340 @@ + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc. + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 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/tinygc-tinygc-2_6/README.txt b/tinygc-tinygc-2_6/README.txt new file mode 100755 index 0000000..6c7c067 --- /dev/null +++ b/tinygc-tinygc-2_6/README.txt @@ -0,0 +1,298 @@ + TinyGC v2.6 (Tiny Garbage Collector) + ------------------------------------ + +Copyright (C) 2006-2010 Ivan Maidanski +All rights reserved. + +Project home page +----------------- + +http://tinygc.sourceforge.net + + +Preface +------- + +TinyGC is an independent implementation of the API of the well-known +Boehm-Demers-Weiser Conservative GC ("BDWGC" or "BoehmGC" for short). + +TinyGC has been initially developed as a part of the JCGO project to be +used as a BoehmGC replacement. At present, TinyGC is a standalone +project. + +Disclaimer/License +------------------ + +This 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. + +This software 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 (GPL) for more details. + +You should have received a copy of the GNU General Public License +along with this software. If not, write to the Free Software +Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, +MA 02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. + +Target environments +------------------- + +TinyGC is designed to be used primary in projects requiring Java-like +memory garbage collection functionality for: +- memory constrained environments; +- 8/16-bit systems; +- BoehmGC temporal replacement (for application debugging, testing and +benchmarking purposes); +- targets where BoehmGC is still not ported to. + +TinyGC is NOT designed for speed. + +Design principles +----------------- + +The major principles are: +- source and binary compatibility with BoehmGC; +- implements only the minimal subset of the BoehmGC API (v7.2) +sufficient for the Java/GCJ-like functionality; +- highly portable (contains no assembler, no machine/OS-specific code +portions) and tunable; +- supports 16/32/64-bit architectures ("flat" data models only); +- compact code and small initial internal data size; +- simple collection World-stopped Mark-and-Sweep algorithm +implementation; +- malloc-based allocation (i.e. every object is allocated using +malloc()); +- objects finalization and memory recycling (reclaiming to the +underlaying malloc implementation) is done lazily (between +collections). + +Advantages and drawbacks +------------------------ + +The major TinyGC advantages over BoehmGC are: +- small code size (it could be as small as 3800 bytes); +- 16-bit architectures are supported; +- small initial internal data size; +- less source code (to verify); +- minimal set of the underlaying clib/pthread/Win32 functions used. + +The drawbacks of TinyGC are: +- lower allocation speed and larger world-stopped collection delays +(typically); +- only a small subset of the BoehmGC API is implemented; +- no support for C++; +- no support for architectures with a separate registers stack (like +IA-64); +- no find-leak and pointer back-trace modes; +- no automatic registration of static data roots, stack bottom and +threads; +- no "advanced" allocation and collection technologies (no +blacklisting, memory unmapping, thread-local allocation, parallel +marking, generation and incremental collections); +- relies on the underlaying malloc/free() implementation (which may be +broken for large heaps, like, e.g., in some versions of msvcrt); +- "all-interior-pointers" mode is limited by the offset of 256 +(1 << GC_LOG2_OFFIGNORE) bytes (this also means that disappearing links +must not be placed at this or higher offsets of an allocated object); +- only the length-based descriptor for the GCJ-style allocation is +supported; +- only Java-like "no-order" finalization policy is implemented. + +Notes +----- + +Release notes: +- no binary distribution is offered on the official site; +- no make file (or other building script) is provided. + +Implementation notes: +- the same environment variables are recognized as in BoehmGC; +- the finalization and disappearing links implementations are generally +the same as in BoehmGC; +- full TinyGC implementation resides in a single file (all the internal +symbols are not visible outside); +- both pthreads and Win32 threads are supported; +- no thread-safety of the underlaying malloc/free is required; +- the stack direction is detected at TinyGC initialization; +- no warnings are printed; +- the thread "suspend" handler does not use pthread synchronization +primitives (yielding and sleeping are used instead for better +portability); +- CPU state is saved by setjmp(); +- there is no object "header" (i.e. the original object size is passed +to the underlaying malloc()). + +Usage notes: +- all pointers must be word-aligned; +- it is assumed that the compiler performs only GC-safe pointer +transformations; +- static data roots must be manually registered; +- application threads must be manually registered and unregistered; +- it would be good to use GC_call_with_gc_active() to record the +correct main stack base (after GC_INIT()). + +Tuning macros +------------- + +Useful macros for tuning (same as in BoehmGC): +- GC_DLL - compile to produce a DLL (gc.dll); +- ALL_INTERIOR_POINTERS - turn on "all-interior-pointers" mode by +default; +- GC_GCJ_SUPPORT - compile with GCJ-style allocation support; +- GC_THREADS - compile with thread support (pthread-based by default); +- GC_WIN32_THREADS - compile with Win32-based thread support; +- JAVA_FINALIZATION_NOT_NEEDED - exclude GC_finalize_all() from the +API; +- DONT_ADD_BYTE_AT_END - do not pad objects even if +"all-interior-pointers" mode is on; +- FINALIZE_ON_DEMAND - causes finalizers to be run only in response to +explicit GC_invoke_finalizers() calls by default (unless overridden at +run-time); +- GC_IGNORE_GCJ_INFO - disable GCJ-style type information (useful for +debugging); +- GC_DONT_EXPAND - do not implicitly expand the heap by default (unless +overridden at run-time); +- GC_INITIAL_HEAP_SIZE= - set the desired default initial heap +size (in bytes); +- GC_FREE_SPACE_DIVISOR= - the default trade-off between garbage +collection and heap growth; +- GC_MAX_RETRIES= - the default maximum number of garbage +collections attempted before reporting out of memory after a heap +expansion failure. + +Major TinyGC-specific macros: +- GC_PRINT_MSGS - compile with statistic and error printing +capabilities; +- GC_GETENV_SKIP - do not recognize any environment variable (for +smaller code size or for WinCE targets); +- GC_WIN32_WCE - compile for WinCE (use thread Id instead of thread +handle, and retry on SuspendThread() failures); +- GC_NO_INACTIVE, GC_MISC_EXCLUDE - exclude the corresponding parts of +the TinyGC API (for smaller code size); +- GC_NO_GCBASE, GC_NO_FNLZ, GC_NO_DLINKS, GC_NO_REGISTER_DLINK - +exclude the support (i.e. expose dummy support) for the corresponding +TinyGC capabilities (for smaller code size); +- GC_USE_WIN32_SYSTEMTIME - use Win32 GetSystemTime() API call instead +of ftime() or gettimeofday() ones (useful for WinCE); +- GC_USE_GETTIMEOFDAY - use Unix gettimeofday() API call instead of +ftime() one; +- GC_OMIT_REGISTER_KEYWORD - ignore C "register" keyword; +- CONST=/**/ - ignore C "const" keyword; +- INLINE=/**/ - ignore C "__inline" keyword; +- GC_FASTCALL=/**/ - ignore C x86-specific "__fastcall" keyword; +- GC_CLIBDECL=/**/ - ignore C x86-specific "__cdecl" keyword; +- GC_DATASTATIC=/**/ - do not use C static storage class for global +data; +- GC_STATIC=/**/ - do not use C static linkage for GC internal +functions; +- GC_DATASTARTSYM= - specify the external symbol which is the first +one in the program data section; +- GC_DATAENDSYM= - specify the external symbol which is the last +one in the program data section; +- GC_DATASTARTSYM2= - specify the external symbol which is the +first one in the program ".bss" section; +- GC_DATAENDSYM2= - specify the external symbol which is the last +one in the program ".bss" section; +- GC_STACKBOTTOMVAR= - specify the external symbol pointing to the +program main thread stack bottom (or top if GC_STACKLEN is 0); +- GC_STACKLENVAR= - specify the external symbol pointing to the +program main thread stack size; +- GC_SIG_SUSPEND= - use specific signal to suspend Posix +threads; +- GC_WIN32_CONTEXT_SP_NAME= - use specific stack pointer +register name (defined in Win32 "winnt.h"); +- GC_LOG2_OFFIGNORE= - explicitly specify the number of address +lowest bits ignored for object address hash computations. + +Useful macros for client application tuning (same as in BoehmGC): +- GC_DONT_EXPAND - do not implicitly expand the heap (unless overridden +at run-time); +- GC_DLL - use TinyGC residing in a DLL; +- GC_THREADS - declare the prototypes for the collector multi-threading +support; +- GC_CALL= - explicitly specify calling convention for +the GC API functions; +- GC_CALLBACK= - explicitly specify an alternate calling +convention for the GC API user callbacks; +- GC_INITIAL_HEAP_SIZE= - set the desired initial heap size (in +bytes); +- GC_MAXIMUM_HEAP_SIZE= - set the desired maximum heap size (in +bytes); +- GC_FREE_SPACE_DIVISOR= - set the desired trade-off between +garbage collection and heap growth; +- GC_MAX_RETRIES= - set the desired maximum number of garbage +collections attempted before reporting out of memory after a heap +expansion failure. + +Note 1: if GC_NO_DLINKS is used without GC_NO_REGISTER_DLINK then all +the disappearing links are treated as normal pointers. + +Note 2: for Unix use the command-line options: + -DGC_FASTCALL= -DGC_CLIBDECL= + +Note 3: for Solaris SunOS "cc" use the command-line options: + -DGC_FASTCALL= -DGC_CLIBDECL= -DINLINE=inline + -erroff=E_WHITE_SPACE_IN_DIRECTIVE + +Environment variables +--------------------- + +Environment variables recognized (if supported, same as in BoehmGC): +GC_DONT_GC - turn off garbage collection; +GC_PRINT_STATS - turn on statistic printing on every garbage collection +(if supported); +GC_ALL_INTERIOR_POINTERS - turn on "all-interior-pointers" collector +mode; +GC_IGNORE_GCJ_INFO - ignore the GCJ-style type descriptors (if +supported); +GC_INITIAL_HEAP_SIZE= - set the initial heap size (in bytes); +GC_MAXIMUM_HEAP_SIZE= - set the maximum heap size (in bytes); +GC_FREE_SPACE_DIVISOR= - change the default trade-off between +garbage collection and heap growth. + +Note: the values assigned to the specified environment variables +override the similar default (or the preset at the compilation time) +values. + +Files list +---------- + +The TinyGC distribution consists of: +- ChangeLog - the standard changes log file; +- GNU_GPL.txt - the GNU GPLv2 license; +- README.txt - this file; +- gc.h - the main include file (the subset of that in BoehmGC); +- gc_gcj.h - GCJ-style allocation API (the subset of that in BoehmGC); +- gc_mark.h - contains only the constants for the GCJ-style +length-based descriptors and the collections notifier prototypes; +- javaxfc.h - same as in BoehmGC; +- tinygc.c - the TinyGC implementation itself. + +User's feedback +--------------- + +Any questions, suggestions, bug reports and patches are welcomed at +the TinyGC site tracker (hosted at SourceForge.net). + + --- [ End of File ] --- diff --git a/tinygc-tinygc-2_6/gc.h b/tinygc-tinygc-2_6/gc.h new file mode 100755 index 0000000..d501582 --- /dev/null +++ b/tinygc-tinygc-2_6/gc.h @@ -0,0 +1,325 @@ +/* + * @(#) gc.h -- TinyGC (Tiny Garbage Collector) header. + * Copyright (C) 2006-2010 Ivan Maidanski All rights reserved. + ** + * Version: 2.6 + * See also files: tinygc.c, gc_gcj.h, gc_mark.h, javaxfc.h + * Required: any ANSI C compiler (assume GC-safe compilation). + */ + +/* + * This 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. + ** + * This software 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 (GPL) for more details. + ** + * Linking this library statically or dynamically with other modules is + * making a combined work based on this library. Thus, the terms and + * conditions of the GNU General Public License cover the whole + * combination. + ** + * As a special exception, the copyright holders of this library give you + * permission to link this library with independent modules to produce an + * executable, regardless of the license terms of these independent + * modules, and to copy and distribute the resulting executable under + * terms of your choice, provided that you also meet, for each linked + * independent module, the terms and conditions of the license of that + * module. An independent module is a module which is not derived from + * or based on this library. If you modify this library, you may extend + * this exception to your version of the library, but you are not + * obligated to do so. If you do not wish to do so, delete this + * exception statement from your version. + */ + +#ifndef GC_H +#define GC_H + +#define GC_TINYGC_VER 260 /* TinyGC v2.6 */ + +/* TinyGC API is a subset of Boehm-Demers-Weiser Conservative GC API v7.2 */ + +/* + * Control macros: GC_DLL, GC_DONT_EXPAND, GC_STACKBASE_WITH_REGBASE, + * GC_THREADS. + * Macros for tuning: CONST, GC_API, GC_CALL, GC_CALLBACK, GC_DATASTART, + * GC_DATASTART2, GC_DATASTARTSYM, GC_DATASTARTSYM2, GC_DATAEND, GC_DATAEND2, + * GC_DATAENDSYM, GC_DATAENDSYM2, GC_FREE_SPACE_DIVISOR, GC_INITIAL_HEAP_SIZE, + * GC_MAXIMUM_HEAP_SIZE, GC_MAX_RETRIES, GC_NEAR, GC_SIGNEDWORD. + */ + +#ifndef _STDDEF_H +#include +/* typedef size_t; */ +#endif + +#ifdef __cplusplus +extern "C" +{ +#endif + +#ifndef CONST +#define CONST const +#endif + +#ifndef GC_API +#ifdef GC_DLL +#define GC_API __declspec(dllimport) +#else +#define GC_API extern +#endif +#endif + +#ifndef GC_CALL +#define GC_CALL /* empty */ +#endif + +#ifndef GC_CALLBACK +#define GC_CALLBACK GC_CALL +#endif + +#ifndef GC_NEAR +/* TinyGC-specific */ +#define GC_NEAR /* empty */ +#endif + +#ifndef GC_SIGNEDWORD +/* TinyGC-specific */ +#ifdef _WIN64 +#define GC_SIGNEDWORD __int64 +#else +#ifdef _LLP64 +#define GC_SIGNEDWORD long long +#else +#ifdef _LP64 +#define GC_SIGNEDWORD long +#endif +#endif +#endif +#endif + +#ifndef GC_STACKBASE_WITH_REGBASE +/* TinyGC-specific */ +#ifdef _M_IA64 +#define GC_STACKBASE_WITH_REGBASE 1 +#else +#ifdef __ia64__ +#define GC_STACKBASE_WITH_REGBASE 1 +#endif +#endif +#endif + +#ifdef GC_SIGNEDWORD +typedef unsigned GC_SIGNEDWORD GC_word; +/* sizeof(GC_word) == sizeof(void GC_NEAR *) */ +#else +typedef unsigned GC_word; +#endif + +#define GC_MALLOC(size) GC_malloc(size) +#define GC_MALLOC_ATOMIC(size) GC_malloc_atomic(size) + +#define GC_NEW(t) ((t GC_NEAR *)GC_MALLOC(sizeof(t))) +#define GC_NEW_ATOMIC(t) ((t GC_NEAR *)GC_MALLOC_ATOMIC(sizeof(t))) + +#define GC_GENERAL_REGISTER_DISAPPEARING_LINK(link, obj) GC_general_register_disappearing_link(link, obj) +#define GC_REGISTER_FINALIZER_NO_ORDER(obj, fn, client_data, ofn, odata) GC_register_finalizer_no_order(obj, fn, client_data, ofn, odata) + +typedef void (GC_CALLBACK *GC_finalizer_notifier_proc)(void); +typedef int (GC_CALLBACK *GC_stop_func)(void); +typedef void (GC_CALLBACK *GC_finalization_proc)(void GC_NEAR *, + void GC_NEAR *); +typedef void (GC_CALLBACK *GC_warn_proc)(char GC_NEAR *, GC_word); +typedef void GC_NEAR *(GC_CALLBACK *GC_fn_type)(void GC_NEAR *); + +GC_API GC_word GC_CALL GC_get_gc_no(void); + +GC_API void GC_CALL GC_set_all_interior_pointers(int); +GC_API void GC_CALL GC_set_finalize_on_demand(int); +GC_API void GC_CALL GC_set_java_finalization(int); +GC_API void GC_CALL GC_set_dont_expand(int); +GC_API void GC_CALL GC_set_no_dls(int); +GC_API void GC_CALL GC_set_dont_precollect(int); + +GC_API void GC_CALL GC_set_free_space_divisor(GC_word); +GC_API void GC_CALL GC_set_max_retries(GC_word); + +GC_API void GC_CALL GC_set_finalizer_notifier(GC_finalizer_notifier_proc); +GC_API GC_finalizer_notifier_proc GC_CALL GC_get_finalizer_notifier(void); + +GC_API void GC_CALL GC_init(void); + +GC_API void GC_NEAR *GC_CALL GC_malloc(size_t); +GC_API void GC_NEAR *GC_CALL GC_malloc_atomic(size_t); + +GC_API void GC_NEAR *GC_CALL GC_base(void GC_NEAR *); + +GC_API int GC_CALL GC_expand_hp(size_t); +GC_API void GC_CALL GC_set_max_heap_size(GC_word); + +GC_API void GC_CALL GC_exclude_static_roots(void GC_NEAR *, void GC_NEAR *); +GC_API void GC_CALL GC_clear_roots(void); +GC_API void GC_CALL GC_add_roots(void GC_NEAR *, void GC_NEAR *); +GC_API void GC_CALL GC_remove_roots(void GC_NEAR *, void GC_NEAR *); + +GC_API void GC_CALL GC_gcollect(void); +GC_API void GC_CALL GC_gcollect_and_unmap(void); +GC_API int GC_CALL GC_try_to_collect(GC_stop_func); + +GC_API void GC_CALL GC_set_stop_func(GC_stop_func); +GC_API GC_stop_func GC_CALL GC_get_stop_func(void); + +GC_API size_t GC_CALL GC_get_heap_size(void); +GC_API size_t GC_CALL GC_get_free_bytes(void); +GC_API size_t GC_CALL GC_get_bytes_since_gc(void); +GC_API size_t GC_CALL GC_get_total_bytes(void); + +GC_API void GC_CALL GC_disable(void); +GC_API void GC_CALL GC_enable(void); + +GC_API void GC_CALL GC_enable_incremental(void); + +GC_API void GC_CALL GC_register_finalizer_no_order(void GC_NEAR *, + GC_finalization_proc, void GC_NEAR *, GC_finalization_proc GC_NEAR *, + void GC_NEAR *GC_NEAR *); + +#define GC_NO_MEMORY 2 + +GC_API int GC_CALL GC_general_register_disappearing_link( + void GC_NEAR *GC_NEAR *, void GC_NEAR *); +GC_API int GC_CALL GC_unregister_disappearing_link(void GC_NEAR *GC_NEAR *); + +GC_API int GC_CALL GC_should_invoke_finalizers(void); +GC_API int GC_CALL GC_invoke_finalizers(void); + +GC_API void GC_CALL GC_set_warn_proc(GC_warn_proc); +GC_API GC_warn_proc GC_CALL GC_get_warn_proc(void); +GC_API void GC_CALLBACK GC_ignore_warn_proc(char GC_NEAR *, GC_word); + +GC_API void GC_NEAR *GC_CALL GC_call_with_alloc_lock(GC_fn_type, + void GC_NEAR *); + +#define GC_SUCCESS 0 +#define GC_DUPLICATE 1 +#define GC_UNIMPLEMENTED 3 + +struct GC_stack_base +{ + void GC_NEAR *mem_base; +#ifdef GC_STACKBASE_WITH_REGBASE + void GC_NEAR *reg_base; /* not used by TinyGC */ +#endif +}; + +typedef void GC_NEAR *(GC_CALLBACK *GC_stack_base_func)( + struct GC_stack_base GC_NEAR *, void GC_NEAR *); + +GC_API void GC_NEAR *GC_CALL GC_call_with_stack_base(GC_stack_base_func, + void GC_NEAR *); +GC_API int GC_CALL GC_get_stack_base(struct GC_stack_base GC_NEAR *); + +GC_API void GC_NEAR *GC_CALL GC_do_blocking(GC_fn_type, void GC_NEAR *); +GC_API void GC_NEAR *GC_CALL GC_call_with_gc_active(GC_fn_type, + void GC_NEAR *); + +#ifdef GC_THREADS + +#ifndef GC_NO_THREAD_REDIRECTS +/* No "implicit thread registration" mode */ +#define GC_NO_THREAD_REDIRECTS +#endif + +GC_API void GC_CALL GC_allow_register_threads(void); +GC_API int GC_CALL GC_register_my_thread( + CONST struct GC_stack_base GC_NEAR *); +GC_API int GC_CALL GC_unregister_my_thread(void); + +#endif + +GC_API void GC_CALL GC_set_force_unmap_on_gcollect(int); + +#ifdef GC_DATASTARTSYM +extern char GC_DATASTARTSYM; +#ifndef GC_DATASTART +#define GC_DATASTART ((void GC_NEAR *)&GC_DATASTARTSYM) +#endif +#endif + +#ifdef GC_DATAENDSYM +extern char GC_DATAENDSYM; +#ifndef GC_DATAEND +#define GC_DATAEND ((void GC_NEAR *)&GC_DATAENDSYM) +#endif +#endif + +#ifdef GC_DATASTARTSYM2 +extern char GC_DATASTARTSYM2; +#ifndef GC_DATASTART2 +#define GC_DATASTART2 ((void GC_NEAR *)&GC_DATASTARTSYM2) +#endif +#endif + +#ifdef GC_DATAENDSYM2 +extern char GC_DATAENDSYM2; +#ifndef GC_DATAEND2 +#define GC_DATAEND2 ((void GC_NEAR *)&GC_DATAENDSYM2) +#endif +#endif + +#ifdef GC_DATASTART +#ifndef GC_DATAEND +#define GC_DATAEND GC_DATASTART +#endif +#ifdef GC_DATASTART2 +#ifndef GC_DATAEND2 +#define GC_DATAEND2 GC_DATASTART2 +#endif +#define GC_INIT_CONF_ROOTS (GC_add_roots(GC_DATASTART, GC_DATAEND), GC_add_roots(GC_DATASTART2, GC_DATAEND2)) +#else +#define GC_INIT_CONF_ROOTS GC_add_roots(GC_DATASTART, GC_DATAEND) +#endif +#else +#define GC_INIT_CONF_ROOTS /* empty */ +#endif + +#ifdef GC_DONT_EXPAND +#define GC_INIT_CONF_DONT_EXPAND GC_set_dont_expand(1) +#else +#define GC_INIT_CONF_DONT_EXPAND /* empty */ +#endif + +#ifdef GC_MAX_RETRIES +#define GC_INIT_CONF_MAX_RETRIES GC_set_max_retries(GC_MAX_RETRIES) +#else +#define GC_INIT_CONF_MAX_RETRIES /* empty */ +#endif + +#ifdef GC_FREE_SPACE_DIVISOR +#define GC_INIT_CONF_FREE_SPACE_DIVISOR GC_set_free_space_divisor(GC_FREE_SPACE_DIVISOR) +#else +#define GC_INIT_CONF_FREE_SPACE_DIVISOR /* empty */ +#endif + +#ifdef GC_MAXIMUM_HEAP_SIZE +#define GC_INIT_CONF_MAXIMUM_HEAP_SIZE GC_set_max_heap_size(GC_MAXIMUM_HEAP_SIZE) +#else +#define GC_INIT_CONF_MAXIMUM_HEAP_SIZE /* empty */ +#endif + +#ifdef GC_INITIAL_HEAP_SIZE +#define GC_INIT_CONF_INITIAL_HEAP_SIZE { size_t GC_heap_size; (void)((GC_heap_size = GC_get_heap_size()) < (size_t)(GC_INITIAL_HEAP_SIZE) ? GC_expand_hp((size_t)(GC_INITIAL_HEAP_SIZE) - GC_heap_size) : 0); } +#else +#define GC_INIT_CONF_INITIAL_HEAP_SIZE /* empty */ +#endif + +#define GC_INIT() { GC_INIT_CONF_DONT_EXPAND; GC_INIT_CONF_MAX_RETRIES; GC_INIT_CONF_FREE_SPACE_DIVISOR; GC_INIT_CONF_MAXIMUM_HEAP_SIZE; GC_init(); GC_INIT_CONF_ROOTS; GC_INIT_CONF_INITIAL_HEAP_SIZE; } + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/tinygc-tinygc-2_6/gc_gcj.h b/tinygc-tinygc-2_6/gc_gcj.h new file mode 100755 index 0000000..dfc7335 --- /dev/null +++ b/tinygc-tinygc-2_6/gc_gcj.h @@ -0,0 +1,66 @@ +/* + * @(#) gc_gcj.h -- TinyGC additional header (GCJ-style API). + * Copyright (C) 2006-2009 Ivan Maidanski All rights reserved. + ** + * See also files: tinygc.c, gc.h, gc_mark.h, javaxfc.h + */ + +/* + * This 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. + ** + * This software 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 (GPL) for more details. + ** + * Linking this library statically or dynamically with other modules is + * making a combined work based on this library. Thus, the terms and + * conditions of the GNU General Public License cover the whole + * combination. + ** + * As a special exception, the copyright holders of this library give you + * permission to link this library with independent modules to produce an + * executable, regardless of the license terms of these independent + * modules, and to copy and distribute the resulting executable under + * terms of your choice, provided that you also meet, for each linked + * independent module, the terms and conditions of the license of that + * module. An independent module is a module which is not derived from + * or based on this library. If you modify this library, you may extend + * this exception to your version of the library, but you are not + * obligated to do so. If you do not wish to do so, delete this + * exception statement from your version. + */ + +#ifndef GC_GCJ_H +#define GC_GCJ_H + +/* TinyGC API is a subset of Boehm-Demers-Weiser Conservative GC API */ + +#ifndef GC_H +#include "gc.h" +#endif + +#ifdef __cplusplus +extern "C" +{ +#endif + +#ifndef GC_NEAR +/* TinyGC-specific */ +#define GC_NEAR /* empty */ +#endif + +#define GC_GCJ_MALLOC(size, vtable) GC_gcj_malloc(size, vtable) + +GC_API void GC_CALL GC_init_gcj_malloc(int, void * /* GC_mark_proc */); + +GC_API void GC_NEAR *GC_CALL GC_gcj_malloc(size_t, void GC_NEAR *); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/tinygc-tinygc-2_6/gc_mark.h b/tinygc-tinygc-2_6/gc_mark.h new file mode 100755 index 0000000..fa35059 --- /dev/null +++ b/tinygc-tinygc-2_6/gc_mark.h @@ -0,0 +1,64 @@ +/* + * @(#) gc_mark.h -- TinyGC additional header (explicit GC marker control). + * Copyright (C) 2006-2010 Ivan Maidanski All rights reserved. + ** + * See also files: tinygc.c, gc.h, gc_gcj.h, javaxfc.h + */ + +/* + * This 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. + ** + * This software 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 (GPL) for more details. + ** + * Linking this library statically or dynamically with other modules is + * making a combined work based on this library. Thus, the terms and + * conditions of the GNU General Public License cover the whole + * combination. + ** + * As a special exception, the copyright holders of this library give you + * permission to link this library with independent modules to produce an + * executable, regardless of the license terms of these independent + * modules, and to copy and distribute the resulting executable under + * terms of your choice, provided that you also meet, for each linked + * independent module, the terms and conditions of the license of that + * module. An independent module is a module which is not derived from + * or based on this library. If you modify this library, you may extend + * this exception to your version of the library, but you are not + * obligated to do so. If you do not wish to do so, delete this + * exception statement from your version. + */ + +#ifndef GC_MARK_H +#define GC_MARK_H + +/* TinyGC API is a subset of Boehm-Demers-Weiser Conservative GC API */ + +#ifndef GC_H +#include "gc.h" +#endif + +#ifdef __cplusplus +extern "C" +{ +#endif + +#define GC_DS_TAG_BITS 2 +#define GC_DS_TAGS ((1 << GC_DS_TAG_BITS) - 1) + +#define GC_DS_LENGTH 0 + +typedef void (GC_CALLBACK *GC_start_callback_proc)(void); +GC_API void GC_CALL GC_set_start_callback(GC_start_callback_proc); +GC_API GC_start_callback_proc GC_CALL GC_get_start_callback(void); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/tinygc-tinygc-2_6/htdocs/index.html b/tinygc-tinygc-2_6/htdocs/index.html new file mode 100755 index 0000000..7f202cb --- /dev/null +++ b/tinygc-tinygc-2_6/htdocs/index.html @@ -0,0 +1,473 @@ + + + + + + + +TinyGC - Tiny Garbage Collector + + + + + + + + + + + +

TinyGC

+ +
+

Preface

+

TinyGC is an independent implementation of the API of the well-known +Boehm-Demers-Weiser Conservative GC ("BDWGC" or "BoehmGC" for short). +

TinyGC has been initially developed as a part of the JCGO project to be +used as a BoehmGC replacement. At present, TinyGC is a standalone project. +

+ +
+

Download

+

To get the latest TinyGC stable release source code, +please visit +"Browse files for +TinyGC". +

+ +
+

Target environments

+

TinyGC is designed to be used primary in projects +requiring Java-like memory garbage collection functionality for: +

    +
  • memory constrained environments; +
  • 8/16-bit systems; +
  • BoehmGC temporal replacement (for application debugging, testing and +benchmarking purposes); +
  • targets where BoehmGC is still not ported to. +
+

TinyGC is NOT designed for speed. +

+ +
+

Design principles

+

The major principles are: +

    +
  • source and binary compatibility with BoehmGC; +
  • implements only the minimal subset of the BoehmGC +API (v7.2) sufficient for the +Java/GCJ-like functionality; +
  • highly portable (contains no assembler, no +machine/OS-specific code portions) and tunable; +
  • supports 16/32/64-bit architectures ("flat" data models only); +
  • compact code and small initial internal data size; +
  • simple collection World-stopped Mark-and-Sweep algorithm implementation; +
  • malloc-based allocation (i.e. every object is allocated using +malloc()); +
  • objects finalization and memory recycling (reclaiming to the underlaying +malloc implementation) is done lazily (between collections). +
+ +
+

Advantages and drawbacks

+

The major TinyGC advantages over +BoehmGC are: +

    +
  • small code size (it could be as small as 3800 bytes); +
  • 16-bit architectures are supported; +
  • small initial internal data size; +
  • less source code (to verify); +
  • minimal set of the underlaying +clib/pthread/Win32 +functions used. +
+

The drawbacks of TinyGC are: +

    +
  • lower allocation speed and larger world-stopped collection delays +(typically); +
  • only a small subset of the BoehmGC +API is implemented; +
  • no support for C++; +
  • no support for architectures with a separate registers stack (like +IA-64); +
  • no find-leak and pointer back-trace modes; +
  • no automatic registration of static data roots, stack bottom and threads; +
  • no "advanced" allocation and collection technologies (no blacklisting, +memory unmapping, thread-local allocation, parallel marking, generation and +incremental collections); +
  • relies on the underlaying malloc/free() implementation (which may be +broken for large heaps, like, e.g., in some versions of msvcrt); +
  • "all-interior-pointers" mode is limited by the offset of 256 +(1 << GC_LOG2_OFFIGNORE) bytes (this also means that +disappearing links must not be placed at this or higher offsets of an +allocated object); +
  • only the length-based descriptor for the GCJ-style +allocation is supported; +
  • only Java-like "no-order" finalization policy is implemented. +
+ +
+

Notes

+

Release notes: +

    +
  • no binary distribution is offered on the official site; +
  • no make file (or other building script) is provided. +
+

Implementation notes: +

    +
  • the same environment variables are recognized as in +BoehmGC; +
  • the finalization and disappearing links implementations are generally the +same as in BoehmGC; +
  • full TinyGC implementation resides in a single file +(all the internal symbols are not visible outside); +
  • both pthreads and Win32 threads are +supported; +
  • no thread-safety of the underlaying malloc/free is required; +
  • the stack direction is detected at TinyGC +initialization; +
  • no warnings are printed; +
  • the thread "suspend" handler does not use pthread +synchronization primitives (yielding and sleeping are used instead for better +portability); +
  • CPU state is saved by setjmp(); +
  • there is no object "header" (i.e. the original object size is passed to +the underlaying malloc()). +
+

Usage notes: +

    +
  • all pointers must be word-aligned; +
  • it is assumed that the compiler performs only GC-safe +pointer transformations; +
  • static data roots must be manually registered; +
  • application threads must be manually registered and unregistered; +
  • it would be good to use GC_call_with_gc_active() to record +the correct main stack base (after GC_INIT()). +
+ +
+

Tuning macros

+

Useful macros for tuning (same as in BoehmGC): +

    +
  • GC_DLL - compile to produce a DLL (gc.dll); +
  • ALL_INTERIOR_POINTERS - turn on "all-interior-pointers" mode by default; +
  • GC_GCJ_SUPPORT - compile with GCJ-style allocation +support; +
  • GC_THREADS - compile with thread support (pthread-based +by default); +
  • GC_WIN32_THREADS - compile with Win32-based thread +support; +
  • JAVA_FINALIZATION_NOT_NEEDED - exclude GC_finalize_all() from +the API; +
  • DONT_ADD_BYTE_AT_END - do not pad objects even if "all-interior-pointers" +mode is on; +
  • FINALIZE_ON_DEMAND - causes finalizers to be run only in response to +explicit GC_invoke_finalizers() calls by default (unless +overridden at run-time); +
  • GC_IGNORE_GCJ_INFO - disable GCJ-style type information +(useful for debugging); +
  • GC_DONT_EXPAND - do not implicitly expand the heap by default (unless +overridden at run-time); +
  • GC_INITIAL_HEAP_SIZE=<value> - set the desired default initial heap +size (in bytes); +
  • GC_FREE_SPACE_DIVISOR=<value> - the default trade-off between garbage +collection and heap growth; +
  • GC_MAX_RETRIES=<value> - the default maximum number of garbage +collections attempted before reporting out of memory after a heap expansion +failure. +
+

Major TinyGC-specific macros: +

    +
  • GC_PRINT_MSGS - compile with statistic and error printing capabilities; +
  • GC_GETENV_SKIP - do not recognize any environment variable (for smaller +code size or for WinCE targets); +
  • GC_WIN32_WCE - compile for WinCE (use thread Id instead +of thread handle, and retry on SuspendThread() failures); +
  • GC_NO_INACTIVE, GC_MISC_EXCLUDE - exclude the corresponding parts of the +TinyGC API (for smaller code size); +
  • GC_NO_GCBASE, GC_NO_FNLZ, GC_NO_DLINKS, GC_NO_REGISTER_DLINK - exclude the +support (i.e. expose dummy support) for the corresponding +TinyGC capabilities (for smaller code size); +
  • GC_USE_WIN32_SYSTEMTIME - use Win32 +GetSystemTime() API call instead of +ftime() or gettimeofday() ones (useful for +WinCE); +
  • GC_USE_GETTIMEOFDAY - use Unix gettimeofday() +API call instead of ftime() one; +
  • GC_OMIT_REGISTER_KEYWORD - ignore C "register" keyword; +
  • CONST=/**/ - ignore C "const" keyword; +
  • INLINE=/**/ - ignore C "__inline" keyword; +
  • GC_FASTCALL=/**/ - ignore C +x86-specific "__fastcall" keyword; +
  • GC_CLIBDECL=/**/ - ignore C +x86-specific "__cdecl" keyword; +
  • GC_DATASTATIC=/**/ - do not use C static storage class +for global data; +
  • GC_STATIC=/**/ - do not use C static linkage for +GC internal functions; +
  • GC_DATASTARTSYM=<id> - specify the external symbol which is the first +one in the program data section; +
  • GC_DATAENDSYM=<id> - specify the external symbol which is the last one +in the program data section; +
  • GC_DATASTARTSYM2=<id> - specify the external symbol which is the first +one in the program ".bss" section; +
  • GC_DATAENDSYM2=<id> - specify the external symbol which is the last one +in the program ".bss" section; +
  • GC_STACKBOTTOMVAR=<id> - specify the external symbol pointing to the +program main thread stack bottom (or top if GC_STACKLEN is 0); +
  • GC_STACKLENVAR=<id> - specify the external symbol pointing to the +program main thread stack size; +
  • GC_SIG_SUSPEND=<sig_id> - use specific signal to suspend Posix threads; +
  • GC_WIN32_CONTEXT_SP_NAME=<sp_id> - use specific stack pointer register +name (defined in Win32 "winnt.h"); +
  • GC_LOG2_OFFIGNORE=<value> - explicitly specify the number of address +lowest bits ignored for object address hash computations. +
+

Useful macros for client application tuning (same as in +BoehmGC): +

    +
  • GC_DONT_EXPAND - do not implicitly expand the heap (unless overridden at +run-time); +
  • GC_DLL - use TinyGC residing in a +DLL; +
  • GC_THREADS - declare the prototypes for the collector multi-threading +support; +
  • GC_CALL=<calling_conv> - explicitly specify calling convention for the +GC API functions; +
  • GC_CALLBACK=<calling_conv> - explicitly specify an alternate calling +convention for the GC API user +callbacks; +
  • GC_INITIAL_HEAP_SIZE=<value> - set the desired initial heap size (in +bytes); +
  • GC_MAXIMUM_HEAP_SIZE=<value> - set the desired maximum heap size (in +bytes); +
  • GC_FREE_SPACE_DIVISOR=<value> - set the desired trade-off between +garbage collection and heap growth; +
  • GC_MAX_RETRIES=<value> - set the desired maximum number of garbage +collections attempted before reporting out of memory after a heap expansion +failure. +
+

Note 1: if GC_NO_DLINKS is used without GC_NO_REGISTER_DLINK then all the +disappearing links are treated as normal pointers. +

Note 2: for Unix use the command-line options: +


+ -DGC_FASTCALL= -DGC_CLIBDECL=
+
+

Note 3: for Solaris SunOS "cc" use the command-line +options: +


+ -DGC_FASTCALL= -DGC_CLIBDECL= -DINLINE=inline -erroff=E_WHITE_SPACE_IN_DIRECTIVE
+
+ +
+

Environment variables

+

Environment variables recognized (if supported, same as in +BoehmGC): +

    +
  • GC_DONT_GC - turn off garbage collection; +
  • GC_PRINT_STATS - turn on statistic printing on every garbage collection +(if supported); +
  • GC_ALL_INTERIOR_POINTERS - turn on "all-interior-pointers" collector mode; +
  • GC_IGNORE_GCJ_INFO - ignore the GCJ-style type +descriptors (if supported); +
  • GC_INITIAL_HEAP_SIZE=<value> - set the initial heap size (in bytes); +
  • GC_MAXIMUM_HEAP_SIZE=<value> - set the maximum heap size (in bytes); +
  • GC_FREE_SPACE_DIVISOR=<value> - change the default trade-off between +garbage collection and heap growth. +
+

Note: the values assigned to the specified environment variables override +the similar default (or the preset at the compilation time) values. +

+ +
+

Files list

+

The TinyGC distribution consists of: +

    +
  • ChangeLog - the standard changes log file; +
  • GNU_GPL.txt - the GNU GPLv2 license; +
  • README.txt - this file; +
  • gc.h - the main include file (the subset of that in +BoehmGC); +
  • gc_gcj.h - GCJ-style allocation API +(the subset of that in BoehmGC); +
  • gc_mark.h - contains only the constants for the +GCJ-style length-based descriptors and the collections +notifier prototypes; +
  • javaxfc.h - same as in BoehmGC; +
  • tinygc.c - the TinyGC implementation itself. +
+ +
+

User's feedback

+

Any questions, suggestions, bug reports and patches are welcomed at the +TinyGC +site tracker +(hosted at SourceForge.net). +

+ +
+

External resources

+

Links to the 3rd-party projects: +

    +
  • BoehmGC +(A garbage collector for C and C++) +
  • GNU GCJ +(a portable optimizing ahead-of-time compiler for Java) +
+

For more links, please visit +"Java and C/C++ developer web resources" +hosted on the JCGO project (a +java2c/java2exe solution) site. +

+ +
+

License

+

This 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. +

This software 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 (GPL) 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +

Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. +

As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. +

+ + + +Locations of visitors to this page + + diff --git a/tinygc-tinygc-2_6/javaxfc.h b/tinygc-tinygc-2_6/javaxfc.h new file mode 100755 index 0000000..bdcd045 --- /dev/null +++ b/tinygc-tinygc-2_6/javaxfc.h @@ -0,0 +1,52 @@ +/* + * @(#) javaxfc.h -- TinyGC additional header (explicit finalization). + * Copyright (C) 2006-2009 Ivan Maidanski All rights reserved. + ** + * See also files: tinygc.c, gc.h, gc_gcj.h, gc_mark.h + */ + +/* + * This 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. + ** + * This software 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 (GPL) for more details. + ** + * Linking this library statically or dynamically with other modules is + * making a combined work based on this library. Thus, the terms and + * conditions of the GNU General Public License cover the whole + * combination. + ** + * As a special exception, the copyright holders of this library give you + * permission to link this library with independent modules to produce an + * executable, regardless of the license terms of these independent + * modules, and to copy and distribute the resulting executable under + * terms of your choice, provided that you also meet, for each linked + * independent module, the terms and conditions of the license of that + * module. An independent module is a module which is not derived from + * or based on this library. If you modify this library, you may extend + * this exception to your version of the library, but you are not + * obligated to do so. If you do not wish to do so, delete this + * exception statement from your version. + */ + +/* TinyGC API is a subset of Boehm-Demers-Weiser Conservative GC API */ + +#ifndef GC_H +#include "gc.h" +#endif + +#ifdef __cplusplus +extern "C" +{ +#endif + +GC_API void GC_CALL GC_finalize_all(void); + +#ifdef __cplusplus +} +#endif diff --git a/tinygc-tinygc-2_6/tinygc.c b/tinygc-tinygc-2_6/tinygc.c new file mode 100755 index 0000000..2b8bad8 --- /dev/null +++ b/tinygc-tinygc-2_6/tinygc.c @@ -0,0 +1,3931 @@ +/* + * @(#) tinygc.c -- TinyGC (Tiny Garbage Collector) source. + * Copyright (C) 2006-2010 Ivan Maidanski All rights reserved. + ** + * Version: 2.6 + * See also files: gc.h, gc_gcj.h, gc_mark.h, javaxfc.h + * Required: any ANSI C compiler (assume GC-safe compilation). + */ + +/* + * This 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. + ** + * This software 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 (GPL) for more details. + ** + * Linking this library statically or dynamically with other modules is + * making a combined work based on this library. Thus, the terms and + * conditions of the GNU General Public License cover the whole + * combination. + ** + * As a special exception, the copyright holders of this library give you + * permission to link this library with independent modules to produce an + * executable, regardless of the license terms of these independent + * modules, and to copy and distribute the resulting executable under + * terms of your choice, provided that you also meet, for each linked + * independent module, the terms and conditions of the license of that + * module. An independent module is a module which is not derived from + * or based on this library. If you modify this library, you may extend + * this exception to your version of the library, but you are not + * obligated to do so. If you do not wish to do so, delete this + * exception statement from your version. + */ + +/* + * Control macros: ALL_INTERIOR_POINTERS, DONT_ADD_BYTE_AT_END, + * FINALIZE_ON_DEMAND, GC_DLL, GC_DONT_EXPAND, GC_GCJ_SUPPORT, GC_GETENV_SKIP, + * GC_IGNORE_GCJ_INFO, GC_MISC_EXCLUDE, GC_NO_DLINKS, GC_NO_FNLZ, + * GC_NO_GCBASE, GC_NO_INACTIVE, GC_NO_REGISTER_DLINK, + * GC_OMIT_REGISTER_KEYWORD, GC_PRINT_MSGS, GC_THREADS, GC_USE_GETTIMEOFDAY, + * GC_USE_WIN32_SYSTEMTIME, GC_WIN32_THREADS, GC_WIN32_WCE, + * JAVA_FINALIZATION_NOT_NEEDED. + ** + * Macros for tuning (also see in gc.h): CONST, GC_ASYNC_PUSHREGS_BEGIN, + * GC_ASYNC_PUSHREGS_END, GC_CLIBDECL, GC_CORE_API, GC_CORE_CALL, + * GC_CORE_FREE, GC_CORE_MALLOC, GC_DATASTATIC, GC_DATASTART, GC_DATASTART2, + * GC_DATAEND, GC_DATAEND2, GC_FATAL_ABORT, GC_FREE_SPACE_DIVISOR, + * GC_MAX_RETRIES, GC_FASTCALL, GC_INLINE_STATIC, GC_LAZYREFILL_BIGCNT, + * GC_LAZYREFILL_COUNT, GC_LOG2_OFFIGNORE, GC_NEW_LINE, GC_PUSHREGS_BEGIN, + * GC_PUSHREGS_END, GC_SIG_SUSPEND, GC_STACKBOTTOM, GC_STACKBOTTOMVAR, + * GC_STACKLEN, GC_STACKLENVAR, GC_STATIC, GC_THREAD_MUTEX_DEFATTR, + * GC_THREAD_YIELD, GC_WIN32_CONTEXT_SP_NAME, GC_YIELD_MAX_ATTEMPT, INLINE, + * MARK_DESCR_OFFSET. + */ + +#ifndef _SETJMP_H +#include +/* int setjmp(jmp_buf); */ +#endif + +#ifndef _STDLIB_H +#include +/* long atol(const char *); */ +/* void exit(int); */ +/* void free(void *); */ +/* char *getenv(const char *); */ +/* void *malloc(size_t); */ +#endif + +#ifndef _STRING_H +#include +/* void *memset(void *, int, size_t); */ +#endif + +#ifndef _LIMITS_H +#include +#endif + +#ifdef GC_WIN32_THREADS + +#ifndef _WINDOWS_H +#include +/* BOOL CloseHandle(HANDLE); */ +/* HANDLE CreateEvent(SECURITY_ATTRIBUTES *, BOOL, BOOL, LPCTSTR); */ +/* BOOL DuplicateHandle(HANDLE, HANDLE, HANDLE, HANDLE *, DWORD, BOOL, DWORD); */ +/* HANDLE GetCurrentProcess(void); */ +/* HANDLE GetCurrentThread(void); */ +/* DWORD GetCurrentThreadId(void); */ +/* BOOL GetThreadContext(HANDLE, CONTEXT *); */ +/* LONG InterlockedExchange(LONG *, LONG); */ +/* DWORD ResumeThread(HANDLE); */ +/* BOOL SetEvent(HANDLE); */ +/* void Sleep(DWORD); */ +/* DWORD SuspendThread(HANDLE); */ +/* DWORD WaitForSingleObject(HANDLE, DWORD); */ +#endif + +#ifndef GC_THREADS +#define GC_THREADS 1 +#endif + +#else /* GC_WIN32_THREADS */ + +#ifdef GC_THREADS + +#ifndef _ERRNO_H +#include +/* int errno; */ +#endif + +#ifndef _SIGNAL_H +#include +/* void (*signal(int, void (*)(int)))(int); */ +#endif + +#ifndef _PTHREAD_H +#include +/* int pthread_kill(pthread_t, int); */ +/* int pthread_mutex_init(pthread_mutex_t *, const pthread_mutexattr_t *); */ +/* int pthread_mutex_lock(pthread_mutex_t *); */ +/* int pthread_mutex_unlock(pthread_mutex_t *); */ +/* pthread_t pthread_self(void); */ +#endif + +#ifndef _SCHED_H +#include +/* int sched_yield(void); */ +#endif + +#ifdef pthread_usleep_np +/* #include */ +/* unsigned pthread_usleep_np(unsigned); */ +#else +#ifndef _UNISTD_H +#include +/* int usleep(useconds_t); */ +#endif +#define pthread_usleep_np usleep +#endif + +#endif /* GC_THREADS */ + +#endif /* ! GC_WIN32_THREADS */ + +#ifdef GC_PRINT_MSGS + +#ifndef _STDIO_H +#include +/* int fprintf(FILE *, const char *, ...); */ +/* FILE * const stderr; */ +/* FILE * const stdout; */ +#endif + +#ifdef GC_USE_WIN32_SYSTEMTIME + +#ifndef _WINDOWS_H +#include +/* void GetSystemTime(SYSTEMTIME *); */ +#endif + +#define GC_CURTIME_T SYSTEMTIME +#define GC_CURTIME_GETMS(pcurt) (GetSystemTime(pcurt), ((((unsigned long)(pcurt)->wDay * 24 + (unsigned long)(pcurt)->wHour) * 60 + (unsigned long)(pcurt)->wMinute) * 60 + (unsigned long)(pcurt)->wSecond) * 1000 + (unsigned long)(pcurt)->wMilliseconds) + +#else /* GC_USE_WIN32_SYSTEMTIME */ + +#ifdef GC_USE_GETTIMEOFDAY + +#ifndef _SYS_TIME_H +#include +/* int gettimeofday(struct timeval *, void *); */ +#endif + +#define GC_CURTIME_T struct timeval + +#ifdef _SVID_GETTOD +#define GC_CURTIME_GETMS(pcurt) (gettimeofday((void *)(pcurt)), (unsigned long)(pcurt)->tv_sec * 1000 + (unsigned long)(pcurt)->tv_usec / 1000) +#else +#define GC_CURTIME_GETMS(pcurt) (gettimeofday((void *)(pcurt), NULL), (unsigned long)(pcurt)->tv_sec * 1000 + (unsigned long)(pcurt)->tv_usec / 1000) +#endif + +#else /* GC_USE_GETTIMEOFDAY */ + +#ifndef _TIME_H +#include +#endif + +#ifndef _SYS_TIMEB_H +#include +/* void ftime(struct timeb *); */ +#endif + +#define GC_CURTIME_T struct timeb +#define GC_CURTIME_GETMS(pcurt) (ftime(pcurt), (unsigned long)(pcurt)->time * 1000 + (unsigned long)(pcurt)->millitm) + +#endif /* ! GC_USE_GETTIMEOFDAY */ + +#endif /* ! GC_USE_WIN32_SYSTEMTIME */ + +#define GC_SIZE_TO_ULKB(size) ((unsigned long)((size) >> 10)) + +#ifndef GC_NEW_LINE +#define GC_NEW_LINE "\n" +#endif + +#endif /* GC_PRINT_MSGS */ + +#ifndef GC_API +#ifdef GC_DLL +#define GC_API __declspec(dllexport) +#endif +#endif + +#include "gc.h" + +#include "gc_gcj.h" + +#include "gc_mark.h" + +#include "javaxfc.h" + +#ifndef NULL +#define NULL (void *)0 +#endif + +#ifndef CHAR_BIT +#define CHAR_BIT 8 +#endif + +#ifndef CONST +#define CONST const +#endif + +#ifndef GC_FATAL_ABORT +#define GC_FATAL_ABORT exit(-1) /* abort(), DebugBreak() */ +#endif + +#ifndef GC_DATASTATIC +#define GC_DATASTATIC static +#endif + +#ifndef GC_STATIC +#define GC_STATIC static +#endif + +#ifndef GC_INLINE_STATIC +#ifdef INLINE +#define GC_INLINE_STATIC GC_STATIC INLINE +#else +#define GC_INLINE_STATIC GC_STATIC __inline +#endif +#endif + +#ifndef GC_FASTCALL +#define GC_FASTCALL __fastcall +#endif + +#ifndef GC_CORE_API +#define GC_CORE_API extern +#endif + +#ifndef GC_CORE_CALL +#define GC_CORE_CALL GC_CALL +#endif + +#ifdef GC_PUSHREGS_BEGIN +#ifndef GC_PUSHREGS_END +#define GC_PUSHREGS_END (void)0 +#endif +#else +#define GC_PUSHREGS_BEGIN jmp_buf buf; (void)setjmp(buf) +#ifndef GC_PUSHREGS_END +#define GC_PUSHREGS_END GC_noop1((GC_word)(&buf)) +#endif +#endif + +#define GC_MEM_BZERO(ptr, size) (void)memset(ptr, '\0', (size_t)(size)) + +#ifdef GC_THREADS + +#ifdef GC_WIN32_THREADS + +#ifndef GC_WIN32_CONTEXT_SP_NAME +#ifdef _M_AMD64 +#define GC_WIN32_CONTEXT_SP_NAME Rsp +#else +#ifdef _M_X64 +#define GC_WIN32_CONTEXT_SP_NAME Rsp +#else +#ifdef __x86_64 +#define GC_WIN32_CONTEXT_SP_NAME Rsp +#endif +#endif +#endif +#endif + +#ifndef GC_WIN32_CONTEXT_SP_NAME +#ifdef _M_ALPHA +#define GC_WIN32_CONTEXT_SP_NAME IntSp +#else +#ifdef _ALPHA_ +#define GC_WIN32_CONTEXT_SP_NAME IntSp +#else +#ifdef _M_MRX000 +#define GC_WIN32_CONTEXT_SP_NAME IntSp +#else +#ifdef _MIPS_ +#define GC_WIN32_CONTEXT_SP_NAME IntSp +#endif +#endif +#endif +#endif +#endif + +#ifndef GC_WIN32_CONTEXT_SP_NAME +#ifdef _M_ARM +#define GC_WIN32_CONTEXT_SP_NAME Sp +#else +#ifdef _ARM_ +#define GC_WIN32_CONTEXT_SP_NAME Sp +#else +#ifdef _M_PPC +#define GC_WIN32_CONTEXT_SP_NAME Gpr1 +#else +#ifdef _PPC_ +#define GC_WIN32_CONTEXT_SP_NAME Gpr1 +#else +#ifdef _M_SH +#define GC_WIN32_CONTEXT_SP_NAME R15 +#else +#ifdef SHx +#define GC_WIN32_CONTEXT_SP_NAME R15 +#endif +#endif +#endif +#endif +#endif +#endif +#endif + +#ifndef GC_WIN32_CONTEXT_SP_NAME +#define GC_WIN32_CONTEXT_SP_NAME Esp /* x86 */ +#endif + +#ifndef GC_THREAD_YIELD +#define GC_THREAD_YIELD Sleep(10) /* "long" yield */ +#endif + +#define GC_THREAD_ID_T DWORD + +#ifdef GC_WIN32_WCE +#define GC_THREAD_HANDLE(stkroot) ((HANDLE)(GC_word)(stkroot)->thread_id) +#else +#define GC_THREAD_HANDLE(stkroot) ((stkroot)->thread_handle) +#endif + +#else /* GC_WIN32_THREADS */ + +#ifndef GC_SIG_SUSPEND +#ifdef SIGPWR +#define GC_SIG_SUSPEND SIGPWR +#else +#ifdef SIGUSR1 +#define GC_SIG_SUSPEND SIGUSR1 +#else +#define GC_SIG_SUSPEND SIGILL +#endif +#endif +#endif + +#ifndef GC_CLIBDECL +#ifdef __CLIB +#define GC_CLIBDECL __CLIB +#else +#ifdef _USERENTRY +#define GC_CLIBDECL _USERENTRY +#else +#ifdef _RTL_FUNC +#define GC_CLIBDECL _RTL_FUNC +#else +#define GC_CLIBDECL __cdecl +#endif +#endif +#endif +#endif + +#ifdef GC_ASYNC_PUSHREGS_BEGIN +#ifndef GC_ASYNC_PUSHREGS_END +#define GC_ASYNC_PUSHREGS_END (void)0 +#endif +#else +#define GC_ASYNC_PUSHREGS_BEGIN GC_PUSHREGS_BEGIN +#ifndef GC_ASYNC_PUSHREGS_END +#define GC_ASYNC_PUSHREGS_END GC_PUSHREGS_END +#endif +#endif + +#ifndef GC_THREAD_MUTEX_DEFATTR +#ifdef pthread_mutexattr_default +#define GC_THREAD_MUTEX_DEFATTR pthread_mutexattr_default +#else +#define GC_THREAD_MUTEX_DEFATTR NULL +#endif +#endif + +#ifndef GC_THREAD_YIELD +#define GC_THREAD_YIELD (void)sched_yield() +#endif + +#ifndef GC_YIELD_MAX_ATTEMPT +#define GC_YIELD_MAX_ATTEMPT 2 +#endif + +#define GC_ERRNO_SET(value) (void)(errno = (value)) + +#define GC_THREAD_ID_T pthread_t + +#endif /* ! GC_WIN32_THREADS */ + +#endif /* GC_THREADS */ + +#ifndef MARK_DESCR_OFFSET +#define MARK_DESCR_OFFSET sizeof(GC_word) +#endif + +#ifndef GC_LOG2_OFFIGNORE +#define GC_LOG2_OFFIGNORE 8 /* must be at least 3 */ +#endif + +#ifndef GC_FREE_SPACE_DIVISOR +#define GC_FREE_SPACE_DIVISOR 3 +#endif + +#ifndef GC_MAX_RETRIES +#define GC_MAX_RETRIES 2 +#endif + +#ifndef GC_LAZYREFILL_COUNT +#define GC_LAZYREFILL_COUNT 10 /* must be at least 3 */ +#endif + +#ifndef GC_LAZYREFILL_BIGCNT +#define GC_LAZYREFILL_BIGCNT 1024 +#endif + +#ifdef GC_OMIT_REGISTER_KEYWORD +#define GC_REGISTER_KEYWORD /* empty */ +#else +#define GC_REGISTER_KEYWORD register +#endif + +#define GC_DEFAULT_LOG2_OBJSIZE 8 +#define GC_DEFAULT_LOG2_SIZE 3 + +#define GC_MEM_SIZELIMIT ((GC_word)((~(size_t)0) >> 1) - ((GC_word)1 << (sizeof(int) << 1))) + +#define GC_ATOMIC_MASK (((~(GC_word)0) >> 1) + 1) + +#ifdef GC_GCJ_SUPPORT +#define GC_HASDSLEN_MASK (((GC_word)GC_ATOMIC_MASK) >> 1) +#else +#define GC_HASDSLEN_MASK 0 +#endif + +#define GC_NEVER_COLLECT (int)((((unsigned)-1) >> 1) + 1) + +#ifndef GC_NO_DLINKS +#define GC_HIDE_POINTER(ptr) (~(GC_word)(ptr)) +#endif + +#define GC_RANDOM_SEED(gcdata) (((gcdata)->total_heapsize ^ (gcdata)->allocd_before_gc) + ((gcdata)->bytes_allocd ^ (gcdata)->marked_bytes) + ((gcdata)->free_bytes ^ (gcdata)->obj_htable.pending_free_size)) +#define GC_HASH_INDEX(word_value, seed, log2_size) ((((word_value) ^ (seed)) * (GC_word)0x9E3779B1L) >> (sizeof(GC_word) * CHAR_BIT - (log2_size))) +#define GC_HASH_RESIZECOND(count, log2_size) (((GC_word)3 << ((log2_size) - 2)) <= (count)) + +#define GC_LEAVE(gcdata) GC_leave() + +#ifdef GC_CORE_MALLOC +GC_CORE_API void *GC_CORE_CALL GC_CORE_MALLOC(size_t size); +#else +#define GC_CORE_MALLOC malloc +#endif + +#ifdef GC_CORE_FREE +GC_CORE_API void GC_CORE_CALL GC_CORE_FREE(void *ptr); +#else +#define GC_CORE_FREE free +#endif + +#ifdef GC_STACKBOTTOMVAR +extern char *GC_STACKBOTTOMVAR; +#endif + +#ifdef GC_STACKLENVAR +extern GC_word GC_STACKLENVAR; +#endif + +#ifndef GC_STACKBOTTOM +#ifdef GC_STACKBOTTOMVAR +#define GC_STACKBOTTOM GC_STACKBOTTOMVAR +#else +#define GC_STACKBOTTOM 0 +#endif +#endif + +#ifndef GC_STACKLEN +#ifdef GC_STACKLENVAR +#define GC_STACKLEN GC_STACKLENVAR +#else +#define GC_STACKLEN 0 +#endif +#endif + +struct GC_objlink_s +{ + void *obj; + struct GC_objlink_s *next; + GC_word atomic_and_size; +}; + +struct GC_obj_htable_s +{ + struct GC_objlink_s **hroots; + struct GC_objlink_s *free_list; + struct GC_objlink_s *marked_list; + struct GC_objlink_s *follow_list; + struct GC_objlink_s *unlinked_list; + GC_word min_obj_addr; + GC_word max_obj_addr; + GC_word count; + GC_word log2_size; + GC_word pending_free_size; +}; + +#ifndef GC_NO_DLINKS + +struct GC_dlink_s +{ + struct GC_dlink_s *next; + struct GC_objlink_s *objlink; + GC_word hidden_link; +}; + +struct GC_dlink_htable_s +{ + struct GC_dlink_s **hroots; + struct GC_dlink_s *free_list; + GC_word count; + GC_word log2_size; + GC_word seed; +}; + +#endif /* ! GC_NO_DLINKS */ + +#ifndef GC_NO_FNLZ + +struct GC_fnlz_s +{ + struct GC_fnlz_s *next; + struct GC_objlink_s *objlink; + void *client_data; + GC_finalization_proc fn; +}; + +struct GC_fnlz_htable_s +{ + struct GC_fnlz_s **hroots; + struct GC_fnlz_s *ready_fnlz; + struct GC_fnlz_s *single_free; + GC_word count; + GC_word log2_size; + GC_word seed; + int has_client_ptrs; +}; + +#endif /* ! GC_NO_FNLZ */ + +#ifndef GC_NO_INACTIVE + +struct GC_activation_frame_s +{ + GC_word inactive_sp; + CONST struct GC_activation_frame_s *prev; +}; + +#endif /* ! GC_NO_INACTIVE */ + +struct GC_dataroot_s +{ + struct GC_dataroot_s *next; + GC_word begin_addr; + GC_word end_addr; +}; + +struct GC_stkroot_s +{ + GC_word begin_addr; + GC_word end_addr; +#ifndef GC_NO_INACTIVE + CONST struct GC_activation_frame_s *activation_frame; +#endif +#ifdef GC_THREADS + struct GC_stkroot_s *next; + GC_THREAD_ID_T thread_id; +#ifdef GC_WIN32_THREADS +#ifndef GC_WIN32_WCE + HANDLE thread_handle; +#endif +#else + volatile int suspend_ack; +#endif +#endif +#ifndef GC_NO_INACTIVE + int inactive; +#endif +#ifndef GC_NO_FNLZ + int inside_fnlz; +#endif +}; + +#ifdef GC_THREADS + +struct GC_stkroot_htable_s +{ + struct GC_stkroot_s **hroots; + GC_word count; + GC_word log2_size; + GC_word seed; +}; + +#endif /* GC_THREADS */ + +struct GC_gcdata_s +{ + struct GC_obj_htable_s obj_htable; + void *objlinks_block_list; +#ifndef GC_NO_DLINKS + struct GC_dlink_htable_s dlink_htable; +#endif +#ifndef GC_NO_FNLZ + struct GC_fnlz_htable_s fnlz_htable; + GC_word notifier_gc_no; + GC_word bytes_finalized; +#endif + struct GC_stkroot_s *cur_stack; + struct GC_dataroot_s *dataroots; + GC_word dataroot_size; + GC_word expanded_heapsize; + GC_word total_heapsize; + GC_word allocd_before_gc; + GC_word bytes_allocd; + GC_word marked_bytes; + GC_word free_bytes; + GC_word followscan_size; +#ifdef GC_THREADS + struct GC_stkroot_htable_s stkroot_htable; +#endif + int recycling; +#ifdef GC_GCJ_SUPPORT +#ifndef GC_GETENV_SKIP +#ifndef GC_IGNORE_GCJ_INFO + int ignore_gcj_info; +#endif +#endif +#endif +}; + +volatile GC_word GC_noop_sink; + +GC_DATASTATIC GC_word GC_gc_no = 0; + +GC_DATASTATIC GC_word GC_free_space_divisor = (GC_FREE_SPACE_DIVISOR); +GC_DATASTATIC GC_word GC_max_retries = (GC_MAX_RETRIES); + +GC_DATASTATIC GC_finalizer_notifier_proc GC_finalizer_notifier = 0; + +GC_DATASTATIC GC_start_callback_proc GC_start_call_back = 0; + +#ifdef ALL_INTERIOR_POINTERS +GC_DATASTATIC int GC_all_interior_pointers = 1; +#else +GC_DATASTATIC int GC_all_interior_pointers = 0; +#endif + +#ifdef FINALIZE_ON_DEMAND +GC_DATASTATIC int GC_finalize_on_demand = 1; +#else +GC_DATASTATIC int GC_finalize_on_demand = 0; +#endif + +GC_DATASTATIC int GC_dont_gc = 0; + +#ifdef GC_DONT_EXPAND +GC_DATASTATIC int GC_dont_expand = 1; +#else +GC_DATASTATIC int GC_dont_expand = 0; +#endif + +GC_STATIC int GC_CALLBACK GC_never_stop_func(void); +GC_DATASTATIC GC_stop_func GC_default_stop_func = GC_never_stop_func; + +#ifndef GC_MISC_EXCLUDE +GC_STATIC void GC_CALLBACK GC_default_warn_proc(char *msg, GC_word arg); +GC_DATASTATIC GC_warn_proc GC_current_warn_proc = + GC_default_warn_proc; /* ignored */ +#endif + +GC_DATASTATIC int GC_stack_grows_up = 0; + +GC_DATASTATIC struct GC_gcdata_s *GC_gcdata_global = NULL; + +GC_DATASTATIC GC_word GC_max_heapsize = ~(GC_word)0; + +GC_DATASTATIC CONST struct GC_objlink_s GC_nil_objlink = { NULL, NULL, 0 }; + +#ifndef GC_NO_DLINKS +GC_DATASTATIC CONST struct GC_dlink_s GC_nil_dlink = { NULL, NULL, 0 }; +#endif + +#ifndef GC_NO_FNLZ +GC_DATASTATIC CONST struct GC_fnlz_s GC_nil_fnlz = { NULL, NULL, NULL, 0 }; +#endif + +#ifdef GC_PRINT_MSGS +GC_DATASTATIC int GC_verbose_gc = 0; +#endif + +#ifdef GC_THREADS + +#ifdef GC_WIN32_THREADS + +struct GC_mutex_s +{ + LONG state; + HANDLE event; +}; + +GC_DATASTATIC struct GC_mutex_s GC_allocate_ml = { 0, 0 }; + +#else /* GC_WIN32_THREADS */ + +volatile int GC_inside_collect = -1; + +GC_DATASTATIC pthread_mutex_t GC_allocate_ml; + +GC_STATIC void GC_CLIBDECL GC_suspend_handler(int sig); + +#endif /* ! GC_WIN32_THREADS */ + +GC_STATIC void GC_FASTCALL GC_stkroot_add(struct GC_gcdata_s *gcdata, + GC_THREAD_ID_T thread_id, struct GC_stkroot_s *new_stkroot); +GC_STATIC void GC_FASTCALL GC_stkroot_tblresize(struct GC_gcdata_s *gcdata, + struct GC_stkroot_s **new_hroots, GC_word new_log2_size); + +#else /* GC_THREADS */ + +GC_DATASTATIC int GC_allocate_ml = 0; + +#endif /* ! GC_THREADS */ + +GC_STATIC void *GC_FASTCALL GC_alloc_hroots(struct GC_gcdata_s *gcdata, + GC_word new_log2_size, CONST void *nil_ptr); +GC_STATIC void *GC_FASTCALL GC_core_malloc_with_gc(struct GC_gcdata_s *gcdata, + GC_word size, int *pres); +GC_STATIC int GC_FASTCALL GC_heap_expand(struct GC_gcdata_s *gcdata, + GC_word incsize); +GC_STATIC void *GC_FASTCALL GC_inner_core_malloc(struct GC_gcdata_s *gcdata, + GC_word size, int dont_expand); +GC_STATIC int GC_FASTCALL GC_roots_add(struct GC_gcdata_s *gcdata, + GC_word begin_addr, GC_word end_addr); + +void GC_noop1(GC_word value) +{ + GC_noop_sink = value; +} + +GC_word GC_approx_sp(void) +{ + volatile GC_word value; + value = (GC_word)(&value); + GC_noop1(value); + return value; +} + +GC_STATIC int GC_FASTCALL GC_roots_autodetect(struct GC_gcdata_s *gcdata) +{ + int res = GC_roots_add(gcdata, 0, 0); +#ifdef GC_DATASTART +#ifdef GC_DATAEND + res |= GC_roots_add(gcdata, (GC_word)GC_DATASTART, (GC_word)GC_DATAEND); +#endif +#endif +#ifdef GC_DATASTART2 +#ifdef GC_DATAEND2 + res |= GC_roots_add(gcdata, (GC_word)GC_DATASTART2, (GC_word)GC_DATAEND2); +#endif +#endif + return res; +} + +GC_INLINE_STATIC GC_word GC_FASTCALL GC_stack_detectbase(void) +{ + return (GC_word)(GC_STACKBOTTOM) + (GC_STACKLEN); +} + +GC_INLINE_STATIC GC_word GC_FASTCALL GC_stack_approx_size( + CONST struct GC_gcdata_s *gcdata) +{ + struct GC_stkroot_s *cur_stack = gcdata->cur_stack; + GC_word totalsize = cur_stack != NULL ? cur_stack->end_addr - + cur_stack->begin_addr : sizeof(GC_word); +#ifdef GC_THREADS + totalsize = gcdata->stkroot_htable.count * totalsize; +#endif + return totalsize; +} + +GC_INLINE_STATIC int GC_FASTCALL GC_guess_collect( + CONST struct GC_gcdata_s *gcdata, GC_word objsize) +{ + return (((GC_stack_approx_size(gcdata) + gcdata->followscan_size) << 1) + + gcdata->dataroot_size + + ((GC_word)sizeof(GC_word) << gcdata->obj_htable.log2_size) + +#ifndef GC_NO_DLINKS + ((GC_word)sizeof(GC_word) << gcdata->dlink_htable.log2_size) + +#endif + ((gcdata->marked_bytes + gcdata->bytes_allocd - + gcdata->followscan_size) >> 2)) / GC_free_space_divisor <= +#ifndef GC_NO_FNLZ + gcdata->bytes_finalized + +#endif + gcdata->bytes_allocd + objsize ? 1 : 0; +} + +GC_INLINE_STATIC GC_word GC_FASTCALL GC_guess_expand_size( + CONST struct GC_gcdata_s *gcdata, GC_word objsize) +{ + GC_word space_divisor = GC_free_space_divisor + 1; + return (gcdata->marked_bytes + gcdata->bytes_allocd) / space_divisor >= + gcdata->free_bytes ? gcdata->free_bytes * space_divisor + + (gcdata->bytes_allocd >> 3) + (objsize << 2) + + gcdata->dataroot_size : 0; +} + +GC_STATIC void GC_FASTCALL GC_abort_badptr(CONST void *ptr) +{ +#ifdef GC_PRINT_MSGS + fprintf(stderr, " GC: Illegal pointer specified: 0x%lX." GC_NEW_LINE, + (unsigned long)((GC_word)ptr)); +#else + GC_noop1((GC_word)ptr); +#endif + GC_FATAL_ABORT; +} + +GC_INLINE_STATIC int GC_FASTCALL GC_config_set(struct GC_gcdata_s *gcdata) +{ + int res = 0; +#ifdef GC_GETENV_SKIP +#ifdef GC_PRINT_MSGS + GC_verbose_gc = 1; +#endif + GC_noop1((GC_word)gcdata); +#else + char *str; + GC_word value; + if ((str = getenv("GC_ALL_INTERIOR_POINTERS")) != NULL && *str) + GC_all_interior_pointers = *str != '0' || *(str + 1) ? 1 : 0; + if ((str = getenv("GC_DONT_GC")) != NULL && *str) + GC_dont_gc = GC_NEVER_COLLECT; +#ifdef GC_GCJ_SUPPORT +#ifndef GC_IGNORE_GCJ_INFO + if ((str = getenv("GC_IGNORE_GCJ_INFO")) != NULL && *str) + gcdata->ignore_gcj_info = 1; +#endif +#endif +#ifdef GC_PRINT_MSGS + if ((str = getenv("GC_PRINT_STATS")) != NULL && *str) + GC_verbose_gc = 1; +#endif + if (((str = getenv("GC_FREE_SPACE_DIVISOR")) != NULL && *str && + ((GC_free_space_divisor = (GC_word)atol(str)) == 0 || + GC_free_space_divisor == ~(GC_word)0)) || + ((str = getenv("GC_MAXIMUM_HEAP_SIZE")) != NULL && *str && + (GC_max_heapsize = (GC_word)atol(str)) == 0) || + ((str = getenv("GC_INITIAL_HEAP_SIZE")) != NULL && *str && + ((value = (GC_word)atol(str)) - (GC_word)1 >= GC_max_heapsize || + (gcdata->total_heapsize < value && GC_heap_expand(gcdata, + value - gcdata->total_heapsize) < 0)))) + res = -1; +#endif + return res; +} + +GC_STATIC int GC_CALLBACK GC_never_stop_func(void) +{ + return 0; +} + +GC_API GC_word GC_CALL GC_get_gc_no(void) +{ + return GC_gc_no; +} + +GC_API void GC_CALL GC_set_finalize_on_demand(int value) +{ + GC_finalize_on_demand = value; +} + +GC_API void GC_CALL GC_set_java_finalization(int value) +{ + if (!value) + GC_abort_badptr(NULL); +} + +GC_API void GC_CALL GC_set_max_heap_size(GC_word size) +{ + GC_max_heapsize = size ? size : ~(GC_word)0; +} + +#ifndef GC_MISC_EXCLUDE + +GC_API void GC_CALL GC_set_free_space_divisor(GC_word value) +{ + if (!value || value == ~(GC_word)0) + GC_abort_badptr(NULL); + GC_free_space_divisor = value; +} + +GC_API void GC_CALL GC_set_all_interior_pointers(int value) +{ + GC_all_interior_pointers = value; +} + +GC_API void GC_CALL GC_set_dont_expand(int value) +{ + GC_dont_expand = value; +} + +GC_API void GC_CALL GC_set_no_dls(int value) +{ + /* dummy */ + GC_noop1((GC_word)value); +} + +GC_API void GC_CALL GC_set_dont_precollect(int value) +{ + /* dummy */ + GC_noop1((GC_word)value); +} + +GC_API void GC_CALL GC_set_force_unmap_on_gcollect(int value) +{ + /* dummy */ + GC_noop1((GC_word)value); +} + +GC_API void GC_CALL GC_set_max_retries(GC_word value) +{ + GC_max_retries = value; +} + +GC_STATIC void GC_CALLBACK GC_default_warn_proc(char *msg, GC_word arg) +{ + /* dummy */ + GC_noop1((GC_word)msg ^ arg); +} + +GC_API void GC_CALLBACK GC_ignore_warn_proc(char *msg, GC_word arg) +{ + GC_default_warn_proc(msg, arg); +} + +#endif /* ! GC_MISC_EXCLUDE */ + +GC_API void *GC_CALL GC_call_with_stack_base(GC_stack_base_func fn, + void *client_data) +{ + GC_word stack_data; + struct GC_stack_base sb; + sb.mem_base = (void *)&stack_data; + return (*fn)(&sb, client_data); +} + +GC_API int GC_CALL GC_get_stack_base(struct GC_stack_base *sb) +{ + if (sb == NULL) + GC_abort_badptr(NULL); + return GC_UNIMPLEMENTED; +} + +GC_INLINE_STATIC struct GC_gcdata_s *GC_FASTCALL GC_gcdata_alloc(void) +{ + struct GC_gcdata_s *gcdata; + if ((gcdata = GC_CORE_MALLOC(sizeof(struct GC_gcdata_s))) != NULL) + { + GC_MEM_BZERO(gcdata, sizeof(struct GC_gcdata_s)); + if ((gcdata->obj_htable.hroots = GC_alloc_hroots(gcdata, + GC_DEFAULT_LOG2_OBJSIZE, &GC_nil_objlink)) != NULL +#ifndef GC_NO_DLINKS + && (gcdata->dlink_htable.hroots = GC_alloc_hroots(gcdata, + GC_DEFAULT_LOG2_SIZE, &GC_nil_dlink)) != NULL +#endif +#ifndef GC_NO_FNLZ + && (gcdata->fnlz_htable.hroots = GC_alloc_hroots(gcdata, + GC_DEFAULT_LOG2_SIZE, &GC_nil_fnlz)) != NULL +#endif +#ifdef GC_THREADS + && (gcdata->stkroot_htable.hroots = GC_alloc_hroots(gcdata, + GC_DEFAULT_LOG2_SIZE, NULL)) != NULL +#endif + ) + { + gcdata->obj_htable.min_obj_addr = ~(GC_word)0; + gcdata->obj_htable.max_obj_addr = (GC_word)1 << GC_LOG2_OFFIGNORE; + gcdata->obj_htable.log2_size = GC_DEFAULT_LOG2_OBJSIZE; +#ifndef GC_NO_DLINKS + gcdata->dlink_htable.log2_size = GC_DEFAULT_LOG2_SIZE; +#endif +#ifndef GC_NO_FNLZ + gcdata->fnlz_htable.log2_size = GC_DEFAULT_LOG2_SIZE; + gcdata->notifier_gc_no = GC_gc_no; +#endif +#ifdef GC_THREADS + gcdata->stkroot_htable.log2_size = GC_DEFAULT_LOG2_SIZE; +#endif + } + else gcdata = NULL; + } + return gcdata; +} + +GC_STATIC int GC_FASTCALL GC_heap_expand(struct GC_gcdata_s *gcdata, + GC_word incsize) +{ + void *ptr; + GC_word free_bytes = gcdata->free_bytes; + GC_word total_heapsize = gcdata->total_heapsize; + GC_word max_heapsize; + int res = -1; + incsize = incsize > ((GC_word)sizeof(GC_word) << GC_LOG2_OFFIGNORE) ? + (incsize + (sizeof(GC_word) - 1)) & ~(sizeof(GC_word) - 1) : + (GC_word)sizeof(GC_word) << GC_LOG2_OFFIGNORE; + if (free_bytes + incsize <= GC_MEM_SIZELIMIT) + { + gcdata->expanded_heapsize = total_heapsize + incsize; + if ((max_heapsize = GC_max_heapsize) > total_heapsize) + { + if (max_heapsize - total_heapsize < incsize) + incsize = max_heapsize - total_heapsize; +#ifdef GC_PRINT_MSGS + if (GC_verbose_gc) + fprintf(stdout, + "[GC: Expand by %lu KiB after %lu KiB allocd, %lu KiB free of %lu KiB]" + GC_NEW_LINE, GC_SIZE_TO_ULKB(incsize), + GC_SIZE_TO_ULKB(gcdata->bytes_allocd), GC_SIZE_TO_ULKB(free_bytes), + GC_SIZE_TO_ULKB(total_heapsize)); +#endif + while ((ptr = GC_CORE_MALLOC((size_t)free_bytes + + (size_t)incsize)) == NULL) + if ((incsize = incsize >> 1) == 0) + break; + if (ptr != NULL) + { + total_heapsize += incsize; + GC_CORE_FREE(ptr); + gcdata->expanded_heapsize = total_heapsize; + gcdata->total_heapsize = total_heapsize; + gcdata->free_bytes = free_bytes + incsize; + res = 0; + } + } + } + return res; +} + +#ifndef GC_MISC_EXCLUDE + +GC_STATIC void GC_FASTCALL GC_roots_del_inside(struct GC_gcdata_s *gcdata, + GC_word begin_addr, GC_word end_addr) +{ + GC_REGISTER_KEYWORD struct GC_dataroot_s *dataroot; + GC_REGISTER_KEYWORD struct GC_dataroot_s **pnext = &gcdata->dataroots; + struct GC_dataroot_s *pred; + GC_word count; + while ((dataroot = *pnext) != NULL && dataroot->begin_addr < begin_addr) + pnext = &dataroot->next; + if (dataroot != NULL) + { + count = 0; + do + { + if (end_addr < dataroot->end_addr) + break; + gcdata->dataroot_size -= dataroot->end_addr - dataroot->begin_addr; + dataroot = (pred = dataroot)->next; + GC_CORE_FREE(pred); + count++; + } while (dataroot != NULL); + *pnext = dataroot; + gcdata->free_bytes += count * sizeof(struct GC_dataroot_s); + } +} + +GC_INLINE_STATIC int GC_FASTCALL GC_roots_exclude(struct GC_gcdata_s *gcdata, + GC_word begin_addr, GC_word end_addr) +{ + struct GC_dataroot_s *dataroot = gcdata->dataroots; + struct GC_dataroot_s *new_dataroot; + int res = 0; + while (dataroot != NULL && begin_addr >= dataroot->end_addr) + dataroot = dataroot->next; + if (dataroot != NULL && dataroot->begin_addr < end_addr) + { + if (dataroot->begin_addr < begin_addr) + { + if (end_addr < dataroot->end_addr) + { + new_dataroot = GC_core_malloc_with_gc(gcdata, + sizeof(struct GC_dataroot_s), &res); + res = -1; + if (new_dataroot != NULL) + { + gcdata->dataroot_size -= end_addr - begin_addr; + new_dataroot->begin_addr = end_addr; + new_dataroot->end_addr = dataroot->end_addr; + new_dataroot->next = dataroot->next; + dataroot->end_addr = begin_addr; + dataroot->next = new_dataroot; + res = 0; + } + } + else + { + gcdata->dataroot_size -= dataroot->end_addr - begin_addr; + dataroot->end_addr = begin_addr; + if ((dataroot = dataroot->next) != NULL && + dataroot->begin_addr < end_addr && end_addr < dataroot->end_addr) + { + gcdata->dataroot_size -= end_addr - dataroot->begin_addr; + dataroot->begin_addr = end_addr; + } + } + } + else + { + gcdata->dataroot_size -= end_addr - dataroot->begin_addr; + dataroot->begin_addr = end_addr; + } + } + return res; +} + +#endif /* ! GC_MISC_EXCLUDE */ + +GC_STATIC int GC_FASTCALL GC_roots_add(struct GC_gcdata_s *gcdata, + GC_word begin_addr, GC_word end_addr) +{ + GC_REGISTER_KEYWORD struct GC_dataroot_s *dataroot; + struct GC_dataroot_s *new_dataroot; + struct GC_dataroot_s **pnext; + int res = 0; + if (begin_addr) + { + begin_addr = (begin_addr + (sizeof(GC_word) - 1)) & ~(sizeof(GC_word) - 1); + if ((end_addr = end_addr & ~(sizeof(GC_word) - 1)) > begin_addr) + { + pnext = &gcdata->dataroots; + while ((dataroot = *pnext) != NULL && dataroot->end_addr < begin_addr) + pnext = &dataroot->next; + if (dataroot == NULL || end_addr < dataroot->begin_addr) + { + new_dataroot = GC_core_malloc_with_gc(gcdata, + sizeof(struct GC_dataroot_s), &res); + res = -1; + if (new_dataroot != NULL) + { + gcdata->dataroot_size += end_addr - begin_addr; + new_dataroot->begin_addr = begin_addr; + new_dataroot->end_addr = end_addr; + new_dataroot->next = dataroot; + *pnext = new_dataroot; + res = 0; + } + } + else + { + if (begin_addr < dataroot->begin_addr) + { + gcdata->dataroot_size += dataroot->begin_addr - begin_addr; + dataroot->begin_addr = begin_addr; + } + if (dataroot->end_addr < end_addr) + { + dataroot = dataroot->next; + while (dataroot != NULL && end_addr >= dataroot->begin_addr) + { + if (dataroot->end_addr >= end_addr) + end_addr = dataroot->end_addr; + gcdata->dataroot_size -= dataroot->end_addr - dataroot->begin_addr; + dataroot = (new_dataroot = dataroot)->next; + GC_CORE_FREE(new_dataroot); + gcdata->free_bytes += sizeof(struct GC_dataroot_s); + } + (new_dataroot = *pnext)->next = dataroot; + gcdata->dataroot_size += end_addr - new_dataroot->end_addr; + new_dataroot->end_addr = end_addr; + } + } + } + } + return res; +} + +#ifdef GC_WIN32_THREADS + +GC_INLINE_STATIC int GC_FASTCALL GC_win32_block_on_mutex( + struct GC_mutex_s *pmutex) +{ + while (InterlockedExchange(&pmutex->state, -1)) + if (WaitForSingleObject(pmutex->event, INFINITE) == WAIT_FAILED) + return -1; + return 0; +} + +#endif /* GC_WIN32_THREADS */ + +GC_STATIC int GC_FASTCALL GC_enter(struct GC_gcdata_s **pgcdata) +{ + GC_REGISTER_KEYWORD struct GC_gcdata_s *gcdata; + GC_REGISTER_KEYWORD struct GC_stkroot_s *cur_stack; + int res; +#ifdef GC_THREADS + struct GC_stkroot_s **new_hroots; + GC_THREAD_ID_T thread_id; + GC_word new_log2_size; + if ( +#ifdef GC_WIN32_THREADS + (!GC_allocate_ml.event && (GC_allocate_ml.event = + CreateEvent(NULL, (BOOL)0, (BOOL)0, NULL)) == 0) || + (InterlockedExchange(&GC_allocate_ml.state, 1) && + GC_win32_block_on_mutex(&GC_allocate_ml) < 0) || + (thread_id = GetCurrentThreadId()) == (GC_THREAD_ID_T)-1L +#else + (GC_inside_collect == -1 && (pthread_mutex_init(&GC_allocate_ml, + GC_THREAD_MUTEX_DEFATTR) ? 1 : (GC_inside_collect = 0))) || + pthread_mutex_lock(&GC_allocate_ml) || + (thread_id = pthread_self()) == (pthread_t)(~(GC_word)0) +#endif + ) + { + *(GC_THREAD_ID_T volatile *)&thread_id = 0; +#ifdef GC_PRINT_MSGS + fprintf(stderr, " GC: Cannot initialize or lock mutex!" GC_NEW_LINE); +#endif + GC_FATAL_ABORT; + } +#else + if (++GC_allocate_ml != 1) + { +#ifdef GC_PRINT_MSGS + fprintf(stderr, " GC: Not re-entrant!" GC_NEW_LINE); +#endif + GC_FATAL_ABORT; + } + res = GC_UNIMPLEMENTED; +#endif + if ((gcdata = GC_gcdata_global) == NULL) + { + if ((gcdata = GC_gcdata_alloc()) == NULL || GC_config_set(gcdata) < 0 || + GC_roots_autodetect(gcdata) < 0 || (gcdata->cur_stack = + GC_inner_core_malloc(gcdata, sizeof(struct GC_stkroot_s), 0)) == NULL) + { +#ifdef GC_PRINT_MSGS + fprintf(stderr, + " GC: Cannot startup - bad config params or no memory!" GC_NEW_LINE); +#endif + GC_FATAL_ABORT; + } + if (GC_approx_sp() > (GC_word)pgcdata) + GC_stack_grows_up = 1; + cur_stack = gcdata->cur_stack; +#ifndef GC_NO_INACTIVE + cur_stack->activation_frame = NULL; + cur_stack->inactive = 0; +#endif +#ifndef GC_NO_FNLZ + cur_stack->inside_fnlz = 0; +#endif + cur_stack->begin_addr = (cur_stack->end_addr = GC_stack_detectbase()) != 0 ? + cur_stack->end_addr : ~(GC_word)0; +#ifdef GC_THREADS + GC_stkroot_add(gcdata, thread_id, cur_stack); + res = GC_SUCCESS; +#endif + GC_gcdata_global = gcdata; + } + else + { + cur_stack = gcdata->cur_stack; +#ifdef GC_THREADS + res = GC_DUPLICATE; + if (cur_stack == NULL || cur_stack->thread_id != thread_id) + { + cur_stack = + gcdata->stkroot_htable.hroots[GC_HASH_INDEX((GC_word)thread_id, + gcdata->stkroot_htable.seed, gcdata->stkroot_htable.log2_size)]; + while (cur_stack != NULL && cur_stack->thread_id != thread_id) + cur_stack = cur_stack->next; + if ((gcdata->cur_stack = cur_stack) == NULL) + { + if (GC_HASH_RESIZECOND(gcdata->stkroot_htable.count, + gcdata->stkroot_htable.log2_size) && + (new_hroots = GC_alloc_hroots(gcdata, new_log2_size = + gcdata->stkroot_htable.log2_size + 1, NULL)) != NULL) + GC_stkroot_tblresize(gcdata, new_hroots, new_log2_size); + res = 0; + if ((cur_stack = GC_core_malloc_with_gc(gcdata, + sizeof(struct GC_stkroot_s), &res)) == NULL) + { +#ifdef GC_PRINT_MSGS + fprintf(stderr, " GC: Cannot register new thread!" GC_NEW_LINE); +#endif + GC_FATAL_ABORT; + } +#ifndef GC_NO_INACTIVE + cur_stack->activation_frame = NULL; + cur_stack->inactive = 0; +#endif +#ifndef GC_NO_FNLZ + cur_stack->inside_fnlz = 0; +#endif + cur_stack->begin_addr = ~(GC_word)0; + cur_stack->end_addr = 0; + GC_stkroot_add(gcdata, thread_id, cur_stack); + gcdata->cur_stack = cur_stack; + res = GC_SUCCESS; + } + } +#endif + } + if (cur_stack->begin_addr >= (GC_word)pgcdata) + cur_stack->begin_addr = (GC_word)pgcdata - sizeof(GC_word); + if ((GC_word)pgcdata >= cur_stack->end_addr) + cur_stack->end_addr = (GC_word)pgcdata + (sizeof(GC_word) << 1); + *pgcdata = gcdata; + return res; +} + +GC_INLINE_STATIC void GC_FASTCALL GC_leave(void) +{ +#ifdef GC_THREADS +#ifdef GC_WIN32_THREADS + if (InterlockedExchange(&GC_allocate_ml.state, 0) < 0 && + !SetEvent(GC_allocate_ml.event)) + GC_FATAL_ABORT; +#else + if (pthread_mutex_unlock(&GC_allocate_ml)) + GC_FATAL_ABORT; +#endif +#else + GC_allocate_ml = 0; +#endif +} + +#ifndef GC_NO_INACTIVE + +GC_INLINE_STATIC int GC_FASTCALL GC_set_inactive_sp( + struct GC_gcdata_s **pgcdata) +{ + GC_REGISTER_KEYWORD struct GC_stkroot_s *cur_stack; + if ((cur_stack = (*pgcdata)->cur_stack) == NULL || cur_stack->inactive) + return 0; + if (GC_stack_grows_up) + cur_stack->end_addr = (GC_word)pgcdata - sizeof(GC_word); + else cur_stack->begin_addr = (GC_word)pgcdata + (sizeof(GC_word) << 1); + cur_stack->inactive = 1; + return 1; +} + +GC_INLINE_STATIC int GC_FASTCALL GC_set_activation_frame( + struct GC_activation_frame_s *activation_frame, + struct GC_stkroot_s *cur_stack) +{ + if (cur_stack == NULL || !cur_stack->inactive) + return 0; + activation_frame->inactive_sp = GC_stack_grows_up ? cur_stack->end_addr : + cur_stack->begin_addr; + activation_frame->prev = cur_stack->activation_frame; + cur_stack->inactive = 0; + cur_stack->activation_frame = activation_frame; + return 1; +} + +GC_INLINE_STATIC void GC_FASTCALL GC_restore_inactive_sp( + struct GC_stkroot_s *cur_stack, + CONST struct GC_activation_frame_s *activation_frame) +{ + cur_stack->activation_frame = activation_frame->prev; + *(GC_stack_grows_up ? &cur_stack->end_addr : + &cur_stack->begin_addr) = activation_frame->inactive_sp; + cur_stack->inactive = 1; +} + +#endif /* ! GC_NO_INACTIVE */ + +#ifdef GC_THREADS + +#ifndef GC_WIN32_THREADS + +GC_STATIC void GC_FASTCALL GC_thread_yield(int attempt) +{ + if (attempt >= GC_YIELD_MAX_ATTEMPT) + (void)pthread_usleep_np((unsigned)(attempt - GC_YIELD_MAX_ATTEMPT) * 1000); + else GC_THREAD_YIELD; +} + +#endif /* ! GC_WIN32_THREADS */ + +#endif /* GC_THREADS */ + +GC_STATIC void GC_FASTCALL GC_mutator_suspend(struct GC_gcdata_s *gcdata) +{ +#ifdef GC_THREADS + GC_REGISTER_KEYWORD GC_word addr; + GC_REGISTER_KEYWORD struct GC_stkroot_s *stkroot; +#ifndef GC_WIN32_THREADS + struct GC_stkroot_s **pnext; +#endif + struct GC_stkroot_s *cur_stack; +#ifndef GC_WIN32_THREADS + int attempt; + GC_inside_collect = 1; +#endif + if ((GC_word)((cur_stack = gcdata->cur_stack) != NULL ? 1 : 0) < + gcdata->stkroot_htable.count) + { + addr = (GC_word)gcdata->stkroot_htable.hroots - sizeof(GC_word); + for (;;) + { + for (;;) + { + if (*(void **)(addr += sizeof(GC_word)) != NULL) + break; + } + if ((GC_word)(stkroot = *(struct GC_stkroot_s **)addr) == ~(GC_word)0) + break; +#ifdef GC_WIN32_THREADS + do + { + if (stkroot != cur_stack +#ifndef GC_NO_INACTIVE + && !stkroot->inactive +#endif + ) + { +#ifdef GC_WIN32_WCE + while (SuspendThread(GC_THREAD_HANDLE(stkroot)) == ~(DWORD)0) + GC_THREAD_YIELD; +#else + if (SuspendThread(stkroot->thread_handle) == ~(DWORD)0) + { +#ifdef GC_PRINT_MSGS + fprintf(stderr, " GC: Cannot suspend thread!" GC_NEW_LINE); +#endif + GC_FATAL_ABORT; + } +#endif + } + } while ((stkroot = stkroot->next) != NULL); +#else + pnext = (struct GC_stkroot_s **)addr; + do + { + if (stkroot != cur_stack +#ifndef GC_NO_INACTIVE + && !stkroot->inactive +#endif + ) + { + stkroot->suspend_ack = 1; + (void)signal(GC_SIG_SUSPEND, GC_suspend_handler); + if (pthread_kill(stkroot->thread_id, GC_SIG_SUSPEND)) + { + *pnext = stkroot->next; +#ifdef GC_PRINT_MSGS + fprintf(stderr, + " GC: Cannot send signal to thread: 0x%lX." GC_NEW_LINE, + (unsigned long)((GC_word)stkroot->thread_id)); +#endif + gcdata->stkroot_htable.count--; + GC_CORE_FREE(stkroot); + gcdata->free_bytes += sizeof(struct GC_stkroot_s); + } + else pnext = &stkroot->next; + } + else pnext = &stkroot->next; + } while ((stkroot = *pnext) != NULL); +#endif + } +#ifndef GC_WIN32_THREADS + addr = (GC_word)gcdata->stkroot_htable.hroots - sizeof(GC_word); + for (;;) + { + for (;;) + { + if (*(void **)(addr += sizeof(GC_word)) != NULL) + break; + } + if ((GC_word)(stkroot = *(struct GC_stkroot_s **)addr) == ~(GC_word)0) + break; + do + { + attempt = 0; + while (stkroot->suspend_ack) + GC_thread_yield(attempt++); + } while ((stkroot = stkroot->next) != NULL); + } +#endif + } +#else + GC_noop1((GC_word)gcdata); +#endif +} + +GC_STATIC void GC_FASTCALL GC_mutator_resume(struct GC_gcdata_s *gcdata) +{ +#ifdef GC_THREADS +#ifdef GC_WIN32_THREADS + GC_REGISTER_KEYWORD GC_word addr; + GC_REGISTER_KEYWORD struct GC_stkroot_s *stkroot; + struct GC_stkroot_s *cur_stack; + DWORD res; + if ((GC_word)((cur_stack = gcdata->cur_stack) != NULL ? 1 : 0) < + gcdata->stkroot_htable.count) + { + addr = (GC_word)gcdata->stkroot_htable.hroots - sizeof(GC_word); + for (;;) + { + for (;;) + { + if (*(void **)(addr += sizeof(GC_word)) != NULL) + break; + } + if ((GC_word)(stkroot = *(struct GC_stkroot_s **)addr) == ~(GC_word)0) + break; + do + { + if (stkroot != cur_stack && +#ifndef GC_NO_INACTIVE + !stkroot->inactive && +#endif + ((res = ResumeThread(GC_THREAD_HANDLE(stkroot))) == ~(DWORD)0 || + !res)) + { +#ifdef GC_PRINT_MSGS + fprintf(stderr, " GC: Cannot resume thread!" GC_NEW_LINE); +#endif + GC_FATAL_ABORT; + } + } while ((stkroot = stkroot->next) != NULL); + } + } +#else + GC_inside_collect = 0; + GC_noop1((GC_word)gcdata); +#endif +#else + GC_noop1((GC_word)gcdata); +#endif +} + +GC_STATIC void GC_FASTCALL GC_scan_region(struct GC_gcdata_s *gcdata, + GC_word begin_addr, GC_word end_addr, int interior_pointers) +{ + GC_REGISTER_KEYWORD GC_word *region; + GC_REGISTER_KEYWORD GC_word *end_of_region; + GC_REGISTER_KEYWORD GC_word min_obj_addr; + GC_REGISTER_KEYWORD GC_word ignore_off; + GC_REGISTER_KEYWORD GC_word addr; + struct GC_objlink_s **hroots; + struct GC_objlink_s *marked_list; + struct GC_objlink_s *follow_list; + GC_word log2_size; + GC_word hmask; + GC_word count; + GC_word align_mask; + if (begin_addr < end_addr) + { + hroots = gcdata->obj_htable.hroots; + marked_list = gcdata->obj_htable.marked_list; + follow_list = gcdata->obj_htable.follow_list; + hmask = ((GC_word)1 << (log2_size = gcdata->obj_htable.log2_size)) - 1; + count = 0; + align_mask = 0; + ignore_off = gcdata->obj_htable.max_obj_addr - + (min_obj_addr = gcdata->obj_htable.min_obj_addr); + region = (GC_word *)begin_addr; + end_of_region = (GC_word *)end_addr; + if (!interior_pointers) + align_mask = sizeof(GC_word) - 1; + do + { + if (*region - min_obj_addr >= ignore_off) + do + { + if (++region >= end_of_region) + goto out; + } while (*region - min_obj_addr >= ignore_off); + if (((addr = *region) & align_mask) == 0) + { + GC_REGISTER_KEYWORD struct GC_objlink_s *objlink; + GC_REGISTER_KEYWORD struct GC_objlink_s **pnext; + if ((GC_word)(objlink = *(pnext = &hroots[(((addr >> log2_size) ^ addr) >> + GC_LOG2_OFFIGNORE) & hmask]))->obj > addr) + for (;;) + { + if ((GC_word)(objlink = *(pnext = &objlink->next))->obj <= addr) + break; + } + if (interior_pointers) + { + if ((objlink->atomic_and_size & ~(GC_ATOMIC_MASK | GC_HASDSLEN_MASK)) <= + addr - (GC_word)objlink->obj) + { + if ((addr | ~(((GC_word)1 << GC_LOG2_OFFIGNORE) - (GC_word)1)) == + ~(GC_word)0) + continue; + pnext = &hroots[((((addr - ((GC_word)1 << GC_LOG2_OFFIGNORE)) >> + log2_size) ^ (addr - ((GC_word)1 << GC_LOG2_OFFIGNORE))) >> + GC_LOG2_OFFIGNORE) & hmask]; + while ((GC_word)(objlink = *pnext)->obj > addr) + pnext = &objlink->next; + if ((objlink->atomic_and_size & ~(GC_ATOMIC_MASK | GC_HASDSLEN_MASK)) <= + addr - (GC_word)objlink->obj) + continue; + } + } + else + { + if ((GC_word)objlink->obj != addr) + continue; + } + *pnext = objlink->next; + count++; + if ((objlink->atomic_and_size & GC_ATOMIC_MASK) != 0) + { + objlink->next = marked_list; + marked_list = objlink; + } + else + { + objlink->next = follow_list; + follow_list = objlink; + } + } + } while (++region < end_of_region); +out: + gcdata->obj_htable.count -= count; + gcdata->obj_htable.marked_list = marked_list; + gcdata->obj_htable.follow_list = follow_list; + } +} + +GC_INLINE_STATIC void *GC_FASTCALL GC_roots_scan(struct GC_gcdata_s *gcdata, + GC_stop_func stop_func) +{ + struct GC_dataroot_s *dataroot; + if ((dataroot = gcdata->dataroots) != NULL) + { + do + { + if ((*stop_func)()) + break; + GC_scan_region(gcdata, dataroot->begin_addr, dataroot->end_addr, + GC_all_interior_pointers); + } while ((dataroot = dataroot->next) != NULL); + } + return dataroot; +} + +#ifndef GC_NO_INACTIVE + +#ifdef GC_THREADS +GC_STATIC +#else +GC_INLINE_STATIC +#endif +void GC_FASTCALL GC_stack_scan_frames(struct GC_gcdata_s *gcdata, + GC_word begin_addr, GC_word end_addr, + CONST struct GC_activation_frame_s *activation_frame) +{ + if (activation_frame != NULL) + { + if (GC_stack_grows_up) + { + do + { + GC_scan_region(gcdata, ((GC_word)activation_frame + + (sizeof(struct GC_activation_frame_s) + (sizeof(GC_word) << 1) - 1)) & + ~(sizeof(GC_word) - 1), end_addr & ~(sizeof(GC_word) - 1), 1); + end_addr = activation_frame->inactive_sp; + } while ((activation_frame = activation_frame->prev) != NULL); + } + else + { + do + { + GC_scan_region(gcdata, (begin_addr + (sizeof(GC_word) - 1)) & + ~(sizeof(GC_word) - 1), ((GC_word)activation_frame - sizeof(GC_word)) & + ~(sizeof(GC_word) - 1), 1); + begin_addr = activation_frame->inactive_sp; + } while ((activation_frame = activation_frame->prev) != NULL); + } + } + GC_scan_region(gcdata, (begin_addr + (sizeof(GC_word) - 1)) & + ~(sizeof(GC_word) - 1), end_addr & ~(sizeof(GC_word) - 1), 1); +} + +#endif /* ! GC_NO_INACTIVE */ + +GC_STATIC void GC_FASTCALL GC_stack_scan_cur(struct GC_gcdata_s *gcdata) +{ + GC_word begin_addr; + GC_word end_addr; + struct GC_stkroot_s *cur_stack; + GC_PUSHREGS_BEGIN; + if ((cur_stack = gcdata->cur_stack) != NULL) + { + begin_addr = cur_stack->begin_addr; + end_addr = GC_approx_sp(); + if (!GC_stack_grows_up) + { + begin_addr = end_addr; + end_addr = cur_stack->end_addr; + } +#ifdef GC_NO_INACTIVE + GC_scan_region(gcdata, (begin_addr + (sizeof(GC_word) - 1)) & + ~(sizeof(GC_word) - 1), end_addr & ~(sizeof(GC_word) - 1), 1); +#else + GC_stack_scan_frames(gcdata, begin_addr, end_addr, + cur_stack->activation_frame); +#endif + } + GC_PUSHREGS_END; +} + +GC_STATIC void GC_FASTCALL GC_scan_followable(struct GC_gcdata_s *gcdata, + GC_stop_func stop_func) +{ + GC_REGISTER_KEYWORD struct GC_objlink_s *objlink; + GC_word begin_addr; + while ((objlink = gcdata->obj_htable.follow_list) != NULL && !(*stop_func)()) + { + gcdata->obj_htable.follow_list = objlink->next; + objlink->next = gcdata->obj_htable.marked_list; + begin_addr = (GC_word)(gcdata->obj_htable.marked_list = objlink)->obj; +#ifdef GC_GCJ_SUPPORT +#ifdef GC_IGNORE_GCJ_INFO + GC_scan_region(gcdata, begin_addr, begin_addr + (objlink->atomic_and_size & + ~(GC_ATOMIC_MASK | (sizeof(GC_word) - 1))), GC_all_interior_pointers); +#else + GC_scan_region(gcdata, begin_addr, + (((objlink->atomic_and_size & GC_HASDSLEN_MASK) != 0 ? + *(GC_word *)(*(GC_word *)begin_addr + MARK_DESCR_OFFSET) : + objlink->atomic_and_size) & ~(GC_ATOMIC_MASK | (sizeof(GC_word) - 1))) + + begin_addr, GC_all_interior_pointers); +#endif +#else + GC_scan_region(gcdata, begin_addr, begin_addr + (objlink->atomic_and_size & + ~(GC_ATOMIC_MASK | (sizeof(GC_word) - 1))), GC_all_interior_pointers); +#endif + } +} + +#ifdef GC_THREADS + +#ifndef GC_WIN32_THREADS + +GC_STATIC void GC_CLIBDECL GC_suspend_handler(int sig) +{ + GC_REGISTER_KEYWORD struct GC_gcdata_s *gcdata; + struct GC_stkroot_s *volatile stkroot; + pthread_t thread_id; + int old_errno; + int attempt; + if ((gcdata = GC_gcdata_global) != NULL) + { + old_errno = errno; +#ifdef SIG_ACK + if (signal(sig, GC_suspend_handler) != SIG_DFL) + (void)signal(sig, SIG_ACK); +#else + (void)signal(sig, GC_suspend_handler); +#endif + thread_id = pthread_self(); + stkroot = + gcdata->stkroot_htable.hroots[GC_HASH_INDEX((GC_word)thread_id, + gcdata->stkroot_htable.seed, gcdata->stkroot_htable.log2_size)]; + while (stkroot != NULL && stkroot->thread_id != thread_id) + stkroot = stkroot->next; + if (gcdata->cur_stack != stkroot && stkroot != NULL +#ifndef GC_NO_INACTIVE + && !stkroot->inactive +#endif + ) + { + GC_ASYNC_PUSHREGS_BEGIN; + *(volatile GC_word *)(GC_stack_grows_up ? &stkroot->end_addr : + &stkroot->begin_addr) = GC_approx_sp(); + attempt = 0; + do + { + stkroot->suspend_ack = 0; + GC_thread_yield(attempt++); + } while (GC_inside_collect); + GC_ASYNC_PUSHREGS_END; + } + GC_ERRNO_SET(old_errno); + } +} + +#endif /* ! GC_WIN32_THREADS */ + +GC_STATIC GC_word GC_FASTCALL GC_stkroot_scan_other( + struct GC_gcdata_s *gcdata, GC_stop_func stop_func) +{ +#ifdef GC_WIN32_THREADS + CONTEXT context; +#endif + GC_REGISTER_KEYWORD GC_word addr; + struct GC_stkroot_s *stkroot = (void *)(~(GC_word)0); + struct GC_stkroot_s *cur_stack; + if ((cur_stack = gcdata->cur_stack) == NULL || + gcdata->stkroot_htable.count > (GC_word)1) + { + addr = (GC_word)gcdata->stkroot_htable.hroots - sizeof(GC_word); + do + { + for (;;) + { + if (*(void **)(addr += sizeof(GC_word)) != NULL) + break; + } + if ((GC_word)(stkroot = *(struct GC_stkroot_s **)addr) == ~(GC_word)0) + break; + do + { + if (stkroot != cur_stack) + { + if ((*stop_func)()) + break; +#ifdef GC_WIN32_THREADS +#ifndef GC_NO_INACTIVE + if (!stkroot->inactive) +#endif + { + context.ContextFlags = CONTEXT_INTEGER | CONTEXT_CONTROL; + if (GetThreadContext(GC_THREAD_HANDLE(stkroot), &context)) + { + GC_scan_region(gcdata, (GC_word)(&context), + (GC_word)(&context) + (sizeof(context) & ~(sizeof(GC_word) - 1)), 1); + if ((*stop_func)()) + break; + *(GC_stack_grows_up ? &stkroot->end_addr : &stkroot->begin_addr) = + context.GC_WIN32_CONTEXT_SP_NAME; + } +#ifdef GC_PRINT_MSGS + else fprintf(stderr, + " GC: Cannot get context of thread: 0x%lX." GC_NEW_LINE, + (unsigned long)stkroot->thread_id); +#endif + } +#endif +#ifdef GC_NO_INACTIVE + GC_scan_region(gcdata, (stkroot->begin_addr + (sizeof(GC_word) - 1)) & + ~(sizeof(GC_word) - 1), stkroot->end_addr & ~(sizeof(GC_word) - 1), 1); +#else + GC_stack_scan_frames(gcdata, stkroot->begin_addr, stkroot->end_addr, + stkroot->activation_frame); +#endif + } + } while ((stkroot = stkroot->next) != NULL); + } while (stkroot == NULL); + } + return ~(GC_word)stkroot; +} + +GC_STATIC void GC_FASTCALL GC_stkroot_tblresize(struct GC_gcdata_s *gcdata, + struct GC_stkroot_s **new_hroots, GC_word new_log2_size) +{ + GC_REGISTER_KEYWORD GC_word addr = + (GC_word)gcdata->stkroot_htable.hroots - sizeof(GC_word); + struct GC_stkroot_s **pnext; + struct GC_stkroot_s *stkroot; + struct GC_stkroot_s *new_stkroot; + GC_word seed = addr + GC_RANDOM_SEED(gcdata); + for (;;) + { + for (;;) + { + if (*(void **)(addr += sizeof(GC_word)) != NULL) + break; + } + if ((GC_word)(stkroot = *(struct GC_stkroot_s **)addr) == ~(GC_word)0) + break; + do + { + pnext = &new_hroots[GC_HASH_INDEX((GC_word)stkroot->thread_id, seed, + new_log2_size)]; + stkroot = (new_stkroot = stkroot)->next; + new_stkroot->next = *pnext; + *pnext = new_stkroot; + } while (stkroot != NULL); + } + gcdata->stkroot_htable.seed = seed; + GC_CORE_FREE(gcdata->stkroot_htable.hroots); + gcdata->free_bytes += ((GC_word)sizeof(GC_word) << + gcdata->stkroot_htable.log2_size) + sizeof(GC_word); + gcdata->stkroot_htable.hroots = new_hroots; + gcdata->stkroot_htable.log2_size = new_log2_size; +} + +GC_STATIC void GC_FASTCALL GC_stkroot_add(struct GC_gcdata_s *gcdata, + GC_THREAD_ID_T thread_id, struct GC_stkroot_s *new_stkroot) +{ + struct GC_stkroot_s **pnext = + &gcdata->stkroot_htable.hroots[GC_HASH_INDEX((GC_word)thread_id, + gcdata->stkroot_htable.seed, gcdata->stkroot_htable.log2_size)]; +#ifdef GC_WIN32_THREADS +#ifndef GC_WIN32_WCE + HANDLE process_handle = GetCurrentProcess(); + if (!DuplicateHandle(process_handle, GetCurrentThread(), process_handle, + &new_stkroot->thread_handle, 0, (BOOL)0, DUPLICATE_SAME_ACCESS)) + { +#ifdef GC_PRINT_MSGS + fprintf(stderr, " GC: Cannot duplicate thread handle!" GC_NEW_LINE); +#endif + GC_FATAL_ABORT; + } +#endif +#else + new_stkroot->suspend_ack = 0; +#endif + new_stkroot->next = *pnext; + new_stkroot->thread_id = thread_id; + *pnext = new_stkroot; + gcdata->stkroot_htable.count++; +#ifndef GC_WIN32_THREADS + (void)signal(GC_SIG_SUSPEND, GC_suspend_handler); +#endif +} + +GC_INLINE_STATIC void GC_FASTCALL GC_stkroot_delete_cur( + struct GC_gcdata_s *gcdata) +{ + struct GC_stkroot_s *cur_stack = gcdata->cur_stack; + GC_REGISTER_KEYWORD struct GC_stkroot_s **pnext = + &gcdata->stkroot_htable.hroots[GC_HASH_INDEX((GC_word)cur_stack->thread_id, + gcdata->stkroot_htable.seed, gcdata->stkroot_htable.log2_size)]; + while (*pnext != cur_stack) + pnext = &(*pnext)->next; + *pnext = cur_stack->next; + gcdata->stkroot_htable.count--; +#ifdef GC_WIN32_THREADS +#ifndef GC_WIN32_WCE + (void)CloseHandle(cur_stack->thread_handle); +#endif +#endif + gcdata->cur_stack = NULL; + GC_CORE_FREE(cur_stack); + gcdata->free_bytes += sizeof(struct GC_stkroot_s); +} + +#endif /* GC_THREADS */ + +#ifndef GC_NO_DLINKS + +GC_STATIC void GC_FASTCALL GC_dlink_scan_clear(struct GC_gcdata_s *gcdata) +{ + GC_REGISTER_KEYWORD GC_word addr = + (GC_word)gcdata->dlink_htable.hroots - sizeof(GC_word); + GC_REGISTER_KEYWORD struct GC_dlink_s *dlink; + struct GC_dlink_s **pnext; + struct GC_dlink_s *free_list = gcdata->dlink_htable.free_list; + struct GC_objlink_s **obj_hroots = gcdata->obj_htable.hroots; + GC_word obj_log2_size; + GC_word obj_hmask; + GC_word saved_addr; + GC_word count = 0; + obj_hmask = ((GC_word)1 << (obj_log2_size = + gcdata->obj_htable.log2_size)) - 1; + for (;;) + { + for (;;) + { + if (*(struct GC_dlink_s **)(addr += sizeof(GC_word)) != &GC_nil_dlink) + break; + } + if ((GC_word)(dlink = *(struct GC_dlink_s **)addr) == ~(GC_word)0) + break; + pnext = (struct GC_dlink_s **)(saved_addr = addr); + do + { + GC_REGISTER_KEYWORD struct GC_objlink_s *objlink; + addr = (GC_word)dlink->objlink->obj; + if ((GC_word)(objlink = obj_hroots[(((addr >> obj_log2_size) ^ addr) >> + GC_LOG2_OFFIGNORE) & obj_hmask])->obj > addr) + for (;;) + { + if ((GC_word)(objlink = objlink->next)->obj <= addr) + break; + } + if ((GC_word)objlink->obj == addr) + { + *pnext = dlink->next; + *(GC_word *)(~dlink->hidden_link) = 0; + dlink->next = free_list; + count++; + free_list = dlink; + } + else pnext = &dlink->next; + } while ((dlink = *pnext) != &GC_nil_dlink); + addr = saved_addr; + } + gcdata->dlink_htable.free_list = free_list; + gcdata->dlink_htable.count -= count; + gcdata->free_bytes += count * sizeof(struct GC_dlink_s); +} + +GC_STATIC GC_word GC_FASTCALL GC_dlink_free_pending( + struct GC_gcdata_s *gcdata, GC_word min_free_count) +{ + GC_REGISTER_KEYWORD struct GC_dlink_s *dlink; + GC_word count = 0; + do + { + if ((dlink = gcdata->dlink_htable.free_list) == NULL) + break; + gcdata->dlink_htable.free_list = dlink->next; + GC_CORE_FREE(dlink); + } while (++count < min_free_count); + return count; +} + +GC_INLINE_STATIC void GC_FASTCALL GC_dlink_tblresize( + struct GC_gcdata_s *gcdata, struct GC_dlink_s **new_hroots, + GC_word new_log2_size) +{ + GC_REGISTER_KEYWORD GC_word addr = + (GC_word)gcdata->dlink_htable.hroots - sizeof(GC_word); + struct GC_dlink_s **pnext; + struct GC_dlink_s *dlink; + GC_word hidden_link; + GC_word saved_addr; + GC_word seed = addr + GC_RANDOM_SEED(gcdata); + for (;;) + { + for (;;) + { + if (*(struct GC_dlink_s **)(addr += sizeof(GC_word)) != &GC_nil_dlink) + break; + } + if ((GC_word)(dlink = *(struct GC_dlink_s **)addr) == ~(GC_word)0) + break; + saved_addr = addr; + do + { + hidden_link = dlink->hidden_link; + pnext = &new_hroots[GC_HASH_INDEX(hidden_link >> GC_LOG2_OFFIGNORE, + seed, new_log2_size)]; + while (((struct GC_dlink_s *)(addr = (GC_word)(*pnext)))->hidden_link > + hidden_link) + pnext = &((struct GC_dlink_s *)addr)->next; + dlink = (*pnext = dlink)->next; + (*pnext)->next = (struct GC_dlink_s *)addr; + } while (dlink != &GC_nil_dlink); + addr = saved_addr; + } + gcdata->dlink_htable.seed = seed; + GC_CORE_FREE(gcdata->dlink_htable.hroots); + gcdata->free_bytes += ((GC_word)sizeof(GC_word) << + gcdata->dlink_htable.log2_size) + sizeof(GC_word); + gcdata->dlink_htable.hroots = new_hroots; + gcdata->dlink_htable.log2_size = new_log2_size; +} + +GC_INLINE_STATIC int GC_FASTCALL GC_dlink_add(struct GC_gcdata_s *gcdata, + GC_word hidden_link, struct GC_objlink_s *objlink, + struct GC_dlink_s *new_dlink) +{ + GC_REGISTER_KEYWORD struct GC_dlink_s *dlink; + struct GC_dlink_s **pnext; + if (!gcdata->dlink_htable.count) + gcdata->dlink_htable.seed += GC_RANDOM_SEED(gcdata); + pnext = &gcdata->dlink_htable.hroots[GC_HASH_INDEX(hidden_link >> + GC_LOG2_OFFIGNORE, gcdata->dlink_htable.seed, + gcdata->dlink_htable.log2_size)]; + while ((dlink = *pnext)->hidden_link > hidden_link) + pnext = &dlink->next; + if (dlink->hidden_link == hidden_link) + { + dlink->objlink = objlink; + if (new_dlink != NULL && + (dlink = gcdata->dlink_htable.free_list) != new_dlink) + { + new_dlink->next = dlink; + gcdata->dlink_htable.free_list = new_dlink; + gcdata->free_bytes += sizeof(struct GC_dlink_s); + } + return GC_DUPLICATE; + } + if (new_dlink == NULL) + return GC_NO_MEMORY; + if (gcdata->dlink_htable.free_list == new_dlink) + { + gcdata->free_bytes -= sizeof(struct GC_dlink_s); + gcdata->dlink_htable.free_list = new_dlink->next; + } + new_dlink->objlink = objlink; + new_dlink->next = dlink; + new_dlink->hidden_link = hidden_link; + *pnext = new_dlink; + gcdata->dlink_htable.count++; + return GC_SUCCESS; +} + +GC_STATIC int GC_FASTCALL GC_dlink_delete(struct GC_gcdata_s *gcdata, + GC_word hidden_link, GC_word min_hidden, GC_word max_hidden) +{ + GC_REGISTER_KEYWORD struct GC_dlink_s *dlink; + struct GC_dlink_s **pnext = + &gcdata->dlink_htable.hroots[GC_HASH_INDEX(hidden_link >> GC_LOG2_OFFIGNORE, + gcdata->dlink_htable.seed, gcdata->dlink_htable.log2_size)]; + while ((dlink = *pnext)->hidden_link > max_hidden) + pnext = &dlink->next; + if (dlink->hidden_link < min_hidden) + return 0; + do + { + *pnext = dlink->next; + gcdata->dlink_htable.count--; + GC_CORE_FREE(dlink); + dlink = *pnext; + gcdata->free_bytes += sizeof(struct GC_dlink_s); + } while (dlink->hidden_link >= min_hidden); + return 1; +} + +#endif /* ! GC_NO_DLINKS */ + +#ifndef GC_NO_FNLZ + +GC_STATIC int GC_FASTCALL GC_objlink_mark(struct GC_gcdata_s *gcdata, + GC_word addr, int interior_pointers) +{ + GC_REGISTER_KEYWORD struct GC_objlink_s *objlink; + GC_REGISTER_KEYWORD struct GC_objlink_s **pnext; + struct GC_objlink_s **hroots = gcdata->obj_htable.hroots; + GC_word log2_size = gcdata->obj_htable.log2_size; + pnext = &hroots[(((addr >> log2_size) ^ addr) >> GC_LOG2_OFFIGNORE) & + (((GC_word)1 << log2_size) - 1)]; + while ((GC_word)(objlink = *pnext)->obj > addr) + pnext = &objlink->next; + if (interior_pointers) + { + if ((objlink->atomic_and_size & ~(GC_ATOMIC_MASK | GC_HASDSLEN_MASK)) <= + addr - (GC_word)objlink->obj) + { + if ((addr | ~(((GC_word)1 << GC_LOG2_OFFIGNORE) - (GC_word)1)) == + ~(GC_word)0) + return 0; + pnext = &hroots[((((addr - ((GC_word)1 << GC_LOG2_OFFIGNORE)) >> + log2_size) ^ (addr - ((GC_word)1 << GC_LOG2_OFFIGNORE))) >> + GC_LOG2_OFFIGNORE) & (((GC_word)1 << log2_size) - 1)]; + while ((GC_word)(objlink = *pnext)->obj > addr) + pnext = &objlink->next; + if ((objlink->atomic_and_size & ~(GC_ATOMIC_MASK | GC_HASDSLEN_MASK)) <= + addr - (GC_word)objlink->obj) + return 0; + } + } + else + { + if ((GC_word)objlink->obj != addr) + return 0; + } + *pnext = objlink->next; + gcdata->obj_htable.count--; + if ((objlink->atomic_and_size & GC_ATOMIC_MASK) != 0) + { + objlink->next = gcdata->obj_htable.marked_list; + gcdata->obj_htable.marked_list = objlink; + } + else + { + objlink->next = gcdata->obj_htable.follow_list; + gcdata->obj_htable.follow_list = objlink; + } + return 1; +} + +GC_INLINE_STATIC GC_word GC_FASTCALL GC_fnlz_precollect( + struct GC_gcdata_s *gcdata, GC_word *pcount) +{ + GC_REGISTER_KEYWORD GC_word addr; + GC_REGISTER_KEYWORD struct GC_fnlz_s *fnlz; + void *client_data; + struct GC_objlink_s *objlink; + GC_word bytes_finalized = 0; + int interior_pointers = GC_all_interior_pointers; + if ((fnlz = gcdata->fnlz_htable.ready_fnlz) != NULL) + { + addr = 0; + do + { + bytes_finalized += (objlink = fnlz->objlink)->atomic_and_size; + (void)GC_objlink_mark(gcdata, (GC_word)objlink->obj, 0); + addr++; + if ((client_data = fnlz->client_data) != NULL) + (void)GC_objlink_mark(gcdata, (GC_word)client_data, interior_pointers); + } while ((fnlz = fnlz->next) != NULL); + *pcount += addr; + } + if (gcdata->fnlz_htable.has_client_ptrs) + { + addr = (GC_word)gcdata->fnlz_htable.hroots - sizeof(GC_word); + for (;;) + { + for (;;) + { + if (*(struct GC_fnlz_s **)(addr += sizeof(GC_word)) != &GC_nil_fnlz) + break; + } + if ((GC_word)(fnlz = *(struct GC_fnlz_s **)addr) == ~(GC_word)0) + break; + do + { + if ((client_data = fnlz->client_data) != NULL) + (void)GC_objlink_mark(gcdata, (GC_word)client_data, interior_pointers); + } while ((fnlz = fnlz->next) != &GC_nil_fnlz); + } + } + return bytes_finalized & ~(GC_ATOMIC_MASK | GC_HASDSLEN_MASK); +} + +GC_STATIC GC_word GC_FASTCALL GC_fnlz_after_collect( + struct GC_gcdata_s *gcdata, GC_word *pcount) +{ + GC_REGISTER_KEYWORD GC_word addr = + (GC_word)gcdata->fnlz_htable.hroots - sizeof(GC_word); + GC_REGISTER_KEYWORD struct GC_fnlz_s *fnlz; + struct GC_fnlz_s **pnext; + struct GC_fnlz_s *ready_fnlz = gcdata->fnlz_htable.ready_fnlz; + struct GC_objlink_s *objlink; + GC_word bytes_finalized = 0; + GC_word count = 0; + for (;;) + { + for (;;) + { + if (*(struct GC_fnlz_s **)(addr += sizeof(GC_word)) != &GC_nil_fnlz) + break; + } + if ((GC_word)(fnlz = *(struct GC_fnlz_s **)addr) == ~(GC_word)0) + break; + pnext = (struct GC_fnlz_s **)addr; + do + { + if (GC_objlink_mark(gcdata, (GC_word)(objlink = fnlz->objlink)->obj, 0)) + { + *pnext = fnlz->next; + bytes_finalized += objlink->atomic_and_size; + fnlz->next = ready_fnlz; + count++; + ready_fnlz = fnlz; + } + else pnext = &fnlz->next; + } while ((fnlz = *pnext) != &GC_nil_fnlz); + } + gcdata->fnlz_htable.ready_fnlz = ready_fnlz; + if ((gcdata->fnlz_htable.count -= count) == 0) + gcdata->fnlz_htable.has_client_ptrs = 0; + gcdata->free_bytes += count * sizeof(struct GC_fnlz_s); + *pcount += count; + return bytes_finalized & ~(GC_ATOMIC_MASK | GC_HASDSLEN_MASK); +} + +GC_INLINE_STATIC void GC_FASTCALL GC_fnlz_tblresize( + struct GC_gcdata_s *gcdata, struct GC_fnlz_s **new_hroots, + GC_word new_log2_size) +{ + GC_REGISTER_KEYWORD GC_word addr = + (GC_word)gcdata->fnlz_htable.hroots - sizeof(GC_word); + struct GC_fnlz_s **pnext; + struct GC_fnlz_s *fnlz; + struct GC_objlink_s *objlink; + GC_word saved_addr; + GC_word seed = addr + GC_RANDOM_SEED(gcdata); + for (;;) + { + for (;;) + { + if (*(struct GC_fnlz_s **)(addr += sizeof(GC_word)) != &GC_nil_fnlz) + break; + } + if ((GC_word)(fnlz = *(struct GC_fnlz_s **)addr) == ~(GC_word)0) + break; + saved_addr = addr; + do + { + objlink = fnlz->objlink; + pnext = &new_hroots[GC_HASH_INDEX((GC_word)objlink / + (sizeof(GC_word) << 1), seed, new_log2_size)]; + while ((GC_word)((struct GC_fnlz_s *)(addr = (GC_word)(*pnext)))->objlink > + (GC_word)objlink) + pnext = &((struct GC_fnlz_s *)addr)->next; + fnlz = (*pnext = fnlz)->next; + (*pnext)->next = (struct GC_fnlz_s *)addr; + } while (fnlz != &GC_nil_fnlz); + addr = saved_addr; + } + gcdata->fnlz_htable.seed = seed; + GC_CORE_FREE(gcdata->fnlz_htable.hroots); + gcdata->free_bytes += ((GC_word)sizeof(GC_word) << + gcdata->fnlz_htable.log2_size) + sizeof(GC_word); + gcdata->fnlz_htable.hroots = new_hroots; + gcdata->fnlz_htable.log2_size = new_log2_size; +} + +GC_INLINE_STATIC GC_finalization_proc GC_FASTCALL GC_fnlz_add_del( + struct GC_gcdata_s *gcdata, struct GC_objlink_s *objlink, + GC_finalization_proc fn, void *client_data, void **odata) +{ + GC_REGISTER_KEYWORD struct GC_fnlz_s *fnlz; + struct GC_fnlz_s **pnext; + struct GC_fnlz_s *new_fnlz; + GC_finalization_proc old_fn; + if (!gcdata->fnlz_htable.count) + gcdata->fnlz_htable.seed += GC_RANDOM_SEED(gcdata); + pnext = &gcdata->fnlz_htable.hroots[GC_HASH_INDEX((GC_word)objlink / + (sizeof(GC_word) << 1), gcdata->fnlz_htable.seed, + gcdata->fnlz_htable.log2_size)]; + while ((GC_word)(fnlz = *pnext)->objlink > (GC_word)objlink) + pnext = &fnlz->next; + if (fnlz->objlink == objlink) + { + *odata = fnlz->client_data; + old_fn = fnlz->fn; + if (fn != 0) + { + fnlz->client_data = client_data; + fnlz->fn = fn; + if (!gcdata->fnlz_htable.has_client_ptrs && + (GC_word)client_data >= gcdata->obj_htable.min_obj_addr && + (GC_word)client_data < gcdata->obj_htable.max_obj_addr) + gcdata->fnlz_htable.has_client_ptrs = 1; + } + else + { + *pnext = fnlz->next; + if (gcdata->fnlz_htable.single_free != NULL) + { + GC_CORE_FREE(fnlz); + gcdata->free_bytes += sizeof(struct GC_fnlz_s); + } + else gcdata->fnlz_htable.single_free = fnlz; + if (!(--gcdata->fnlz_htable.count)) + gcdata->fnlz_htable.has_client_ptrs = 0; + } + } + else + { + if (fn != 0) + { + if ((new_fnlz = gcdata->fnlz_htable.single_free) != NULL) + { + gcdata->fnlz_htable.single_free = NULL; + new_fnlz->next = fnlz; + new_fnlz->objlink = objlink; + new_fnlz->client_data = client_data; + new_fnlz->fn = fn; + *pnext = new_fnlz; + gcdata->fnlz_htable.count++; + *odata = NULL; + if (!gcdata->fnlz_htable.has_client_ptrs && + (GC_word)client_data >= gcdata->obj_htable.min_obj_addr && + (GC_word)client_data < gcdata->obj_htable.max_obj_addr) + gcdata->fnlz_htable.has_client_ptrs = 1; + } + } + else *odata = NULL; + old_fn = 0; + } + return old_fn; +} + +GC_STATIC GC_finalization_proc GC_FASTCALL GC_fnlz_del_ready( + struct GC_gcdata_s *gcdata, struct GC_objlink_s **pobjlink, void **odata) +{ + GC_REGISTER_KEYWORD struct GC_fnlz_s *fnlz; + GC_finalization_proc fn = 0; + if ((fnlz = gcdata->fnlz_htable.ready_fnlz) != NULL) + { + *pobjlink = fnlz->objlink; + gcdata->fnlz_htable.ready_fnlz = fnlz->next; + *odata = fnlz->client_data; + fn = fnlz->fn; + GC_CORE_FREE(fnlz); + } + return fn; +} + +#ifndef JAVA_FINALIZATION_NOT_NEEDED + +GC_INLINE_STATIC void GC_FASTCALL GC_fnlz_ready_all( + struct GC_gcdata_s *gcdata) +{ + GC_REGISTER_KEYWORD GC_word addr = + (GC_word)gcdata->fnlz_htable.hroots - sizeof(GC_word); + GC_REGISTER_KEYWORD struct GC_fnlz_s *fnlz; + struct GC_fnlz_s *ready_fnlz = gcdata->fnlz_htable.ready_fnlz; + for (;;) + { + for (;;) + { + if (*(struct GC_fnlz_s **)(addr += sizeof(GC_word)) != &GC_nil_fnlz) + break; + } + if ((GC_word)(fnlz = *(struct GC_fnlz_s **)addr) == ~(GC_word)0) + break; + while (fnlz->next != &GC_nil_fnlz) + fnlz = fnlz->next; + fnlz->next = ready_fnlz; + ready_fnlz = *(struct GC_fnlz_s **)addr; + *(CONST struct GC_fnlz_s **)addr = &GC_nil_fnlz; + } + gcdata->free_bytes += gcdata->fnlz_htable.count * sizeof(struct GC_fnlz_s); + gcdata->fnlz_htable.ready_fnlz = ready_fnlz; + gcdata->fnlz_htable.count = 0; + gcdata->fnlz_htable.has_client_ptrs = 0; +} + +#endif /* ! JAVA_FINALIZATION_NOT_NEEDED */ + +#endif /* ! GC_NO_FNLZ */ + +GC_INLINE_STATIC void GC_FASTCALL GC_objlink_add(struct GC_gcdata_s *gcdata, + void *obj, GC_word objsize, GC_word vtable) +{ + GC_REGISTER_KEYWORD struct GC_objlink_s *objlink; + struct GC_objlink_s **pnext; + struct GC_objlink_s *new_objlink; + gcdata->obj_htable.unlinked_list = + (new_objlink = gcdata->obj_htable.unlinked_list)->next; + if (vtable) + { + GC_MEM_BZERO(obj, objsize); + gcdata->followscan_size += objsize & ~(sizeof(GC_word) - 1); +#ifdef GC_GCJ_SUPPORT +#ifdef GC_IGNORE_GCJ_INFO + if (vtable != ~(GC_word)0) + *(GC_word *)obj = vtable; + new_objlink->atomic_and_size = objsize; +#else + new_objlink->atomic_and_size = + vtable != ~(GC_word)0 && (*(GC_word *)obj = vtable, +#ifndef GC_GETENV_SKIP + !gcdata->ignore_gcj_info && +#endif + *(GC_word *)(vtable + MARK_DESCR_OFFSET) != GC_DS_LENGTH) ? + objsize | GC_HASDSLEN_MASK : objsize; +#endif +#else + new_objlink->atomic_and_size = objsize; +#endif + } + else new_objlink->atomic_and_size = objsize | GC_ATOMIC_MASK; + new_objlink->obj = obj; + if ((GC_word)(objlink = *(pnext = + &gcdata->obj_htable.hroots[(((((GC_word)obj) >> + gcdata->obj_htable.log2_size) ^ (GC_word)obj) >> GC_LOG2_OFFIGNORE) & + (((GC_word)1 << gcdata->obj_htable.log2_size) - 1)]))->obj > + (GC_word)obj) + for (;;) + { + if ((GC_word)(objlink = *(pnext = &objlink->next))->obj <= (GC_word)obj) + break; + } + new_objlink->next = objlink; + *pnext = new_objlink; + if (gcdata->obj_htable.min_obj_addr >= (GC_word)obj) + gcdata->obj_htable.min_obj_addr = (GC_word)obj; + if ((GC_word)obj + ((GC_word)1 << GC_LOG2_OFFIGNORE) > + gcdata->obj_htable.max_obj_addr) + gcdata->obj_htable.max_obj_addr = + (GC_word)obj + ((GC_word)1 << GC_LOG2_OFFIGNORE); + gcdata->obj_htable.count++; +} + +GC_STATIC GC_word GC_FASTCALL GC_objlink_remove_all( + struct GC_gcdata_s *gcdata) +{ + GC_REGISTER_KEYWORD GC_word addr = + (GC_word)gcdata->obj_htable.hroots - sizeof(GC_word); + GC_REGISTER_KEYWORD struct GC_objlink_s *objlink; + GC_word removed_bytes = 0; + GC_word count = 0; + struct GC_objlink_s *free_list = gcdata->obj_htable.free_list; + for (;;) + { + for (;;) + { + if (*(struct GC_objlink_s **)(addr += sizeof(GC_word)) != &GC_nil_objlink) + break; + } + if ((GC_word)(objlink = *(struct GC_objlink_s **)addr) == ~(GC_word)0) + break; + removed_bytes += objlink->atomic_and_size; + while (objlink->next != &GC_nil_objlink) + { + removed_bytes += (objlink = objlink->next)->atomic_and_size; + count++; + } + objlink->next = free_list; + count++; + free_list = *(struct GC_objlink_s **)addr; + *(CONST struct GC_objlink_s **)addr = &GC_nil_objlink; + } + gcdata->marked_bytes -= removed_bytes & ~(GC_ATOMIC_MASK | GC_HASDSLEN_MASK); + gcdata->obj_htable.free_list = free_list; + gcdata->obj_htable.count = 0; + gcdata->obj_htable.min_obj_addr = ~(GC_word)0; + gcdata->obj_htable.max_obj_addr = (GC_word)1 << GC_LOG2_OFFIGNORE; + return count; +} + +#ifdef GC_NO_FNLZ +#ifdef GC_NO_GCBASE +GC_INLINE_STATIC +#else +GC_STATIC +#endif +#else +GC_STATIC +#endif +struct GC_objlink_s *GC_FASTCALL GC_objlink_get(struct GC_gcdata_s *gcdata, + void *displaced_pointer) +{ + GC_REGISTER_KEYWORD struct GC_objlink_s *objlink; + struct GC_objlink_s **hroots = gcdata->obj_htable.hroots; + GC_word log2_size = gcdata->obj_htable.log2_size; + objlink = hroots[(((((GC_word)displaced_pointer) >> log2_size) ^ + (GC_word)displaced_pointer) >> GC_LOG2_OFFIGNORE) & + (((GC_word)1 << log2_size) - 1)]; + while ((GC_word)objlink->obj > (GC_word)displaced_pointer) + objlink = objlink->next; + if ((objlink->atomic_and_size & ~(GC_ATOMIC_MASK | GC_HASDSLEN_MASK)) <= + (GC_word)displaced_pointer - (GC_word)objlink->obj) + { + objlink = hroots[(((((GC_word)displaced_pointer - + (((GC_word)1 << GC_LOG2_OFFIGNORE) - (GC_word)1)) >> + log2_size) ^ ((GC_word)displaced_pointer - + (((GC_word)1 << GC_LOG2_OFFIGNORE) - (GC_word)1))) >> + GC_LOG2_OFFIGNORE) & (((GC_word)1 << log2_size) - 1)]; + while ((GC_word)objlink->obj > (GC_word)displaced_pointer) + objlink = objlink->next; + if ((objlink->atomic_and_size & ~(GC_ATOMIC_MASK | GC_HASDSLEN_MASK)) <= + (GC_word)displaced_pointer - (GC_word)objlink->obj) + objlink = NULL; + } + return objlink; +} + +#ifdef GC_NO_FNLZ +#ifdef GC_NO_GCBASE +GC_INLINE_STATIC +#else +GC_STATIC +#endif +#else +GC_STATIC +#endif +struct GC_objlink_s *GC_FASTCALL GC_objlink_refill_find( + struct GC_gcdata_s *gcdata, void *displaced_pointer) +{ + GC_REGISTER_KEYWORD struct GC_objlink_s *marked_list; + GC_REGISTER_KEYWORD struct GC_objlink_s **pnext; + struct GC_objlink_s *objlink; + struct GC_objlink_s **hroots; + GC_word min_obj_addr; + GC_word max_obj_addr; + GC_word log2_size; + GC_word hmask; + GC_word count; + if ((void *)(marked_list = gcdata->obj_htable.follow_list) != + (void *)gcdata->obj_htable.marked_list) + { + hroots = gcdata->obj_htable.hroots; + min_obj_addr = gcdata->obj_htable.min_obj_addr; + max_obj_addr = gcdata->obj_htable.max_obj_addr - + ((GC_word)1 << GC_LOG2_OFFIGNORE); + if (marked_list == NULL) + marked_list = gcdata->obj_htable.marked_list; + hmask = ((GC_word)1 << (log2_size = gcdata->obj_htable.log2_size)) - 1; + count = 0; + do + { + do + { + GC_REGISTER_KEYWORD GC_word addr = (GC_word)marked_list->obj; + if (min_obj_addr >= addr) + min_obj_addr = addr; + if (max_obj_addr <= addr) + max_obj_addr = addr; + pnext = &hroots[(((addr >> log2_size) ^ addr) >> + GC_LOG2_OFFIGNORE) & hmask]; + while ((GC_word)(objlink = *pnext)->obj > addr) + pnext = &objlink->next; + count++; + if ((GC_word)displaced_pointer - addr < + (marked_list->atomic_and_size & ~(GC_ATOMIC_MASK | GC_HASDSLEN_MASK))) + break; + marked_list = (*pnext = marked_list)->next; + (*pnext)->next = objlink; + } while (marked_list != NULL); + if (marked_list != NULL) + break; + if (gcdata->obj_htable.follow_list == NULL) + { + gcdata->obj_htable.marked_list = NULL; + break; + } + gcdata->obj_htable.follow_list = NULL; + } while ((marked_list = gcdata->obj_htable.marked_list) != NULL); + gcdata->obj_htable.min_obj_addr = min_obj_addr; + gcdata->obj_htable.max_obj_addr = + max_obj_addr + ((GC_word)1 << GC_LOG2_OFFIGNORE); + gcdata->obj_htable.count += count; + if (marked_list != NULL) + { + if (gcdata->obj_htable.follow_list != NULL) + gcdata->obj_htable.follow_list = marked_list->next; + else gcdata->obj_htable.marked_list = marked_list->next; + *pnext = marked_list; + marked_list->next = objlink; + } + } + return marked_list; +} + +GC_STATIC GC_word GC_FASTCALL GC_objlink_some_refill( + struct GC_gcdata_s *gcdata, GC_word max_count) +{ + GC_REGISTER_KEYWORD struct GC_objlink_s *marked_list; + GC_REGISTER_KEYWORD struct GC_objlink_s **pnext; + struct GC_objlink_s *objlink; + struct GC_objlink_s **hroots; + GC_word min_obj_addr; + GC_word max_obj_addr; + GC_word log2_size; + GC_word hmask; + GC_word count = 0; + if ((void *)(marked_list = gcdata->obj_htable.follow_list) != + (void *)gcdata->obj_htable.marked_list) + { + hroots = gcdata->obj_htable.hroots; + min_obj_addr = gcdata->obj_htable.min_obj_addr; + max_obj_addr = gcdata->obj_htable.max_obj_addr - + ((GC_word)1 << GC_LOG2_OFFIGNORE); + if (marked_list == NULL) + marked_list = gcdata->obj_htable.marked_list; + hmask = ((GC_word)1 << (log2_size = gcdata->obj_htable.log2_size)) - 1; + count = max_count; + do + { + GC_REGISTER_KEYWORD GC_word addr = (GC_word)marked_list->obj; + if (min_obj_addr >= addr) + min_obj_addr = addr; + if (max_obj_addr <= addr) + max_obj_addr = addr; + if ((GC_word)(objlink = *(pnext = &hroots[(((addr >> log2_size) ^ addr) >> + GC_LOG2_OFFIGNORE) & hmask]))->obj > addr) + for (;;) + { + if ((GC_word)(objlink = *(pnext = &objlink->next))->obj <= addr) + break; + } + marked_list = (*pnext = marked_list)->next; + (*pnext)->next = objlink; + } while (--count && marked_list != NULL); + gcdata->obj_htable.min_obj_addr = min_obj_addr; + count = max_count - count; + gcdata->obj_htable.max_obj_addr = + max_obj_addr + ((GC_word)1 << GC_LOG2_OFFIGNORE); + gcdata->obj_htable.count += count; + if (gcdata->obj_htable.follow_list != NULL) + gcdata->obj_htable.follow_list = marked_list; + else gcdata->obj_htable.marked_list = marked_list; + } + return count; +} + +GC_STATIC GC_word GC_FASTCALL GC_objlink_free_pending( + struct GC_gcdata_s *gcdata, GC_word min_free_bytes) +{ + GC_REGISTER_KEYWORD struct GC_objlink_s *objlink; +#ifndef GC_NO_DLINKS + GC_word max_hidden; + GC_word min_hidden; +#endif + GC_word objsize; + GC_word totalsize = 0; + GC_word count = 0; + while ((objlink = gcdata->obj_htable.free_list) != NULL) + { + objsize = objlink->atomic_and_size; +#ifndef GC_NO_DLINKS + if (gcdata->dlink_htable.count) + { + min_hidden = GC_HIDE_POINTER((char *)objlink->obj + + (objsize & ~(GC_ATOMIC_MASK | GC_HASDSLEN_MASK | + (sizeof(GC_word) - 1))) - (GC_word)sizeof(GC_word)); + if ((max_hidden = GC_HIDE_POINTER(objlink->obj)) >= min_hidden) + { + (void)GC_dlink_delete(gcdata, max_hidden, min_hidden, max_hidden); + if (((min_hidden ^ max_hidden) & + ~(((GC_word)1 << GC_LOG2_OFFIGNORE) - 1)) != 0) + (void)GC_dlink_delete(gcdata, max_hidden - + ((GC_word)1 << GC_LOG2_OFFIGNORE), min_hidden, max_hidden); + } + } +#endif + gcdata->obj_htable.free_list = objlink->next; + GC_CORE_FREE(objlink->obj); + if ((objsize & GC_ATOMIC_MASK) == 0) + gcdata->followscan_size -= objsize & ~(GC_HASDSLEN_MASK | + (sizeof(GC_word) - 1)); + objlink->obj = NULL; + objlink->next = gcdata->obj_htable.unlinked_list; + gcdata->obj_htable.unlinked_list = objlink; + totalsize += objsize; + count++; + if ((gcdata->free_bytes += + objsize & ~(GC_ATOMIC_MASK | GC_HASDSLEN_MASK)) >= min_free_bytes) + break; + } + gcdata->obj_htable.pending_free_size -= + totalsize & ~(GC_ATOMIC_MASK | GC_HASDSLEN_MASK); + return count; +} + +GC_STATIC void GC_FASTCALL GC_collect_unreachable(struct GC_gcdata_s *gcdata, + GC_stop_func stop_func) +{ + GC_word oldcnt; + GC_word obj_count; + GC_start_callback_proc start_fn; +#ifndef GC_NO_FNLZ + GC_word ready_count = 0; +#endif + struct GC_objlink_s **new_hroots; + int stopped; +#ifdef GC_PRINT_MSGS +#ifndef GC_NO_DLINKS + GC_word dlinks_count = gcdata->dlink_htable.count; +#endif + GC_CURTIME_T curt; + unsigned long time_ms = 0; +#endif + if (gcdata->dataroots != NULL) + { + if ((start_fn = GC_start_call_back) != 0) + (*start_fn)(); +#ifdef GC_PRINT_MSGS + if (GC_verbose_gc) + { + fprintf(stdout, + "[GC: #%lu Scan %lu KiB after %lu KiB allocd, %lu KiB free of %lu KiB]" + GC_NEW_LINE, (unsigned long)(GC_gc_no + 1), + GC_SIZE_TO_ULKB(GC_stack_approx_size(gcdata) + gcdata->dataroot_size + + gcdata->followscan_size), GC_SIZE_TO_ULKB(gcdata->bytes_allocd), + GC_SIZE_TO_ULKB(gcdata->free_bytes), + GC_SIZE_TO_ULKB(gcdata->total_heapsize)); + time_ms = GC_CURTIME_GETMS(&curt); + } + obj_count = gcdata->obj_htable.count; +#endif + if (!(*stop_func)()) + { + stopped = 0; + while (GC_objlink_some_refill(gcdata, GC_LAZYREFILL_BIGCNT)) + if ((stopped = (*stop_func)()) != 0) + break; + obj_count = gcdata->obj_htable.count; + if (!stopped) + { +#ifndef GC_NO_FNLZ + oldcnt = GC_fnlz_precollect(gcdata, &ready_count); +#endif + if ( +#ifdef GC_NO_FNLZ + obj_count +#else + gcdata->obj_htable.count && + ((!oldcnt && !gcdata->fnlz_htable.count) || + (stopped = (*stop_func)()) == 0) +#endif + ) + { + GC_mutator_suspend(gcdata); + GC_stack_scan_cur(gcdata); + stopped = 1; + if (GC_roots_scan(gcdata, stop_func) == NULL +#ifdef GC_THREADS + && !GC_stkroot_scan_other(gcdata, stop_func) +#endif + ) + { + GC_scan_followable(gcdata, stop_func); + if (gcdata->obj_htable.follow_list == NULL) + stopped = 0; + } + GC_mutator_resume(gcdata); +#ifdef GC_NO_FNLZ +#ifndef GC_NO_DLINKS + if (!stopped && gcdata->dlink_htable.count) + GC_dlink_scan_clear(gcdata); +#endif +#else + if (!stopped) + { +#ifndef GC_NO_DLINKS + if (gcdata->dlink_htable.count) + GC_dlink_scan_clear(gcdata); +#endif + if (gcdata->fnlz_htable.count) + oldcnt += GC_fnlz_after_collect(gcdata, &ready_count); + gcdata->bytes_finalized = oldcnt; + } +#endif + } + if (!stopped) + { + GC_gc_no++; +#ifndef GC_NO_FNLZ + GC_scan_followable(gcdata, GC_never_stop_func); +#endif + oldcnt = obj_count; + gcdata->marked_bytes += gcdata->bytes_allocd; + if (gcdata->obj_htable.count) + { + gcdata->obj_htable.pending_free_size += gcdata->marked_bytes; + obj_count -= GC_objlink_remove_all(gcdata); + gcdata->obj_htable.pending_free_size -= gcdata->marked_bytes; + } + if ((oldcnt >> 1) < obj_count && + GC_HASH_RESIZECOND(oldcnt, gcdata->obj_htable.log2_size) && + (new_hroots = GC_alloc_hroots(gcdata, + gcdata->obj_htable.log2_size + 1, &GC_nil_objlink)) != NULL) + { + GC_CORE_FREE(gcdata->obj_htable.hroots); + gcdata->free_bytes += ((GC_word)sizeof(GC_word) << + gcdata->obj_htable.log2_size) + sizeof(GC_word); + gcdata->obj_htable.hroots = new_hroots; + gcdata->obj_htable.log2_size++; + } + gcdata->allocd_before_gc += gcdata->bytes_allocd; + gcdata->bytes_allocd = 0; + } + } + } + if (!gcdata->bytes_allocd) + { + gcdata->recycling = 1; +#ifdef GC_PRINT_MSGS + if (GC_verbose_gc) + { + fprintf(stdout, + "[GC: Done in %lu ms, %lu KiB used by %lu objs, %lu KiB used by GC]" + GC_NEW_LINE, GC_CURTIME_GETMS(&curt) - time_ms, + GC_SIZE_TO_ULKB(gcdata->marked_bytes), (unsigned long)obj_count, + GC_SIZE_TO_ULKB(gcdata->total_heapsize - gcdata->marked_bytes - + gcdata->free_bytes)); +#ifndef GC_NO_DLINKS + if (dlinks_count) + fprintf(stdout, + "[GC: %lu disappearing links cleared of %lu registered]" GC_NEW_LINE, + (unsigned long)(dlinks_count - gcdata->dlink_htable.count), + (unsigned long)dlinks_count); +#endif +#ifndef GC_NO_FNLZ + if ((oldcnt = gcdata->fnlz_htable.count + ready_count) != 0) + fprintf(stdout, + "[GC: %lu finalizers ready of %lu registered]" GC_NEW_LINE, + (unsigned long)ready_count, (unsigned long)oldcnt); +#endif + } +#endif + } + } +} + +GC_STATIC void *GC_FASTCALL GC_inner_core_malloc(struct GC_gcdata_s *gcdata, + GC_word size, int dont_expand) +{ + GC_word free_bytes; + void *ptr = NULL; + if (size <= (~(GC_ATOMIC_MASK | GC_HASDSLEN_MASK) < GC_MEM_SIZELIMIT ? + ~(GC_ATOMIC_MASK | GC_HASDSLEN_MASK) : GC_MEM_SIZELIMIT) && + ((free_bytes = gcdata->free_bytes) > size || (!dont_expand && + gcdata->total_heapsize - (free_bytes - size) <= GC_max_heapsize))) + { + do + { + ptr = GC_CORE_MALLOC((size_t)size); + } while ((GC_word)ptr > ~((GC_word)1 << GC_LOG2_OFFIGNORE) || + ((GC_word)ptr & (sizeof(GC_word) - 1)) != 0); + if (ptr != NULL) + { + if (free_bytes < size) + { + gcdata->total_heapsize += size - free_bytes; + gcdata->free_bytes = 0; + } + else gcdata->free_bytes = free_bytes - size; + } + } + return ptr; +} + +GC_STATIC void *GC_FASTCALL GC_alloc_hroots(struct GC_gcdata_s *gcdata, + GC_word new_log2_size, CONST void *nil_ptr) +{ + GC_REGISTER_KEYWORD GC_word size = (GC_word)sizeof(GC_word) << new_log2_size; + void *ptr; + if ((ptr = GC_inner_core_malloc(gcdata, size + sizeof(GC_word), + GC_dont_expand)) != NULL || (( +#ifndef GC_NO_DLINKS + GC_dlink_free_pending(gcdata, ~(GC_word)0) + +#endif + GC_objlink_free_pending(gcdata, ~(GC_word)0) != 0 || GC_dont_expand) && + (ptr = GC_inner_core_malloc(gcdata, size + sizeof(GC_word), 0)) != NULL)) + { + *(GC_word *)((char *)ptr + size) = ~(GC_word)0; + if (nil_ptr != NULL) + { + while ((size -= sizeof(GC_word)) != 0) + *(CONST void **)((char *)ptr + size) = nil_ptr; + *(CONST void **)ptr = nil_ptr; + } + else GC_MEM_BZERO(ptr, size); + } + return ptr; +} + +GC_STATIC void *GC_FASTCALL GC_core_malloc_with_gc(struct GC_gcdata_s *gcdata, + GC_word size, int *pres) +{ + GC_REGISTER_KEYWORD void *ptr; +#ifndef GC_NO_FNLZ + struct GC_stkroot_s *cur_stack; +#endif + GC_word count; + if ((ptr = GC_inner_core_malloc(gcdata, size, GC_dont_expand)) == NULL) + { + if (*pres >= 0) + { + *pres = 0; + if ((!GC_objlink_free_pending(gcdata, ~(GC_word)0) || + (ptr = GC_inner_core_malloc(gcdata, size, GC_dont_expand)) == NULL) && + !GC_dont_gc) + { + GC_collect_unreachable(gcdata, GC_never_stop_func); + *pres = -1; +#ifndef GC_NO_FNLZ + if ((cur_stack = gcdata->cur_stack) != NULL) + cur_stack->inside_fnlz = 0; +#endif + } + } + if (ptr == NULL && ((count = GC_objlink_free_pending(gcdata, size)) == 0 || + (ptr = GC_inner_core_malloc(gcdata, size, GC_dont_expand)) == NULL)) + { +#ifndef GC_NO_DLINKS + if (GC_dlink_free_pending(gcdata, ~(GC_word)0)) + { + *pres = 1; + if ((ptr = GC_inner_core_malloc(gcdata, size, 0)) != NULL) + *pres = 0; + } + else +#endif + { + if (!count || GC_dont_expand) + ptr = GC_inner_core_malloc(gcdata, size, 0); + } +#ifdef GC_PRINT_MSGS + if (ptr == NULL && GC_verbose_gc) + fprintf(stderr, + " GC: Out of memory! Cannot allocate %lu bytes." GC_NEW_LINE, + (unsigned long)size); +#endif + } + } + return ptr; +} + +GC_STATIC int GC_FASTCALL GC_alloc_objlinks(struct GC_gcdata_s *gcdata, + int *pres) +{ + GC_REGISTER_KEYWORD void *objlinks_block_list; + GC_word count = (GC_word)1 << (gcdata->obj_htable.log2_size - 2); + if ((objlinks_block_list = GC_core_malloc_with_gc(gcdata, + count * sizeof(struct GC_objlink_s) + sizeof(GC_word), pres)) == NULL) + return 0; + *(void **)objlinks_block_list = gcdata->objlinks_block_list; + gcdata->objlinks_block_list = objlinks_block_list; + if (*pres >= 0) + *pres = 0; + ((struct GC_objlink_s *)(objlinks_block_list = + (char *)objlinks_block_list + sizeof(GC_word)))->obj = NULL; + ((struct GC_objlink_s *)objlinks_block_list)->next = + gcdata->obj_htable.unlinked_list; + while (--count) + { + ((struct GC_objlink_s *)((GC_word)objlinks_block_list + + sizeof(struct GC_objlink_s)))->next = objlinks_block_list; + ((struct GC_objlink_s *)(objlinks_block_list = + (char *)objlinks_block_list + sizeof(struct GC_objlink_s)))->obj = NULL; + } + gcdata->obj_htable.unlinked_list = objlinks_block_list; + return 1; +} + +GC_STATIC void *GC_FASTCALL GC_general_malloc(struct GC_gcdata_s **pgcdata, + GC_word objsize, GC_word vtable) +{ + struct GC_gcdata_s *gcdata; + void *obj = NULL; + struct GC_objlink_s **new_hroots; + GC_word retry; + int res; +#ifndef GC_NO_FNLZ + struct GC_objlink_s *objlink; + void *client_data; + GC_finalization_proc fn; + GC_finalizer_notifier_proc notifier_fn; +#endif + if (objsize) + { + retry = ~(GC_word)0; +#ifndef GC_NO_FNLZ + objlink = NULL; + client_data = NULL; + fn = 0; +#endif +#ifndef DONT_ADD_BYTE_AT_END + if (objsize < ((GC_word)1 << GC_LOG2_OFFIGNORE) && GC_all_interior_pointers) + objsize++; +#endif + do + { + res = 1; + GC_enter(pgcdata); + gcdata = *pgcdata; + if (retry == ~(GC_word)0) + { + if ( +#ifdef GC_NO_FNLZ + GC_HASH_RESIZECOND(gcdata->obj_htable.count, + gcdata->obj_htable.log2_size) && +#else + GC_HASH_RESIZECOND(gcdata->obj_htable.count, + gcdata->obj_htable.log2_size + + (GC_word)gcdata->cur_stack->inside_fnlz) && +#endif + gcdata->bytes_allocd) + { + if (GC_dont_gc || gcdata->dataroots == NULL) + { + if ((GC_dont_gc == GC_NEVER_COLLECT || gcdata->dataroots == NULL) && + (new_hroots = GC_alloc_hroots(gcdata, + gcdata->obj_htable.log2_size + 1, &GC_nil_objlink)) != NULL) + { + (void)GC_objlink_free_pending(gcdata, ~(GC_word)0); + gcdata->obj_htable.free_list = gcdata->obj_htable.marked_list; + retry = gcdata->marked_bytes; + (void)GC_objlink_remove_all(gcdata); + gcdata->marked_bytes = retry; + gcdata->obj_htable.marked_list = gcdata->obj_htable.free_list; + retry = ~(GC_word)0; + gcdata->obj_htable.free_list = NULL; + GC_CORE_FREE(gcdata->obj_htable.hroots); + gcdata->free_bytes += ((GC_word)sizeof(GC_word) << + gcdata->obj_htable.log2_size) + sizeof(GC_word); + gcdata->obj_htable.hroots = new_hroots; + gcdata->obj_htable.log2_size++; + res = -1; + } + } + else + { + GC_collect_unreachable(gcdata, GC_default_stop_func); + res = -1; + } + } + else + { + if (!gcdata->recycling && +#ifndef GC_NO_FNLZ + !gcdata->cur_stack->inside_fnlz && +#endif + !GC_dont_gc) + { + if (GC_guess_collect(gcdata, objsize)) + { + GC_collect_unreachable(gcdata, GC_default_stop_func); + res = -1; + } + else retry = 0; + } + if (gcdata->bytes_allocd && + (retry = GC_guess_expand_size(gcdata, objsize)) != 0) + { + if (!GC_dont_expand && + gcdata->expanded_heapsize <= gcdata->total_heapsize) + (void)GC_heap_expand(gcdata, retry); + retry = 0; + } + } + } + if (gcdata->obj_htable.unlinked_list != NULL || + GC_alloc_objlinks(gcdata, &res)) + obj = GC_core_malloc_with_gc(gcdata, objsize, &res); +#ifndef GC_NO_FNLZ + notifier_fn = 0; + if (gcdata->fnlz_htable.ready_fnlz != NULL && GC_finalize_on_demand && + gcdata->notifier_gc_no != GC_gc_no) + { + gcdata->notifier_gc_no = GC_gc_no; + notifier_fn = GC_finalizer_notifier; + } +#endif + if (obj != NULL) + { + gcdata->bytes_allocd += objsize; + GC_objlink_add(gcdata, obj, objsize, vtable); + if (!retry && gcdata->recycling && res > 0) + { + res = (int)GC_objlink_some_refill(gcdata, GC_LAZYREFILL_COUNT); + if (gcdata->obj_htable.free_list != NULL && + (res += (int)GC_objlink_free_pending(gcdata, 0) << 1) > 1 && + (res > 2 || GC_objlink_free_pending(gcdata, + gcdata->free_bytes + ((GC_word)1 << GC_LOG2_OFFIGNORE)) == 1)) + (void)GC_objlink_free_pending(gcdata, 0); +#ifndef GC_NO_FNLZ + if (notifier_fn == 0 && !GC_dont_gc && !GC_finalize_on_demand && + ++gcdata->cur_stack->inside_fnlz == 1) + { + if ((fn = GC_fnlz_del_ready(gcdata, &objlink, &client_data)) != 0) + res = 1; + else gcdata->cur_stack->inside_fnlz = 0; + } +#endif + if (!res +#ifndef GC_NO_DLINKS + && (gcdata->dlink_htable.free_list == NULL || + !GC_dlink_free_pending(gcdata, + objsize / (sizeof(struct GC_dlink_s) - sizeof(GC_word)) + 1)) +#endif + ) + { + gcdata->recycling = 0; +#ifdef GC_PRINT_MSGS + if (GC_verbose_gc) + fprintf(stdout, + "[GC: Recycled, %lu + %lu /A/ KiB in use, %lu KiB free of %lu KiB]" + GC_NEW_LINE, GC_SIZE_TO_ULKB(gcdata->followscan_size), + GC_SIZE_TO_ULKB(gcdata->marked_bytes + gcdata->bytes_allocd - + gcdata->followscan_size), GC_SIZE_TO_ULKB(gcdata->free_bytes), + GC_SIZE_TO_ULKB(gcdata->total_heapsize)); +#endif + } + } + } +#ifndef GC_NO_FNLZ + else + { + if (notifier_fn == 0 && !GC_finalize_on_demand) + fn = GC_fnlz_del_ready(gcdata, &objlink, &client_data); + } +#endif + *pgcdata = NULL; + GC_LEAVE(gcdata); +#ifdef GC_NO_FNLZ + if (obj != NULL || res <= 0) + break; +#else + if (fn != 0) + { + (*fn)(objlink->obj, client_data); + if (obj != NULL) + { + GC_enter(pgcdata); + gcdata = *pgcdata; + gcdata->cur_stack->inside_fnlz = 0; + *pgcdata = NULL; + GC_LEAVE(gcdata); + break; + } + fn = 0; + if (!GC_finalize_on_demand) + for (;;) + { + GC_enter(pgcdata); + gcdata = *pgcdata; + (void)GC_objlink_some_refill(gcdata, GC_LAZYREFILL_BIGCNT); + fn = GC_fnlz_del_ready(gcdata, &objlink, &client_data); + *pgcdata = NULL; + GC_LEAVE(gcdata); + if (fn == 0) + break; + (*fn)(objlink->obj, client_data); + } + } + else + { + if (notifier_fn != 0) + (*notifier_fn)(); + if (obj != NULL || (notifier_fn == 0 && res <= 0)) + break; + } +#endif + if (retry == ~(GC_word)0) + retry = 0; + } while (++retry <= GC_max_retries); + } + return obj; +} + +GC_API void *GC_CALL GC_malloc(size_t size) +{ + struct GC_gcdata_s *gcdata; + return GC_general_malloc(&gcdata, (GC_word)size, ~(GC_word)0); +} + +GC_API void *GC_CALL GC_malloc_atomic(size_t size) +{ + struct GC_gcdata_s *gcdata; + return GC_general_malloc(&gcdata, (GC_word)size, 0); +} + +GC_API void GC_CALL GC_init(void) +{ + struct GC_gcdata_s *gcdata; + GC_enter(&gcdata); + GC_LEAVE(gcdata); +} + +GC_API void GC_CALL GC_set_finalizer_notifier(GC_finalizer_notifier_proc fn) +{ + struct GC_gcdata_s *gcdata; + GC_enter(&gcdata); + GC_finalizer_notifier = fn; + GC_LEAVE(gcdata); +} + +GC_API void GC_CALL GC_set_start_callback(GC_start_callback_proc fn) +{ + struct GC_gcdata_s *gcdata; + GC_enter(&gcdata); + GC_start_call_back = fn; + GC_LEAVE(gcdata); +} + +GC_API void GC_CALL GC_set_stop_func(GC_stop_func fn) +{ + struct GC_gcdata_s *gcdata; + if (fn == 0) + GC_abort_badptr(NULL); + GC_enter(&gcdata); + GC_default_stop_func = fn; + GC_LEAVE(gcdata); +} + +GC_API void *GC_CALL GC_do_blocking(GC_fn_type fn, void *client_data) +{ +#ifndef GC_NO_INACTIVE + struct GC_gcdata_s *gcdata; + GC_enter(&gcdata); + if (!GC_set_inactive_sp(&gcdata)) + GC_abort_badptr(NULL); + GC_LEAVE(gcdata); +#endif + client_data = (*fn)(client_data); +#ifndef GC_NO_INACTIVE + GC_enter(&gcdata); + gcdata->cur_stack->inactive = 0; + GC_LEAVE(gcdata); +#endif + return client_data; +} + +GC_API void *GC_CALL GC_call_with_gc_active(GC_fn_type fn, void *client_data) +{ + struct GC_gcdata_s *gcdata; +#ifdef GC_NO_INACTIVE + GC_enter(&gcdata); + GC_LEAVE(gcdata); + return (*fn)(client_data); +#else + struct GC_activation_frame_s frame; + GC_enter(&gcdata); + if (!GC_set_activation_frame(&frame, gcdata->cur_stack)) + { + GC_LEAVE(gcdata); + return (*fn)(client_data); + } + GC_LEAVE(gcdata); + client_data = (*fn)(client_data); + GC_enter(&gcdata); + GC_restore_inactive_sp(gcdata->cur_stack, &frame); + GC_LEAVE(gcdata); + return client_data; +#endif +} + +#ifdef GC_THREADS + +GC_API void GC_CALL GC_allow_register_threads(void) +{ + /* dummy */ +} + +GC_API int GC_CALL GC_register_my_thread(CONST struct GC_stack_base *sb) +{ + struct GC_gcdata_s *gcdata; + struct GC_stkroot_s *cur_stack; + GC_word stack_addr; + int res; + res = GC_enter(&gcdata); + if ((stack_addr = (GC_word)sb->mem_base) != 0) + { + if ((cur_stack = gcdata->cur_stack)->begin_addr > stack_addr) + cur_stack->begin_addr = stack_addr; + if (cur_stack->end_addr < stack_addr) + cur_stack->end_addr = stack_addr; + } + GC_LEAVE(gcdata); + return res; +} + +GC_API int GC_CALL GC_unregister_my_thread(void) +{ + struct GC_gcdata_s *gcdata; + GC_enter(&gcdata); + GC_stkroot_delete_cur(gcdata); + GC_LEAVE(gcdata); + return GC_SUCCESS; +} + +#endif /* GC_THREADS */ + +GC_API void *GC_CALL GC_call_with_alloc_lock(GC_fn_type fn, void *client_data) +{ + struct GC_gcdata_s *gcdata; + GC_enter(&gcdata); + client_data = (*fn)(client_data); + GC_LEAVE(gcdata); + return client_data; +} + +#ifndef GC_MISC_EXCLUDE + +GC_API GC_finalizer_notifier_proc GC_CALL GC_get_finalizer_notifier(void) +{ + struct GC_gcdata_s *gcdata; + GC_finalizer_notifier_proc fn; + GC_enter(&gcdata); + fn = GC_finalizer_notifier; + GC_LEAVE(gcdata); + return fn; +} + +GC_API GC_start_callback_proc GC_CALL GC_get_start_callback(void) +{ + struct GC_gcdata_s *gcdata; + GC_start_callback_proc fn; + GC_enter(&gcdata); + fn = GC_start_call_back; + GC_LEAVE(gcdata); + return fn; +} + +GC_API GC_stop_func GC_CALL GC_get_stop_func(void) +{ + struct GC_gcdata_s *gcdata; + GC_stop_func fn; + GC_enter(&gcdata); + fn = GC_default_stop_func; + GC_LEAVE(gcdata); + return fn; +} + +GC_API void GC_CALL GC_set_warn_proc(GC_warn_proc fn) +{ + struct GC_gcdata_s *gcdata; + if (fn == 0) + GC_abort_badptr(NULL); + GC_enter(&gcdata); + GC_current_warn_proc = fn; + GC_LEAVE(gcdata); +} + +GC_API GC_warn_proc GC_CALL GC_get_warn_proc(void) +{ + struct GC_gcdata_s *gcdata; + GC_warn_proc fn; + GC_enter(&gcdata); + fn = GC_current_warn_proc; + GC_LEAVE(gcdata); + return fn; +} + +GC_API void GC_CALL GC_enable_incremental(void) +{ + /* dummy */ + struct GC_gcdata_s *gcdata; + GC_enter(&gcdata); + GC_LEAVE(gcdata); +} + +GC_API int GC_CALL GC_expand_hp(size_t incsize) +{ + struct GC_gcdata_s *gcdata; + int res; + GC_enter(&gcdata); + res = GC_heap_expand(gcdata, (GC_word)incsize); + GC_LEAVE(gcdata); + return res >= 0 ? 1 : 0; +} + +GC_API void GC_CALL GC_disable(void) +{ + struct GC_gcdata_s *gcdata; + GC_enter(&gcdata); + GC_dont_gc++; + GC_LEAVE(gcdata); +} + +GC_API void GC_CALL GC_enable(void) +{ + struct GC_gcdata_s *gcdata; + GC_enter(&gcdata); + GC_dont_gc--; + GC_LEAVE(gcdata); +} + +GC_API int GC_CALL GC_should_invoke_finalizers(void) +{ + int res = 0; +#ifndef GC_NO_FNLZ + struct GC_gcdata_s *gcdata; + GC_enter(&gcdata); + if (gcdata->fnlz_htable.ready_fnlz != NULL) + res = 1; + GC_LEAVE(gcdata); +#endif + return res; +} + +GC_API size_t GC_CALL GC_get_bytes_since_gc(void) +{ + struct GC_gcdata_s *gcdata; + GC_word size; + GC_enter(&gcdata); + size = gcdata->bytes_allocd; + GC_LEAVE(gcdata); + return (size_t)size; +} + +GC_API size_t GC_CALL GC_get_total_bytes(void) +{ + struct GC_gcdata_s *gcdata; + GC_word size; + GC_enter(&gcdata); + size = gcdata->allocd_before_gc + gcdata->bytes_allocd; + GC_LEAVE(gcdata); + return (size_t)size; +} + +GC_API void GC_CALL GC_remove_roots(void *low_addr, void *high_addr_plus_1) +{ + struct GC_gcdata_s *gcdata; + if (low_addr != NULL) + { + low_addr = (void *)(((GC_word)low_addr + (sizeof(GC_word) - 1)) & + ~(sizeof(GC_word) - 1)); + high_addr_plus_1 = + (void *)((GC_word)high_addr_plus_1 & ~(sizeof(GC_word) - 1)); + GC_enter(&gcdata); + if ((GC_word)low_addr < (GC_word)high_addr_plus_1) + GC_roots_del_inside(gcdata, (GC_word)low_addr, (GC_word)high_addr_plus_1); + GC_LEAVE(gcdata); + } +} + +GC_API void GC_CALL GC_clear_roots(void) +{ + struct GC_gcdata_s *gcdata; + GC_enter(&gcdata); + GC_roots_del_inside(gcdata, sizeof(GC_word), + ~(GC_word)(sizeof(GC_word) - 1)); + GC_LEAVE(gcdata); +} + +GC_API void GC_CALL GC_exclude_static_roots(void *low_addr, + void *high_addr_plus_1) +{ + struct GC_gcdata_s *gcdata; + if (low_addr != NULL) + { + low_addr = (void *)(((GC_word)low_addr + (sizeof(GC_word) - 1)) & + ~(sizeof(GC_word) - 1)); + high_addr_plus_1 = + (void *)((GC_word)high_addr_plus_1 & ~(sizeof(GC_word) - 1)); + GC_enter(&gcdata); + if ((GC_word)low_addr < (GC_word)high_addr_plus_1) + { + GC_roots_del_inside(gcdata, (GC_word)low_addr, (GC_word)high_addr_plus_1); + (void)GC_roots_exclude(gcdata, (GC_word)low_addr, + (GC_word)high_addr_plus_1); + } + GC_LEAVE(gcdata); + } +} + +#endif /* ! GC_MISC_EXCLUDE */ + +GC_API void GC_CALL GC_add_roots(void *low_addr, void *high_addr_plus_1) +{ + struct GC_gcdata_s *gcdata; + GC_enter(&gcdata); + (void)GC_roots_add(gcdata, (GC_word)low_addr, (GC_word)high_addr_plus_1); + GC_LEAVE(gcdata); +} + +GC_API size_t GC_CALL GC_get_heap_size(void) +{ + struct GC_gcdata_s *gcdata; + GC_word size; + GC_enter(&gcdata); + size = gcdata->marked_bytes + gcdata->bytes_allocd + +#ifndef GC_NO_DLINKS + gcdata->dlink_htable.count * sizeof(struct GC_dlink_s) + +#endif +#ifndef GC_NO_FNLZ + gcdata->fnlz_htable.count * sizeof(struct GC_fnlz_s) + +#endif + gcdata->obj_htable.pending_free_size + gcdata->free_bytes; + GC_LEAVE(gcdata); + return (size_t)size; +} + +GC_API size_t GC_CALL GC_get_free_bytes(void) +{ + struct GC_gcdata_s *gcdata; + GC_word size; + GC_enter(&gcdata); + size = gcdata->free_bytes; + GC_LEAVE(gcdata); + return (size_t)size; +} + +GC_API int GC_CALL GC_try_to_collect(GC_stop_func stop_func) +{ + struct GC_gcdata_s *gcdata; + int res = 1; +#ifndef GC_NO_FNLZ + GC_finalizer_notifier_proc notifier_fn = 0; +#endif + if (stop_func == 0) + GC_abort_badptr(NULL); + GC_enter(&gcdata); + if (!GC_dont_gc && gcdata->bytes_allocd) + { + GC_collect_unreachable(gcdata, stop_func); + res = 0; + if (!gcdata->bytes_allocd) + { + res = 1; +#ifndef GC_NO_FNLZ + gcdata->cur_stack->inside_fnlz = 0; + if (gcdata->fnlz_htable.ready_fnlz != NULL && GC_finalize_on_demand) + { + gcdata->notifier_gc_no = GC_gc_no; + notifier_fn = GC_finalizer_notifier; + } +#endif + } + } + GC_LEAVE(gcdata); +#ifndef GC_NO_FNLZ + if (notifier_fn != 0) + (*notifier_fn)(); +#endif + return res; +} + +GC_API void GC_CALL GC_gcollect_and_unmap(void) +{ + (void)GC_try_to_collect(GC_never_stop_func); +} + +GC_API void GC_CALL GC_gcollect(void) +{ + struct GC_gcdata_s *gcdata; +#ifndef GC_NO_FNLZ + GC_finalizer_notifier_proc notifier_fn = 0; +#endif + GC_enter(&gcdata); + if (!GC_dont_gc && gcdata->bytes_allocd) + { + GC_collect_unreachable(gcdata, GC_default_stop_func); +#ifndef GC_NO_FNLZ + if (!gcdata->bytes_allocd) + { + gcdata->cur_stack->inside_fnlz = 0; + if (gcdata->fnlz_htable.ready_fnlz != NULL && GC_finalize_on_demand) + { + gcdata->notifier_gc_no = GC_gc_no; + notifier_fn = GC_finalizer_notifier; + } + } +#endif + } + GC_LEAVE(gcdata); +#ifndef GC_NO_FNLZ + if (notifier_fn != 0) + (*notifier_fn)(); +#endif +} + +GC_API void *GC_CALL GC_base(void *displaced_pointer) +{ +#ifdef GC_NO_GCBASE + if (displaced_pointer != NULL) + GC_abort_badptr(displaced_pointer); +#else + struct GC_gcdata_s *gcdata; + struct GC_objlink_s *objlink; + if (displaced_pointer != NULL) + { + GC_enter(&gcdata); + displaced_pointer = + (objlink = GC_objlink_get(gcdata, displaced_pointer)) != NULL || + (objlink = GC_objlink_refill_find(gcdata, displaced_pointer)) != NULL ? + objlink->obj : NULL; + GC_LEAVE(gcdata); + } +#endif + return displaced_pointer; +} + +GC_API int GC_CALL GC_general_register_disappearing_link(void **link, + void *obj) +{ +#ifndef GC_NO_REGISTER_DLINK + struct GC_gcdata_s *gcdata; + struct GC_objlink_s *objlink; +#ifdef GC_NO_DLINKS + GC_word objsize; +#else + struct GC_dlink_s **new_hroots; + struct GC_dlink_s *new_dlink; + GC_word new_log2_size; +#endif +#endif + int res = 0; + if (((GC_word)link & (sizeof(GC_word) - 1)) != 0 || link == NULL) + GC_abort_badptr(link); +#ifndef GC_NO_REGISTER_DLINK + GC_enter(&gcdata); + if (obj != NULL) + { +#ifdef GC_NO_DLINKS + if ((objlink = GC_objlink_get(gcdata, (void *)link)) != NULL || + (objlink = GC_objlink_refill_find(gcdata, (void *)link)) != NULL) + { + obj = NULL; + if (((objsize = objlink->atomic_and_size) & GC_ATOMIC_MASK) != 0) + { + gcdata->followscan_size += objsize & ~(GC_ATOMIC_MASK | + (sizeof(GC_word) - 1)); +#ifndef GC_GCJ_SUPPORT + objlink->atomic_and_size = objsize & ~GC_ATOMIC_MASK; +#endif + } +#ifdef GC_GCJ_SUPPORT + objlink->atomic_and_size = objsize & ~(GC_ATOMIC_MASK | GC_HASDSLEN_MASK); +#endif + } +#else + if ((objlink = GC_objlink_get(gcdata, obj)) != NULL || + (objlink = GC_objlink_refill_find(gcdata, obj)) != NULL) + { + if (objlink->obj == obj) + { + res = GC_dlink_add(gcdata, GC_HIDE_POINTER(link), objlink, + (new_dlink = gcdata->dlink_htable.free_list) != NULL && + gcdata->free_bytes >= sizeof(struct GC_dlink_s) ? new_dlink : + ((GC_HASH_RESIZECOND(gcdata->dlink_htable.count, + gcdata->dlink_htable.log2_size) && + (new_hroots = GC_alloc_hroots(gcdata, new_log2_size = + gcdata->dlink_htable.log2_size + 1, &GC_nil_dlink)) != NULL ? + (GC_dlink_tblresize(gcdata, new_hroots, new_log2_size), 0) : 0), + GC_core_malloc_with_gc(gcdata, sizeof(struct GC_dlink_s), &res))); + obj = NULL; + } + } + else obj = NULL; +#endif + } + GC_LEAVE(gcdata); +#endif + if (obj != NULL) + GC_abort_badptr(obj); + return res; +} + +#ifndef GC_MISC_EXCLUDE + +GC_API int GC_CALL GC_unregister_disappearing_link(void **link) +{ +#ifndef GC_NO_DLINKS + struct GC_gcdata_s *gcdata; + GC_word hidden_link; +#endif + int res = 0; +#ifdef GC_NO_DLINKS + GC_noop1((GC_word)link); +#else + GC_enter(&gcdata); + if (gcdata->dlink_htable.count && (hidden_link = GC_HIDE_POINTER(link)) != 0) + res = GC_dlink_delete(gcdata, hidden_link, hidden_link, hidden_link); + GC_LEAVE(gcdata); +#endif + return res; +} + +#endif /* ! GC_MISC_EXCLUDE */ + +GC_API void GC_CALL GC_register_finalizer_no_order(void *obj, + GC_finalization_proc fn, void *client_data, GC_finalization_proc *ofn, + void **odata) +{ +#ifdef GC_NO_FNLZ + if (obj != NULL && fn != 0) + GC_noop1((GC_word)client_data); + if (ofn != NULL) + *ofn = 0; + if (odata != NULL) + *odata = NULL; +#else + struct GC_gcdata_s *gcdata; + struct GC_objlink_s *objlink; + struct GC_fnlz_s **new_hroots; + void *old_data; + GC_word new_log2_size; + int res = 0; + if (odata == NULL) + odata = &old_data; + GC_enter(&gcdata); + if (obj != NULL && ((objlink = GC_objlink_get(gcdata, obj)) != NULL || + (objlink = GC_objlink_refill_find(gcdata, obj)) != NULL)) + { + if (objlink->obj == obj) + { + if (fn != 0) + { + if (GC_HASH_RESIZECOND(gcdata->fnlz_htable.count, + gcdata->fnlz_htable.log2_size) && + (new_hroots = GC_alloc_hroots(gcdata, new_log2_size = + gcdata->fnlz_htable.log2_size + 1, &GC_nil_fnlz)) != NULL) + GC_fnlz_tblresize(gcdata, new_hroots, new_log2_size); + if (gcdata->fnlz_htable.single_free == NULL) + res = (gcdata->fnlz_htable.single_free = GC_core_malloc_with_gc(gcdata, + sizeof(struct GC_fnlz_s), &res)) != NULL ? 1 : -1; + } + obj = NULL; + if ((fn = GC_fnlz_add_del(gcdata, objlink, fn, client_data, odata)) != 0) + { + if (ofn != NULL) + *ofn = fn; + fn = 0; + } + else + { + if ((res >> 1) == 0) + { + if (ofn != NULL) + *ofn = 0; + if (res > 0 && !GC_finalize_on_demand && + ++gcdata->cur_stack->inside_fnlz == 1 && + (fn = GC_fnlz_del_ready(gcdata, &objlink, &client_data)) == 0) + gcdata->cur_stack->inside_fnlz = 0; + } + } + } + } + else + { + obj = NULL; + if (ofn != NULL) + *ofn = 0; + fn = 0; + *odata = NULL; + objlink = NULL; + } + GC_LEAVE(gcdata); + if (obj != NULL) + GC_abort_badptr(obj); + if (fn != 0) + { + (*fn)(objlink->obj, client_data); + GC_enter(&gcdata); + gcdata->cur_stack->inside_fnlz = 0; + GC_LEAVE(gcdata); + } +#endif +} + +GC_API int GC_CALL GC_invoke_finalizers(void) +{ + GC_word count = 0; +#ifndef GC_NO_FNLZ + struct GC_gcdata_s *gcdata; + struct GC_objlink_s *objlink = NULL; + void *client_data = NULL; + GC_finalization_proc fn; + for (;;) + { + GC_enter(&gcdata); + if ((fn = GC_fnlz_del_ready(gcdata, &objlink, &client_data)) != 0) + { + if (!count) + gcdata->cur_stack->inside_fnlz++; + } + else + { + if (count) + gcdata->cur_stack->inside_fnlz = 0; + } + GC_LEAVE(gcdata); + if (fn == 0) + break; + count++; + (*fn)(objlink->obj, client_data); + } +#endif + return (int)count; +} + +#ifdef GC_GCJ_SUPPORT + +GC_API void GC_CALL GC_init_gcj_malloc(int mp_index, void *mp) +{ + /* dummy */ + struct GC_gcdata_s *gcdata; + if (mp != 0) + GC_noop1((GC_word)mp_index); + GC_enter(&gcdata); + GC_LEAVE(gcdata); +} + +GC_API void *GC_CALL GC_gcj_malloc(size_t size, void *vtable) +{ + struct GC_gcdata_s *gcdata; + if ((*(GC_word *)((char *)vtable + MARK_DESCR_OFFSET) & GC_DS_TAGS) != + GC_DS_LENGTH || size < sizeof(GC_word)) + GC_abort_badptr(vtable); + return GC_general_malloc(&gcdata, (GC_word)size, (GC_word)vtable); +} + +#endif /* GC_GCJ_SUPPORT */ + +#ifndef JAVA_FINALIZATION_NOT_NEEDED + +GC_API void GC_CALL GC_finalize_all(void) +{ +#ifndef GC_NO_FNLZ + struct GC_gcdata_s *gcdata; + struct GC_objlink_s *objlink = NULL; + void *client_data = NULL; + GC_word count = 0; + GC_finalization_proc fn; + for (;;) + { + GC_enter(&gcdata); + if (!count && gcdata->fnlz_htable.count) + GC_fnlz_ready_all(gcdata); + if ((fn = GC_fnlz_del_ready(gcdata, &objlink, &client_data)) != 0) + { + if (!count) + gcdata->cur_stack->inside_fnlz++; + } + else + { + if (count) + gcdata->cur_stack->inside_fnlz = 0; + } + GC_LEAVE(gcdata); + if (fn != 0) + { + count++; + (*fn)(objlink->obj, client_data); + } + else + { + if (!count) + break; + count = 0; + } + } +#endif +} + +#endif /* ! JAVA_FINALIZATION_NOT_NEEDED */ diff --git a/tinygc-tinygc-2_6/tinygcmt.o b/tinygc-tinygc-2_6/tinygcmt.o new file mode 100644 index 0000000..dcfda2c Binary files /dev/null and b/tinygc-tinygc-2_6/tinygcmt.o differ