* This is a rather huge commit, which changes the build order of
[cacao.git] / src / vmcore / method.c
1 /* src/vmcore/method.c - method functions
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    $Id: method.c 7246 2007-01-29 18:49:05Z twisti $
26
27 */
28
29
30 #include "config.h"
31
32 #include <assert.h>
33 #include <stdio.h>
34
35 #include "vm/types.h"
36
37 #include "mm/memory.h"
38
39 #include "vm/global.h"
40
41 #include "vm/jit/methodheader.h"
42
43 #include "vmcore/class.h"
44 #include "vmcore/linker.h"
45 #include "vmcore/loader.h"
46 #include "vmcore/method.h"
47 #include "vmcore/options.h"
48
49
50 #if !defined(NDEBUG) && defined(ENABLE_INLINING)
51 extern bool inline_debug_log;
52 #define INLINELOG(code)  do { if (inline_debug_log) { code } } while (0)
53 #else
54 #define INLINELOG(code)
55 #endif
56
57
58 /* method_free *****************************************************************
59
60    Frees all memory that was allocated for this method.
61
62 *******************************************************************************/
63
64 void method_free(methodinfo *m)
65 {
66         if (m->jcode)
67                 MFREE(m->jcode, u1, m->jcodelength);
68
69         if (m->rawexceptiontable)
70                 MFREE(m->rawexceptiontable, raw_exception_entry, m->rawexceptiontablelength);
71
72         code_free_code_of_method(m);
73
74         if (m->stubroutine) {
75                 if (m->flags & ACC_NATIVE) {
76                         removenativestub(m->stubroutine);
77
78                 } else {
79                         removecompilerstub(m->stubroutine);
80                 }
81         }
82 }
83
84
85 /* method_canoverwrite *********************************************************
86
87    Check if m and old are identical with respect to type and
88    name. This means that old can be overwritten with m.
89         
90 *******************************************************************************/
91
92 bool method_canoverwrite(methodinfo *m, methodinfo *old)
93 {
94         if (m->name != old->name)
95                 return false;
96
97         if (m->descriptor != old->descriptor)
98                 return false;
99
100         if (m->flags & ACC_STATIC)
101                 return false;
102
103         return true;
104 }
105
106
107 /* method_vftbl_lookup *********************************************************
108
109    Does a method lookup in the passed virtual function table.  This
110    function does exactly the same thing as JIT, but additionally
111    relies on the fact, that the methodinfo pointer is at the first
112    data segment slot (even for compiler stubs).
113
114 *******************************************************************************/
115
116 methodinfo *method_vftbl_lookup(vftbl_t *vftbl, methodinfo* m)
117 {
118         methodptr   mptr;
119         methodptr  *pmptr;
120         methodinfo *resm;                   /* pointer to new resolved method     */
121         codeinfo   *code;
122
123         /* If the method is not an instance method, just return it. */
124
125         if (m->flags & ACC_STATIC)
126                 return m;
127
128         assert(vftbl);
129
130         /* Get the method from the virtual function table.  Is this an
131            interface method? */
132
133         if (m->class->flags & ACC_INTERFACE) {
134                 pmptr = vftbl->interfacetable[-(m->class->index)];
135                 mptr  = pmptr[(m - m->class->methods)];
136         }
137         else {
138                 mptr = vftbl->table[m->vftblindex];
139         }
140
141         /* and now get the codeinfo pointer from the first data segment slot */
142
143         code = *((codeinfo **) (mptr + CodeinfoPointer));
144
145         resm = code->m;
146
147         return resm;
148 }
149
150
151 /* method_count_implementations ************************************************
152
153    Count the implementations of a method in a class cone (a class and all its
154    subclasses.)
155
156    IN:
157        m................the method to count
158            c................class at which to start the counting (this class and
159                             all its subclasses will be searched)
160
161    OUT:
162        *found...........if found != NULL, *found receives the method
163                             implementation that was found. This value is only
164                                                 meaningful if the return value is 1.
165
166    RETURN VALUE:
167        the number of implementations found
168
169 *******************************************************************************/
170
171 s4 method_count_implementations(methodinfo *m, classinfo *c, methodinfo **found)
172 {
173         s4          count;
174         methodinfo *mp;
175         methodinfo *mend;
176         classinfo  *child;
177
178         count = 0;
179
180         mp = c->methods;
181         mend = mp + c->methodscount;
182
183         for (; mp < mend; ++mp) {
184                 if (method_canoverwrite(mp, m)) {
185                         if (found)
186                                 *found = mp;
187                         count++;
188                         break;
189                 }
190         }
191
192         for (child = c->sub; child != NULL; child = child->nextsub) {
193                 count += method_count_implementations(m, child, found);
194         }
195
196         return count;
197 }
198
199
200 /* method_add_to_worklist ******************************************************
201
202    Add the method to the given worklist. If the method already occurs in
203    the worklist, the worklist remains unchanged.
204
205 *******************************************************************************/
206
207 static void method_add_to_worklist(methodinfo *m, method_worklist **wl)
208 {
209         method_worklist *wi;
210
211         for (wi = *wl; wi != NULL; wi = wi->next)
212                 if (wi->m == m)
213                         return;
214
215         wi = NEW(method_worklist);
216         wi->next = *wl;
217         wi->m = m;
218
219         *wl = wi;
220 }
221
222
223 /* method_add_assumption_monomorphic *******************************************
224
225    Record the assumption that the method is monomorphic.
226
227    IN:
228       m.................the method
229           caller............the caller making the assumption
230
231 *******************************************************************************/
232
233 void method_add_assumption_monomorphic(methodinfo *m, methodinfo *caller)
234 {
235         method_assumption *as;
236
237         /* XXX LOCKING FOR THIS FUNCTION? */
238
239         /* check if we already have registered this assumption */
240
241         for (as = m->assumptions; as != NULL; as = as->next) {
242                 if (as->context == caller)
243                         return;
244         }
245
246         /* register the assumption */
247
248         as = NEW(method_assumption);
249         as->next = m->assumptions;
250         as->context = caller;
251
252         m->assumptions = as;
253 }
254
255
256 /* method_break_assumption_monomorphic *****************************************
257
258    Break the assumption that this method is monomorphic. All callers that
259    have registered this assumption are added to the worklist.
260
261    IN:
262       m.................the method
263           wl................worklist where to add invalidated callers
264
265 *******************************************************************************/
266
267 void method_break_assumption_monomorphic(methodinfo *m, method_worklist **wl)
268 {
269         method_assumption *as;
270
271         /* XXX LOCKING FOR THIS FUNCTION? */
272
273         for (as = m->assumptions; as != NULL; as = as->next) {
274                 INLINELOG(
275                         printf("ASSUMPTION BROKEN (monomorphism): ");
276                         method_print(m);
277                         printf(" in ");
278                         method_println(as->context);
279                 );
280
281                 method_add_to_worklist(as->context, wl);
282         }
283 }
284
285
286 /* method_printflags ***********************************************************
287
288    Prints the flags of a method to stdout like.
289
290 *******************************************************************************/
291
292 #if !defined(NDEBUG)
293 void method_printflags(methodinfo *m)
294 {
295         if (m == NULL) {
296                 printf("NULL");
297                 return;
298         }
299
300         if (m->flags & ACC_PUBLIC)       printf(" PUBLIC");
301         if (m->flags & ACC_PRIVATE)      printf(" PRIVATE");
302         if (m->flags & ACC_PROTECTED)    printf(" PROTECTED");
303         if (m->flags & ACC_STATIC)       printf(" STATIC");
304         if (m->flags & ACC_FINAL)        printf(" FINAL");
305         if (m->flags & ACC_SYNCHRONIZED) printf(" SYNCHRONIZED");
306         if (m->flags & ACC_VOLATILE)     printf(" VOLATILE");
307         if (m->flags & ACC_TRANSIENT)    printf(" TRANSIENT");
308         if (m->flags & ACC_NATIVE)       printf(" NATIVE");
309         if (m->flags & ACC_INTERFACE)    printf(" INTERFACE");
310         if (m->flags & ACC_ABSTRACT)     printf(" ABSTRACT");
311         if (m->flags & ACC_METHOD_MONOMORPHIC) printf(" (mono)");
312         if (m->flags & ACC_METHOD_IMPLEMENTED) printf(" (impl)");
313 }
314 #endif /* !defined(NDEBUG) */
315
316
317 /* method_print ****************************************************************
318
319    Prints a method to stdout like:
320
321    java.lang.Object.<init>()V
322
323 *******************************************************************************/
324
325 #if !defined(NDEBUG)
326 void method_print(methodinfo *m)
327 {
328         if (m == NULL) {
329                 printf("NULL");
330                 return;
331         }
332
333         utf_display_printable_ascii_classname(m->class->name);
334         printf(".");
335         utf_display_printable_ascii(m->name);
336         utf_display_printable_ascii(m->descriptor);
337
338         method_printflags(m);
339 }
340 #endif /* !defined(NDEBUG) */
341
342
343 /* method_println **************************************************************
344
345    Prints a method plus new line to stdout like:
346
347    java.lang.Object.<init>()V
348
349 *******************************************************************************/
350
351 #if !defined(NDEBUG)
352 void method_println(methodinfo *m)
353 {
354         if (opt_debugcolor) printf("\033[31m"); /* red */
355         method_print(m);
356         if (opt_debugcolor) printf("\033[m");   
357         printf("\n");
358 }
359 #endif /* !defined(NDEBUG) */
360
361
362 /* method_methodref_print ******************************************************
363
364    Prints a method reference to stdout.
365
366 *******************************************************************************/
367
368 #if !defined(NDEBUG)
369 void method_methodref_print(constant_FMIref *mr)
370 {
371         if (!mr) {
372                 printf("(constant_FMIref *)NULL");
373                 return;
374         }
375
376         if (IS_FMIREF_RESOLVED(mr)) {
377                 printf("<method> ");
378                 method_print(mr->p.method);
379         }
380         else {
381                 printf("<methodref> ");
382                 utf_display_printable_ascii_classname(mr->p.classref->name);
383                 printf(".");
384                 utf_display_printable_ascii(mr->name);
385                 utf_display_printable_ascii(mr->descriptor);
386         }
387 }
388 #endif /* !defined(NDEBUG) */
389
390
391 /* method_methodref_println ****************************************************
392
393    Prints a method reference to stdout, followed by a newline.
394
395 *******************************************************************************/
396
397 #if !defined(NDEBUG)
398 void method_methodref_println(constant_FMIref *mr)
399 {
400         method_methodref_print(mr);
401         printf("\n");
402 }
403 #endif /* !defined(NDEBUG) */
404
405
406 /*
407  * These are local overrides for various environment variables in Emacs.
408  * Please do not remove this and leave it at the end of the file, where
409  * Emacs will automagically detect them.
410  * ---------------------------------------------------------------------
411  * Local variables:
412  * mode: c
413  * indent-tabs-mode: t
414  * c-basic-offset: 4
415  * tab-width: 4
416  * End:
417  * vim:noexpandtab:sw=4:ts=4:
418  */