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