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