#include #include #include #include #include #include #include #include #include "../../oberon-internals.h" #include "../../oberon-type-compat.h" #include "../../generator.h" #include "generator-jvm.h" #include "generator-jvm-abi.h" #include "generator-jvm-asm.h" #include "generator-jvm-basic.h" static void push_item(gen_proc_t * p, oberon_item_t * item); static void jvm_generate_new(gen_proc_t * p, oberon_type_t * type, int num); static void jvm_generate_cast_prefix(gen_proc_t * p, char prefix, char postfix) { if((prefix == 'b' || prefix == 's') && (postfix = 'l' || postfix == 'd')) { prefix = 'i'; } if(prefix == postfix) { return; } if((prefix == 'l' || prefix == 'd') && (postfix == 'b' || postfix == 's')) { jvm_generate(p, 2, 1, "%c2i", prefix); prefix = 'i'; } int from_cell_size = jvm_cell_size_for_postfix(prefix); int to_cell_size = jvm_cell_size_for_postfix(postfix); jvm_generate(p, from_cell_size, to_cell_size, "%c2%c", prefix, postfix); } static void jvm_generate_cast_type(gen_proc_t * p, oberon_type_t * from, oberon_type_t * to) { if(to -> class == OBERON_TYPE_RECORD || to -> class == OBERON_TYPE_POINTER) { if(to -> class == OBERON_TYPE_POINTER && to -> base -> class == OBERON_TYPE_RECORD) { char * full_name = jvm_get_class_full_name(to); jvm_generate(p, 1, 1, "checkcast %s", full_name); } } else { char prefix = jvm_get_prefix(from); char postfix = jvm_get_postfix(to); jvm_generate_cast_prefix(p, prefix, postfix); } } static void jvm_generate_hard_cast_type(gen_proc_t * p, oberon_type_t * from, oberon_type_t * to) { if(from -> class == OBERON_TYPE_REAL && (to -> class == OBERON_TYPE_INTEGER || to -> class == OBERON_TYPE_SYSTEM_BYTE)) { char postfix = jvm_get_postfix(to); if(from -> size <= 4) { jvm_generate(p, 1, 1, "invokestatic java/lang/Float/floatToRawIntBits(F)I"); jvm_generate_cast_prefix(p, 'i', postfix); } else { jvm_generate(p, 2, 2, "invokestatic java/lang/Double/doubleToRawLongBits(D)J"); jvm_generate_cast_prefix(p, 'l', postfix); } } else if((from -> class == OBERON_TYPE_INTEGER || from -> class == OBERON_TYPE_SYSTEM_BYTE) && to -> class == OBERON_TYPE_REAL) { char prefix = jvm_get_prefix(from); if(to -> size <= 4) { jvm_generate_cast_prefix(p, prefix, 'i'); jvm_generate(p, 1, 1, "invokestatic java/lang/Float/intBitsToFloat(I)F"); } else { jvm_generate_cast_prefix(p, prefix, 'l'); jvm_generate(p, 2, 2, "invokestatic java/lang/Double/longBitsToDouble(J)D"); } } else { jvm_generate_cast_type(p, from, to); } } static void check_index(gen_proc_t * p, oberon_type_t * index_type) { // TODO проверка валидности границ char prefix = jvm_get_prefix(index_type); jvm_generate_cast_prefix(p, prefix, 'i'); } /* * Генерирует код для инициализации массива со статическим базовым типом * ( aref -- ) */ static void jvm_generate_array_initialization(gen_proc_t * p, oberon_type_t * arr) { int dim = 0; oberon_type_t * base = arr; while(base -> class == OBERON_TYPE_ARRAY) { dim += 1; base = base -> base; } if(base -> class != OBERON_TYPE_RECORD) { jvm_generate(p, 1, 0, "pop"); return; } struct { int reg_index; int reg_length; int start; int end; } loop[dim]; int reg_dst; reg_dst = jvm_alloc_register_untyped(p -> rf, false); jvm_generate(p, 1, 0, "astore %i", reg_dst); /* * Входящие параметры заграблены. * Теперь генерируем эквивалентный код: * int i = 0; * int len = dst.length * while(i < len) * { * ... * { * dst[i, ...] = new record; * } * ... * i += 1; * } * Где "..." такой же код (начало и конец) для следующей размерности. */ for(int i = 0; i < dim; i++) { loop[i].reg_index = jvm_alloc_register_untyped(p -> rf, false); loop[i].reg_length = jvm_alloc_register_untyped(p -> rf, false); loop[i].start = jvm_new_label_id(p); loop[i].end = jvm_new_label_id(p); jvm_generate(p, 0, 1, "iconst_0"); jvm_generate(p, 1, 0, "istore %i", loop[i].reg_index); jvm_generate(p, 0, 1, "aload %i", reg_dst); jvm_generate(p, 1, 1, "arraylength"); jvm_generate(p, 1, 0, "istore %i", loop[i].reg_length); /* if(i >= len) goto end; */ jvm_generate_label(p, loop[i].start); jvm_generate(p, 0, 1, "iload %i", loop[i].reg_index); jvm_generate(p, 0, 1, "iload %i", loop[i].reg_length); jvm_generate(p, 2, 0, "if_icmpge L%i", loop[i].end); } jvm_generate(p, 0, 1, "aload %i", reg_dst); jvm_generate(p, 0, 1, "iload %i", loop[0].reg_index); for(int i = 1; i < dim; i++) { jvm_generate(p, 2, 1, "aaload"); jvm_generate(p, 0, 1, "iload %i", loop[i].reg_index); } jvm_generate_new(p, base, 0); jvm_generate(p, 3, 0, "aastore"); for(int i = dim - 1; i >= 0; i--) { jvm_generate(p, 0, 0, "iinc %i 1", loop[i].reg_index); jvm_generate(p, 0, 0, "goto L%i", loop[i].start); jvm_generate_label(p, loop[i].end); } } static void jvm_generate_new(gen_proc_t * p, oberon_type_t * type, int num) { 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: assert(num == 0); 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) { if(num > 0) { assert(base -> size == 0); num -= 1; } else { assert(base -> size > 0); jvm_generate_push_int(p, base -> size); } dim += 1; base = base -> base; } assert(num == 0); jvm_generate(p, dim, 1, "multianewarray %s %i", desc, dim); jvm_generate(p, 1, 2, "dup"); jvm_generate_array_initialization(p, type); break; default: gen_error("jvm_generate_new_static: unk type class %i", type -> class); break; } } /* * Генерирует код для копирования полей из первой записи во вторую. * ( aref_dst aref_src -- ) * dst := src; */ static void jvm_generate_copy_record(gen_proc_t * p, oberon_type_t * rec) { assert(rec -> class == OBERON_TYPE_RECORD); char * desc = jvm_get_descriptor(rec); char * cname = jvm_get_class_full_name(rec); jvm_generate(p, 1 + 1, 0, "invokestatic %s/$COPY$(%s%s)V", cname, desc, desc); } /* * Генерирует кода для копирования массивов. * ( aref_dst aref_src -- ) * dst := src; */ static void jvm_generate_copy_array(gen_proc_t * p, oberon_type_t * arr) { int dim = 0; oberon_type_t * base = arr; while(base -> class == OBERON_TYPE_ARRAY) { dim += 1; base = base -> base; } struct { int reg_index; int reg_length; int start; int end; } loop[dim]; int reg_dst = jvm_alloc_register_untyped(p -> rf, false); int reg_src = jvm_alloc_register_untyped(p -> rf, false); jvm_generate(p, 1, 0, "astore %i", reg_src); jvm_generate(p, 1, 0, "astore %i", reg_dst); /* * Входящие параметры заграблены. * Теперь генерируем эквивалентный код: * int i = 0; * int len = src.length * while(i < len) * { * ... * { * copy from src[i, ...] to dst[i, ...]; * } * ... * i += 1; * } * Где "..." такой же код (начало и конец) для следующей размерности. */ for(int i = 0; i < dim; i++) { loop[i].reg_index = jvm_alloc_register_untyped(p -> rf, false); loop[i].reg_length = jvm_alloc_register_untyped(p -> rf, false); loop[i].start = jvm_new_label_id(p); loop[i].end = jvm_new_label_id(p); jvm_generate(p, 0, 1, "iconst_0"); jvm_generate(p, 1, 0, "istore %i", loop[i].reg_index); jvm_generate(p, 0, 1, "aload %i", reg_src); jvm_generate(p, 1, 1, "arraylength"); jvm_generate(p, 1, 0, "istore %i", loop[i].reg_length); /* if(i >= len) goto end; */ jvm_generate_label(p, loop[i].start); jvm_generate(p, 0, 1, "iload %i", loop[i].reg_index); jvm_generate(p, 0, 1, "iload %i", loop[i].reg_length); jvm_generate(p, 2, 0, "if_icmpge L%i", loop[i].end); } if(base -> class == OBERON_TYPE_RECORD) { /* Получаем записи по индексам ( -- dst src ) */ jvm_generate(p, 0, 1, "aload %i", reg_dst); for(int i = 0; i < dim; i++) { jvm_generate(p, 0, 1, "iload %i", loop[i].reg_index); jvm_generate(p, 2, 1, "aaload"); } jvm_generate(p, 0, 1, "aload %i", reg_src); for(int i = 0; i < dim; i++) { jvm_generate(p, 0, 1, "iload %i", loop[i].reg_index); jvm_generate(p, 2, 1, "aaload"); } /* Копируем записи ( dst src -- ) */ jvm_generate_copy_record(p, base); } else { char postfix = jvm_get_postfix(base); int cell_size = jvm_cell_size_for_postfix(postfix); /* Получаем массивы и индексы ( -- dst i src i ) */ jvm_generate(p, 0, 1, "aload %i", reg_dst); jvm_generate(p, 0, 1, "iload %i", loop[0].reg_index); for(int i = 1; i < dim; i++) { jvm_generate(p, 2, 1, "aaload"); jvm_generate(p, 0, 1, "iload %i", loop[i].reg_index); } jvm_generate(p, 0, 1, "aload %i", reg_src); jvm_generate(p, 0, 1, "iload %i", loop[0].reg_index); for(int i = 1; i < dim; i++) { jvm_generate(p, 2, 1, "aaload"); jvm_generate(p, 0, 1, "iload %i", loop[i].reg_index); } /* Копируем значения ( dst i src i -- ) */ jvm_generate(p, 2, cell_size, "%caload", postfix); jvm_generate(p, 2 + cell_size, 0, "%castore", postfix); } for(int i = dim - 1; i >= 0; i--) { jvm_generate(p, 0, 0, "iinc %i 1", loop[i].reg_index); jvm_generate(p, 0, 0, "goto L%i", loop[i].start); jvm_generate_label(p, loop[i].end); } } static void jvm_generate_push_procedure_pointer(gen_proc_t * p, oberon_object_t * proc) { char * full_name = jvm_get_field_full_name_safe(proc); char * desc = jvm_get_descriptor(proc -> type); jvm_generate(p, 0, 1, "getstatic %s/pointer %s", full_name, desc); } void oberon_generator_init_context(oberon_context_t * ctx) { gen_context_t * gen_context = GC_MALLOC(sizeof *gen_context); memset(gen_context, 0, sizeof *gen_context); ctx -> gen_context = gen_context; gen_context -> dir = "."; } void oberon_generator_destroy_context(oberon_context_t * ctx) { } static void oberon_generate_procedure_class(const char * dir, oberon_type_t * proc) { FILE * fp; char * cname; char * signature; struct gen_class * class; cname = jvm_get_class_full_name(proc); class = jvm_create_class(dir, cname); fp = class -> fp; fprintf(fp, ".source SYSTEM\n"); fprintf(fp, ".class public abstract %s\n", cname); fprintf(fp, ".super java/lang/Object\n\n"); fprintf(fp, ".method ()V\n"); fprintf(fp, " aload_0\n"); fprintf(fp, " invokespecial java/lang/Object/()V\n"); fprintf(fp, " return\n"); fprintf(fp, ".end method\n\n"); signature = jvm_get_procedure_signature(proc); fprintf(fp, ".method public abstract invoke%s\n", signature); fprintf(fp, ".end method\n\n"); jvm_destroy_class(class); } static void oberon_generate_procedure_pointer_class(const char * dir, oberon_object_t * proc) { FILE * fp; char * cname; char * abscname; char * absdesc; char * signature; struct gen_class * class; cname = jvm_get_field_full_name_safe(proc); class = jvm_create_class(dir, cname); abscname = jvm_get_class_full_name(proc -> type); absdesc = jvm_get_descriptor(proc -> type); fp = class -> fp; fprintf(fp, ".source %s\n", proc -> module -> name); fprintf(fp, ".class public %s\n", cname); fprintf(fp, ".super %s\n\n", abscname); fprintf(fp, ".field public static pointer %s\n\n", absdesc); fprintf(fp, ".method private ()V\n"); fprintf(fp, " aload_0\n"); fprintf(fp, " invokespecial %s/()V\n", abscname); fprintf(fp, " return\n"); fprintf(fp, ".end method\n\n"); fprintf(fp, ".method static ()V\n"); fprintf(fp, " .limit stack 2\n"); fprintf(fp, " new %s\n", cname); fprintf(fp, " dup\n"); fprintf(fp, " invokespecial %s/()V\n", cname); fprintf(fp, " putstatic %s/pointer %s\n", cname, absdesc); fprintf(fp, " return\n"); fprintf(fp, ".end method\n\n"); signature = jvm_get_procedure_signature(proc -> type); gen_proc_t * p = jvm_create_proc(class); jvm_generate_function_header(p, "public", "invoke", signature); jvm_alloc_register_untyped(p -> rf, false); int use_size = 0; int num = proc -> type -> num_decl; oberon_object_t * param = proc -> type -> decl; for(int i = 0; i < num; i++) { gen_type_t * t = param -> type -> gen_type; if(param -> class == OBERON_CLASS_VAR_PARAM) { int reg = jvm_alloc_register_untyped(p -> rf, true); jvm_generate(p, 0, 1, "aload %i", reg); jvm_generate(p, 0, 1, "iload %i", reg + 1); } else { int reg = jvm_alloc_register_untyped(p -> rf, t -> wide); jvm_generate(p, 0, t -> cell_size, "%cload %i", t -> prefix, reg); } use_size += t -> cell_size; param = param -> next; } char * full_name = jvm_get_field_full_name(proc); int cell_size = jvm_cell_size_for_type(proc -> type -> base); jvm_generate(p, use_size, cell_size, "invokestatic %s%s", full_name, signature); if(proc -> type -> base -> class == OBERON_TYPE_NOTYPE) { jvm_generate(p, 0, 0, "return"); } else { char prefix = jvm_get_prefix(proc -> type -> base); jvm_generate(p, cell_size, 0, "%creturn", prefix); } jvm_generate_function_end(p); jvm_destroy_class(class); } static void oberon_generate_record_class(const char * dir, gen_module_t * m, oberon_type_t * rec) { char * cname; struct gen_class * class; /* Устанавливаем новоый id */ rec -> gen_type -> rec_id = m -> rec_id; m -> rec_id += 1; cname = jvm_get_class_full_name(rec); class = jvm_create_class(dir, cname); fprintf(class -> fp, ".source %s\n", rec -> module -> name); fprintf(class -> fp, ".class public %s\n", cname); if(rec -> base == NULL) { fprintf(class -> fp, ".super java/lang/Object\n\n"); } else { class -> base = rec -> base -> gen_type -> class; fprintf(class -> fp, ".super %s\n\n", class -> base -> full_name); } rec -> gen_type -> class = class; } void oberon_generator_init_type(oberon_context_t * ctx, oberon_type_t * type) { gen_type_t * t = GC_MALLOC(sizeof *t); memset(t, 0, sizeof *t); type -> gen_type = t; gen_context_t * c; c = ctx -> gen_context; gen_module_t * m; switch(type -> class) { case OBERON_TYPE_NOTYPE: case OBERON_TYPE_INTEGER: case OBERON_TYPE_BOOLEAN: case OBERON_TYPE_ARRAY: case OBERON_TYPE_POINTER: case OBERON_TYPE_REAL: case OBERON_TYPE_CHAR: case OBERON_TYPE_STRING: case OBERON_TYPE_SET: case OBERON_TYPE_NIL: case OBERON_TYPE_SYSTEM_BYTE: case OBERON_TYPE_SYSTEM_PTR: break; case OBERON_TYPE_RECORD: m = type -> module -> gen_mod; t -> full_name = jvm_get_class_full_name(type); oberon_generate_record_class(c -> dir, m, type); break; case OBERON_TYPE_PROCEDURE: oberon_generate_procedure_class(c -> dir, type); break; default: gen_error("oberon_generator_init_type: unk calss %i", type -> class); break; } if(type -> class != OBERON_TYPE_NOTYPE) { t -> wide = jvm_is_wide_type(type); t -> prefix = jvm_get_prefix(type); t -> postfix = jvm_get_postfix(type); } if((type -> class == OBERON_TYPE_POINTER && type -> base -> class == OBERON_TYPE_RECORD) || type -> class == OBERON_TYPE_PROCEDURE || type -> class == OBERON_TYPE_RECORD || type -> class == OBERON_TYPE_SYSTEM_PTR) { t -> full_name = jvm_get_class_full_name(type); } t -> cell_size = jvm_cell_size_for_type(type); if(type -> class != OBERON_TYPE_NIL) { t -> desc = jvm_get_descriptor(type); } } void oberon_generator_init_record(oberon_context_t * ctx, oberon_type_t * rec) { struct gen_class * class; class = rec -> gen_type -> class; int num = rec -> num_decl; oberon_object_t * field = rec -> decl; for(int i = 0; i < num; i++) { jvm_generate_var(field -> gen_var); field = field -> next; } /* Стандартный конструктор класса */ /* Инициализирует внутренние статические записи и массивы */ 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"); if(class -> base) { jvm_generate(p, 1, 0, "invokespecial %s/()V", class -> base -> full_name); } else { jvm_generate(p, 1, 0, "invokespecial java/lang/Object/()V"); } num = rec -> num_decl; field = rec -> decl; for(int i = 0; i < num; i++) { jvm_generate(p, 0, 1, "aload_0"); jvm_generate_var_initialization(p, field -> gen_var); if(field -> type -> class == OBERON_TYPE_RECORD || field -> type -> class == OBERON_TYPE_ARRAY) { jvm_generate(p, 0, 1, "aload_0"); jvm_generate_ldst_prepare(p, field -> gen_var); jvm_generate_new(p, field -> type, 0); jvm_generate_store(p, field -> gen_var); } field = field -> next; } jvm_generate(p, 0, 0, "return"); jvm_generate_function_end(p); /* Метод для копирования полей класса */ /* reg0 == src -> reg1 == dst */ p = jvm_create_proc(class); char * signature = new_string("(%s%s)V", rec -> gen_type -> desc, rec -> gen_type -> desc); jvm_generate_function_header(p, "public static", "$COPY$", signature); gen_var_t * copy_dst = jvm_create_function_var(p, JVM_STORAGE_REGISTER, "dst", rec -> gen_type); gen_var_t * copy_src = jvm_create_function_var(p, JVM_STORAGE_REGISTER, "src", rec -> gen_type); jvm_generate_var(copy_dst); jvm_generate_var(copy_src); jvm_generate_var_initialization(p, copy_dst); jvm_generate_var_initialization(p, copy_src); if(rec -> base) { jvm_generate_load(p, copy_dst); jvm_generate_load(p, copy_src); jvm_generate_copy_record(p, rec -> base); } num = rec -> num_decl; field = rec -> decl; for(int i = 0; i < num; i++) { if(field -> type -> class == OBERON_TYPE_RECORD) { jvm_generate_load(p, copy_dst); jvm_generate_load(p, field -> gen_var); jvm_generate_load(p, copy_src); jvm_generate_load(p, field -> gen_var); jvm_generate_copy_record(p, field -> type); } else if(field -> type -> class == OBERON_TYPE_ARRAY) { jvm_generate_load(p, copy_dst); jvm_generate_load(p, field -> gen_var); jvm_generate_load(p, copy_src); jvm_generate_load(p, field -> gen_var); jvm_generate_copy_array(p, field -> type); } else { jvm_generate_load(p, copy_dst); jvm_generate_ldst_prepare(p, field -> gen_var); jvm_generate_load(p, copy_src); jvm_generate_load(p, field -> gen_var); jvm_generate_store(p, field -> gen_var); } field = field -> next; } jvm_generate(p, 0, 0, "return"); jvm_generate_function_end(p); jvm_destroy_class(class); } void oberon_generator_init_var(oberon_context_t * ctx, oberon_object_t * var) { gen_module_t * m; m = ctx -> mod -> gen_mod; struct gen_class * class; class = m -> class; gen_proc_t * p; struct gen_class * c; char * name = var -> name; gen_type_t * t = var -> type -> gen_type; assert(name); if(t == NULL) { gen_error("uninitialized type class %i", var -> type -> class); } switch(var -> class) { case OBERON_CLASS_VAR_PARAM: p = var -> parent -> gen_proc; var -> gen_var = jvm_create_function_var(p, JVM_STORAGE_FRAME_PARAM_VARPTR, name, t); break; case OBERON_CLASS_PARAM: p = var -> parent -> gen_proc; var -> gen_var = jvm_create_function_var(p, JVM_STORAGE_FRAME_PARAM_VAR, name, t); break; case OBERON_CLASS_FIELD: c = var -> parent_type -> gen_type -> class; var -> gen_var = jvm_create_class_var(c, JVM_STORAGE_FIELD_VAR, name, t); break; case OBERON_CLASS_VAR: if(var -> local) { p = var -> parent -> gen_proc; var -> gen_var = jvm_create_function_var(p, JVM_STORAGE_FRAME_VAR, name, t); } else { var -> gen_var = jvm_create_class_var(class, JVM_STORAGE_STATIC_VAR, name, t); jvm_generate_var(var -> gen_var); } break; default: gen_error("oberon_generator_init_var: unk var class %i", var -> class); break; } } static void oberon_generate_static_initialization(gen_proc_t * p, oberon_object_t * x) { if(x -> type -> class == OBERON_TYPE_ARRAY || x -> type -> class == OBERON_TYPE_RECORD) { jvm_generate_ldst_prepare(p, x -> gen_var); jvm_generate_new(p, x -> type, 0); jvm_generate_store(p, x -> gen_var); } } void oberon_generator_init_temp_var(oberon_context_t * ctx, oberon_object_t * var) { assert(var -> class == OBERON_CLASS_VAR); gen_module_t * m; m = ctx -> mod -> gen_mod; gen_proc_t * p; p = m -> class -> p; gen_type_t * t; t = var -> type -> gen_type; var -> gen_var = jvm_create_function_temp_var(p, t); jvm_generate_var(var -> gen_var); jvm_generate_var_initialization(p, var -> gen_var); oberon_generate_static_initialization(p, var); } void oberon_generator_init_proc(oberon_context_t * ctx, oberon_object_t * proc) { struct gen_class * class = proc -> module -> gen_mod -> class; proc -> gen_proc = jvm_create_proc(class); proc -> gen_proc -> full_name = jvm_get_field_full_name_safe(proc); jvm_create_static_links(proc); } void oberon_generator_init_module(oberon_context_t * ctx, oberon_module_t * mod) { gen_module_t * m = GC_MALLOC(sizeof *m); memset(m, 0, sizeof *m); mod -> gen_mod = m; gen_context_t * c; c = ctx -> gen_context; struct gen_class * class; class = jvm_create_class(c -> dir, mod -> name); fprintf(class -> fp, ".source %s\n", mod -> name); fprintf(class -> fp, ".class %s\n", mod -> name); fprintf(class -> fp, ".super java/lang/Object\n\n"); fprintf(class -> fp, ".field private static $INITIALIZED$ Z\n\n"); m -> class = class; c -> current_m = m; } void oberon_generator_fini_module(oberon_module_t * mod) { jvm_destroy_class(mod -> gen_mod -> class); } static void push_expr(gen_proc_t * p, oberon_expr_t * expr); void oberon_generate_begin_module(oberon_context_t * ctx) { gen_proc_t * p; int label_cont; struct gen_class * class; class = ctx -> mod -> gen_mod -> class; p = jvm_create_proc(class); jvm_generate_function_header(p, "public static", "BEGIN", "()V"); label_cont = jvm_new_label_id(p); jvm_generate(p, 0, 1, "getstatic %s/$INITIALIZED$ Z", class -> full_name); jvm_generate(p, 1, 0, "ifeq L%i", label_cont); jvm_generate(p, 0, 0, "return"); jvm_generate_label(p, label_cont); jvm_generate(p, 0, 1, "iconst_1"); jvm_generate(p, 1, 0, "putstatic %s/$INITIALIZED$ Z", class -> full_name); /* Инициализация переменных объявленных в модуле */ oberon_object_t * x = ctx -> mod -> decl -> list -> next; while(x != NULL) { if(x -> class == OBERON_CLASS_MODULE) { if(!x -> module -> intrinsic) { jvm_generate(p, 0, 0, "invokestatic %s/BEGIN()V", x -> module -> gen_mod -> class -> full_name); } } else if(x -> class == OBERON_CLASS_VAR) { jvm_generate_var_initialization(p, x -> gen_var); oberon_generate_static_initialization(p, x); } x = x -> next; } } void oberon_generate_end_module(oberon_context_t * ctx) { struct gen_class * class = ctx -> mod -> gen_mod -> class; gen_proc_t * p = class -> p; jvm_generate(p, 0, 0, "return"); jvm_generate_function_end(class -> p); p = jvm_create_proc(class); jvm_generate_function_header(p, "private", "", "()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"); jvm_generate(p, 0, 0, "return"); jvm_generate_function_end(class -> p); } /* * Генерирует код для получения размера измерения массива * Аналог Обероновского LEN(v, n); где n = 0 - первое измерение. * ( aref -- int ) */ static void jvm_generate_array_len(gen_proc_t * p, int dim) { while(dim > 0) { jvm_generate(p, 0, 1, "iconst_0"); jvm_generate(p, 2, 1, "aaload"); dim -= 1; } jvm_generate(p, 1, 1, "arraylength"); } static void jvm_generate_array_duplicate_and_replace(gen_proc_t * p, gen_var_t * v, oberon_type_t * arr) { jvm_generate_ldst_prepare(p, v); int dim = 0; oberon_type_t * base = arr; while(base -> class == OBERON_TYPE_ARRAY) { if(base -> size == 0) { jvm_generate_load(p, v); jvm_generate_array_len(p, dim); dim += 1; } base = base -> base; } jvm_generate_new(p, arr, dim); jvm_generate(p, 1, 2, "dup"); jvm_generate_load(p, v); jvm_generate_copy_array(p, arr); jvm_generate_store(p, v); } static void jvm_generate_record_duplicate_and_replace(gen_proc_t * p, gen_var_t * v, oberon_type_t * rec) { jvm_generate_ldst_prepare(p, v); jvm_generate_new(p, rec, 0); jvm_generate(p, 1, 2, "dup"); jvm_generate_load(p, v); jvm_generate_copy_record(p, rec); jvm_generate_store(p, v); } static void jvm_generate_local_object(gen_proc_t * p, oberon_object_t * x) { gen_var_t * v; struct gen_class * class; v = x -> gen_var; class = p -> class; // Убеждаемся что сейчас находимся в функции assert(class -> p); assert(x -> local); switch(x -> class) { case OBERON_CLASS_VAR_PARAM: case OBERON_CLASS_PARAM: case OBERON_CLASS_VAR: jvm_generate_var(v); break; case OBERON_CLASS_CONST: case OBERON_CLASS_TYPE: case OBERON_CLASS_PROC: break; default: gen_error("jvm_generate_local_initialization: wat class %i", x -> class); break; } } static void jvm_generate_local_initialization(gen_proc_t * p, oberon_object_t * x) { gen_var_t * v; struct gen_class * class; v = x -> gen_var; class = p -> class; // Убеждаемся что сейчас находимся в функции assert(class -> p); assert(x -> local); switch(x -> class) { case OBERON_CLASS_VAR_PARAM: jvm_generate_var_initialization(p, v); break; case OBERON_CLASS_PARAM: jvm_generate_var_initialization(p, v); if(x -> type -> class == OBERON_TYPE_ARRAY) { jvm_generate_array_duplicate_and_replace(p, v, x -> type); } else if(x -> type -> class == OBERON_TYPE_RECORD) { jvm_generate_record_duplicate_and_replace(p, v, x -> type); } break; case OBERON_CLASS_VAR: jvm_generate_var_initialization(p, v); oberon_generate_static_initialization(p, x); break; case OBERON_CLASS_CONST: case OBERON_CLASS_TYPE: case OBERON_CLASS_PROC: break; default: gen_error("jvm_generate_local_initialization: wat class %i", x -> class); break; } } void oberon_generate_begin_proc(oberon_context_t * ctx, oberon_object_t * proc) { gen_proc_t * p; char * name; char * signature; oberon_object_t * var; p = proc -> gen_proc; if(proc -> local) { signature = jvm_get_local_procedure_signature(proc); } else { oberon_generate_procedure_pointer_class(p -> class -> dir, proc); signature = jvm_get_procedure_signature(proc -> type); } name = jvm_get_name(proc); p -> ret_prefix = jvm_get_prefix(proc -> type -> base); jvm_generate_function_header(p, "public static", name, signature); if(proc -> local) { jvm_generate_staticlinks(proc); } jvm_generate_procedure_frame(proc); /* Создание параметров и переменных */ var = proc -> scope -> list -> next; while(var) { jvm_generate_local_object(p, var); var = var -> next; } jvm_generate_frame_initialization(p); /* Инициализация парамеров и переменных */ var = proc -> scope -> list -> next; while(var) { jvm_generate_local_initialization(p, var); var = var -> next; } } void oberon_generate_end_proc(oberon_context_t * ctx) { gen_module_t * m; gen_proc_t * p; m = ctx -> mod -> gen_mod; p = m -> class -> p; oberon_generate_trap(ctx, -4); if(p -> ret_prefix == ' ') { jvm_generate(p, 0, 0, "return"); } else { int sz = jvm_cell_size_for_postfix(p -> ret_prefix); switch(p -> ret_prefix) { case 'a': jvm_generate(p, 0, 1, "aconst_null"); break; case 'l': jvm_generate_push_int_size(p, 0, 8); break; case 'f': jvm_generate_push_float(p, 0, 4); break; case 'd': jvm_generate_push_float(p, 0, 8); break; default: jvm_generate_push_int(p, 0); break; } jvm_generate(p, sz, 0, "%creturn", p -> ret_prefix); } jvm_generate_function_end(p); } gen_label_t * oberon_generator_reserve_label(oberon_context_t * ctx) { gen_module_t * m; gen_proc_t * p; gen_label_t * l; m = ctx -> mod -> gen_mod; p = m -> class -> p; l = GC_MALLOC(sizeof *l); memset(l, 0, sizeof *l); l -> id = jvm_new_label_id(p); return l; } void oberon_generate_label(oberon_context_t * ctx, gen_label_t * l) { gen_module_t * m; gen_proc_t * p; m = ctx -> mod -> gen_mod; p = m -> class -> p; jvm_generate_label(p, l -> id); } void oberon_generate_goto(oberon_context_t * ctx, gen_label_t * l) { gen_module_t * m; gen_proc_t * p; m = ctx -> mod -> gen_mod; p = m -> class -> p; jvm_generate(p, 0, 0, "goto L%i", l -> id); } void oberon_generate_branch(oberon_context_t * ctx, oberon_expr_t * cond, bool gotoif, gen_label_t * l) { gen_module_t * m; gen_proc_t * p; m = ctx -> mod -> gen_mod; p = m -> class -> p; push_expr(p, cond); if(gotoif == false) { /* переход если false */ jvm_generate(p, 1, 0, "ifeq L%i", l -> id); } else { /* переход если true */ jvm_generate(p, 1, 0, "ifne L%i", l -> id); } } static void push_varptr(gen_proc_t * p, oberon_expr_t * expr) { assert(expr -> is_item); switch(expr -> item.mode) { case MODE_VAR: jvm_generate_ldst_prepare(p, expr -> item.var -> gen_var); break; case MODE_INDEX: push_item(p, expr -> item.parent); push_expr(p, expr -> item.args); check_index(p, expr -> item.args -> result); break; case MODE_FIELD: push_item(p, expr -> item.parent); jvm_generate_ldst_prepare(p, expr -> item.var -> gen_var); break; case MODE_DEREF: push_varptr(p, (oberon_expr_t *) expr -> item.parent); break; default: gen_error("push_varptr: wat %i", expr -> item.mode); break; } } static void jvm_generate_call_proc(gen_proc_t * p, oberon_item_t * desig) { assert(desig -> var == NULL); assert(desig -> mode == MODE_CALL); bool direct_call = false; if(desig -> parent -> mode == MODE_VAR) { if(desig -> parent -> var -> class == OBERON_CLASS_PROC) { direct_call = true; } } oberon_type_t * procsig; procsig = desig -> parent -> result; if(direct_call == false) { /* Загружаем указатель на процедуру */ push_item(p, desig -> parent); } if(direct_call) { jvm_generate_push_static_links(p, desig -> parent -> var); } int args_cells = 0; int result_cells = jvm_cell_size_for_type(procsig -> base); int num = desig -> num_args; oberon_expr_t * arg = desig -> args; oberon_object_t * param = procsig -> decl; for(int i = 0; i < num; i++) { if(param -> class == OBERON_CLASS_VAR_PARAM) { args_cells += 2; push_varptr(p, arg); } else { args_cells += jvm_cell_size_for_type(arg -> result); push_expr(p, arg); } arg = arg -> next; param = param -> next; } if(direct_call) { char * full_name = jvm_get_field_full_name(desig -> parent -> var); char * signature = jvm_get_local_procedure_signature(desig -> parent -> var); jvm_generate(p, args_cells, result_cells, "invokestatic %s%s", full_name, signature); } else { char * cname = jvm_get_class_full_name(procsig); char * signature = jvm_get_procedure_signature(procsig); jvm_generate(p, 1 + args_cells, result_cells, "invokevirtual %s/invoke%s", cname, signature); } } void oberon_generate_call_proc(oberon_context_t * ctx, oberon_expr_t * desig) { assert(desig -> is_item); jvm_generate_call_proc(ctx -> mod -> gen_mod -> class -> p, (oberon_item_t *) desig); } void oberon_generate_return(oberon_context_t * ctx, oberon_expr_t * expr) { gen_module_t * m; gen_proc_t * p; char prefix; int cell_size; m = ctx -> mod -> gen_mod; p = m -> class -> p; if(expr) { push_expr(p, expr); prefix = jvm_get_prefix(expr -> result); cell_size = jvm_cell_size_for_type(expr -> result); jvm_generate(p, cell_size, 0, "%creturn", prefix); } else { jvm_generate(p, 0, 0, "return"); } } static void 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); for(int i = 0; i < num; i++) { push_expr(p, arg); check_index(p, arg -> result); arg = arg -> next; } jvm_generate_new(p, type -> base, num); } static void push_item(gen_proc_t * p, oberon_item_t * item) { switch(item -> mode) { case MODE_VAR: if(item -> var -> class == OBERON_CLASS_PROC) { jvm_generate_push_procedure_pointer(p, item -> var); } else { jvm_generate_load(p, item -> var -> gen_var); } break; case MODE_INTEGER: case MODE_BOOLEAN: case MODE_CHAR: case MODE_SET: jvm_generate_push_int_size(p, item -> integer, item -> result -> size); break; case MODE_CALL: jvm_generate_call_proc(p, item); break; case MODE_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); check_index(p, item -> args -> result); jvm_generate(p, 1 + 1, cell_size, "%caload", postfix); break; case MODE_FIELD: push_item(p, item -> parent); jvm_generate_load(p, item -> var -> gen_var); break; case MODE_DEREF: /* Все объекты в jvm представляются как указатели */ push_item(p, item -> parent); break; case MODE_NIL: jvm_generate(p, 0, 1, "aconst_null"); break; case MODE_NEW: 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); break; case MODE_STRING: jvm_generate_push_string(p, item -> string, item -> result -> size); break; case MODE_LEN: push_item(p, item -> parent); jvm_generate_array_len(p, item -> integer); jvm_generate_cast_prefix(p, 'i', jvm_get_postfix(item -> result)); break; case MODE_AS: push_item(p, item -> parent); jvm_generate_cast_type(p, item -> parent -> result, item -> result); break; default: gen_error("push_item: unk mode %i", item -> mode); break; } } static void jvm_generate_logical_not(gen_proc_t * p) { int label_done = jvm_new_label_id(p); int label_false = jvm_new_label_id(p); jvm_generate(p, 1, 0, "ifne L%i", label_false); jvm_generate(p, 0, 1, "iconst_1"); jvm_generate(p, 0, 0, "goto L%i", label_done); jvm_generate_label(p, label_false); jvm_generate(p, 0, 1, "iconst_0"); jvm_generate_label(p, label_done); } 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_postfix(prefix); jvm_generate(p, cell_size, cell_size, "invokestatic java/lang/Math/abs(%c)%c", t, t); } static char * jvm_get_compare_postfix(int op) { char * cmpop = ""; switch(op) { case OP_EQ: cmpop = "eq"; break; case OP_NEQ: cmpop = "ne"; break; case OP_LSS: cmpop = "lt"; break; case OP_LEQ: cmpop = "le"; break; case OP_GRT: cmpop = "gt"; break; case OP_GEQ: cmpop = "ge"; break; default: gen_error("jvm_generate_compare_op: wat"); break; } return cmpop; } static void jvm_generate_compare_op(gen_proc_t * p, oberon_type_t * t, int op) { char prefix = jvm_get_prefix(t); int label_true = jvm_new_label_id(p); int label_done = jvm_new_label_id(p); int cell_size = jvm_cell_size_for_type(t); char * cmpop = jvm_get_compare_postfix(op); if(prefix == 'l') { jvm_generate(p, 2 * cell_size, 1, "lcmp"); jvm_generate(p, 1, 1, "if%s L%i", cmpop, label_true); } else if(prefix == 'f' || prefix == 'd') { char fop; if(op == OP_EQ || op == OP_NEQ || op == OP_GRT || op == OP_GEQ) { fop = 'l'; } else { fop = 'g'; } jvm_generate(p, 2 * cell_size, 1, "%ccmp%c", prefix, fop); jvm_generate(p, 1, 1, "if%s L%i", cmpop, label_true); } else if(prefix == 'a') { if(oberon_is_array_of_char_type(t) || oberon_is_string_type(t)) { jvm_generate(p, 2, 1, "invokestatic SYSTEM/STRCMP([B[B)I"); jvm_generate(p, 1, 0, "if%s L%i", cmpop, label_true); } else { jvm_generate(p, 1, 0, "if_acmp%s L%i", cmpop, label_true); } } else { jvm_generate(p, 2 * cell_size, 0, "if_%ccmp%s L%i", prefix, cmpop, label_true); } jvm_generate(p, 0, 1, "iconst_0"); jvm_generate(p, 0, 0, "goto L%i", label_done); jvm_generate_label(p, label_true); jvm_generate(p, 0, 1, "iconst_1"); jvm_generate_label(p, label_done); } static void jvm_generate_operator(gen_proc_t * p, oberon_type_t * t, int op) { char prefix = jvm_get_prefix(t); int cell_size = jvm_cell_size_for_type(t); switch(op) { case OP_UNARY_MINUS: jvm_generate(p, cell_size, cell_size, "%cneg", prefix); break; case OP_COMPLEMENTATION: jvm_generate_push_int_size(p, -1, t -> size); jvm_generate(p, 2 * cell_size, cell_size, "%cxor", prefix); break; case OP_LOGIC_NOT: jvm_generate_logical_not(p); break; case OP_ABS: jvm_generate_abs(p, prefix); break; case OP_CAP: jvm_generate(p, cell_size, cell_size, "invokestatic java/lang/Character/toUpperCase(I)I"); break; case OP_ADD: jvm_generate(p, 2 * cell_size, cell_size, "%cadd", prefix); break; case OP_SUB: jvm_generate(p, 2 * cell_size, cell_size, "%csub", prefix); break; case OP_MUL: jvm_generate(p, 2 * cell_size, cell_size, "%cmul", prefix); break; case OP_DIV: jvm_generate(p, 2 * cell_size, cell_size, "%cdiv", prefix); break; case OP_MOD: jvm_generate(p, 2 * cell_size, cell_size, "%crem", prefix); break; case OP_UNION: jvm_generate(p, 2 * cell_size, cell_size, "%cor", prefix); break; case OP_INTERSECTION: jvm_generate(p, 2 * cell_size, cell_size, "%cand", prefix); break; case OP_DIFFERENCE: /* (a - b) == a & ~b */ jvm_generate_push_int_size(p, -1, t -> size); jvm_generate(p, 2 * cell_size, cell_size, "%cxor", prefix); jvm_generate(p, 2 * cell_size, cell_size, "%cand", prefix); break; case OP_SYM_DIFFERENCE: jvm_generate(p, 2 * cell_size, cell_size, "%cxor", prefix); break; case OP_EQ: case OP_NEQ: case OP_LSS: case OP_LEQ: case OP_GRT: case OP_GEQ: jvm_generate_compare_op(p, t, op); break; default: gen_error("jvm_generate_operator: unk op %i", op); break; } } static void jvm_generate_logical_or(gen_proc_t * p, oberon_expr_t * a, oberon_expr_t * b) { int label_calc_b = jvm_new_label_id(p); int label_done = jvm_new_label_id(p); /* a OR b -- если a, то TRUE, иначе b */ push_expr(p, a); jvm_generate(p, 1, 0, "ifeq L%i", label_calc_b); jvm_generate(p, 0, 1, "iconst_1"); jvm_generate(p, 0, 0, "goto L%i", label_done); jvm_generate_label(p, label_calc_b); push_expr(p, b); jvm_generate_label(p, label_done); } static void jvm_generate_logical_and(gen_proc_t * p, oberon_expr_t * a, oberon_expr_t * b) { int label_false = jvm_new_label_id(p); int label_done = jvm_new_label_id(p); /* a AND b -- если a, то b, иначе FALSE */ push_expr(p, a); jvm_generate(p, 1, 0, "ifeq L%i", label_false); push_expr(p, b); jvm_generate(p, 0, 0, "goto L%i", label_done); jvm_generate_label(p, label_false); jvm_generate(p, 0, 1, "iconst_0"); jvm_generate_label(p, label_done); } static void jvm_generate_range(gen_proc_t * p, oberon_expr_t * a, oberon_expr_t * b) { /* { a } == 1 << a */ /* { a..b } == (a <= b) ? ((2 << b) - (1 << a)) : (0); */ char prefix; int cell_size; oberon_type_t * type; gen_var_t * ra; gen_var_t * rb; int label_else; int label_end; type = a -> result; cell_size = jvm_cell_size_for_type(type); prefix = jvm_get_prefix(type); if(b == NULL) { jvm_generate_push_int_size(p, 1, type -> size); push_expr(p, a); jvm_generate(p, 2 * cell_size, cell_size, "%cshl", prefix); } else { ra = jvm_create_function_temp_var(p, type -> gen_type); rb = jvm_create_function_temp_var(p, type -> gen_type); jvm_generate_var(ra); jvm_generate_var(rb); jvm_generate_var_initialization(p, ra); jvm_generate_var_initialization(p, rb); label_else = jvm_new_label_id(p); label_end = jvm_new_label_id(p); push_expr(p, a); jvm_generate_store(p, ra); push_expr(p, b); jvm_generate_store(p, rb); jvm_generate_load(p, ra); jvm_generate_load(p, rb); jvm_generate(p, 2 * cell_size, 0, "if_%ccmpgt L%i", prefix, label_else); jvm_generate_push_int_size(p, 2, type -> size); jvm_generate_load(p, rb); jvm_generate(p, 2 * cell_size, cell_size, "%cshl", prefix); jvm_generate_push_int_size(p, 2, type -> size); jvm_generate_load(p, ra); jvm_generate(p, 2 * cell_size, cell_size, "%cshl", prefix); jvm_generate(p, 2 * cell_size, cell_size, "%csub", prefix); jvm_generate(p, 0, 0, "goto L%i", label_end); jvm_generate_label(p, label_else); jvm_generate_push_int_size(p, 0, type -> size); jvm_generate_label(p, label_end); } /* TODO free registers */ } static void jvm_generate_in(gen_proc_t * p, oberon_expr_t * a, oberon_expr_t * b) { oberon_type_t * t = a -> result; int cell_size = jvm_cell_size_for_type(t); char prefix = jvm_get_prefix(t); int label_else = jvm_new_label_id(p); int label_end = jvm_new_label_id(p); /* (a IN b) == (1 << a) & b */ jvm_generate_push_int_size(p, 1, t -> size); push_expr(p, a); jvm_generate(p, 2 * cell_size, cell_size, "%cshl", prefix); push_expr(p, b); jvm_generate(p, 2 * cell_size, cell_size, "%cand", prefix); if(cell_size > 1) { jvm_generate(p, cell_size, 0, "lcmp"); } jvm_generate(p, 1, 0, "ifeq L%i", label_else); jvm_generate(p, 0, 1, "iconst_1"); jvm_generate(p, 0, 0, "goto L%i", label_end); jvm_generate_label(p, label_else); jvm_generate(p, 0, 1, "iconst_0"); jvm_generate_label(p, label_end); } static void jvm_generate_shift(gen_proc_t * p, int op, oberon_expr_t * a, oberon_expr_t * b) { oberon_type_t * t = a -> result; int cell_size = jvm_cell_size_for_type(t); char prefix = jvm_get_prefix(t); char dt = jvm_get_type_of_prefix(prefix); push_expr(p, a); jvm_generate_cast_type(p, a -> result, t); push_expr(p, b); jvm_generate_cast_type(p, b -> result, t); char * opname; switch(op) { case OP_ASH: opname = "ASH"; break; case OP_LSH: opname = "LSH"; break; case OP_ROT: opname = "ROT"; break; default: gen_error("jvm_generate_shift: invalid op %i", op); } jvm_generate(p, 2 * cell_size, cell_size, "invokestatic SYSTEM/%s(%c%c)%c", opname, dt, dt, dt); } static void jvm_generate_entier(gen_proc_t * p, oberon_expr_t * x, oberon_type_t * res) { char prefix = jvm_get_prefix(x -> result); char postfix = jvm_get_postfix(res); push_expr(p, x); jvm_generate_cast_prefix(p, prefix, 'd'); jvm_generate(p, 2, 2, "invokestatic java/lang/Math/floor(D)D"); jvm_generate_cast_prefix(p, 'd', postfix); } static void push_operator(gen_proc_t * p, oberon_oper_t * oper) { oberon_type_t * preq = oper -> left -> result; int op = oper -> op; switch(op) { case OP_CAST: push_expr(p, oper -> left); jvm_generate_cast_type(p, oper -> left -> result, oper -> result); break; case OP_HARDCAST: push_expr(p, oper -> left); jvm_generate_hard_cast_type(p, oper -> left -> result, oper -> result); break; case OP_COMPLEMENTATION: case OP_UNARY_MINUS: case OP_LOGIC_NOT: case OP_ABS: case OP_CAP: push_expr(p, oper -> left); jvm_generate_operator(p, preq, op); break; case OP_ENTIER: jvm_generate_entier(p, oper -> left, oper -> result); break; case OP_ADD: case OP_SUB: case OP_MUL: case OP_DIV: case OP_MOD: case OP_UNION: case OP_INTERSECTION: case OP_DIFFERENCE: case OP_SYM_DIFFERENCE: case OP_EQ: case OP_NEQ: case OP_LSS: case OP_LEQ: case OP_GRT: case OP_GEQ: push_expr(p, oper -> left); push_expr(p, oper -> right); jvm_generate_operator(p, preq, op); break; case OP_LOGIC_OR: jvm_generate_logical_or(p, oper -> left, oper -> right); break; case OP_LOGIC_AND: jvm_generate_logical_and(p, oper -> left, oper -> right); break; case OP_IS: preq = oper -> right -> result; char * cname = jvm_get_class_full_name(preq); push_expr(p, oper -> left); jvm_generate(p, 1, 1, "instanceof %s", cname); break; case OP_RANGE: jvm_generate_range(p, oper -> left, oper -> right); break; case OP_IN: jvm_generate_in(p, oper -> left, oper -> right); break; case OP_ASH: case OP_LSH: case OP_ROT: jvm_generate_shift(p, op, oper -> left, oper -> right); break; default: gen_error("push_oper: unk op %i", op); break; } } static void push_expr(gen_proc_t * p, oberon_expr_t * expr) { if(expr -> is_item) { push_item(p, (oberon_item_t *) expr); } else { push_operator(p, (oberon_oper_t *) expr); } } static void 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; if(dst -> result -> class == OBERON_TYPE_ARRAY || src -> result -> class == OBERON_TYPE_ARRAY) { push_expr(p, dst); push_expr(p, src); jvm_generate_copy_array(p, dst -> result); } else if(dst -> result -> class == OBERON_TYPE_RECORD || src -> result -> class == OBERON_TYPE_RECORD) { push_expr(p, dst); push_expr(p, src); jvm_generate_copy_record(p, dst -> result); } else switch(item -> mode) { case MODE_VAR: jvm_generate_ldst_prepare(p, item -> var -> gen_var); push_expr(p, src); jvm_generate_store(p, item -> var -> gen_var); break; case MODE_INDEX: ; char postfix = jvm_get_postfix(src -> result); int cell_size = jvm_cell_size_for_postfix(postfix); assert(item -> parent -> is_item); push_item(p, (oberon_item_t *) item -> parent); push_expr(p, item -> args); check_index(p, item -> args -> result); push_expr(p, src); jvm_generate(p, 1 + 1 + cell_size, 0, "%castore", postfix); break; case MODE_FIELD: assert(item -> parent -> is_item); push_item(p, (oberon_item_t *) item -> parent); jvm_generate_ldst_prepare(p, item -> var -> gen_var); push_expr(p, src); jvm_generate_store(p, item -> var -> gen_var); break; default: gen_error("store_expr: unk mode %i", item -> mode); break; } } void oberon_generate_assign(oberon_context_t * ctx, oberon_expr_t * src, oberon_expr_t * dst) { gen_module_t * m; gen_proc_t * p; m = ctx -> mod -> gen_mod; p = m -> class -> p; store_expr(p, dst, src); } void oberon_generate_copy(oberon_context_t * ctx, oberon_expr_t * src, oberon_expr_t * dst) { gen_module_t * m; gen_proc_t * p; char * desc; m = ctx -> mod -> gen_mod; p = m -> class -> p; push_expr(p, src); push_expr(p, dst); desc = jvm_get_descriptor(dst -> result); jvm_generate(p, 2, 0, "invokestatic SYSTEM/COPY(%s%s)V", desc, desc); } void oberon_generate_assert(oberon_context_t * ctx, oberon_expr_t * cond) { gen_module_t * m; gen_proc_t * p; m = ctx -> mod -> gen_mod; p = m -> class -> p; push_expr(p, cond); jvm_generate(p, 1, 0, "invokestatic SYSTEM/ASSERT(Z)V"); } void oberon_generate_assert_n(oberon_context_t * ctx, oberon_expr_t * cond, int64_t n) { gen_module_t * m; gen_proc_t * p; m = ctx -> mod -> gen_mod; p = m -> class -> p; push_expr(p, cond); jvm_generate_push_int_size(p, n, 8); jvm_generate(p, 1 + 2, 0, "invokestatic SYSTEM/ASSERT(ZJ)V"); } void oberon_generate_trap(oberon_context_t * ctx, int64_t n) { gen_module_t * m; gen_proc_t * p; m = ctx -> mod -> gen_mod; p = m -> class -> p; jvm_generate_push_int_size(p, n, 8); jvm_generate(p, 2, 0, "invokestatic SYSTEM/TRAP(J)V"); } void oberon_generate_halt(oberon_context_t * ctx, int64_t n) { gen_module_t * m; gen_proc_t * p; m = ctx -> mod -> gen_mod; p = m -> class -> p; jvm_generate_push_int_size(p, n, 8); jvm_generate(p, 2, 0, "invokestatic SYSTEM/HALT(J)V"); } void oberon_set_out_directory(oberon_context_t * ctx, const char * path) { gen_context_t * c; c = ctx -> gen_context; c -> dir = new_string(path); } void oberon_set_typecheck(oberon_object_t * var, bool enable) { var -> gen_var -> typecheck = enable; var -> gen_var -> forcetype = (enable) ? (var -> type -> gen_type) : (NULL); } void oberon_set_line(oberon_context_t * ctx, int line) { gen_module_t * m; gen_proc_t * p; m = ctx -> mod -> gen_mod; if(m != NULL) { p = m -> class -> p; if(p != NULL) { jvm_generate(p, 0, 0, ".line %i", line); } m -> line = line; } }