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