X-Git-Url: https://deadsoftware.ru/gitweb?a=blobdiff_plain;f=src%2Fbackends%2Fjvm%2Fgenerator-jvm.c;h=215f6d757b1d92fd1b1b2c67ed088333959e927d;hb=351f950548241d4c4bd799acabbcd98a39b096cc;hp=2a2abcdcd3632f1b73a22aecc2135138f8e94523;hpb=2a0d7e7fbb7dcccc65f98301a0627ee47c755f2f;p=dsw-obn.git diff --git a/src/backends/jvm/generator-jvm.c b/src/backends/jvm/generator-jvm.c index 2a2abcd..215f6d7 100644 --- a/src/backends/jvm/generator-jvm.c +++ b/src/backends/jvm/generator-jvm.c @@ -96,6 +96,9 @@ get_descriptor(oberon_context_t * ctx, oberon_type_t * type) case OBERON_TYPE_BOOLEAN: return new_string("Z"); break; + case OBERON_TYPE_POINTER: + return get_descriptor(ctx, type -> base); + break; case OBERON_TYPE_PROCEDURE: case OBERON_TYPE_RECORD: desc = get_class_full_name(ctx, type); @@ -141,7 +144,21 @@ get_prefix(oberon_context_t * ctx, oberon_type_t * type) static char * get_field_full_name(oberon_context_t * ctx, oberon_object_t * x) { - return new_string("%s/%s", x -> module -> name, x -> name); + switch(x -> class) + { + case OBERON_CLASS_VAR: + return new_string("%s/%s", x -> module -> name, x -> name); + case OBERON_CLASS_FIELD:; + char * rec_name = get_class_full_name(ctx, x -> parent_type); + return new_string("%s/%s", rec_name, x -> name); + case OBERON_CLASS_MODULE: + return new_string(x -> module -> name); + default: + oberon_error(ctx, "get_field_full_name: wat"); + break; + } + + return NULL; } static char * @@ -170,8 +187,6 @@ get_class_full_name(oberon_context_t * ctx, oberon_type_t * type) break; case OBERON_TYPE_RECORD: - assert(type -> module); - assert(type -> module -> gen_mod); rec_id = type -> gen_type -> rec_id; name = new_string("%s$RECORD%i", type -> module -> name, rec_id); break; @@ -229,7 +244,7 @@ oberon_generate_procedure_class(oberon_context_t * ctx, oberon_type_t * proc) fprintf(fp, " aload_0\n"); fprintf(fp, " invokespecial java/lang/Object/()V\n"); fprintf(fp, " return\n"); - fprintf(fp, ".end method\n"); + fprintf(fp, ".end method\n\n"); fprintf(fp, ".method public abstract invoke%s\n", signature); fprintf(fp, ".end method\n\n"); @@ -282,7 +297,6 @@ oberon_generator_init_type(oberon_context_t * ctx, oberon_type_t * type) oberon_generate_procedure_class(ctx, type); break; case OBERON_TYPE_POINTER: - assert(type -> base -> class == OBERON_TYPE_VOID); break; default: oberon_error(ctx, "oberon_generator_init_type: unk calss %i", type -> class); @@ -301,7 +315,10 @@ oberon_generate_object(oberon_context_t * ctx, FILE * fp, oberon_object_t * x) switch(x -> class) { case OBERON_CLASS_VAR: - fprintf(fp, ".field public static %s %s\n\n", name, desc); + if(x -> local == 0) + { + fprintf(fp, ".field public static %s %s\n\n", name, desc); + } break; case OBERON_CLASS_FIELD: fprintf(fp, ".field public %s %s\n\n", name, desc); @@ -347,6 +364,9 @@ oberon_generator_init_var(oberon_context_t * ctx, oberon_object_t * var) switch(var -> class) { + case OBERON_CLASS_VAR_PARAM: + oberon_error(ctx, "generator: VAR-parameters not implemented"); + break; case OBERON_CLASS_PARAM: case OBERON_CLASS_FIELD: break; @@ -366,6 +386,10 @@ oberon_generator_init_proc(oberon_context_t * ctx, oberon_object_t * proc) memset(p, 0, sizeof *p); proc -> gen_proc = p; + struct gen_register_file * rf = GC_MALLOC(sizeof *rf); + memset(rf, 0, sizeof *rf); + p -> rf = rf; + if(proc -> local) { oberon_error(ctx, "generator: local procedures not implemented"); @@ -398,6 +422,9 @@ oberon_generator_init_module(oberon_context_t * ctx, oberon_module_t * mod) // GENERATOR // ======================================================================= +static void +push_expr(oberon_context_t * ctx, FILE * fp, oberon_expr_t * expr); + void oberon_generate_begin_module(oberon_context_t * ctx) { @@ -418,45 +445,199 @@ oberon_generate_end_module(oberon_context_t * ctx) fprintf(m -> fp, ".end method\n"); } +static int +jvm_cell_size_for_type(oberon_type_t * type) +{ + if(type -> class == OBERON_TYPE_INTEGER + || type -> class == OBERON_TYPE_REAL) + { + if(type -> size > 4) + { + return 2; + } + } + + return 1; +} + +static bool +jvm_is_wide_type(oberon_type_t * type) +{ + int cell; + cell = jvm_cell_size_for_type(type); + assert(cell <= 2); + return (cell == 2); +} + +static 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); + } +} + +static int +jvm_alloc_register(struct gen_register_file * rf, oberon_type_t * type) +{ + bool wide; + wide = jvm_is_wide_type(type); + + 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; +} + +static void +jvm_init_local_object(oberon_context_t * ctx, FILE * fp, oberon_object_t * x) +{ + int reg; + gen_context_t * c; + gen_var_t * v; + char * desc; + + c = ctx -> gen_context; + v = x -> gen_var; + desc = get_descriptor(ctx, x -> type); + + reg = -1; + switch(x -> class) + { + case OBERON_CLASS_VAR: + case OBERON_CLASS_PARAM: + if(x -> local) + { + reg = jvm_alloc_register(c -> rf, x -> type); + } + v -> reg = reg; + fprintf(fp, ".var %i is %s %s from start to end\n", reg, x -> name, desc); + break; + default: + oberon_error(ctx, "jvm_init_local_object: wat"); + break; + } +} + void oberon_generate_begin_proc(oberon_context_t * ctx, oberon_object_t * proc) { + gen_context_t * c; gen_module_t * m; + gen_proc_t * p; char * signature; + c = ctx -> gen_context; m = ctx -> mod -> gen_mod; - signature = get_procedure_signature(ctx, proc -> type); + p = proc -> gen_proc; + signature = get_procedure_signature(ctx, proc -> type); fprintf(m -> fp, ".method public static %s%s\n", proc -> name, signature); -} -void -oberon_generate_call_proc(oberon_context_t * ctx, oberon_expr_t * desig) -{ - printf("call proc\n"); + /* Сохраняем регистровый файл в стеке */ + p -> rf -> up = c -> rf; + c -> rf = p -> rf; + + oberon_object_t * var = proc -> type -> decl; + while(var) + { + jvm_init_local_object(ctx, m -> fp, var); + var = var -> next; + } + + fprintf(m -> fp, "start:\n"); } void oberon_generate_end_proc(oberon_context_t * ctx) { + gen_context_t * c; gen_module_t * m; + + c = ctx -> gen_context; m = ctx -> mod -> gen_mod; + fprintf(m -> fp, "end:\n"); fprintf(m -> fp, " .limit stack 32\n"); - fprintf(m -> fp, " .limit locals 32\n"); + fprintf(m -> fp, " .limit locals %i\n", c -> rf -> max_used); fprintf(m -> fp, ".end method\n\n"); + + /* Возвращаем исходный регистровый файл */ + c -> rf = c -> rf -> up; +} + +void +oberon_generate_call_proc(oberon_context_t * ctx, oberon_expr_t * desig) +{ + oberon_object_t * proc; + gen_module_t * m; + char * fullname; + char * signature; + + assert(desig -> is_item); + assert(desig -> item.mode == MODE_CALL); + + m = ctx -> mod -> gen_mod; + proc = desig -> item.var; + fullname = get_field_full_name(ctx, proc); + signature = get_procedure_signature(ctx, proc -> type); + + int num = desig -> item.num_args; + oberon_expr_t * arg = desig -> item.args; + for(int i = 0; i < num; i++) + { + push_expr(ctx, m -> fp, arg); + arg = arg -> next; + } + + fprintf(m -> fp, "invokestatic %s%s\n", fullname, signature); } void oberon_generate_return(oberon_context_t * ctx, oberon_expr_t * expr) { gen_module_t * m; + char prefix; m = ctx -> mod -> gen_mod; if(expr) { - oberon_error(ctx, "oberon_generate_return: TODO return expr"); + push_expr(ctx, m -> fp, expr); + prefix = get_prefix(ctx, expr -> result); + fprintf(m -> fp, " %creturn\n", prefix); } else { @@ -532,8 +713,6 @@ push_float(FILE * fp, double f, int size) } } -static void push_expr(oberon_context_t * ctx, FILE * fp, oberon_expr_t * expr); - static void push_var(oberon_context_t * ctx, FILE * fp, oberon_object_t * var) { @@ -551,6 +730,44 @@ push_var(oberon_context_t * ctx, FILE * fp, oberon_object_t * var) } } +static void +jvm_generate_new_static(oberon_context_t * ctx, FILE * fp, oberon_type_t * type, int num, oberon_expr_t * arg) +{ + //char * desc; + char * cname; + //desc = get_descriptor(ctx, type); + cname = get_class_full_name(ctx, 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: + fprintf(fp, "new %s\n", cname); + fprintf(fp, "dup\n"); + fprintf(fp, "invokespecial %s/()V\n", cname); + break; + case OBERON_TYPE_ARRAY: + oberon_error(ctx, "jvm_generate_new_static: TODO array"); + break; + default: + oberon_error(ctx, "jvm_generate_new_static: unk type class %i", type -> class); + break; + } +} + +static void +jvm_generate_new_pointer(oberon_context_t * ctx, FILE * fp, oberon_type_t * type, int num, oberon_expr_t * arg) +{ + assert(type -> class == OBERON_TYPE_POINTER); + jvm_generate_new_static(ctx, fp, type -> base, num, arg); +} + static void push_item(oberon_context_t * ctx, FILE * fp, oberon_item_t * item) { @@ -566,22 +783,26 @@ push_item(oberon_context_t * ctx, FILE * fp, oberon_item_t * item) push_int(fp, item -> boolean); break; case MODE_CALL: - oberon_error(ctx, "push_item: TODO call"); + oberon_generate_call_proc(ctx, (oberon_expr_t *) item); break; case MODE_INDEX: oberon_error(ctx, "push_item: TODO index"); break; case MODE_FIELD: - oberon_error(ctx, "push_item: TODO field"); + push_item(ctx, fp, item -> parent); + char * field = get_field_full_name(ctx, item -> var); + char * desc = get_descriptor(ctx, item -> var -> type); + fprintf(fp, "getfield %s %s\n", field, desc); break; case MODE_DEREF: - oberon_error(ctx, "push_item: TODO deref"); + /* Все объекты представляются как увказатели */ + push_item(ctx, fp, item -> parent); break; case MODE_NIL: fprintf(fp, "aconst_null\n"); break; case MODE_NEW: - oberon_error(ctx, "push_item: TODO new"); + jvm_generate_new_pointer(ctx, fp, item -> result, item -> num_args, item -> args); break; case MODE_REAL: push_float(fp, item -> real, item -> result -> size); @@ -592,60 +813,155 @@ push_item(oberon_context_t * ctx, FILE * fp, oberon_item_t * item) } } +static int +jvm_new_label_id(oberon_context_t * ctx) +{ + gen_context_t * c = ctx -> gen_context; + int label_id = c -> label_id; + c -> label_id += 1; + return label_id; +} + +static char * +jvm_get_label_name(int label_id) +{ + return new_string("L%i", label_id); +} + static void -push_operator(oberon_context_t * ctx, FILE * fp, oberon_oper_t * oper) +jvm_generate_label(FILE * fp, int label_id) { - char prefix = get_prefix(ctx, oper -> result); - switch(oper -> op) + fprintf(fp, "L%i:\n", label_id); +} + +static void +jvm_generate_logical_not(oberon_context_t * ctx, FILE * fp) +{ + int label_true = jvm_new_label_id(ctx); + int label_false = jvm_new_label_id(ctx); + char * label_name_true = jvm_get_label_name(label_true); + char * label_name_false = jvm_get_label_name(label_false); + + fprintf(fp, "ifne %s\n", label_name_false); + fprintf(fp, "iconst_1\n"); + fprintf(fp, "goto %s\n", label_name_true); + jvm_generate_label(fp, label_false); + fprintf(fp, "iconst_0\n"); + jvm_generate_label(fp, label_true); +} + +static 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); +} + +static void +jvm_generate_abs(FILE * fp, char prefix) +{ + char t = jvm_get_type_of_prefix(prefix); + fprintf(fp, "invokestatic java/lang/Math/abs(%c)%c\n", t, t); +} + +static void +jvm_generate_compare_op(oberon_context_t * ctx, FILE *fp, char prefix, int op) +{ + int label_true = jvm_new_label_id(ctx); + int label_false = jvm_new_label_id(ctx); + char * label_name_true = jvm_get_label_name(label_true); + char * label_name_false = jvm_get_label_name(label_false); + + assert(prefix == 'i' || prefix == 'a'); + + switch(op) + { + case OP_EQ: + fprintf(fp, "if_%ccmpeq %s\n", prefix, label_name_true); + break; + case OP_NEQ: + fprintf(fp, "if_%ccmpne %s\n", prefix, label_name_true); + break; + case OP_LSS: + fprintf(fp, "if_icmplt %s\n", label_name_true); + break; + case OP_LEQ: + fprintf(fp, "if_icmple %s\n", label_name_true); + break; + case OP_GRT: + fprintf(fp, "if_icmpgt %s\n", label_name_true); + break; + case OP_GEQ: + fprintf(fp, "if_icmpge %s\n", label_name_true); + break; + default: + oberon_error(ctx, "jvm_generate_compare_op: wat"); + break; + } + + fprintf(fp, "iconst_0\n"); + fprintf(fp, "goto %s\n", label_name_false); + jvm_generate_label(fp, label_true); + fprintf(fp, "iconst_1\n"); + jvm_generate_label(fp, label_false); +} + +static void +jvm_generate_operator(oberon_context_t * ctx, FILE *fp, char prefix, int op) +{ + switch(op) { case OP_UNARY_MINUS: - push_expr(ctx, fp, oper -> left); fprintf(fp, "%cneg\n", prefix); break; case OP_BITWISE_NOT: - push_expr(ctx, fp, oper -> left); push_int(fp, -1); fprintf(fp, "%cxor\n", prefix); break; + case OP_LOGIC_NOT: + jvm_generate_logical_not(ctx, fp); + break; + case OP_ABS: + jvm_generate_abs(fp, prefix); + break; case OP_ADD: - push_expr(ctx, fp, oper -> left); - push_expr(ctx, fp, oper -> right); fprintf(fp, "%cadd\n", prefix); break; case OP_SUB: - push_expr(ctx, fp, oper -> left); - push_expr(ctx, fp, oper -> right); fprintf(fp, "%csub\n", prefix); break; case OP_MUL: - push_expr(ctx, fp, oper -> left); - push_expr(ctx, fp, oper -> right); fprintf(fp, "%cmul\n", prefix); break; case OP_DIV: - push_expr(ctx, fp, oper -> left); - push_expr(ctx, fp, oper -> right); fprintf(fp, "%cdiv\n", prefix); break; case OP_MOD: - push_expr(ctx, fp, oper -> left); - push_expr(ctx, fp, oper -> right); fprintf(fp, "%crem\n", prefix); break; case OP_BITWISE_AND: - push_expr(ctx, fp, oper -> left); - push_expr(ctx, fp, oper -> right); fprintf(fp, "%cand\n", prefix); break; case OP_BITWISE_XOR: - push_expr(ctx, fp, oper -> left); - push_expr(ctx, fp, oper -> right); fprintf(fp, "%cxor\n", prefix); break; case OP_BITWISE_OR: - push_expr(ctx, fp, oper -> left); - push_expr(ctx, fp, oper -> right); fprintf(fp, "%cor\n", prefix); break; @@ -655,12 +971,95 @@ push_operator(oberon_context_t * ctx, FILE * fp, oberon_oper_t * oper) case OP_LEQ: case OP_GRT: case OP_GEQ: + jvm_generate_compare_op(ctx, fp, prefix, op); + break; + default: + oberon_error(ctx, "jvm_generate_operator: unk op %i", op); + break; + } +} + +static void +jvm_generate_logical_or(oberon_context_t * ctx, FILE * fp, oberon_expr_t * p, oberon_expr_t * q) +{ + int label_calc_q = jvm_new_label_id(ctx); + int label_done = jvm_new_label_id(ctx); + char * label_name_calc_q = jvm_get_label_name(label_calc_q); + char * label_name_done = jvm_get_label_name(label_done); + + /* p OR q -- если p, то TRUE, иначе q */ + + push_expr(ctx, fp, p); + fprintf(fp, "ifne %s\n", label_name_calc_q); + fprintf(fp, "iconst_1\n"); + fprintf(fp, "goto %s\n", label_name_done); + jvm_generate_label(fp, label_calc_q); + push_expr(ctx, fp, q); + jvm_generate_label(fp, label_done); +} + +static void +jvm_generate_logical_and(oberon_context_t * ctx, FILE * fp, oberon_expr_t * p, oberon_expr_t * q) +{ + int label_false = jvm_new_label_id(ctx); + int label_done = jvm_new_label_id(ctx); + char * label_name_false = jvm_get_label_name(label_false); + char * label_name_done = jvm_get_label_name(label_done); + + /* p AND q -- если p, то q, иначе FALSE */ + + push_expr(ctx, fp, p); + fprintf(fp, "ifne %s\n", label_name_false); + push_expr(ctx, fp, q); + fprintf(fp, "goto %s\n", label_name_done); + jvm_generate_label(fp, label_false); + fprintf(fp, "iconst_0\n"); + jvm_generate_label(fp, label_done); +} + +static void +push_operator(oberon_context_t * ctx, FILE * fp, oberon_oper_t * oper) +{ + char prefix = get_prefix(ctx, oper -> result); + int op = oper -> op; + switch(op) + { + case OP_UNARY_MINUS: + case OP_BITWISE_NOT: case OP_LOGIC_NOT: case OP_ABS: - oberon_error(ctx, "push_oper: TODO op %i", oper -> op); + push_expr(ctx, fp, oper -> left); + jvm_generate_operator(ctx, fp, prefix, op); + break; + + case OP_ADD: + case OP_SUB: + case OP_MUL: + case OP_DIV: + case OP_MOD: + case OP_BITWISE_AND: + case OP_BITWISE_XOR: + case OP_BITWISE_OR: + + case OP_EQ: + case OP_NEQ: + case OP_LSS: + case OP_LEQ: + case OP_GRT: + case OP_GEQ: + push_expr(ctx, fp, oper -> left); + push_expr(ctx, fp, oper -> right); + jvm_generate_operator(ctx, fp, prefix, op); + break; + + case OP_LOGIC_OR: + jvm_generate_logical_or(ctx, fp, oper -> left, oper -> right); + break; + case OP_LOGIC_AND: + jvm_generate_logical_and(ctx, fp, oper -> left, oper -> right); break; default: - oberon_error(ctx, "push_oper: unk op %i", oper -> op); + oberon_error(ctx, "push_oper: unk op %i", op); break; } } @@ -679,15 +1078,16 @@ push_expr(oberon_context_t * ctx, FILE * fp, oberon_expr_t * expr) } static void -store_expr(oberon_context_t * ctx, FILE * fp, oberon_expr_t * expr) +store_expr(oberon_context_t * ctx, FILE * fp, oberon_expr_t * dst, oberon_expr_t * src) { - assert(expr -> is_item); - oberon_item_t * item = (oberon_item_t *) expr; + assert(dst -> is_item); + oberon_item_t * item = (oberon_item_t *) dst; char prefix; switch(item -> mode) { case MODE_VAR: + push_expr(ctx, fp, src); if(item -> var -> local) { int reg = item -> var -> gen_var -> reg; @@ -701,6 +1101,21 @@ store_expr(oberon_context_t * ctx, FILE * fp, oberon_expr_t * expr) fprintf(fp, "putstatic %s %s\n", fullname, desc); } break; + case MODE_INDEX: + oberon_error(ctx, "store_expr: TODO index"); + break; + case MODE_FIELD: + { + char * fullname = get_field_full_name(ctx, item -> var); + char * desc = get_descriptor(ctx, item -> result); + printf("push parent\n"); + push_item(ctx, fp, item -> parent); + printf("push expr\n"); + push_expr(ctx, fp, src); + printf("store to field %s:%s\n", fullname, desc); + fprintf(fp, "putfield %s %s ; store field\n", fullname, desc); + } + break; default: oberon_error(ctx, "store_expr: unk mode %i", item -> mode); break; @@ -713,8 +1128,7 @@ oberon_generate_assign(oberon_context_t * ctx, oberon_expr_t * src, oberon_expr_ gen_module_t * m; m = ctx -> mod -> gen_mod; - push_expr(ctx, m -> fp, src); - store_expr(ctx, m -> fp, dst); + store_expr(ctx, m -> fp, dst, src); } void