* src/threads/native/threads.h: Added THREAD_FLAG_IN_NATIVE and gc_critical.
[cacao.git] / src / cacaoh / headers.c
1 /* src/cacaoh/headers.c - functions for header generation
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: headers.c 7486 2007-03-08 13:50:07Z twisti $
26
27 */
28
29
30 #include "config.h"
31
32 #include <assert.h>
33 #include <ctype.h>
34 #include <stdarg.h>
35 #include <stdlib.h>
36 #include <string.h>
37
38 #include "vm/types.h"
39
40 #if defined(ENABLE_THREADS)
41 # if defined(__DARWIN__)
42 #  include <signal.h>
43 # endif
44 # include <ucontext.h>
45 #endif
46
47 #include "mm/gc-common.h"
48 #include "mm/memory.h"
49
50 #include "toolbox/chain.h"
51 #include "toolbox/logging.h"
52
53 #include "vm/builtin.h"
54 #include "vm/global.h"
55 #include "vm/stringlocal.h"
56
57 #include "vmcore/class.h"
58 #include "vmcore/method.h"
59 #include "vmcore/loader.h"
60 #include "vmcore/options.h"
61
62
63 /************************ global variables **********************/
64
65 #define ACC_NATIVELY_OVERLOADED    0x10000000
66
67 chain *ident_chain;     /* chain with method and field names in current class */
68 FILE *file = NULL;
69 static u4 outputsize;
70 static bool dopadding;
71
72
73 static void printIDpart(int c)
74 {
75         if ((c >= 'a' && c <= 'z') ||
76                 (c >= 'A' && c <= 'Z') ||
77                 (c >= '0' && c <= '9') ||
78                 (c == '_'))
79                 putc(c, file);
80         else
81                 putc('_', file);
82 }
83
84
85 void printID(utf *u)
86 {
87         char *utf_ptr = u->text;
88         int i;
89
90         for (i = 0; i < utf_get_number_of_u2s(u); i++) 
91                 printIDpart(utf_nextu2(&utf_ptr));
92 }
93
94
95 static void addoutputsize (int len)
96 {
97         u4 newsize,i;
98         if (!dopadding) return;
99
100         newsize = MEMORY_ALIGN(outputsize, len);
101         
102         for (i = outputsize; i < newsize; i++) fprintf(file, "   u1 pad%d\n", (int) i);
103         outputsize = newsize;
104 }
105
106
107 void printOverloadPart(utf *desc)
108 {
109         char *utf_ptr=desc->text;
110         u2 c;
111
112         fprintf(file, "__");
113
114         while ((c = utf_nextu2(&utf_ptr)) != ')') {
115                 switch (c) {
116                 case 'I':
117                 case 'S':
118                 case 'B':
119                 case 'C':
120                 case 'Z':
121                 case 'J':
122                 case 'F':
123                 case 'D': 
124                         fprintf(file, "%c", (char) c);
125                         break;
126                 case '[':
127                         fprintf(file, "_3");
128                         break;
129                 case 'L':
130                         putc('L', file);
131                         while ((c = utf_nextu2(&utf_ptr)) != ';')
132                                 printIDpart(c);
133                         fprintf(file, "_2");
134                         break;
135                 case '(':
136                         break;
137                 default: 
138                         log_text("invalid method descriptor");
139                         assert(0);
140                 }
141         }
142 }
143
144 static char *printtype(char *utf_ptr)
145 {
146         u2 c;
147
148         switch (utf_nextu2(&utf_ptr)) {
149         case 'V': fprintf (file, "void");
150                 break;
151         case 'I':
152         case 'S':
153         case 'B':
154         case 'C':
155         case 'Z': addoutputsize (4);
156                 fprintf (file, "s4");
157                 break;
158         case 'J': addoutputsize (8);
159                 fprintf (file, "s8");
160                 break;
161         case 'F': addoutputsize (4);
162                 fprintf (file, "float");
163                 break;
164         case 'D': addoutputsize (8);
165                 fprintf (file, "double");
166                 break;
167         case '[':
168                 addoutputsize ( sizeof(java_arrayheader*) ); 
169                 switch (utf_nextu2(&utf_ptr)) {
170                 case 'I':  fprintf (file, "java_intarray*"); break;
171                 case 'J':  fprintf (file, "java_longarray*"); break;
172                 case 'Z':  fprintf (file, "java_booleanarray*"); break;
173                 case 'B':  fprintf (file, "java_bytearray*"); break;
174                 case 'S':  fprintf (file, "java_shortarray*"); break;
175                 case 'C':  fprintf (file, "java_chararray*"); break;
176                 case 'F':  fprintf (file, "java_floatarray*"); break;
177                 case 'D':  fprintf (file, "java_doublearray*"); break;
178                                 
179                 case '[': fprintf(file, "java_objectarray*");
180                         while ((c = utf_nextu2(&utf_ptr)) == '[');
181                         if (c == 'L')
182                                 while (utf_nextu2(&utf_ptr) != ';');
183                         break;
184                            
185                 case 'L':  fprintf(file, "java_objectarray*");
186                         while (utf_nextu2(&utf_ptr) != ';');
187                         break;
188                 default:
189                         log_text("invalid type descriptor");
190                         assert(0);
191                 }
192                 break;
193                 
194         case 'L': 
195                 addoutputsize ( sizeof(java_objectheader*));
196                 fprintf (file, "struct ");
197                 while ( (c = utf_nextu2(&utf_ptr)) != ';' ) printIDpart (c);     
198                 fprintf (file, "*");
199                 break;
200                                         
201         default:
202                 log_text("Unknown type in field descriptor");
203                 assert(0);
204         }
205         
206         return utf_ptr;
207 }
208
209
210 /***** determine the number of entries of a utf string in the ident chain *****/
211
212 static int searchidentchain_utf(utf *ident) 
213 {
214         utf *u = chain_first(ident_chain);     /* first element of list */
215         int count = 0;
216
217         while (u) {
218                 if (u==ident) count++;         /* string found */
219                 u = chain_next(ident_chain);   /* next element in list */ 
220         }
221
222         return count;
223 }
224
225
226 /************** print structure for direct access to objects ******************/
227
228 static void printfields(classinfo *c)
229 {
230         u4 i;
231         fieldinfo *f;
232         int ident_count;
233         
234         if (!c) {
235                 addoutputsize(sizeof(java_objectheader));
236                 fprintf(file, "   java_objectheader header;\n");
237                 return;
238         }
239                 
240         printfields(c->super.cls);
241         
242         for (i = 0; i < c->fieldscount; i++) {
243                 f = &(c->fields[i]);
244                 
245                 if (!(f->flags & ACC_STATIC)) {
246                         fprintf(file, "   ");
247                         printtype(f->descriptor->text);
248                         fprintf(file, " ");
249                         utf_fprint_printable_ascii(file, f->name);
250
251                         /* rename multiple fieldnames */
252                         if ((ident_count = searchidentchain_utf(f->name)))
253                                 fprintf(file, "%d", ident_count - 1);
254                         chain_addlast(ident_chain, f->name);    
255
256                         fprintf(file, ";\n");
257                 }
258         }
259 }
260
261
262 /***************** store prototype for native method in file ******************/
263
264 void printmethod(methodinfo *m)
265 {
266         char *utf_ptr;
267         u2 paramnum = 1;
268
269         /* search for return-type in descriptor */      
270         utf_ptr = m->descriptor->text;
271         while (utf_nextu2(&utf_ptr) != ')');
272
273         /* create remarks */
274         fprintf(file, "\n/*\n * Class:     ");
275         utf_fprint_printable_ascii(file, m->class->name);
276         fprintf(file, "\n * Method:    ");
277         utf_fprint_printable_ascii(file, m->name);
278         fprintf(file, "\n * Signature: ");
279         utf_fprint_printable_ascii(file, m->descriptor);
280         fprintf(file, "\n */\n");
281
282         /* create prototype */                  
283         fprintf(file, "JNIEXPORT ");
284         printtype(utf_ptr);
285         fprintf(file, " JNICALL Java_");
286         printID(m->class->name);
287
288         chain_addlast(ident_chain, m->name);
289
290         fprintf(file, "_");
291         printID(m->name);
292
293         /* ATTENTION: We use a dummy flag here. */
294
295         if (m->flags & ACC_NATIVELY_OVERLOADED)
296                 printOverloadPart(m->descriptor);
297
298         fprintf(file, "(JNIEnv *env");
299         
300         utf_ptr = m->descriptor->text + 1;
301                         
302         if (!(m->flags & ACC_STATIC)) {
303                 fprintf(file, ", struct ");
304                 printID(m->class->name);
305                 fprintf(file, "* this");
306
307         } else {
308                 fprintf(file, ", jclass clazz");
309         }
310
311         if ((*utf_ptr) != ')') fprintf(file, ", ");
312                         
313         while ((*utf_ptr) != ')') {
314                 utf_ptr = printtype(utf_ptr);
315                 fprintf(file, " par%d", paramnum++);
316                 if ((*utf_ptr)!=')') fprintf(file, ", ");
317         }
318                         
319         fprintf(file, ");\n\n");
320 }
321
322
323 /******* remove package-name in fully-qualified classname *********************/
324
325 void gen_header_filename(char *buffer, utf *u)
326 {
327         s4 i;
328   
329         for (i = 0; i < utf_get_number_of_u2s(u); i++) {
330                 if ((u->text[i] == '/') || (u->text[i] == '$')) {
331                         buffer[i] = '_';  /* convert '$' and '/' to '_' */
332
333                 } else {
334                         buffer[i] = u->text[i];
335                 }
336         }
337         buffer[utf_get_number_of_u2s(u)] = '\0';
338 }
339
340
341 /* create headerfile for classes and store native methods in chain ************/
342
343 void headerfile_generate(classinfo *c, char *opt_directory)
344 {
345         char header_filename[1024] = "";
346         char classname[1024]; 
347         char uclassname[1024];
348         u2 i;
349         methodinfo *m;                  
350         u2 j;
351         methodinfo *m2;
352         bool nativelyoverloaded;
353
354         /* prevent compiler warnings */
355
356         nativelyoverloaded = false;
357
358         /* open headerfile for class */
359         gen_header_filename(classname, c->name);
360
361         /* create chain for renaming fields */
362         ident_chain = chain_new();
363         
364         if (opt_directory) {
365                 sprintf(header_filename, "%s/%s.h", opt_directory, classname);
366
367         } else {
368                 sprintf(header_filename, "%s.h", classname);
369         }
370
371         file = fopen(header_filename, "w");
372         if (!file) {
373                 log_text("Can not open file to store header information");
374                 assert(0);
375         }
376
377         fprintf(file, "/* This file is machine generated, don't edit it! */\n\n");
378
379         /* convert to uppercase */
380         for (i = 0; classname[i]; i++) {
381                 uclassname[i] = toupper(classname[i]);
382         }
383         uclassname[i] = '\0';
384
385         fprintf(file, "#ifndef _%s_H\n#define _%s_H\n\n", uclassname, uclassname);
386
387         /* create structure for direct access to objects */     
388         fprintf(file, "/* Structure information for class: ");
389         utf_fprint_printable_ascii(file, c->name);
390         fprintf(file, " */\n\n");
391         fprintf(file, "typedef struct ");
392         printID(c->name);                                                       
393         fprintf(file, " {\n");
394         outputsize = 0;
395         dopadding = true;
396
397         printfields(c);
398
399         fprintf(file, "} ");
400         printID(c->name);
401         fprintf(file, ";\n\n");
402
403         /* create chain for renaming overloaded methods */
404         chain_free(ident_chain);
405         ident_chain = chain_new();
406
407         /* create method-prototypes */
408                                 
409         /* find overloaded methods */
410
411         for (i = 0; i < c->methodscount; i++) {
412                 m = &(c->methods[i]);
413
414                 if (!(m->flags & ACC_NATIVE))
415                         continue;
416
417                 /* We use a dummy flag here. */
418
419                 if (!(m->flags & ACC_NATIVELY_OVERLOADED)) {
420                         nativelyoverloaded = false;
421
422                         for (j = i + 1; j < c->methodscount; j++) {
423                                 m2 = &(c->methods[j]);
424
425                                 if (!(m2->flags & ACC_NATIVE))
426                                         continue;
427
428                                 if (m->name == m2->name) {
429                                         m2->flags          |= ACC_NATIVELY_OVERLOADED;
430                                         nativelyoverloaded  = true;
431                                 }
432                         }
433                 }
434
435                 if (nativelyoverloaded == true)
436                         m->flags |= ACC_NATIVELY_OVERLOADED;
437         }
438
439         for (i = 0; i < c->methodscount; i++) {
440                 m = &(c->methods[i]);
441
442                 if (m->flags & ACC_NATIVE)
443                         printmethod(m);
444         }
445
446         chain_free(ident_chain);
447
448         fprintf(file, "#endif\n\n");
449
450         fclose(file);
451 }
452
453
454 /******** print classname, '$' used to seperate inner-class name ***********/
455
456 void print_classname(classinfo *clazz)
457 {
458         utf *u = clazz->name;
459     char *endpos  = u->text + u->blength;
460     char *utf_ptr = u->text; 
461         u2 c;
462
463     while (utf_ptr < endpos) {
464                 if ((c = utf_nextu2(&utf_ptr)) == '_')
465                         putc('$', file);
466                 else
467                         putc(c, file);
468         }
469
470
471
472 /*
473  * These are local overrides for various environment variables in Emacs.
474  * Please do not remove this and leave it at the end of the file, where
475  * Emacs will automagically detect them.
476  * ---------------------------------------------------------------------
477  * Local variables:
478  * mode: c
479  * indent-tabs-mode: t
480  * c-basic-offset: 4
481  * tab-width: 4
482  * End:
483  * vim:noexpandtab:sw=4:ts=4:
484  */