* src/vm/vm.c, src/vm/vm.h: Moved to .cpp.
[cacao.git] / src / native / localref.c
1 /* src/native/localref.c - Management of local reference tables
2
3    Copyright (C) 1996-2005, 2006, 2007, 2008
4    CACAOVM - Verein zur Foerderung der freien virtuellen Maschine CACAO
5
6    This file is part of CACAO.
7
8    This program is free software; you can redistribute it and/or
9    modify it under the terms of the GNU General Public License as
10    published by the Free Software Foundation; either version 2, or (at
11    your option) any later version.
12
13    This program is distributed in the hope that it will be useful, but
14    WITHOUT ANY WARRANTY; without even the implied warranty of
15    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16    General Public License for more details.
17
18    You should have received a copy of the GNU General Public License
19    along with this program; if not, write to the Free Software
20    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
21    02110-1301, USA.
22
23 */
24
25
26 #include "config.h"
27
28 #include <assert.h>
29 #include <stdint.h>
30
31 #include "mm/memory.h"
32
33 #include "native/localref.h"
34
35 #include "threads/thread.h"
36
37 #include "toolbox/logging.h"
38
39 #include "vm/vm.hpp"
40
41 #include "vm/jit/argument.h"
42
43 #include "vmcore/options.h"
44
45
46 /* debug **********************************************************************/
47
48 #if !defined(NDEBUG)
49 # define DEBUGLOCALREF(message, index) \
50         do { \
51                 if (opt_DebugLocalReferences) { \
52                         localref_table *dlrt = LOCALREFTABLE; \
53                         log_start(); \
54                         log_print("[local reference %-12s: lrt=%016p frame=%d capacity=%d used=%d", message, dlrt, dlrt->localframes, dlrt->capacity, dlrt->used); \
55                         if (index >= 0) \
56                                 log_print(" localref=%p object=%p", &(dlrt->refs[index]), dlrt->refs[index]); \
57                         log_print("]"); \
58                         log_finish(); \
59                 } \
60         } while (0)
61 #else
62 # define DEBUGLOCALREF(message, index)
63 #endif
64
65
66 /* global variables ***********************************************************/
67
68 #if !defined(ENABLE_THREADS)
69 localref_table *_no_threads_localref_table;
70 #endif
71
72
73 /* some forward declarations **************************************************/
74
75 #if !defined(NDEBUG)
76 static bool localref_check_uncleared();
77 #endif
78
79
80 /* localref_table_init *********************************************************
81
82    Initializes the local references table of the current thread.
83
84 *******************************************************************************/
85
86 bool localref_table_init(void)
87 {
88         localref_table *lrt;
89
90         TRACESUBSYSTEMINITIALIZATION("localref_table_init");
91
92         assert(LOCALREFTABLE == NULL);
93
94 #if !defined(ENABLE_GC_BOEHM)
95         /* this is freed by localref_table_destroy */
96         lrt = NEW(localref_table);
97 #else
98         /* this does not need to be freed again */
99         lrt = GCNEW(localref_table);
100 #endif
101
102         if (lrt == NULL)
103                 return false;
104
105         localref_table_add(lrt);
106
107         DEBUGLOCALREF("table init", -1);
108
109         return true;
110 }
111
112
113 /* localref_table_destroy ******************************************************
114
115    Destroys the complete local references table of the current thread.
116
117 *******************************************************************************/
118
119 bool localref_table_destroy(void)
120 {
121         localref_table *lrt;
122
123         lrt = LOCALREFTABLE;
124         assert(lrt != NULL);
125         assert(lrt->prev == NULL);
126
127         DEBUGLOCALREF("table destroy", -1);
128
129 #if !defined(ENABLE_GC_BOEHM)
130         FREE(lrt, localref_table);
131 #endif
132
133         LOCALREFTABLE = NULL;
134
135         return true;
136 }
137
138
139 /* localref_table_add **********************************************************
140
141    Adds a new local references table to the current thread.
142
143 *******************************************************************************/
144
145 void localref_table_add(localref_table *lrt)
146 {
147         /* initialize the local reference table */
148
149         lrt->capacity    = LOCALREFTABLE_CAPACITY;
150         lrt->used        = 0;
151         lrt->localframes = 1;
152         lrt->prev        = LOCALREFTABLE;
153
154         /* clear the references array (memset is faster the a for-loop) */
155
156         MSET(lrt->refs, 0, void*, LOCALREFTABLE_CAPACITY);
157
158         /* add given local references table to this thread */
159
160         LOCALREFTABLE = lrt;
161
162         /*DEBUGLOCALREF("table add", -1);*/
163 }
164
165
166 /* localref_table_remove *******************************************************
167
168    Removes the topmost local references table from the current thread.
169
170 *******************************************************************************/
171
172 void localref_table_remove()
173 {
174         localref_table *lrt;
175
176 #if !defined(NDEBUG)
177         /* check for uncleared local references */
178
179         localref_check_uncleared();
180 #endif
181
182         /* get current local reference table from thread */
183
184         lrt = LOCALREFTABLE;
185         assert(lrt != NULL);
186         assert(lrt->localframes == 1);
187
188         /*DEBUGLOCALREF("table remove", -1);*/
189
190         lrt = lrt->prev;
191
192         LOCALREFTABLE = lrt;
193 }
194
195
196 /* localref_frame_push *********************************************************
197
198    Creates a new local reference frame, in which at least a given
199    number of local references can be created.
200
201 *******************************************************************************/
202
203 bool localref_frame_push(int32_t capacity)
204 {
205         localref_table *lrt;
206         localref_table *nlrt;
207         int32_t         additionalrefs;
208
209         /* get current local reference table from thread */
210
211         lrt = LOCALREFTABLE;
212         assert(lrt != NULL);
213         assert(capacity > 0);
214
215         /* Allocate new local reference table on Java heap.  Calculate the
216            additional memory we have to allocate. */
217
218         if (capacity > LOCALREFTABLE_CAPACITY)
219                 additionalrefs = capacity - LOCALREFTABLE_CAPACITY;
220         else
221                 additionalrefs = 0;
222
223 #if !defined(ENABLE_GC_BOEHM)
224         nlrt = (localref_table *)
225                         MNEW(u1, sizeof(localref_table) + additionalrefs * SIZEOF_VOID_P);
226 #else
227         nlrt = (localref_table *)
228                         GCMNEW(u1, sizeof(localref_table) + additionalrefs * SIZEOF_VOID_P);
229 #endif
230
231         if (nlrt == NULL)
232                 return false;
233
234         /* Set up the new local reference table and add it to the local
235            frames chain. */
236
237         nlrt->capacity    = capacity;
238         nlrt->used        = 0;
239         nlrt->localframes = lrt->localframes + 1;
240         nlrt->prev        = lrt;
241
242         /* store new local reference table in thread */
243
244         LOCALREFTABLE = nlrt;
245
246         DEBUGLOCALREF("frame push", -1);
247
248         return true;
249 }
250
251
252 /* localref_frame_pop_all ******************************************************
253
254    Pops off all the local reference frames of the current table.
255
256 *******************************************************************************/
257
258 void localref_frame_pop_all(void)
259 {
260         localref_table *lrt;
261         localref_table *plrt;
262         int32_t         localframes;
263 #if !defined(ENABLE_GC_BOEHM)
264         int32_t         additionalrefs;
265 #endif
266
267         /* get current local reference table from thread */
268
269         lrt = LOCALREFTABLE;
270         assert(lrt != NULL);
271
272         localframes = lrt->localframes;
273
274         /* Don't delete the top local frame, as this one is allocated in
275            the native stub on the stack and is freed automagically on
276            return. */
277
278         if (localframes == 1)
279                 return;
280
281         /* release all current local frames */
282
283         for (; localframes > 1; localframes--) {
284                 /* get previous frame */
285
286                 plrt = lrt->prev;
287
288                 DEBUGLOCALREF("frame pop", -1);
289
290                 /* clear all reference entries */
291
292                 MSET(lrt->refs, 0, void*, lrt->capacity);
293
294                 lrt->prev = NULL;
295
296 #if !defined(ENABLE_GC_BOEHM)
297                 /* for the exact GC local reference tables are not on the heap,
298                    so we need to free them explicitly here. */
299
300                 if (lrt->capacity > LOCALREFTABLE_CAPACITY)
301                         additionalrefs = lrt->capacity - LOCALREFTABLE_CAPACITY;
302                 else
303                         additionalrefs = 0;
304
305                 MFREE(lrt, u1, sizeof(localref_table) + additionalrefs * SIZEOF_VOID_P);
306 #endif
307
308                 /* set new local references table */
309
310                 lrt = plrt;
311         }
312
313         /* store new local reference table in thread */
314
315         LOCALREFTABLE = lrt;
316 }
317
318
319 /* localref_add ****************************************************************
320
321    Adds a new entry into the local reference table and returns the
322    new local reference.
323
324 *******************************************************************************/
325
326 java_handle_t *localref_add(java_object_t *o)
327 {
328         localref_table *lrt;
329         java_handle_t  *h;
330         int32_t         i;
331
332         /* get current local reference table from thread */
333
334         lrt = LOCALREFTABLE;
335         assert(lrt != NULL);
336         assert(o != NULL);
337         /* XXX: assert that we are in a GC critical section! */
338
339         /* Check if we have space for the requested reference?  No,
340            allocate a new frame.  This is actually not what the spec says,
341            but for compatibility reasons... */
342
343     if (lrt->used == lrt->capacity) {
344                 if (!localref_frame_push(64))
345                         assert(0);
346
347                 /* get the new local reference table */ 
348
349                 lrt = LOCALREFTABLE;
350         }
351
352         /* insert the reference into the local reference table */
353
354         for (i = 0; i < lrt->capacity; i++) {
355                 if (lrt->refs[i] == NULL) {
356                         lrt->refs[i] = o;
357                         lrt->used++;
358
359 #if defined(ENABLE_HANDLES)
360                         h = (java_handle_t *) &(lrt->refs[i]);
361 #else
362                         h = (java_handle_t *) o;
363 #endif
364
365                         /*DEBUGLOCALREF("entry add", i);*/
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         assert(lrt != NULL);
396         assert(localref != 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                                 DEBUGLOCALREF("entry delete", i);
416
417                                 lrt->refs[i] = NULL;
418                                 lrt->used--;
419
420                                 return;
421                         }
422                 }
423
424                 lrt = lrt->prev;
425         }
426
427         /* this should not happen */
428
429         log_println("localref_del: WARNING: unable to find localref %p", localref);
430 }
431
432
433 /* localref_native_enter *******************************************************
434
435    Insert arguments to a native method into the local reference table.
436    This is done by the native stub through codegen_start_native_call.
437
438 *******************************************************************************/
439
440 void localref_native_enter(methodinfo *m, uint64_t *argument_regs, uint64_t *argument_stack)
441 {
442         localref_table *lrt;
443         methoddesc     *md;
444         imm_union       arg;
445         java_handle_t  *h;
446         int i;
447
448         /* get local reference table from thread */
449
450         lrt = LOCALREFTABLE;
451         assert(lrt != NULL);
452         assert(m != NULL);
453
454         md = m->parseddesc;
455
456         /* walk through all parameters to the method */
457
458         for (i = 0; i < md->paramcount; ++i) {
459                 /* load TYPE_ADR parameters ... */
460
461                 if (md->paramtypes[i].type == TYPE_ADR) {
462                         arg = argument_jitarray_load(md, i, argument_regs, argument_stack);
463
464                         if (arg.a == NULL)
465                                 continue;
466
467                         /* ... and insert them into the table */
468
469                         h = localref_add((java_object_t *) arg.a);
470
471 #if defined(ENABLE_HANDLES)
472                         /* update the modified parameter if necesarry */
473
474                         arg.a = (void *) h;
475                         argument_jitarray_store(md, i, argument_regs, argument_stack, arg);
476 #endif
477                 }
478         }
479 }
480
481
482 /* localref_native_exit ********************************************************
483
484    Undo the wrapping of the return value of a native method. This is
485    done by the native stub through codegen_finish_native_call.
486
487    NOTE: This function is only useful if handles are enabled.
488
489 *******************************************************************************/
490
491 #if defined(ENABLE_HANDLES)
492 void localref_native_exit(methodinfo *m, uint64_t *return_regs)
493 {
494         localref_table *lrt;
495         methoddesc     *md;
496         imm_union       ret;
497         java_handle_t  *h;
498
499         /* get local reference table from thread */
500
501         lrt = LOCALREFTABLE;
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) && 0
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 /* localref_check_uncleared ****************************************************
581
582    Checks the topmost local reference table for uncleared references.
583
584 *******************************************************************************/
585
586 #if !defined(NDEBUG)
587 static bool localref_check_uncleared()
588 {
589         localref_table *lrt;
590         int32_t         localframes;
591         int32_t         lrt_uncleared;
592         int32_t         lrt_used;
593         int i;
594
595         /* get current local reference table from thread */
596
597         lrt = LOCALREFTABLE;
598         assert(lrt != NULL);
599         assert(lrt->localframes > 0);
600
601         localframes   = lrt->localframes;
602         lrt_uncleared = 0;
603         lrt_used      = 0;
604
605         for (; localframes > 0; localframes--) {
606                 lrt_used += lrt->used;
607
608                 for (i = 0; i < lrt->capacity; i++) {
609                         if (lrt->refs[i] != NULL)
610                                 lrt_uncleared++;
611                 }
612
613                 lrt = lrt->prev;
614         }
615
616         if (lrt_uncleared != lrt_used) {
617                 localref_dump();
618                 vm_abort("localref_check_uncleared: (uncleared=%d) != (used=%d)", lrt_uncleared, lrt_used);
619         }
620
621         if (lrt_uncleared <= 1)
622                 return true;
623         else {
624                 /*log_println("localref_check_uncleared: %d uncleared local references", lrt_uncleared);*/
625                 return false;
626         }
627 }
628 #endif
629
630
631 /*
632  * These are local overrides for various environment variables in Emacs.
633  * Please do not remove this and leave it at the end of the file, where
634  * Emacs will automagically detect them.
635  * ---------------------------------------------------------------------
636  * Local variables:
637  * mode: c
638  * indent-tabs-mode: t
639  * c-basic-offset: 4
640  * tab-width: 4
641  * End:
642  * vim:noexpandtab:sw=4:ts=4:
643  */