Pārlūkot izejas kodu

started OO impl

Nicolas Cannasse 10 gadi atpakaļ
vecāks
revīzija
e14e799f59
1 mainītis faili ar 347 papildinājumiem un 69 dzēšanām
  1. 347 69
      genhl.ml

+ 347 - 69
genhl.ml

@@ -23,6 +23,13 @@ open Ast
 open Type
 open Common
 
+type reg = int
+type global = int
+type sindex = int
+type findex = int
+type iindex = int
+type pindex = int
+
 type ttype =
 	| TVoid
 	| TUI8
@@ -32,12 +39,18 @@ type ttype =
 	| TBool
 	| TAny
 	| TFun of ttype list * ttype
+	| TObj of class_proto
+
+and class_proto = {
+	pname : string;
+	pid : int;
+	mutable psuper : class_proto option;
+	mutable pproto : (string * sindex * ttype * global) array;
+	mutable pfields : (string * sindex * ttype) array;
+	mutable pindex : (string, int) PMap.t;
+}
 
-type reg = int
-type global = int
-type sindex = int
-type findex = int
-type iindex = int
+type unused = int
 
 type opcode =
 	| OMov of reg * reg
@@ -73,7 +86,12 @@ type opcode =
 	| OJNeq of reg * reg * int
 	| OJAlways of int
 	| OToAny of reg * reg
-	| OLabel
+	| OLabel of unused
+	| ONew of reg
+	| OField of reg * reg * pindex
+	| OSetField of reg * pindex * reg
+	| OGetThis of reg * pindex
+	| OSetThis of pindex * reg
 
 type fundecl = {
 	index : global;
@@ -87,6 +105,7 @@ type code = {
 	strings : string array;
 	ints : int32 array;
 	floats : float array;
+	(* types : ttype array // only in bytecode, rebuilt on save() *)
 	globals : ttype array;
 	natives : (sindex * global) array;
 	functions : fundecl array;
@@ -112,12 +131,19 @@ type context = {
 	cints : (int32, int32) lookup;
 	cnatives : (string, (sindex * global)) lookup;
 	cfunctions : fundecl DynArray.t;
+	overrides : (string * path, bool) Hashtbl.t;
+	mutable cached_types : (path, ttype) PMap.t;
 	mutable m : method_context;
 }
 
 (* --- *)
 
-let rec tstr t =
+type global_access =
+	| GNone
+	| GStatic of int
+	| GInstance of texpr * int
+
+let rec tstr ?(detailed=false) t =
 	match t with
 	| TVoid -> "void"
 	| TUI8 -> "ui8"
@@ -126,7 +152,12 @@ let rec tstr t =
 	| TF64 -> "f64"
 	| TBool -> "bool"
 	| TAny -> "any"
-	| TFun (args,ret) -> "(" ^ String.concat "," (List.map tstr args) ^ "):" ^ tstr ret
+	| TFun (args,ret) -> "(" ^ String.concat "," (List.map (tstr ~detailed) args) ^ "):" ^ tstr ~detailed ret
+	| TObj o when not detailed -> "#" ^ o.pname
+	| TObj o ->
+		let fields = "{" ^ String.concat "," (List.map (fun(s,_,t) -> s ^ " : " ^ tstr ~detailed:false t) (Array.to_list o.pfields)) ^ "}" in
+		let proto = "{"  ^ String.concat "," (List.map (fun(s,_,t,g) -> s ^ "@" ^  string_of_int g ^ " : " ^ tstr ~detailed:false t) (Array.to_list o.pproto)) ^ "}" in
+		"#" ^ o.pname ^ "[" ^ (match o.psuper with None -> "" | Some p -> ">" ^ p.pname ^ " ") ^ "fields=" ^ fields ^ " proto=" ^ proto ^ "]"
 
 let iteri f l =
 	let p = ref (-1) in
@@ -156,18 +187,38 @@ let method_context() =
 let field_name c f =
 	s_type_path c.cl_path ^ ":" ^ f.cf_name
 
-let rec to_type t =
+let global_type ctx g =
+	DynArray.get ctx.cglobals.arr g
+
+let is_overriden ctx c f =
+	Hashtbl.mem ctx.overrides (f.cf_name,c.cl_path)
+
+let alloc_float ctx f =
+	lookup ctx.cfloats f (fun() -> f)
+
+let alloc_i32 ctx i =
+	lookup ctx.cints i (fun() -> i)
+
+let alloc_string ctx s =
+	lookup ctx.cstrings s (fun() -> s)
+
+let member_fun c t =
+	match follow t with
+	| Type.TFun (args, ret) -> Type.TFun (("this",false,TInst(c,[])) :: args, ret)
+	| _ -> assert false
+
+let rec to_type ctx t =
 	match t with
 	| TMono r ->
 		(match !r with
 		| None -> TAny
-		| Some t -> to_type t)
+		| Some t -> to_type ctx t)
 	| TType (t,tl) ->
-		to_type (apply_params t.t_params tl t.t_type)
+		to_type ctx (apply_params t.t_params tl t.t_type)
 	| TLazy f ->
-		to_type (!f())
+		to_type ctx (!f())
 	| Type.TFun (args, ret) ->
-		TFun (List.map (fun (_,_,t) -> to_type t) args, to_type ret)
+		TFun (List.map (fun (_,_,t) -> to_type ctx t) args, to_type ctx ret)
 	| TAnon _ ->
 		TAny
 	| TDynamic _ ->
@@ -175,7 +226,7 @@ let rec to_type t =
 	| TEnum (e,_) ->
 		assert false
 	| TInst (c,_) ->
-		assert false
+		class_type ctx c
 	| TAbstract (a,pl) ->
 		if Meta.has Meta.CoreType a.a_meta then
 			(match a.a_path with
@@ -184,22 +235,55 @@ let rec to_type t =
 			| [], "Float" -> TF64
 			| _ -> failwith ("Unknown core type " ^ s_type_path a.a_path))
 		else
-			to_type (Abstract.get_underlying_type a pl)
+			to_type ctx (Abstract.get_underlying_type a pl)
 
-let alloc_global ctx name t =
-	lookup ctx.cglobals name (fun() -> to_type t)
+and class_type ctx c =
+	try
+		PMap.find c.cl_path ctx.cached_types
+	with Not_found ->
+		let pname = s_type_path c.cl_path in
+		let p = {
+			pname = pname;
+			pid = alloc_string ctx pname;
+			psuper = None;
+			pproto = [||];
+			pfields = [||];
+			pindex = PMap.empty;
+		} in
+		let t = TObj p in
+		ctx.cached_types <- PMap.add c.cl_path t ctx.cached_types;
+		(match c.cl_super with
+		| None -> ()
+		| Some (c,_) ->
+			(match class_type ctx c with
+			| TObj p -> p.psuper <- Some p
+			| _ -> assert false));
+		let fa = DynArray.create() and pa = DynArray.create() in
+		List.iter (fun f ->
+			if is_extern_field f then () else
+			match f.cf_kind with
+			| Var _ | Method MethDynamic ->
+				let t = to_type ctx f.cf_type in
+				p.pindex <- PMap.add f.cf_name (DynArray.length fa) p.pindex;
+				DynArray.add fa (f.cf_name, alloc_string ctx f.cf_name, t);
+			| Method _ when is_overriden ctx c f ->
+				let g = alloc_field ctx c f false in
+				(* can't use global_type here *)
+				DynArray.add pa (f.cf_name, alloc_string ctx f.cf_name, to_type ctx (member_fun c f.cf_type), g)
+			| _ -> ()
+		) c.cl_ordered_fields;
+		p.pfields <- DynArray.to_array fa;
+		p.pproto <- DynArray.to_array pa;
+		t
+
+and alloc_field ctx c f isStatic =
+	alloc_global ctx (field_name c f) (if isStatic then f.cf_type else member_fun c f.cf_type)
+
+and alloc_global ctx name t =
+	lookup ctx.cglobals name (fun() -> to_type ctx t)
 
 let alloc_reg ctx v =
-	lookup ctx.m.mregs v.v_id (fun() -> to_type v.v_type)
-
-let alloc_float ctx f =
-	lookup ctx.cfloats f (fun() -> f)
-
-let alloc_i32 ctx i =
-	lookup ctx.cints i (fun() -> i)
-
-let alloc_string ctx s =
-	lookup ctx.cstrings s (fun() -> s)
+	lookup ctx.m.mregs v.v_id (fun() -> to_type ctx v.v_type)
 
 let alloc_tmp ctx t =
 	let rid = DynArray.length ctx.m.mregs.arr in
@@ -217,6 +301,21 @@ let jump ctx f =
 let rtype ctx r =
 	DynArray.get ctx.m.mregs.arr r
 
+let rec resolve_field ctx p fname =
+	(* each class contains only its own fields, so let's get absolute index *)
+	let rec loop id sup =
+		match sup with
+		| None -> id
+		| Some p -> loop (id + Array.length p.pfields) p.psuper
+	in
+	try
+		let fid = PMap.find fname p.pindex in
+		loop fid p.psuper
+	with Not_found ->
+		match p.psuper with
+		| None -> assert false
+		| Some p -> resolve_field ctx p fname
+
 let rec eval_to ctx e (t:ttype) =
 	let r = eval_expr ctx e in
 	cast_to ctx r t
@@ -232,18 +331,20 @@ and cast_to ctx (r:reg) (t:ttype) =
 	| _ ->
 		failwith ("Don't know how to cast " ^ tstr rt ^ " to " ^ tstr t)
 
-and get_global ctx e =
+and get_global_fun ctx e =
 	match e.eexpr with
-	| TField (f, a) ->
-		(match a with
-		| FStatic (c,f) ->
-			Some (alloc_global ctx (field_name c f) f.cf_type)
+	| TField (ethis, a) ->
+		(match a, follow ethis.etype with
+		| FStatic (c,({ cf_kind = Method _ } as f)), _ ->
+			GStatic (alloc_field ctx c f true)
+		| FInstance (cdef,_,({ cf_kind = Method _ } as f)), TInst (c,_) when not (is_overriden ctx c f) ->
+			GInstance (ethis, alloc_field ctx cdef f false)
 		| _ ->
-			None)
+			GNone)
 	| TParenthesis e ->
-		get_global ctx e
+		get_global_fun ctx e
 	| _ ->
-		None
+		GNone
 
 and jump_expr ctx e jcond =
 	match e.eexpr with
@@ -270,6 +371,9 @@ and jump_expr ctx e jcond =
 		let r = eval_expr ctx e in
 		jump ctx (fun i -> if jcond then OJTrue (r,i) else OJFalse (r,i))
 
+and eval_args ctx el t =
+	List.map2 (fun e t -> eval_to ctx e t) el (match t with TFun (args,_) -> args | _ -> assert false)
+
 and eval_expr ctx e =
 	match e.eexpr with
 	| TConst c ->
@@ -286,6 +390,8 @@ and eval_expr ctx e =
 			let r = alloc_tmp ctx TBool in
 			op ctx (OBool (r,b));
 			r
+		| TThis ->
+			0 (* first reg *)
 		| _ ->
 			failwith ("TODO " ^ s_const c))
 	| TVar (v,e) ->
@@ -318,10 +424,10 @@ and eval_expr ctx e =
 		in
 		loop el
 	| TCall (ec,el) ->
-		(match get_global ctx ec with
-		| Some g when List.length el < 5 ->
-			let el = List.map2 (fun e t -> eval_to ctx e t) el (match to_type ec.etype with TFun (args,_) -> args | _ -> assert false) in
-			let ret = alloc_tmp ctx (to_type e.etype) in
+		(match get_global_fun ctx ec with
+		| GStatic g when List.length el < 5 ->
+			let el = eval_args ctx el (to_type ctx ec.etype) in
+			let ret = alloc_tmp ctx (to_type ctx e.etype) in
 			(match el with
 			| [] -> op ctx (OCall0 (ret, g))
 			| [a] -> op ctx (OCall1 (ret, g, a))
@@ -330,25 +436,66 @@ and eval_expr ctx e =
 			| [a;b;c;d] -> op ctx (OCall4 (ret, g, a, b, c, d))
 			| _ -> assert false);
 			ret
+		| GInstance (ethis, g) when List.length el < 4 ->
+			let el = eval_expr ctx ethis :: eval_args ctx el (to_type ctx ec.etype) in
+			let ret = alloc_tmp ctx (to_type ctx e.etype) in
+			(match el with
+			| [a] -> op ctx (OCall1 (ret, g, a))
+			| [a;b] -> op ctx (OCall2 (ret, g, a, b))
+			| [a;b;c] -> op ctx (OCall3 (ret, g, a, b, c))
+			| [a;b;c;d] -> op ctx (OCall4 (ret, g, a, b, c, d))
+			| _ -> assert false);
+			ret
 		| _ ->
 			let r = eval_expr ctx ec in
-			let el = List.map2 (fun e t -> eval_to ctx e t) el (match rtype ctx r with TFun (args,_) -> args | _ -> assert false) in
-			let ret = alloc_tmp ctx (to_type e.etype) in
+			let el = eval_args ctx el (rtype ctx r) in
+			let ret = alloc_tmp ctx (to_type ctx e.etype) in
 			op ctx (OCallN (ret, r, el));
 			ret)
-	| TField (f,a) ->
+	| TField (eobj,a) ->
 		(match a with
 		| FStatic (c,f) ->
-			let g = alloc_global ctx (field_name c f) f.cf_type in
-			let r = alloc_tmp ctx (to_type f.cf_type) in
+			let g = alloc_field ctx c f true in
+			let r = alloc_tmp ctx (to_type ctx f.cf_type) in
 			op ctx (OGetGlobal (r,g));
 			r
+		| FInstance (c,_,f) ->
+			(match class_type ctx c with
+			| TObj p ->
+				let fid = resolve_field ctx p f.cf_name in
+				let r = alloc_tmp ctx (to_type ctx e.etype) in
+				let robj = eval_expr ctx eobj in
+				op ctx (match eobj.eexpr with TConst TThis -> OGetThis (r,fid) | _ -> OField (r,robj,fid));
+				r
+			| _ -> assert false)
 		| _ -> assert false)
 	| TObjectDecl o ->
 		(* TODO *)
 		alloc_tmp ctx TVoid
+	| TNew (c,pl,el) ->
+		let r = alloc_tmp ctx (class_type ctx c) in
+		op ctx (ONew r);
+		(match c.cl_constructor with
+		| None -> ()
+		| Some { cf_expr = None } -> assert false
+		| Some ({ cf_expr = Some { eexpr = TFunction({ tf_expr = { eexpr = TBlock([]) } }) } }) when el = [] -> ()
+		| Some ({ cf_expr = Some cexpr } as constr) ->
+			let rl = eval_args ctx el (to_type ctx cexpr.etype) in
+			let ret = alloc_tmp ctx TVoid in
+			let g = alloc_field ctx c constr false in
+			op ctx (match rl with
+			| [] -> OCall1 (ret,g,r)
+			| [a] -> OCall2 (ret,g,r,a)
+			| [a;b] -> OCall3 (ret,g,r,a,b)
+			| [a;b;c] -> OCall4 (ret,g,r,a,b,c)
+			| _ ->
+				let rf = alloc_tmp ctx (global_type ctx g) in
+				op ctx (OGetGlobal (rf,g));
+				OCallN (ret,rf,r :: rl));
+		);
+		r
 	| TIf (cond,eif,eelse) ->
-		let out = alloc_tmp ctx (to_type e.etype) in
+		let out = alloc_tmp ctx (to_type ctx e.etype) in
 		let j = jump_expr ctx cond false in
 		op ctx (OMov (out,eval_expr ctx eif));
 		(match eelse with
@@ -368,7 +515,7 @@ and eval_expr ctx e =
 			op ctx (OGte (r,b,a));
 			r
 		| OpAdd ->
-			let t = to_type e.etype in
+			let t = to_type ctx e.etype in
 			let r = alloc_tmp ctx t in
 			(match t with
 			| TI32 | TF32 | TF64 | TUI8 ->
@@ -379,7 +526,7 @@ and eval_expr ctx e =
 			| _ ->
 				assert false)
 		| OpSub | OpMult ->
-			let t = to_type e.etype in
+			let t = to_type ctx e.etype in
 			let r = alloc_tmp ctx t in
 			(match t with
 			| TI32 | TF32 | TF64 | TUI8 ->
@@ -392,14 +539,32 @@ and eval_expr ctx e =
 				r
 			| _ ->
 				assert false)
+		| OpAssign ->
+			let value = eval_to ctx e2 (to_type ctx e1.etype) in
+			(match e1.eexpr with
+			| TField (ec,FStatic (c,f)) ->
+				op ctx (OSetGlobal (alloc_field ctx c f true,value))
+			| TField (ethis,FInstance (_,_,f)) ->
+				let rthis = eval_expr ctx ethis in
+				(match rtype ctx rthis with
+				| TObj p ->
+					let fid = resolve_field ctx p f.cf_name in
+					op ctx (match ethis.eexpr with TConst TThis -> OSetThis (fid,value) | _ -> OSetField (rthis, fid, value))
+				| _ -> assert false)
+			| TLocal v -> op ctx (OMov (alloc_reg ctx v, value))
+			| _ -> assert false);
+			value
 		| _ ->
 			failwith ("TODO " ^ s_expr (s_type (print_context())) e))
 	| _ ->
 		failwith ("TODO " ^ s_expr (s_type (print_context())) e)
 
-let make_fun ctx f idx =
+let make_fun ctx f idx cthis =
 	let old = ctx.m in
 	ctx.m <- method_context();
+	(match cthis with
+	| None -> ()
+	| Some c -> ignore(alloc_tmp ctx (to_type ctx (TInst (c,[])))));
 	List.iter (fun (v,o) ->
 		let r = alloc_reg ctx v in
 		match o with
@@ -414,7 +579,7 @@ let make_fun ctx f idx =
 			| TString s -> assert false (* TODO *)
 	) f.tf_args;
 	ignore(eval_expr ctx f.tf_expr);
-	if to_type f.tf_type = TVoid then op ctx (ORet (alloc_tmp ctx TVoid));
+	if to_type ctx f.tf_type = TVoid then op ctx (ORet (alloc_tmp ctx TVoid));
 	let f = {
 		index = idx;
 		regs = DynArray.to_array ctx.m.mregs.arr;
@@ -428,7 +593,14 @@ let generate_static ctx c f =
 	| Var v -> assert false
 	| Method m ->
 		let gid = alloc_global ctx (field_name c f) f.cf_type in
-		make_fun ctx (match f.cf_expr with Some { eexpr = TFunction f } -> f | _ -> assert false) gid
+		make_fun ctx (match f.cf_expr with Some { eexpr = TFunction f } -> f | _ -> assert false) gid None
+
+let generate_member ctx c f =
+	match f.cf_kind with
+	| Var _ -> ()
+	| Method m ->
+		let gid = alloc_global ctx (field_name c f) (member_fun c f.cf_type) in
+		make_fun ctx (match f.cf_expr with Some { eexpr = TFunction f } -> f | _ -> assert false) gid (Some c)
 
 let generate_type ctx t =
 	match t with
@@ -442,7 +614,11 @@ let generate_type ctx t =
 			) f.cf_meta
 		) c.cl_ordered_statics
 	| TClassDecl c ->
-		List.iter (generate_static ctx c) c.cl_ordered_statics
+		List.iter (generate_static ctx c) c.cl_ordered_statics;
+		(match c.cl_constructor with
+		| None -> ()
+		| Some f -> generate_member ctx c f);
+		List.iter (generate_member ctx c) c.cl_ordered_fields;
 	| TTypeDecl _ ->
 		()
 	| TAbstractDecl a when a.a_impl = None ->
@@ -460,8 +636,15 @@ let check code =
 		in
 		let targs, tret = (match code.globals.(f.index) with TFun (args,ret) -> args, ret | _ -> assert false) in
 		let rtype i = f.regs.(i) in
+		let rec same_type t1 t2 =
+			if t1 == t2 then true else
+			match t1, t2 with
+			| TFun (args1,ret1), TFun (args2,ret2) -> List.for_all2 same_type args1 args2 && same_type ret1 ret2
+			| TObj p1, TObj p2 -> p1.pname = p2.pname
+			| _ -> false
+		in
 		let reg r t =
-			if rtype r <> t then error ("Register " ^ string_of_int r ^ " should be " ^ tstr t ^ " and not " ^ tstr (rtype r))
+			if not (same_type (rtype r) t) then error ("Register " ^ string_of_int r ^ " should be " ^ tstr t ^ " and not " ^ tstr (rtype r))
 		in
 		let numeric r =
 			match rtype r with
@@ -483,7 +666,35 @@ let check code =
 		in
 		let can_jump delta =
 			if !pos + 1 + delta < 0 || !pos + 1 + delta >= Array.length f.code then failwith "Jump outside function bounds";
-			if delta < 0 && Array.get f.code (!pos + 1 + delta) <> OLabel then failwith "Jump back without Label";
+			if delta < 0 && Array.get f.code (!pos + 1 + delta) <> OLabel 0 then failwith "Jump back without Label";
+		in
+		let is_obj r =
+			match rtype r with
+			| TObj _ -> ()
+			| _ -> error ("Register " ^ string_of_int r ^ " should be object")
+		in
+		let tfield o id =
+			match rtype o with
+			| TObj p ->
+				let rec loop pl p =
+					let pl = p :: pl in
+					match p.psuper with
+					| None ->
+						let rec fetch id = function
+							| [] -> assert false
+							| p :: pl ->
+								let d = id - Array.length p.pfields in
+								if d < 0 then p.pfields.(id) else fetch d pl
+						in
+						fetch id pl
+					| Some p ->
+						loop pl p
+				in
+				let _,_,t = loop [] p in
+				t
+			| _ ->
+				is_obj o;
+				TVoid
 		in
 		iteri reg targs;
 		Array.iteri (fun i op ->
@@ -546,8 +757,14 @@ let check code =
 			| OToAny (r,a) ->
 				ignore(rtype a);
 				reg r TAny
-			| OLabel ->
+			| OLabel _ ->
 				()
+			| ONew r ->
+				is_obj r
+			| OField (r,o,fid) | OSetField (o,fid,r) ->
+				reg r (tfield o fid)
+			| OGetThis (r,fid) | OSetThis(fid,r) ->
+				reg r (tfield 0 fid)
 		) f.code
 		(* TODO : check that all path correctly initialize NULL values and reach a return *)
 	in
@@ -563,12 +780,18 @@ type value =
 	| VBool of bool
 	| VAny of value * ttype
 	| VNativeFun of (value list -> value)
+	| VObj of vobject
+
+and vobject = {
+	vproto : class_proto;
+	vfields : value array;
+}
 
 exception Return of value
 
 let rec default t =
 	match t with
-	| TVoid | TFun _ | TAny -> VNull
+	| TVoid | TFun _ | TAny | TObj _ -> VNull
 	| TI32 | TUI8 -> VInt Int32.zero
 	| TF32 | TF64 -> VFloat 0.
 	| TBool -> VBool false
@@ -582,11 +805,22 @@ let rec str v =
 	| VBool b -> if b then "true" else "false"
 	| VAny (v,t) -> "any(" ^ str v ^ ":" ^ tstr t ^ ")"
 	| VNativeFun _ -> "native"
+	| VObj o -> o.vproto.pname
+
+exception Runtime_error of string
 
 let interp code =
 
 	let globals = Array.map default code.globals in
 
+	let new_obj t =
+		match t with
+		| TObj p -> { vproto = p; vfields = Array.map (fun(_,_,t) -> default t) p.pfields }
+		| _ -> assert false
+	in
+
+	let error msg = raise (Runtime_error msg) in
+
 	let rec call f args =
 		let regs = Array.map default f.regs in
 		iteri (fun i v -> regs.(i) <- v) args;
@@ -629,6 +863,7 @@ let interp code =
 			match v with
 			| VFun f -> call f args
 			| VNativeFun f -> f args
+			| VNull -> error "Uninitialized method"
 			| _ -> assert false
 		in
 		let rec loop() =
@@ -668,7 +903,21 @@ let interp code =
 			| OJNeq (a,b,i) -> if get a <> get b then pos := !pos + i
 			| OJAlways i -> pos := !pos + i
 			| OToAny (r,a) -> set r (VAny (get a, f.regs.(a)))
-			| OLabel -> ()
+			| OLabel _ -> ()
+			| ONew r -> set r (VObj (new_obj (rtype r)))
+			| OField (r,o,fid) ->
+				set r (match get o with VObj v -> v.vfields.(fid) | VNull -> error "Null access" | _ -> assert false)
+			| OSetField (o,fid,r) ->
+				(match get o with
+				| VObj v -> v.vfields.(fid) <- get r
+				| VNull -> error "Null access"
+				| _ -> assert false)
+			| OGetThis (r, fid) ->
+				set r (match get 0 with VObj v -> v.vfields.(fid) | _ -> assert false)
+			| OSetThis (fid, r) ->
+				(match get 0 with
+				| VObj v -> v.vfields.(fid) <- get r
+				| _ -> assert false)
 			);
 			loop()
 		in
@@ -680,7 +929,7 @@ let interp code =
 	let load_native name =
 		match name with
 		| "std@log" -> VNativeFun (fun args -> print_endline (str (List.hd args)); VNull);
-		| _ -> failwith ("Unresolved native " ^ name)
+		| _ -> error ("Unresolved native " ^ name)
 	in
 	Array.iter (fun f -> globals.(f.index) <- VFun f) code.functions;
 	Array.iter (fun (name,idx) -> globals.(idx) <- load_native code.strings.(name)) code.natives;
@@ -733,14 +982,12 @@ let write_code ch code =
 
 	let write_op op =
 
-		if op = OLabel then
-			byte (Obj.magic op)
-		else
-
 		let o = Obj.repr op in
 		let oid = Obj.tag o in
 
 		match op with
+		| OLabel _ ->
+			byte oid
 		| OCall2 (r,g,a,b) ->
 			byte oid;
 			write_index r;
@@ -801,6 +1048,7 @@ let write_code ch code =
 	let calc_types() =
 		let tmp_ch = IO.output_string() in
 		let b = IO.write_byte tmp_ch in
+		let idx = write_index_gen b in
 		let rec get_type t =
 			lookup types t (fun() -> write_type t)
 		and write_type = function
@@ -814,12 +1062,23 @@ let write_code ch code =
 			| TFun (args,ret) ->
 				let n = List.length args in
 				if n > 0xFF then assert false;
+				let iargs = List.map get_type args in
+				let iret = get_type ret in
 				b 7;
 				b n;
-				List.iter write_type_ref args;
-				write_type_ref ret
-		and write_type_ref t =
-			write_index_gen b (get_type t)
+				List.iter idx iargs;
+				idx iret
+			| TObj p ->
+				let psup = (match p.psuper with None -> 0 | Some p -> 1 + get_type (TObj p)) in
+				let fields = Array.map (fun (_,n,t) -> n, get_type t) p.pfields in
+				let proto = Array.map (fun (_,n,t,g) -> n, get_type t, g) p.pproto in
+				b 8;
+				idx p.pid;
+				idx psup;
+				idx (Array.length fields);
+				idx (Array.length proto);
+				Array.iter (fun (n,t) -> idx n; idx t) fields;
+				Array.iter (fun (n,t,g) -> idx n; idx t; idx g) proto;
 		in
 		List.iter (fun t -> ignore(get_type t)) [TVoid; TUI8; TI32; TF32; TF64; TBool; TAny]; (* make sure all basic types get lower indexes *)
 		Array.iter (fun g -> ignore(get_type g)) code.globals;
@@ -897,7 +1156,12 @@ let ostr o =
 	| OJNeq (a,b,i) -> Printf.sprintf "jneq %d,%d,%d" a b i
 	| OJAlways d -> Printf.sprintf "jalways %d" d
 	| OToAny (r,a) -> Printf.sprintf "toany %d,%d" r a
-	| OLabel -> "label"
+	| OLabel _ -> "label"
+	| ONew r -> Printf.sprintf "new %d" r
+	| OField (r,o,i) -> Printf.sprintf "field %d,%d[%d]" r o i
+	| OSetField (o,i,r) -> Printf.sprintf "setfield %d[%d],%d" o i r
+	| OGetThis (r,i) -> Printf.sprintf "getthis %d,[%d]" r i
+	| OSetThis (i,r) -> Printf.sprintf "setthis [%d],%d" i r
 
 let dump code =
 	let lines = ref [] in
@@ -957,8 +1221,23 @@ let generate com =
 		cglobals = new_lookup();
 		cnatives = new_lookup();
 		cfunctions = DynArray.create();
+		overrides = Hashtbl.create 0;
+		cached_types = PMap.empty;
 	} in
 	ignore(alloc_string ctx "");
+	List.iter (fun t ->
+		match t with
+		| TClassDecl c ->
+			let rec loop p f =
+				match p with
+				| Some (p,_) when PMap.mem f.cf_name p.cl_fields ->
+					Hashtbl.replace ctx.overrides (f.cf_name,p.cl_path) true;
+					loop p.cl_super f
+				| _ -> ()
+			in
+			List.iter (fun f -> loop c.cl_super f) c.cl_overrides
+ 		| _ -> ()
+	) com.types;
 	List.iter (generate_type ctx) com.types;
 	let ep = (match com.main_class with
 		| None -> assert false (* TODO *)
@@ -975,6 +1254,7 @@ let generate com =
 		natives = DynArray.to_array ctx.cnatives.arr;
 		functions = DynArray.to_array ctx.cfunctions;
 	} in
+	if Common.defined com Define.Dump then prerr_endline (dump code);
 	check code;
 	let ch = IO.output_string() in
 	write_code ch code;
@@ -982,7 +1262,5 @@ let generate com =
 	let ch = open_out_bin com.file in
 	output_string ch str;
 	close_out ch;
-(*	prerr_endline (dump code);
-	ignore(interp code); *)
-	()
+	if Common.defined com Define.Interp then ignore(interp code)