Line data Source code
1 : /*
2 : * Copyright (c) 2011 by Hewlett-Packard Company. All rights reserved.
3 : *
4 : * THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED
5 : * OR IMPLIED. ANY USE IS AT YOUR OWN RISK.
6 : *
7 : * Permission is hereby granted to use or copy this program
8 : * for any purpose, provided the above notices are retained on all copies.
9 : * Permission to modify the code and to distribute modified code is granted,
10 : * provided the above notices are retained, and a notice that the code was
11 : * modified is included with the above copyright notice.
12 : *
13 : */
14 :
15 : #include "private/gc_priv.h"
16 :
17 : #ifdef ENABLE_DISCLAIM
18 :
19 : #include "gc_disclaim.h"
20 :
21 : #ifdef THREAD_LOCAL_ALLOC
22 : # include "private/thread_local_alloc.h"
23 : #else
24 : STATIC ptr_t * GC_finalized_objfreelist = NULL;
25 : #endif /* !THREAD_LOCAL_ALLOC */
26 :
27 : STATIC int GC_finalized_kind = 0;
28 :
29 0 : STATIC int GC_CALLBACK GC_finalized_disclaim(void *obj)
30 : {
31 0 : word fc_word = *(word *)obj;
32 :
33 0 : if ((fc_word & 1) != 0) {
34 : /* The disclaim function may be passed fragments from the */
35 : /* free-list, on which it should not run finalization. */
36 : /* To recognize this case, we use the fact that the first word */
37 : /* on such fragments are always even (a link to the next */
38 : /* fragment, or NULL). If it is desirable to have a finalizer */
39 : /* which does not use the first word for storing finalization */
40 : /* info, GC_reclaim_with_finalization must be extended to clear */
41 : /* fragments so that the assumption holds for the selected word. */
42 0 : const struct GC_finalizer_closure *fc = (void *)(fc_word & ~(word)1);
43 0 : (*fc->proc)((word *)obj + 1, fc->cd);
44 : }
45 0 : return 0;
46 : }
47 :
48 : static GC_bool done_init = FALSE;
49 :
50 0 : GC_API void GC_CALL GC_init_finalized_malloc(void)
51 : {
52 : DCL_LOCK_STATE;
53 :
54 0 : GC_init(); /* In case it's not already done. */
55 0 : LOCK();
56 0 : if (done_init) {
57 0 : UNLOCK();
58 0 : return;
59 : }
60 0 : done_init = TRUE;
61 :
62 : /* The finalizer closure is placed in the first word in order to */
63 : /* use the lower bits to distinguish live objects from objects on */
64 : /* the free list. The downside of this is that we need one-word */
65 : /* offset interior pointers, and that GC_base does not return the */
66 : /* start of the user region. */
67 0 : GC_register_displacement_inner(sizeof(word));
68 :
69 0 : GC_finalized_objfreelist = (ptr_t *)GC_new_free_list_inner();
70 0 : GC_finalized_kind = GC_new_kind_inner((void **)GC_finalized_objfreelist,
71 : GC_DS_LENGTH, TRUE, TRUE);
72 0 : GC_register_disclaim_proc(GC_finalized_kind, GC_finalized_disclaim, TRUE);
73 0 : UNLOCK();
74 : }
75 :
76 0 : GC_API void GC_CALL GC_register_disclaim_proc(int kind, GC_disclaim_proc proc,
77 : int mark_unconditionally)
78 : {
79 : GC_ASSERT((unsigned)kind < MAXOBJKINDS);
80 0 : GC_obj_kinds[kind].ok_disclaim_proc = proc;
81 0 : GC_obj_kinds[kind].ok_mark_unconditionally = (GC_bool)mark_unconditionally;
82 0 : }
83 :
84 : #ifdef THREAD_LOCAL_ALLOC
85 0 : STATIC void * GC_core_finalized_malloc(size_t lb,
86 : const struct GC_finalizer_closure *fclos)
87 : #else
88 : GC_API GC_ATTR_MALLOC void * GC_CALL GC_finalized_malloc(size_t lb,
89 : const struct GC_finalizer_closure *fclos)
90 : #endif
91 : {
92 : ptr_t op;
93 : ptr_t *opp;
94 : word lg;
95 : DCL_LOCK_STATE;
96 :
97 0 : lb += sizeof(word);
98 : GC_ASSERT(done_init);
99 0 : if (SMALL_OBJ(lb)) {
100 : GC_DBG_COLLECT_AT_MALLOC(lb);
101 0 : lg = GC_size_map[lb];
102 0 : opp = &GC_finalized_objfreelist[lg];
103 0 : LOCK();
104 0 : op = *opp;
105 0 : if (EXPECT(0 == op, FALSE)) {
106 0 : UNLOCK();
107 0 : op = GC_generic_malloc((word)lb, GC_finalized_kind);
108 0 : if (NULL == op)
109 0 : return NULL;
110 : /* GC_generic_malloc has extended the size map for us. */
111 0 : lg = GC_size_map[lb];
112 : } else {
113 0 : *opp = obj_link(op);
114 0 : obj_link(op) = 0;
115 0 : GC_bytes_allocd += GRANULES_TO_BYTES(lg);
116 0 : UNLOCK();
117 : }
118 : GC_ASSERT(lg > 0);
119 : } else {
120 0 : op = GC_generic_malloc(lb, GC_finalized_kind);
121 0 : if (NULL == op)
122 0 : return NULL;
123 : GC_ASSERT(GC_size(op) >= lb);
124 : }
125 0 : *(word *)op = (word)fclos | 1;
126 0 : return GC_clear_stack((word *)op + 1);
127 : }
128 :
129 : #ifdef THREAD_LOCAL_ALLOC
130 0 : GC_API GC_ATTR_MALLOC void * GC_CALL GC_finalized_malloc(size_t client_lb,
131 : const struct GC_finalizer_closure *fclos)
132 : {
133 0 : size_t lb = client_lb + sizeof(word);
134 0 : size_t lg = ROUNDED_UP_GRANULES(lb);
135 : GC_tlfs tsd;
136 : void *result;
137 : void **tiny_fl, **my_fl, *my_entry;
138 : void *next;
139 :
140 0 : if (EXPECT(lg >= GC_TINY_FREELISTS, FALSE))
141 0 : return GC_core_finalized_malloc(client_lb, fclos);
142 :
143 0 : tsd = GC_getspecific(GC_thread_key);
144 0 : tiny_fl = tsd->finalized_freelists;
145 0 : my_fl = tiny_fl + lg;
146 0 : my_entry = *my_fl;
147 0 : while (EXPECT((word)my_entry
148 : <= DIRECT_GRANULES + GC_TINY_FREELISTS + 1, FALSE)) {
149 0 : if ((word)my_entry - 1 < DIRECT_GRANULES) {
150 0 : *my_fl = (ptr_t)my_entry + lg + 1;
151 0 : return GC_core_finalized_malloc(client_lb, fclos);
152 : } else {
153 0 : GC_generic_malloc_many(GC_RAW_BYTES_FROM_INDEX(lg),
154 : GC_finalized_kind, my_fl);
155 0 : my_entry = *my_fl;
156 0 : if (my_entry == 0) {
157 0 : return (*GC_get_oom_fn())(lb);
158 : }
159 : }
160 : }
161 :
162 0 : next = obj_link(my_entry);
163 0 : result = (void *)my_entry;
164 0 : *my_fl = next;
165 0 : obj_link(result) = 0;
166 0 : *(word *)result = (word)fclos | 1;
167 0 : PREFETCH_FOR_WRITE(next);
168 0 : return (word *)result + 1;
169 : }
170 : #endif /* THREAD_LOCAL_ALLOC */
171 :
172 : #endif /* ENABLE_DISCLAIM */
|