1 /********************************************************************
3 classgen.c - methods for creating the .class binary file
5 Niksa Orlic, 2004-05-16
7 ********************************************************************/
9 //#include "../util/message.h"
10 #include "../util/error.h"
11 #include "../util/strings.h"
12 #include "../structures/type_list.h"
13 #include "../structures/string_list.h"
14 #include "../structures/type.h"
15 #include "../structures/identifier.h"
16 #include "../structures/name_table.h"
17 #include "../classgen/bytecode.h"
18 #include "../structures/block.h"
19 #include "../classgen/constant_pool.h"
20 #include "../classgen/preverify.h"
21 #include "../util/memory.h"
29 extern char* output_path
;
32 extern int detect_units_only
;
34 extern constant_pool
*constants
;
35 extern int constant_pool_size
;
37 //extern int usesFloat;
43 Creates a class file for pascal record.
45 void create_record_class(type
*record
)
47 char class_file_name
[16];
48 char *output_file_name
;
53 bytecode
*init_method
;
54 bytecode
*copy_method
;
56 /* save the previous constant pool state */
57 constant_pool
*global_cp
;
60 global_cp
= constants
;
61 global_cp_count
= constant_pool_size
;
64 constant_pool_size
= 0;
66 /* check for consistency */
67 if (record
->type_class
!= record_type
)
70 sprintf(class_name
, "R_%d", record
->unique_record_ID
);
71 sprintf(class_file_name
, "%s.class", class_name
);
73 if (!detect_units_only
)
74 requires(3, class_file_name
);
76 output_file_name
= (char*) mem_alloc(strlen(output_path
) +
77 strlen(class_file_name
) + 5);
78 if (output_file_name
== NULL
)
82 sprintf(output_file_name
, "%s\\%s", output_path
, class_file_name
);
85 sprintf(output_file_name
, "%s/%s", output_path
, class_file_name
);
87 record_file
= fopen(output_file_name
, "wb");
88 mem_free(output_file_name
);
90 if (record_file
== NULL
)
93 /* write the class file header */
94 create_class_file_header(record_file
);
96 /* add some stuff into the constant pool */
97 cp_add_class(class_name
);
98 cp_add_class("java/lang/Object");
99 cp_add_utf8("<init>");
103 sprintf(copy_sig
, "(LR_%d;)LR_%d;", record
->unique_record_ID
, record
->unique_record_ID
);
104 cp_add_utf8(copy_sig
);
106 create_record_fields(record
);
108 /* create the bytecode for the init method */
109 init_method
= bytecode_create();
110 create_init_method(record
, init_method
);
112 /* create the bytecode for the copy method */
113 copy_method
= bytecode_create();
114 create_copy_method(record
, copy_method
);
116 /* write the constant pool into the file */
117 write_constant_pool(record_file
);
119 /* write the access flags, set to ACC_PUBLIC and ACC_SUPER */
120 write_short_int(record_file
, 0x0021);
122 /* write the index to constat pool with this class description */
123 write_short_int(record_file
, cp_add_class(class_name
));
125 /* write the index to constant pool with the super class description */
126 write_short_int(record_file
, cp_add_class("java/lang/Object"));
128 /* we have no interfaces */
129 write_short_int(record_file
, 0);
131 /* write the fields */
132 write_short_int(record_file
, (short) type_list_length(record
->elements_type_list
));
133 write_record_fields(record_file
, record
);
135 /* we have <init> and Copy method */
136 write_short_int(record_file
, 2);
138 /* write the init method */
139 write_init_method(record_file
, init_method
);
141 /* write the copy method */
142 write_copy_method(record
, record_file
, copy_method
);
144 /* we have no attributes */
145 write_short_int(record_file
, 0);
150 /* restore the constant pool */
151 constants
= global_cp
;
152 constant_pool_size
= global_cp_count
;
157 Writes a class file header into the output file
159 void create_class_file_header(FILE *class_file
)
161 char magic
[4] = { (char)0xCA, (char)0xFE, (char)0xBA, (char)0xBE };
163 fwrite(magic
, 1, 4, class_file
);
165 /* Write the minor version number 3 */
166 write_short_int(class_file
, 0x0003);
168 /* Wrte the major version number 45 */
169 write_short_int(class_file
, 0x002d);
174 Creates entries into constant pool with names and types of
175 the elements of the structure.
177 void create_record_fields(type
*record
)
181 char descriptor
[128];
183 names
= record
->elements_name_list
;
184 types
= record
->elements_type_list
;
186 while (names
!= NULL
)
188 if (names
->data
!= NULL
)
190 lowercase(names
->data
->cstr
);
191 get_field_descriptor(types
->data
, descriptor
);
192 cp_add_nameandtype(names
->data
->cstr
, descriptor
);
202 Writes the fields from the record into the
205 void write_record_fields(FILE *class_file
, type
*record
)
209 char descriptor
[128];
212 names
= record
->elements_name_list
;
213 types
= record
->elements_type_list
;
215 while (names
!= NULL
)
217 if (names
->data
!= NULL
)
219 /* write the access flags: ACC_PUBLIC */
220 write_short_int(class_file
, 0x0001);
222 /* write the name index */
223 lowercase(names
->data
->cstr
);
224 write_short_int(class_file
, cp_add_utf8(names
->data
->cstr
));
226 /* write the descriptor index */
227 get_field_descriptor(types
->data
, descriptor
);
228 write_short_int(class_file
, cp_add_utf8(descriptor
));
230 /* we have no attributes */
231 write_short_int(class_file
, 0);
242 Writes a short int in bigendian format. If
243 class_file is NULL, does nothing.
245 void write_short_int(FILE *class_file
, short int num
)
249 if (class_file
== NULL
)
252 ch
= (char) (num
>> 8);
253 fwrite(&ch
, 1, 1, class_file
);
256 fwrite(&ch
, 1, 1, class_file
);
259 void write_long_int(FILE *class_file
, long int num
)
263 if (class_file
== NULL
)
266 ch
= (char) (num
>> 24);
267 fwrite(&ch
, 1, 1, class_file
);
269 ch
= (char) (num
>> 16);
270 fwrite(&ch
, 1, 1, class_file
);
272 ch
= (char) (num
>> 8);
273 fwrite(&ch
, 1, 1, class_file
);
276 fwrite(&ch
, 1, 1, class_file
);
280 short int read_short_int(FILE *class_file
)
282 short int return_value
= 0;
284 return_value
= fgetc(class_file
) << 8;
285 return_value
|= (fgetc(class_file
) & 0x00FF);
290 long int read_long_int(FILE *class_file
)
292 long int return_value
= 0;
294 return_value
= fgetc(class_file
) << 24;
295 return_value
|= (fgetc(class_file
) & 0x00FF) << 16;
296 return_value
|= (fgetc(class_file
) & 0x00FF) << 8;
297 return_value
|= (fgetc(class_file
) & 0x00FF);
303 Construct a valid Java field descriptor for a given type.
305 void get_field_descriptor(type
*field_type
, char *descriptor
)
307 switch (field_type
->type_class
)
310 sprintf(descriptor
, "V");
316 sprintf(descriptor
, "I");
321 sprintf(descriptor
, "I");
323 sprintf(descriptor
, "LReal;");
327 sprintf(descriptor
, "Ljava/lang/String;");
331 sprintf(descriptor
, "Ljavax/microedition/lcdui/Command;");
335 sprintf(descriptor
, "Ljava/io/InputStream;");
338 case record_store_type
:
339 sprintf(descriptor
, "Ljavax/microedition/rms/RecordStore;");
343 sprintf(descriptor
, "LH;");
347 sprintf(descriptor
, "Ljavax/microedition/lcdui/AlertType;");
351 sprintf(descriptor
, "Ljavax/microedition/lcdui/Image;");
356 char element_type
[128];
359 get_field_descriptor(field_type
->element_type
, element_type
);
361 len
= type_list_length(field_type
->dimensions_list
);
362 for(i
=0; i
< len
; i
++)
367 descriptor
[len
] = '\0';
369 sprintf(descriptor
+ len
, "%s", element_type
);
374 sprintf(descriptor
, "LR_%d;", field_type
->unique_record_ID
);
387 Creates the <init> method for records.
389 void create_init_method(type
*record
, bytecode
*code
)
392 string_list
*name_it
;
398 /* create the code */
399 type_it
= record
->elements_type_list
;
400 name_it
= record
->elements_name_list
;
402 bytecode_append(code
, aload_0$
);
403 bytecode_append(code
, invokespecial$
);
404 bytecode_append_short_int(code
, cp_add_methodref("java/lang/Object", "<init>", "()V"));
407 while (type_it
!= NULL
)
409 if ((type_it
->data
!= NULL
) && (name_it
->data
!= NULL
))
412 identifier
*type_wrapper
;
414 code_wrapper
= block_create(NULL
, string_create());
415 code_wrapper
->code
= code
;
417 type_wrapper
= identifier_create();
418 type_wrapper
->identifier_class
= variable_name
;
419 type_wrapper
->variable_type
= type_it
->data
;
420 type_wrapper
->belongs_to_program_block
= 1;
422 /* put 'this' to the stack */
423 bytecode_append(code
, aload_0$
);
425 /* create the code to initialize the variable */
426 initialize_variable(code_wrapper
, type_wrapper
, name_it
->data
->cstr
, 0, class_name
);
428 if (type_it
->data
->type_class
== array_type
)
429 add_error_message(446, name_it
->data
->cstr
, "");
431 code_wrapper
->code
= bytecode_create();
432 block_destroy(code_wrapper
);
434 type_wrapper
->variable_type
= type_create();
435 identifier_destroy(type_wrapper
);
438 type_it
= type_it
->next
;
440 name_it
= name_it
->next
;
445 bytecode_append(code
, return$
);
449 Creates the Copy method for records.
451 void create_copy_method(type
*record
, bytecode
*code
)
456 string_list
*name_it
;
462 sprintf(type_name
, "R_%d", record
->unique_record_ID
);
464 /* create the code */
465 type_it
= record
->elements_type_list
;
466 name_it
= record
->elements_name_list
;
468 while (type_it
!= NULL
)
470 if ((type_it
->data
!= NULL
) && (name_it
->data
!= NULL
))
472 lowercase(name_it
->data
->cstr
);
474 if (type_it
->data
->type_class
== record_type
)
477 char type_descriptor
[128];
478 get_field_descriptor(type_it
->data
, type_descriptor
);
480 sprintf(copy_sig
, "(LR_%d;)LR_%d;", record
->unique_record_ID
, record
->unique_record_ID
);
482 bytecode_append(code
, aload_0$
);
483 bytecode_append(code
, getfield$
);
484 bytecode_append_short_int(code
, cp_add_fieldref(type_name
, name_it
->data
->cstr
, type_descriptor
));
486 bytecode_append(code
, aload_1$
);
487 bytecode_append(code
, getfield$
);
488 bytecode_append_short_int(code
, cp_add_fieldref(type_name
, name_it
->data
->cstr
, type_descriptor
));
490 bytecode_append(code
, invokevirtual$
);
491 bytecode_append_short_int(code
, cp_add_methodref(type_name
, "Copy", copy_sig
));
494 else if (type_it
->data
->type_class
== string_type
)
496 bytecode_append(code
, aload_0$
);
498 bytecode_append(code
, aload_1$
);
499 bytecode_append(code
, getfield$
);
500 bytecode_append_short_int(code
, cp_add_fieldref(type_name
, name_it
->data
->cstr
, "Ljava/lang/String;"));
502 bytecode_append(code
, new$
);
503 bytecode_append_short_int(code
, cp_add_class("java/lang/String"));
504 bytecode_append(code
, dup_x1$
);
505 bytecode_append(code
, swap$
);
506 bytecode_append(code
, invokespecial$
);
507 bytecode_append_short_int(code
, cp_add_methodref("java/lang/String", "<init>", "(Ljava/lang/String;)V"));
509 bytecode_append(code
, putfield$
);
510 bytecode_append_short_int(code
, cp_add_fieldref(type_name
, name_it
->data
->cstr
, "Ljava/lang/String;"));
512 else if ((type_it
->data
->type_class
== real_type
) && (mathType
!= 1))
514 bytecode_append(code
, aload_0$
);
516 bytecode_append(code
, aload_1$
);
517 bytecode_append(code
, getfield$
);
518 bytecode_append_short_int(code
, cp_add_fieldref(type_name
, name_it
->data
->cstr
, "LReal;"));
520 bytecode_append(code
, new$
);
521 bytecode_append_short_int(code
, cp_add_class("Real"));
522 bytecode_append(code
, dup_x1$
);
523 bytecode_append(code
, swap$
);
524 bytecode_append(code
, invokespecial$
);
525 bytecode_append_short_int(code
, cp_add_methodref("Real", "<init>", "(LReal;)V"));
527 bytecode_append(code
, putfield$
);
528 bytecode_append_short_int(code
, cp_add_fieldref(type_name
, name_it
->data
->cstr
, "LReal;"));
533 char type_descriptor
[128];
534 get_field_descriptor(type_it
->data
, type_descriptor
);
536 bytecode_append(code
, aload_0$
);
537 bytecode_append(code
, aload_1$
);
539 bytecode_append(code
, getfield$
);
540 bytecode_append_short_int(code
, cp_add_fieldref(type_name
, name_it
->data
->cstr
, type_descriptor
));
542 bytecode_append(code
, putfield$
);
543 bytecode_append_short_int(code
, cp_add_fieldref(type_name
, name_it
->data
->cstr
, type_descriptor
));
547 type_it
= type_it
->next
;
549 name_it
= name_it
->next
;
555 bytecode_append(code
, aload_0$
);
556 bytecode_append(code
, areturn$
);
561 Writes the <init> method to the file.
563 void write_init_method(FILE *fp
, bytecode
*code
)
565 /* write the method headers */
567 /* write access flags, ACC_PUBLIC */
568 write_short_int(fp
, 0x0001);
570 /* write method name '<init>' */
571 write_short_int(fp
, cp_add_utf8("<init>"));
573 /* write method descriptor '()V' */
574 write_short_int(fp
, cp_add_utf8("()V"));
576 /* write 1 attribute */
577 write_short_int(fp
, 1);
579 /* write the Code attribute 'Code' */
580 write_short_int(fp
, cp_add_utf8("Code"));
581 write_long_int(fp
, code
->bytecode_pos
+ 12);
583 /* write the max stack */
584 write_short_int(fp
, 10);
586 /* max locals for program block */
587 write_short_int(fp
, 2);
590 write_long_int(fp
, code
->bytecode_pos
);
592 /* write the code itself */
594 fwrite(code
->bytecode
, 1, code
->bytecode_pos
, fp
);
596 bytecode_destroy(code
);
598 write_short_int(fp
, 0);
599 write_short_int(fp
, 0);
603 Writes the Copy method to the file.
605 void write_copy_method(type
* record
, FILE *fp
, bytecode
*code
)
609 /* write the method headers */
611 /* write access flags, ACC_PUBLIC */
612 write_short_int(fp
, 0x0001);
614 /* write method name '<init>' */
615 write_short_int(fp
, cp_add_utf8("Copy"));
617 /* write method descriptor (record)record */
618 sprintf(method_sig
, "(LR_%d;)LR_%d;", record
->unique_record_ID
, record
->unique_record_ID
);
619 write_short_int(fp
, cp_add_utf8(method_sig
));
621 /* write 1 attribute */
622 write_short_int(fp
, 1);
624 /* write the Code attribute 'Code' */
625 write_short_int(fp
, cp_add_utf8("Code"));
626 write_long_int(fp
, code
->bytecode_pos
+ 12);
628 /* write the max stack */
629 write_short_int(fp
, 10);
631 /* max locals for program block */
632 write_short_int(fp
, 2);
635 write_long_int(fp
, code
->bytecode_pos
);
637 /* write the code itself */
639 fwrite(code
->bytecode
, 1, code
->bytecode_pos
, fp
);
641 bytecode_destroy(code
);
643 write_short_int(fp
, 0);
644 write_short_int(fp
, 0);