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