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