aboutsummaryrefslogtreecommitdiffstats
path: root/gc/nursery.c
blob: 8bbb1015855364a0e3f07e5a153ca9750afd82c5 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
/* 
 * Copyright (c) 1999 by Silicon Graphics.  All rights reserved.
 *
 * THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED
 * OR IMPLIED.  ANY USE IS AT YOUR OWN RISK.
 *
 * Permission is hereby granted to use or copy this program
 * for any purpose,  provided the above notices are retained on all copies.
 * Permission to modify the code and to distribute modified code is granted,
 * provided the above notices are retained, and a notice that the code was
 * modified is included with the above copyright notice.
 */


??? This implementation is incomplete.  If you are trying to
??? compile this you are doing something wrong.

#include "nursery.h"

struct copy_obj {
    ptr_t forward;	/* Forwarding link for copied objects.	*/
    GC_copy_descriptor descr; /* Object descriptor	*/
    word data[1];
}

ptr_t GC_nursery_start;	/* Start of nursery area.	*/
			/* Must be NURSERY_BLOCK_SIZE	*/
			/* aligned.			*/
ptr_t GC_nursery_end;	/* End of nursery area.		*/
unsigned char * GC_nursery_map;
			/* GC_nursery_map[i] != 0 if an object	*/
			/* starts on the ith 64-bit "word" of 	*/
			/* nursery.  This simple structure has	*/
			/* the advantage that 			*/
			/* allocation is cheap.  Lookup is 	*/
			/* cheap for pointers to the head of	*/
			/* an object, which should be the	*/
			/* usual case.				*/
#   define NURSERY_MAP_NOT_START	0  /* Not start of object. */
#   define NURSERY_MAP_START		1  /* Start of object.	   */
#   define NURSERY_MAP_PINNED		2  /* Start of pinned obj. */

# ifdef ALIGN_DOUBLE
#   define NURSERY_WORD_SIZE (2 * sizeof(word))
# else
#   define NURSERY_WORD_SIZE sizeof(word)
# endif

# define NURSERY_BLOCK_SIZE (HBLKSIZE/2)	
	/* HBLKSIZE must be a multiple of NURSERY_BLOCK_SIZE */
# define NURSERY_SIZE (1024 * NURSERY_BLOCK_SIZE)

size_t GC_nursery_size = NURSERY_SIZE;
			/* Must be multiple of NURSERY_BLOCK_SIZE	*/

size_t GC_nursery_blocks; /* Number of blocks in the nursery.	*/

unsigned GC_next_nursery_block; /* index of next block we will attempt 	*/
				/* allocate from during this cycle.	*/
				/* If it is pinned, we won't actually	*/
				/* use it.				*/

unsigned short *GC_pinned;	/* Number of pinned objects in ith	*/
				/* nursery block.			*/
				/* GC_pinned[i] != 0 if the ith nursery */
				/* block is pinned, and thus not used	*/
				/* for allocation.			*/

GC_copy_alloc_state global_alloc_state = (ptr_t)(-1);	/* will overflow. */

/* Should be called with allocator lock held.	*/
GC_nursery_init() {
    GC_nursery_start = GET_MEM(GC_nursery_size);
    GC_nursery_end = GC_nursery_start + GC_nursery_size;
    GC_next_nursery_block = 0;
    if (GC_nursery_start < GC_least_plausible_heap_addr) { 
        GC_least_plausible_heap_addr = GC_nursery_start;   
    }
    if (GC_nursery_end > GC_greatest_plausible_heap_addr) {
        GC_greatest_plausible_heap_addr = GC_nursery_end;  
    }
    if (GC_nursery_start & (NURSERY_BLOCK_SIZE-1)) {
	GC_err_printf1("Nursery area is misaligned!!");
	/* This should be impossible, since GET_MEM returns HBLKSIZE */
	/* aligned chunks, and that should be a multiple of 	     */
	/* NURSERY_BLOCK_SIZE					     */
	ABORT("misaligned nursery");
    }
    GC_nursery_map = GET_MEM(GC_nursery_size/NURSERY_WORD_SIZE);
    /* Map is cleared a block at a time when we allocate from the block. */
    /* BZERO(GC_nursery_map, GC_nursery_size/NURSERY_WORD_SIZE);	 */
    GC_nursery_blocks = GC_nursery_size/NURSERY_BLOCK_SIZE;
    GC_pinned = GC_scratch_alloc(GC_nursery_blocks * sizeof(unsigned short));
    BZERO(GC_pinned, GC_nursery_blocks);
}

/* Pin all nursery objects referenced from mark stack. */
void GC_pin_mark_stack_objects(void) {
    for each possible pointer current in a mark stack object
	if (current >= GC_nursery_start && current < GC_nursery_end) {
	    unsigned offset = current - GC_nursery_start;
	    unsigned word_offset = BYTES_TO_WORDS(offset);
	    unsigned blockno = (current - GC_nursery_start)/NURSERY_BLOCK_SIZE;
	    while (GC_nursery_map[word_offset] == NURSERY_MAP_NOT_START) {
		--word_offset;    
	    }
	    if (GC_nursery_map[word_offset] != NURSERY_MAP_PINNED) {
	        GC_nursery_map[word_offset] = NURSERY_MAP_PINNED;
	        ++GC_pinned[blockno];
	        ??Push object at GC_nursery_start + WORDS_TO_BYTES(word_offset)
	        ??onto stack. 
	    }
	}
    }
}

/* Caller holds allocation lock.	*/
void GC_collect_nursery(void) {
    int i;
    ptr_t scan_ptr = 0;
    ?? old_mark_stack_top;
    STOP_WORLD;
    for (i = 0; i < GC_nursery_blocks; ++i) GC_pinned[i] = 0;
    GC_push_all_roots();
    old_mark_stack_top = GC_mark_stack_top();
    GC_pin_mark_stack_objects();
    START_WORLD;
}

/* Initialize an allocation state so that it can be used for 	*/
/* allocation.  This implicitly reserves a small section of the	*/
/* nursery for use with his allocator.				*/
void GC_init_copy_alloc_state(GC_copy_alloc_state *)
    unsigned next_block;
    ptr_t block_addr;
    LOCK();
    next_block = GC_next_nursery_block;
    while(is_pinned[next_block] && next_block < GC_nursery_blocks) {
	++next_block;
    }
    if (next_block < GC_nursery_blocks) {
	block_addr = GC_nursery_start + NURSERY_BLOCK_SIZE * next_block;
   	GC_next_nursery_block = next_block + 1;
	BZERO(GC_nursery_map + next_block *
				(NURSERY_BLOCK_SIZE/NURSERY_WORD_SIZE),
	      NURSERY_BLOCK_SIZE/NURSERY_WORD_SIZE);
	*GC_copy_alloc_state = block_addr;
	UNLOCK();
    } else {
     	GC_collect_nursery();
    	GC_next_nursery_block = 0;
    	UNLOCK();
    	get_new_block(s);
    }
}

GC_PTR GC_copying_malloc2(GC_copy_descriptor *d, GC_copy_alloc_state *s) {
    size_t sz = GC_SIZE_FROM_DESCRIPTOR(d);
    ptrdiff_t offset;
    ptr_t result = *s;
    ptr_t new = result + sz;
    if (new & COPY_BLOCK_MASK <= result & COPY_BLOCK_MASK> {
	GC_init_copy_alloc_state(s);
	result = *s;
	new = result + sz;
        GC_ASSERT(new & COPY_BLOCK_MASK > result & COPY_BLOCK_MASK>
    }
    (struct copy_obj *)result -> descr = d;      
    (struct copy_obj *)result -> forward = 0;      
    offset = (result - GC_nursery_start)/NURSERY_WORD_SIZE;
    GC_nursery_map[offset] = NURSERY_MAP_NOT_START;
}

GC_PTR GC_copying_malloc(GC_copy_descriptor *d) {
}