CACAO
localref.cpp
Go to the documentation of this file.
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 
82 {
83  localref_table *lrt;
84 
85  TRACESUBSYSTEMINITIALIZATION("localref_table_init");
86 
87  assert(LOCALREFTABLE == NULL);
88 
89 #if !defined(ENABLE_GC_BOEHM)
90  /* this is freed by localref_table_destroy */
92 #else
93  /* this does not need to be freed again */
95 #endif
96 
97  if (lrt == NULL)
98  return false;
99 
100  localref_table_add(lrt);
101 
102  DEBUGLOCALREF("table init", -1);
103 
104  return true;
105 }
106 
107 
108 /* localref_table_destroy ******************************************************
109 
110  Destroys the complete local references table of the current thread.
111 
112 *******************************************************************************/
113 
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  DEBUGLOCALREF("table destroy", -1);
125 
126 #if !defined(ENABLE_GC_BOEHM)
127  FREE(lrt, localref_table);
128 #endif
129 
130  LOCALREFTABLE = NULL;
131 
132  return true;
133 }
134 
135 
136 /* localref_table_add **********************************************************
137 
138  Adds a new local references table to the current thread.
139 
140 *******************************************************************************/
141 
143 {
144  /* initialize the local reference table */
145 
147  lrt->used = 0;
148  lrt->localframes = 1;
149  lrt->prev = LOCALREFTABLE;
150 
151  lrt->hwm = 0;
152  lrt->firstfree = -1;
153 
154  /* add given local references table to this thread */
155 
156  LOCALREFTABLE = lrt;
157 
158  /*DEBUGLOCALREF("table add", -1);*/
159 }
160 
161 
162 /* localref_table_remove *******************************************************
163 
164  Removes the topmost local references table from the current thread.
165 
166 *******************************************************************************/
167 
169 {
170  localref_table *lrt;
171 
172 #if !defined(NDEBUG)
173  /* check for uncleared local references */
174 
176 #endif
177 
178  /* get current local reference table from thread */
179 
180  lrt = LOCALREFTABLE;
181  assert(lrt != NULL);
182  assert(lrt->localframes == 1);
183 
184  /*DEBUGLOCALREF("table remove", -1);*/
185 
186  lrt = lrt->prev;
187 
188  LOCALREFTABLE = lrt;
189 }
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 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  lrt = LOCALREFTABLE;
208  assert(lrt != NULL);
209  assert(capacity > 0);
210 
211  /* Allocate new local reference table on Java heap. Calculate the
212  additional memory we have to allocate. */
213 
214  if (capacity > LOCALREFTABLE_CAPACITY)
215  additionalrefs = capacity - LOCALREFTABLE_CAPACITY;
216  else
217  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  GCMNEW(u1, sizeof(localref_table) + additionalrefs * SIZEOF_VOID_P);
225 #endif
226 
227  if (nlrt == NULL)
228  return false;
229 
230  /* Set up the new local reference table and add it to the local
231  frames chain. */
232 
233  nlrt->capacity = capacity;
234  nlrt->used = 0;
235  nlrt->localframes = lrt->localframes + 1;
236  nlrt->prev = lrt;
237 
238  /* store new local reference table in thread */
239 
240  LOCALREFTABLE = nlrt;
241 
242  DEBUGLOCALREF("frame push", -1);
243 
244  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 
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  lrt = LOCALREFTABLE;
266  assert(lrt != NULL);
267 
268  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  if (localframes == 1)
275  return;
276 
277  /* release all current local frames */
278 
279  for (; localframes > 1; localframes--) {
280  /* get previous frame */
281 
282  plrt = lrt->prev;
283 
284  DEBUGLOCALREF("frame pop", -1);
285 
286  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  lrt = plrt;
303  }
304 
305  /* store new local reference table in thread */
306 
307  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 
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  lrt = LOCALREFTABLE;
327  assert(lrt != NULL);
328  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  if (lrt->used == lrt->capacity) {
336  if (!localref_frame_push(64))
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  i = lrt->hwm;
347  if (i == lrt->capacity) {
348  if (lrt->firstfree >= 0) {
349  i = lrt->firstfree;
350  lrt->firstfree = lrt->refs[i].nextfree;
351  }
352  else {
353  /* this should not happen */
354 
355  log_println("localref_add: WARNING: unable to add localref for %p", o);
356 
357  return NULL;
358  }
359  } else
360  lrt->hwm++;
361 
362  lrt->refs[i].ptr = o;
363  lrt->used++;
364 
365 #if defined(ENABLE_HANDLES)
366  h = (java_handle_t *) &(lrt->refs[i].ptr);
367 #else
368  h = (java_handle_t *) o;
369 #endif
370 
371  /*DEBUGLOCALREF("entry add", i);*/
372 
373  return h;
374 }
375 
376 
377 /* localref_del ****************************************************************
378 
379  Deletes an entry from the local reference table.
380 
381 *******************************************************************************/
382 
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  lrt = LOCALREFTABLE;
393  assert(lrt != NULL);
394  assert(localref != NULL);
395 
396  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  for (; localframes > 0; localframes--) {
402 
403  /* and try to remove the reference */
404 
405  for (i = 0; i < lrt->hwm; i++) {
406 #if defined(ENABLE_HANDLES)
407  h = (java_handle_t *) &(lrt->refs[i].ptr);
408 #else
409  h = (java_handle_t *) lrt->refs[i].ptr;
410 #endif
411 
412  if (h == localref) {
413  DEBUGLOCALREF("entry delete", i);
414 
415  lrt->refs[i].nextfree = lrt->firstfree;
416  lrt->firstfree = i;
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  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  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 #if !defined(ENABLE_HANDLES)
468  /* ... and insert them into the table */
469 
470  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 }
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
546 {
547  localref_table *lrt, dlrt;
548  int i, j;
549 
550  /* get current local reference table from thread */
551 
552  lrt = LOCALREFTABLE;
553 
554  log_println("--------- Local Reference Tables Dump ---------");
555 
556  while (lrt != NULL) {
557  log_println("Frame #%d, Used=%d, Capacity=%d, Hwm=%d, Addr=%p:", lrt->localframes, lrt->used, lrt->capacity, lrt->hwm, (void *) lrt);
558 
559  if (lrt->used != 0) {
560 
561  dlrt = *lrt; // copy it for dumping
562  for (i = dlrt.firstfree; i >= 0; i = j) {
563  j = dlrt.refs[i].nextfree;
564  dlrt.refs[i].ptr = NULL;
565  }
566 
567  log_start();
568 
569  j = 0;
570  for (i = 0; i < dlrt.hwm; i++) {
571  if (dlrt.refs[i].ptr != NULL) {
572  if (j != 0 && j % LOCALREF_DUMP_REFS_PER_LINE == 0) {
573  log_finish();
574  log_start();
575  }
576  j++;
577  log_print("\t0x%016lx ", (intptr_t) dlrt.refs[i].ptr);
578  }
579  }
580 
581  log_finish();
582  }
583 
584  lrt = lrt->prev;
585  }
586 }
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)
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  lrt = LOCALREFTABLE;
608  assert(lrt != NULL);
609  assert(lrt->localframes > 0);
610 
611  localframes = lrt->localframes;
612  lrt_uncleared = 0;
613  lrt_used = 0;
614 
615  for (; localframes > 0; localframes--) {
616  lrt_used += lrt->used;
617 
618  lrt_uncleared += lrt->hwm;
619  for (i = lrt->firstfree; i >= 0; i = lrt->refs[i].nextfree)
620  lrt_uncleared--;
621 
622  lrt = lrt->prev;
623  }
624 
625  if (lrt_uncleared != lrt_used) {
626  localref_dump();
627  vm_abort("localref_check_uncleared: (uncleared=%d) != (used=%d)", lrt_uncleared, lrt_used);
628  }
629 
630  if (lrt_uncleared <= 1)
631  return true;
632  else {
633  /*log_println("localref_check_uncleared: %d uncleared local references", lrt_uncleared);*/
634  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  */
bool localref_table_init(void)
Definition: localref.cpp:81
void localref_del(java_handle_t *localref)
Definition: localref.cpp:383
#define GCMNEW(type, num)
Definition: memory.hpp:118
imm_union argument_jitreturn_load(methoddesc *md, uint64_t *return_regs)
Definition: argument.cpp:153
void localref_native_exit(methodinfo *m, uint64_t *return_regs)
#define GCNEW(type)
Definition: memory.hpp:117
#define NEW(type)
Definition: memory.hpp:93
imm_union argument_jitarray_load(methoddesc *md, int32_t index, uint64_t *arg_regs, uint64_t *stack)
Definition: argument.cpp:57
void * a
Definition: global.hpp:58
#define FREE(ptr, type)
Definition: memory.hpp:94
void localref_table_remove()
Definition: localref.cpp:168
void localref_native_enter(methodinfo *m, uint64_t *argument_regs, uint64_t *argument_stack)
Definition: localref.cpp:439
void argument_jitarray_store(methoddesc *md, int32_t index, uint64_t *arg_regs, uint64_t *stack, imm_union param)
Definition: argument.cpp:120
java_object_t * ptr
Definition: localref.hpp:59
uint8_t u1
Definition: types.hpp:40
void log_finish(void)
Definition: logging.cpp:117
void log_println(const char *text,...)
Definition: logging.cpp:193
#define TRACESUBSYSTEMINITIALIZATION(text)
Definition: options.hpp:258
void vm_abort(const char *text,...)
Definition: vm.cpp:2586
bool localref_frame_push(int32_t capacity)
Definition: localref.cpp:199
typedesc paramtypes[1]
Definition: descriptor.hpp:167
void log_print(const char *text,...)
Definition: logging.cpp:149
JNIEnv void * arg
Definition: jvmti.h:405
java_handle_t * localref_add(java_object_t *o)
Definition: localref.cpp:318
static bool localref_check_uncleared()
Definition: localref.cpp:597
bool localref_table_destroy(void)
Definition: localref.cpp:114
void localref_frame_pop_all(void)
Definition: localref.cpp:254
void log_start(void)
Definition: logging.cpp:106
MIIterator i
typedesc returntype
Definition: descriptor.hpp:166
void argument_jitreturn_store(methoddesc *md, uint64_t *return_regs, imm_union ret)
Definition: argument.cpp:191
#define DEBUGLOCALREF(message, index)
Definition: localref.cpp:52
void localref_dump()
Definition: localref.cpp:545
methoddesc * parseddesc
Definition: method.hpp:78
#define LOCALREFTABLE
Definition: localref.cpp:47
#define MNEW(type, num)
Definition: memory.hpp:96
#define LOCALREFTABLE_CAPACITY
Definition: localref.hpp:48
void localref_table_add(localref_table *lrt)
Definition: localref.cpp:142
union localref_table::@1 refs[LOCALREFTABLE_CAPACITY]
#define MFREE(ptr, type, num)
Definition: memory.hpp:97
#define LOCALREF_DUMP_REFS_PER_LINE
Definition: localref.cpp:544
localref_table * prev
Definition: localref.hpp:57