1 //////////////////////////////////////////////////////////////////////////////
4 // ADLib, Prop and their related set of tools and documentation are in the
5 // public domain. The author(s) of this software reserve no copyrights on
6 // the source code and any code generated using the tools. You are encouraged
7 // to use ADLib and Prop to develop software, in both academic and commercial
8 // settings, and are welcomed to incorporate any part of ADLib and Prop into
11 // Although you are under no obligation to do so, we strongly recommend that
12 // you give away all software developed using our tools.
14 // We also ask that credit be given to us when ADLib and/or Prop are used in
15 // your programs, and that this notice be preserved intact in all the source
18 // This software is still under development and we welcome(read crave for)
19 // any suggestions and help from the users.
21 // Allen Leung (leunga@cs.nyu.edu)
23 //////////////////////////////////////////////////////////////////////////////
32 #include <sys/types.h>
33 #include <AD/gc/gcconfig.h> // system configuration
34 #include <AD/gc/cgc.h> // Conservative garbage collector
35 #include <AD/gc/gcobject.h> // garbage collectable objects
36 #include <AD/gc/gcheaps.h> // the heap manager
37 #include <AD/gc/gcmacros.h> // useful macros
38 #include <AD/gc/weakptr.h> // weak pointers
40 # include <sys/time.h>
41 # include <sys/resource.h>
42 # include <AD/gc/gctimer.h>
45 //////////////////////////////////////////////////////////////////////////////
46 // Some identifying information.
47 //////////////////////////////////////////////////////////////////////////////
48 // #define DEBUG_GC // no debugging for production use
49 #define SANITY_CHECK // inexpensive checking (left in place for your assurance)
54 //////////////////////////////////////////////////////////////////////////////
56 //////////////////////////////////////////////////////////////////////////////
57 typedef HM::GCPageId GCPageId
;
58 typedef HM::PageStatus PageStatus
;
60 //////////////////////////////////////////////////////////////////////////////
61 // Method to locate the bottom of the stack.
62 // We'll take care of both upward growing and downward growing stacks.
63 //////////////////////////////////////////////////////////////////////////////
64 static void ** compute_stack_bottom(void ** stack_mark1
, Bool
& downward_stack
)
65 { void * stack_mark2
[1];
66 size_t stack_alignment
= 0x1000000;
67 if (stack_mark1
< stack_mark2
) {
68 // case a: stack grows upward.
69 // We'll truncate the address downward.
70 downward_stack
= false;
71 return (void**)((size_t)stack_mark1
& (stack_alignment
-1));
73 // case b: stack grows downward.
74 // We'll round the address upward.
75 downward_stack
= true;
76 return (void**)(((size_t)stack_mark1
+ stack_alignment
- 1)
77 & ~(stack_alignment
-1));
81 //////////////////////////////////////////////////////////////////////////////
82 // Method to locate the top of the heap
83 //////////////////////////////////////////////////////////////////////////////
84 void CGC::get_heap_top()
85 { // This heap top is tentative.
86 // On Linux sometimes this points to addresses that hasn't been
88 heap_top
= (void**)GC_GET_HEAP_TOP
;
90 // Try read from the end of this address.
91 // If a seg fault occurs, we know it is not the real thing.
92 // We'll adjust the heap top stuff in that case.
93 // If we don't have to adjust then this is does nothing.
97 //////////////////////////////////////////////////////////////////////////////
99 // Method to verify the heap top
101 //////////////////////////////////////////////////////////////////////////////
102 void CGC::verify_heap_top()
103 { void ** try_addr
= (void **)((char*)GC_TRUNC_ADDR(heap_top
) - GC_ALIGNMENT
);
104 if (is_debugging() && console
)
105 { (*console
) << "[ GC" << id
106 << ": checking heap top address " << (void*)try_addr
110 void * dummy_unused_variable
= *try_addr
; // may trap here
112 if (is_debugging() && console
)
113 { (*console
) << "[ GC" << id
114 << ": heap top address " << (void*)try_addr
115 << " is ok ]\n" << flush
;
120 //////////////////////////////////////////////////////////////////////////////
121 // Method to flush the register windows on the sparc
122 //////////////////////////////////////////////////////////////////////////////
125 asm (" .seg \"text\"");
126 asm (" .globl _flush_sparc_register_windows");
127 asm ("_flush_sparc_register_windows:");
129 asm (" mov %sp, %o0");
131 asm (" nop"); // delay slot
132 extern "C" void * flush_sparc_register_windows();
135 void CGC::flush_registers()
139 flush_sparc_register_windows();
144 //////////////////////////////////////////////////////////////////////////////
146 // Get the bottom heap address
148 //////////////////////////////////////////////////////////////////////////////
149 void * CGC::global_heap_bottom
= 0;
150 void * CGC::get_heap_bottom()
151 { if (global_heap_bottom
!= 0) return global_heap_bottom
;
152 global_heap_bottom
= (void*)GC_GET_HEAP_BOTTOM
;
153 void * static_data_end
= (void*)GC_DATA_END
;
155 get_address_limit(global_heap_bottom
, static_data_end
, -1);
156 return global_heap_bottom
;
159 //////////////////////////////////////////////////////////////////////////////
161 // Retrieve the limit address
163 //////////////////////////////////////////////////////////////////////////////
164 static volatile Bool segfault
;
165 static void segfault_handler(int) { segfault
= true; }
166 void * CGC::get_address_limit(void * start
, void * limit
, int dir
)
170 (*console
) << "[ CGC::get_address_limit(" << start
<< ", " << limit
173 typedef void (*signal_handler
)(int);
174 signal_handler old_handler
= signal(SIGSEGV
, segfault_handler
);
179 for (addr
= start
; addr
< limit
; addr
= ((long *)addr
) + dir
)
180 { dummy
+= *(long *)addr
;
185 for (addr
= start
; addr
> limit
; addr
= ((long *)addr
) + dir
)
186 { dummy
+= *(long *)addr
;
190 addr
= ((long*)addr
) - dir
;
191 signal(SIGSEGV
, old_handler
);
194 { (*console
) << "[ CGC::get_address_limit(" << start
<< ", " << limit
195 << ") = " << addr
<< "]\n";
201 //////////////////////////////////////////////////////////////////////////////
203 //////////////////////////////////////////////////////////////////////////////
207 // Determine the boundaries of the stack, heap, and static area.
209 void * stack_mark1
[1];
210 stack_bottom
= compute_stack_bottom(stack_mark1
, is_downward_stack
);
211 stack_top
= stack_bottom
;
212 data_bottom
= (void**)GC_DATA_START
;
213 data_top
= (void**)GC_DATA_END
;
214 heap_bottom
= (void**)get_heap_bottom();
215 heap_top
= heap_bottom
;
217 // Set the initial heap size and heap growth.
218 // Be conservative and let the subclass override them if necessary
219 initial_heap_size
= 128 * 1024;
220 min_heap_growth
= 256 * 1024;
222 // Initialize the scanning queue
224 scan_limit_queue
= 0;
226 number_of_pages_to_scan
= 0;
228 initialization_message();
231 //////////////////////////////////////////////////////////////////////////////
233 //////////////////////////////////////////////////////////////////////////////
236 delete [] scan_queue
;
240 //////////////////////////////////////////////////////////////////////////////
241 // Methods for setting the initial heap size and amount of heap growth
242 //////////////////////////////////////////////////////////////////////////////
243 void CGC::set_initial_heap_size (size_t n
) { initial_heap_size
= n
; }
244 void CGC::set_min_heap_growth (size_t n
) { min_heap_growth
= n
; }
246 //////////////////////////////////////////////////////////////////////////////
247 // Method that returns the size of an allocated block
248 //////////////////////////////////////////////////////////////////////////////
249 size_t CGC::size(const void * obj
) const
250 { if (HM::is_mapped((void*)obj
) &&
251 HM::get_object_map().is_marked((void*)obj
)) {
252 return GC_OBJ_HEADER_LEN(GC_OBJ_HEADER(obj
));
258 //////////////////////////////////////////////////////////////////////////////
259 // Method for growing the scan queue
260 //////////////////////////////////////////////////////////////////////////////
261 void CGC::grow_scan_queue(size_t pages
)
262 { if (scan_queue_size
< pages
) {
263 delete [] scan_queue
;
264 scan_queue
= new size_t [2 * pages
];
265 scan_limit_queue
= scan_queue
+ pages
;
266 scan_queue_size
= pages
;
270 //////////////////////////////////////////////////////////////////////////////
271 // Method for printing an initialization message
272 //////////////////////////////////////////////////////////////////////////////
273 void CGC::initialization_message() const
275 if (is_debugging() && console
)
276 (*console
) << "[ GC" << id
277 << ": initializing (page size = " << GC_PAGE_SIZE
278 << ", alignment = " << GC_ALIGNMENT
<< ") ]\n" << flush
;
281 //////////////////////////////////////////////////////////////////////////////
282 // Method for printing a cleanup message
283 //////////////////////////////////////////////////////////////////////////////
284 void CGC::cleanup_message() const
286 if (is_debugging() && console
)
287 (*console
) << "[ GC" << id
<< ": cleaning up. ]\n" << flush
;
290 //////////////////////////////////////////////////////////////////////////////
291 // Method for printing a scanning message.
292 //////////////////////////////////////////////////////////////////////////////
293 void CGC::scanning_message(const char * area
, void * start
, void * stop
) const
295 if (is_debugging() && console
) {
296 (*console
) << "[ GC" << id
<< ": scanning the " << area
297 << " (" << start
<< " ... " << stop
<< ") "
298 << ((Byte
*)stop
- (Byte
*)start
) << " bytes ]\n" << flush
;
302 //////////////////////////////////////////////////////////////////////////////
303 // Method for performing weak pointer collection
304 //////////////////////////////////////////////////////////////////////////////
305 void CGC::do_weak_pointer_collection()
306 { if (! should_collect_weak_pointers
) return;
307 int size
= WeakPointerManager::size();
308 int capacity
= WeakPointerManager::capacity();
309 if (size
== 0) return;
310 if ((verbosity_level
& gc_notify_weak_pointer_collection
) && console
) {
311 (*console
) << "[ GC" << id
<< ": weakpointer collection ("
312 << size
<< "/" << capacity
<< ") ..." << flush
;
314 WeakPointerManager::scavenge_wp_table(this);
315 int new_size
= WeakPointerManager::size();
316 int new_capacity
= WeakPointerManager::capacity();
317 if ((verbosity_level
& gc_notify_weak_pointer_collection
) && console
) {
318 (*console
) << " done (" << new_size
<< "/" << new_capacity