From: DeaDDooMER <deaddoomer@deadsoftware.ru>
Date: Tue, 25 Jul 2017 17:51:11 +0000 (+0300)
Subject: Первые наработки бэкэнда для jvm
X-Git-Url: http://deadsoftware.ru/gitweb?a=commitdiff_plain;h=2a0d7e7fbb7dcccc65f98301a0627ee47c755f2f;p=dsw-obn.git

Первые наработки бэкэнда для jvm
---

diff --git a/.gitignore b/.gitignore
index bbbc7ed..6cd2ab3 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,2 +1,4 @@
 *.out
 dump.txt
+*.j
+*.class
diff --git a/Launcher.java b/Launcher.java
new file mode 100644
index 0000000..220f671
--- /dev/null
+++ b/Launcher.java
@@ -0,0 +1,6 @@
+class Launcher {
+	public static void main(String[] args)
+	throws ClassNotFoundException, InstantiationException, IllegalAccessException {
+		Class.forName(args[0]).newInstance();;
+	}
+}
diff --git a/jvm_test.sh b/jvm_test.sh
new file mode 100755
index 0000000..9dce872
--- /dev/null
+++ b/jvm_test.sh
@@ -0,0 +1,15 @@
+#!/bin/sh
+
+set -e
+
+./make.sh jvm
+./run.sh
+jasmin *.j
+proguard -injars . \
+	-libraryjars /usr/lib/jvm/java-8-openjdk/jre/lib/rt.jar \
+	-dontshrink -dontobfuscate -keep class Test
+
+java -cp . Launcher Test
+
+echo Everythin ok! Wheee...
+
diff --git a/make.sh b/make.sh
index 9e4b255..561238e 100755
--- a/make.sh
+++ b/make.sh
@@ -9,11 +9,14 @@ case "$1" in
   dummy)
     $CC $CFLAGS src/*.c src/backends/dummy/*.c
   ;;
+  jvm)
+    $CC $CFLAGS src/*.c src/backends/jvm/*.c
+  ;;
   libgccjit)
     CFLAGS="-lgccjit $CFLAGS"
     $CC $CFLAGS src/*.c src/backends/libgccjit/*.c
   ;;
   ***)
     echo "use: make.sh <backend>"
-    echo "list of backends: dummy libgccjit"
+    echo "list of backends: dummy jvm libgccjit"
 esac
diff --git a/src/backends/dummy/generator-libgccjit.c b/src/backends/dummy/generator-dummy.c
similarity index 98%
rename from src/backends/dummy/generator-libgccjit.c
rename to src/backends/dummy/generator-dummy.c
index e9b26b5..fc709a0 100644
--- a/src/backends/dummy/generator-libgccjit.c
+++ b/src/backends/dummy/generator-dummy.c
@@ -5,7 +5,7 @@
 
 #include "../../../include/oberon.h"
 #include "../../oberon-internals.h"
-#include "generator-libgccjit.h"
+#include "generator-dummy.h"
 
 void
 oberon_generator_init_context(oberon_context_t * ctx)
diff --git a/src/backends/dummy/generator-libgccjit.h b/src/backends/dummy/generator-dummy.h
similarity index 100%
rename from src/backends/dummy/generator-libgccjit.h
rename to src/backends/dummy/generator-dummy.h
diff --git a/src/backends/jvm/generator-jvm.c b/src/backends/jvm/generator-jvm.c
new file mode 100644
index 0000000..2a2abcd
--- /dev/null
+++ b/src/backends/jvm/generator-jvm.c
@@ -0,0 +1,744 @@
+#include <stdio.h>
+#include <stdarg.h>
+#include <stdbool.h>
+#include <string.h>
+#include <assert.h>
+
+#include <gc.h>
+
+#include "../../../include/oberon.h"
+#include "../../oberon-internals.h"
+#include "generator-jvm.h"
+
+char *
+new_string(const char * format, ...)
+{
+	va_list ptr;
+	va_start(ptr, format);
+
+	char buf[1024];
+	vsnprintf(buf, 1024, format, ptr);
+
+	va_end(ptr);
+
+	char * result;
+	int size;
+
+	size = strlen(buf);
+	result = GC_MALLOC(size + 1);
+	memset(result, 0, size);
+	strncpy(result, buf, size);
+
+	return result;
+}
+
+void
+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;
+}
+
+void
+oberon_generator_destroy_context(oberon_context_t * ctx)
+{
+	ctx -> gen_context = NULL;
+}
+
+static char * get_class_full_name(oberon_context_t * ctx, oberon_type_t * type);
+
+static char *
+get_descriptor(oberon_context_t * ctx, oberon_type_t * type)
+{
+	char * desc;
+
+	switch(type -> class)
+	{
+		case OBERON_TYPE_VOID:
+			return new_string("V");
+			break;
+		case OBERON_TYPE_INTEGER:
+			switch(type -> size)
+			{
+				case 1:
+					return new_string("B");
+					break;
+				case 2:
+					return new_string("S");
+					break;
+				case 4:
+					return new_string("I");
+					break;
+				case 8:
+					return new_string("J");
+					break;
+				default:
+					oberon_error(ctx, "get_descriptor: unsupported int size %i", type -> size);
+					break;
+			}
+			break;
+		case OBERON_TYPE_REAL:
+			switch(type -> size)
+			{
+				case 4:
+					return new_string("F");
+					break;
+				case 8:
+					return new_string("D");
+					break;
+				default:
+					oberon_error(ctx, "get_descriptor: unsupported float size %i", type -> size);
+					break;
+			}
+			break;
+		case OBERON_TYPE_BOOLEAN:
+			return new_string("Z");
+			break;
+		case OBERON_TYPE_PROCEDURE:
+		case OBERON_TYPE_RECORD:
+			desc = get_class_full_name(ctx, type);
+			return new_string("L%s;", desc);
+			break;
+		case OBERON_TYPE_ARRAY:
+			desc = get_descriptor(ctx, type -> base);
+			return new_string("[%s", desc);
+			break;
+		default:
+			oberon_error(ctx, "print_descriptor: unsupported type class %i", type -> class);
+			break;
+	}
+
+	return NULL;
+}
+
+static char
+get_prefix(oberon_context_t * ctx, oberon_type_t * type)
+{
+	int size = type -> size;
+	switch(type -> class)
+	{
+		case OBERON_TYPE_BOOLEAN:
+		case OBERON_TYPE_INTEGER:
+			return (size <= 4) ? ('i') : ('l');
+			break;
+		case OBERON_TYPE_PROCEDURE:
+		case OBERON_TYPE_ARRAY:
+		case OBERON_TYPE_RECORD:
+		case OBERON_TYPE_POINTER:
+			return 'a';
+			break;
+		case OBERON_TYPE_REAL:
+			return (size <= 4) ? ('f') : ('d');
+			break;
+	}
+
+	oberon_error(ctx, "get_prefix: wat");
+	return '!';
+}
+
+static char *
+get_field_full_name(oberon_context_t * ctx, oberon_object_t * x)
+{
+	return new_string("%s/%s", x -> module -> name, x -> name);
+}
+
+static char *
+get_class_full_name(oberon_context_t * ctx, oberon_type_t * type)
+{
+	int rec_id;
+	char * name = NULL;
+
+	switch(type -> class)
+	{
+		case OBERON_TYPE_PROCEDURE:
+			name = new_string("SYSTEM$PROCEDURE");
+
+			char * desc;
+			desc = get_descriptor(ctx, type -> base);
+			name = new_string("%s$%s", name, desc);
+
+			int num = type -> num_decl;
+			oberon_object_t * arg = type -> decl;
+			for(int i = 0; i < num; i++)
+			{
+				desc = get_descriptor(ctx, arg -> type);
+				name = new_string("%s%s", name, desc);
+				arg = arg -> next;
+			}
+
+			break;
+		case OBERON_TYPE_RECORD:
+			assert(type -> module);
+			assert(type -> module -> gen_mod);
+			rec_id = type -> gen_type -> rec_id;
+			name = new_string("%s$RECORD%i", type -> module -> name, rec_id);
+			break;
+		default:
+			oberon_error(ctx, "get_record_full_name: unk type class %i", type -> class);
+			break;
+	}
+
+	return name;
+}
+
+static char *
+get_procedure_signature(oberon_context_t * ctx, oberon_type_t * proc)
+{
+	char * signature;
+	char * desc;
+
+	signature = new_string("(");
+
+	int num = proc -> num_decl;
+	oberon_object_t * arg = proc -> decl;
+	for(int i = 0; i < num; i++)
+	{
+		desc = get_descriptor(ctx, arg -> type);
+		signature = new_string("%s%s", signature, desc);
+		arg = arg -> next;
+	}
+
+	desc = get_descriptor(ctx, proc -> base);
+	signature = new_string("%s)%s", signature, desc);
+
+	return signature;
+}
+
+static void
+oberon_generate_procedure_class(oberon_context_t * ctx, oberon_type_t * proc)
+{
+	FILE * fp;
+	char * cname;
+	char * fname;
+	char * signature;
+
+	cname = get_class_full_name(ctx, proc);
+	fname = new_string("%s.j", cname);
+
+	fp = fopen(fname, "w");
+
+	fprintf(fp, ".source SYSTEM\n");
+	fprintf(fp, ".class  public abstract %s\n", cname);
+	fprintf(fp, ".super  java/lang/Object\n\n");
+
+	signature = get_procedure_signature(ctx, proc);
+
+	fprintf(fp, ".method public <init>()V\n");
+	fprintf(fp, "  aload_0\n");
+	fprintf(fp, "  invokespecial java/lang/Object/<init>()V\n");
+	fprintf(fp, "  return\n");
+	fprintf(fp, ".end method\n");
+
+	fprintf(fp, ".method public abstract invoke%s\n", signature);
+	fprintf(fp, ".end method\n\n");
+
+	fclose(fp);
+}
+
+static void
+oberon_generate_record_class(oberon_context_t * ctx, oberon_type_t * rec)
+{
+	FILE * fp;
+	char * cname;
+	char * fname;
+
+	/* Устанавливаем новоый id */
+	rec -> gen_type -> rec_id = rec -> module -> gen_mod -> rec_id;
+	rec -> module -> gen_mod -> rec_id += 1;
+
+	cname = get_class_full_name(ctx, rec);
+	fname = new_string("%s.j", cname);
+
+	fp = fopen(fname, "w");
+
+	fprintf(fp, ".source %s\n", rec -> module -> name);
+	fprintf(fp, ".class  public %s\n", cname);
+	fprintf(fp, ".super  java/lang/Object\n\n");
+
+	rec -> gen_type -> fp = fp;
+}
+
+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;
+
+	switch(type -> class)
+	{
+		case OBERON_TYPE_VOID:
+		case OBERON_TYPE_INTEGER:
+		case OBERON_TYPE_BOOLEAN:
+		case OBERON_TYPE_ARRAY:
+		case OBERON_TYPE_REAL:
+			break;
+		case OBERON_TYPE_RECORD:
+			oberon_generate_record_class(ctx, type);
+			break;
+		case OBERON_TYPE_PROCEDURE:
+			oberon_generate_procedure_class(ctx, type);
+			break;
+		case OBERON_TYPE_POINTER:
+			assert(type -> base -> class == OBERON_TYPE_VOID);
+			break;
+		default:
+			oberon_error(ctx, "oberon_generator_init_type: unk calss %i", type -> class);
+			break;
+	}
+}
+
+static void
+oberon_generate_object(oberon_context_t * ctx, FILE * fp, oberon_object_t * x)
+{
+	char * name;
+	char * desc;
+
+	name = x -> name;
+	desc = get_descriptor(ctx, x -> type);
+	switch(x -> class)
+	{
+		case OBERON_CLASS_VAR:
+			fprintf(fp, ".field public static %s %s\n\n", name, desc);
+			break;
+		case OBERON_CLASS_FIELD:
+			fprintf(fp, ".field public %s %s\n\n", name, desc);
+			break;
+		default:
+			oberon_error(ctx, "oberon_generate_object: unk class %i", x -> class);
+			break;
+	}
+}
+
+void
+oberon_generator_init_record(oberon_context_t * ctx, oberon_type_t * rec)
+{
+	FILE * fp;
+
+	fp = rec -> gen_type -> fp;
+
+	int num = rec -> num_decl;
+	oberon_object_t * field = rec -> decl;
+	for(int i = 0; i < num; i++)
+	{
+		oberon_generate_object(ctx, fp, field);
+		field = field -> next;
+	}
+
+	fprintf(fp, ".method public <init>()V\n");
+	fprintf(fp, "  aload_0\n");
+	fprintf(fp, "  invokespecial java/lang/Object/<init>()V\n");
+	fprintf(fp, "  return\n");
+	fprintf(fp, ".end method\n");
+
+	fclose(fp);
+}
+
+void
+oberon_generator_init_var(oberon_context_t * ctx, oberon_object_t * var)
+{
+	gen_var_t * v = GC_MALLOC(sizeof *v);
+	memset(v, 0, sizeof *v);
+	var -> gen_var = v;
+
+	gen_module_t * m = ctx -> mod -> gen_mod;	
+
+	switch(var -> class)
+	{
+		case OBERON_CLASS_PARAM:
+		case OBERON_CLASS_FIELD:
+			break;
+		case OBERON_CLASS_VAR:
+			oberon_generate_object(ctx, m -> fp, var);
+			break;
+		default:
+			oberon_error(ctx, "oberon_generator_init_var: unk var class %i", var -> class);
+			break;
+	}
+}
+
+void
+oberon_generator_init_proc(oberon_context_t * ctx, oberon_object_t * proc)
+{
+	gen_proc_t * p = GC_MALLOC(sizeof *p);
+	memset(p, 0, sizeof *p);
+	proc -> gen_proc = p;
+
+	if(proc -> local)
+	{
+		oberon_error(ctx, "generator: local procedures not implemented");
+	}
+}
+
+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;
+
+	int fnamesz = strlen(mod -> name) + 3;
+	char fname[fnamesz + 1];
+	snprintf(fname, fnamesz, "%s.j", mod -> name);
+
+	FILE * fp;
+	fp = fopen(fname, "w");
+	assert(fp != NULL);
+
+	fprintf(fp, ".source %s\n", mod -> name);
+	fprintf(fp, ".class %s\n", mod -> name);
+	fprintf(fp, ".super java/lang/Object\n\n");
+
+	m -> fp = fp;
+}
+
+// =======================================================================
+//   GENERATOR
+// ======================================================================= 
+
+void
+oberon_generate_begin_module(oberon_context_t * ctx)
+{
+	gen_module_t * m = ctx -> mod -> gen_mod;
+	fprintf(m -> fp, ".method public <init>()V\n");
+	fprintf(m -> fp, "  aload_0\n");
+	fprintf(m -> fp, "  invokespecial java/lang/Object/<init>()V\n");
+}
+
+void
+oberon_generate_end_module(oberon_context_t * ctx)
+{
+	gen_module_t * m = ctx -> mod -> gen_mod;
+
+	fprintf(m -> fp, "  .limit stack 32\n");
+	fprintf(m -> fp, "  .limit locals 32\n");
+	fprintf(m -> fp, "  return\n");
+	fprintf(m -> fp, ".end method\n");
+}
+
+void
+oberon_generate_begin_proc(oberon_context_t * ctx, oberon_object_t * proc)
+{
+	gen_module_t * m;
+	char * signature;
+
+	m = ctx -> mod -> gen_mod;
+	signature = get_procedure_signature(ctx, proc -> type);
+
+	fprintf(m -> fp, ".method public static %s%s\n", proc -> name, signature);
+}
+
+void
+oberon_generate_call_proc(oberon_context_t * ctx, oberon_expr_t * desig)
+{
+	printf("call proc\n");
+}
+
+void
+oberon_generate_end_proc(oberon_context_t * ctx)
+{
+	gen_module_t * m;
+	m = ctx -> mod -> gen_mod;
+
+	fprintf(m -> fp, "  .limit stack 32\n");
+	fprintf(m -> fp, "  .limit locals 32\n");
+	fprintf(m -> fp, ".end method\n\n");
+}
+
+void
+oberon_generate_return(oberon_context_t * ctx, oberon_expr_t * expr)
+{
+	gen_module_t * m;
+
+	m = ctx -> mod -> gen_mod;
+
+	if(expr)
+	{
+		oberon_error(ctx, "oberon_generate_return: TODO return expr");
+	}
+	else
+	{
+		fprintf(m -> fp, "  return\n");
+	}
+}
+
+static void
+push_int(FILE * fp, long i)
+{
+	if(i == -1)
+	{
+		fprintf(fp, "iconst_m1\n");
+	}
+	else if(i >= 0 && i <= 5)
+	{
+		fprintf(fp, "iconst_%li\n", i);
+	}
+	else if(i >= -128 && i <= 127)
+	{
+		fprintf(fp, "bipush %li\n", i);
+	}
+	else if(i >= -32768 && i <= 32767)
+	{
+		fprintf(fp, "sipush %li\n", i);		
+	}
+	else if(i >= -2147483648 && i <= 2147483647)
+	{
+		fprintf(fp, "ldc %li\n", i);
+	}
+	else
+	{
+		fprintf(fp, "ldc2 %li\n", i);
+	}
+}
+
+static void
+push_float(FILE * fp, double f, int size)
+{
+	if(size <= 4)
+	{
+		if(f == 0.0)
+		{
+			fprintf(fp, "fconst_0\n");
+		}
+		if(f == 1.0)
+		{
+			fprintf(fp, "fconst_1\n");
+		}
+		if(f == 2.0)
+		{
+			fprintf(fp, "fconst_2\n");
+		}
+		else
+		{
+			fprintf(fp, "ldc %lf\n", f);
+		}
+	}
+	else
+	{
+		if(f == 0.0)
+		{
+			fprintf(fp, "dconst_0\n");
+		}
+		if(f == 1.0)
+		{
+			fprintf(fp, "dconst_1\n");
+		}
+		else
+		{
+			fprintf(fp, "ldc2 %lf\n", f);
+		}
+	}
+}
+
+static void push_expr(oberon_context_t * ctx, FILE * fp, oberon_expr_t * expr);
+
+static void
+push_var(oberon_context_t * ctx, FILE * fp, oberon_object_t * var)
+{
+	if(var -> local)
+	{
+		int reg = var -> gen_var -> reg;
+		char prefix = get_prefix(ctx, var -> type);
+		fprintf(fp, "%cload %i\n", prefix, reg);
+	}
+	else
+	{
+		char * fullname = get_field_full_name(ctx, var);
+		char * desc = get_descriptor(ctx, var -> type);
+		fprintf(fp, "getstatic %s %s\n", fullname, desc);
+	}
+}
+
+static void
+push_item(oberon_context_t * ctx, FILE * fp, oberon_item_t * item)
+{
+	switch(item -> mode)
+	{
+		case MODE_VAR:
+			push_var(ctx, fp, item -> var);
+			break;
+		case MODE_INTEGER:
+			push_int(fp, item -> integer);
+			break;
+		case MODE_BOOLEAN:
+			push_int(fp, item -> boolean);
+			break;
+		case MODE_CALL:
+			oberon_error(ctx, "push_item: TODO call");
+			break;
+		case MODE_INDEX:
+			oberon_error(ctx, "push_item: TODO index");
+			break;
+		case MODE_FIELD:
+			oberon_error(ctx, "push_item: TODO field");
+			break;
+		case MODE_DEREF:
+			oberon_error(ctx, "push_item: TODO deref");
+			break;
+		case MODE_NIL:
+			fprintf(fp, "aconst_null\n");
+			break;
+		case MODE_NEW:
+			oberon_error(ctx, "push_item: TODO new");
+			break;
+		case MODE_REAL:
+			push_float(fp, item -> real, item -> result -> size);
+			break;
+		default:
+			oberon_error(ctx, "push_item: unk mode %i", item -> mode);
+			break;
+	}
+}
+
+static void
+push_operator(oberon_context_t * ctx, FILE * fp, oberon_oper_t * oper)
+{
+	char prefix = get_prefix(ctx, oper -> result);
+	switch(oper -> op)
+	{
+		case OP_UNARY_MINUS:
+			push_expr(ctx, fp, oper -> left);
+			fprintf(fp, "%cneg\n", prefix);
+			break;
+		case OP_BITWISE_NOT:
+			push_expr(ctx, fp, oper -> left);
+			push_int(fp, -1);
+			fprintf(fp, "%cxor\n", prefix);
+			break;
+
+		case OP_ADD:
+			push_expr(ctx, fp, oper -> left);
+			push_expr(ctx, fp, oper -> right);
+			fprintf(fp, "%cadd\n", prefix);
+			break;
+		case OP_SUB:
+			push_expr(ctx, fp, oper -> left);
+			push_expr(ctx, fp, oper -> right);
+			fprintf(fp, "%csub\n", prefix);
+			break;
+		case OP_MUL:
+			push_expr(ctx, fp, oper -> left);
+			push_expr(ctx, fp, oper -> right);
+			fprintf(fp, "%cmul\n", prefix);
+			break;
+		case OP_DIV:
+			push_expr(ctx, fp, oper -> left);
+			push_expr(ctx, fp, oper -> right);
+			fprintf(fp, "%cdiv\n", prefix);
+			break;
+		case OP_MOD:
+			push_expr(ctx, fp, oper -> left);
+			push_expr(ctx, fp, oper -> right);
+			fprintf(fp, "%crem\n", prefix);
+			break;
+		case OP_BITWISE_AND:
+			push_expr(ctx, fp, oper -> left);
+			push_expr(ctx, fp, oper -> right);
+			fprintf(fp, "%cand\n", prefix);
+			break;
+		case OP_BITWISE_XOR:
+			push_expr(ctx, fp, oper -> left);
+			push_expr(ctx, fp, oper -> right);
+			fprintf(fp, "%cxor\n", prefix);
+			break;
+		case OP_BITWISE_OR:
+			push_expr(ctx, fp, oper -> left);
+			push_expr(ctx, fp, oper -> right);
+			fprintf(fp, "%cor\n", prefix);
+			break;
+
+		case OP_EQ:
+		case OP_NEQ:
+		case OP_LSS:
+		case OP_LEQ:
+		case OP_GRT:
+		case OP_GEQ:
+		case OP_LOGIC_NOT:
+		case OP_ABS:
+			oberon_error(ctx, "push_oper: TODO op %i", oper -> op);
+			break;
+		default:
+			oberon_error(ctx, "push_oper: unk op %i", oper -> op);
+			break;
+	}
+}
+
+static void
+push_expr(oberon_context_t * ctx, FILE * fp, oberon_expr_t * expr)
+{
+	if(expr -> is_item)
+	{
+		push_item(ctx, fp, (oberon_item_t *) expr);
+	}
+	else
+	{
+		push_operator(ctx, fp, (oberon_oper_t *) expr);
+	}
+}
+
+static void
+store_expr(oberon_context_t * ctx, FILE * fp, oberon_expr_t * expr)
+{
+	assert(expr -> is_item);
+	oberon_item_t * item = (oberon_item_t *) expr;
+
+	char prefix;
+	switch(item -> mode)
+	{
+		case MODE_VAR:
+			if(item -> var -> local)
+			{
+				int reg = item -> var -> gen_var -> reg;
+				prefix = get_prefix(ctx, item -> result);
+				fprintf(fp, "%cstore %i\n", prefix, reg);
+			}
+			else
+			{
+				char * fullname = get_field_full_name(ctx, item -> var);
+				char * desc = get_descriptor(ctx, item -> result);
+				fprintf(fp, "putstatic %s %s\n", fullname, desc);
+			}
+			break;
+		default:
+			oberon_error(ctx, "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;
+	m = ctx -> mod -> gen_mod;
+
+	push_expr(ctx, m -> fp, src);
+	store_expr(ctx, m -> fp, dst);
+}
+
+void
+oberon_generate_code(oberon_context_t * ctx)
+{
+	printf("generate code\n");
+}
+
+void
+oberon_generator_dump(oberon_context_t * ctx, char * path)
+{
+	printf("jit: dump code\n");
+}
+
+void *
+oberon_generator_get_procedure(oberon_context_t * ctx, const char * name)
+{
+	printf("jit: get pointer to procedure %s\n", name);
+	return NULL;
+}
+
+void *
+oberon_generator_get_var(oberon_context_t * ctx, const char * name)
+{
+	printf("jit: get pointer to var %s\n", name);
+	return NULL;
+}
diff --git a/src/backends/jvm/generator-jvm.h b/src/backends/jvm/generator-jvm.h
new file mode 100644
index 0000000..9357519
--- /dev/null
+++ b/src/backends/jvm/generator-jvm.h
@@ -0,0 +1,41 @@
+#define MAX_REGISTERS 256
+
+struct gen_register_file {
+	struct
+	{
+		bool used;
+	} reg[MAX_REGISTERS];
+	int max_used;
+};
+
+struct gen_proc_t
+{
+
+};
+
+struct gen_type_t
+{
+	int rec_id;
+	FILE * fp;
+};
+
+struct gen_var_t
+{
+	int reg;
+};
+
+struct gen_block_t
+{
+
+};
+
+struct gen_context_t
+{
+	gen_module_t * m;
+};
+
+struct gen_module_t
+{
+	int rec_id;
+	FILE * fp;
+};
diff --git a/src/generator.h b/src/generator.h
index 08df5c8..885b9fa 100644
--- a/src/generator.h
+++ b/src/generator.h
@@ -7,6 +7,7 @@ void oberon_generator_init_type(oberon_context_t * ctx, oberon_type_t * type);
 void oberon_generator_init_record(oberon_context_t * ctx, oberon_type_t * type);
 void oberon_generator_init_var(oberon_context_t * ctx, oberon_object_t * var);
 void oberon_generator_init_proc(oberon_context_t * ctx, oberon_object_t * proc);
+void oberon_generator_init_module(oberon_context_t * ctx, oberon_module_t * mod);
 void oberon_generator_destroy_context(oberon_context_t * ctx);
 
 /*
diff --git a/src/oberon-internals.h b/src/oberon-internals.h
index e265a79..a6174c3 100644
--- a/src/oberon-internals.h
+++ b/src/oberon-internals.h
@@ -1,6 +1,7 @@
 #ifndef OBERON_INTERNALS_H
 #define OBERON_INTERNALS_H
 
+typedef struct gen_module_t gen_module_t;
 typedef struct gen_proc_t gen_proc_t;
 typedef struct gen_type_t gen_type_t;
 typedef struct gen_var_t gen_var_t;
@@ -107,6 +108,8 @@ struct oberon_module_t
 	oberon_scope_t * decl;
 
 	oberon_module_t * next;
+
+	gen_module_t * gen_mod;
 };
 
 typedef const char * (*ModuleImportCallback)(const char * name);
@@ -168,7 +171,7 @@ enum
 	OP_MOD,
 	OP_BITWISE_AND,
 	OP_BITWISE_XOR,
-	OP_BITWISE_OP,
+	OP_BITWISE_OR,
 	OP_LOGIC_AND,
 	OP_LOGIC_OR,
 
diff --git a/src/oberon.c b/src/oberon.c
index d636fba..382f4f1 100644
--- a/src/oberon.c
+++ b/src/oberon.c
@@ -2083,6 +2083,7 @@ oberon_type(oberon_context_t * ctx, oberon_type_t ** type)
 		oberon_type_t * rec;
 		rec = *type;
 		rec -> class = OBERON_TYPE_RECORD;
+		rec -> module = ctx -> mod;
 
 		oberon_scope_t * record_scope;
 		record_scope = oberon_open_scope(ctx);
@@ -2672,6 +2673,8 @@ oberon_parse_module(oberon_context_t * ctx)
 	oberon_assert_token(ctx, SEMICOLON);
 	ctx -> mod -> name = name1;
 
+	oberon_generator_init_module(ctx, ctx -> mod);
+
 	if(ctx -> token == IMPORT)
 	{
 		oberon_import_list(ctx);
diff --git a/src/test.c b/src/test.c
index 1c3c8e3..53be586 100644
--- a/src/test.c
+++ b/src/test.c
@@ -7,40 +7,31 @@
 static char source_test[] =
 	"(* Main module *)"
 	"MODULE Test;"
-	"IMPORT Out;"
-	"TYPE Ar = ARRAY OF ARRAY OF INTEGER;"
-	"VAR a : POINTER TO Ar;"
+	"VAR"
+	"  x : INTEGER;"
+	"  z : BOOLEAN;"
 	""
-	"PROCEDURE Ax(VAR x : POINTER TO Ar);"
-	"BEGIN"
-	"  x[0, 0] := 777;"
-	"END Ax;"
+	"PROCEDURE Tier(a, b :INTEGER);"
+	"END Tier;"
 	""
 	"BEGIN;"
-	"  NEW(a, 2, 2);"
-	"  a[0, 0] := 666;"
-	"  Out.Open;"
-	"  Out.Int(a[0, 0], 0);"
-	"  Out.Ln;"
-	""
-	"  Ax(a);"
-//	"  Out.Int(a[0, 0], 0);"
-//	"  Out.Ln;"
+	" x := x + 1;"
+	" z := TRUE;"
 	"END Test."
 ;
 
 static char source_out[] =
 	"MODULE Out;"
-	"(* Interface to outer program ;) *)"
-	"VAR"
-	"  Open-     : PROCEDURE;"
+//	"(* Interface to outer program ;) *)"
+//	"VAR"
+//	"  Open-     : PROCEDURE;"
 //	"  Char-     : PROCEDURE(ch : CHAR);"
 //	"  String-   : PROCEDURE(str : ARRAY OF CHAR)"
 //	"  Int-      : PROCEDURE(i, n : LONGINT);"
-	"  Int-      : PROCEDURE(i, n : INTEGER);"
-	"  Real-     : PROCEDURE(x : REAL; n : INTEGER);"
+//	"  Int-      : PROCEDURE(i, n : INTEGER);"
+//	"  Real-     : PROCEDURE(x : REAL; n : INTEGER);"
 //	"  LongReal- : PROCEDURE(x : LONGREAL; n : INTEGER);"
-	"  Ln-       : PROCEDURE;"
+//	"  Ln-       : PROCEDURE;"
 	"END Out."
 ;
 
@@ -131,11 +122,11 @@ main(int argc, char ** argv)
 
 	oberon_generate_code(ctx);
 
-	init_system_modules();
+//	init_system_modules();
 
-	oberon_generator_dump(ctx, "dump.txt");
+//	oberon_generator_dump(ctx, "dump.txt");
 
-	start_module();
+//	start_module();
 
 	oberon_destroy_context(ctx);
 	return 0;
diff --git a/tst.java b/tst.java
new file mode 100644
index 0000000..2dae5b2
--- /dev/null
+++ b/tst.java
@@ -0,0 +1,4 @@
+public abstract class tst
+{
+	public abstract void invoke();
+}