* Merged with default branch at rev 16f3633aaa5a.
[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 */
26
27
28 #include "config.h"
29
30 #include <assert.h>
31 #include <stdint.h>
32
33 #include "mm/memory.h"
34
35 #include "native/localref.h"
36
37 #include "threads/threads-common.h"
38
39 #include "toolbox/logging.h"
40
41
42 /* debug **********************************************************************/
43
44 #if !defined(NDEBUG) && 0
45 # define TRACELOCALREF(message) log_println("%s", message)
46 #else
47 # define TRACELOCALREF(message)
48 #endif
49
50
51 /* global variables ***********************************************************/
52
53 #if !defined(ENABLE_THREADS)
54 localref_table *_no_threads_localref_table;
55 #endif
56
57
58 /* localref_table_init *********************************************************
59
60    Initializes the local references table of the current thread.
61
62 *******************************************************************************/
63
64 bool localref_table_init(void)
65 {
66         localref_table *lrt;
67
68         TRACELOCALREF("table init");
69
70         assert(LOCALREFTABLE == NULL);
71
72 #if defined(ENABLE_GC_CACAO)
73         /* this is freed by localref_table_destroy */
74         lrt = NEW(localref_table);
75 #else
76         /* this does not need to be freed again */
77         lrt = GCNEW(localref_table);
78 #endif
79
80         if (lrt == NULL)
81                 return false;
82
83         localref_table_add(lrt);
84
85         return true;
86 }
87
88
89 /* localref_table_destroy ******************************************************
90
91    Destroys the complete local references table of the current thread.
92
93 *******************************************************************************/
94
95 bool localref_table_destroy(void)
96 {
97         localref_table *lrt;
98
99         TRACELOCALREF("table destroy");
100
101         lrt = LOCALREFTABLE;
102
103         assert(lrt);
104         assert(lrt->prev == NULL);
105
106 #if defined(ENABLE_GC_CACAO)
107         FREE(lrt, localref_table);
108 #endif
109
110         LOCALREFTABLE = NULL;
111
112         return true;
113 }
114
115
116 /* localref_table_add **********************************************************
117
118    Adds a new local references table to the current thread.
119
120 *******************************************************************************/
121
122 void localref_table_add(localref_table *lrt)
123 {
124         /* initialize the local reference table */
125
126         lrt->capacity    = LOCALREFTABLE_CAPACITY;
127         lrt->used        = 0;
128         lrt->localframes = 1;
129         lrt->prev        = LOCALREFTABLE;
130
131         /* clear the references array (memset is faster the a for-loop) */
132
133         MSET(lrt->refs, 0, void*, LOCALREFTABLE_CAPACITY);
134
135         /* add given local references table to this thread */
136
137         LOCALREFTABLE = lrt;
138 }
139
140
141 /* localref_table_remove *******************************************************
142
143    Removes the topmost local references table from the current thread.
144
145 *******************************************************************************/
146
147 void localref_table_remove()
148 {
149         localref_table *lrt;
150
151         /* get current local reference table from thread */
152
153         lrt = LOCALREFTABLE;
154
155         assert(lrt != NULL);
156         assert(lrt->localframes == 1);
157
158         lrt = lrt->prev;
159
160         LOCALREFTABLE = lrt;
161 }
162
163
164 /* localref_frame_push *********************************************************
165
166    Creates a new local reference frame, in which at least a given
167    number of local references can be created.
168
169 *******************************************************************************/
170
171 bool localref_frame_push(int32_t capacity)
172 {
173         localref_table *lrt;
174         localref_table *nlrt;
175         int32_t         additionalrefs;
176
177         TRACELOCALREF("frame push");
178
179         /* get current local reference table from thread */
180
181         lrt = LOCALREFTABLE;
182
183         assert(lrt != NULL);
184         assert(capacity > 0);
185
186         /* Allocate new local reference table on Java heap.  Calculate the
187            additional memory we have to allocate. */
188
189         if (capacity > LOCALREFTABLE_CAPACITY)
190                 additionalrefs = capacity - LOCALREFTABLE_CAPACITY;
191         else
192                 additionalrefs = 0;
193
194 #if defined(ENABLE_GC_CACAO)
195         nlrt = MNEW(u1, sizeof(localref_table) + additionalrefs * SIZEOF_VOID_P);
196 #else
197         nlrt = GCMNEW(u1, sizeof(localref_table) + additionalrefs * SIZEOF_VOID_P);
198 #endif
199
200         if (nlrt == NULL)
201                 return false;
202
203         /* Set up the new local reference table and add it to the local
204            frames chain. */
205
206         nlrt->capacity    = capacity;
207         nlrt->used        = 0;
208         nlrt->localframes = lrt->localframes + 1;
209         nlrt->prev        = lrt;
210
211         /* store new local reference table in thread */
212
213         LOCALREFTABLE = nlrt;
214
215         return true;
216 }
217
218
219 /* localref_frame_pop_all ******************************************************
220
221    Pops off all the local reference frames of the current table.
222
223 *******************************************************************************/
224
225 void localref_frame_pop_all(void)
226 {
227         localref_table *lrt;
228         localref_table *plrt;
229         int32_t         localframes;
230 #if defined(ENABLE_GC_CACAO)
231         int32_t         additionalrefs;
232 #endif
233
234         TRACELOCALREF("frame pop all");
235
236         /* get current local reference table from thread */
237
238         lrt = LOCALREFTABLE;
239
240         assert(lrt != NULL);
241
242         localframes = lrt->localframes;
243
244         /* Don't delete the top local frame, as this one is allocated in
245            the native stub on the stack and is freed automagically on
246            return. */
247
248         if (localframes == 1)
249                 return;
250
251         /* release all current local frames */
252
253         for (; localframes > 1; localframes--) {
254                 /* get previous frame */
255
256                 plrt = lrt->prev;
257
258                 /* clear all reference entries */
259
260                 MSET(lrt->refs, 0, void*, lrt->capacity);
261
262                 lrt->prev = NULL;
263
264 #if defined(ENABLE_GC_CACAO)
265                 /* for the exact GC local reference tables are not on the heap,
266                    so we need to free them explicitly here. */
267
268                 if (lrt->capacity > LOCALREFTABLE_CAPACITY)
269                         additionalrefs = lrt->capacity - LOCALREFTABLE_CAPACITY;
270                 else
271                         additionalrefs = 0;
272
273                 MFREE(lrt, u1, sizeof(localref_table) + additionalrefs * SIZEOF_VOID_P);
274 #endif
275
276                 /* set new local references table */
277
278                 lrt = plrt;
279         }
280
281         /* store new local reference table in thread */
282
283         LOCALREFTABLE = lrt;
284 }
285
286
287 /* localref_add ****************************************************************
288
289    Adds a new entry into the local reference table and returns the
290    new local reference.
291
292 *******************************************************************************/
293
294 java_handle_t *localref_add(java_object_t *o)
295 {
296         localref_table *lrt;
297         java_handle_t  *h;
298         int32_t         i;
299
300 #if !defined(NDEBUG)
301         if (o == NULL) {
302                 log_println("localref_add: WARNING: trying to add localref for (NIL)!");
303                 return NULL;
304         }
305 #endif
306
307         /* XXX: assert that we are in a GC critical section! */
308
309         /* XXX: this is only an ugly hack */
310 #if defined(ENABLE_HANDLES)
311         if (LOCALREFTABLE == NULL) {
312                 h = NEW(java_handle_t);
313                 h->heap_object = o;
314                 log_println("localref_add: WARNING: added preliminary localref %p for %p", h, o);
315                 return h;
316         }
317 #endif
318
319         /* get current local reference table from thread */
320
321         lrt = LOCALREFTABLE;
322
323         assert(lrt != NULL);
324
325         /* Check if we have space for the requested reference?  No,
326            allocate a new frame.  This is actually not what the spec says,
327            but for compatibility reasons... */
328
329     if (lrt->used == lrt->capacity) {
330                 if (!localref_frame_push(16))
331                         assert(0);
332
333                 /* get the new local reference table */ 
334
335                 lrt = LOCALREFTABLE;
336         }
337
338         /* insert the reference into the local reference table */
339
340         for (i = 0; i < lrt->capacity; i++) {
341                 if (lrt->refs[i] == NULL) {
342                         lrt->refs[i] = o;
343                         lrt->used++;
344
345 #if defined(ENABLE_HANDLES)
346                         h = (java_handle_t *) &(lrt->refs[i]);
347 #else
348                         h = (java_handle_t *) o;
349 #endif
350
351 #if 0
352                         {
353                                 int count = 0;
354                                 for (lrt = LOCALREFTABLE; lrt != NULL; lrt = lrt->prev)
355                                         count += lrt->used;
356                                 log_println("added localref %p for %p (total count %d)", h, o, count);
357                                 /*localref_dump();*/
358                         }
359 #endif
360
361                         return h;
362                 }
363         }
364
365         /* this should not happen */
366
367         log_println("localref_add: WARNING: unable to add localref for %p", o);
368
369         return NULL;
370 }
371
372
373 /* localref_del ****************************************************************
374
375    Deletes an entry from the local reference table.
376
377 *******************************************************************************/
378
379 void localref_del(java_handle_t *localref)
380 {
381         localref_table *lrt;
382         java_handle_t  *h;
383         int32_t         i;
384
385         /* get local reference table from thread */
386
387         lrt = LOCALREFTABLE;
388
389         assert(lrt != NULL);
390
391         /* go through all local frames */
392
393         /* XXX: this is definitely not what the spec wants! */
394         /*for (; lrt != NULL; lrt = lrt->prev) {*/
395
396                 /* and try to remove the reference */
397     
398                 for (i = 0; i < lrt->capacity; i++) {
399 #if defined(ENABLE_HANDLES)
400                         h = (java_handle_t *) &(lrt->refs[i]);
401 #else
402                         h = (java_handle_t *) lrt->refs[i];
403 #endif
404
405                         if (h == localref) {
406                                 lrt->refs[i] = NULL;
407                                 lrt->used--;
408
409                                 return;
410                         }
411                 }
412         /*}*/
413
414         /* this should not happen */
415
416         log_println("localref_del: WARNING: unable to find localref %p", localref);
417 }
418
419
420 /* localref_dump ***************************************************************
421
422    Dumps all local reference tables, including all frames.
423
424 *******************************************************************************/
425
426 #if !defined(NDEBUG)
427 # define LOCALREF_DUMP_REFS_PER_LINE 4
428 void localref_dump()
429 {
430         localref_table *lrt;
431         int i, j;
432
433         /* get current local reference table from thread */
434
435         lrt = LOCALREFTABLE;
436
437         log_println("--------- Local Reference Tables Dump ---------");
438
439         while (lrt != NULL) {
440                 log_println("Frame #%d, Used=%d, Capacity=%d, Addr=%p:", lrt->localframes, lrt->used, lrt->capacity, (void *) lrt);
441
442                         if (lrt->used != 0) {
443
444                                 log_start();
445
446                                 j = 0;
447                                 for (i = 0; i < lrt->capacity; i++) {
448                                         if (lrt->refs[i] != NULL) {
449                                                 if (j != 0 && j % LOCALREF_DUMP_REFS_PER_LINE == 0) {
450                                                         log_finish();
451                                                         log_start();
452                                                 }
453                                                 j++;
454                                                 log_print("\t0x%016lx ", (intptr_t) lrt->refs[i]);
455                                         }
456                                 }
457
458                                 log_finish();
459                         }
460
461                 lrt = lrt->prev;
462         }
463 }
464 #endif /* !defined(NDEBUG) */
465
466
467 /*
468  * These are local overrides for various environment variables in Emacs.
469  * Please do not remove this and leave it at the end of the file, where
470  * Emacs will automagically detect them.
471  * ---------------------------------------------------------------------
472  * Local variables:
473  * mode: c
474  * indent-tabs-mode: t
475  * c-basic-offset: 4
476  * tab-width: 4
477  * End:
478  * vim:noexpandtab:sw=4:ts=4:
479  */