a7b8d07117d1d4effb1ea6b048d43419f8c315af
[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 #include "vm/vm.h"
42
43 #include "vm/jit/argument.h"
44
45
46 /* debug **********************************************************************/
47
48 #if !defined(NDEBUG) && 0
49 # define TRACELOCALREF(message) log_println("%s", message)
50 #else
51 # define TRACELOCALREF(message)
52 #endif
53
54
55 /* global variables ***********************************************************/
56
57 #if !defined(ENABLE_THREADS)
58 localref_table *_no_threads_localref_table;
59 #endif
60
61
62 /* localref_table_init *********************************************************
63
64    Initializes the local references table of the current thread.
65
66 *******************************************************************************/
67
68 bool localref_table_init(void)
69 {
70         localref_table *lrt;
71
72         TRACELOCALREF("table init");
73
74         assert(LOCALREFTABLE == NULL);
75
76 #if defined(ENABLE_GC_CACAO)
77         /* this is freed by localref_table_destroy */
78         lrt = NEW(localref_table);
79 #else
80         /* this does not need to be freed again */
81         lrt = GCNEW(localref_table);
82 #endif
83
84         if (lrt == NULL)
85                 return false;
86
87         localref_table_add(lrt);
88
89         return true;
90 }
91
92
93 /* localref_table_destroy ******************************************************
94
95    Destroys the complete local references table of the current thread.
96
97 *******************************************************************************/
98
99 bool localref_table_destroy(void)
100 {
101         localref_table *lrt;
102
103         TRACELOCALREF("table destroy");
104
105         lrt = LOCALREFTABLE;
106
107         assert(lrt);
108         assert(lrt->prev == NULL);
109
110 #if defined(ENABLE_GC_CACAO)
111         FREE(lrt, localref_table);
112 #endif
113
114         LOCALREFTABLE = NULL;
115
116         return true;
117 }
118
119
120 /* localref_table_add **********************************************************
121
122    Adds a new local references table to the current thread.
123
124 *******************************************************************************/
125
126 void localref_table_add(localref_table *lrt)
127 {
128         /* initialize the local reference table */
129
130         lrt->capacity    = LOCALREFTABLE_CAPACITY;
131         lrt->used        = 0;
132         lrt->localframes = 1;
133         lrt->prev        = LOCALREFTABLE;
134
135         /* clear the references array (memset is faster the a for-loop) */
136
137         MSET(lrt->refs, 0, void*, LOCALREFTABLE_CAPACITY);
138
139         /* add given local references table to this thread */
140
141         LOCALREFTABLE = lrt;
142 }
143
144
145 /* localref_table_remove *******************************************************
146
147    Removes the topmost local references table from the current thread.
148
149 *******************************************************************************/
150
151 void localref_table_remove()
152 {
153         localref_table *lrt;
154
155         /* get current local reference table from thread */
156
157         lrt = LOCALREFTABLE;
158
159         assert(lrt != NULL);
160         assert(lrt->localframes == 1);
161
162         lrt = lrt->prev;
163
164         LOCALREFTABLE = lrt;
165 }
166
167
168 /* localref_frame_push *********************************************************
169
170    Creates a new local reference frame, in which at least a given
171    number of local references can be created.
172
173 *******************************************************************************/
174
175 bool localref_frame_push(int32_t capacity)
176 {
177         localref_table *lrt;
178         localref_table *nlrt;
179         int32_t         additionalrefs;
180
181         TRACELOCALREF("frame push");
182
183         /* get current local reference table from thread */
184
185         lrt = LOCALREFTABLE;
186
187         assert(lrt != NULL);
188         assert(capacity > 0);
189
190         /* Allocate new local reference table on Java heap.  Calculate the
191            additional memory we have to allocate. */
192
193         if (capacity > LOCALREFTABLE_CAPACITY)
194                 additionalrefs = capacity - LOCALREFTABLE_CAPACITY;
195         else
196                 additionalrefs = 0;
197
198 #if defined(ENABLE_GC_CACAO)
199         nlrt = (localref_table *)
200                         MNEW(u1, sizeof(localref_table) + additionalrefs * SIZEOF_VOID_P);
201 #else
202         nlrt = (localref_table *)
203                         GCMNEW(u1, sizeof(localref_table) + additionalrefs * SIZEOF_VOID_P);
204 #endif
205
206         if (nlrt == NULL)
207                 return false;
208
209         /* Set up the new local reference table and add it to the local
210            frames chain. */
211
212         nlrt->capacity    = capacity;
213         nlrt->used        = 0;
214         nlrt->localframes = lrt->localframes + 1;
215         nlrt->prev        = lrt;
216
217         /* store new local reference table in thread */
218
219         LOCALREFTABLE = nlrt;
220
221         return true;
222 }
223
224
225 /* localref_frame_pop_all ******************************************************
226
227    Pops off all the local reference frames of the current table.
228
229 *******************************************************************************/
230
231 void localref_frame_pop_all(void)
232 {
233         localref_table *lrt;
234         localref_table *plrt;
235         int32_t         localframes;
236 #if defined(ENABLE_GC_CACAO)
237         int32_t         additionalrefs;
238 #endif
239
240         TRACELOCALREF("frame pop all");
241
242         /* get current local reference table from thread */
243
244         lrt = LOCALREFTABLE;
245
246         assert(lrt != NULL);
247
248         localframes = lrt->localframes;
249
250         /* Don't delete the top local frame, as this one is allocated in
251            the native stub on the stack and is freed automagically on
252            return. */
253
254         if (localframes == 1)
255                 return;
256
257         /* release all current local frames */
258
259         for (; localframes > 1; localframes--) {
260                 /* get previous frame */
261
262                 plrt = lrt->prev;
263
264                 /* clear all reference entries */
265
266                 MSET(lrt->refs, 0, void*, lrt->capacity);
267
268                 lrt->prev = NULL;
269
270 #if defined(ENABLE_GC_CACAO)
271                 /* for the exact GC local reference tables are not on the heap,
272                    so we need to free them explicitly here. */
273
274                 if (lrt->capacity > LOCALREFTABLE_CAPACITY)
275                         additionalrefs = lrt->capacity - LOCALREFTABLE_CAPACITY;
276                 else
277                         additionalrefs = 0;
278
279                 MFREE(lrt, u1, sizeof(localref_table) + additionalrefs * SIZEOF_VOID_P);
280 #endif
281
282                 /* set new local references table */
283
284                 lrt = plrt;
285         }
286
287         /* store new local reference table in thread */
288
289         LOCALREFTABLE = lrt;
290 }
291
292
293 /* localref_add ****************************************************************
294
295    Adds a new entry into the local reference table and returns the
296    new local reference.
297
298 *******************************************************************************/
299
300 java_handle_t *localref_add(java_object_t *o)
301 {
302         localref_table *lrt;
303         java_handle_t  *h;
304         int32_t         i;
305
306 #if !defined(NDEBUG)
307         if (o == NULL) {
308                 log_println("localref_add: WARNING: trying to add localref for (NIL)!");
309                 return NULL;
310         }
311 #endif
312
313         /* XXX: assert that we are in a GC critical section! */
314
315         /* XXX: this is only an ugly hack */
316 #if defined(ENABLE_HANDLES)
317         if (LOCALREFTABLE == NULL) {
318                 h = NEW(java_handle_t);
319                 h->heap_object = o;
320                 log_println("localref_add: WARNING: added preliminary localref %p for %p", h, o);
321                 return h;
322         }
323 #endif
324
325         /* get current local reference table from thread */
326
327         lrt = LOCALREFTABLE;
328
329         assert(lrt != NULL);
330
331         /* Check if we have space for the requested reference?  No,
332            allocate a new frame.  This is actually not what the spec says,
333            but for compatibility reasons... */
334
335     if (lrt->used == lrt->capacity) {
336                 if (!localref_frame_push(16))
337                         assert(0);
338
339                 /* get the new local reference table */ 
340
341                 lrt = LOCALREFTABLE;
342         }
343
344         /* insert the reference into the local reference table */
345
346         for (i = 0; i < lrt->capacity; i++) {
347                 if (lrt->refs[i] == NULL) {
348                         lrt->refs[i] = o;
349                         lrt->used++;
350
351 #if defined(ENABLE_HANDLES)
352                         h = (java_handle_t *) &(lrt->refs[i]);
353 #else
354                         h = (java_handle_t *) o;
355 #endif
356
357 #if 0
358                         {
359                                 int count = 0;
360                                 for (lrt = LOCALREFTABLE; lrt != NULL; lrt = lrt->prev)
361                                         count += lrt->used;
362                                 log_println("added localref %p for %p (total count %d)", h, o, count);
363                                 /*localref_dump();*/
364                         }
365 #endif
366
367                         return h;
368                 }
369         }
370
371         /* this should not happen */
372
373         log_println("localref_add: WARNING: unable to add localref for %p", o);
374
375         return NULL;
376 }
377
378
379 /* localref_del ****************************************************************
380
381    Deletes an entry from the local reference table.
382
383 *******************************************************************************/
384
385 void localref_del(java_handle_t *localref)
386 {
387         localref_table *lrt;
388         java_handle_t  *h;
389         int32_t         localframes;
390         int32_t         i;
391
392         /* get local reference table from thread */
393
394         lrt = LOCALREFTABLE;
395
396         assert(lrt != NULL);
397
398         localframes = lrt->localframes;
399
400         /* go through all local frames of the current table */
401         /* XXX: this is propably not what the spec wants! */
402
403         for (; localframes > 0; localframes--) {
404
405                 /* and try to remove the reference */
406     
407                 for (i = 0; i < lrt->capacity; i++) {
408 #if defined(ENABLE_HANDLES)
409                         h = (java_handle_t *) &(lrt->refs[i]);
410 #else
411                         h = (java_handle_t *) lrt->refs[i];
412 #endif
413
414                         if (h == localref) {
415                                 lrt->refs[i] = NULL;
416                                 lrt->used--;
417
418                                 return;
419                         }
420                 }
421
422                 lrt = lrt->prev;
423         }
424
425         /* this should not happen */
426
427         log_println("localref_del: WARNING: unable to find localref %p", localref);
428 }
429
430
431 /* localref_native_enter *******************************************************
432
433    Insert arguments to a native method into the local reference table.
434    This is done by the native stub through codegen_start_native_call.
435
436 *******************************************************************************/
437
438 void localref_native_enter(methodinfo *m, uint64_t *argument_regs, uint64_t *argument_stack)
439 {
440         localref_table *lrt;
441         methoddesc     *md;
442         imm_union       arg;
443         java_handle_t  *h;
444         int i;
445
446         /* get local reference table from thread */
447
448         lrt = LOCALREFTABLE;
449
450         assert(lrt != NULL);
451         assert(m != NULL);
452
453         md = m->parseddesc;
454
455         /* walk through all parameters to the method */
456
457         for (i = 0; i < md->paramcount; ++i) {
458                 /* load TYPE_ADR parameters ... */
459
460                 if (md->paramtypes[i].type == TYPE_ADR) {
461                         arg = argument_jitarray_load(md, i, argument_regs, argument_stack);
462
463                         if (arg.a == NULL)
464                                 continue;
465
466                         /* ... and insert them into the table */
467
468                         h = localref_add((java_object_t *) arg.a);
469
470 #if defined(ENABLE_HANDLES)
471                         /* update the modified parameter if necesarry */
472
473                         arg.a = (void *) h;
474                         argument_jitarray_store(md, i, argument_regs, argument_stack, arg);
475 #endif
476                 }
477         }
478 }
479
480
481 /* localref_native_exit ********************************************************
482
483    Undo the wrapping of the return value of a native method. This is
484    done by the native stub through codegen_finish_native_call.
485
486    NOTE: This function is only useful if handles are enabled.
487
488 *******************************************************************************/
489
490 #if defined(ENABLE_HANDLES)
491 void localref_native_exit(methodinfo *m, uint64_t *return_regs)
492 {
493         localref_table *lrt;
494         methoddesc     *md;
495         imm_union       ret;
496         java_handle_t  *h;
497
498         /* get local reference table from thread */
499
500         lrt = LOCALREFTABLE;
501
502         assert(lrt != NULL);
503         assert(m != NULL);
504
505         md = m->parseddesc;
506
507         /* load TYPE_ADR return values ... */
508
509         if (md->returntype.type == TYPE_ADR) {
510                 ret = argument_jitreturn_load(md, return_regs);
511
512                 if (ret.a == NULL)
513                         return;
514
515                 h = (java_handle_t *) ret.a;
516
517                 /* update the modified return valie */
518
519                 ret.a = (void *) h->heap_object;
520                 argument_jitreturn_store(md, return_regs, ret);
521
522 #if !defined(NDEBUG)
523                 /* removing the entry from the local reference table is not really
524                    necesarry, but gives us warnings if the entry does not exist. */
525
526                 localref_del(h);
527 #endif
528         }
529 }
530 #endif /* defined(ENABLE_HANDLES) */
531
532
533 /* localref_dump ***************************************************************
534
535    Dumps all local reference tables, including all frames.
536
537 *******************************************************************************/
538
539 #if !defined(NDEBUG)
540 # define LOCALREF_DUMP_REFS_PER_LINE 4
541 void localref_dump()
542 {
543         localref_table *lrt;
544         int i, j;
545
546         /* get current local reference table from thread */
547
548         lrt = LOCALREFTABLE;
549
550         log_println("--------- Local Reference Tables Dump ---------");
551
552         while (lrt != NULL) {
553                 log_println("Frame #%d, Used=%d, Capacity=%d, Addr=%p:", lrt->localframes, lrt->used, lrt->capacity, (void *) lrt);
554
555                         if (lrt->used != 0) {
556
557                                 log_start();
558
559                                 j = 0;
560                                 for (i = 0; i < lrt->capacity; i++) {
561                                         if (lrt->refs[i] != NULL) {
562                                                 if (j != 0 && j % LOCALREF_DUMP_REFS_PER_LINE == 0) {
563                                                         log_finish();
564                                                         log_start();
565                                                 }
566                                                 j++;
567                                                 log_print("\t0x%016lx ", (intptr_t) lrt->refs[i]);
568                                         }
569                                 }
570
571                                 log_finish();
572                         }
573
574                 lrt = lrt->prev;
575         }
576 }
577 #endif /* !defined(NDEBUG) */
578
579
580 /*
581  * These are local overrides for various environment variables in Emacs.
582  * Please do not remove this and leave it at the end of the file, where
583  * Emacs will automagically detect them.
584  * ---------------------------------------------------------------------
585  * Local variables:
586  * mode: c
587  * indent-tabs-mode: t
588  * c-basic-offset: 4
589  * tab-width: 4
590  * End:
591  * vim:noexpandtab:sw=4:ts=4:
592  */