* src/native/localref.c (localref_add): Implemented (moved parts from jni.c).
[cacao.git] / src / native / localref.c
1 /* src/native/localref.c - Management of local reference tables
2
3    Copyright (C) 1996-2005, 2006, 2007 R. Grafl, A. Krall, C. Kruegel,
4    C. Oates, R. Obermaisser, M. Platter, M. Probst, S. Ring,
5    E. Steiner, C. Thalinger, D. Thuernbeck, P. Tomsich, C. Ullrich,
6    J. Wenninger, Institut f. Computersprachen - TU Wien
7
8    This file is part of CACAO.
9
10    This program is free software; you can redistribute it and/or
11    modify it under the terms of the GNU General Public License as
12    published by the Free Software Foundation; either version 2, or (at
13    your option) any later version.
14
15    This program is distributed in the hope that it will be useful, but
16    WITHOUT ANY WARRANTY; without even the implied warranty of
17    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
18    General Public License for more details.
19
20    You should have received a copy of the GNU General Public License
21    along with this program; if not, write to the Free Software
22    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
23    02110-1301, USA.
24
25    $Id: localref.c 8364 2007-08-20 19:52:00Z michi $
26
27 */
28
29
30 #include "config.h"
31
32 #include <assert.h>
33 #include <stdint.h>
34
35 #include "mm/memory.h"
36
37 #include "native/localref.h"
38
39 #include "threads/threads-common.h"
40
41 #include "toolbox/logging.h"
42
43
44 /* debug **********************************************************************/
45
46 #if !defined(NDEBUG) && 0
47 # define TRACELOCALREF(message) log_println("%s", message)
48 #else
49 # define TRACELOCALREF(message)
50 #endif
51
52
53 /* global variables ***********************************************************/
54
55 #if !defined(ENABLE_THREADS)
56 localref_table *_no_threads_localref_table;
57 #endif
58
59
60 /* localref_table_init *********************************************************
61
62    Initializes the local references table of the current thread.
63
64 *******************************************************************************/
65
66 bool localref_table_init(void)
67 {
68         localref_table *lrt;
69
70         TRACELOCALREF("table init");
71
72         assert(LOCALREFTABLE == NULL);
73
74 #if defined(ENABLE_GC_CACAO)
75         /* this is freed by localref_table_destroy */
76         lrt = NEW(localref_table);
77 #else
78         /* this does not need to be freed again */
79         lrt = GCNEW(localref_table);
80 #endif
81
82         if (lrt == NULL)
83                 return false;
84
85         localref_table_add(lrt);
86
87         return true;
88 }
89
90
91 /* localref_table_destroy ******************************************************
92
93    Destroys the complete local references table of the current thread.
94
95 *******************************************************************************/
96
97 bool localref_table_destroy(void)
98 {
99         localref_table *lrt;
100
101         TRACELOCALREF("table destroy");
102
103         lrt = LOCALREFTABLE;
104
105         assert(lrt);
106         assert(lrt->prev == NULL);
107
108 #if defined(ENABLE_GC_CACAO)
109         FREE(lrt, localref_table);
110 #endif
111
112         LOCALREFTABLE = NULL;
113
114         return true;
115 }
116
117
118 /* localref_table_add **********************************************************
119
120    Adds a new local references table to the current thread.
121
122 *******************************************************************************/
123
124 void localref_table_add(localref_table *lrt)
125 {
126         /* initialize the local reference table */
127
128         lrt->capacity    = LOCALREFTABLE_CAPACITY;
129         lrt->used        = 0;
130         lrt->localframes = 1;
131         lrt->prev        = LOCALREFTABLE;
132
133         /* clear the references array (memset is faster the a for-loop) */
134
135         MSET(lrt->refs, 0, void*, LOCALREFTABLE_CAPACITY);
136
137         /* add given local references table to this thread */
138
139         LOCALREFTABLE = lrt;
140 }
141
142
143 /* localref_table_remove *******************************************************
144
145    Removes the topmost local references table from the current thread.
146
147 *******************************************************************************/
148
149 void localref_table_remove()
150 {
151         localref_table *lrt;
152
153         /* get current local reference table from thread */
154
155         lrt = LOCALREFTABLE;
156
157         assert(lrt != NULL);
158         assert(lrt->localframes == 1);
159
160         lrt = lrt->prev;
161
162         LOCALREFTABLE = lrt;
163 }
164
165
166 /* localref_frame_push *********************************************************
167
168    Creates a new local reference frame, in which at least a given
169    number of local references can be created.
170
171 *******************************************************************************/
172
173 bool localref_frame_push(int32_t capacity)
174 {
175         localref_table *lrt;
176         localref_table *nlrt;
177         int32_t         additionalrefs;
178
179         TRACELOCALREF("frame push");
180
181         /* get current local reference table from thread */
182
183         lrt = LOCALREFTABLE;
184
185         assert(lrt != NULL);
186         assert(capacity > 0);
187
188         /* Allocate new local reference table on Java heap.  Calculate the
189            additional memory we have to allocate. */
190
191         if (capacity > LOCALREFTABLE_CAPACITY)
192                 additionalrefs = capacity - LOCALREFTABLE_CAPACITY;
193         else
194                 additionalrefs = 0;
195
196 #if defined(ENABLE_GC_CACAO)
197         nlrt = MNEW(u1, sizeof(localref_table) + additionalrefs * SIZEOF_VOID_P);
198 #else
199         nlrt = GCMNEW(u1, sizeof(localref_table) + additionalrefs * SIZEOF_VOID_P);
200 #endif
201
202         if (nlrt == NULL)
203                 return false;
204
205         /* Set up the new local reference table and add it to the local
206            frames chain. */
207
208         nlrt->capacity    = capacity;
209         nlrt->used        = 0;
210         nlrt->localframes = lrt->localframes + 1;
211         nlrt->prev        = lrt;
212
213         /* store new local reference table in thread */
214
215         LOCALREFTABLE = nlrt;
216
217         return true;
218 }
219
220
221 /* localref_frame_pop_all ******************************************************
222
223    Pops off all the local reference frames of the current table.
224
225 *******************************************************************************/
226
227 void localref_frame_pop_all(void)
228 {
229         localref_table *lrt;
230         localref_table *plrt;
231         int32_t         localframes;
232 #if defined(ENABLE_GC_CACAO)
233         int32_t         additionalrefs;
234 #endif
235
236         TRACELOCALREF("frame pop all");
237
238         /* get current local reference table from thread */
239
240         lrt = LOCALREFTABLE;
241
242         assert(lrt != NULL);
243
244         localframes = lrt->localframes;
245
246         /* Don't delete the top local frame, as this one is allocated in
247            the native stub on the stack and is freed automagically on
248            return. */
249
250         if (localframes == 1)
251                 return;
252
253         /* release all current local frames */
254
255         for (; localframes > 1; localframes--) {
256                 /* get previous frame */
257
258                 plrt = lrt->prev;
259
260                 /* clear all reference entries */
261
262                 MSET(lrt->refs, 0, void*, lrt->capacity);
263
264                 lrt->prev = NULL;
265
266 #if defined(ENABLE_GC_CACAO)
267                 /* for the exact GC local reference tables are not on the heap,
268                    so we need to free them explicitly here. */
269
270                 if (lrt->capacity > LOCALREFTABLE_CAPACITY)
271                         additionalrefs = lrt->capacity - LOCALREFTABLE_CAPACITY;
272                 else
273                         additionalrefs = 0;
274
275                 MFREE(lrt, u1, sizeof(localref_table) + additionalrefs * SIZEOF_VOID_P);
276 #endif
277
278                 /* set new local references table */
279
280                 lrt = plrt;
281         }
282
283         /* store new local reference table in thread */
284
285         LOCALREFTABLE = lrt;
286 }
287
288
289 /* localref_add ****************************************************************
290
291    Adds a new entry into the local reference table and returns the
292    new local reference.
293
294 *******************************************************************************/
295
296 java_handle_t *localref_add(java_object_t *o)
297 {
298         localref_table *lrt;
299         java_handle_t  *h;
300         int32_t         i;
301
302 #if !defined(NDEBUG)
303         if (o == NULL) {
304                 log_println("localref_add: WARNING: trying to add localref for (NIL)!");
305                 return NULL;
306         }
307 #endif
308
309         /* XXX: assert that we are in a GC critical section! */
310
311         /* XXX: this is only an ugly hack */
312 #if defined(ENABLE_HANDLES)
313         if (LOCALREFTABLE == NULL) {
314                 h = NEW(java_handle_t);
315                 h->heap_object = o;
316                 log_println("localref_add: WARNING: added preliminary localref %p for %p", h, o);
317                 return h;
318         }
319 #endif
320
321         /* get current local reference table from thread */
322
323         lrt = LOCALREFTABLE;
324
325         assert(lrt != NULL);
326
327         /* Check if we have space for the requested reference?  No,
328            allocate a new frame.  This is actually not what the spec says,
329            but for compatibility reasons... */
330
331     if (lrt->used == lrt->capacity) {
332                 if (!localref_frame_push(16))
333                         assert(0);
334
335                 /* get the new local reference table */ 
336
337                 lrt = LOCALREFTABLE;
338         }
339
340         /* insert the reference into the local reference table */
341
342         h = NULL;
343
344         for (i = 0; i < lrt->capacity; i++) {
345                 if (lrt->refs[i] == NULL) {
346                         lrt->refs[i] = o;
347                         lrt->used++;
348
349 #if defined(ENABLE_HANDLES)
350                         h = (java_handle_t *) &(lrt->refs[i]);
351 #else
352                         h = (java_handle_t *) o;
353 #endif
354
355                         break;
356                 }
357         }
358
359         /* this should not happen */
360
361         if (h == NULL)
362                 assert(0);
363
364 #if 1
365         {
366                 int count = 0;
367                 for (lrt = LOCALREFTABLE; lrt != NULL; lrt = lrt->prev)
368                         count += lrt->used;
369                 log_println("added localref %p for %p (total count %d)", h, o, count);
370                 /*localref_dump();*/
371         }
372 #endif
373
374         return h;
375 }
376
377
378 /* localref_dump ***************************************************************
379
380    Dumps all local reference tables, including all frames.
381
382 *******************************************************************************/
383
384 #if !defined(NDEBUG)
385 # define LOCALREF_DUMP_REFS_PER_LINE 4
386 void localref_dump()
387 {
388         localref_table *lrt;
389         int i, j;
390
391         /* get current local reference table from thread */
392
393         lrt = LOCALREFTABLE;
394
395         log_println("--------- Local Reference Tables Dump ---------");
396
397         while (lrt != NULL) {
398                 log_println("Frame #%d, Used=%d, Capacity=%d, Addr=%p:", lrt->localframes, lrt->used, lrt->capacity, (void *) lrt);
399
400                         if (lrt->used != 0) {
401
402                                 log_start();
403
404                                 j = 0;
405                                 for (i = 0; i < lrt->capacity; i++) {
406                                         if (lrt->refs[i] != NULL) {
407                                                 if (j != 0 && j % LOCALREF_DUMP_REFS_PER_LINE == 0) {
408                                                         log_finish();
409                                                         log_start();
410                                                 }
411                                                 j++;
412                                                 log_print("\t0x%016lx ", (intptr_t) lrt->refs[i]);
413                                         }
414                                 }
415
416                                 log_finish();
417                         }
418
419                 lrt = lrt->prev;
420         }
421 }
422 #endif /* !defined(NDEBUG) */
423
424
425 /*
426  * These are local overrides for various environment variables in Emacs.
427  * Please do not remove this and leave it at the end of the file, where
428  * Emacs will automagically detect them.
429  * ---------------------------------------------------------------------
430  * Local variables:
431  * mode: c
432  * indent-tabs-mode: t
433  * c-basic-offset: 4
434  * tab-width: 4
435  * End:
436  * vim:noexpandtab:sw=4:ts=4:
437  */