source: git/ppcc/gclib/tinygc.c @ 54b24c

spielwiese
Last change on this file since 54b24c was 54b24c, checked in by Reimer Behrends <behrends@…>, 5 years ago
Finalizing thread support.
  • Property mode set to 100644
File size: 102.3 KB
Line 
1/*
2 * @(#) tinygc.c -- TinyGC (Tiny Garbage Collector) source.
3 * Copyright (C) 2006-2010 Ivan Maidanski <ivmai@mail.ru> All rights reserved.
4 **
5 * Version: 2.6
6 * See also files: gc.h, gc_gcj.h, gc_mark.h, javaxfc.h
7 * Required: any ANSI C compiler (assume GC-safe compilation).
8 */
9
10/*
11 * This is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License as published by
13 * the Free Software Foundation; either version 2, or (at your option)
14 * any later version.
15 **
16 * This software is distributed in the hope that it will be useful, but
17 * WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19 * General Public License (GPL) for more details.
20 **
21 * Linking this library statically or dynamically with other modules is
22 * making a combined work based on this library. Thus, the terms and
23 * conditions of the GNU General Public License cover the whole
24 * combination.
25 **
26 * As a special exception, the copyright holders of this library give you
27 * permission to link this library with independent modules to produce an
28 * executable, regardless of the license terms of these independent
29 * modules, and to copy and distribute the resulting executable under
30 * terms of your choice, provided that you also meet, for each linked
31 * independent module, the terms and conditions of the license of that
32 * module. An independent module is a module which is not derived from
33 * or based on this library. If you modify this library, you may extend
34 * this exception to your version of the library, but you are not
35 * obligated to do so. If you do not wish to do so, delete this
36 * exception statement from your version.
37 */
38
39/*
40 * Control macros: ALL_INTERIOR_POINTERS, DONT_ADD_BYTE_AT_END,
41 * FINALIZE_ON_DEMAND, GC_DLL, GC_DONT_EXPAND, GC_GCJ_SUPPORT, GC_GETENV_SKIP,
42 * GC_IGNORE_GCJ_INFO, GC_MISC_EXCLUDE, GC_NO_DLINKS, GC_NO_FNLZ,
43 * GC_NO_GCBASE, GC_NO_INACTIVE, GC_NO_REGISTER_DLINK,
44 * GC_OMIT_REGISTER_KEYWORD, GC_PRINT_MSGS, GC_THREADS, GC_USE_GETTIMEOFDAY,
45 * GC_USE_WIN32_SYSTEMTIME, GC_WIN32_THREADS, GC_WIN32_WCE,
46 * JAVA_FINALIZATION_NOT_NEEDED.
47 **
48 * Macros for tuning (also see in gc.h): CONST, GC_ASYNC_PUSHREGS_BEGIN,
49 * GC_ASYNC_PUSHREGS_END, GC_CLIBDECL, GC_CORE_API, GC_CORE_CALL,
50 * GC_CORE_FREE, GC_CORE_MALLOC, GC_DATASTATIC, GC_DATASTART, GC_DATASTART2,
51 * GC_DATAEND, GC_DATAEND2, GC_FATAL_ABORT, GC_FREE_SPACE_DIVISOR,
52 * GC_MAX_RETRIES, GC_FASTCALL, GC_INLINE_STATIC, GC_LAZYREFILL_BIGCNT,
53 * GC_LAZYREFILL_COUNT, GC_LOG2_OFFIGNORE, GC_NEW_LINE, GC_PUSHREGS_BEGIN,
54 * GC_PUSHREGS_END, GC_SIG_SUSPEND, GC_STACKBOTTOM, GC_STACKBOTTOMVAR,
55 * GC_STACKLEN, GC_STACKLENVAR, GC_STATIC, GC_THREAD_MUTEX_DEFATTR,
56 * GC_THREAD_YIELD, GC_WIN32_CONTEXT_SP_NAME, GC_YIELD_MAX_ATTEMPT, INLINE,
57 * MARK_DESCR_OFFSET.
58 */
59
60#ifndef _SETJMP_H
61#include <setjmp.h>
62/* int setjmp(jmp_buf); */
63#endif
64
65#ifndef _STDLIB_H
66#include <stdlib.h>
67/* long atol(const char *); */
68/* void exit(int); */
69/* void free(void *); */
70/* char *getenv(const char *); */
71/* void *malloc(size_t); */
72#endif
73
74#ifndef _STRING_H
75#include <string.h>
76/* void *memset(void *, int, size_t); */
77#endif
78
79#ifndef _LIMITS_H
80#include <limits.h>
81#endif
82
83#ifdef GC_WIN32_THREADS
84
85#ifndef _WINDOWS_H
86#include <windows.h>
87/* BOOL CloseHandle(HANDLE); */
88/* HANDLE CreateEvent(SECURITY_ATTRIBUTES *, BOOL, BOOL, LPCTSTR); */
89/* BOOL DuplicateHandle(HANDLE, HANDLE, HANDLE, HANDLE *, DWORD, BOOL, DWORD); */
90/* HANDLE GetCurrentProcess(void); */
91/* HANDLE GetCurrentThread(void); */
92/* DWORD GetCurrentThreadId(void); */
93/* BOOL GetThreadContext(HANDLE, CONTEXT *); */
94/* LONG InterlockedExchange(LONG *, LONG); */
95/* DWORD ResumeThread(HANDLE); */
96/* BOOL SetEvent(HANDLE); */
97/* void Sleep(DWORD); */
98/* DWORD SuspendThread(HANDLE); */
99/* DWORD WaitForSingleObject(HANDLE, DWORD); */
100#endif
101
102#ifndef GC_THREADS
103#define GC_THREADS 1
104#endif
105
106#else /* GC_WIN32_THREADS */
107
108#ifdef GC_THREADS
109
110#ifndef _ERRNO_H
111#include <errno.h>
112/* int errno; */
113#endif
114
115#ifndef _SIGNAL_H
116#include <signal.h>
117/* void (*signal(int, void (*)(int)))(int); */
118#endif
119
120#ifndef _PTHREAD_H
121#include <pthread.h>
122/* int pthread_kill(pthread_t, int); */
123/* int pthread_mutex_init(pthread_mutex_t *, const pthread_mutexattr_t *); */
124/* int pthread_mutex_lock(pthread_mutex_t *); */
125/* int pthread_mutex_unlock(pthread_mutex_t *); */
126/* pthread_t pthread_self(void); */
127#endif
128
129#ifndef _SCHED_H
130#include <sched.h>
131/* int sched_yield(void); */
132#endif
133
134#ifdef pthread_usleep_np
135/* #include <pthread.h> */
136/* unsigned pthread_usleep_np(unsigned); */
137#else
138#ifndef _UNISTD_H
139#include <unistd.h>
140/* int usleep(useconds_t); */
141#endif
142#define pthread_usleep_np usleep
143#endif
144
145#endif /* GC_THREADS */
146
147#endif /* ! GC_WIN32_THREADS */
148
149#ifdef GC_PRINT_MSGS
150
151#ifndef _STDIO_H
152#include <stdio.h>
153/* int fprintf(FILE *, const char *, ...); */
154/* FILE * const stderr; */
155/* FILE * const stdout; */
156#endif
157
158#ifdef GC_USE_WIN32_SYSTEMTIME
159
160#ifndef _WINDOWS_H
161#include <windows.h>
162/* void GetSystemTime(SYSTEMTIME *); */
163#endif
164
165#define GC_CURTIME_T SYSTEMTIME
166#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)
167
168#else /* GC_USE_WIN32_SYSTEMTIME */
169
170#ifdef GC_USE_GETTIMEOFDAY
171
172#ifndef _SYS_TIME_H
173#include <sys/time.h>
174/* int gettimeofday(struct timeval *, void *); */
175#endif
176
177#define GC_CURTIME_T struct timeval
178
179#ifdef _SVID_GETTOD
180#define GC_CURTIME_GETMS(pcurt) (gettimeofday((void *)(pcurt)), (unsigned long)(pcurt)->tv_sec * 1000 + (unsigned long)(pcurt)->tv_usec / 1000)
181#else
182#define GC_CURTIME_GETMS(pcurt) (gettimeofday((void *)(pcurt), NULL), (unsigned long)(pcurt)->tv_sec * 1000 + (unsigned long)(pcurt)->tv_usec / 1000)
183#endif
184
185#else /* GC_USE_GETTIMEOFDAY */
186
187#ifndef _TIME_H
188#include <time.h>
189#endif
190
191#ifndef _SYS_TIMEB_H
192#include <sys/timeb.h>
193/* void ftime(struct timeb *); */
194#endif
195
196#define GC_CURTIME_T struct timeb
197#define GC_CURTIME_GETMS(pcurt) (ftime(pcurt), (unsigned long)(pcurt)->time * 1000 + (unsigned long)(pcurt)->millitm)
198
199#endif /* ! GC_USE_GETTIMEOFDAY */
200
201#endif /* ! GC_USE_WIN32_SYSTEMTIME */
202
203#define GC_SIZE_TO_ULKB(size) ((unsigned long)((size) >> 10))
204
205#ifndef GC_NEW_LINE
206#define GC_NEW_LINE "\n"
207#endif
208
209#endif /* GC_PRINT_MSGS */
210
211#ifndef GC_API
212#ifdef GC_DLL
213#define GC_API __declspec(dllexport)
214#endif
215#endif
216
217#include "gc.h"
218
219#include "gc_gcj.h"
220
221#include "gc_mark.h"
222
223#include "javaxfc.h"
224
225#ifndef NULL
226#define NULL (void *)0
227#endif
228
229#ifndef CHAR_BIT
230#define CHAR_BIT 8
231#endif
232
233#ifndef CONST
234#define CONST const
235#endif
236
237#ifndef GC_FATAL_ABORT
238#define GC_FATAL_ABORT exit(-1) /* abort(), DebugBreak() */
239#endif
240
241#ifndef GC_DATASTATIC
242#define GC_DATASTATIC static
243#endif
244
245#ifndef GC_STATIC
246#define GC_STATIC static
247#endif
248
249#ifndef GC_INLINE_STATIC
250#ifdef INLINE
251#define GC_INLINE_STATIC GC_STATIC INLINE
252#else
253#define GC_INLINE_STATIC GC_STATIC __inline
254#endif
255#endif
256
257#ifndef GC_FASTCALL
258#define GC_FASTCALL __fastcall
259#endif
260
261#ifndef GC_CORE_API
262#define GC_CORE_API extern
263#endif
264
265#ifndef GC_CORE_CALL
266#define GC_CORE_CALL GC_CALL
267#endif
268
269#ifdef GC_PUSHREGS_BEGIN
270#ifndef GC_PUSHREGS_END
271#define GC_PUSHREGS_END (void)0
272#endif
273#else
274#define GC_PUSHREGS_BEGIN jmp_buf buf; (void)setjmp(buf)
275#ifndef GC_PUSHREGS_END
276#define GC_PUSHREGS_END GC_noop1((GC_word)(&buf))
277#endif
278#endif
279
280#define GC_MEM_BZERO(ptr, size) (void)memset(ptr, '\0', (size_t)(size))
281
282#ifdef GC_THREADS
283
284#ifdef GC_WIN32_THREADS
285
286#ifndef GC_WIN32_CONTEXT_SP_NAME
287#ifdef _M_AMD64
288#define GC_WIN32_CONTEXT_SP_NAME Rsp
289#else
290#ifdef _M_X64
291#define GC_WIN32_CONTEXT_SP_NAME Rsp
292#else
293#ifdef __x86_64
294#define GC_WIN32_CONTEXT_SP_NAME Rsp
295#endif
296#endif
297#endif
298#endif
299
300#ifndef GC_WIN32_CONTEXT_SP_NAME
301#ifdef _M_ALPHA
302#define GC_WIN32_CONTEXT_SP_NAME IntSp
303#else
304#ifdef _ALPHA_
305#define GC_WIN32_CONTEXT_SP_NAME IntSp
306#else
307#ifdef _M_MRX000
308#define GC_WIN32_CONTEXT_SP_NAME IntSp
309#else
310#ifdef _MIPS_
311#define GC_WIN32_CONTEXT_SP_NAME IntSp
312#endif
313#endif
314#endif
315#endif
316#endif
317
318#ifndef GC_WIN32_CONTEXT_SP_NAME
319#ifdef _M_ARM
320#define GC_WIN32_CONTEXT_SP_NAME Sp
321#else
322#ifdef _ARM_
323#define GC_WIN32_CONTEXT_SP_NAME Sp
324#else
325#ifdef _M_PPC
326#define GC_WIN32_CONTEXT_SP_NAME Gpr1
327#else
328#ifdef _PPC_
329#define GC_WIN32_CONTEXT_SP_NAME Gpr1
330#else
331#ifdef _M_SH
332#define GC_WIN32_CONTEXT_SP_NAME R15
333#else
334#ifdef SHx
335#define GC_WIN32_CONTEXT_SP_NAME R15
336#endif
337#endif
338#endif
339#endif
340#endif
341#endif
342#endif
343
344#ifndef GC_WIN32_CONTEXT_SP_NAME
345#define GC_WIN32_CONTEXT_SP_NAME Esp /* x86 */
346#endif
347
348#ifndef GC_THREAD_YIELD
349#define GC_THREAD_YIELD Sleep(10) /* "long" yield */
350#endif
351
352#define GC_THREAD_ID_T DWORD
353
354#ifdef GC_WIN32_WCE
355#define GC_THREAD_HANDLE(stkroot) ((HANDLE)(GC_word)(stkroot)->thread_id)
356#else
357#define GC_THREAD_HANDLE(stkroot) ((stkroot)->thread_handle)
358#endif
359
360#else /* GC_WIN32_THREADS */
361
362#ifndef GC_SIG_SUSPEND
363#ifdef SIGPWR
364#define GC_SIG_SUSPEND SIGPWR
365#else
366#ifdef SIGUSR1
367#define GC_SIG_SUSPEND SIGUSR1
368#else
369#define GC_SIG_SUSPEND SIGILL
370#endif
371#endif
372#endif
373
374#ifndef GC_CLIBDECL
375#ifdef __CLIB
376#define GC_CLIBDECL __CLIB
377#else
378#ifdef _USERENTRY
379#define GC_CLIBDECL _USERENTRY
380#else
381#ifdef _RTL_FUNC
382#define GC_CLIBDECL _RTL_FUNC
383#else
384#define GC_CLIBDECL __cdecl
385#endif
386#endif
387#endif
388#endif
389
390#ifdef GC_ASYNC_PUSHREGS_BEGIN
391#ifndef GC_ASYNC_PUSHREGS_END
392#define GC_ASYNC_PUSHREGS_END (void)0
393#endif
394#else
395#define GC_ASYNC_PUSHREGS_BEGIN GC_PUSHREGS_BEGIN
396#ifndef GC_ASYNC_PUSHREGS_END
397#define GC_ASYNC_PUSHREGS_END GC_PUSHREGS_END
398#endif
399#endif
400
401#ifndef GC_THREAD_MUTEX_DEFATTR
402#ifdef pthread_mutexattr_default
403#define GC_THREAD_MUTEX_DEFATTR pthread_mutexattr_default
404#else
405#define GC_THREAD_MUTEX_DEFATTR NULL
406#endif
407#endif
408
409#ifndef GC_THREAD_YIELD
410#define GC_THREAD_YIELD (void)sched_yield()
411#endif
412
413#ifndef GC_YIELD_MAX_ATTEMPT
414#define GC_YIELD_MAX_ATTEMPT 2
415#endif
416
417#define GC_ERRNO_SET(value) (void)(errno = (value))
418
419#define GC_THREAD_ID_T pthread_t
420
421#endif /* ! GC_WIN32_THREADS */
422
423#endif /* GC_THREADS */
424
425#ifndef MARK_DESCR_OFFSET
426#define MARK_DESCR_OFFSET sizeof(GC_word)
427#endif
428
429#ifndef GC_LOG2_OFFIGNORE
430#define GC_LOG2_OFFIGNORE 8 /* must be at least 3 */
431#endif
432
433#ifndef GC_FREE_SPACE_DIVISOR
434#define GC_FREE_SPACE_DIVISOR 3
435#endif
436
437#ifndef GC_MAX_RETRIES
438#define GC_MAX_RETRIES 2
439#endif
440
441#ifndef GC_LAZYREFILL_COUNT
442#define GC_LAZYREFILL_COUNT 10 /* must be at least 3 */
443#endif
444
445#ifndef GC_LAZYREFILL_BIGCNT
446#define GC_LAZYREFILL_BIGCNT 1024
447#endif
448
449#ifdef GC_OMIT_REGISTER_KEYWORD
450#define GC_REGISTER_KEYWORD /* empty */
451#else
452#define GC_REGISTER_KEYWORD register
453#endif
454
455#define GC_DEFAULT_LOG2_OBJSIZE 8
456#define GC_DEFAULT_LOG2_SIZE 3
457
458#define GC_MEM_SIZELIMIT ((GC_word)((~(size_t)0) >> 1) - ((GC_word)1 << (sizeof(int) << 1)))
459
460#define GC_ATOMIC_MASK (((~(GC_word)0) >> 1) + 1)
461
462#ifdef GC_GCJ_SUPPORT
463#define GC_HASDSLEN_MASK (((GC_word)GC_ATOMIC_MASK) >> 1)
464#else
465#define GC_HASDSLEN_MASK 0
466#endif
467
468#define GC_NEVER_COLLECT (int)((((unsigned)-1) >> 1) + 1)
469
470#ifndef GC_NO_DLINKS
471#define GC_HIDE_POINTER(ptr) (~(GC_word)(ptr))
472#endif
473
474#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))
475#define GC_HASH_INDEX(word_value, seed, log2_size) ((((word_value) ^ (seed)) * (GC_word)0x9E3779B1L) >> (sizeof(GC_word) * CHAR_BIT - (log2_size)))
476#define GC_HASH_RESIZECOND(count, log2_size) (((GC_word)3 << ((log2_size) - 2)) <= (count))
477
478#define GC_LEAVE(gcdata) GC_leave()
479
480#ifdef GC_CORE_MALLOC
481GC_CORE_API void *GC_CORE_CALL GC_CORE_MALLOC(size_t size);
482#else
483#define GC_CORE_MALLOC malloc
484#endif
485
486#ifdef GC_CORE_FREE
487GC_CORE_API void GC_CORE_CALL GC_CORE_FREE(void *ptr);
488#else
489#define GC_CORE_FREE free
490#endif
491
492#ifdef GC_STACKBOTTOMVAR
493extern char *GC_STACKBOTTOMVAR;
494#endif
495
496#ifdef GC_STACKLENVAR
497extern GC_word GC_STACKLENVAR;
498#endif
499
500#ifndef GC_STACKBOTTOM
501#ifdef GC_STACKBOTTOMVAR
502#define GC_STACKBOTTOM GC_STACKBOTTOMVAR
503#else
504#define GC_STACKBOTTOM 0
505#endif
506#endif
507
508#ifndef GC_STACKLEN
509#ifdef GC_STACKLENVAR
510#define GC_STACKLEN GC_STACKLENVAR
511#else
512#define GC_STACKLEN 0
513#endif
514#endif
515
516struct GC_objlink_s
517{
518 void *obj;
519 struct GC_objlink_s *next;
520 GC_word atomic_and_size;
521};
522
523struct GC_obj_htable_s
524{
525 struct GC_objlink_s **hroots;
526 struct GC_objlink_s *free_list;
527 struct GC_objlink_s *marked_list;
528 struct GC_objlink_s *follow_list;
529 struct GC_objlink_s *unlinked_list;
530 GC_word min_obj_addr;
531 GC_word max_obj_addr;
532 GC_word count;
533 GC_word log2_size;
534 GC_word pending_free_size;
535};
536
537#ifndef GC_NO_DLINKS
538
539struct GC_dlink_s
540{
541 struct GC_dlink_s *next;
542 struct GC_objlink_s *objlink;
543 GC_word hidden_link;
544};
545
546struct GC_dlink_htable_s
547{
548 struct GC_dlink_s **hroots;
549 struct GC_dlink_s *free_list;
550 GC_word count;
551 GC_word log2_size;
552 GC_word seed;
553};
554
555#endif /* ! GC_NO_DLINKS */
556
557#ifndef GC_NO_FNLZ
558
559struct GC_fnlz_s
560{
561 struct GC_fnlz_s *next;
562 struct GC_objlink_s *objlink;
563 void *client_data;
564 GC_finalization_proc fn;
565};
566
567struct GC_fnlz_htable_s
568{
569 struct GC_fnlz_s **hroots;
570 struct GC_fnlz_s *ready_fnlz;
571 struct GC_fnlz_s *single_free;
572 GC_word count;
573 GC_word log2_size;
574 GC_word seed;
575 int has_client_ptrs;
576};
577
578#endif /* ! GC_NO_FNLZ */
579
580#ifndef GC_NO_INACTIVE
581
582struct GC_activation_frame_s
583{
584 GC_word inactive_sp;
585 CONST struct GC_activation_frame_s *prev;
586};
587
588#endif /* ! GC_NO_INACTIVE */
589
590struct GC_dataroot_s
591{
592 struct GC_dataroot_s *next;
593 GC_word begin_addr;
594 GC_word end_addr;
595};
596
597struct GC_stkroot_s
598{
599 GC_word begin_addr;
600 GC_word end_addr;
601#ifndef GC_NO_INACTIVE
602 CONST struct GC_activation_frame_s *activation_frame;
603#endif
604#ifdef GC_THREADS
605 struct GC_stkroot_s *next;
606 GC_THREAD_ID_T thread_id;
607#ifdef GC_WIN32_THREADS
608#ifndef GC_WIN32_WCE
609 HANDLE thread_handle;
610#endif
611#else
612 volatile int suspend_ack;
613#endif
614#endif
615#ifndef GC_NO_INACTIVE
616 int inactive;
617#endif
618#ifndef GC_NO_FNLZ
619 int inside_fnlz;
620#endif
621};
622
623#ifdef GC_THREADS
624
625struct GC_stkroot_htable_s
626{
627 struct GC_stkroot_s **hroots;
628 GC_word count;
629 GC_word log2_size;
630 GC_word seed;
631};
632
633#endif /* GC_THREADS */
634
635struct GC_gcdata_s
636{
637 struct GC_obj_htable_s obj_htable;
638 void *objlinks_block_list;
639#ifndef GC_NO_DLINKS
640 struct GC_dlink_htable_s dlink_htable;
641#endif
642#ifndef GC_NO_FNLZ
643 struct GC_fnlz_htable_s fnlz_htable;
644 GC_word notifier_gc_no;
645 GC_word bytes_finalized;
646#endif
647 struct GC_stkroot_s *cur_stack;
648 struct GC_dataroot_s *dataroots;
649 GC_word dataroot_size;
650 GC_word expanded_heapsize;
651 GC_word total_heapsize;
652 GC_word allocd_before_gc;
653 GC_word bytes_allocd;
654 GC_word marked_bytes;
655 GC_word free_bytes;
656 GC_word followscan_size;
657#ifdef GC_THREADS
658 struct GC_stkroot_htable_s stkroot_htable;
659#endif
660 int recycling;
661#ifdef GC_GCJ_SUPPORT
662#ifndef GC_GETENV_SKIP
663#ifndef GC_IGNORE_GCJ_INFO
664 int ignore_gcj_info;
665#endif
666#endif
667#endif
668};
669
670volatile GC_word GC_noop_sink;
671
672GC_DATASTATIC GC_word GC_gc_no = 0;
673
674GC_DATASTATIC GC_word GC_free_space_divisor = (GC_FREE_SPACE_DIVISOR);
675GC_DATASTATIC GC_word GC_max_retries = (GC_MAX_RETRIES);
676
677GC_DATASTATIC GC_finalizer_notifier_proc GC_finalizer_notifier = 0;
678
679GC_DATASTATIC GC_start_callback_proc GC_start_call_back = 0;
680
681#ifdef ALL_INTERIOR_POINTERS
682GC_DATASTATIC int GC_all_interior_pointers = 1;
683#else
684GC_DATASTATIC int GC_all_interior_pointers = 0;
685#endif
686
687#ifdef FINALIZE_ON_DEMAND
688GC_DATASTATIC int GC_finalize_on_demand = 1;
689#else
690GC_DATASTATIC int GC_finalize_on_demand = 0;
691#endif
692
693GC_DATASTATIC int GC_dont_gc = 0;
694
695#ifdef GC_DONT_EXPAND
696GC_DATASTATIC int GC_dont_expand = 1;
697#else
698GC_DATASTATIC int GC_dont_expand = 0;
699#endif
700
701GC_STATIC int GC_CALLBACK GC_never_stop_func(void);
702GC_DATASTATIC GC_stop_func GC_default_stop_func = GC_never_stop_func;
703
704#ifndef GC_MISC_EXCLUDE
705GC_STATIC void GC_CALLBACK GC_default_warn_proc(char *msg, GC_word arg);
706GC_DATASTATIC GC_warn_proc GC_current_warn_proc =
707 GC_default_warn_proc; /* ignored */
708#endif
709
710GC_DATASTATIC int GC_stack_grows_up = 0;
711
712GC_DATASTATIC struct GC_gcdata_s *GC_gcdata_global = NULL;
713
714GC_DATASTATIC GC_word GC_max_heapsize = ~(GC_word)0;
715
716GC_DATASTATIC CONST struct GC_objlink_s GC_nil_objlink = { NULL, NULL, 0 };
717
718#ifndef GC_NO_DLINKS
719GC_DATASTATIC CONST struct GC_dlink_s GC_nil_dlink = { NULL, NULL, 0 };
720#endif
721
722#ifndef GC_NO_FNLZ
723GC_DATASTATIC CONST struct GC_fnlz_s GC_nil_fnlz = { NULL, NULL, NULL, 0 };
724#endif
725
726#ifdef GC_PRINT_MSGS
727GC_DATASTATIC int GC_verbose_gc = 0;
728#endif
729
730#ifdef GC_THREADS
731
732#ifdef GC_WIN32_THREADS
733
734struct GC_mutex_s
735{
736 LONG state;
737 HANDLE event;
738};
739
740GC_DATASTATIC struct GC_mutex_s GC_allocate_ml = { 0, 0 };
741
742#else /* GC_WIN32_THREADS */
743
744volatile int GC_inside_collect = -1;
745
746GC_DATASTATIC pthread_mutex_t GC_allocate_ml;
747
748GC_STATIC void GC_CLIBDECL GC_suspend_handler(int sig);
749
750#endif /* ! GC_WIN32_THREADS */
751
752GC_STATIC void GC_FASTCALL GC_stkroot_add(struct GC_gcdata_s *gcdata,
753 GC_THREAD_ID_T thread_id, struct GC_stkroot_s *new_stkroot);
754GC_STATIC void GC_FASTCALL GC_stkroot_tblresize(struct GC_gcdata_s *gcdata,
755 struct GC_stkroot_s **new_hroots, GC_word new_log2_size);
756
757#else /* GC_THREADS */
758
759GC_DATASTATIC int GC_allocate_ml = 0;
760
761#endif /* ! GC_THREADS */
762
763GC_STATIC void *GC_FASTCALL GC_alloc_hroots(struct GC_gcdata_s *gcdata,
764 GC_word new_log2_size, CONST void *nil_ptr);
765GC_STATIC void *GC_FASTCALL GC_core_malloc_with_gc(struct GC_gcdata_s *gcdata,
766 GC_word size, int *pres);
767GC_STATIC int GC_FASTCALL GC_heap_expand(struct GC_gcdata_s *gcdata,
768 GC_word incsize);
769GC_STATIC void *GC_FASTCALL GC_inner_core_malloc(struct GC_gcdata_s *gcdata,
770 GC_word size, int dont_expand);
771GC_STATIC int GC_FASTCALL GC_roots_add(struct GC_gcdata_s *gcdata,
772 GC_word begin_addr, GC_word end_addr);
773
774void GC_noop1(GC_word value)
775{
776 GC_noop_sink = value;
777}
778
779GC_word GC_approx_sp(void)
780{
781 volatile GC_word value;
782 value = (GC_word)(&value);
783 GC_noop1(value);
784 return value;
785}
786
787GC_STATIC int GC_FASTCALL GC_roots_autodetect(struct GC_gcdata_s *gcdata)
788{
789 int res = GC_roots_add(gcdata, 0, 0);
790#ifdef GC_DATASTART
791#ifdef GC_DATAEND
792 res |= GC_roots_add(gcdata, (GC_word)GC_DATASTART, (GC_word)GC_DATAEND);
793#endif
794#endif
795#ifdef GC_DATASTART2
796#ifdef GC_DATAEND2
797 res |= GC_roots_add(gcdata, (GC_word)GC_DATASTART2, (GC_word)GC_DATAEND2);
798#endif
799#endif
800 return res;
801}
802
803GC_INLINE_STATIC GC_word GC_FASTCALL GC_stack_detectbase(void)
804{
805 return (GC_word)(GC_STACKBOTTOM) + (GC_STACKLEN);
806}
807
808GC_INLINE_STATIC GC_word GC_FASTCALL GC_stack_approx_size(
809 CONST struct GC_gcdata_s *gcdata)
810{
811 struct GC_stkroot_s *cur_stack = gcdata->cur_stack;
812 GC_word totalsize = cur_stack != NULL ? cur_stack->end_addr -
813                      cur_stack->begin_addr : sizeof(GC_word);
814#ifdef GC_THREADS
815 totalsize = gcdata->stkroot_htable.count * totalsize;
816#endif
817 return totalsize;
818}
819
820GC_INLINE_STATIC int GC_FASTCALL GC_guess_collect(
821 CONST struct GC_gcdata_s *gcdata, GC_word objsize)
822{
823 return (((GC_stack_approx_size(gcdata) + gcdata->followscan_size) << 1) +
824         gcdata->dataroot_size +
825         ((GC_word)sizeof(GC_word) << gcdata->obj_htable.log2_size) +
826#ifndef GC_NO_DLINKS
827         ((GC_word)sizeof(GC_word) << gcdata->dlink_htable.log2_size) +
828#endif
829         ((gcdata->marked_bytes + gcdata->bytes_allocd -
830         gcdata->followscan_size) >> 2)) / GC_free_space_divisor <=
831#ifndef GC_NO_FNLZ
832         gcdata->bytes_finalized +
833#endif
834         gcdata->bytes_allocd + objsize ? 1 : 0;
835}
836
837GC_INLINE_STATIC GC_word GC_FASTCALL GC_guess_expand_size(
838 CONST struct GC_gcdata_s *gcdata, GC_word objsize)
839{
840 GC_word space_divisor = GC_free_space_divisor + 1;
841 return (gcdata->marked_bytes + gcdata->bytes_allocd) / space_divisor >=
842         gcdata->free_bytes ? gcdata->free_bytes * space_divisor +
843         (gcdata->bytes_allocd >> 3) + (objsize << 2) +
844         gcdata->dataroot_size : 0;
845}
846
847GC_STATIC void GC_FASTCALL GC_abort_badptr(CONST void *ptr)
848{
849#ifdef GC_PRINT_MSGS
850 fprintf(stderr, " GC: Illegal pointer specified: 0x%lX." GC_NEW_LINE,
851  (unsigned long)((GC_word)ptr));
852#else
853 GC_noop1((GC_word)ptr);
854#endif
855 GC_FATAL_ABORT;
856}
857
858GC_INLINE_STATIC int GC_FASTCALL GC_config_set(struct GC_gcdata_s *gcdata)
859{
860 int res = 0;
861#ifdef GC_GETENV_SKIP
862#ifdef GC_PRINT_MSGS
863 GC_verbose_gc = 1;
864#endif
865 GC_noop1((GC_word)gcdata);
866#else
867 char *str;
868 GC_word value;
869 if ((str = getenv("GC_ALL_INTERIOR_POINTERS")) != NULL && *str)
870  GC_all_interior_pointers = *str != '0' || *(str + 1) ? 1 : 0;
871 if ((str = getenv("GC_DONT_GC")) != NULL && *str)
872  GC_dont_gc = GC_NEVER_COLLECT;
873#ifdef GC_GCJ_SUPPORT
874#ifndef GC_IGNORE_GCJ_INFO
875 if ((str = getenv("GC_IGNORE_GCJ_INFO")) != NULL && *str)
876  gcdata->ignore_gcj_info = 1;
877#endif
878#endif
879#ifdef GC_PRINT_MSGS
880 if ((str = getenv("GC_PRINT_STATS")) != NULL && *str)
881  GC_verbose_gc = 1;
882#endif
883 if (((str = getenv("GC_FREE_SPACE_DIVISOR")) != NULL && *str &&
884     ((GC_free_space_divisor = (GC_word)atol(str)) == 0 ||
885     GC_free_space_divisor == ~(GC_word)0)) ||
886     ((str = getenv("GC_MAXIMUM_HEAP_SIZE")) != NULL && *str &&
887     (GC_max_heapsize = (GC_word)atol(str)) == 0) ||
888     ((str = getenv("GC_INITIAL_HEAP_SIZE")) != NULL && *str &&
889     ((value = (GC_word)atol(str)) - (GC_word)1 >= GC_max_heapsize ||
890     (gcdata->total_heapsize < value && GC_heap_expand(gcdata,
891     value - gcdata->total_heapsize) < 0))))
892  res = -1;
893#endif
894 return res;
895}
896
897GC_STATIC int GC_CALLBACK GC_never_stop_func(void)
898{
899 return 0;
900}
901
902GC_API GC_word GC_CALL GC_get_gc_no(void)
903{
904 return GC_gc_no;
905}
906
907GC_API void GC_CALL GC_set_finalize_on_demand(int value)
908{
909 GC_finalize_on_demand = value;
910}
911
912GC_API void GC_CALL GC_set_java_finalization(int value)
913{
914 if (!value)
915  GC_abort_badptr(NULL);
916}
917
918GC_API void GC_CALL GC_set_max_heap_size(GC_word size)
919{
920 GC_max_heapsize = size ? size : ~(GC_word)0;
921}
922
923#ifndef GC_MISC_EXCLUDE
924
925GC_API void GC_CALL GC_set_free_space_divisor(GC_word value)
926{
927 if (!value || value == ~(GC_word)0)
928  GC_abort_badptr(NULL);
929 GC_free_space_divisor = value;
930}
931
932GC_API void GC_CALL GC_set_all_interior_pointers(int value)
933{
934 GC_all_interior_pointers = value;
935}
936
937GC_API void GC_CALL GC_set_dont_expand(int value)
938{
939 GC_dont_expand = value;
940}
941
942GC_API void GC_CALL GC_set_no_dls(int value)
943{
944 /* dummy */
945 GC_noop1((GC_word)value);
946}
947
948GC_API void GC_CALL GC_set_dont_precollect(int value)
949{
950 /* dummy */
951 GC_noop1((GC_word)value);
952}
953
954GC_API void GC_CALL GC_set_force_unmap_on_gcollect(int value)
955{
956 /* dummy */
957 GC_noop1((GC_word)value);
958}
959
960GC_API void GC_CALL GC_set_max_retries(GC_word value)
961{
962 GC_max_retries = value;
963}
964
965GC_STATIC void GC_CALLBACK GC_default_warn_proc(char *msg, GC_word arg)
966{
967 /* dummy */
968 GC_noop1((GC_word)msg ^ arg);
969}
970
971GC_API void GC_CALLBACK GC_ignore_warn_proc(char *msg, GC_word arg)
972{
973 GC_default_warn_proc(msg, arg);
974}
975
976#endif /* ! GC_MISC_EXCLUDE */
977
978GC_API void *GC_CALL GC_call_with_stack_base(GC_stack_base_func fn,
979 void *client_data)
980{
981 GC_word stack_data;
982 struct GC_stack_base sb;
983 sb.mem_base = (void *)&stack_data;
984 return (*fn)(&sb, client_data);
985}
986
987GC_API int GC_CALL GC_get_stack_base(struct GC_stack_base *sb)
988{
989 if (sb == NULL)
990  GC_abort_badptr(NULL);
991 return GC_UNIMPLEMENTED;
992}
993
994GC_INLINE_STATIC struct GC_gcdata_s *GC_FASTCALL GC_gcdata_alloc(void)
995{
996 struct GC_gcdata_s *gcdata;
997 if ((gcdata = GC_CORE_MALLOC(sizeof(struct GC_gcdata_s))) != NULL)
998 {
999  GC_MEM_BZERO(gcdata, sizeof(struct GC_gcdata_s));
1000  if ((gcdata->obj_htable.hroots = GC_alloc_hroots(gcdata,
1001      GC_DEFAULT_LOG2_OBJSIZE, &GC_nil_objlink)) != NULL
1002#ifndef GC_NO_DLINKS
1003      && (gcdata->dlink_htable.hroots = GC_alloc_hroots(gcdata,
1004      GC_DEFAULT_LOG2_SIZE, &GC_nil_dlink)) != NULL
1005#endif
1006#ifndef GC_NO_FNLZ
1007      && (gcdata->fnlz_htable.hroots = GC_alloc_hroots(gcdata,
1008      GC_DEFAULT_LOG2_SIZE, &GC_nil_fnlz)) != NULL
1009#endif
1010#ifdef GC_THREADS
1011      && (gcdata->stkroot_htable.hroots = GC_alloc_hroots(gcdata,
1012      GC_DEFAULT_LOG2_SIZE, NULL)) != NULL
1013#endif
1014      )
1015  {
1016   gcdata->obj_htable.min_obj_addr = ~(GC_word)0;
1017   gcdata->obj_htable.max_obj_addr = (GC_word)1 << GC_LOG2_OFFIGNORE;
1018   gcdata->obj_htable.log2_size = GC_DEFAULT_LOG2_OBJSIZE;
1019#ifndef GC_NO_DLINKS
1020   gcdata->dlink_htable.log2_size = GC_DEFAULT_LOG2_SIZE;
1021#endif
1022#ifndef GC_NO_FNLZ
1023   gcdata->fnlz_htable.log2_size = GC_DEFAULT_LOG2_SIZE;
1024   gcdata->notifier_gc_no = GC_gc_no;
1025#endif
1026#ifdef GC_THREADS
1027   gcdata->stkroot_htable.log2_size = GC_DEFAULT_LOG2_SIZE;
1028#endif
1029  }
1030   else gcdata = NULL;
1031 }
1032 return gcdata;
1033}
1034
1035GC_STATIC int GC_FASTCALL GC_heap_expand(struct GC_gcdata_s *gcdata,
1036 GC_word incsize)
1037{
1038 void *ptr;
1039 GC_word free_bytes = gcdata->free_bytes;
1040 GC_word total_heapsize = gcdata->total_heapsize;
1041 GC_word max_heapsize;
1042 int res = -1;
1043 incsize = incsize > ((GC_word)sizeof(GC_word) << GC_LOG2_OFFIGNORE) ?
1044            (incsize + (sizeof(GC_word) - 1)) & ~(sizeof(GC_word) - 1) :
1045            (GC_word)sizeof(GC_word) << GC_LOG2_OFFIGNORE;
1046 if (free_bytes + incsize <= GC_MEM_SIZELIMIT)
1047 {
1048  gcdata->expanded_heapsize = total_heapsize + incsize;
1049  if ((max_heapsize = GC_max_heapsize) > total_heapsize)
1050  {
1051   if (max_heapsize - total_heapsize < incsize)
1052    incsize = max_heapsize - total_heapsize;
1053#ifdef GC_PRINT_MSGS
1054   if (GC_verbose_gc)
1055    fprintf(stdout,
1056     "[GC: Expand by %lu KiB after %lu KiB allocd, %lu KiB free of %lu KiB]"
1057     GC_NEW_LINE, GC_SIZE_TO_ULKB(incsize),
1058     GC_SIZE_TO_ULKB(gcdata->bytes_allocd), GC_SIZE_TO_ULKB(free_bytes),
1059     GC_SIZE_TO_ULKB(total_heapsize));
1060#endif
1061   while ((ptr = GC_CORE_MALLOC((size_t)free_bytes +
1062          (size_t)incsize)) == NULL)
1063    if ((incsize = incsize >> 1) == 0)
1064     break;
1065   if (ptr != NULL)
1066   {
1067    total_heapsize += incsize;
1068    GC_CORE_FREE(ptr);
1069    gcdata->expanded_heapsize = total_heapsize;
1070    gcdata->total_heapsize = total_heapsize;
1071    gcdata->free_bytes = free_bytes + incsize;
1072    res = 0;
1073   }
1074  }
1075 }
1076 return res;
1077}
1078
1079#ifndef GC_MISC_EXCLUDE
1080
1081GC_STATIC void GC_FASTCALL GC_roots_del_inside(struct GC_gcdata_s *gcdata,
1082 GC_word begin_addr, GC_word end_addr)
1083{
1084 GC_REGISTER_KEYWORD struct GC_dataroot_s *dataroot;
1085 GC_REGISTER_KEYWORD struct GC_dataroot_s **pnext = &gcdata->dataroots;
1086 struct GC_dataroot_s *pred;
1087 GC_word count;
1088 while ((dataroot = *pnext) != NULL && dataroot->begin_addr < begin_addr)
1089  pnext = &dataroot->next;
1090 if (dataroot != NULL)
1091 {
1092  count = 0;
1093  do
1094  {
1095   if (end_addr < dataroot->end_addr)
1096    break;
1097   gcdata->dataroot_size -= dataroot->end_addr - dataroot->begin_addr;
1098   dataroot = (pred = dataroot)->next;
1099   GC_CORE_FREE(pred);
1100   count++;
1101  } while (dataroot != NULL);
1102  *pnext = dataroot;
1103  gcdata->free_bytes += count * sizeof(struct GC_dataroot_s);
1104 }
1105}
1106
1107GC_INLINE_STATIC int GC_FASTCALL GC_roots_exclude(struct GC_gcdata_s *gcdata,
1108 GC_word begin_addr, GC_word end_addr)
1109{
1110 struct GC_dataroot_s *dataroot = gcdata->dataroots;
1111 struct GC_dataroot_s *new_dataroot;
1112 int res = 0;
1113 while (dataroot != NULL && begin_addr >= dataroot->end_addr)
1114  dataroot = dataroot->next;
1115 if (dataroot != NULL && dataroot->begin_addr < end_addr)
1116 {
1117  if (dataroot->begin_addr < begin_addr)
1118  {
1119   if (end_addr < dataroot->end_addr)
1120   {
1121    new_dataroot = GC_core_malloc_with_gc(gcdata,
1122                    sizeof(struct GC_dataroot_s), &res);
1123    res = -1;
1124    if (new_dataroot != NULL)
1125    {
1126     gcdata->dataroot_size -= end_addr - begin_addr;
1127     new_dataroot->begin_addr = end_addr;
1128     new_dataroot->end_addr = dataroot->end_addr;
1129     new_dataroot->next = dataroot->next;
1130     dataroot->end_addr = begin_addr;
1131     dataroot->next = new_dataroot;
1132     res = 0;
1133    }
1134   }
1135    else
1136    {
1137     gcdata->dataroot_size -= dataroot->end_addr - begin_addr;
1138     dataroot->end_addr = begin_addr;
1139     if ((dataroot = dataroot->next) != NULL &&
1140         dataroot->begin_addr < end_addr && end_addr < dataroot->end_addr)
1141     {
1142      gcdata->dataroot_size -= end_addr - dataroot->begin_addr;
1143      dataroot->begin_addr = end_addr;
1144     }
1145    }
1146  }
1147   else
1148   {
1149    gcdata->dataroot_size -= end_addr - dataroot->begin_addr;
1150    dataroot->begin_addr = end_addr;
1151   }
1152 }
1153 return res;
1154}
1155
1156#endif /* ! GC_MISC_EXCLUDE */
1157
1158GC_STATIC int GC_FASTCALL GC_roots_add(struct GC_gcdata_s *gcdata,
1159 GC_word begin_addr, GC_word end_addr)
1160{
1161 GC_REGISTER_KEYWORD struct GC_dataroot_s *dataroot;
1162 struct GC_dataroot_s *new_dataroot;
1163 struct GC_dataroot_s **pnext;
1164 int res = 0;
1165 if (begin_addr)
1166 {
1167  begin_addr = (begin_addr + (sizeof(GC_word) - 1)) & ~(sizeof(GC_word) - 1);
1168  if ((end_addr = end_addr & ~(sizeof(GC_word) - 1)) > begin_addr)
1169  {
1170   pnext = &gcdata->dataroots;
1171   while ((dataroot = *pnext) != NULL && dataroot->end_addr < begin_addr)
1172    pnext = &dataroot->next;
1173   if (dataroot == NULL || end_addr < dataroot->begin_addr)
1174   {
1175    new_dataroot = GC_core_malloc_with_gc(gcdata,
1176                    sizeof(struct GC_dataroot_s), &res);
1177    res = -1;
1178    if (new_dataroot != NULL)
1179    {
1180     gcdata->dataroot_size += end_addr - begin_addr;
1181     new_dataroot->begin_addr = begin_addr;
1182     new_dataroot->end_addr = end_addr;
1183     new_dataroot->next = dataroot;
1184     *pnext = new_dataroot;
1185     res = 0;
1186    }
1187   }
1188    else
1189    {
1190     if (begin_addr < dataroot->begin_addr)
1191     {
1192      gcdata->dataroot_size += dataroot->begin_addr - begin_addr;
1193      dataroot->begin_addr = begin_addr;
1194     }
1195     if (dataroot->end_addr < end_addr)
1196     {
1197      dataroot = dataroot->next;
1198      while (dataroot != NULL && end_addr >= dataroot->begin_addr)
1199      {
1200       if (dataroot->end_addr >= end_addr)
1201        end_addr = dataroot->end_addr;
1202       gcdata->dataroot_size -= dataroot->end_addr - dataroot->begin_addr;
1203       dataroot = (new_dataroot = dataroot)->next;
1204       GC_CORE_FREE(new_dataroot);
1205       gcdata->free_bytes += sizeof(struct GC_dataroot_s);
1206      }
1207      (new_dataroot = *pnext)->next = dataroot;
1208      gcdata->dataroot_size += end_addr - new_dataroot->end_addr;
1209      new_dataroot->end_addr = end_addr;
1210     }
1211    }
1212  }
1213 }
1214 return res;
1215}
1216
1217#ifdef GC_WIN32_THREADS
1218
1219GC_INLINE_STATIC int GC_FASTCALL GC_win32_block_on_mutex(
1220 struct GC_mutex_s *pmutex)
1221{
1222 while (InterlockedExchange(&pmutex->state, -1))
1223  if (WaitForSingleObject(pmutex->event, INFINITE) == WAIT_FAILED)
1224   return -1;
1225 return 0;
1226}
1227
1228#endif /* GC_WIN32_THREADS */
1229
1230GC_STATIC int GC_FASTCALL GC_enter(struct GC_gcdata_s **pgcdata)
1231{
1232 GC_REGISTER_KEYWORD struct GC_gcdata_s *gcdata;
1233 GC_REGISTER_KEYWORD struct GC_stkroot_s *cur_stack;
1234 int res;
1235#ifdef GC_THREADS
1236 struct GC_stkroot_s **new_hroots;
1237 GC_THREAD_ID_T thread_id;
1238 GC_word new_log2_size;
1239 if (
1240#ifdef GC_WIN32_THREADS
1241     (!GC_allocate_ml.event && (GC_allocate_ml.event =
1242     CreateEvent(NULL, (BOOL)0, (BOOL)0, NULL)) == 0) ||
1243     (InterlockedExchange(&GC_allocate_ml.state, 1) &&
1244     GC_win32_block_on_mutex(&GC_allocate_ml) < 0) ||
1245     (thread_id = GetCurrentThreadId()) == (GC_THREAD_ID_T)-1L
1246#else
1247     (GC_inside_collect == -1 && (pthread_mutex_init(&GC_allocate_ml,
1248     GC_THREAD_MUTEX_DEFATTR) ? 1 : (GC_inside_collect = 0))) ||
1249     pthread_mutex_lock(&GC_allocate_ml) ||
1250     (thread_id = pthread_self()) == (pthread_t)(~(GC_word)0)
1251#endif
1252     )
1253 {
1254  *(GC_THREAD_ID_T volatile *)&thread_id = 0;
1255#ifdef GC_PRINT_MSGS
1256  fprintf(stderr, " GC: Cannot initialize or lock mutex!" GC_NEW_LINE);
1257#endif
1258  GC_FATAL_ABORT;
1259 }
1260#else
1261 if (++GC_allocate_ml != 1)
1262 {
1263#ifdef GC_PRINT_MSGS
1264  fprintf(stderr, " GC: Not re-entrant!" GC_NEW_LINE);
1265#endif
1266  GC_FATAL_ABORT;
1267 }
1268 res = GC_UNIMPLEMENTED;
1269#endif
1270 if ((gcdata = GC_gcdata_global) == NULL)
1271 {
1272  if ((gcdata = GC_gcdata_alloc()) == NULL || GC_config_set(gcdata) < 0 ||
1273      GC_roots_autodetect(gcdata) < 0 || (gcdata->cur_stack =
1274      GC_inner_core_malloc(gcdata, sizeof(struct GC_stkroot_s), 0)) == NULL)
1275  {
1276#ifdef GC_PRINT_MSGS
1277   fprintf(stderr,
1278    " GC: Cannot startup - bad config params or no memory!" GC_NEW_LINE);
1279#endif
1280   GC_FATAL_ABORT;
1281  }
1282  if (GC_approx_sp() > (GC_word)pgcdata)
1283   GC_stack_grows_up = 1;
1284  cur_stack = gcdata->cur_stack;
1285#ifndef GC_NO_INACTIVE
1286  cur_stack->activation_frame = NULL;
1287  cur_stack->inactive = 0;
1288#endif
1289#ifndef GC_NO_FNLZ
1290  cur_stack->inside_fnlz = 0;
1291#endif
1292  cur_stack->begin_addr = (cur_stack->end_addr = GC_stack_detectbase()) != 0 ?
1293                           cur_stack->end_addr : ~(GC_word)0;
1294#ifdef GC_THREADS
1295  GC_stkroot_add(gcdata, thread_id, cur_stack);
1296  res = GC_SUCCESS;
1297#endif
1298  GC_gcdata_global = gcdata;
1299 }
1300  else
1301  {
1302   cur_stack = gcdata->cur_stack;
1303#ifdef GC_THREADS
1304   res = GC_DUPLICATE;
1305   if (cur_stack == NULL || cur_stack->thread_id != thread_id)
1306   {
1307    cur_stack =
1308     gcdata->stkroot_htable.hroots[GC_HASH_INDEX((GC_word)thread_id,
1309     gcdata->stkroot_htable.seed, gcdata->stkroot_htable.log2_size)];
1310    while (cur_stack != NULL && cur_stack->thread_id != thread_id)
1311     cur_stack = cur_stack->next;
1312    if ((gcdata->cur_stack = cur_stack) == NULL)
1313    {
1314     if (GC_HASH_RESIZECOND(gcdata->stkroot_htable.count,
1315         gcdata->stkroot_htable.log2_size) &&
1316         (new_hroots = GC_alloc_hroots(gcdata, new_log2_size =
1317         gcdata->stkroot_htable.log2_size + 1, NULL)) != NULL)
1318      GC_stkroot_tblresize(gcdata, new_hroots, new_log2_size);
1319     res = 0;
1320     if ((cur_stack = GC_core_malloc_with_gc(gcdata,
1321         sizeof(struct GC_stkroot_s), &res)) == NULL)
1322     {
1323#ifdef GC_PRINT_MSGS
1324      fprintf(stderr, " GC: Cannot register new thread!" GC_NEW_LINE);
1325#endif
1326      GC_FATAL_ABORT;
1327     }
1328#ifndef GC_NO_INACTIVE
1329     cur_stack->activation_frame = NULL;
1330     cur_stack->inactive = 0;
1331#endif
1332#ifndef GC_NO_FNLZ
1333     cur_stack->inside_fnlz = 0;
1334#endif
1335     cur_stack->begin_addr = ~(GC_word)0;
1336     cur_stack->end_addr = 0;
1337     GC_stkroot_add(gcdata, thread_id, cur_stack);
1338     gcdata->cur_stack = cur_stack;
1339     res = GC_SUCCESS;
1340    }
1341   }
1342#endif
1343  }
1344 if (cur_stack->begin_addr >= (GC_word)pgcdata)
1345  cur_stack->begin_addr = (GC_word)pgcdata - sizeof(GC_word);
1346 if ((GC_word)pgcdata >= cur_stack->end_addr)
1347  cur_stack->end_addr = (GC_word)pgcdata + (sizeof(GC_word) << 1);
1348 *pgcdata = gcdata;
1349 return res;
1350}
1351
1352GC_INLINE_STATIC void GC_FASTCALL GC_leave(void)
1353{
1354#ifdef GC_THREADS
1355#ifdef GC_WIN32_THREADS
1356 if (InterlockedExchange(&GC_allocate_ml.state, 0) < 0 &&
1357     !SetEvent(GC_allocate_ml.event))
1358  GC_FATAL_ABORT;
1359#else
1360 if (pthread_mutex_unlock(&GC_allocate_ml))
1361  GC_FATAL_ABORT;
1362#endif
1363#else
1364 GC_allocate_ml = 0;
1365#endif
1366}
1367
1368#ifndef GC_NO_INACTIVE
1369
1370GC_INLINE_STATIC int GC_FASTCALL GC_set_inactive_sp(
1371 struct GC_gcdata_s **pgcdata)
1372{
1373 GC_REGISTER_KEYWORD struct GC_stkroot_s *cur_stack;
1374 if ((cur_stack = (*pgcdata)->cur_stack) == NULL || cur_stack->inactive)
1375  return 0;
1376 if (GC_stack_grows_up)
1377  cur_stack->end_addr = (GC_word)pgcdata - sizeof(GC_word);
1378  else cur_stack->begin_addr = (GC_word)pgcdata + (sizeof(GC_word) << 1);
1379 cur_stack->inactive = 1;
1380 return 1;
1381}
1382
1383GC_INLINE_STATIC int GC_FASTCALL GC_set_activation_frame(
1384 struct GC_activation_frame_s *activation_frame,
1385 struct GC_stkroot_s *cur_stack)
1386{
1387 if (cur_stack == NULL || !cur_stack->inactive)
1388  return 0;
1389 activation_frame->inactive_sp = GC_stack_grows_up ? cur_stack->end_addr :
1390                                  cur_stack->begin_addr;
1391 activation_frame->prev = cur_stack->activation_frame;
1392 cur_stack->inactive = 0;
1393 cur_stack->activation_frame = activation_frame;
1394 return 1;
1395}
1396
1397GC_INLINE_STATIC void GC_FASTCALL GC_restore_inactive_sp(
1398 struct GC_stkroot_s *cur_stack,
1399 CONST struct GC_activation_frame_s *activation_frame)
1400{
1401 cur_stack->activation_frame = activation_frame->prev;
1402 *(GC_stack_grows_up ? &cur_stack->end_addr :
1403  &cur_stack->begin_addr) = activation_frame->inactive_sp;
1404 cur_stack->inactive = 1;
1405}
1406
1407#endif /* ! GC_NO_INACTIVE */
1408
1409#ifdef GC_THREADS
1410
1411#ifndef GC_WIN32_THREADS
1412
1413GC_STATIC void GC_FASTCALL GC_thread_yield(int attempt)
1414{
1415 if (attempt >= GC_YIELD_MAX_ATTEMPT)
1416  (void)pthread_usleep_np((unsigned)(attempt - GC_YIELD_MAX_ATTEMPT) * 1000);
1417  else GC_THREAD_YIELD;
1418}
1419
1420#endif /* ! GC_WIN32_THREADS */
1421
1422#endif /* GC_THREADS */
1423
1424GC_STATIC void GC_FASTCALL GC_mutator_suspend(struct GC_gcdata_s *gcdata)
1425{
1426#ifdef GC_THREADS
1427 GC_REGISTER_KEYWORD GC_word addr;
1428 GC_REGISTER_KEYWORD struct GC_stkroot_s *stkroot;
1429#ifndef GC_WIN32_THREADS
1430 struct GC_stkroot_s **pnext;
1431#endif
1432 struct GC_stkroot_s *cur_stack;
1433#ifndef GC_WIN32_THREADS
1434 int attempt;
1435 GC_inside_collect = 1;
1436#endif
1437 if ((GC_word)((cur_stack = gcdata->cur_stack) != NULL ? 1 : 0) <
1438     gcdata->stkroot_htable.count)
1439 {
1440  addr = (GC_word)gcdata->stkroot_htable.hroots - sizeof(GC_word);
1441  for (;;)
1442  {
1443   for (;;)
1444   {
1445    if (*(void **)(addr += sizeof(GC_word)) != NULL)
1446     break;
1447   }
1448   if ((GC_word)(stkroot = *(struct GC_stkroot_s **)addr) == ~(GC_word)0)
1449    break;
1450#ifdef GC_WIN32_THREADS
1451   do
1452   {
1453    if (stkroot != cur_stack
1454#ifndef GC_NO_INACTIVE
1455        && !stkroot->inactive
1456#endif
1457        )
1458    {
1459#ifdef GC_WIN32_WCE
1460     while (SuspendThread(GC_THREAD_HANDLE(stkroot)) == ~(DWORD)0)
1461      GC_THREAD_YIELD;
1462#else
1463     if (SuspendThread(stkroot->thread_handle) == ~(DWORD)0)
1464     {
1465#ifdef GC_PRINT_MSGS
1466      fprintf(stderr, " GC: Cannot suspend thread!" GC_NEW_LINE);
1467#endif
1468      GC_FATAL_ABORT;
1469     }
1470#endif
1471    }
1472   } while ((stkroot = stkroot->next) != NULL);
1473#else
1474   pnext = (struct GC_stkroot_s **)addr;
1475   do
1476   {
1477    if (stkroot != cur_stack
1478#ifndef GC_NO_INACTIVE
1479        && !stkroot->inactive
1480#endif
1481        )
1482    {
1483     stkroot->suspend_ack = 1;
1484     (void)signal(GC_SIG_SUSPEND, GC_suspend_handler);
1485     if (pthread_kill(stkroot->thread_id, GC_SIG_SUSPEND))
1486     {
1487      *pnext = stkroot->next;
1488#ifdef GC_PRINT_MSGS
1489      fprintf(stderr,
1490       " GC: Cannot send signal to thread: 0x%lX." GC_NEW_LINE,
1491       (unsigned long)((GC_word)stkroot->thread_id));
1492#endif
1493      gcdata->stkroot_htable.count--;
1494      GC_CORE_FREE(stkroot);
1495      gcdata->free_bytes += sizeof(struct GC_stkroot_s);
1496     }
1497      else pnext = &stkroot->next;
1498    }
1499     else pnext = &stkroot->next;
1500   } while ((stkroot = *pnext) != NULL);
1501#endif
1502  }
1503#ifndef GC_WIN32_THREADS
1504  addr = (GC_word)gcdata->stkroot_htable.hroots - sizeof(GC_word);
1505  for (;;)
1506  {
1507   for (;;)
1508   {
1509    if (*(void **)(addr += sizeof(GC_word)) != NULL)
1510     break;
1511   }
1512   if ((GC_word)(stkroot = *(struct GC_stkroot_s **)addr) == ~(GC_word)0)
1513    break;
1514   do
1515   {
1516    attempt = 0;
1517    while (stkroot->suspend_ack)
1518     GC_thread_yield(attempt++);
1519   } while ((stkroot = stkroot->next) != NULL);
1520  }
1521#endif
1522 }
1523#else
1524 GC_noop1((GC_word)gcdata);
1525#endif
1526}
1527
1528GC_STATIC void GC_FASTCALL GC_mutator_resume(struct GC_gcdata_s *gcdata)
1529{
1530#ifdef GC_THREADS
1531#ifdef GC_WIN32_THREADS
1532 GC_REGISTER_KEYWORD GC_word addr;
1533 GC_REGISTER_KEYWORD struct GC_stkroot_s *stkroot;
1534 struct GC_stkroot_s *cur_stack;
1535 DWORD res;
1536 if ((GC_word)((cur_stack = gcdata->cur_stack) != NULL ? 1 : 0) <
1537     gcdata->stkroot_htable.count)
1538 {
1539  addr = (GC_word)gcdata->stkroot_htable.hroots - sizeof(GC_word);
1540  for (;;)
1541  {
1542   for (;;)
1543   {
1544    if (*(void **)(addr += sizeof(GC_word)) != NULL)
1545     break;
1546   }
1547   if ((GC_word)(stkroot = *(struct GC_stkroot_s **)addr) == ~(GC_word)0)
1548    break;
1549   do
1550   {
1551    if (stkroot != cur_stack &&
1552#ifndef GC_NO_INACTIVE
1553        !stkroot->inactive &&
1554#endif
1555        ((res = ResumeThread(GC_THREAD_HANDLE(stkroot))) == ~(DWORD)0 ||
1556        !res))
1557    {
1558#ifdef GC_PRINT_MSGS
1559     fprintf(stderr, " GC: Cannot resume thread!" GC_NEW_LINE);
1560#endif
1561     GC_FATAL_ABORT;
1562    }
1563   } while ((stkroot = stkroot->next) != NULL);
1564  }
1565 }
1566#else
1567 GC_inside_collect = 0;
1568 GC_noop1((GC_word)gcdata);
1569#endif
1570#else
1571 GC_noop1((GC_word)gcdata);
1572#endif
1573}
1574
1575GC_STATIC void GC_FASTCALL GC_scan_region(struct GC_gcdata_s *gcdata,
1576 GC_word begin_addr, GC_word end_addr, int interior_pointers)
1577{
1578 GC_REGISTER_KEYWORD GC_word *region;
1579 GC_REGISTER_KEYWORD GC_word *end_of_region;
1580 GC_REGISTER_KEYWORD GC_word min_obj_addr;
1581 GC_REGISTER_KEYWORD GC_word ignore_off;
1582 GC_REGISTER_KEYWORD GC_word addr;
1583 struct GC_objlink_s **hroots;
1584 struct GC_objlink_s *marked_list;
1585 struct GC_objlink_s *follow_list;
1586 GC_word log2_size;
1587 GC_word hmask;
1588 GC_word count;
1589 GC_word align_mask;
1590 if (begin_addr < end_addr)
1591 {
1592  hroots = gcdata->obj_htable.hroots;
1593  marked_list = gcdata->obj_htable.marked_list;
1594  follow_list = gcdata->obj_htable.follow_list;
1595  hmask = ((GC_word)1 << (log2_size = gcdata->obj_htable.log2_size)) - 1;
1596  count = 0;
1597  align_mask = 0;
1598  ignore_off = gcdata->obj_htable.max_obj_addr -
1599                (min_obj_addr = gcdata->obj_htable.min_obj_addr);
1600  region = (GC_word *)begin_addr;
1601  end_of_region = (GC_word *)end_addr;
1602  if (!interior_pointers)
1603   align_mask = sizeof(GC_word) - 1;
1604  do
1605  {
1606   if (*region - min_obj_addr >= ignore_off)
1607    do
1608    {
1609     if (++region >= end_of_region)
1610      goto out;
1611    } while (*region - min_obj_addr >= ignore_off);
1612   if (((addr = *region) & align_mask) == 0)
1613   {
1614    GC_REGISTER_KEYWORD struct GC_objlink_s *objlink;
1615    GC_REGISTER_KEYWORD struct GC_objlink_s **pnext;
1616    if ((GC_word)(objlink = *(pnext = &hroots[(((addr >> log2_size) ^ addr) >>
1617        GC_LOG2_OFFIGNORE) & hmask]))->obj > addr)
1618     for (;;)
1619     {
1620      if ((GC_word)(objlink = *(pnext = &objlink->next))->obj <= addr)
1621       break;
1622     }
1623    if (interior_pointers)
1624    {
1625     if ((objlink->atomic_and_size & ~(GC_ATOMIC_MASK | GC_HASDSLEN_MASK)) <=
1626         addr - (GC_word)objlink->obj)
1627     {
1628      if ((addr | ~(((GC_word)1 << GC_LOG2_OFFIGNORE) - (GC_word)1)) ==
1629          ~(GC_word)0)
1630       continue;
1631      pnext = &hroots[((((addr - ((GC_word)1 << GC_LOG2_OFFIGNORE)) >>
1632               log2_size) ^ (addr - ((GC_word)1 << GC_LOG2_OFFIGNORE))) >>
1633               GC_LOG2_OFFIGNORE) & hmask];
1634      while ((GC_word)(objlink = *pnext)->obj > addr)
1635       pnext = &objlink->next;
1636      if ((objlink->atomic_and_size & ~(GC_ATOMIC_MASK | GC_HASDSLEN_MASK)) <=
1637          addr - (GC_word)objlink->obj)
1638       continue;
1639     }
1640    }
1641     else
1642     {
1643      if ((GC_word)objlink->obj != addr)
1644       continue;
1645     }
1646    *pnext = objlink->next;
1647    count++;
1648    if ((objlink->atomic_and_size & GC_ATOMIC_MASK) != 0)
1649    {
1650     objlink->next = marked_list;
1651     marked_list = objlink;
1652    }
1653     else
1654     {
1655      objlink->next = follow_list;
1656      follow_list = objlink;
1657     }
1658   }
1659  } while (++region < end_of_region);
1660out:
1661  gcdata->obj_htable.count -= count;
1662  gcdata->obj_htable.marked_list = marked_list;
1663  gcdata->obj_htable.follow_list = follow_list;
1664 }
1665}
1666
1667GC_INLINE_STATIC void *GC_FASTCALL GC_roots_scan(struct GC_gcdata_s *gcdata,
1668 GC_stop_func stop_func)
1669{
1670 struct GC_dataroot_s *dataroot;
1671 if ((dataroot = gcdata->dataroots) != NULL)
1672 {
1673  do
1674  {
1675   if ((*stop_func)())
1676    break;
1677   GC_scan_region(gcdata, dataroot->begin_addr, dataroot->end_addr,
1678    GC_all_interior_pointers);
1679  } while ((dataroot = dataroot->next) != NULL);
1680 }
1681 return dataroot;
1682}
1683
1684#ifndef GC_NO_INACTIVE
1685
1686#ifdef GC_THREADS
1687GC_STATIC
1688#else
1689GC_INLINE_STATIC
1690#endif
1691void GC_FASTCALL GC_stack_scan_frames(struct GC_gcdata_s *gcdata,
1692 GC_word begin_addr, GC_word end_addr,
1693 CONST struct GC_activation_frame_s *activation_frame)
1694{
1695 if (activation_frame != NULL)
1696 {
1697  if (GC_stack_grows_up)
1698  {
1699   do
1700   {
1701    GC_scan_region(gcdata, ((GC_word)activation_frame +
1702     (sizeof(struct GC_activation_frame_s) + (sizeof(GC_word) << 1) - 1)) &
1703     ~(sizeof(GC_word) - 1), end_addr & ~(sizeof(GC_word) - 1), 1);
1704    end_addr = activation_frame->inactive_sp;
1705   } while ((activation_frame = activation_frame->prev) != NULL);
1706  }
1707   else
1708   {
1709    do
1710    {
1711     GC_scan_region(gcdata, (begin_addr + (sizeof(GC_word) - 1)) &
1712      ~(sizeof(GC_word) - 1), ((GC_word)activation_frame - sizeof(GC_word)) &
1713      ~(sizeof(GC_word) - 1), 1);
1714     begin_addr = activation_frame->inactive_sp;
1715    } while ((activation_frame = activation_frame->prev) != NULL);
1716   }
1717 }
1718 GC_scan_region(gcdata, (begin_addr + (sizeof(GC_word) - 1)) &
1719  ~(sizeof(GC_word) - 1), end_addr & ~(sizeof(GC_word) - 1), 1);
1720}
1721
1722#endif /* ! GC_NO_INACTIVE */
1723
1724GC_STATIC void GC_FASTCALL GC_stack_scan_cur(struct GC_gcdata_s *gcdata)
1725{
1726 GC_word begin_addr;
1727 GC_word end_addr;
1728 struct GC_stkroot_s *cur_stack;
1729 GC_PUSHREGS_BEGIN;
1730 if ((cur_stack = gcdata->cur_stack) != NULL)
1731 {
1732  begin_addr = cur_stack->begin_addr;
1733  end_addr = GC_approx_sp();
1734  if (!GC_stack_grows_up)
1735  {
1736   begin_addr = end_addr;
1737   end_addr = cur_stack->end_addr;
1738  }
1739#ifdef GC_NO_INACTIVE
1740  GC_scan_region(gcdata, (begin_addr + (sizeof(GC_word) - 1)) &
1741   ~(sizeof(GC_word) - 1), end_addr & ~(sizeof(GC_word) - 1), 1);
1742#else
1743  GC_stack_scan_frames(gcdata, begin_addr, end_addr,
1744   cur_stack->activation_frame);
1745#endif
1746 }
1747 GC_PUSHREGS_END;
1748}
1749
1750GC_STATIC void GC_FASTCALL GC_scan_followable(struct GC_gcdata_s *gcdata,
1751 GC_stop_func stop_func)
1752{
1753 GC_REGISTER_KEYWORD struct GC_objlink_s *objlink;
1754 GC_word begin_addr;
1755 while ((objlink = gcdata->obj_htable.follow_list) != NULL && !(*stop_func)())
1756 {
1757  gcdata->obj_htable.follow_list = objlink->next;
1758  objlink->next = gcdata->obj_htable.marked_list;
1759  begin_addr = (GC_word)(gcdata->obj_htable.marked_list = objlink)->obj;
1760#ifdef GC_GCJ_SUPPORT
1761#ifdef GC_IGNORE_GCJ_INFO
1762  GC_scan_region(gcdata, begin_addr, begin_addr + (objlink->atomic_and_size &
1763   ~(GC_ATOMIC_MASK | (sizeof(GC_word) - 1))), GC_all_interior_pointers);
1764#else
1765  GC_scan_region(gcdata, begin_addr,
1766   (((objlink->atomic_and_size & GC_HASDSLEN_MASK) != 0 ?
1767   *(GC_word *)(*(GC_word *)begin_addr + MARK_DESCR_OFFSET) :
1768   objlink->atomic_and_size) & ~(GC_ATOMIC_MASK | (sizeof(GC_word) - 1))) +
1769   begin_addr, GC_all_interior_pointers);
1770#endif
1771#else
1772  GC_scan_region(gcdata, begin_addr, begin_addr + (objlink->atomic_and_size &
1773   ~(GC_ATOMIC_MASK | (sizeof(GC_word) - 1))), GC_all_interior_pointers);
1774#endif
1775 }
1776}
1777
1778#ifdef GC_THREADS
1779
1780#ifndef GC_WIN32_THREADS
1781
1782GC_STATIC void GC_CLIBDECL GC_suspend_handler(int sig)
1783{
1784 GC_REGISTER_KEYWORD struct GC_gcdata_s *gcdata;
1785 struct GC_stkroot_s *volatile stkroot;
1786 pthread_t thread_id;
1787 int old_errno;
1788 int attempt;
1789 if ((gcdata = GC_gcdata_global) != NULL)
1790 {
1791  old_errno = errno;
1792#ifdef SIG_ACK
1793  if (signal(sig, GC_suspend_handler) != SIG_DFL)
1794   (void)signal(sig, SIG_ACK);
1795#else
1796  (void)signal(sig, GC_suspend_handler);
1797#endif
1798  thread_id = pthread_self();
1799  stkroot =
1800   gcdata->stkroot_htable.hroots[GC_HASH_INDEX((GC_word)thread_id,
1801   gcdata->stkroot_htable.seed, gcdata->stkroot_htable.log2_size)];
1802  while (stkroot != NULL && stkroot->thread_id != thread_id)
1803   stkroot = stkroot->next;
1804  if (gcdata->cur_stack != stkroot && stkroot != NULL
1805#ifndef GC_NO_INACTIVE
1806      && !stkroot->inactive
1807#endif
1808      )
1809  {
1810   GC_ASYNC_PUSHREGS_BEGIN;
1811   *(volatile GC_word *)(GC_stack_grows_up ? &stkroot->end_addr :
1812    &stkroot->begin_addr) = GC_approx_sp();
1813   attempt = 0;
1814   do
1815   {
1816    stkroot->suspend_ack = 0;
1817    GC_thread_yield(attempt++);
1818   } while (GC_inside_collect);
1819   GC_ASYNC_PUSHREGS_END;
1820  }
1821  GC_ERRNO_SET(old_errno);
1822 }
1823}
1824
1825#endif /* ! GC_WIN32_THREADS */
1826
1827GC_STATIC GC_word GC_FASTCALL GC_stkroot_scan_other(
1828 struct GC_gcdata_s *gcdata, GC_stop_func stop_func)
1829{
1830#ifdef GC_WIN32_THREADS
1831 CONTEXT context;
1832#endif
1833 GC_REGISTER_KEYWORD GC_word addr;
1834 struct GC_stkroot_s *stkroot = (void *)(~(GC_word)0);
1835 struct GC_stkroot_s *cur_stack;
1836 if ((cur_stack = gcdata->cur_stack) == NULL ||
1837     gcdata->stkroot_htable.count > (GC_word)1)
1838 {
1839  addr = (GC_word)gcdata->stkroot_htable.hroots - sizeof(GC_word);
1840  do
1841  {
1842   for (;;)
1843   {
1844    if (*(void **)(addr += sizeof(GC_word)) != NULL)
1845     break;
1846   }
1847   if ((GC_word)(stkroot = *(struct GC_stkroot_s **)addr) == ~(GC_word)0)
1848    break;
1849   do
1850   {
1851    if (stkroot != cur_stack)
1852    {
1853     if ((*stop_func)())
1854      break;
1855#ifdef GC_WIN32_THREADS
1856#ifndef GC_NO_INACTIVE
1857     if (!stkroot->inactive)
1858#endif
1859     {
1860      context.ContextFlags = CONTEXT_INTEGER | CONTEXT_CONTROL;
1861      if (GetThreadContext(GC_THREAD_HANDLE(stkroot), &context))
1862      {
1863       GC_scan_region(gcdata, (GC_word)(&context),
1864        (GC_word)(&context) + (sizeof(context) & ~(sizeof(GC_word) - 1)), 1);
1865       if ((*stop_func)())
1866        break;
1867       *(GC_stack_grows_up ? &stkroot->end_addr : &stkroot->begin_addr) =
1868        context.GC_WIN32_CONTEXT_SP_NAME;
1869      }
1870#ifdef GC_PRINT_MSGS
1871       else fprintf(stderr,
1872             " GC: Cannot get context of thread: 0x%lX." GC_NEW_LINE,
1873             (unsigned long)stkroot->thread_id);
1874#endif
1875     }
1876#endif
1877#ifdef GC_NO_INACTIVE
1878     GC_scan_region(gcdata, (stkroot->begin_addr + (sizeof(GC_word) - 1)) &
1879      ~(sizeof(GC_word) - 1), stkroot->end_addr & ~(sizeof(GC_word) - 1), 1);
1880#else
1881     GC_stack_scan_frames(gcdata, stkroot->begin_addr, stkroot->end_addr,
1882      stkroot->activation_frame);
1883#endif
1884    }
1885   } while ((stkroot = stkroot->next) != NULL);
1886  } while (stkroot == NULL);
1887 }
1888 return ~(GC_word)stkroot;
1889}
1890
1891GC_STATIC void GC_FASTCALL GC_stkroot_tblresize(struct GC_gcdata_s *gcdata,
1892 struct GC_stkroot_s **new_hroots, GC_word new_log2_size)
1893{
1894 GC_REGISTER_KEYWORD GC_word addr =
1895  (GC_word)gcdata->stkroot_htable.hroots - sizeof(GC_word);
1896 struct GC_stkroot_s **pnext;
1897 struct GC_stkroot_s *stkroot;
1898 struct GC_stkroot_s *new_stkroot;
1899 GC_word seed = addr + GC_RANDOM_SEED(gcdata);
1900 for (;;)
1901 {
1902  for (;;)
1903  {
1904   if (*(void **)(addr += sizeof(GC_word)) != NULL)
1905    break;
1906  }
1907  if ((GC_word)(stkroot = *(struct GC_stkroot_s **)addr) == ~(GC_word)0)
1908   break;
1909  do
1910  {
1911   pnext = &new_hroots[GC_HASH_INDEX((GC_word)stkroot->thread_id, seed,
1912            new_log2_size)];
1913   stkroot = (new_stkroot = stkroot)->next;
1914   new_stkroot->next = *pnext;
1915   *pnext = new_stkroot;
1916  } while (stkroot != NULL);
1917 }
1918 gcdata->stkroot_htable.seed = seed;
1919 GC_CORE_FREE(gcdata->stkroot_htable.hroots);
1920 gcdata->free_bytes += ((GC_word)sizeof(GC_word) <<
1921                        gcdata->stkroot_htable.log2_size) + sizeof(GC_word);
1922 gcdata->stkroot_htable.hroots = new_hroots;
1923 gcdata->stkroot_htable.log2_size = new_log2_size;
1924}
1925
1926GC_STATIC void GC_FASTCALL GC_stkroot_add(struct GC_gcdata_s *gcdata,
1927 GC_THREAD_ID_T thread_id, struct GC_stkroot_s *new_stkroot)
1928{
1929 struct GC_stkroot_s **pnext =
1930  &gcdata->stkroot_htable.hroots[GC_HASH_INDEX((GC_word)thread_id,
1931  gcdata->stkroot_htable.seed, gcdata->stkroot_htable.log2_size)];
1932#ifdef GC_WIN32_THREADS
1933#ifndef GC_WIN32_WCE
1934 HANDLE process_handle = GetCurrentProcess();
1935 if (!DuplicateHandle(process_handle, GetCurrentThread(), process_handle,
1936     &new_stkroot->thread_handle, 0, (BOOL)0, DUPLICATE_SAME_ACCESS))
1937 {
1938#ifdef GC_PRINT_MSGS
1939  fprintf(stderr, " GC: Cannot duplicate thread handle!" GC_NEW_LINE);
1940#endif
1941  GC_FATAL_ABORT;
1942 }
1943#endif
1944#else
1945 new_stkroot->suspend_ack = 0;
1946#endif
1947 new_stkroot->next = *pnext;
1948 new_stkroot->thread_id = thread_id;
1949 *pnext = new_stkroot;
1950 gcdata->stkroot_htable.count++;
1951#ifndef GC_WIN32_THREADS
1952 (void)signal(GC_SIG_SUSPEND, GC_suspend_handler);
1953#endif
1954}
1955
1956GC_INLINE_STATIC void GC_FASTCALL GC_stkroot_delete_cur(
1957 struct GC_gcdata_s *gcdata)
1958{
1959 struct GC_stkroot_s *cur_stack = gcdata->cur_stack;
1960 GC_REGISTER_KEYWORD struct GC_stkroot_s **pnext =
1961  &gcdata->stkroot_htable.hroots[GC_HASH_INDEX((GC_word)cur_stack->thread_id,
1962  gcdata->stkroot_htable.seed, gcdata->stkroot_htable.log2_size)];
1963 while (*pnext != cur_stack)
1964  pnext = &(*pnext)->next;
1965 *pnext = cur_stack->next;
1966 gcdata->stkroot_htable.count--;
1967#ifdef GC_WIN32_THREADS
1968#ifndef GC_WIN32_WCE
1969 (void)CloseHandle(cur_stack->thread_handle);
1970#endif
1971#endif
1972 gcdata->cur_stack = NULL;
1973 GC_CORE_FREE(cur_stack);
1974 gcdata->free_bytes += sizeof(struct GC_stkroot_s);
1975}
1976
1977#endif /* GC_THREADS */
1978
1979#ifndef GC_NO_DLINKS
1980
1981GC_STATIC void GC_FASTCALL GC_dlink_scan_clear(struct GC_gcdata_s *gcdata)
1982{
1983 GC_REGISTER_KEYWORD GC_word addr =
1984  (GC_word)gcdata->dlink_htable.hroots - sizeof(GC_word);
1985 GC_REGISTER_KEYWORD struct GC_dlink_s *dlink;
1986 struct GC_dlink_s **pnext;
1987 struct GC_dlink_s *free_list = gcdata->dlink_htable.free_list;
1988 struct GC_objlink_s **obj_hroots = gcdata->obj_htable.hroots;
1989 GC_word obj_log2_size;
1990 GC_word obj_hmask;
1991 GC_word saved_addr;
1992 GC_word count = 0;
1993 obj_hmask = ((GC_word)1 << (obj_log2_size =
1994              gcdata->obj_htable.log2_size)) - 1;
1995 for (;;)
1996 {
1997  for (;;)
1998  {
1999   if (*(struct GC_dlink_s **)(addr += sizeof(GC_word)) != &GC_nil_dlink)
2000    break;
2001  }
2002  if ((GC_word)(dlink = *(struct GC_dlink_s **)addr) == ~(GC_word)0)
2003   break;
2004  pnext = (struct GC_dlink_s **)(saved_addr = addr);
2005  do
2006  {
2007   GC_REGISTER_KEYWORD struct GC_objlink_s *objlink;
2008   addr = (GC_word)dlink->objlink->obj;
2009   if ((GC_word)(objlink = obj_hroots[(((addr >> obj_log2_size) ^ addr) >>
2010       GC_LOG2_OFFIGNORE) & obj_hmask])->obj > addr)
2011    for (;;)
2012    {
2013     if ((GC_word)(objlink = objlink->next)->obj <= addr)
2014      break;
2015    }
2016   if ((GC_word)objlink->obj == addr)
2017   {
2018    *pnext = dlink->next;
2019    *(GC_word *)(~dlink->hidden_link) = 0;
2020    dlink->next = free_list;
2021    count++;
2022    free_list = dlink;
2023   }
2024    else pnext = &dlink->next;
2025  } while ((dlink = *pnext) != &GC_nil_dlink);
2026  addr = saved_addr;
2027 }
2028 gcdata->dlink_htable.free_list = free_list;
2029 gcdata->dlink_htable.count -= count;
2030 gcdata->free_bytes += count * sizeof(struct GC_dlink_s);
2031}
2032
2033GC_STATIC GC_word GC_FASTCALL GC_dlink_free_pending(
2034 struct GC_gcdata_s *gcdata, GC_word min_free_count)
2035{
2036 GC_REGISTER_KEYWORD struct GC_dlink_s *dlink;
2037 GC_word count = 0;
2038 do
2039 {
2040  if ((dlink = gcdata->dlink_htable.free_list) == NULL)
2041   break;
2042  gcdata->dlink_htable.free_list = dlink->next;
2043  GC_CORE_FREE(dlink);
2044 } while (++count < min_free_count);
2045 return count;
2046}
2047
2048GC_INLINE_STATIC void GC_FASTCALL GC_dlink_tblresize(
2049 struct GC_gcdata_s *gcdata, struct GC_dlink_s **new_hroots,
2050 GC_word new_log2_size)
2051{
2052 GC_REGISTER_KEYWORD GC_word addr =
2053  (GC_word)gcdata->dlink_htable.hroots - sizeof(GC_word);
2054 struct GC_dlink_s **pnext;
2055 struct GC_dlink_s *dlink;
2056 GC_word hidden_link;
2057 GC_word saved_addr;
2058 GC_word seed = addr + GC_RANDOM_SEED(gcdata);
2059 for (;;)
2060 {
2061  for (;;)
2062  {
2063   if (*(struct GC_dlink_s **)(addr += sizeof(GC_word)) != &GC_nil_dlink)
2064    break;
2065  }
2066  if ((GC_word)(dlink = *(struct GC_dlink_s **)addr) == ~(GC_word)0)
2067   break;
2068  saved_addr = addr;
2069  do
2070  {
2071   hidden_link = dlink->hidden_link;
2072   pnext = &new_hroots[GC_HASH_INDEX(hidden_link >> GC_LOG2_OFFIGNORE,
2073            seed, new_log2_size)];
2074   while (((struct GC_dlink_s *)(addr = (GC_word)(*pnext)))->hidden_link >
2075          hidden_link)
2076    pnext = &((struct GC_dlink_s *)addr)->next;
2077   dlink = (*pnext = dlink)->next;
2078   (*pnext)->next = (struct GC_dlink_s *)addr;
2079  } while (dlink != &GC_nil_dlink);
2080  addr = saved_addr;
2081 }
2082 gcdata->dlink_htable.seed = seed;
2083 GC_CORE_FREE(gcdata->dlink_htable.hroots);
2084 gcdata->free_bytes += ((GC_word)sizeof(GC_word) <<
2085                        gcdata->dlink_htable.log2_size) + sizeof(GC_word);
2086 gcdata->dlink_htable.hroots = new_hroots;
2087 gcdata->dlink_htable.log2_size = new_log2_size;
2088}
2089
2090GC_INLINE_STATIC int GC_FASTCALL GC_dlink_add(struct GC_gcdata_s *gcdata,
2091 GC_word hidden_link, struct GC_objlink_s *objlink,
2092 struct GC_dlink_s *new_dlink)
2093{
2094 GC_REGISTER_KEYWORD struct GC_dlink_s *dlink;
2095 struct GC_dlink_s **pnext;
2096 if (!gcdata->dlink_htable.count)
2097  gcdata->dlink_htable.seed += GC_RANDOM_SEED(gcdata);
2098 pnext = &gcdata->dlink_htable.hroots[GC_HASH_INDEX(hidden_link >>
2099          GC_LOG2_OFFIGNORE, gcdata->dlink_htable.seed,
2100          gcdata->dlink_htable.log2_size)];
2101 while ((dlink = *pnext)->hidden_link > hidden_link)
2102  pnext = &dlink->next;
2103 if (dlink->hidden_link == hidden_link)
2104 {
2105  dlink->objlink = objlink;
2106  if (new_dlink != NULL &&
2107      (dlink = gcdata->dlink_htable.free_list) != new_dlink)
2108  {
2109   new_dlink->next = dlink;
2110   gcdata->dlink_htable.free_list = new_dlink;
2111   gcdata->free_bytes += sizeof(struct GC_dlink_s);
2112  }
2113  return GC_DUPLICATE;
2114 }
2115 if (new_dlink == NULL)
2116  return GC_NO_MEMORY;
2117 if (gcdata->dlink_htable.free_list == new_dlink)
2118 {
2119  gcdata->free_bytes -= sizeof(struct GC_dlink_s);
2120  gcdata->dlink_htable.free_list = new_dlink->next;
2121 }
2122 new_dlink->objlink = objlink;
2123 new_dlink->next = dlink;
2124 new_dlink->hidden_link = hidden_link;
2125 *pnext = new_dlink;
2126 gcdata->dlink_htable.count++;
2127 return GC_SUCCESS;
2128}
2129
2130GC_STATIC int GC_FASTCALL GC_dlink_delete(struct GC_gcdata_s *gcdata,
2131 GC_word hidden_link, GC_word min_hidden, GC_word max_hidden)
2132{
2133 GC_REGISTER_KEYWORD struct GC_dlink_s *dlink;
2134 struct GC_dlink_s **pnext =
2135  &gcdata->dlink_htable.hroots[GC_HASH_INDEX(hidden_link >> GC_LOG2_OFFIGNORE,
2136  gcdata->dlink_htable.seed, gcdata->dlink_htable.log2_size)];
2137 while ((dlink = *pnext)->hidden_link > max_hidden)
2138  pnext = &dlink->next;
2139 if (dlink->hidden_link < min_hidden)
2140  return 0;
2141 do
2142 {
2143  *pnext = dlink->next;
2144  gcdata->dlink_htable.count--;
2145  GC_CORE_FREE(dlink);
2146  dlink = *pnext;
2147  gcdata->free_bytes += sizeof(struct GC_dlink_s);
2148 } while (dlink->hidden_link >= min_hidden);
2149 return 1;
2150}
2151
2152#endif /* ! GC_NO_DLINKS */
2153
2154#ifndef GC_NO_FNLZ
2155
2156GC_STATIC int GC_FASTCALL GC_objlink_mark(struct GC_gcdata_s *gcdata,
2157 GC_word addr, int interior_pointers)
2158{
2159 GC_REGISTER_KEYWORD struct GC_objlink_s *objlink;
2160 GC_REGISTER_KEYWORD struct GC_objlink_s **pnext;
2161 struct GC_objlink_s **hroots = gcdata->obj_htable.hroots;
2162 GC_word log2_size = gcdata->obj_htable.log2_size;
2163 pnext = &hroots[(((addr >> log2_size) ^ addr) >> GC_LOG2_OFFIGNORE) &
2164          (((GC_word)1 << log2_size) - 1)];
2165 while ((GC_word)(objlink = *pnext)->obj > addr)
2166  pnext = &objlink->next;
2167 if (interior_pointers)
2168 {
2169  if ((objlink->atomic_and_size & ~(GC_ATOMIC_MASK | GC_HASDSLEN_MASK)) <=
2170      addr - (GC_word)objlink->obj)
2171  {
2172   if ((addr | ~(((GC_word)1 << GC_LOG2_OFFIGNORE) - (GC_word)1)) ==
2173       ~(GC_word)0)
2174    return 0;
2175   pnext = &hroots[((((addr - ((GC_word)1 << GC_LOG2_OFFIGNORE)) >>
2176            log2_size) ^ (addr - ((GC_word)1 << GC_LOG2_OFFIGNORE))) >>
2177            GC_LOG2_OFFIGNORE) & (((GC_word)1 << log2_size) - 1)];
2178   while ((GC_word)(objlink = *pnext)->obj > addr)
2179    pnext = &objlink->next;
2180   if ((objlink->atomic_and_size & ~(GC_ATOMIC_MASK | GC_HASDSLEN_MASK)) <=
2181       addr - (GC_word)objlink->obj)
2182    return 0;
2183  }
2184 }
2185  else
2186  {
2187   if ((GC_word)objlink->obj != addr)
2188    return 0;
2189  }
2190 *pnext = objlink->next;
2191 gcdata->obj_htable.count--;
2192 if ((objlink->atomic_and_size & GC_ATOMIC_MASK) != 0)
2193 {
2194  objlink->next = gcdata->obj_htable.marked_list;
2195  gcdata->obj_htable.marked_list = objlink;
2196 }
2197  else
2198  {
2199   objlink->next = gcdata->obj_htable.follow_list;
2200   gcdata->obj_htable.follow_list = objlink;
2201  }
2202 return 1;
2203}
2204
2205GC_INLINE_STATIC GC_word GC_FASTCALL GC_fnlz_precollect(
2206 struct GC_gcdata_s *gcdata, GC_word *pcount)
2207{
2208 GC_REGISTER_KEYWORD GC_word addr;
2209 GC_REGISTER_KEYWORD struct GC_fnlz_s *fnlz;
2210 void *client_data;
2211 struct GC_objlink_s *objlink;
2212 GC_word bytes_finalized = 0;
2213 int interior_pointers = GC_all_interior_pointers;
2214 if ((fnlz = gcdata->fnlz_htable.ready_fnlz) != NULL)
2215 {
2216  addr = 0;
2217  do
2218  {
2219   bytes_finalized += (objlink = fnlz->objlink)->atomic_and_size;
2220   (void)GC_objlink_mark(gcdata, (GC_word)objlink->obj, 0);
2221   addr++;
2222   if ((client_data = fnlz->client_data) != NULL)
2223    (void)GC_objlink_mark(gcdata, (GC_word)client_data, interior_pointers);
2224  } while ((fnlz = fnlz->next) != NULL);
2225  *pcount += addr;
2226 }
2227 if (gcdata->fnlz_htable.has_client_ptrs)
2228 {
2229  addr = (GC_word)gcdata->fnlz_htable.hroots - sizeof(GC_word);
2230  for (;;)
2231  {
2232   for (;;)
2233   {
2234    if (*(struct GC_fnlz_s **)(addr += sizeof(GC_word)) != &GC_nil_fnlz)
2235     break;
2236   }
2237   if ((GC_word)(fnlz = *(struct GC_fnlz_s **)addr) == ~(GC_word)0)
2238    break;
2239   do
2240   {
2241    if ((client_data = fnlz->client_data) != NULL)
2242     (void)GC_objlink_mark(gcdata, (GC_word)client_data, interior_pointers);
2243   } while ((fnlz = fnlz->next) != &GC_nil_fnlz);
2244  }
2245 }
2246 return bytes_finalized & ~(GC_ATOMIC_MASK | GC_HASDSLEN_MASK);
2247}
2248
2249GC_STATIC GC_word GC_FASTCALL GC_fnlz_after_collect(
2250 struct GC_gcdata_s *gcdata, GC_word *pcount)
2251{
2252 GC_REGISTER_KEYWORD GC_word addr =
2253  (GC_word)gcdata->fnlz_htable.hroots - sizeof(GC_word);
2254 GC_REGISTER_KEYWORD struct GC_fnlz_s *fnlz;
2255 struct GC_fnlz_s **pnext;
2256 struct GC_fnlz_s *ready_fnlz = gcdata->fnlz_htable.ready_fnlz;
2257 struct GC_objlink_s *objlink;
2258 GC_word bytes_finalized = 0;
2259 GC_word count = 0;
2260 for (;;)
2261 {
2262  for (;;)
2263  {
2264   if (*(struct GC_fnlz_s **)(addr += sizeof(GC_word)) != &GC_nil_fnlz)
2265    break;
2266  }
2267  if ((GC_word)(fnlz = *(struct GC_fnlz_s **)addr) == ~(GC_word)0)
2268   break;
2269  pnext = (struct GC_fnlz_s **)addr;
2270  do
2271  {
2272   if (GC_objlink_mark(gcdata, (GC_word)(objlink = fnlz->objlink)->obj, 0))
2273   {
2274    *pnext = fnlz->next;
2275    bytes_finalized += objlink->atomic_and_size;
2276    fnlz->next = ready_fnlz;
2277    count++;
2278    ready_fnlz = fnlz;
2279   }
2280    else pnext = &fnlz->next;
2281  } while ((fnlz = *pnext) != &GC_nil_fnlz);
2282 }
2283 gcdata->fnlz_htable.ready_fnlz = ready_fnlz;
2284 if ((gcdata->fnlz_htable.count -= count) == 0)
2285  gcdata->fnlz_htable.has_client_ptrs = 0;
2286 gcdata->free_bytes += count * sizeof(struct GC_fnlz_s);
2287 *pcount += count;
2288 return bytes_finalized & ~(GC_ATOMIC_MASK | GC_HASDSLEN_MASK);
2289}
2290
2291GC_INLINE_STATIC void GC_FASTCALL GC_fnlz_tblresize(
2292 struct GC_gcdata_s *gcdata, struct GC_fnlz_s **new_hroots,
2293 GC_word new_log2_size)
2294{
2295 GC_REGISTER_KEYWORD GC_word addr =
2296  (GC_word)gcdata->fnlz_htable.hroots - sizeof(GC_word);
2297 struct GC_fnlz_s **pnext;
2298 struct GC_fnlz_s *fnlz;
2299 struct GC_objlink_s *objlink;
2300 GC_word saved_addr;
2301 GC_word seed = addr + GC_RANDOM_SEED(gcdata);
2302 for (;;)
2303 {
2304  for (;;)
2305  {
2306   if (*(struct GC_fnlz_s **)(addr += sizeof(GC_word)) != &GC_nil_fnlz)
2307    break;
2308  }
2309  if ((GC_word)(fnlz = *(struct GC_fnlz_s **)addr) == ~(GC_word)0)
2310   break;
2311  saved_addr = addr;
2312  do
2313  {
2314   objlink = fnlz->objlink;
2315   pnext = &new_hroots[GC_HASH_INDEX((GC_word)objlink /
2316            (sizeof(GC_word) << 1), seed, new_log2_size)];
2317   while ((GC_word)((struct GC_fnlz_s *)(addr = (GC_word)(*pnext)))->objlink >
2318          (GC_word)objlink)
2319    pnext = &((struct GC_fnlz_s *)addr)->next;
2320   fnlz = (*pnext = fnlz)->next;
2321   (*pnext)->next = (struct GC_fnlz_s *)addr;
2322  } while (fnlz != &GC_nil_fnlz);
2323  addr = saved_addr;
2324 }
2325 gcdata->fnlz_htable.seed = seed;
2326 GC_CORE_FREE(gcdata->fnlz_htable.hroots);
2327 gcdata->free_bytes += ((GC_word)sizeof(GC_word) <<
2328                        gcdata->fnlz_htable.log2_size) + sizeof(GC_word);
2329 gcdata->fnlz_htable.hroots = new_hroots;
2330 gcdata->fnlz_htable.log2_size = new_log2_size;
2331}
2332
2333GC_INLINE_STATIC GC_finalization_proc GC_FASTCALL GC_fnlz_add_del(
2334 struct GC_gcdata_s *gcdata, struct GC_objlink_s *objlink,
2335 GC_finalization_proc fn, void *client_data, void **odata)
2336{
2337 GC_REGISTER_KEYWORD struct GC_fnlz_s *fnlz;
2338 struct GC_fnlz_s **pnext;
2339 struct GC_fnlz_s *new_fnlz;
2340 GC_finalization_proc old_fn;
2341 if (!gcdata->fnlz_htable.count)
2342  gcdata->fnlz_htable.seed += GC_RANDOM_SEED(gcdata);
2343 pnext = &gcdata->fnlz_htable.hroots[GC_HASH_INDEX((GC_word)objlink /
2344          (sizeof(GC_word) << 1), gcdata->fnlz_htable.seed,
2345          gcdata->fnlz_htable.log2_size)];
2346 while ((GC_word)(fnlz = *pnext)->objlink > (GC_word)objlink)
2347  pnext = &fnlz->next;
2348 if (fnlz->objlink == objlink)
2349 {
2350  *odata = fnlz->client_data;
2351  old_fn = fnlz->fn;
2352  if (fn != 0)
2353  {
2354   fnlz->client_data = client_data;
2355   fnlz->fn = fn;
2356   if (!gcdata->fnlz_htable.has_client_ptrs &&
2357       (GC_word)client_data >= gcdata->obj_htable.min_obj_addr &&
2358       (GC_word)client_data < gcdata->obj_htable.max_obj_addr)
2359    gcdata->fnlz_htable.has_client_ptrs = 1;
2360  }
2361   else
2362   {
2363    *pnext = fnlz->next;
2364    if (gcdata->fnlz_htable.single_free != NULL)
2365    {
2366     GC_CORE_FREE(fnlz);
2367     gcdata->free_bytes += sizeof(struct GC_fnlz_s);
2368    }
2369     else gcdata->fnlz_htable.single_free = fnlz;
2370    if (!(--gcdata->fnlz_htable.count))
2371     gcdata->fnlz_htable.has_client_ptrs = 0;
2372   }
2373 }
2374  else
2375  {
2376   if (fn != 0)
2377   {
2378    if ((new_fnlz = gcdata->fnlz_htable.single_free) != NULL)
2379    {
2380     gcdata->fnlz_htable.single_free = NULL;
2381     new_fnlz->next = fnlz;
2382     new_fnlz->objlink = objlink;
2383     new_fnlz->client_data = client_data;
2384     new_fnlz->fn = fn;
2385     *pnext = new_fnlz;
2386     gcdata->fnlz_htable.count++;
2387     *odata = NULL;
2388     if (!gcdata->fnlz_htable.has_client_ptrs &&
2389         (GC_word)client_data >= gcdata->obj_htable.min_obj_addr &&
2390         (GC_word)client_data < gcdata->obj_htable.max_obj_addr)
2391      gcdata->fnlz_htable.has_client_ptrs = 1;
2392    }
2393   }
2394    else *odata = NULL;
2395   old_fn = 0;
2396  }
2397 return old_fn;
2398}
2399
2400GC_STATIC GC_finalization_proc GC_FASTCALL GC_fnlz_del_ready(
2401 struct GC_gcdata_s *gcdata, struct GC_objlink_s **pobjlink, void **odata)
2402{
2403 GC_REGISTER_KEYWORD struct GC_fnlz_s *fnlz;
2404 GC_finalization_proc fn = 0;
2405 if ((fnlz = gcdata->fnlz_htable.ready_fnlz) != NULL)
2406 {
2407  *pobjlink = fnlz->objlink;
2408  gcdata->fnlz_htable.ready_fnlz = fnlz->next;
2409  *odata = fnlz->client_data;
2410  fn = fnlz->fn;
2411  GC_CORE_FREE(fnlz);
2412 }
2413 return fn;
2414}
2415
2416#ifndef JAVA_FINALIZATION_NOT_NEEDED
2417
2418GC_INLINE_STATIC void GC_FASTCALL GC_fnlz_ready_all(
2419 struct GC_gcdata_s *gcdata)
2420{
2421 GC_REGISTER_KEYWORD GC_word addr =
2422  (GC_word)gcdata->fnlz_htable.hroots - sizeof(GC_word);
2423 GC_REGISTER_KEYWORD struct GC_fnlz_s *fnlz;
2424 struct GC_fnlz_s *ready_fnlz = gcdata->fnlz_htable.ready_fnlz;
2425 for (;;)
2426 {
2427  for (;;)
2428  {
2429   if (*(struct GC_fnlz_s **)(addr += sizeof(GC_word)) != &GC_nil_fnlz)
2430    break;
2431  }
2432  if ((GC_word)(fnlz = *(struct GC_fnlz_s **)addr) == ~(GC_word)0)
2433   break;
2434  while (fnlz->next != &GC_nil_fnlz)
2435   fnlz = fnlz->next;
2436  fnlz->next = ready_fnlz;
2437  ready_fnlz = *(struct GC_fnlz_s **)addr;
2438  *(CONST struct GC_fnlz_s **)addr = &GC_nil_fnlz;
2439 }
2440 gcdata->free_bytes += gcdata->fnlz_htable.count * sizeof(struct GC_fnlz_s);
2441 gcdata->fnlz_htable.ready_fnlz = ready_fnlz;
2442 gcdata->fnlz_htable.count = 0;
2443 gcdata->fnlz_htable.has_client_ptrs = 0;
2444}
2445
2446#endif /* ! JAVA_FINALIZATION_NOT_NEEDED */
2447
2448#endif /* ! GC_NO_FNLZ */
2449
2450GC_INLINE_STATIC void GC_FASTCALL GC_objlink_add(struct GC_gcdata_s *gcdata,
2451 void *obj, GC_word objsize, GC_word vtable)
2452{
2453 GC_REGISTER_KEYWORD struct GC_objlink_s *objlink;
2454 struct GC_objlink_s **pnext;
2455 struct GC_objlink_s *new_objlink;
2456 gcdata->obj_htable.unlinked_list =
2457  (new_objlink = gcdata->obj_htable.unlinked_list)->next;
2458 if (vtable)
2459 {
2460  GC_MEM_BZERO(obj, objsize);
2461  gcdata->followscan_size += objsize & ~(sizeof(GC_word) - 1);
2462#ifdef GC_GCJ_SUPPORT
2463#ifdef GC_IGNORE_GCJ_INFO
2464  if (vtable != ~(GC_word)0)
2465   *(GC_word *)obj = vtable;
2466  new_objlink->atomic_and_size = objsize;
2467#else
2468  new_objlink->atomic_and_size =
2469   vtable != ~(GC_word)0 && (*(GC_word *)obj = vtable,
2470#ifndef GC_GETENV_SKIP
2471   !gcdata->ignore_gcj_info &&
2472#endif
2473   *(GC_word *)(vtable + MARK_DESCR_OFFSET) != GC_DS_LENGTH) ?
2474   objsize | GC_HASDSLEN_MASK : objsize;
2475#endif
2476#else
2477  new_objlink->atomic_and_size = objsize;
2478#endif
2479 }
2480  else new_objlink->atomic_and_size = objsize | GC_ATOMIC_MASK;
2481 new_objlink->obj = obj;
2482 if ((GC_word)(objlink = *(pnext =
2483     &gcdata->obj_htable.hroots[(((((GC_word)obj) >>
2484     gcdata->obj_htable.log2_size) ^ (GC_word)obj) >> GC_LOG2_OFFIGNORE) &
2485     (((GC_word)1 << gcdata->obj_htable.log2_size) - 1)]))->obj >
2486     (GC_word)obj)
2487  for (;;)
2488  {
2489   if ((GC_word)(objlink = *(pnext = &objlink->next))->obj <= (GC_word)obj)
2490    break;
2491  }
2492 new_objlink->next = objlink;
2493 *pnext = new_objlink;
2494 if (gcdata->obj_htable.min_obj_addr >= (GC_word)obj)
2495  gcdata->obj_htable.min_obj_addr = (GC_word)obj;
2496 if ((GC_word)obj + ((GC_word)1 << GC_LOG2_OFFIGNORE) >
2497     gcdata->obj_htable.max_obj_addr)
2498  gcdata->obj_htable.max_obj_addr =
2499   (GC_word)obj + ((GC_word)1 << GC_LOG2_OFFIGNORE);
2500 gcdata->obj_htable.count++;
2501}
2502
2503GC_STATIC GC_word GC_FASTCALL GC_objlink_remove_all(
2504 struct GC_gcdata_s *gcdata)
2505{
2506 GC_REGISTER_KEYWORD GC_word addr =
2507  (GC_word)gcdata->obj_htable.hroots - sizeof(GC_word);
2508 GC_REGISTER_KEYWORD struct GC_objlink_s *objlink;
2509 GC_word removed_bytes = 0;
2510 GC_word count = 0;
2511 struct GC_objlink_s *free_list = gcdata->obj_htable.free_list;
2512 for (;;)
2513 {
2514  for (;;)
2515  {
2516   if (*(struct GC_objlink_s **)(addr += sizeof(GC_word)) != &GC_nil_objlink)
2517    break;
2518  }
2519  if ((GC_word)(objlink = *(struct GC_objlink_s **)addr) == ~(GC_word)0)
2520   break;
2521  removed_bytes += objlink->atomic_and_size;
2522  while (objlink->next != &GC_nil_objlink)
2523  {
2524   removed_bytes += (objlink = objlink->next)->atomic_and_size;
2525   count++;
2526  }
2527  objlink->next = free_list;
2528  count++;
2529  free_list = *(struct GC_objlink_s **)addr;
2530  *(CONST struct GC_objlink_s **)addr = &GC_nil_objlink;
2531 }
2532 gcdata->marked_bytes -= removed_bytes & ~(GC_ATOMIC_MASK | GC_HASDSLEN_MASK);
2533 gcdata->obj_htable.free_list = free_list;
2534 gcdata->obj_htable.count = 0;
2535 gcdata->obj_htable.min_obj_addr = ~(GC_word)0;
2536 gcdata->obj_htable.max_obj_addr = (GC_word)1 << GC_LOG2_OFFIGNORE;
2537 return count;
2538}
2539
2540#ifdef GC_NO_FNLZ
2541#ifdef GC_NO_GCBASE
2542GC_INLINE_STATIC
2543#else
2544GC_STATIC
2545#endif
2546#else
2547GC_STATIC
2548#endif
2549struct GC_objlink_s *GC_FASTCALL GC_objlink_get(struct GC_gcdata_s *gcdata,
2550 void *displaced_pointer)
2551{
2552 GC_REGISTER_KEYWORD struct GC_objlink_s *objlink;
2553 struct GC_objlink_s **hroots = gcdata->obj_htable.hroots;
2554 GC_word log2_size = gcdata->obj_htable.log2_size;
2555 objlink = hroots[(((((GC_word)displaced_pointer) >> log2_size) ^
2556            (GC_word)displaced_pointer) >> GC_LOG2_OFFIGNORE) &
2557            (((GC_word)1 << log2_size) - 1)];
2558 while ((GC_word)objlink->obj > (GC_word)displaced_pointer)
2559  objlink = objlink->next;
2560 if ((objlink->atomic_and_size & ~(GC_ATOMIC_MASK | GC_HASDSLEN_MASK)) <=
2561     (GC_word)displaced_pointer - (GC_word)objlink->obj)
2562 {
2563  objlink = hroots[(((((GC_word)displaced_pointer -
2564             (((GC_word)1 << GC_LOG2_OFFIGNORE) - (GC_word)1)) >>
2565             log2_size) ^ ((GC_word)displaced_pointer -
2566             (((GC_word)1 << GC_LOG2_OFFIGNORE) - (GC_word)1))) >>
2567             GC_LOG2_OFFIGNORE) & (((GC_word)1 << log2_size) - 1)];
2568  while ((GC_word)objlink->obj > (GC_word)displaced_pointer)
2569   objlink = objlink->next;
2570  if ((objlink->atomic_and_size & ~(GC_ATOMIC_MASK | GC_HASDSLEN_MASK)) <=
2571      (GC_word)displaced_pointer - (GC_word)objlink->obj)
2572   objlink = NULL;
2573 }
2574 return objlink;
2575}
2576
2577#ifdef GC_NO_FNLZ
2578#ifdef GC_NO_GCBASE
2579GC_INLINE_STATIC
2580#else
2581GC_STATIC
2582#endif
2583#else
2584GC_STATIC
2585#endif
2586struct GC_objlink_s *GC_FASTCALL GC_objlink_refill_find(
2587 struct GC_gcdata_s *gcdata, void *displaced_pointer)
2588{
2589 GC_REGISTER_KEYWORD struct GC_objlink_s *marked_list;
2590 GC_REGISTER_KEYWORD struct GC_objlink_s **pnext;
2591 struct GC_objlink_s *objlink;
2592 struct GC_objlink_s **hroots;
2593 GC_word min_obj_addr;
2594 GC_word max_obj_addr;
2595 GC_word log2_size;
2596 GC_word hmask;
2597 GC_word count;
2598 if ((void *)(marked_list = gcdata->obj_htable.follow_list) !=
2599     (void *)gcdata->obj_htable.marked_list)
2600 {
2601  hroots = gcdata->obj_htable.hroots;
2602  min_obj_addr = gcdata->obj_htable.min_obj_addr;
2603  max_obj_addr = gcdata->obj_htable.max_obj_addr -
2604                  ((GC_word)1 << GC_LOG2_OFFIGNORE);
2605  if (marked_list == NULL)
2606   marked_list = gcdata->obj_htable.marked_list;
2607  hmask = ((GC_word)1 << (log2_size = gcdata->obj_htable.log2_size)) - 1;
2608  count = 0;
2609  do
2610  {
2611   do
2612   {
2613    GC_REGISTER_KEYWORD GC_word addr = (GC_word)marked_list->obj;
2614    if (min_obj_addr >= addr)
2615     min_obj_addr = addr;
2616    if (max_obj_addr <= addr)
2617     max_obj_addr = addr;
2618    pnext = &hroots[(((addr >> log2_size) ^ addr) >>
2619             GC_LOG2_OFFIGNORE) & hmask];
2620    while ((GC_word)(objlink = *pnext)->obj > addr)
2621     pnext = &objlink->next;
2622    count++;
2623    if ((GC_word)displaced_pointer - addr <
2624        (marked_list->atomic_and_size & ~(GC_ATOMIC_MASK | GC_HASDSLEN_MASK)))
2625     break;
2626    marked_list = (*pnext = marked_list)->next;
2627    (*pnext)->next = objlink;
2628   } while (marked_list != NULL);
2629   if (marked_list != NULL)
2630    break;
2631   if (gcdata->obj_htable.follow_list == NULL)
2632   {
2633    gcdata->obj_htable.marked_list = NULL;
2634    break;
2635   }
2636   gcdata->obj_htable.follow_list = NULL;
2637  } while ((marked_list = gcdata->obj_htable.marked_list) != NULL);
2638  gcdata->obj_htable.min_obj_addr = min_obj_addr;
2639  gcdata->obj_htable.max_obj_addr =
2640   max_obj_addr + ((GC_word)1 << GC_LOG2_OFFIGNORE);
2641  gcdata->obj_htable.count += count;
2642  if (marked_list != NULL)
2643  {
2644   if (gcdata->obj_htable.follow_list != NULL)
2645    gcdata->obj_htable.follow_list = marked_list->next;
2646    else gcdata->obj_htable.marked_list = marked_list->next;
2647   *pnext = marked_list;
2648   marked_list->next = objlink;
2649  }
2650 }
2651 return marked_list;
2652}
2653
2654GC_STATIC GC_word GC_FASTCALL GC_objlink_some_refill(
2655 struct GC_gcdata_s *gcdata, GC_word max_count)
2656{
2657 GC_REGISTER_KEYWORD struct GC_objlink_s *marked_list;
2658 GC_REGISTER_KEYWORD struct GC_objlink_s **pnext;
2659 struct GC_objlink_s *objlink;
2660 struct GC_objlink_s **hroots;
2661 GC_word min_obj_addr;
2662 GC_word max_obj_addr;
2663 GC_word log2_size;
2664 GC_word hmask;
2665 GC_word count = 0;
2666 if ((void *)(marked_list = gcdata->obj_htable.follow_list) !=
2667     (void *)gcdata->obj_htable.marked_list)
2668 {
2669  hroots = gcdata->obj_htable.hroots;
2670  min_obj_addr = gcdata->obj_htable.min_obj_addr;
2671  max_obj_addr = gcdata->obj_htable.max_obj_addr -
2672                  ((GC_word)1 << GC_LOG2_OFFIGNORE);
2673  if (marked_list == NULL)
2674   marked_list = gcdata->obj_htable.marked_list;
2675  hmask = ((GC_word)1 << (log2_size = gcdata->obj_htable.log2_size)) - 1;
2676  count = max_count;
2677  do
2678  {
2679   GC_REGISTER_KEYWORD GC_word addr = (GC_word)marked_list->obj;
2680   if (min_obj_addr >= addr)
2681    min_obj_addr = addr;
2682   if (max_obj_addr <= addr)
2683    max_obj_addr = addr;
2684   if ((GC_word)(objlink = *(pnext = &hroots[(((addr >> log2_size) ^ addr) >>
2685       GC_LOG2_OFFIGNORE) & hmask]))->obj > addr)
2686    for (;;)
2687    {
2688     if ((GC_word)(objlink = *(pnext = &objlink->next))->obj <= addr)
2689      break;
2690    }
2691   marked_list = (*pnext = marked_list)->next;
2692   (*pnext)->next = objlink;
2693  } while (--count && marked_list != NULL);
2694  gcdata->obj_htable.min_obj_addr = min_obj_addr;
2695  count = max_count - count;
2696  gcdata->obj_htable.max_obj_addr =
2697   max_obj_addr + ((GC_word)1 << GC_LOG2_OFFIGNORE);
2698  gcdata->obj_htable.count += count;
2699  if (gcdata->obj_htable.follow_list != NULL)
2700   gcdata->obj_htable.follow_list = marked_list;
2701   else gcdata->obj_htable.marked_list = marked_list;
2702 }
2703 return count;
2704}
2705
2706GC_STATIC GC_word GC_FASTCALL GC_objlink_free_pending(
2707 struct GC_gcdata_s *gcdata, GC_word min_free_bytes)
2708{
2709 GC_REGISTER_KEYWORD struct GC_objlink_s *objlink;
2710#ifndef GC_NO_DLINKS
2711 GC_word max_hidden;
2712 GC_word min_hidden;
2713#endif
2714 GC_word objsize;
2715 GC_word totalsize = 0;
2716 GC_word count = 0;
2717 while ((objlink = gcdata->obj_htable.free_list) != NULL)
2718 {
2719  objsize = objlink->atomic_and_size;
2720#ifndef GC_NO_DLINKS
2721  if (gcdata->dlink_htable.count)
2722  {
2723   min_hidden = GC_HIDE_POINTER((char *)objlink->obj +
2724                 (objsize & ~(GC_ATOMIC_MASK | GC_HASDSLEN_MASK |
2725                 (sizeof(GC_word) - 1))) - (GC_word)sizeof(GC_word));
2726   if ((max_hidden = GC_HIDE_POINTER(objlink->obj)) >= min_hidden)
2727   {
2728    (void)GC_dlink_delete(gcdata, max_hidden, min_hidden, max_hidden);
2729    if (((min_hidden ^ max_hidden) &
2730        ~(((GC_word)1 << GC_LOG2_OFFIGNORE) - 1)) != 0)
2731     (void)GC_dlink_delete(gcdata, max_hidden -
2732      ((GC_word)1 << GC_LOG2_OFFIGNORE), min_hidden, max_hidden);
2733   }
2734  }
2735#endif
2736  gcdata->obj_htable.free_list = objlink->next;
2737  GC_CORE_FREE(objlink->obj);
2738  if ((objsize & GC_ATOMIC_MASK) == 0)
2739   gcdata->followscan_size -= objsize & ~(GC_HASDSLEN_MASK |
2740                               (sizeof(GC_word) - 1));
2741  objlink->obj = NULL;
2742  objlink->next = gcdata->obj_htable.unlinked_list;
2743  gcdata->obj_htable.unlinked_list = objlink;
2744  totalsize += objsize;
2745  count++;
2746  if ((gcdata->free_bytes +=
2747      objsize & ~(GC_ATOMIC_MASK | GC_HASDSLEN_MASK)) >= min_free_bytes)
2748   break;
2749 }
2750 gcdata->obj_htable.pending_free_size -=
2751  totalsize & ~(GC_ATOMIC_MASK | GC_HASDSLEN_MASK);
2752 return count;
2753}
2754
2755GC_STATIC void GC_FASTCALL GC_collect_unreachable(struct GC_gcdata_s *gcdata,
2756 GC_stop_func stop_func)
2757{
2758 GC_word oldcnt;
2759 GC_word obj_count;
2760 GC_start_callback_proc start_fn;
2761#ifndef GC_NO_FNLZ
2762 GC_word ready_count = 0;
2763#endif
2764 struct GC_objlink_s **new_hroots;
2765 int stopped;
2766#ifdef GC_PRINT_MSGS
2767#ifndef GC_NO_DLINKS
2768 GC_word dlinks_count = gcdata->dlink_htable.count;
2769#endif
2770 GC_CURTIME_T curt;
2771 unsigned long time_ms = 0;
2772#endif
2773 if (gcdata->dataroots != NULL)
2774 {
2775  if ((start_fn = GC_start_call_back) != 0)
2776   (*start_fn)();
2777#ifdef GC_PRINT_MSGS
2778  if (GC_verbose_gc)
2779  {
2780   fprintf(stdout,
2781    "[GC: #%lu Scan %lu KiB after %lu KiB allocd, %lu KiB free of %lu KiB]"
2782    GC_NEW_LINE, (unsigned long)(GC_gc_no + 1),
2783    GC_SIZE_TO_ULKB(GC_stack_approx_size(gcdata) + gcdata->dataroot_size +
2784    gcdata->followscan_size), GC_SIZE_TO_ULKB(gcdata->bytes_allocd),
2785    GC_SIZE_TO_ULKB(gcdata->free_bytes),
2786    GC_SIZE_TO_ULKB(gcdata->total_heapsize));
2787   time_ms = GC_CURTIME_GETMS(&curt);
2788  }
2789  obj_count = gcdata->obj_htable.count;
2790#endif
2791  if (!(*stop_func)())
2792  {
2793   stopped = 0;
2794   while (GC_objlink_some_refill(gcdata, GC_LAZYREFILL_BIGCNT))
2795    if ((stopped = (*stop_func)()) != 0)
2796     break;
2797   obj_count = gcdata->obj_htable.count;
2798   if (!stopped)
2799   {
2800#ifndef GC_NO_FNLZ
2801    oldcnt = GC_fnlz_precollect(gcdata, &ready_count);
2802#endif
2803    if (
2804#ifdef GC_NO_FNLZ
2805        obj_count
2806#else
2807        gcdata->obj_htable.count &&
2808        ((!oldcnt && !gcdata->fnlz_htable.count) ||
2809        (stopped = (*stop_func)()) == 0)
2810#endif
2811        )
2812    {
2813     GC_mutator_suspend(gcdata);
2814     GC_stack_scan_cur(gcdata);
2815     stopped = 1;
2816     if (GC_roots_scan(gcdata, stop_func) == NULL
2817#ifdef GC_THREADS
2818         && !GC_stkroot_scan_other(gcdata, stop_func)
2819#endif
2820         )
2821     {
2822      GC_scan_followable(gcdata, stop_func);
2823      if (gcdata->obj_htable.follow_list == NULL)
2824       stopped = 0;
2825     }
2826     GC_mutator_resume(gcdata);
2827#ifdef GC_NO_FNLZ
2828#ifndef GC_NO_DLINKS
2829     if (!stopped && gcdata->dlink_htable.count)
2830      GC_dlink_scan_clear(gcdata);
2831#endif
2832#else
2833     if (!stopped)
2834     {
2835#ifndef GC_NO_DLINKS
2836      if (gcdata->dlink_htable.count)
2837       GC_dlink_scan_clear(gcdata);
2838#endif
2839      if (gcdata->fnlz_htable.count)
2840       oldcnt += GC_fnlz_after_collect(gcdata, &ready_count);
2841      gcdata->bytes_finalized = oldcnt;
2842     }
2843#endif
2844    }
2845    if (!stopped)
2846    {
2847     GC_gc_no++;
2848#ifndef GC_NO_FNLZ
2849     GC_scan_followable(gcdata, GC_never_stop_func);
2850#endif
2851     oldcnt = obj_count;
2852     gcdata->marked_bytes += gcdata->bytes_allocd;
2853     if (gcdata->obj_htable.count)
2854     {
2855      gcdata->obj_htable.pending_free_size += gcdata->marked_bytes;
2856      obj_count -= GC_objlink_remove_all(gcdata);
2857      gcdata->obj_htable.pending_free_size -= gcdata->marked_bytes;
2858     }
2859     if ((oldcnt >> 1) < obj_count &&
2860         GC_HASH_RESIZECOND(oldcnt, gcdata->obj_htable.log2_size) &&
2861         (new_hroots = GC_alloc_hroots(gcdata,
2862         gcdata->obj_htable.log2_size + 1, &GC_nil_objlink)) != NULL)
2863     {
2864      GC_CORE_FREE(gcdata->obj_htable.hroots);
2865      gcdata->free_bytes += ((GC_word)sizeof(GC_word) <<
2866                             gcdata->obj_htable.log2_size) + sizeof(GC_word);
2867      gcdata->obj_htable.hroots = new_hroots;
2868      gcdata->obj_htable.log2_size++;
2869     }
2870     gcdata->allocd_before_gc += gcdata->bytes_allocd;
2871     gcdata->bytes_allocd = 0;
2872    }
2873   }
2874  }
2875  if (!gcdata->bytes_allocd)
2876  {
2877   gcdata->recycling = 1;
2878#ifdef GC_PRINT_MSGS
2879   if (GC_verbose_gc)
2880   {
2881    fprintf(stdout,
2882     "[GC: Done in %lu ms, %lu KiB used by %lu objs, %lu KiB used by GC]"
2883     GC_NEW_LINE, GC_CURTIME_GETMS(&curt) - time_ms,
2884     GC_SIZE_TO_ULKB(gcdata->marked_bytes), (unsigned long)obj_count,
2885     GC_SIZE_TO_ULKB(gcdata->total_heapsize - gcdata->marked_bytes -
2886     gcdata->free_bytes));
2887#ifndef GC_NO_DLINKS
2888    if (dlinks_count)
2889     fprintf(stdout,
2890      "[GC: %lu disappearing links cleared of %lu registered]" GC_NEW_LINE,
2891      (unsigned long)(dlinks_count - gcdata->dlink_htable.count),
2892      (unsigned long)dlinks_count);
2893#endif
2894#ifndef GC_NO_FNLZ
2895    if ((oldcnt = gcdata->fnlz_htable.count + ready_count) != 0)
2896     fprintf(stdout,
2897      "[GC: %lu finalizers ready of %lu registered]" GC_NEW_LINE,
2898      (unsigned long)ready_count, (unsigned long)oldcnt);
2899#endif
2900   }
2901#endif
2902  }
2903 }
2904}
2905
2906GC_STATIC void *GC_FASTCALL GC_inner_core_malloc(struct GC_gcdata_s *gcdata,
2907 GC_word size, int dont_expand)
2908{
2909 GC_word free_bytes;
2910 void *ptr = NULL;
2911 if (size <= (~(GC_ATOMIC_MASK | GC_HASDSLEN_MASK) < GC_MEM_SIZELIMIT ?
2912     ~(GC_ATOMIC_MASK | GC_HASDSLEN_MASK) : GC_MEM_SIZELIMIT) &&
2913     ((free_bytes = gcdata->free_bytes) > size || (!dont_expand &&
2914     gcdata->total_heapsize - (free_bytes - size) <= GC_max_heapsize)))
2915 {
2916  do
2917  {
2918   ptr = GC_CORE_MALLOC((size_t)size);
2919  } while ((GC_word)ptr > ~((GC_word)1 << GC_LOG2_OFFIGNORE) ||
2920           ((GC_word)ptr & (sizeof(GC_word) - 1)) != 0);
2921  if (ptr != NULL)
2922  {
2923   if (free_bytes < size)
2924   {
2925    gcdata->total_heapsize += size - free_bytes;
2926    gcdata->free_bytes = 0;
2927   }
2928    else gcdata->free_bytes = free_bytes - size;
2929  }
2930 }
2931 return ptr;
2932}
2933
2934GC_STATIC void *GC_FASTCALL GC_alloc_hroots(struct GC_gcdata_s *gcdata,
2935 GC_word new_log2_size, CONST void *nil_ptr)
2936{
2937 GC_REGISTER_KEYWORD GC_word size = (GC_word)sizeof(GC_word) << new_log2_size;
2938 void *ptr;
2939 if ((ptr = GC_inner_core_malloc(gcdata, size + sizeof(GC_word),
2940     GC_dont_expand)) != NULL || ((
2941#ifndef GC_NO_DLINKS
2942     GC_dlink_free_pending(gcdata, ~(GC_word)0) +
2943#endif
2944     GC_objlink_free_pending(gcdata, ~(GC_word)0) != 0 || GC_dont_expand) &&
2945     (ptr = GC_inner_core_malloc(gcdata, size + sizeof(GC_word), 0)) != NULL))
2946 {
2947  *(GC_word *)((char *)ptr + size) = ~(GC_word)0;
2948  if (nil_ptr != NULL)
2949  {
2950   while ((size -= sizeof(GC_word)) != 0)
2951    *(CONST void **)((char *)ptr + size) = nil_ptr;
2952   *(CONST void **)ptr = nil_ptr;
2953  }
2954   else GC_MEM_BZERO(ptr, size);
2955 }
2956 return ptr;
2957}
2958
2959GC_STATIC void *GC_FASTCALL GC_core_malloc_with_gc(struct GC_gcdata_s *gcdata,
2960 GC_word size, int *pres)
2961{
2962 GC_REGISTER_KEYWORD void *ptr;
2963#ifndef GC_NO_FNLZ
2964 struct GC_stkroot_s *cur_stack;
2965#endif
2966 GC_word count;
2967 if ((ptr = GC_inner_core_malloc(gcdata, size, GC_dont_expand)) == NULL)
2968 {
2969  if (*pres >= 0)
2970  {
2971   *pres = 0;
2972   if ((!GC_objlink_free_pending(gcdata, ~(GC_word)0) ||
2973       (ptr = GC_inner_core_malloc(gcdata, size, GC_dont_expand)) == NULL) &&
2974       !GC_dont_gc)
2975   {
2976    GC_collect_unreachable(gcdata, GC_never_stop_func);
2977    *pres = -1;
2978#ifndef GC_NO_FNLZ
2979    if ((cur_stack = gcdata->cur_stack) != NULL)
2980     cur_stack->inside_fnlz = 0;
2981#endif
2982   }
2983  }
2984  if (ptr == NULL && ((count = GC_objlink_free_pending(gcdata, size)) == 0 ||
2985      (ptr = GC_inner_core_malloc(gcdata, size, GC_dont_expand)) == NULL))
2986  {
2987#ifndef GC_NO_DLINKS
2988   if (GC_dlink_free_pending(gcdata, ~(GC_word)0))
2989   {
2990    *pres = 1;
2991    if ((ptr = GC_inner_core_malloc(gcdata, size, 0)) != NULL)
2992     *pres = 0;
2993   }
2994    else
2995#endif
2996    {
2997     if (!count || GC_dont_expand)
2998      ptr = GC_inner_core_malloc(gcdata, size, 0);
2999    }
3000#ifdef GC_PRINT_MSGS
3001   if (ptr == NULL && GC_verbose_gc)
3002    fprintf(stderr,
3003     " GC: Out of memory! Cannot allocate %lu bytes." GC_NEW_LINE,
3004     (unsigned long)size);
3005#endif
3006  }
3007 }
3008 return ptr;
3009}
3010
3011GC_STATIC int GC_FASTCALL GC_alloc_objlinks(struct GC_gcdata_s *gcdata,
3012 int *pres)
3013{
3014 GC_REGISTER_KEYWORD void *objlinks_block_list;
3015 GC_word count = (GC_word)1 << (gcdata->obj_htable.log2_size - 2);
3016 if ((objlinks_block_list = GC_core_malloc_with_gc(gcdata,
3017     count * sizeof(struct GC_objlink_s) + sizeof(GC_word), pres)) == NULL)
3018  return 0;
3019 *(void **)objlinks_block_list = gcdata->objlinks_block_list;
3020 gcdata->objlinks_block_list = objlinks_block_list;
3021 if (*pres >= 0)
3022  *pres = 0;
3023 ((struct GC_objlink_s *)(objlinks_block_list =
3024  (char *)objlinks_block_list + sizeof(GC_word)))->obj = NULL;
3025 ((struct GC_objlink_s *)objlinks_block_list)->next =
3026  gcdata->obj_htable.unlinked_list;
3027 while (--count)
3028 {
3029  ((struct GC_objlink_s *)((GC_word)objlinks_block_list +
3030   sizeof(struct GC_objlink_s)))->next = objlinks_block_list;
3031  ((struct GC_objlink_s *)(objlinks_block_list =
3032   (char *)objlinks_block_list + sizeof(struct GC_objlink_s)))->obj = NULL;
3033 }
3034 gcdata->obj_htable.unlinked_list = objlinks_block_list;
3035 return 1;
3036}
3037
3038GC_STATIC void *GC_FASTCALL GC_general_malloc(struct GC_gcdata_s **pgcdata,
3039 GC_word objsize, GC_word vtable)
3040{
3041 struct GC_gcdata_s *gcdata;
3042 void *obj = NULL;
3043 struct GC_objlink_s **new_hroots;
3044 GC_word retry;
3045 int res;
3046#ifndef GC_NO_FNLZ
3047 struct GC_objlink_s *objlink;
3048 void *client_data;
3049 GC_finalization_proc fn;
3050 GC_finalizer_notifier_proc notifier_fn;
3051#endif
3052 if (objsize)
3053 {
3054  retry = ~(GC_word)0;
3055#ifndef GC_NO_FNLZ
3056  objlink = NULL;
3057  client_data = NULL;
3058  fn = 0;
3059#endif
3060#ifndef DONT_ADD_BYTE_AT_END
3061  if (objsize < ((GC_word)1 << GC_LOG2_OFFIGNORE) && GC_all_interior_pointers)
3062   objsize++;
3063#endif
3064  do
3065  {
3066   res = 1;
3067   GC_enter(pgcdata);
3068   gcdata = *pgcdata;
3069   if (retry == ~(GC_word)0)
3070   {
3071    if (
3072#ifdef GC_NO_FNLZ
3073        GC_HASH_RESIZECOND(gcdata->obj_htable.count,
3074        gcdata->obj_htable.log2_size) &&
3075#else
3076        GC_HASH_RESIZECOND(gcdata->obj_htable.count,
3077        gcdata->obj_htable.log2_size +
3078        (GC_word)gcdata->cur_stack->inside_fnlz) &&
3079#endif
3080        gcdata->bytes_allocd)
3081    {
3082     if (GC_dont_gc || gcdata->dataroots == NULL)
3083     {
3084      if ((GC_dont_gc == GC_NEVER_COLLECT || gcdata->dataroots == NULL) &&
3085          (new_hroots = GC_alloc_hroots(gcdata,
3086          gcdata->obj_htable.log2_size + 1, &GC_nil_objlink)) != NULL)
3087      {
3088       (void)GC_objlink_free_pending(gcdata, ~(GC_word)0);
3089       gcdata->obj_htable.free_list = gcdata->obj_htable.marked_list;
3090       retry = gcdata->marked_bytes;
3091       (void)GC_objlink_remove_all(gcdata);
3092       gcdata->marked_bytes = retry;
3093       gcdata->obj_htable.marked_list = gcdata->obj_htable.free_list;
3094       retry = ~(GC_word)0;
3095       gcdata->obj_htable.free_list = NULL;
3096       GC_CORE_FREE(gcdata->obj_htable.hroots);
3097       gcdata->free_bytes += ((GC_word)sizeof(GC_word) <<
3098                              gcdata->obj_htable.log2_size) + sizeof(GC_word);
3099       gcdata->obj_htable.hroots = new_hroots;
3100       gcdata->obj_htable.log2_size++;
3101       res = -1;
3102      }
3103     }
3104      else
3105      {
3106       GC_collect_unreachable(gcdata, GC_default_stop_func);
3107       res = -1;
3108      }
3109    }
3110     else
3111     {
3112      if (!gcdata->recycling &&
3113#ifndef GC_NO_FNLZ
3114          !gcdata->cur_stack->inside_fnlz &&
3115#endif
3116          !GC_dont_gc)
3117      {
3118       if (GC_guess_collect(gcdata, objsize))
3119       {
3120        GC_collect_unreachable(gcdata, GC_default_stop_func);
3121        res = -1;
3122       }
3123        else retry = 0;
3124      }
3125      if (gcdata->bytes_allocd &&
3126          (retry = GC_guess_expand_size(gcdata, objsize)) != 0)
3127      {
3128       if (!GC_dont_expand &&
3129           gcdata->expanded_heapsize <= gcdata->total_heapsize)
3130        (void)GC_heap_expand(gcdata, retry);
3131       retry = 0;
3132      }
3133     }
3134   }
3135   if (gcdata->obj_htable.unlinked_list != NULL ||
3136       GC_alloc_objlinks(gcdata, &res))
3137    obj = GC_core_malloc_with_gc(gcdata, objsize, &res);
3138#ifndef GC_NO_FNLZ
3139   notifier_fn = 0;
3140   if (gcdata->fnlz_htable.ready_fnlz != NULL && GC_finalize_on_demand &&
3141       gcdata->notifier_gc_no != GC_gc_no)
3142   {
3143    gcdata->notifier_gc_no = GC_gc_no;
3144    notifier_fn = GC_finalizer_notifier;
3145   }
3146#endif
3147   if (obj != NULL)
3148   {
3149    gcdata->bytes_allocd += objsize;
3150    GC_objlink_add(gcdata, obj, objsize, vtable);
3151    if (!retry && gcdata->recycling && res > 0)
3152    {
3153     res = (int)GC_objlink_some_refill(gcdata, GC_LAZYREFILL_COUNT);
3154     if (gcdata->obj_htable.free_list != NULL &&
3155         (res += (int)GC_objlink_free_pending(gcdata, 0) << 1) > 1 &&
3156         (res > 2 || GC_objlink_free_pending(gcdata,
3157         gcdata->free_bytes + ((GC_word)1 << GC_LOG2_OFFIGNORE)) == 1))
3158      (void)GC_objlink_free_pending(gcdata, 0);
3159#ifndef GC_NO_FNLZ
3160     if (notifier_fn == 0 && !GC_dont_gc && !GC_finalize_on_demand &&
3161         ++gcdata->cur_stack->inside_fnlz == 1)
3162     {
3163      if ((fn = GC_fnlz_del_ready(gcdata, &objlink, &client_data)) != 0)
3164       res = 1;
3165       else gcdata->cur_stack->inside_fnlz = 0;
3166     }
3167#endif
3168     if (!res
3169#ifndef GC_NO_DLINKS
3170         && (gcdata->dlink_htable.free_list == NULL ||
3171         !GC_dlink_free_pending(gcdata,
3172         objsize / (sizeof(struct GC_dlink_s) - sizeof(GC_word)) + 1))
3173#endif
3174        )
3175     {
3176      gcdata->recycling = 0;
3177#ifdef GC_PRINT_MSGS
3178      if (GC_verbose_gc)
3179       fprintf(stdout,
3180        "[GC: Recycled, %lu + %lu /A/ KiB in use, %lu KiB free of %lu KiB]"
3181        GC_NEW_LINE, GC_SIZE_TO_ULKB(gcdata->followscan_size),
3182        GC_SIZE_TO_ULKB(gcdata->marked_bytes + gcdata->bytes_allocd -
3183        gcdata->followscan_size), GC_SIZE_TO_ULKB(gcdata->free_bytes),
3184        GC_SIZE_TO_ULKB(gcdata->total_heapsize));
3185#endif
3186     }
3187    }
3188   }
3189#ifndef GC_NO_FNLZ
3190    else
3191    {
3192     if (notifier_fn == 0 && !GC_finalize_on_demand)
3193      fn = GC_fnlz_del_ready(gcdata, &objlink, &client_data);
3194    }
3195#endif
3196   *pgcdata = NULL;
3197   GC_LEAVE(gcdata);
3198#ifdef GC_NO_FNLZ
3199   if (obj != NULL || res <= 0)
3200    break;
3201#else
3202   if (fn != 0)
3203   {
3204    (*fn)(objlink->obj, client_data);
3205    if (obj != NULL)
3206    {
3207     GC_enter(pgcdata);
3208     gcdata = *pgcdata;
3209     gcdata->cur_stack->inside_fnlz = 0;
3210     *pgcdata = NULL;
3211     GC_LEAVE(gcdata);
3212     break;
3213    }
3214    fn = 0;
3215    if (!GC_finalize_on_demand)
3216     for (;;)
3217     {
3218      GC_enter(pgcdata);
3219      gcdata = *pgcdata;
3220      (void)GC_objlink_some_refill(gcdata, GC_LAZYREFILL_BIGCNT);
3221      fn = GC_fnlz_del_ready(gcdata, &objlink, &client_data);
3222      *pgcdata = NULL;
3223      GC_LEAVE(gcdata);
3224      if (fn == 0)
3225       break;
3226      (*fn)(objlink->obj, client_data);
3227     }
3228   }
3229    else
3230    {
3231     if (notifier_fn != 0)
3232      (*notifier_fn)();
3233     if (obj != NULL || (notifier_fn == 0 && res <= 0))
3234      break;
3235    }
3236#endif
3237   if (retry == ~(GC_word)0)
3238    retry = 0;
3239  } while (++retry <= GC_max_retries);
3240 }
3241 return obj;
3242}
3243
3244GC_API void *GC_CALL GC_malloc(size_t size)
3245{
3246 struct GC_gcdata_s *gcdata;
3247 return GC_general_malloc(&gcdata, (GC_word)size, ~(GC_word)0);
3248}
3249
3250GC_API void *GC_CALL GC_malloc_atomic(size_t size)
3251{
3252 struct GC_gcdata_s *gcdata;
3253 return GC_general_malloc(&gcdata, (GC_word)size, 0);
3254}
3255
3256GC_API void GC_CALL GC_init(void)
3257{
3258 struct GC_gcdata_s *gcdata;
3259 GC_enter(&gcdata);
3260 GC_LEAVE(gcdata);
3261}
3262
3263GC_API void GC_CALL GC_set_finalizer_notifier(GC_finalizer_notifier_proc fn)
3264{
3265 struct GC_gcdata_s *gcdata;
3266 GC_enter(&gcdata);
3267 GC_finalizer_notifier = fn;
3268 GC_LEAVE(gcdata);
3269}
3270
3271GC_API void GC_CALL GC_set_start_callback(GC_start_callback_proc fn)
3272{
3273 struct GC_gcdata_s *gcdata;
3274 GC_enter(&gcdata);
3275 GC_start_call_back = fn;
3276 GC_LEAVE(gcdata);
3277}
3278
3279GC_API void GC_CALL GC_set_stop_func(GC_stop_func fn)
3280{
3281 struct GC_gcdata_s *gcdata;
3282 if (fn == 0)
3283  GC_abort_badptr(NULL);
3284 GC_enter(&gcdata);
3285 GC_default_stop_func = fn;
3286 GC_LEAVE(gcdata);
3287}
3288
3289GC_API void *GC_CALL GC_do_blocking(GC_fn_type fn, void *client_data)
3290{
3291#ifndef GC_NO_INACTIVE
3292 struct GC_gcdata_s *gcdata;
3293 GC_enter(&gcdata);
3294 if (!GC_set_inactive_sp(&gcdata))
3295  GC_abort_badptr(NULL);
3296 GC_LEAVE(gcdata);
3297#endif
3298 client_data = (*fn)(client_data);
3299#ifndef GC_NO_INACTIVE
3300 GC_enter(&gcdata);
3301 gcdata->cur_stack->inactive = 0;
3302 GC_LEAVE(gcdata);
3303#endif
3304 return client_data;
3305}
3306
3307GC_API void *GC_CALL GC_call_with_gc_active(GC_fn_type fn, void *client_data)
3308{
3309 struct GC_gcdata_s *gcdata;
3310#ifdef GC_NO_INACTIVE
3311 GC_enter(&gcdata);
3312 GC_LEAVE(gcdata);
3313 return (*fn)(client_data);
3314#else
3315 struct GC_activation_frame_s frame;
3316 GC_enter(&gcdata);
3317 if (!GC_set_activation_frame(&frame, gcdata->cur_stack))
3318 {
3319  GC_LEAVE(gcdata);
3320  return (*fn)(client_data);
3321 }
3322 GC_LEAVE(gcdata);
3323 client_data = (*fn)(client_data);
3324 GC_enter(&gcdata);
3325 GC_restore_inactive_sp(gcdata->cur_stack, &frame);
3326 GC_LEAVE(gcdata);
3327 return client_data;
3328#endif
3329}
3330
3331#ifdef GC_THREADS
3332
3333GC_API void GC_CALL GC_allow_register_threads(void)
3334{
3335 /* dummy */
3336}
3337
3338GC_API int GC_CALL GC_register_my_thread(CONST struct GC_stack_base *sb)
3339{
3340 struct GC_gcdata_s *gcdata;
3341 struct GC_stkroot_s *cur_stack;
3342 GC_word stack_addr;
3343 int res;
3344 res = GC_enter(&gcdata);
3345 if ((stack_addr = (GC_word)sb->mem_base) != 0)
3346 {
3347  if ((cur_stack = gcdata->cur_stack)->begin_addr > stack_addr)
3348   cur_stack->begin_addr = stack_addr;
3349  if (cur_stack->end_addr < stack_addr)
3350   cur_stack->end_addr = stack_addr;
3351 }
3352 GC_LEAVE(gcdata);
3353 return res;
3354}
3355
3356GC_API int GC_CALL GC_unregister_my_thread(void)
3357{
3358 struct GC_gcdata_s *gcdata;
3359 GC_enter(&gcdata);
3360 GC_stkroot_delete_cur(gcdata);
3361 GC_LEAVE(gcdata);
3362 return GC_SUCCESS;
3363}
3364
3365#endif /* GC_THREADS */
3366
3367GC_API void *GC_CALL GC_call_with_alloc_lock(GC_fn_type fn, void *client_data)
3368{
3369 struct GC_gcdata_s *gcdata;
3370 GC_enter(&gcdata);
3371 client_data = (*fn)(client_data);
3372 GC_LEAVE(gcdata);
3373 return client_data;
3374}
3375
3376#ifndef GC_MISC_EXCLUDE
3377
3378GC_API GC_finalizer_notifier_proc GC_CALL GC_get_finalizer_notifier(void)
3379{
3380 struct GC_gcdata_s *gcdata;
3381 GC_finalizer_notifier_proc fn;
3382 GC_enter(&gcdata);
3383 fn = GC_finalizer_notifier;
3384 GC_LEAVE(gcdata);
3385 return fn;
3386}
3387
3388GC_API GC_start_callback_proc GC_CALL GC_get_start_callback(void)
3389{
3390 struct GC_gcdata_s *gcdata;
3391 GC_start_callback_proc fn;
3392 GC_enter(&gcdata);
3393 fn = GC_start_call_back;
3394 GC_LEAVE(gcdata);
3395 return fn;
3396}
3397
3398GC_API GC_stop_func GC_CALL GC_get_stop_func(void)
3399{
3400 struct GC_gcdata_s *gcdata;
3401 GC_stop_func fn;
3402 GC_enter(&gcdata);
3403 fn = GC_default_stop_func;
3404 GC_LEAVE(gcdata);
3405 return fn;
3406}
3407
3408GC_API void GC_CALL GC_set_warn_proc(GC_warn_proc fn)
3409{
3410 struct GC_gcdata_s *gcdata;
3411 if (fn == 0)
3412  GC_abort_badptr(NULL);
3413 GC_enter(&gcdata);
3414 GC_current_warn_proc = fn;
3415 GC_LEAVE(gcdata);
3416}
3417
3418GC_API GC_warn_proc GC_CALL GC_get_warn_proc(void)
3419{
3420 struct GC_gcdata_s *gcdata;
3421 GC_warn_proc fn;
3422 GC_enter(&gcdata);
3423 fn = GC_current_warn_proc;
3424 GC_LEAVE(gcdata);
3425 return fn;
3426}
3427
3428GC_API void GC_CALL GC_enable_incremental(void)
3429{
3430 /* dummy */
3431 struct GC_gcdata_s *gcdata;
3432 GC_enter(&gcdata);
3433 GC_LEAVE(gcdata);
3434}
3435
3436GC_API int GC_CALL GC_expand_hp(size_t incsize)
3437{
3438 struct GC_gcdata_s *gcdata;
3439 int res;
3440 GC_enter(&gcdata);
3441 res = GC_heap_expand(gcdata, (GC_word)incsize);
3442 GC_LEAVE(gcdata);
3443 return res >= 0 ? 1 : 0;
3444}
3445
3446GC_API void GC_CALL GC_disable(void)
3447{
3448 struct GC_gcdata_s *gcdata;
3449 GC_enter(&gcdata);
3450 GC_dont_gc++;
3451 GC_LEAVE(gcdata);
3452}
3453
3454GC_API void GC_CALL GC_enable(void)
3455{
3456 struct GC_gcdata_s *gcdata;
3457 GC_enter(&gcdata);
3458 GC_dont_gc--;
3459 GC_LEAVE(gcdata);
3460}
3461
3462GC_API int GC_CALL GC_should_invoke_finalizers(void)
3463{
3464 int res = 0;
3465#ifndef GC_NO_FNLZ
3466 struct GC_gcdata_s *gcdata;
3467 GC_enter(&gcdata);
3468 if (gcdata->fnlz_htable.ready_fnlz != NULL)
3469  res = 1;
3470 GC_LEAVE(gcdata);
3471#endif
3472 return res;
3473}
3474
3475GC_API size_t GC_CALL GC_get_bytes_since_gc(void)
3476{
3477 struct GC_gcdata_s *gcdata;
3478 GC_word size;
3479 GC_enter(&gcdata);
3480 size = gcdata->bytes_allocd;
3481 GC_LEAVE(gcdata);
3482 return (size_t)size;
3483}
3484
3485GC_API size_t GC_CALL GC_get_total_bytes(void)
3486{
3487 struct GC_gcdata_s *gcdata;
3488 GC_word size;
3489 GC_enter(&gcdata);
3490 size = gcdata->allocd_before_gc + gcdata->bytes_allocd;
3491 GC_LEAVE(gcdata);
3492 return (size_t)size;
3493}
3494
3495GC_API void GC_CALL GC_remove_roots(void *low_addr, void *high_addr_plus_1)
3496{
3497 struct GC_gcdata_s *gcdata;
3498 if (low_addr != NULL)
3499 {
3500  low_addr = (void *)(((GC_word)low_addr + (sizeof(GC_word) - 1)) &
3501              ~(sizeof(GC_word) - 1));
3502  high_addr_plus_1 =
3503   (void *)((GC_word)high_addr_plus_1 & ~(sizeof(GC_word) - 1));
3504  GC_enter(&gcdata);
3505  if ((GC_word)low_addr < (GC_word)high_addr_plus_1)
3506   GC_roots_del_inside(gcdata, (GC_word)low_addr, (GC_word)high_addr_plus_1);
3507  GC_LEAVE(gcdata);
3508 }
3509}
3510
3511GC_API void GC_CALL GC_clear_roots(void)
3512{
3513 struct GC_gcdata_s *gcdata;
3514 GC_enter(&gcdata);
3515 GC_roots_del_inside(gcdata, sizeof(GC_word),
3516  ~(GC_word)(sizeof(GC_word) - 1));
3517 GC_LEAVE(gcdata);
3518}
3519
3520GC_API void GC_CALL GC_exclude_static_roots(void *low_addr,
3521 void *high_addr_plus_1)
3522{
3523 struct GC_gcdata_s *gcdata;
3524 if (low_addr != NULL)
3525 {
3526  low_addr = (void *)(((GC_word)low_addr + (sizeof(GC_word) - 1)) &
3527              ~(sizeof(GC_word) - 1));
3528  high_addr_plus_1 =
3529   (void *)((GC_word)high_addr_plus_1 & ~(sizeof(GC_word) - 1));
3530  GC_enter(&gcdata);
3531  if ((GC_word)low_addr < (GC_word)high_addr_plus_1)
3532  {
3533   GC_roots_del_inside(gcdata, (GC_word)low_addr, (GC_word)high_addr_plus_1);
3534   (void)GC_roots_exclude(gcdata, (GC_word)low_addr,
3535    (GC_word)high_addr_plus_1);
3536  }
3537  GC_LEAVE(gcdata);
3538 }
3539}
3540
3541#endif /* ! GC_MISC_EXCLUDE */
3542
3543GC_API void GC_CALL GC_add_roots(void *low_addr, void *high_addr_plus_1)
3544{
3545 struct GC_gcdata_s *gcdata;
3546 GC_enter(&gcdata);
3547 (void)GC_roots_add(gcdata, (GC_word)low_addr, (GC_word)high_addr_plus_1);
3548 GC_LEAVE(gcdata);
3549}
3550
3551GC_API size_t GC_CALL GC_get_heap_size(void)
3552{
3553 struct GC_gcdata_s *gcdata;
3554 GC_word size;
3555 GC_enter(&gcdata);
3556 size = gcdata->marked_bytes + gcdata->bytes_allocd +
3557#ifndef GC_NO_DLINKS
3558         gcdata->dlink_htable.count * sizeof(struct GC_dlink_s) +
3559#endif
3560#ifndef GC_NO_FNLZ
3561         gcdata->fnlz_htable.count * sizeof(struct GC_fnlz_s) +
3562#endif
3563         gcdata->obj_htable.pending_free_size + gcdata->free_bytes;
3564 GC_LEAVE(gcdata);
3565 return (size_t)size;
3566}
3567
3568GC_API size_t GC_CALL GC_get_free_bytes(void)
3569{
3570 struct GC_gcdata_s *gcdata;
3571 GC_word size;
3572 GC_enter(&gcdata);
3573 size = gcdata->free_bytes;
3574 GC_LEAVE(gcdata);
3575 return (size_t)size;
3576}
3577
3578GC_API int GC_CALL GC_try_to_collect(GC_stop_func stop_func)
3579{
3580 struct GC_gcdata_s *gcdata;
3581 int res = 1;
3582#ifndef GC_NO_FNLZ
3583 GC_finalizer_notifier_proc notifier_fn = 0;
3584#endif
3585 if (stop_func == 0)
3586  GC_abort_badptr(NULL);
3587 GC_enter(&gcdata);
3588 if (!GC_dont_gc && gcdata->bytes_allocd)
3589 {
3590  GC_collect_unreachable(gcdata, stop_func);
3591  res = 0;
3592  if (!gcdata->bytes_allocd)
3593  {
3594   res = 1;
3595#ifndef GC_NO_FNLZ
3596   gcdata->cur_stack->inside_fnlz = 0;
3597   if (gcdata->fnlz_htable.ready_fnlz != NULL && GC_finalize_on_demand)
3598   {
3599    gcdata->notifier_gc_no = GC_gc_no;
3600    notifier_fn = GC_finalizer_notifier;
3601   }
3602#endif
3603  }
3604 }
3605 GC_LEAVE(gcdata);
3606#ifndef GC_NO_FNLZ
3607 if (notifier_fn != 0)
3608  (*notifier_fn)();
3609#endif
3610 return res;
3611}
3612
3613GC_API void GC_CALL GC_gcollect_and_unmap(void)
3614{
3615 (void)GC_try_to_collect(GC_never_stop_func);
3616}
3617
3618GC_API void GC_CALL GC_gcollect(void)
3619{
3620 struct GC_gcdata_s *gcdata;
3621#ifndef GC_NO_FNLZ
3622 GC_finalizer_notifier_proc notifier_fn = 0;
3623#endif
3624 GC_enter(&gcdata);
3625 if (!GC_dont_gc && gcdata->bytes_allocd)
3626 {
3627  GC_collect_unreachable(gcdata, GC_default_stop_func);
3628#ifndef GC_NO_FNLZ
3629  if (!gcdata->bytes_allocd)
3630  {
3631   gcdata->cur_stack->inside_fnlz = 0;
3632   if (gcdata->fnlz_htable.ready_fnlz != NULL && GC_finalize_on_demand)
3633   {
3634    gcdata->notifier_gc_no = GC_gc_no;
3635    notifier_fn = GC_finalizer_notifier;
3636   }
3637  }
3638#endif
3639 }
3640 GC_LEAVE(gcdata);
3641#ifndef GC_NO_FNLZ
3642 if (notifier_fn != 0)
3643  (*notifier_fn)();
3644#endif
3645}
3646
3647GC_API void *GC_CALL GC_base(void *displaced_pointer)
3648{
3649#ifdef GC_NO_GCBASE
3650 if (displaced_pointer != NULL)
3651  GC_abort_badptr(displaced_pointer);
3652#else
3653 struct GC_gcdata_s *gcdata;
3654 struct GC_objlink_s *objlink;
3655 if (displaced_pointer != NULL)
3656 {
3657  GC_enter(&gcdata);
3658  displaced_pointer =
3659   (objlink = GC_objlink_get(gcdata, displaced_pointer)) != NULL ||
3660   (objlink = GC_objlink_refill_find(gcdata, displaced_pointer)) != NULL ?
3661   objlink->obj : NULL;
3662  GC_LEAVE(gcdata);
3663 }
3664#endif
3665 return displaced_pointer;
3666}
3667
3668GC_API int GC_CALL GC_general_register_disappearing_link(void **link,
3669 void *obj)
3670{
3671#ifndef GC_NO_REGISTER_DLINK
3672 struct GC_gcdata_s *gcdata;
3673 struct GC_objlink_s *objlink;
3674#ifdef GC_NO_DLINKS
3675 GC_word objsize;
3676#else
3677 struct GC_dlink_s **new_hroots;
3678 struct GC_dlink_s *new_dlink;
3679 GC_word new_log2_size;
3680#endif
3681#endif
3682 int res = 0;
3683 if (((GC_word)link & (sizeof(GC_word) - 1)) != 0 || link == NULL)
3684  GC_abort_badptr(link);
3685#ifndef GC_NO_REGISTER_DLINK
3686 GC_enter(&gcdata);
3687 if (obj != NULL)
3688 {
3689#ifdef GC_NO_DLINKS
3690  if ((objlink = GC_objlink_get(gcdata, (void *)link)) != NULL ||
3691      (objlink = GC_objlink_refill_find(gcdata, (void *)link)) != NULL)
3692  {
3693   obj = NULL;
3694   if (((objsize = objlink->atomic_and_size) & GC_ATOMIC_MASK) != 0)
3695   {
3696    gcdata->followscan_size += objsize & ~(GC_ATOMIC_MASK |
3697                                (sizeof(GC_word) - 1));
3698#ifndef GC_GCJ_SUPPORT
3699    objlink->atomic_and_size = objsize & ~GC_ATOMIC_MASK;
3700#endif
3701   }
3702#ifdef GC_GCJ_SUPPORT
3703   objlink->atomic_and_size = objsize & ~(GC_ATOMIC_MASK | GC_HASDSLEN_MASK);
3704#endif
3705  }
3706#else
3707  if ((objlink = GC_objlink_get(gcdata, obj)) != NULL ||
3708      (objlink = GC_objlink_refill_find(gcdata, obj)) != NULL)
3709  {
3710   if (objlink->obj == obj)
3711   {
3712    res = GC_dlink_add(gcdata, GC_HIDE_POINTER(link), objlink,
3713           (new_dlink = gcdata->dlink_htable.free_list) != NULL &&
3714           gcdata->free_bytes >= sizeof(struct GC_dlink_s) ? new_dlink :
3715           ((GC_HASH_RESIZECOND(gcdata->dlink_htable.count,
3716           gcdata->dlink_htable.log2_size) &&
3717           (new_hroots = GC_alloc_hroots(gcdata, new_log2_size =
3718           gcdata->dlink_htable.log2_size + 1, &GC_nil_dlink)) != NULL ?
3719           (GC_dlink_tblresize(gcdata, new_hroots, new_log2_size), 0) : 0),
3720           GC_core_malloc_with_gc(gcdata, sizeof(struct GC_dlink_s), &res)));
3721    obj = NULL;
3722   }
3723  }
3724   else obj = NULL;
3725#endif
3726 }
3727 GC_LEAVE(gcdata);
3728#endif
3729 if (obj != NULL)
3730  GC_abort_badptr(obj);
3731 return res;
3732}
3733
3734#ifndef GC_MISC_EXCLUDE
3735
3736GC_API int GC_CALL GC_unregister_disappearing_link(void **link)
3737{
3738#ifndef GC_NO_DLINKS
3739 struct GC_gcdata_s *gcdata;
3740 GC_word hidden_link;
3741#endif
3742 int res = 0;
3743#ifdef GC_NO_DLINKS
3744 GC_noop1((GC_word)link);
3745#else
3746 GC_enter(&gcdata);
3747 if (gcdata->dlink_htable.count && (hidden_link = GC_HIDE_POINTER(link)) != 0)
3748  res = GC_dlink_delete(gcdata, hidden_link, hidden_link, hidden_link);
3749 GC_LEAVE(gcdata);
3750#endif
3751 return res;
3752}
3753
3754#endif /* ! GC_MISC_EXCLUDE */
3755
3756GC_API void GC_CALL GC_register_finalizer_no_order(void *obj,
3757 GC_finalization_proc fn, void *client_data, GC_finalization_proc *ofn,
3758 void **odata)
3759{
3760#ifdef GC_NO_FNLZ
3761 if (obj != NULL && fn != 0)
3762  GC_noop1((GC_word)client_data);
3763 if (ofn != NULL)
3764  *ofn = 0;
3765 if (odata != NULL)
3766  *odata = NULL;
3767#else
3768 struct GC_gcdata_s *gcdata;
3769 struct GC_objlink_s *objlink;
3770 struct GC_fnlz_s **new_hroots;
3771 void *old_data;
3772 GC_word new_log2_size;
3773 int res = 0;
3774 if (odata == NULL)
3775  odata = &old_data;
3776 GC_enter(&gcdata);
3777 if (obj != NULL && ((objlink = GC_objlink_get(gcdata, obj)) != NULL ||
3778     (objlink = GC_objlink_refill_find(gcdata, obj)) != NULL))
3779 {
3780  if (objlink->obj == obj)
3781  {
3782   if (fn != 0)
3783   {
3784    if (GC_HASH_RESIZECOND(gcdata->fnlz_htable.count,
3785        gcdata->fnlz_htable.log2_size) &&
3786        (new_hroots = GC_alloc_hroots(gcdata, new_log2_size =
3787        gcdata->fnlz_htable.log2_size + 1, &GC_nil_fnlz)) != NULL)
3788     GC_fnlz_tblresize(gcdata, new_hroots, new_log2_size);
3789    if (gcdata->fnlz_htable.single_free == NULL)
3790     res = (gcdata->fnlz_htable.single_free = GC_core_malloc_with_gc(gcdata,
3791            sizeof(struct GC_fnlz_s), &res)) != NULL ? 1 : -1;
3792   }
3793   obj = NULL;
3794   if ((fn = GC_fnlz_add_del(gcdata, objlink, fn, client_data, odata)) != 0)
3795   {
3796    if (ofn != NULL)
3797     *ofn = fn;
3798    fn = 0;
3799   }
3800    else
3801    {
3802     if ((res >> 1) == 0)
3803     {
3804      if (ofn != NULL)
3805       *ofn = 0;
3806      if (res > 0 && !GC_finalize_on_demand &&
3807          ++gcdata->cur_stack->inside_fnlz == 1 &&
3808          (fn = GC_fnlz_del_ready(gcdata, &objlink, &client_data)) == 0)
3809       gcdata->cur_stack->inside_fnlz = 0;
3810     }
3811    }
3812  }
3813 }
3814  else
3815  {
3816   obj = NULL;
3817   if (ofn != NULL)
3818    *ofn = 0;
3819   fn = 0;
3820   *odata = NULL;
3821   objlink = NULL;
3822  }
3823 GC_LEAVE(gcdata);
3824 if (obj != NULL)
3825  GC_abort_badptr(obj);
3826 if (fn != 0)
3827 {
3828  (*fn)(objlink->obj, client_data);
3829  GC_enter(&gcdata);
3830  gcdata->cur_stack->inside_fnlz = 0;
3831  GC_LEAVE(gcdata);
3832 }
3833#endif
3834}
3835
3836GC_API int GC_CALL GC_invoke_finalizers(void)
3837{
3838 GC_word count = 0;
3839#ifndef GC_NO_FNLZ
3840 struct GC_gcdata_s *gcdata;
3841 struct GC_objlink_s *objlink = NULL;
3842 void *client_data = NULL;
3843 GC_finalization_proc fn;
3844 for (;;)
3845 {
3846  GC_enter(&gcdata);
3847  if ((fn = GC_fnlz_del_ready(gcdata, &objlink, &client_data)) != 0)
3848  {
3849   if (!count)
3850    gcdata->cur_stack->inside_fnlz++;
3851  }
3852   else
3853   {
3854    if (count)
3855     gcdata->cur_stack->inside_fnlz = 0;
3856   }
3857  GC_LEAVE(gcdata);
3858  if (fn == 0)
3859   break;
3860  count++;
3861  (*fn)(objlink->obj, client_data);
3862 }
3863#endif
3864 return (int)count;
3865}
3866
3867#ifdef GC_GCJ_SUPPORT
3868
3869GC_API void GC_CALL GC_init_gcj_malloc(int mp_index, void *mp)
3870{
3871 /* dummy */
3872 struct GC_gcdata_s *gcdata;
3873 if (mp != 0)
3874  GC_noop1((GC_word)mp_index);
3875 GC_enter(&gcdata);
3876 GC_LEAVE(gcdata);
3877}
3878
3879GC_API void *GC_CALL GC_gcj_malloc(size_t size, void *vtable)
3880{
3881 struct GC_gcdata_s *gcdata;
3882 if ((*(GC_word *)((char *)vtable + MARK_DESCR_OFFSET) & GC_DS_TAGS) !=
3883     GC_DS_LENGTH || size < sizeof(GC_word))
3884  GC_abort_badptr(vtable);
3885 return GC_general_malloc(&gcdata, (GC_word)size, (GC_word)vtable);
3886}
3887
3888#endif /* GC_GCJ_SUPPORT */
3889
3890#ifndef JAVA_FINALIZATION_NOT_NEEDED
3891
3892GC_API void GC_CALL GC_finalize_all(void)
3893{
3894#ifndef GC_NO_FNLZ
3895 struct GC_gcdata_s *gcdata;
3896 struct GC_objlink_s *objlink = NULL;
3897 void *client_data = NULL;
3898 GC_word count = 0;
3899 GC_finalization_proc fn;
3900 for (;;)
3901 {
3902  GC_enter(&gcdata);
3903  if (!count && gcdata->fnlz_htable.count)
3904   GC_fnlz_ready_all(gcdata);
3905  if ((fn = GC_fnlz_del_ready(gcdata, &objlink, &client_data)) != 0)
3906  {
3907   if (!count)
3908    gcdata->cur_stack->inside_fnlz++;
3909  }
3910   else
3911   {
3912    if (count)
3913     gcdata->cur_stack->inside_fnlz = 0;
3914   }
3915  GC_LEAVE(gcdata);
3916  if (fn != 0)
3917  {
3918   count++;
3919   (*fn)(objlink->obj, client_data);
3920  }
3921   else
3922   {
3923    if (!count)
3924     break;
3925    count = 0;
3926   }
3927 }
3928#endif
3929}
3930
3931#endif /* ! JAVA_FINALIZATION_NOT_NEEDED */
Note: See TracBrowser for help on using the repository browser.