#include #include #include #include #include #include #include #include "../../../include/oberon.h" #include "../../oberon-internals.h" #include "generator-jvm.h" #include "generator-jvm-basic.h" char * new_string(const char * format, ...) { va_list ptr; va_start(ptr, format); char buf[1024]; vsnprintf(buf, 1024, format, ptr); va_end(ptr); char * result; int size; size = strlen(buf); result = GC_MALLOC(size + 1); memset(result, 0, size); strncpy(result, buf, size); return result; } void gen_error(const char * fmt, ...) { va_list ptr; va_start(ptr, fmt); fprintf(stderr, "generator: "); vfprintf(stderr, fmt, ptr); fprintf(stderr, "\n"); va_end(ptr); exit(1); } char * jvm_get_descriptor(oberon_type_t * type) { char * desc; switch(type -> class) { case OBERON_TYPE_VOID: return new_string("V"); break; case OBERON_TYPE_INTEGER: case OBERON_TYPE_SET: switch(type -> size) { case 1: return new_string("B"); break; case 2: return new_string("S"); break; case 4: return new_string("I"); break; case 8: return new_string("J"); break; default: gen_error("jvm_get_descriptor: unsupported int size %i", type -> size); break; } break; case OBERON_TYPE_REAL: switch(type -> size) { case 4: return new_string("F"); break; case 8: return new_string("D"); break; default: gen_error("jvm_get_descriptor: unsupported float size %i", type -> size); break; } break; case OBERON_TYPE_CHAR: switch(type -> size) { case 1: return new_string("B"); break; case 2: return new_string("C"); break; case 4: return new_string("I"); break; case 8: return new_string("J"); break; default: gen_error("jvm_get_descriptor: unsupported char size %i", type -> size); break; } break; case OBERON_TYPE_BOOLEAN: return new_string("Z"); break; case OBERON_TYPE_POINTER: return jvm_get_descriptor(type -> base); break; case OBERON_TYPE_PROCEDURE: case OBERON_TYPE_RECORD: desc = jvm_get_class_full_name(type); return new_string("L%s;", desc); break; case OBERON_TYPE_ARRAY: desc = jvm_get_descriptor(type -> base); return new_string("[%s", desc); break; default: gen_error("jvm_get_descriptor: unsupported type class %i", type -> class); break; } return NULL; } char * jvm_get_descriptor_safe(oberon_type_t * type) { switch(type -> class) { case OBERON_TYPE_POINTER: return new_string("PTR%s", jvm_get_descriptor_safe(type -> base)); break; case OBERON_TYPE_PROCEDURE: case OBERON_TYPE_RECORD: return jvm_get_class_full_name(type); break; case OBERON_TYPE_ARRAY: return new_string("A%s", jvm_get_descriptor_safe(type -> base)); break; default: return jvm_get_descriptor(type); break; } return NULL; } char jvm_get_prefix(oberon_type_t * type) { int size = type -> size; switch(type -> class) { case OBERON_TYPE_BOOLEAN: case OBERON_TYPE_INTEGER: case OBERON_TYPE_CHAR: case OBERON_TYPE_SET: return (size <= 4) ? ('i') : ('l'); break; case OBERON_TYPE_PROCEDURE: case OBERON_TYPE_ARRAY: case OBERON_TYPE_RECORD: case OBERON_TYPE_POINTER: return 'a'; break; case OBERON_TYPE_REAL: return (size <= 4) ? ('f') : ('d'); break; default: gen_error("jvm_get_prefix: wat"); return '!'; break; } } char jvm_get_postfix(oberon_type_t * type) { int size = type -> size; switch(type -> class) { case OBERON_TYPE_BOOLEAN: return 'b'; break; case OBERON_TYPE_INTEGER: case OBERON_TYPE_SET: switch(size) { case 1: return 'b'; break; case 2: return 's'; break; case 4: return 'i'; break; case 8: return 'l'; break; default: gen_error("jvm_get_postfix: int wat"); break; } break; case OBERON_TYPE_CHAR: switch(size) { case 1: return 'b'; break; case 2: return 'c'; break; case 4: return 'i'; break; case 8: return 'l'; break; default: gen_error("jvm_get_postfix: char wat"); break; } break; case OBERON_TYPE_PROCEDURE: case OBERON_TYPE_ARRAY: case OBERON_TYPE_RECORD: case OBERON_TYPE_POINTER: return 'a'; break; case OBERON_TYPE_REAL: return (size <= 4) ? ('f') : ('d'); break; default: gen_error("jvm_get_postfix: wat"); break; } return '!'; } char * jvm_get_field_full_name(oberon_object_t * x) { switch(x -> class) { case OBERON_CLASS_VAR: case OBERON_CLASS_PROC: return new_string("%s/%s", x -> module -> name, x -> name); case OBERON_CLASS_FIELD:; char * rec_name = jvm_get_class_full_name(x -> parent_type); return new_string("%s/%s", rec_name, x -> name); case OBERON_CLASS_MODULE: return new_string(x -> module -> name); default: gen_error("jvm_get_field_full_name: wat"); break; } return NULL; } char * jvm_get_field_full_name_safe(oberon_object_t * x) { switch(x -> class) { case OBERON_CLASS_VAR: case OBERON_CLASS_PROC: return new_string("%s$%s", x -> module -> name, x -> name); case OBERON_CLASS_FIELD:; char * rec_name = jvm_get_class_full_name(x -> parent_type); return new_string("%s$%s", rec_name, x -> name); case OBERON_CLASS_MODULE: return new_string(x -> module -> name); default: gen_error("jvm_get_field_full_name: wat"); break; } return NULL; } char * jvm_get_class_full_name(oberon_type_t * type) { int rec_id; char * name = NULL; switch(type -> class) { case OBERON_TYPE_POINTER: name = jvm_get_class_full_name(type -> base); break; case OBERON_TYPE_PROCEDURE: name = new_string("SYSTEM$PROCEDURE"); char * desc; desc = jvm_get_descriptor_safe(type -> base); name = new_string("%s$%s", name, desc); int num = type -> num_decl; oberon_object_t * arg = type -> decl; for(int i = 0; i < num; i++) { desc = jvm_get_descriptor_safe(arg -> type); name = new_string("%s%s", name, desc); arg = arg -> next; } break; case OBERON_TYPE_RECORD: rec_id = type -> gen_type -> rec_id; name = new_string("%s$RECORD%i", type -> module -> name, rec_id); break; default: gen_error("jvm_get_class_full_name: unk type class %i", type -> class); break; } return name; } char * jvm_get_procedure_signature(oberon_type_t * proc) { char * signature; char * desc; signature = new_string("("); int num = proc -> num_decl; oberon_object_t * arg = proc -> decl; for(int i = 0; i < num; i++) { desc = jvm_get_descriptor(arg -> type); signature = new_string("%s%s", signature, desc); arg = arg -> next; } desc = jvm_get_descriptor(proc -> base); signature = new_string("%s)%s", signature, desc); return signature; } int jvm_cell_size_for_type(oberon_type_t * type) { if(type -> class == OBERON_TYPE_INTEGER || type -> class == OBERON_TYPE_REAL || type -> class == OBERON_TYPE_CHAR || type -> class == OBERON_TYPE_SET) { if(type -> size > 4) { return 2; } } else if(type -> class == OBERON_TYPE_VOID) { return 0; } return 1; } int jvm_cell_size_for_postfix(char postfix) { switch(postfix) { case 'a': case 'b': case 's': case 'i': case 'f': return 1; case 'l': case 'd': return 2; default: gen_error("jvm_cell_size_for_postfix: unk postfix %c", postfix); } return -666; } bool jvm_is_wide_type(oberon_type_t * type) { int cell; cell = jvm_cell_size_for_type(type); assert(cell <= 2); return (cell == 2); } bool jvm_is_free_register(struct gen_register_file * rf, int i, bool wide) { if(wide) { assert(i + 1 < MAX_REGISTERS); return !(rf -> reg[i].used || rf -> reg[i + 1].used); } else { assert(i < MAX_REGISTERS); return !(rf -> reg[i].used); } } int jvm_alloc_register_untyped(struct gen_register_file * rf, bool wide) { int i = 0; while(i < MAX_REGISTERS && !jvm_is_free_register(rf, i, wide)) { i += 1; } if(wide) { assert(i + 1 <= MAX_REGISTERS); rf -> num_used += 2; rf -> reg[i].used = true; rf -> reg[i + 1].used = true; rf -> reg[i].used = true; rf -> reg[i + 1].wide = false; } else { assert(i <= MAX_REGISTERS); rf -> num_used += 1; rf -> reg[i].used = true; rf -> reg[i].wide = false; } if(rf -> num_used > rf -> max_used) { rf -> max_used = rf -> num_used; } return i; } int jvm_alloc_register(struct gen_register_file * rf, oberon_type_t * type) { bool wide; wide = jvm_is_wide_type(type); return jvm_alloc_register_untyped(rf, wide); } char jvm_get_type_of_prefix(char prefix) { switch(prefix) { case 'b': return 'B'; case 'c': return 'C'; case 'd': return 'D'; case 'f': return 'F'; case 'i': return 'I'; case 'l': return 'J'; } assert(0); }