From 55d9ee92b95dd306ac80fb643ed21d3b733395d7 Mon Sep 17 00:00:00 2001 From: DeaDDooMER Date: Sun, 6 Aug 2017 19:23:41 +0300 Subject: [PATCH] =?utf8?q?JVM:=20=D0=A0=D0=B5=D0=B0=D0=BB=D0=B8=D0=B7?= =?utf8?q?=D0=BE=D0=B2=D0=B0=D0=BD=D1=8B=20VAR-=D0=BF=D0=B0=D1=80=D0=B0?= =?utf8?q?=D0=BC=D0=B5=D1=82=D1=80=D1=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit --- src/backends/jvm/generator-jvm-abi.c | 196 ++++++ src/backends/jvm/generator-jvm-abi.h | 29 + src/backends/jvm/generator-jvm-asm.c | 302 +++++++++ src/backends/jvm/generator-jvm-asm.h | 53 ++ src/backends/jvm/generator-jvm-basic.c | 33 +- src/backends/jvm/generator-jvm.c | 810 ++++++++----------------- src/backends/jvm/generator-jvm.h | 12 +- src/oberon.c | 10 +- src/test.c | 36 +- 9 files changed, 886 insertions(+), 595 deletions(-) create mode 100644 src/backends/jvm/generator-jvm-abi.c create mode 100644 src/backends/jvm/generator-jvm-abi.h create mode 100644 src/backends/jvm/generator-jvm-asm.c create mode 100644 src/backends/jvm/generator-jvm-asm.h diff --git a/src/backends/jvm/generator-jvm-abi.c b/src/backends/jvm/generator-jvm-abi.c new file mode 100644 index 0000000..ed4a19a --- /dev/null +++ b/src/backends/jvm/generator-jvm-abi.c @@ -0,0 +1,196 @@ +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "../../../include/oberon.h" +#include "../../oberon-internals.h" +#include "generator-jvm.h" +#include "generator-jvm-abi.h" +#include "generator-jvm-asm.h" +#include "generator-jvm-basic.h" + +/* + * --- Каждый модуль является объектом. + * Импортируемые модули представляются полями. + * Каждая глобальная переменная представляется не статическим полем. + * Каждая процедура представляется не статическим метеодом. + * Процедура инициализации модуля имеет название BEGIN. + * Процедура финализации модуля имеет название END. + * Это позволит сделать динамическую загрузку и выгрузку. + * +++ всем переменным и полям в дескриптор добавляется "[" + * Это позволит делать ссылки на переменные в VAR-параметрах. + * --- Каждая процедура снабжается параметром-фреймом. + * Это позволит реализовать локальные процедуры и средства рефлекции над стеком. + */ + +void +jvm_generate_ldst_prepare(gen_proc_t * p, gen_var_t * v) +{ + char * full_name = v -> full_name; + char * desc = v -> type -> desc; + + switch(v -> storage) + { + case JVM_STORAGE_REGISTER: + break; + case JVM_STORAGE_STATIC: + jvm_generate(p, 0, 1, "getstatic %s [%s", full_name, desc); + jvm_generate(p, 0, 1, "iconst_0"); + break; + case JVM_STORAGE_FIELD: + jvm_generate(p, 1, 1, "getfield %s [%s", full_name, desc); + jvm_generate(p, 0, 1, "iconst_0"); + break; + case JVM_STORAGE_LOCAL: + jvm_generate(p, 0, 1, "aload %i", v -> reg); + jvm_generate(p, 0, 1, "iconst_0"); + break; + case JVM_STORAGE_VARPTR: + jvm_generate(p, 0, 1, "aload %i", v -> reg); + jvm_generate(p, 0, 1, "iload %i", v -> reg + 1); + break; + default: + gen_error("jvm_abi_obn_generate_ldst_prepare: wat %i", v -> storage); + } +} + +void +jvm_generate_load(gen_proc_t * p, gen_var_t * src) +{ + char prefix = src -> type -> prefix; + int cell_size = src -> type -> cell_size; + + switch(src -> storage) + { + case JVM_STORAGE_REGISTER: + jvm_generate(p, 0, cell_size, "%cload %i", prefix, src -> reg); + break; + case JVM_STORAGE_STATIC: + case JVM_STORAGE_FIELD: + case JVM_STORAGE_LOCAL: + case JVM_STORAGE_VARPTR: + jvm_generate_ldst_prepare(p, src); + jvm_generate(p, 1 + 1, cell_size, "%caload", prefix); + break; + default: + gen_error("jvm_generate_load: unknow storage type %i", src -> storage); + break; + } +} + +void +jvm_generate_store(gen_proc_t * p, gen_var_t * dst) +{ + char prefix = dst -> type -> prefix; + int cell_size = dst -> type -> cell_size; + + switch(dst -> storage) + { + case JVM_STORAGE_REGISTER: + jvm_generate(p, cell_size, 0, "%cstore %i", prefix, dst -> reg); + break; + case JVM_STORAGE_STATIC: + case JVM_STORAGE_FIELD: + case JVM_STORAGE_LOCAL: + case JVM_STORAGE_VARPTR: + jvm_generate(p, 1 + 1 + cell_size, 0, "%castore", prefix); + break; + default: + gen_error("jvm_generate_store: unknow storage type %i", dst -> storage); + break; + } +} + +void +jvm_generate_and_init_global_var(struct gen_class * class, gen_var_t * v, char * name, gen_type_t * t) +{ + assert(class -> p == NULL); + fprintf(class -> fp, ".field public static %s [%s\n\n", name, t -> desc); + + v -> storage = JVM_STORAGE_STATIC; + v -> full_name = new_string("%s/%s", class -> full_name, name); + v -> type = t; +} + +void +jvm_generate_and_init_field(struct gen_class * class, gen_var_t * v, char * name, gen_type_t * t) +{ + assert(class -> p == NULL); + fprintf(class -> fp, ".field public %s [%s\n\n", name, t -> desc); + + v -> storage = JVM_STORAGE_FIELD; + v -> full_name = new_string("%s/%s", class -> full_name, name); + v -> type = t; +} + +void +jvm_generate_and_init_local_var(gen_proc_t * p, gen_var_t * v, gen_type_t * t) +{ + v -> storage = JVM_STORAGE_REGISTER; + v -> reg = jvm_alloc_register_untyped(p -> rf, t -> wide); + v -> type = t; +} + +void +jvm_generate_and_init_named_local_var(gen_proc_t * p, gen_var_t * v, char * name, gen_type_t * t) +{ + jvm_generate_and_init_local_var(p, v, t); + jvm_generate(p, 0, 0, ".var %i is %s %s from start to end", v -> reg, name, t -> desc); +} + +void +jvm_generate_and_init_var_param(gen_proc_t * p, gen_var_t * v, char * name, gen_type_t * t) +{ + v -> storage = JVM_STORAGE_VARPTR; + v -> reg = jvm_alloc_register_untyped(p -> rf, true); + v -> type = t; + jvm_generate(p, 0, 0, ".var %i is %s [%s from start to end", v -> reg, name, t -> desc); + jvm_generate(p, 0, 0, ".var %i is __%s_offset I from start to end", v -> reg + 1, name); +} + +void +jvm_generate_variable_initialization(gen_proc_t * p, gen_var_t * v) +{ + if(v -> storage == JVM_STORAGE_STATIC) + { + jvm_generate(p, 0, 1, "iconst_1"); + jvm_generate(p, 1, 1, "multianewarray [%s 1", v -> type -> desc); + jvm_generate(p, 1, 0, "putstatic %s [%s", v -> full_name, v -> type -> desc); + } + else if(v -> storage == JVM_STORAGE_FIELD) + { + jvm_generate(p, 0, 1, "iconst_1"); + jvm_generate(p, 1, 1, "multianewarray [%s 1", v -> type -> desc); + jvm_generate(p, 1, 0, "putfield %s [%s", v -> full_name, v -> type -> desc); + } +} + +void +jvm_generate_param_initialization(gen_proc_t * p, gen_var_t * v) +{ + assert(v -> storage == JVM_STORAGE_REGISTER); + + int old_reg = v -> reg; + bool wide = v -> type -> wide; + int cell_size = v -> type -> cell_size; + char prefix = v -> type -> prefix; + char * desc = v -> type -> desc; + + v -> storage = JVM_STORAGE_LOCAL; + v -> reg = jvm_alloc_register_untyped(p -> rf, wide); + + jvm_generate(p, 0, 1, "iconst_1"); + jvm_generate(p, 1, 1, "multianewarray [%s 1", desc); + jvm_generate(p, 1, 2, "dup"); + jvm_generate(p, 1, 0, "astore %i", v -> reg); + + jvm_generate(p, 0, 1, "iconst_0"); + jvm_generate(p, 0, cell_size, "%cload %i", prefix, old_reg); + jvm_generate(p, 1 + 1 + cell_size, 0, "%castore", prefix); +} diff --git a/src/backends/jvm/generator-jvm-abi.h b/src/backends/jvm/generator-jvm-abi.h new file mode 100644 index 0000000..01bfefc --- /dev/null +++ b/src/backends/jvm/generator-jvm-abi.h @@ -0,0 +1,29 @@ +void +jvm_generate_ldst_prepare(gen_proc_t * p, gen_var_t * v); + +void +jvm_generate_load(gen_proc_t * p, gen_var_t * src); + +void +jvm_generate_store(gen_proc_t * p, gen_var_t * dst); + +void +jvm_generate_and_init_global_var(struct gen_class * class, gen_var_t * v, char * name, gen_type_t * t); + +void +jvm_generate_and_init_field(struct gen_class * class, gen_var_t * v, char * name, gen_type_t * t); + +void +jvm_generate_and_init_local_var(gen_proc_t * p, gen_var_t * v, gen_type_t * t); + +void +jvm_generate_and_init_named_local_var(gen_proc_t * p, gen_var_t * v, char * name, gen_type_t * t); + +void +jvm_generate_and_init_var_param(gen_proc_t * p, gen_var_t * v, char * name, gen_type_t * t); + +void +jvm_generate_variable_initialization(gen_proc_t * p, gen_var_t * v); + +void +jvm_generate_param_initialization(gen_proc_t * p, gen_var_t * v); diff --git a/src/backends/jvm/generator-jvm-asm.c b/src/backends/jvm/generator-jvm-asm.c new file mode 100644 index 0000000..50f3af9 --- /dev/null +++ b/src/backends/jvm/generator-jvm-asm.c @@ -0,0 +1,302 @@ +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "../../../include/oberon.h" +#include "../../oberon-internals.h" +#include "generator-jvm.h" +#include "generator-jvm-abi.h" +#include "generator-jvm-asm.h" +#include "generator-jvm-basic.h" + +gen_proc_t * +jvm_create_proc(struct gen_class * class) +{ + gen_proc_t * p = GC_MALLOC(sizeof *p); + memset(p, 0, sizeof *p); + + struct gen_register_file * rf = GC_MALLOC(sizeof *rf); + memset(rf, 0, sizeof *rf); + + struct gen_stack * stack = GC_MALLOC(sizeof *stack); + memset(rf, 0, sizeof *stack); + + p -> rf = rf; + p -> stack = stack; + p -> class = class; + p -> label_id = 0; + + return p; +} + +void +jvm_generate_function_header(gen_proc_t * p, char * access, char * name, char * signature) +{ + struct gen_class * class; + class = p -> class; + + /* Делаем процедуру текущей в этом классе */ + assert(class -> p == NULL); + class -> p = p; + + fprintf(class -> fp, ".method %s %s%s\n", access, name, signature); + fprintf(class -> fp, " start:\n"); +} + +void +jvm_generate_function_end(gen_proc_t * p) +{ + struct gen_class * class; + class = p -> class; + + assert(class -> p); + class -> p = NULL; + + 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:\n"); + fprintf(class -> fp, ".end method\n\n"); +} + +struct gen_class * +jvm_create_class(char * full_name) +{ + struct gen_class * class = GC_MALLOC(sizeof *class); + 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); + + return class; +} + +void +jvm_destroy_class(struct gen_class * class) +{ + assert(class -> p == NULL); + fclose(class -> fp); +} + +void +jvm_stack_push(gen_proc_t * p, unsigned size) +{ + p -> stack -> pointer += size; + if(p -> stack -> pointer > p -> stack -> max_pointer) + { + p -> stack -> max_pointer = p -> stack -> pointer; + } +} + +void +jvm_stack_pop(gen_proc_t * p, unsigned size) +{ + p -> stack -> pointer -= size; + + if(p -> stack -> pointer < 0) + { + printf("WARING: stack pointer %i\n", p -> stack -> pointer); + } +} + +void +jvm_generate(gen_proc_t * p, unsigned get, unsigned push, char * format, ...) +{ + va_list ptr; + va_start(ptr, format); + + jvm_stack_pop(p, get); + fprintf(p -> class -> fp, " "); + vfprintf(p -> class -> fp, format, ptr); + jvm_stack_push(p, push); + fprintf(p -> class -> fp, " \t ;>>>> %i -- %i : current_stack(%i)\n", get, push, p -> stack -> pointer); + + va_end(ptr); +} + +void +jvm_generate_comment(gen_proc_t * p, char * format, ...) +{ + va_list ptr; + va_start(ptr, format); + + fprintf(p -> class -> fp, " ;;;; "); + vfprintf(p -> class -> fp, format, ptr); + fprintf(p -> class -> fp, "\n"); + + va_end(ptr); +} + +void +jvm_generate_push_int(gen_proc_t * p, int64_t i) +{ + if(i == -1) + { + jvm_generate(p, 0, 1, "iconst_m1"); + } + else if(i >= 0 && i <= 5) + { + jvm_generate(p, 0, 1, "iconst_%li", i); + } + else if(i >= -128 && i <= 127) + { + jvm_generate(p, 0, 1, "bipush %li", i); + } + else if(i >= -32768 && i <= 32767) + { + jvm_generate(p, 0, 1, "sipush %li", i); + } + else if(i >= -2147483648 && i <= 2147483647) + { + jvm_generate(p, 0, 1, "ldc %li", i); + } + else + { + jvm_generate(p, 0, 2, "ldc2_w %li", i); + } +} + +void +jvm_generate_push_int_size(gen_proc_t * p, int64_t i, int size) +{ + int pushed_cell = 1; + + if(i == -1) + { + jvm_generate(p, 0, 1, "iconst_m1"); + } + else if(i >= 0 && i <= 5) + { + jvm_generate(p, 0, 1, "iconst_%li", i); + } + else if(i >= -128 && i <= 127) + { + jvm_generate(p, 0, 1, "bipush %li", i); + } + else if(i >= -32768 && i <= 32767) + { + jvm_generate(p, 0, 1, "sipush %li", i); + } + else if(i >= -2147483648 && i <= 2147483647) + { + jvm_generate(p, 0, 1, "ldc %li", i); + } + else + { + pushed_cell = 2; + jvm_generate(p, 0, 2, "ldc2_w %li", i); + } + + assert(size <= 8); + if(size > 4 && pushed_cell == 1) + { + jvm_generate(p, pushed_cell, 2, "i2l"); + } + else if(size <= 4) + { + if(pushed_cell > 1) + { + jvm_generate(p, 2, 1, "l2i"); + } + + if(size == 2) + { + jvm_generate(p, 1, 1, "i2s"); + } + else if(size == 1) + { + jvm_generate(p, 1, 1, "i2b"); + } + } +} + +void +jvm_generate_push_float(gen_proc_t * p, double f, int size) +{ + if(size <= 4) + { + if(f == 0.0) + { + jvm_generate(p, 0, 1, "fconst_0"); + } + if(f == 1.0) + { + jvm_generate(p, 0, 1, "fconst_1"); + } + if(f == 2.0) + { + jvm_generate(p, 0, 1, "fconst_2"); + } + else + { + jvm_generate(p, 0, 1, "ldc %lf", f); + } + } + else + { + if(f == 0.0) + { + jvm_generate(p, 0, 2, "dconst_0"); + } + if(f == 1.0) + { + jvm_generate(p, 0, 2, "dconst_1"); + } + else + { + jvm_generate(p, 0, 2, "ldc2_w %lf", f); + } + } +} + +void +jvm_generate_push_string(gen_proc_t * p, char * str, int char_size) +{ + assert(char_size == 1); + int len = strlen(str); + + jvm_generate_push_int(p, len + 1); + jvm_generate(p, 1, 1, "newarray byte"); + + for(int i = 0; i < len; i++) + { + jvm_generate(p, 1, 2, "dup"); + jvm_generate_push_int(p, i); + jvm_generate_push_int(p, str[i]); + jvm_generate(p, 3, 0, "bastore"); + } +} + +gen_var_t * +oberon_generator_new_var() +{ + gen_var_t * v = GC_MALLOC(sizeof *v); + memset(v, 0, sizeof *v); + return v; +} + +int +jvm_new_label_id(gen_proc_t * p) +{ + int label_id = p -> label_id; + p -> label_id += 1; + return label_id; +} + +void +jvm_generate_label(gen_proc_t * p, int label_id) +{ + jvm_generate(p, 0, 0, "L%i:", label_id); +} diff --git a/src/backends/jvm/generator-jvm-asm.h b/src/backends/jvm/generator-jvm-asm.h new file mode 100644 index 0000000..da287a0 --- /dev/null +++ b/src/backends/jvm/generator-jvm-asm.h @@ -0,0 +1,53 @@ +struct gen_class * +jvm_create_class(char * full_name); + +void +jvm_destroy_class(struct gen_class * class); + +gen_proc_t * +jvm_create_proc(struct gen_class * class); + +gen_var_t * +oberon_generator_new_var(); + + + +void +jvm_generate_function_header(gen_proc_t * p, char * access, char * name, char * signature); + +void +jvm_generate_function_end(gen_proc_t * p); + +int +jvm_new_label_id(gen_proc_t * p); + +void +jvm_generate_label(gen_proc_t * p, int label_id); + + + +void +jvm_stack_push(gen_proc_t * p, unsigned size); + +void +jvm_stack_pop(gen_proc_t * p, unsigned size); + + + +void +jvm_generate(gen_proc_t * p, unsigned get, unsigned push, char * format, ...); + +void +jvm_generate_comment(gen_proc_t * p, char * format, ...); + +void +jvm_generate_push_int(gen_proc_t * p, int64_t i); + +void +jvm_generate_push_int_size(gen_proc_t * p, int64_t i, int size); + +void +jvm_generate_push_float(gen_proc_t * p, double f, int size); + +void +jvm_generate_push_string(gen_proc_t * p, char * str, int char_size); diff --git a/src/backends/jvm/generator-jvm-basic.c b/src/backends/jvm/generator-jvm-basic.c index bcd82a2..277940c 100644 --- a/src/backends/jvm/generator-jvm-basic.c +++ b/src/backends/jvm/generator-jvm-basic.c @@ -126,6 +126,26 @@ jvm_get_descriptor(oberon_type_t * type) desc = jvm_get_descriptor(type -> base); return new_string("[%s", desc); break; + case OBERON_TYPE_STRING: + 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 string size %i", type -> size); + break; + } + break; default: gen_error("jvm_get_descriptor: unsupported type class %i", type -> class); break; @@ -173,13 +193,14 @@ jvm_get_prefix(oberon_type_t * type) case OBERON_TYPE_ARRAY: case OBERON_TYPE_RECORD: case OBERON_TYPE_POINTER: + case OBERON_TYPE_STRING: return 'a'; break; case OBERON_TYPE_REAL: return (size <= 4) ? ('f') : ('d'); break; default: - gen_error("jvm_get_prefix: wat"); + gen_error("jvm_get_prefix: wat %i", type -> class); return '!'; break; } @@ -239,6 +260,7 @@ jvm_get_postfix(oberon_type_t * type) case OBERON_TYPE_ARRAY: case OBERON_TYPE_RECORD: case OBERON_TYPE_POINTER: + case OBERON_TYPE_STRING: return 'a'; break; case OBERON_TYPE_REAL: @@ -347,7 +369,14 @@ jvm_get_procedure_signature(oberon_type_t * proc) for(int i = 0; i < num; i++) { desc = jvm_get_descriptor(arg -> type); - signature = new_string("%s%s", signature, desc); + if(arg -> class == OBERON_CLASS_VAR_PARAM) + { + signature = new_string("%s[%sI", signature, desc); + } + else + { + signature = new_string("%s%s", signature, desc); + } arg = arg -> next; } diff --git a/src/backends/jvm/generator-jvm.c b/src/backends/jvm/generator-jvm.c index a107efc..da8b06b 100644 --- a/src/backends/jvm/generator-jvm.c +++ b/src/backends/jvm/generator-jvm.c @@ -11,392 +11,12 @@ #include "../../../include/oberon.h" #include "../../oberon-internals.h" #include "generator-jvm.h" +#include "generator-jvm-abi.h" +#include "generator-jvm-asm.h" #include "generator-jvm-basic.h" -// ========================================== -// ========================================== -// ========================================== - -gen_proc_t * -jvm_create_proc(struct gen_class * class) -{ - gen_proc_t * p = GC_MALLOC(sizeof *p); - memset(p, 0, sizeof *p); - - struct gen_register_file * rf = GC_MALLOC(sizeof *rf); - memset(rf, 0, sizeof *rf); - - struct gen_stack * stack = GC_MALLOC(sizeof *stack); - memset(rf, 0, sizeof *stack); - - p -> rf = rf; - p -> stack = stack; - p -> class = class; - p -> label_id = 0; - - return p; -} - -void -jvm_generate_function_header(gen_proc_t * p, char * access, char * name, char * signature) -{ - struct gen_class * class; - class = p -> class; - - /* Делаем процедуру текущей в этом классе */ - assert(class -> p == NULL); - class -> p = p; - - fprintf(class -> fp, ".method %s %s%s\n", access, name, signature); - fprintf(class -> fp, " start:\n"); -} - -void -jvm_generate_function_end(gen_proc_t * p) -{ - struct gen_class * class; - class = p -> class; - - assert(class -> p); - class -> p = NULL; - - 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:\n"); - fprintf(class -> fp, ".end method\n\n"); -} - -struct gen_class * -jvm_create_class(char * full_name) -{ - struct gen_class * class = GC_MALLOC(sizeof *class); - 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); - - return class; -} - -static void -jvm_destroy_class(struct gen_class * class) -{ - assert(class -> p == NULL); - fclose(class -> fp); -} - -static void -jvm_stack_push(gen_proc_t * p, unsigned size) -{ - p -> stack -> pointer += size; - if(p -> stack -> pointer > p -> stack -> max_pointer) - { - p -> stack -> max_pointer = p -> stack -> pointer; - } -} - -static void -jvm_stack_pop(gen_proc_t * p, unsigned size) -{ - p -> stack -> pointer -= size; - - if(p -> stack -> pointer < 0) - { - printf("WARING: stack pointer %i\n", p -> stack -> pointer); - } -} - -static void -jvm_generate(gen_proc_t * p, unsigned get, unsigned push, char * format, ...) -{ - va_list ptr; - va_start(ptr, format); - - jvm_stack_pop(p, get); - fprintf(p -> class -> fp, " "); - vfprintf(p -> class -> fp, format, ptr); - jvm_stack_push(p, push); - fprintf(p -> class -> fp, " \t ;>>>> %i -- %i : current_stack(%i)\n", get, push, p -> stack -> pointer); - - va_end(ptr); -} - -static void -jvm_generate_comment(gen_proc_t * p, char * format, ...) -{ - va_list ptr; - va_start(ptr, format); - - fprintf(p -> class -> fp, " ;;;; "); - vfprintf(p -> class -> fp, format, ptr); - fprintf(p -> class -> fp, "\n"); - - va_end(ptr); -} - -static void -jvm_generate_push_int(gen_proc_t * p, int64_t i) -{ - if(i == -1) - { - jvm_generate(p, 0, 1, "iconst_m1"); - } - else if(i >= 0 && i <= 5) - { - jvm_generate(p, 0, 1, "iconst_%li", i); - } - else if(i >= -128 && i <= 127) - { - jvm_generate(p, 0, 1, "bipush %li", i); - } - else if(i >= -32768 && i <= 32767) - { - jvm_generate(p, 0, 1, "sipush %li", i); - } - else if(i >= -2147483648 && i <= 2147483647) - { - jvm_generate(p, 0, 1, "ldc %li", i); - } - else - { - jvm_generate(p, 0, 2, "ldc2_w %li", i); - } -} - -static void -jvm_generate_push_int_size(gen_proc_t * p, int64_t i, int size) -{ - int pushed_cell = 1; - - if(i == -1) - { - jvm_generate(p, 0, 1, "iconst_m1"); - } - else if(i >= 0 && i <= 5) - { - jvm_generate(p, 0, 1, "iconst_%li", i); - } - else if(i >= -128 && i <= 127) - { - jvm_generate(p, 0, 1, "bipush %li", i); - } - else if(i >= -32768 && i <= 32767) - { - jvm_generate(p, 0, 1, "sipush %li", i); - } - else if(i >= -2147483648 && i <= 2147483647) - { - jvm_generate(p, 0, 1, "ldc %li", i); - } - else - { - pushed_cell = 2; - jvm_generate(p, 0, 2, "ldc2_w %li", i); - } - - assert(size <= 8); - if(size > 4 && pushed_cell == 1) - { - jvm_generate(p, pushed_cell, 2, "i2l"); - } - else if(size <= 4) - { - if(pushed_cell > 1) - { - jvm_generate(p, 2, 1, "l2i"); - } - - if(size == 2) - { - jvm_generate(p, 1, 1, "i2s"); - } - else if(size == 1) - { - jvm_generate(p, 1, 1, "i2b"); - } - } -} - -static void -jvm_generate_push_float(gen_proc_t * p, double f, int size) -{ - if(size <= 4) - { - if(f == 0.0) - { - jvm_generate(p, 0, 1, "fconst_0"); - } - if(f == 1.0) - { - jvm_generate(p, 0, 1, "fconst_1"); - } - if(f == 2.0) - { - jvm_generate(p, 0, 1, "fconst_2"); - } - else - { - jvm_generate(p, 0, 1, "ldc %lf", f); - } - } - else - { - if(f == 0.0) - { - jvm_generate(p, 0, 2, "dconst_0"); - } - if(f == 1.0) - { - jvm_generate(p, 0, 2, "dconst_1"); - } - else - { - jvm_generate(p, 0, 2, "ldc2_w %lf", f); - } - } -} - -static void -jvm_generate_push_string(gen_proc_t * p, char * str, int char_size) -{ - assert(char_size == 1); - int len = strlen(str); - - jvm_generate_push_int(p, len + 1); - jvm_generate(p, 1, 1, "newarray byte"); - - for(int i = 0; i < len; i++) - { - jvm_generate(p, 1, 2, "dup"); - jvm_generate_push_int(p, i); - jvm_generate_push_int(p, str[i]); - jvm_generate(p, 3, 0, "bastore"); - } -} - -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) -{ - int label_id = p -> label_id; - p -> label_id += 1; - return label_id; -} - -static char * -jvm_get_label_name(int label_id) -{ - return new_string("L%i", label_id); -} - -static void -jvm_generate_label(gen_proc_t * p, int label_id) -{ - jvm_generate(p, 0, 0, "L%i:", label_id); -} - -static void -jvm_generate_load(gen_proc_t * p, oberon_type_t * src_type, gen_var_t * src) -{ - char prefix; - int cell_size; - - cell_size = jvm_cell_size_for_type(src_type); - - switch(src -> storage) - { - case JVM_STORAGE_REGISTER: - prefix = jvm_get_prefix(src_type); - jvm_generate(p, 0, cell_size, "%cload %i", prefix, src -> reg); - break; - case JVM_STORAGE_STATIC: - jvm_generate(p, 0, cell_size, "getstatic %s %s", src -> full_name, src -> desc); - break; - case JVM_STORAGE_FIELD: - jvm_generate(p, 1, cell_size, "getfield %s %s", src -> full_name, src -> desc); - break; - default: - gen_error("jvm_generate_load: unknow storage type %i", src -> storage); - 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; - } -} +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); @@ -424,15 +44,15 @@ jvm_generate_array_initialization(gen_proc_t * p, oberon_type_t * arr) } struct { - gen_var_t * index; - gen_var_t * length; + int reg_index; + int reg_length; int start; int end; } loop[dim]; - gen_var_t * dst = oberon_generator_new_var(); - jvm_generate_and_init_local_var(dst, p, false); - jvm_generate_store(p, arr, dst); + int reg_dst; + reg_dst = jvm_alloc_register_untyped(p -> rf, false); + jvm_generate(p, 1, 0, "astore %i", reg_dst); /* * Входящие параметры заграблены. @@ -453,42 +73,38 @@ jvm_generate_array_initialization(gen_proc_t * p, oberon_type_t * arr) for(int i = 0; i < dim; i++) { - loop[i].index = oberon_generator_new_var(); - loop[i].length = oberon_generator_new_var(); + 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_and_init_local_var(loop[i].index, p, false); - jvm_generate_and_init_local_var(loop[i].length, p, false); - - /* TODO преределать через jvm_generate_load{{store}} */ jvm_generate(p, 0, 1, "iconst_0"); - jvm_generate(p, 1, 0, "istore %i", loop[i].index -> reg); + jvm_generate(p, 1, 0, "istore %i", loop[i].reg_index); - jvm_generate_load(p, arr, dst); + jvm_generate(p, 0, 1, "aload %i", reg_dst); jvm_generate(p, 1, 1, "arraylength"); - jvm_generate(p, 1, 0, "istore %i", loop[i].length -> reg); + 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].index -> reg); - jvm_generate(p, 0, 1, "iload %i", loop[i].length -> reg); + 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_load(p, arr, dst); - jvm_generate(p, 0, 1, "iload %i", loop[0].index -> reg); + 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].index -> reg); + 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].index -> reg); + 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); } @@ -582,19 +198,16 @@ jvm_generate_copy_array(gen_proc_t * p, oberon_type_t * arr) } struct { - gen_var_t * index; - gen_var_t * length; + int reg_index; + int reg_length; int start; int end; } loop[dim]; - gen_var_t * dst = oberon_generator_new_var(); - gen_var_t * src = oberon_generator_new_var(); - jvm_generate_and_init_local_var(dst, p, false); - jvm_generate_and_init_local_var(src, p, false); - - jvm_generate_store(p, arr, src); - jvm_generate_store(p, arr, dst); + 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); /* * Входящие параметры заграблены. @@ -615,26 +228,22 @@ jvm_generate_copy_array(gen_proc_t * p, oberon_type_t * arr) for(int i = 0; i < dim; i++) { - loop[i].index = oberon_generator_new_var(); - loop[i].length = oberon_generator_new_var(); + 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_and_init_local_var(loop[i].index, p, false); - jvm_generate_and_init_local_var(loop[i].length, p, false); - - /* TODO преределать через jvm_generate_load{{store}} */ jvm_generate(p, 0, 1, "iconst_0"); - jvm_generate(p, 1, 0, "istore %i", loop[i].index -> reg); + jvm_generate(p, 1, 0, "istore %i", loop[i].reg_index); - jvm_generate_load(p, arr, src); + jvm_generate(p, 0, 1, "aload %i", reg_src); jvm_generate(p, 1, 1, "arraylength"); - jvm_generate(p, 1, 0, "istore %i", loop[i].length -> reg); + 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].index -> reg); - jvm_generate(p, 0, 1, "iload %i", loop[i].length -> reg); + 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); } @@ -642,17 +251,17 @@ jvm_generate_copy_array(gen_proc_t * p, oberon_type_t * arr) { /* Получаем записи по индексам ( -- dst src ) */ - jvm_generate_load(p, arr, dst); + 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].index -> reg); + jvm_generate(p, 0, 1, "iload %i", loop[i].reg_index); jvm_generate(p, 2, 1, "aaload"); } - jvm_generate_load(p, arr, src); + 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].index -> reg); + jvm_generate(p, 0, 1, "iload %i", loop[i].reg_index); jvm_generate(p, 2, 1, "aaload"); } @@ -666,20 +275,20 @@ jvm_generate_copy_array(gen_proc_t * p, oberon_type_t * arr) /* Получаем массивы и индексы ( -- dst i src i ) */ - jvm_generate_load(p, arr, dst); - jvm_generate(p, 0, 1, "iload %i", loop[0].index -> reg); + 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].index -> reg); + jvm_generate(p, 0, 1, "iload %i", loop[i].reg_index); } - jvm_generate_load(p, arr, src); - jvm_generate(p, 0, 1, "iload %i", loop[0].index -> reg); + 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].index -> reg); + jvm_generate(p, 0, 1, "iload %i", loop[i].reg_index); } /* Копируем значения ( dst i src i -- ) */ @@ -689,7 +298,7 @@ jvm_generate_copy_array(gen_proc_t * p, oberon_type_t * arr) for(int i = dim - 1; i >= 0; i--) { - jvm_generate(p, 0, 0, "iinc %i 1", loop[i].index -> reg); + 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); } @@ -703,13 +312,6 @@ jvm_generate_push_procedure_pointer(gen_proc_t * p, oberon_object_t * proc) jvm_generate(p, 0, 1, "getstatic %s/pointer %s", full_name, desc); } -// ========================================== -// ========================================== -// ========================================== - -static void -push_item(gen_proc_t * p, oberon_item_t * item); - void oberon_generator_init_context(oberon_context_t * ctx) { @@ -793,36 +395,34 @@ oberon_generate_procedure_pointer_class(oberon_object_t * proc) signature = jvm_get_procedure_signature(proc -> type); - gen_proc_t * p; - gen_var_t * this_v; - - p = jvm_create_proc(class); + gen_proc_t * p = jvm_create_proc(class); jvm_generate_function_header(p, "public", "invoke", signature); + jvm_alloc_register_untyped(p -> rf, false); - this_v = oberon_generator_new_var(); - jvm_generate_and_init_local_var(this_v, p, false); - - gen_var_t * v; int use_size = 0; int num = proc -> type -> num_decl; - oberon_object_t * arg = proc -> type -> decl; + oberon_object_t * param = proc -> type -> decl; for(int i = 0; i < num; i++) { - v = oberon_generator_new_var(); - bool wide = jvm_is_wide_type(arg -> type); - char * desc = jvm_get_descriptor(arg -> type); - jvm_generate_and_init_named_local_var(v, p, wide, arg -> name, desc); - - jvm_generate_load(p, arg -> type, v); - - use_size += (wide) ? (2) : (1); - - arg = arg -> next; + gen_var_t * v = oberon_generator_new_var(); + gen_type_t * t = param -> type -> gen_type; + use_size += t -> cell_size; + if(param -> class == OBERON_CLASS_VAR_PARAM) + { + jvm_generate_and_init_var_param(p, v, param -> name, t); + jvm_generate_ldst_prepare(p, v); + } + else + { + jvm_generate_and_init_named_local_var(p, v, param -> name, t); + jvm_generate_load(p, v); + } + 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_VOID) @@ -876,12 +476,22 @@ oberon_generator_init_type(oberon_context_t * ctx, oberon_type_t * type) memset(t, 0, sizeof *t); type -> gen_type = t; + if(type -> class != OBERON_TYPE_VOID) + { + t -> wide = jvm_is_wide_type(type); + t -> prefix = jvm_get_prefix(type); + t -> postfix = jvm_get_postfix(type); + } + t -> cell_size = jvm_cell_size_for_type(type); + t -> desc = jvm_get_descriptor(type); + switch(type -> class) { case OBERON_TYPE_VOID: 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: @@ -896,8 +506,6 @@ oberon_generator_init_type(oberon_context_t * ctx, oberon_type_t * type) case OBERON_TYPE_PROCEDURE: oberon_generate_procedure_class(type); break; - case OBERON_TYPE_POINTER: - break; default: gen_error("oberon_generator_init_type: unk calss %i", type -> class); break; @@ -914,10 +522,10 @@ 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++) { - 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); + gen_var_t * v = field -> gen_var; + gen_type_t * t = field -> type -> gen_type; + jvm_generate_and_init_field(class, v, name, t); field = field -> next; } @@ -939,12 +547,16 @@ oberon_generator_init_record(oberon_context_t * ctx, oberon_type_t * rec) field = rec -> decl; for(int i = 0; i < num; i++) { + jvm_generate(p, 0, 1, "aload_0"); + jvm_generate_variable_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 -> type, field -> gen_var); + jvm_generate_store(p, field -> gen_var); } field = field -> next; } @@ -956,37 +568,37 @@ oberon_generator_init_record(oberon_context_t * ctx, oberon_type_t * rec) p = jvm_create_proc(class); gen_var_t * copy_dst = oberon_generator_new_var(); gen_var_t * copy_src = oberon_generator_new_var(); - char * desc = jvm_get_descriptor(rec); - char * signature = new_string("(%s%s)V", desc, desc); + char * signature = new_string("(%s%s)V", rec -> gen_type -> desc, rec -> gen_type -> desc); jvm_generate_function_header(p, "public static", "$COPY$", signature); - jvm_generate_and_init_named_local_var(copy_dst, p, false, "dst", desc); - jvm_generate_and_init_named_local_var(copy_src, p, false, "src", desc); + jvm_generate_and_init_named_local_var(p, copy_dst, "dst", rec -> gen_type); + jvm_generate_and_init_named_local_var(p, copy_src, "src", rec -> gen_type); 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, rec, copy_dst); - jvm_generate_load(p, field -> type, field -> gen_var); - jvm_generate_load(p, rec, copy_src); - jvm_generate_load(p, field -> type, field -> gen_var); + 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, rec, copy_dst); - jvm_generate_load(p, field -> type, field -> gen_var); - jvm_generate_load(p, rec, copy_src); - jvm_generate_load(p, field -> type, field -> gen_var); + 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, rec, copy_dst); - jvm_generate_load(p, rec, copy_src); - jvm_generate_load(p, field -> type, field -> gen_var); - jvm_generate_store(p, field -> type, field -> gen_var); + 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; } @@ -1008,12 +620,9 @@ 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() */ @@ -1025,10 +634,9 @@ oberon_generator_init_var(oberon_context_t * ctx, oberon_object_t * var) case OBERON_CLASS_VAR: /* Локальные заполняются при генерации функции */ /* смотри jvm_init_local_object() */ - if(var -> local == 0) + if(var -> local == false) { - desc = jvm_get_descriptor(var -> type); - jvm_generate_and_init_global_var(v, class, "public", var -> name, desc); + jvm_generate_and_init_global_var(class, v, var -> name, var -> type -> gen_type); } break; default: @@ -1051,10 +659,7 @@ oberon_generator_init_temp_var(oberon_context_t * ctx, oberon_object_t * var) gen_proc_t * p; p = m -> class -> p; - bool wide; - wide = jvm_is_wide_type(var -> type); - - jvm_generate_and_init_local_var(v, p, wide); + jvm_generate_and_init_local_var(p, v, var -> type -> gen_type); } void @@ -1067,8 +672,10 @@ oberon_generator_init_proc(oberon_context_t * ctx, oberon_object_t * proc) { gen_error("generator: local procedures not implemented"); } - - oberon_generate_procedure_pointer_class(proc); + else + { + oberon_generate_procedure_pointer_class(proc); + } } void @@ -1116,11 +723,13 @@ oberon_generate_begin_module(oberon_context_t * ctx) { if(x -> class == OBERON_CLASS_VAR) { + jvm_generate_variable_initialization(p, x -> gen_var); 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 -> type, x -> gen_var); + jvm_generate_store(p, x -> gen_var); } } @@ -1138,35 +747,6 @@ oberon_generate_end_module(oberon_context_t * ctx) jvm_generate_function_end(class -> p); } -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); - - // Убеждаемся что сейчас находимся в функции - assert(class -> p); - assert(x -> local); - - switch(x -> class) - { - case OBERON_CLASS_VAR: - case OBERON_CLASS_PARAM: - jvm_generate_and_init_named_local_var(v, p, wide, x -> name, desc); - break; - default: - gen_error("jvm_init_local_object: wat"); - break; - } -} - /* * Генерирует код для получения размера измерения массива * Аналог Обероновского LEN(v, n); где n = 0 - первое измерение. @@ -1188,13 +768,15 @@ jvm_generate_array_len(gen_proc_t * p, int dim) 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, arr, v); + jvm_generate_load(p, v); jvm_generate_array_len(p, dim); dim += 1; } @@ -1203,19 +785,77 @@ jvm_generate_array_duplicate_and_replace(gen_proc_t * p, gen_var_t * v, oberon_t jvm_generate_new(p, arr, dim); jvm_generate(p, 1, 2, "dup"); - jvm_generate_load(p, arr, v); + jvm_generate_load(p, v); jvm_generate_copy_array(p, arr); - jvm_generate_store(p, arr, v); + 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, rec, v); + jvm_generate_load(p, v); jvm_generate_copy_record(p, rec); - jvm_generate_store(p, rec, v); + jvm_generate_store(p, v); +} + +static void +jvm_init_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: + jvm_generate_and_init_var_param(p, v, x -> name, x -> type -> gen_type); + break; + case OBERON_CLASS_VAR: + case OBERON_CLASS_PARAM: + jvm_generate_and_init_named_local_var(p, v, x -> name, x -> type -> gen_type); + break; + default: + gen_error("jvm_init_local_object: wat"); + 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: + break; + case OBERON_CLASS_VAR: + jvm_generate_variable_initialization(p, v); + break; + case OBERON_CLASS_PARAM: + jvm_generate_param_initialization(p, v); + break; + default: + gen_error("jvm_generate_local_initialization: wat"); + break; + } } void @@ -1230,13 +870,21 @@ oberon_generate_begin_proc(oberon_context_t * ctx, oberon_object_t * proc) jvm_generate_function_header(p, "public static", proc -> name, signature); /* Выделение регистров под параметры и переменные */ - oberon_object_t * var = proc -> type -> decl; + oberon_object_t * var = proc -> scope -> list -> next; while(var) { jvm_init_local_object(p, var); var = var -> next; } + /* Инициализация */ + var = proc -> scope -> list -> next; + while(var) + { + jvm_generate_local_initialization(p, var); + var = var -> next; + } + /* Копирование статических/открытых массивов и записей */ var = proc -> type -> decl; while(var) @@ -1332,6 +980,30 @@ oberon_generate_branch(oberon_context_t * ctx, oberon_expr_t * cond, bool gotoif } } +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, (oberon_item_t *) expr -> item.parent); + push_expr(p, expr -> item.args); + break; + case MODE_FIELD: + push_item(p, (oberon_item_t *) expr -> item.parent); + jvm_generate_ldst_prepare(p, expr -> item.var -> gen_var); + 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) { @@ -1366,11 +1038,21 @@ jvm_generate_call_proc(gen_proc_t * p, oberon_item_t * desig) int num = desig -> num_args; oberon_expr_t * arg = desig -> args; + oberon_object_t * param = procsig -> decl; for(int i = 0; i < num; i++) { - args_cells += jvm_cell_size_for_type(arg -> result); - push_expr(p, arg); + 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) @@ -1468,7 +1150,7 @@ push_item(gen_proc_t * p, oberon_item_t * item) } else { - jvm_generate_load(p, item -> result, item -> var -> gen_var); + jvm_generate_load(p, item -> var -> gen_var); } break; case MODE_INTEGER: @@ -1494,7 +1176,7 @@ push_item(gen_proc_t * p, oberon_item_t * item) case MODE_FIELD: assert(item -> parent -> is_item); push_item(p, (oberon_item_t *) item -> parent); - jvm_generate_load(p, item -> result, item -> var -> gen_var); + jvm_generate_load(p, item -> var -> gen_var); break; case MODE_DEREF: /* Все объекты в jvm представляются как указатели */ @@ -1524,12 +1206,10 @@ jvm_generate_logical_not(gen_proc_t * p) { int label_done = jvm_new_label_id(p); int label_false = jvm_new_label_id(p); - char * label_name_done = jvm_get_label_name(label_done); - char * label_name_false = jvm_get_label_name(label_false); - jvm_generate(p, 1, 0, "ifne %s", label_name_false); + jvm_generate(p, 1, 0, "ifne L%i", label_false); jvm_generate(p, 0, 1, "iconst_1"); - jvm_generate(p, 0, 0, "goto %s", label_name_done); + 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); @@ -1684,15 +1364,13 @@ 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); - char * label_name_calc_b = jvm_get_label_name(label_calc_b); - char * label_name_done = jvm_get_label_name(label_done); /* a OR b -- если a, то TRUE, иначе b */ push_expr(p, a); - jvm_generate(p, 1, 0, "ifeq %s", label_name_calc_b); + jvm_generate(p, 1, 0, "ifeq L%i", label_calc_b); jvm_generate(p, 0, 1, "iconst_1"); - jvm_generate(p, 0, 0, "goto %s", label_name_done); + 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); @@ -1703,15 +1381,13 @@ 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); - char * label_name_false = jvm_get_label_name(label_false); - char * label_name_done = jvm_get_label_name(label_done); /* a AND b -- если a, то b, иначе FALSE */ push_expr(p, a); - jvm_generate(p, 1, 0, "ifeq %s", label_name_false); + jvm_generate(p, 1, 0, "ifeq L%i", label_false); push_expr(p, b); - jvm_generate(p, 0, 0, "goto %s", label_name_done); + 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); @@ -1725,53 +1401,51 @@ jvm_generate_range(gen_proc_t * p, oberon_expr_t * a, oberon_expr_t * b) char prefix; int cell_size; - oberon_type_t * t; + oberon_type_t * type; gen_var_t * ra; gen_var_t * rb; int label_else; int label_end; - bool wide; - t = a -> result; - cell_size = jvm_cell_size_for_type(t); - prefix = jvm_get_prefix(t); + 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, t -> size); + jvm_generate_push_int_size(p, 1, type -> size); push_expr(p, a); jvm_generate(p, 2 * cell_size, cell_size, "%cshl", prefix); } else { - wide = jvm_is_wide_type(t); ra = oberon_generator_new_var(); rb = oberon_generator_new_var(); - jvm_generate_and_init_local_var(ra, p, wide); - jvm_generate_and_init_local_var(rb, p, wide); + jvm_generate_and_init_local_var(p, ra, type -> gen_type); + jvm_generate_and_init_local_var(p, rb, type -> gen_type); label_else = jvm_new_label_id(p); label_end = jvm_new_label_id(p); push_expr(p, a); - jvm_generate_store(p, t, ra); + jvm_generate_store(p, ra); push_expr(p, b); - jvm_generate_store(p, t, rb); + jvm_generate_store(p, rb); - jvm_generate_load(p, t, ra); - jvm_generate_load(p, t, 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, t -> size); - jvm_generate_load(p, t, rb); + 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, t -> size); - jvm_generate_load(p, t, ra); + 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, t -> size); + jvm_generate_push_int_size(p, 0, type -> size); jvm_generate_label(p, label_end); } @@ -1908,8 +1582,9 @@ store_expr(gen_proc_t * p, oberon_expr_t * dst, oberon_expr_t * src) else switch(item -> mode) { case MODE_VAR: + jvm_generate_ldst_prepare(p, item -> var -> gen_var); push_expr(p, src); - jvm_generate_store(p, src -> result, item -> var -> gen_var); + jvm_generate_store(p, item -> var -> gen_var); break; case MODE_INDEX: ; @@ -1924,8 +1599,9 @@ store_expr(gen_proc_t * p, oberon_expr_t * dst, oberon_expr_t * src) 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, src -> result, item -> var -> gen_var); + jvm_generate_store(p, item -> var -> gen_var); break; default: gen_error("store_expr: unk mode %i", item -> mode); diff --git a/src/backends/jvm/generator-jvm.h b/src/backends/jvm/generator-jvm.h index 3095a49..242aa70 100644 --- a/src/backends/jvm/generator-jvm.h +++ b/src/backends/jvm/generator-jvm.h @@ -30,7 +30,9 @@ enum gen_storage JVM_STORAGE_UNKNOWN, JVM_STORAGE_REGISTER, JVM_STORAGE_STATIC, - JVM_STORAGE_FIELD + JVM_STORAGE_FIELD, + JVM_STORAGE_LOCAL, + JVM_STORAGE_VARPTR }; @@ -46,14 +48,20 @@ struct gen_type_t { int rec_id; struct gen_class * class; + + bool wide; + char prefix; + char postfix; + char * desc; + int cell_size; }; struct gen_var_t { enum gen_storage storage; + gen_type_t * type; int reg; char * full_name; - char * desc; }; struct gen_context_t diff --git a/src/oberon.c b/src/oberon.c index e4b9157..58eb67c 100644 --- a/src/oberon.c +++ b/src/oberon.c @@ -1223,13 +1223,21 @@ oberon_autocast_call(oberon_context_t * ctx, oberon_item_t * desig) { if(param -> class == OBERON_CLASS_VAR_PARAM) { + if(arg -> result != param -> type) + { + oberon_error(ctx, "incompatible type"); + } if(arg -> read_only) { oberon_error(ctx, "assign to read-only var"); } + casted[i] = arg; + } + else + { + casted[i] = oberon_autocast_to(ctx, arg, param -> type); } - casted[i] = oberon_autocast_to(ctx, arg, param -> type); arg = arg -> next; param = param -> next; } diff --git a/src/test.c b/src/test.c index dab2914..cd28a21 100644 --- a/src/test.c +++ b/src/test.c @@ -8,34 +8,24 @@ static char source_test[] = "(* Main module *)" "MODULE Test;" "IMPORT Out;" + "" "TYPE" - " R1 = POINTER TO R1Desc;" - " R1Desc = RECORD a : INTEGER; END;" - " R2 = POINTER TO R2Desc;" - " R2Desc = RECORD (R1Desc) b : INTEGER; END;" - " Y1 = POINTER TO Y1Desc;" - " Y1Desc = RECORD END;" + " R = RECORD iii : INTEGER; END;" "" "VAR" - " r1 : R1;" - " r2 : R2;" - " y1 : Y1;" + " i : INTEGER;" + " a : ARRAY 3 OF INTEGER;" + " r : R;" "" + "PROCEDURE X(VAR x : INTEGER);" "BEGIN" - " NEW(r1);" - " NEW(r2);" - " NEW(y1);" - " r1 := r2;" - " Out.Open;" - " WITH r1 : R2 DO" - " r1.b := 666;" - " Out.String('R2 branch');" - " | y1 : Y1 DO" - " Out.String('Y1 branch');" - " ELSE" - " Out.String('Something else');" - " END;" - " Out.Ln;" + " x := x * 666;" + "END X;" + "" + "BEGIN;" + " r.iii := 2;" + " X(r.iii);" + " Out.Int(r.iii, 0); Out.Ln;" "END Test." ; -- 2.29.2