X-Git-Url: http://deadsoftware.ru/gitweb?a=blobdiff_plain;f=src%2Fbackends%2Fjvm%2Fgenerator-jvm.c;h=9408eca32328248fd37b8454c30b99d663ad7ebd;hb=13d2ebdd52d42ab2e9d5f3764a9296a25fe16464;hp=7c426d546c7bdf190f3594e7b5bda31293f89543;hpb=f89bbec89e4dd5c7cd15954f0c02370fb9127518;p=dsw-obn.git diff --git a/src/backends/jvm/generator-jvm.c b/src/backends/jvm/generator-jvm.c index 7c426d5..9408eca 100644 --- a/src/backends/jvm/generator-jvm.c +++ b/src/backends/jvm/generator-jvm.c @@ -59,8 +59,13 @@ jvm_generate_function_end(gen_proc_t * p) assert(class -> p); class -> p = NULL; - fprintf(class -> fp, " .limit stack %i\n", p -> stack -> max_pointer); - fprintf(class -> fp, " .limit locals %i\n", p -> rf -> max_used); + int pointer = p -> stack -> pointer; + int max_pointer = p -> stack -> max_pointer; + int locals = p -> rf -> num_used; + int max_locals = p -> rf -> max_used; + + fprintf(class -> fp, " .limit stack %i \t; current(%i)\n", max_pointer, pointer); + fprintf(class -> fp, " .limit locals %i \t; current(%i)\n", max_locals, locals); fprintf(class -> fp, ".end method\n\n"); } @@ -71,6 +76,7 @@ jvm_create_class(char * full_name) memset(class, 0, sizeof *class); char * fname = new_string("%s.j", full_name); + class -> full_name = new_string(full_name); class -> fp = fopen(fname, "w"); assert(class -> fp); @@ -84,13 +90,6 @@ jvm_destroy_class(struct gen_class * class) fclose(class -> fp); } -static void -jvm_generate_field(struct gen_class * class, char * access, char * name, char * desc) -{ - assert(class -> p == NULL); - fprintf(class -> fp, ".field %s %s %s\n\n", access, name, desc); -} - static void jvm_stack_push(gen_proc_t * p, unsigned size) { @@ -117,8 +116,8 @@ jvm_generate(gen_proc_t * p, unsigned get, unsigned push, char * format, ...) jvm_stack_pop(p, get); fprintf(p -> class -> fp, " "); vfprintf(p -> class -> fp, format, ptr); - fprintf(p -> class -> fp, "\n"); jvm_stack_push(p, push); + fprintf(p -> class -> fp, " \t ;>>>> %i -- %i : current_stack(%i)\n", get, push, p -> stack -> pointer); va_end(ptr); } @@ -191,6 +190,51 @@ jvm_generate_push_float(gen_proc_t * p, double f, int size) } } +static gen_var_t * +oberon_generator_new_var() +{ + gen_var_t * v = GC_MALLOC(sizeof *v); + memset(v, 0, sizeof *v); + return v; +} + +static void +jvm_generate_and_init_global_var(gen_var_t * v, struct gen_class * class, char * access, char * name, char * desc) +{ + assert(class -> p == NULL); + fprintf(class -> fp, ".field %s static %s %s\n\n", access, name, desc); + + v -> storage = JVM_STORAGE_STATIC; + v -> full_name = new_string("%s/%s", class -> full_name, name); + v -> desc = new_string(desc); +} + +static void +jvm_generate_and_init_field(gen_var_t * v, struct gen_class * class, char * access, char * name, char * desc) +{ + assert(class -> p == NULL); + fprintf(class -> fp, ".field %s %s %s\n\n", access, name, desc); + + v -> storage = JVM_STORAGE_FIELD; + v -> full_name = new_string("%s/%s", class -> full_name, name); + v -> desc = new_string(desc); +} + +static void +jvm_generate_and_init_local_var(gen_var_t * v, gen_proc_t * p, bool wide) +{ + v -> storage = JVM_STORAGE_REGISTER; + v -> reg = jvm_alloc_register_untyped(p -> rf, wide); +} + +static void +jvm_generate_and_init_named_local_var(gen_var_t * v, gen_proc_t * p, bool wide, char * name, char * desc) +{ + jvm_generate_and_init_local_var(v, p, wide); + v -> desc = new_string(desc); + jvm_generate(p, 0, 0, ".var %i is %s %s from start to end", v -> reg, name, desc); +} + static int jvm_new_label_id(gen_proc_t * p) { @@ -211,6 +255,166 @@ jvm_generate_label(gen_proc_t * p, int label_id) jvm_generate(p, 0, 0, "L%i:", label_id); } +static void +jvm_generate_new_static(gen_proc_t * p, oberon_type_t * type); + +/* + * Функция jvm_generate_static_array_initialization генерирует код для + * статической инициализации массива. На входе массив, на выходе тот же массив. + * arrayref -- arrayref + */ + +static void +jvm_generate_static_array_initialization(gen_proc_t * p, oberon_type_t * type) +{ + /* for(int i = 0; i < a.length; i++) */ + /* a[i] := new(base); */ + /* init(a[i]) */ + + /* a := pop(array) */ + gen_var_t * va = oberon_generator_new_var(); + jvm_generate_and_init_local_var(va, p, false); + int reg_a = va -> reg; + /* ссылка уже на стеке */ + jvm_generate(p, 1, 0, "astore %i", reg_a); + + /* int i = 0; */ + gen_var_t * vi = oberon_generator_new_var(); + jvm_generate_and_init_local_var(vi, p, false); + int reg_i = vi -> reg; + jvm_generate(p, 0, 1, "iconst_0"); + jvm_generate(p, 1, 0, "istore %i", reg_i); + + /* int l := a.length */ + gen_var_t * vl = oberon_generator_new_var(); + jvm_generate_and_init_local_var(vl, p, false); + int reg_l = vl -> reg; + jvm_generate(p, 0, 1, "aload %i", reg_a); + jvm_generate(p, 1, 1, "arraylength"); + jvm_generate(p, 1, 0, "istore %i", reg_l); + + int label_start = jvm_new_label_id(p); + int label_end = jvm_new_label_id(p); + + /* start: */ + /* if (i >= l) goto end; */ + /* body*/ + /* i += 1;*/ + /* goto start;*/ + /* end: */ + /* push a */ + + jvm_generate_label(p, label_start); + jvm_generate(p, 0, 1, "iload %i", reg_i); + jvm_generate(p, 0, 1, "iload %i", reg_l); + jvm_generate(p, 2, 0, "if_icmpge L%i", label_end); + + if(type -> base -> class == OBERON_TYPE_ARRAY) + { + /* Инициализируем следующую размерность */ + jvm_generate(p, 0, 1, "aload %i", reg_a); + jvm_generate(p, 0, 1, "iload %i", reg_i); + jvm_generate(p, 0, 1, "aaload"); + jvm_generate_static_array_initialization(p, type -> base); + jvm_generate(p, 1, 0, "pop"); + } + else if(type -> base -> class == OBERON_TYPE_RECORD) + { + jvm_generate(p, 0, 1, "aload %i", reg_a); + jvm_generate(p, 0, 1, "iload %i", reg_i); + jvm_generate_new_static(p, type -> base); + jvm_generate(p, 3, 0, "aastore"); + } + else + { + assert(0); + } + + /* i += 1; */ + /* goto start */ + + jvm_generate(p, 0, 0, "iinc %i %i", reg_i, 1); + jvm_generate(p, 0, 0, "goto L%i", label_start); + jvm_generate_label(p, label_end); + + /* push(a) */ + jvm_generate(p, 0, 1, "aload %i", reg_a); + + /* TODO освобождение регистров */ +} + +static void +jvm_generate_new_static(gen_proc_t * p, oberon_type_t * type) +{ + int dim; + char * cname; + char * desc; + oberon_type_t * base; + + switch(type -> class) + { + case OBERON_TYPE_INTEGER: + case OBERON_TYPE_BOOLEAN: + case OBERON_TYPE_PROCEDURE: + case OBERON_TYPE_REAL: + case OBERON_TYPE_POINTER: + gen_error("jvm_generate_new_static: static alocation not allowed"); + break; + case OBERON_TYPE_RECORD: + cname = jvm_get_class_full_name(type); + jvm_generate(p, 0, 1, "new %s", cname); + jvm_generate(p, 1, 2, "dup"); + jvm_generate(p, 1, 0, "invokespecial %s/()V", cname); + break; + case OBERON_TYPE_ARRAY: + dim = 0; + base = type; + desc = jvm_get_descriptor(type); + while(base -> class == OBERON_TYPE_ARRAY) + { + dim += 1; + jvm_generate_push_int(p, base -> size); + base = base -> base; + } + jvm_generate(p, dim, 1, "multianewarray %s %i", desc, dim); + + if(base -> class == OBERON_TYPE_RECORD) + { + jvm_generate_static_array_initialization(p, type); + } + break; + default: + gen_error("jvm_generate_new_static: unk type class %i", type -> class); + break; + } +} + +static void +jvm_generate_store(gen_proc_t * p, oberon_type_t * src_type, gen_var_t * dst) +{ + char prefix; + int cell_size; + + cell_size = jvm_cell_size_for_type(src_type); + + switch(dst -> storage) + { + case JVM_STORAGE_REGISTER: + prefix = jvm_get_prefix(src_type); + jvm_generate(p, cell_size, 0, "%cstore %i", prefix, dst -> reg); + break; + case JVM_STORAGE_STATIC: + jvm_generate(p, cell_size, 0, "putstatic %s %s", dst -> full_name, dst -> desc); + break; + case JVM_STORAGE_FIELD: + jvm_generate(p, 1 + cell_size, 0, "putfield %s %s", dst -> full_name, dst -> desc); + break; + default: + gen_error("jvm_generate_store: unknow storage type %i", dst -> storage); + break; + } +} + // ========================================== // ========================================== // ========================================== @@ -311,35 +515,6 @@ oberon_generator_init_type(oberon_context_t * ctx, oberon_type_t * type) } } -static void -jvm_generate_object(struct gen_class * class, oberon_object_t * x) -{ - char * name; - char * desc; - - name = x -> name; - desc = jvm_get_descriptor(x -> type); - switch(x -> class) - { - case OBERON_CLASS_VAR: - if(x -> local == 0) - { - jvm_generate_field(class, "public static", name, desc); - } - else - { - gen_error("jvm_generate_object: local variable as class field? wat"); - } - break; - case OBERON_CLASS_FIELD: - jvm_generate_field(class, "public", name, desc); - break; - default: - gen_error("jvm_generate_object: unk class %i", x -> class); - break; - } -} - void oberon_generator_init_record(oberon_context_t * ctx, oberon_type_t * rec) { @@ -350,15 +525,36 @@ oberon_generator_init_record(oberon_context_t * ctx, oberon_type_t * rec) oberon_object_t * field = rec -> decl; for(int i = 0; i < num; i++) { - jvm_generate_object(class, field); + gen_var_t * v = field -> gen_var; + char * name = field -> name; + char * desc = jvm_get_descriptor(field -> type); + jvm_generate_and_init_field(v, class, "public", name, desc); field = field -> next; } - fprintf(class -> fp, ".method public ()V\n"); - fprintf(class -> fp, " aload_0\n"); - fprintf(class -> fp, " invokespecial java/lang/Object/()V\n"); - fprintf(class -> fp, " return\n"); - fprintf(class -> fp, ".end method\n"); + gen_proc_t * p = jvm_create_proc(class); + + jvm_generate_function_header(p, "public", "", "()V"); + jvm_alloc_register_untyped(p -> rf, false); + jvm_generate(p, 0, 1, "aload_0"); + jvm_generate(p, 1, 0, "invokespecial java/lang/Object/()V"); + + num = rec -> num_decl; + field = rec -> decl; + for(int i = 0; i < num; i++) + { + if(field -> type -> class == OBERON_TYPE_RECORD + || field -> type -> class == OBERON_TYPE_ARRAY) + { + jvm_generate(p, 0, 1, "aload_0"); + jvm_generate_new_static(p, field -> type); + jvm_generate_store(p, field -> type, field -> gen_var); + } + field = field -> next; + } + + jvm_generate(p, 0, 0, "return"); + jvm_generate_function_end(p); jvm_destroy_class(class); } @@ -366,8 +562,7 @@ oberon_generator_init_record(oberon_context_t * ctx, oberon_type_t * rec) void oberon_generator_init_var(oberon_context_t * ctx, oberon_object_t * var) { - gen_var_t * v = GC_MALLOC(sizeof *v); - memset(v, 0, sizeof *v); + gen_var_t * v = oberon_generator_new_var(); var -> gen_var = v; gen_module_t * m; @@ -376,16 +571,28 @@ oberon_generator_init_var(oberon_context_t * ctx, oberon_object_t * var) struct gen_class * class; class = m -> class; + char * desc; switch(var -> class) { case OBERON_CLASS_VAR_PARAM: gen_error("generator: VAR-parameters not implemented"); break; case OBERON_CLASS_PARAM: + /* Заполняется при генерации функции */ + /* смотри jvm_init_local_object() */ + break; case OBERON_CLASS_FIELD: + /* Заполняются при инициализации структуры */ + /* смотри oberon_generator_init_record() */ break; case OBERON_CLASS_VAR: - jvm_generate_object(class, var); + /* Локальные заполняются при генерации функции */ + /* смотри jvm_init_local_object() */ + if(var -> local == 0) + { + desc = jvm_get_descriptor(var -> type); + jvm_generate_and_init_global_var(v, class, "public", var -> name, desc); + } break; default: gen_error("oberon_generator_init_var: unk var class %i", var -> class); @@ -443,6 +650,22 @@ oberon_generate_begin_module(oberon_context_t * ctx) jvm_alloc_register_untyped(p -> rf, false); jvm_generate(p, 0, 1, "aload_0"); jvm_generate(p, 1, 0, "invokespecial java/lang/Object/()V"); + + /* Инициализация переменных объявленных в модуле */ + oberon_object_t * x = ctx -> mod -> decl -> list -> next; + while(x != NULL) + { + if(x -> class == OBERON_CLASS_VAR) + { + if(x -> type -> class == OBERON_TYPE_ARRAY + || x -> type -> class == OBERON_TYPE_RECORD) + { + jvm_generate_new_static(p, x -> type); + jvm_generate_store(p, x -> type, x -> gen_var); + } + } + x = x -> next; + } } void @@ -459,11 +682,13 @@ static void jvm_init_local_object(gen_proc_t * p, oberon_object_t * x) { gen_var_t * v; + bool wide; char * desc; struct gen_class * class; v = x -> gen_var; class = p -> class; + wide = jvm_is_wide_type(x -> type); desc = jvm_get_descriptor(x -> type); // Убеждаемся что сейчас находимся в функции @@ -474,8 +699,7 @@ jvm_init_local_object(gen_proc_t * p, oberon_object_t * x) { case OBERON_CLASS_VAR: case OBERON_CLASS_PARAM: - v -> reg = jvm_alloc_register(p -> rf, x -> type); - fprintf(class -> fp, ".var %i is %s %s from start to end\n", v -> reg, x -> name, desc); + jvm_generate_and_init_named_local_var(v, p, wide, x -> name, desc); break; default: gen_error("jvm_init_local_object: wat"); @@ -594,41 +818,17 @@ jvm_push_var(gen_proc_t * p, oberon_object_t * var) } static void -jvm_generate_new_static(gen_proc_t * p, oberon_type_t * type, int num, oberon_expr_t * arg) +jvm_generate_expr_new_static(gen_proc_t * p, oberon_type_t * type, int num, oberon_expr_t * arg) { - //char * desc; - char * cname; - //desc = jvm_get_descriptor(type); - cname = jvm_get_class_full_name(type); - - switch(type -> class) - { - case OBERON_TYPE_INTEGER: - case OBERON_TYPE_BOOLEAN: - case OBERON_TYPE_PROCEDURE: - case OBERON_TYPE_REAL: - case OBERON_TYPE_POINTER: - /* ничего не надо делать при статической инициализации */ - break; - case OBERON_TYPE_RECORD: - jvm_generate(p, 0, 1, "new %s", cname); - jvm_generate(p, 1, 2, "dup"); - jvm_generate(p, 1, 0, "invokespecial %s/()V", cname); - break; - case OBERON_TYPE_ARRAY: - gen_error("jvm_generate_new_static: TODO array"); - break; - default: - gen_error("jvm_generate_new_static: unk type class %i", type -> class); - break; - } + assert(num == 0); + jvm_generate_new_static(p, type); } static void -jvm_generate_new_pointer(gen_proc_t * p, oberon_type_t * type, int num, oberon_expr_t * arg) +jvm_generate_expr_new_pointer(gen_proc_t * p, oberon_type_t * type, int num, oberon_expr_t * arg) { assert(type -> class == OBERON_TYPE_POINTER); - jvm_generate_new_static(p, type -> base, num, arg); + jvm_generate_expr_new_static(p, type -> base, num, arg); } static void @@ -649,7 +849,12 @@ push_item(gen_proc_t * p, oberon_item_t * item) jvm_generate_call_proc(p, (oberon_expr_t *) item); break; case MODE_INDEX: - gen_error("push_item: TODO index"); + ; + char postfix = jvm_get_postfix(item -> result); + int cell_size = jvm_cell_size_for_postfix(postfix); + push_item(p, item -> parent); + push_expr(p, item -> args); + jvm_generate(p, 1 + 1, cell_size, "%caload", postfix); break; case MODE_FIELD: push_item(p, item -> parent); @@ -665,7 +870,7 @@ push_item(gen_proc_t * p, oberon_item_t * item) jvm_generate(p, 0, 1, "aconst_null"); break; case MODE_NEW: - jvm_generate_new_pointer(p, item -> result, item -> num_args, item -> args); + jvm_generate_expr_new_pointer(p, item -> result, item -> num_args, item -> args); break; case MODE_REAL: jvm_generate_push_float(p, item -> real, item -> result -> size); @@ -696,7 +901,7 @@ static void jvm_generate_abs(gen_proc_t * p, char prefix) { char t = jvm_get_type_of_prefix(prefix); - int cell_size = jvm_cell_size_for_prefix(prefix); + int cell_size = jvm_cell_size_for_postfix(prefix); jvm_generate(p, cell_size, cell_size, "invokestatic java/lang/Math/abs(%c)%c", t, t); } @@ -707,7 +912,7 @@ jvm_generate_compare_op(gen_proc_t * p, char prefix, int op) int label_done = jvm_new_label_id(p); char * label_name_true = jvm_get_label_name(label_true); char * label_name_done = jvm_get_label_name(label_done); - int cell_size = 2 * jvm_cell_size_for_prefix(prefix); + int cell_size = 2 * jvm_cell_size_for_postfix(prefix); assert(prefix == 'i' || prefix == 'a'); @@ -748,7 +953,7 @@ jvm_generate_compare_op(gen_proc_t * p, char prefix, int op) static void jvm_generate_operator(gen_proc_t * p, char prefix, int op) { - int cell_size = jvm_cell_size_for_prefix(prefix); + int cell_size = jvm_cell_size_for_postfix(prefix); switch(op) { case OP_UNARY_MINUS: @@ -908,37 +1113,36 @@ store_expr(gen_proc_t * p, oberon_expr_t * dst, oberon_expr_t * src) assert(dst -> is_item); oberon_item_t * item = (oberon_item_t *) dst; - int cell_size = jvm_cell_size_for_type(src -> result); + if(dst -> result -> class == OBERON_TYPE_ARRAY + || src -> result -> class == OBERON_TYPE_ARRAY) + { + gen_error("array copy not implemented"); + } + else if(dst -> result -> class == OBERON_TYPE_RECORD + || src -> result -> class == OBERON_TYPE_RECORD) + { + gen_error("record copy not implemented"); + } - char prefix; switch(item -> mode) { case MODE_VAR: push_expr(p, src); - if(item -> var -> local) - { - int reg = item -> var -> gen_var -> reg; - prefix = jvm_get_prefix(item -> result); - jvm_generate(p, cell_size, 0, "%cstore %i", prefix, reg); - } - else - { - char * fullname = jvm_get_field_full_name(item -> var); - char * desc = jvm_get_descriptor(item -> result); - jvm_generate(p, cell_size, 0, "putstatic %s %s", fullname, desc); - } + jvm_generate_store(p, src -> result, item -> var -> gen_var); break; case MODE_INDEX: - gen_error("store_expr: TODO index"); + ; + char postfix = jvm_get_postfix(src -> result); + int cell_size = jvm_cell_size_for_postfix(postfix); + push_item(p, item -> parent); + push_expr(p, item -> args); + push_expr(p, src); + jvm_generate(p, 1 + 1 + cell_size, 0, "%castore", postfix); break; case MODE_FIELD: - { - char * fullname = jvm_get_field_full_name(item -> var); - char * desc = jvm_get_descriptor(item -> result); - push_item(p, item -> parent); - push_expr(p, src); - jvm_generate(p, 1 + cell_size, 0, "putfield %s %s", fullname, desc); - } + push_item(p, item -> parent); + push_expr(p, src); + jvm_generate_store(p, src -> result, item -> var -> gen_var); break; default: gen_error("store_expr: unk mode %i", item -> mode);